Skip to content

Commit eed92d3

Browse files
authored
Simplify InheritingContainer.allModelElements and _inheritedElements (#3689)
1 parent 7b3274a commit eed92d3

File tree

2 files changed

+57
-47
lines changed

2 files changed

+57
-47
lines changed

lib/src/model/inheriting_container.dart

+56-44
Original file line numberDiff line numberDiff line change
@@ -100,15 +100,10 @@ abstract class InheritingContainer extends Container
100100
late final List<LanguageFeature> displayedLanguageFeatures =
101101
containerModifiers.asLanguageFeatureSet.toList();
102102

103-
late final List<ModelElement> _allModelElements = () {
104-
_inheritedElementsCache = _inheritedElements;
105-
var result = [
106-
...super.allModelElements,
107-
...typeParameters,
108-
];
109-
_inheritedElementsCache = null;
110-
return result;
111-
}();
103+
late final List<ModelElement> _allModelElements = [
104+
...super.allModelElements,
105+
...typeParameters,
106+
];
112107

113108
Iterable<Method> get inheritedMethods {
114109
var methodNames = declaredMethods.map((m) => m.element.name).toSet();
@@ -145,55 +140,69 @@ abstract class InheritingContainer extends Container
145140
late final List<DefinedElementType> publicSuperChain =
146141
model_utils.filterNonPublic(superChain).toList(growable: false);
147142

148-
List<ExecutableElement>? _inheritedElementsCache;
149-
List<ExecutableElement> get _inheritedElements {
150-
if (_inheritedElementsCache != null) return _inheritedElementsCache!;
151-
if (element is ClassElement && (element as ClassElement).isDartCoreObject) {
143+
/// A list of the inherited executable elements, one element per inherited
144+
/// `Name`.
145+
///
146+
/// In this list, elements that are "closer" in the inheritance chain to
147+
/// _this_ element are preferred over elements that are further away. In the
148+
/// case of ties, concrete inherited elements are prefered to non-concrete
149+
/// ones.
150+
late final List<ExecutableElement> _inheritedElements = () {
151+
if (element case ClassElement classElement
152+
when classElement.isDartCoreObject) {
152153
return const <ExecutableElement>[];
153154
}
154155

155-
final concreteInheritenceMap =
156+
// The mapping of all of the inherited element names to their _concrete_
157+
// implementation element.
158+
var concreteInheritanceMap =
156159
packageGraph.inheritanceManager.getInheritedConcreteMap2(element);
157-
final inheritenceMap =
160+
// The mapping of all inherited element names to the nearest inherited
161+
// element that they resolve to.
162+
var inheritanceMap =
158163
packageGraph.inheritanceManager.getInheritedMap2(element);
159164

160-
List<InterfaceElement>? inheritanceChainElements;
165+
var inheritanceChainElements =
166+
inheritanceChain.map((c) => c.element).toList(growable: false);
161167

162-
final combinedMap = {
163-
for (final name in concreteInheritenceMap.keys)
164-
name.name: concreteInheritenceMap[name]!,
168+
// A combined map of names to inherited _concrete_ Elements, and other
169+
// inherited Elements.
170+
var combinedMap = {
171+
for (var MapEntry(:key, :value) in concreteInheritanceMap.entries)
172+
key.name: value,
165173
};
166-
for (final name in inheritenceMap.keys) {
167-
final inheritenceElement = inheritenceMap[name]!;
168-
final combinedMapElement = combinedMap[name.name];
174+
for (var MapEntry(key: name, value: inheritedElement)
175+
in inheritanceMap.entries) {
176+
var combinedMapElement = combinedMap[name.name];
169177
if (combinedMapElement == null) {
170-
combinedMap[name.name] = inheritenceElement;
178+
combinedMap[name.name] = inheritedElement;
171179
continue;
172180
}
173181

174-
// Elements in the inheritance chain starting from `this.element` down to,
175-
// but not including, [Object].
176-
inheritanceChainElements ??=
177-
inheritanceChain.map((c) => c.element).toList(growable: false);
178-
final enclosingElement =
179-
inheritenceElement.enclosingElement as InterfaceElement;
182+
// Elements in the inheritance chain starting from `this.element` up to,
183+
// but not including, `Object`.
184+
var enclosingElement =
185+
inheritedElement.enclosingElement as InterfaceElement;
180186
assert(inheritanceChainElements.contains(enclosingElement) ||
181187
enclosingElement.isDartCoreObject);
182188

183-
// If the concrete object from
184-
// [InheritanceManager3.getInheritedConcreteMap2] is farther from this
185-
// class in the inheritance chain than the one provided by
186-
// `inheritedMap2`, prefer `inheritedMap2`. This correctly accounts for
187-
// intermediate abstract classes that have method/field implementations.
188-
if (inheritanceChainElements.indexOf(
189-
combinedMapElement.enclosingElement as InterfaceElement) <
189+
// If the concrete element from `getInheritedConcreteMap2` is farther in
190+
// the inheritance chain from this class than the (non-concrete) one
191+
// provided by `getInheritedMap2`, prefer the latter. This correctly
192+
// accounts for intermediate abstract classes that have method/field
193+
// implementations.
194+
var enclosingElementFromCombined =
195+
combinedMapElement.enclosingElement as InterfaceElement;
196+
if (inheritanceChainElements.indexOf(enclosingElementFromCombined) <
190197
inheritanceChainElements.indexOf(enclosingElement)) {
191-
combinedMap[name.name] = inheritenceElement;
198+
combinedMap[name.name] = inheritedElement;
192199
}
193200
}
194201

202+
// Finally, return all of the elements ultimately collected in the combined
203+
// map.
195204
return combinedMap.values.toList(growable: false);
196-
}
205+
}();
197206

198207
/// All fields defined on this container, _including inherited fields_.
199208
late List<Field> allFields = () {
@@ -308,12 +317,13 @@ abstract class InheritingContainer extends Container
308317

309318
bool get hasPublicSuperChainReversed => publicSuperChainReversed.isNotEmpty;
310319

311-
/// Not the same as [superChain] as it may include mixins.
320+
/// A sorted list of [element]'s inheritance chain, including interfaces and
321+
/// mixins.
312322
///
313-
/// It's really not even the same as ordinary Dart inheritance, either,
323+
/// Note: this list is really not even the same as ordinary Dart inheritance,
314324
/// because we pretend that interfaces are part of the inheritance chain
315325
/// to include them in the set of things we might link to for documentation
316-
/// purposes in abstract classes.
326+
/// purposes.
317327
List<InheritingContainer> get inheritanceChain;
318328

319329
@visibleForTesting
@@ -376,19 +386,21 @@ abstract class InheritingContainer extends Container
376386
Iterable<DefinedElementType> get publicSuperChainReversed =>
377387
publicSuperChain.reversed;
378388

389+
/// The chain of super-types, starting with [supertype], up to, but not
390+
/// including, `Object`.
379391
List<DefinedElementType> get superChain {
380392
var typeChain = <DefinedElementType>[];
381393
var parent = supertype;
382394
while (parent != null) {
383395
typeChain.add(parent);
384396
final parentType = parent.type;
385397
if (parentType is! InterfaceType) {
386-
throw StateError('ancestor of $this is $parent with model element '
387-
'${parent.modelElement}');
398+
throw StateError("ancestor of '$this' is '$parent' with model element "
399+
"'${parent.modelElement}'");
388400
}
389401

390402
var superclass = parentType.superclass;
391-
// Avoid adding [Object] to the [superChain] ([_supertype] already has
403+
// Avoid adding `Object` to the `superChain` (`_supertype` already has
392404
// this check).
393405
if (superclass == null || superclass.superclass == null) {
394406
break;

lib/src/model/mixin.dart

+1-3
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,12 @@ class Mixin extends InheritingContainer with TypeImplementing {
2929
@override
3030
late final List<InheritingContainer> inheritanceChain = [
3131
this,
32-
33-
// Mix-in interfaces come before other interfaces.
3432
...superclassConstraints.modelElements.expandInheritanceChain,
3533

3634
for (var container in superChain.modelElements)
3735
...container.inheritanceChain,
3836

39-
// Interfaces need to come last, because classes in the superChain might
37+
// Interfaces need to come last, because classes in the `superChain` might
4038
// implement them even when they aren't mentioned.
4139
...interfaceElements.expandInheritanceChain,
4240
];

0 commit comments

Comments
 (0)