Skip to content

Commit 414953e

Browse files
authored
Simplify how inheritance is computed. (#4079)
The motivation here is that `Inheritable.computeCanonicalEnclosingContainer` is a complicated subroutine, [even](12d271a) [after](d629e1e) [several](dcc239a) [refactorings](95f4208). This is the code that decides where to link inherited members. So questions like "ah ha, `List` has a `.isEmpty`, but it inherits the docs from... `Iterable.isEmpty`." It's the wild west out there, with docs coming from indirect supertypes, interfaces, mixins, etc. A big portion of the complexity comes from choosing an order in which to search the supertypes. We have to take a directed acyclic graph, and choose an order. Prior to this change, the ordering comes from each container class's implementation of `get inheritanceChain`. I think on paper this sounds like a good idea: let a Mixin compute its inheritance chain, let an Enum compute its inheritance chain. In practice, it spread complexity out too much, and a combined implementation is actually quite compact. So in this change we remove `InheritingContainer.inheritanceChain`, the `expandInheritanceChain` extension getter, and `Inheritable._inheritance`. We replace all of this code with `Inheritable._enclosingSuperTypes`, which returns all of the various supertypes of the enclosing element, in a specific order. This getter performs a fairly simple walk up the inheritance tree (extended types, implemented types, mixed-in types, and superclass constraints). The single call to `Inheritable._inheritance` is now a call to `Inheritable._enclosingSuperTypes`. `computeCanonicalEnclosingContainer` calls this in order to collect its set of candidates for the canonical enclosing container. `_enclosingSuperTypes` handles `Object` differently, which allows the impl of `computeCanonicalEnclosingContainer` to be much simplified, no longer concerning itself with any _previous_ candidate. This is very nearly a no-op. There is some change in the handling of `Object` and it's members. Because of this, we tweak the `enum_test` to no longer use `--no-link-to-remote`, so that the links to Object.hashCode and Enum.index continue to work. I tested this with some manual verification of the Dart SDK docs, Flutter SDK docs, and the collection package docs.
1 parent 882aea9 commit 414953e

File tree

8 files changed

+73
-278
lines changed

8 files changed

+73
-278
lines changed

lib/src/generator/templates.runtime_renderers.dart

Lines changed: 2 additions & 140 deletions
Original file line numberDiff line numberDiff line change
@@ -2734,34 +2734,6 @@ class _Renderer_Class extends RendererBase<Class> {
27342734
);
27352735
},
27362736
),
2737-
'inheritanceChain': Property(
2738-
getValue: (CT_ c) => c.inheritanceChain,
2739-
renderVariable:
2740-
(CT_ c, Property<CT_> self, List<String> remainingNames) =>
2741-
self.renderSimpleVariable(
2742-
c,
2743-
remainingNames,
2744-
'List<InheritingContainer>',
2745-
),
2746-
2747-
renderIterable:
2748-
(
2749-
CT_ c,
2750-
RendererBase<CT_> r,
2751-
List<MustachioNode> ast,
2752-
StringSink sink,
2753-
) {
2754-
return c.inheritanceChain.map(
2755-
(e) => _render_InheritingContainer(
2756-
e,
2757-
ast,
2758-
r.template,
2759-
sink,
2760-
parent: r,
2761-
),
2762-
);
2763-
},
2764-
),
27652737
'isAbstract': Property(
27662738
getValue: (CT_ c) => c.isAbstract,
27672739
renderVariable:
@@ -7213,34 +7185,6 @@ class _Renderer_Enum extends RendererBase<Enum> {
72137185
);
72147186
},
72157187
),
7216-
'inheritanceChain': Property(
7217-
getValue: (CT_ c) => c.inheritanceChain,
7218-
renderVariable:
7219-
(CT_ c, Property<CT_> self, List<String> remainingNames) =>
7220-
self.renderSimpleVariable(
7221-
c,
7222-
remainingNames,
7223-
'List<InheritingContainer>',
7224-
),
7225-
7226-
renderIterable:
7227-
(
7228-
CT_ c,
7229-
RendererBase<CT_> r,
7230-
List<MustachioNode> ast,
7231-
StringSink sink,
7232-
) {
7233-
return c.inheritanceChain.map(
7234-
(e) => _render_InheritingContainer(
7235-
e,
7236-
ast,
7237-
r.template,
7238-
sink,
7239-
parent: r,
7240-
),
7241-
);
7242-
},
7243-
),
72447188
'isAbstract': Property(
72457189
getValue: (CT_ c) => c.isAbstract,
72467190
renderVariable:
@@ -8519,34 +8463,6 @@ class _Renderer_ExtensionType extends RendererBase<ExtensionType> {
85198463
);
85208464
},
85218465
),
8522-
'inheritanceChain': Property(
8523-
getValue: (CT_ c) => c.inheritanceChain,
8524-
renderVariable:
8525-
(CT_ c, Property<CT_> self, List<String> remainingNames) =>
8526-
self.renderSimpleVariable(
8527-
c,
8528-
remainingNames,
8529-
'List<InheritingContainer>',
8530-
),
8531-
8532-
renderIterable:
8533-
(
8534-
CT_ c,
8535-
RendererBase<CT_> r,
8536-
List<MustachioNode> ast,
8537-
StringSink sink,
8538-
) {
8539-
return c.inheritanceChain.map(
8540-
(e) => _render_InheritingContainer(
8541-
e,
8542-
ast,
8543-
r.template,
8544-
sink,
8545-
parent: r,
8546-
),
8547-
);
8548-
},
8549-
),
85508466
'isAbstract': Property(
85518467
getValue: (CT_ c) => c.isAbstract,
85528468
renderVariable:
@@ -11894,34 +11810,6 @@ class _Renderer_InheritingContainer extends RendererBase<InheritingContainer> {
1189411810

1189511811
getBool: (CT_ c) => c.hasPublicSuperChainReversed,
1189611812
),
11897-
'inheritanceChain': Property(
11898-
getValue: (CT_ c) => c.inheritanceChain,
11899-
renderVariable:
11900-
(CT_ c, Property<CT_> self, List<String> remainingNames) =>
11901-
self.renderSimpleVariable(
11902-
c,
11903-
remainingNames,
11904-
'List<InheritingContainer>',
11905-
),
11906-
11907-
renderIterable:
11908-
(
11909-
CT_ c,
11910-
RendererBase<CT_> r,
11911-
List<MustachioNode> ast,
11912-
StringSink sink,
11913-
) {
11914-
return c.inheritanceChain.map(
11915-
(e) => _render_InheritingContainer(
11916-
e,
11917-
ast,
11918-
r.template,
11919-
sink,
11920-
parent: r,
11921-
),
11922-
);
11923-
},
11924-
),
1192511813
'instanceFields': Property(
1192611814
getValue: (CT_ c) => c.instanceFields,
1192711815
renderVariable:
@@ -15922,34 +15810,6 @@ class _Renderer_Mixin extends RendererBase<Mixin> {
1592215810

1592315811
getBool: (CT_ c) => c.hasPublicSuperclassConstraints,
1592415812
),
15925-
'inheritanceChain': Property(
15926-
getValue: (CT_ c) => c.inheritanceChain,
15927-
renderVariable:
15928-
(CT_ c, Property<CT_> self, List<String> remainingNames) =>
15929-
self.renderSimpleVariable(
15930-
c,
15931-
remainingNames,
15932-
'List<InheritingContainer>',
15933-
),
15934-
15935-
renderIterable:
15936-
(
15937-
CT_ c,
15938-
RendererBase<CT_> r,
15939-
List<MustachioNode> ast,
15940-
StringSink sink,
15941-
) {
15942-
return c.inheritanceChain.map(
15943-
(e) => _render_InheritingContainer(
15944-
e,
15945-
ast,
15946-
r.template,
15947-
sink,
15948-
parent: r,
15949-
),
15950-
);
15951-
},
15952-
),
1595315813
'isAbstract': Property(
1595415814
getValue: (CT_ c) => c.isAbstract,
1595515815
renderVariable:
@@ -25741,6 +25601,7 @@ const _invisibleGetters = {
2574125601
'nonSynthetic2',
2574225602
'runtimeType',
2574325603
'session',
25604+
'sinceSdkVersion',
2574425605
},
2574525606
'EnumElement2': {
2574625607
'constants2',
@@ -26192,6 +26053,7 @@ const _invisibleGetters = {
2619226053
'baseElement',
2619326054
'children',
2619426055
'children2',
26056+
'constantInitializer',
2619526057
'constantInitializer2',
2619626058
'context',
2619726059
'declaration',

lib/src/model/class.dart

Lines changed: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@ import 'package:dartdoc/src/model/model.dart';
1414
/// **instance**: As with [Container], but also includes inherited children.
1515
/// **inherited**: Filtered getters giving only inherited children.
1616
class Class extends InheritingContainer with Constructable, MixedInTypes {
17-
@override
18-
1917
@override
2018
final ClassElement2 element;
2119

@@ -29,22 +27,6 @@ class Class extends InheritingContainer with Constructable, MixedInTypes {
2927
String get sidebarPath =>
3028
'${canonicalLibraryOrThrow.dirName}/$name-class-sidebar.html';
3129

32-
@override
33-
late final List<InheritingContainer> inheritanceChain = [
34-
this,
35-
36-
// Caching should make this recursion a little less painful.
37-
for (var container in mixedInTypes.modelElements.reversed)
38-
...container.inheritanceChain,
39-
40-
for (var container in superChain.modelElements)
41-
...container.inheritanceChain,
42-
43-
// Interfaces need to come last, because classes in the superChain might
44-
// implement them even when they aren't mentioned.
45-
...interfaceElements.expandInheritanceChain,
46-
];
47-
4830
Class(this.element, Library library, PackageGraph packageGraph)
4931
: super(library, packageGraph) {
5032
if (element.name3 == 'Object' &&
@@ -75,8 +57,7 @@ class Class extends InheritingContainer with Constructable, MixedInTypes {
7557
bool get isFinal => element.isFinal && !element.isSealed;
7658

7759
@override
78-
bool get isImplementableInterface =>
79-
element.isInterface && !element.isSealed;
60+
bool get isImplementableInterface => element.isInterface && !element.isSealed;
8061

8162
@override
8263
bool get isMixinClass => element.isMixinClass;

lib/src/model/enum.dart

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,6 @@ class Enum extends InheritingContainer with Constructable, MixedInTypes {
2020
...constructors,
2121
];
2222

23-
@override
24-
late final List<InheritingContainer> inheritanceChain = [
25-
this,
26-
for (var container in mixedInTypes.modelElements.reversed)
27-
...container.inheritanceChain,
28-
for (var container in superChain.modelElements)
29-
...container.inheritanceChain,
30-
...interfaceElements.expandInheritanceChain,
31-
];
32-
3323
@override
3424
// Prevent a collision with the library file.
3525
String get fileName => name == 'index' ? '$name-enum.html' : '$name.html';

lib/src/model/extension_type.dart

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,8 @@ import 'package:dartdoc/src/model/model.dart';
1010
import 'package:meta/meta.dart';
1111

1212
class ExtensionType extends InheritingContainer with Constructable {
13-
1413
@override
15-
final ExtensionTypeElement2 element;
14+
final ExtensionTypeElement2 element;
1615

1716
late final ElementType representationType =
1817
getTypeFor(element.representation2.type, library);
@@ -45,13 +44,11 @@ class ExtensionType extends InheritingContainer with Constructable {
4544
ContainerAccessor? getter, setter;
4645
final fieldGetter = field.getter2;
4746
if (fieldGetter != null) {
48-
getter = ContainerAccessor(
49-
fieldGetter, library, packageGraph, this);
47+
getter = ContainerAccessor(fieldGetter, library, packageGraph, this);
5048
}
5149
final fieldSetter = field.setter2;
5250
if (fieldSetter != null) {
53-
setter = ContainerAccessor(
54-
fieldSetter, library, packageGraph, this);
51+
setter = ContainerAccessor(fieldSetter, library, packageGraph, this);
5552
}
5653
return getModelForPropertyInducingElement(field, library,
5754
getter: getter, setter: setter) as Field;
@@ -63,12 +60,6 @@ class ExtensionType extends InheritingContainer with Constructable {
6360
...constructors,
6461
];
6562

66-
@override
67-
late final List<InheritingContainer> inheritanceChain = [
68-
this,
69-
...interfaceElements.expandInheritanceChain,
70-
];
71-
7263
@override
7364
String get fileName => '$name-extension-type.html';
7465

0 commit comments

Comments
 (0)