Skip to content

Commit e8b8faa

Browse files
authored
Include extension types in 'implementers' list (#3658)
1 parent 7e171fc commit e8b8faa

11 files changed

+354
-86
lines changed

lib/src/generator/templates.runtime_renderers.dart

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7746,6 +7746,19 @@ class _Renderer_InheritingContainer extends RendererBase<InheritingContainer> {
77467746
self.renderSimpleVariable(c, remainingNames, 'bool'),
77477747
getBool: (CT_ c) => c.publicInheritedInstanceOperators,
77487748
),
7749+
'publicInterfaceElements': Property(
7750+
getValue: (CT_ c) => c.publicInterfaceElements,
7751+
renderVariable: (CT_ c, Property<CT_> self,
7752+
List<String> remainingNames) =>
7753+
self.renderSimpleVariable(
7754+
c, remainingNames, 'Iterable<InheritingContainer>'),
7755+
renderIterable: (CT_ c, RendererBase<CT_> r,
7756+
List<MustachioNode> ast, StringSink sink) {
7757+
return c.publicInterfaceElements.map((e) =>
7758+
_render_InheritingContainer(e, ast, r.template, sink,
7759+
parent: r));
7760+
},
7761+
),
77497762
'publicInterfaces': Property(
77507763
getValue: (CT_ c) => c.publicInterfaces,
77517764
renderVariable: (CT_ c, Property<CT_> self,
@@ -9934,17 +9947,17 @@ class _Renderer_MixedInTypes extends RendererBase<MixedInTypes> {
99349947
self.renderSimpleVariable(c, remainingNames, 'bool'),
99359948
getBool: (CT_ c) => c.hasPublicMixedInTypes,
99369949
),
9937-
'mixedInTypes': Property(
9938-
getValue: (CT_ c) => c.mixedInTypes,
9950+
'mixedInElements': Property(
9951+
getValue: (CT_ c) => c.mixedInElements,
99399952
renderVariable: (CT_ c, Property<CT_> self,
99409953
List<String> remainingNames) =>
99419954
self.renderSimpleVariable(
9942-
c, remainingNames, 'List<DefinedElementType>'),
9955+
c, remainingNames, 'List<InheritingContainer>'),
99439956
renderIterable: (CT_ c, RendererBase<CT_> r,
99449957
List<MustachioNode> ast, StringSink sink) {
9945-
return c.mixedInTypes.map((e) => _render_DefinedElementType(
9946-
e, ast, r.template, sink,
9947-
parent: r));
9958+
return c.mixedInElements.map((e) =>
9959+
_render_InheritingContainer(e, ast, r.template, sink,
9960+
parent: r));
99489961
},
99499962
),
99509963
'publicMixedInTypes': Property(
@@ -15267,6 +15280,19 @@ class _Renderer_TypeImplementing extends RendererBase<TypeImplementing> {
1526715280
self.renderSimpleVariable(c, remainingNames, 'bool'),
1526815281
getBool: (CT_ c) => c.hasPublicInterfaces,
1526915282
),
15283+
'interfaceElements': Property(
15284+
getValue: (CT_ c) => c.interfaceElements,
15285+
renderVariable: (CT_ c, Property<CT_> self,
15286+
List<String> remainingNames) =>
15287+
self.renderSimpleVariable(
15288+
c, remainingNames, 'List<InheritingContainer>'),
15289+
renderIterable: (CT_ c, RendererBase<CT_> r,
15290+
List<MustachioNode> ast, StringSink sink) {
15291+
return c.interfaceElements.map((e) =>
15292+
_render_InheritingContainer(e, ast, r.template, sink,
15293+
parent: r));
15294+
},
15295+
),
1527015296
'interfaces': Property(
1527115297
getValue: (CT_ c) => c.interfaces,
1527215298
renderVariable: (CT_ c, Property<CT_> self,

lib/src/model/class.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,15 @@ class Class extends InheritingContainer
3131
this,
3232

3333
// Caching should make this recursion a little less painful.
34-
for (var container in mixedInTypes.reversed.modelElements)
34+
for (var container in mixedInElements.reversed)
3535
...container.inheritanceChain,
3636

3737
for (var container in superChain.modelElements)
3838
...container.inheritanceChain,
3939

4040
// Interfaces need to come last, because classes in the superChain might
4141
// implement them even when they aren't mentioned.
42-
...interfaces.expandInheritanceChain,
42+
...interfaceElements.expandInheritanceChain,
4343
];
4444

4545
Class(this.element, Library library, PackageGraph packageGraph)

lib/src/model/enum.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,11 @@ class Enum extends InheritingContainer
2727
@override
2828
late final List<InheritingContainer> inheritanceChain = [
2929
this,
30-
for (var container in mixedInTypes.reversed.modelElements)
30+
for (var container in mixedInElements.reversed)
3131
...container.inheritanceChain,
3232
for (var container in superChain.modelElements)
3333
...container.inheritanceChain,
34-
...interfaces.expandInheritanceChain,
34+
...interfaceElements.expandInheritanceChain,
3535
];
3636

3737
@override

lib/src/model/extension_type.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ class ExtensionType extends InheritingContainer
6363
@override
6464
late final List<InheritingContainer> inheritanceChain = [
6565
this,
66-
...interfaces.expandInheritanceChain,
66+
...interfaceElements.expandInheritanceChain,
6767
];
6868

6969
@override

lib/src/model/inheriting_container.dart

Lines changed: 35 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -370,7 +370,12 @@ abstract class InheritingContainer extends Container
370370
Iterable<Method> get publicInheritedMethods =>
371371
model_utils.filterNonPublic(inheritedMethods);
372372

373-
Iterable<DefinedElementType> get publicInterfaces => const [];
373+
Iterable<DefinedElementType> get publicInterfaces;
374+
375+
Iterable<InheritingContainer> get publicInterfaceElements => [
376+
for (var interface in publicInterfaces)
377+
interface.modelElement as InheritingContainer,
378+
];
374379

375380
Iterable<DefinedElementType> get publicSuperChainReversed =>
376381
publicSuperChain.reversed;
@@ -474,10 +479,15 @@ abstract class InheritingContainer extends Container
474479

475480
/// Add the ability to support mixed-in types to an [InheritingContainer].
476481
mixin MixedInTypes on InheritingContainer {
482+
@visibleForTesting
477483
late final List<DefinedElementType> mixedInTypes = element.mixins
478484
.map((f) => modelBuilder.typeFrom(f, library) as DefinedElementType)
479485
.toList(growable: false);
480486

487+
List<InheritingContainer> get mixedInElements => [
488+
for (var t in mixedInTypes) t.modelElement as InheritingContainer,
489+
];
490+
481491
@override
482492
bool get hasModifiers => super.hasModifiers || hasPublicMixedInTypes;
483493

@@ -509,9 +519,14 @@ mixin TypeImplementing on InheritingContainer {
509519
/// Interfaces directly implemented by this container.
510520
List<DefinedElementType> get interfaces => _directInterfaces;
511521

512-
/// Returns all the "immediate" public implementors of this
513-
/// [TypeImplementing]. For a [Mixin], this is actually the mixin
514-
/// applications using the [Mixin].
522+
List<InheritingContainer> get interfaceElements => [
523+
for (var interface in interfaces)
524+
interface.modelElement as InheritingContainer,
525+
];
526+
527+
/// All the "immediate" public implementors of this [TypeImplementing].
528+
///
529+
/// For a [Mixin], this is actually the mixin applications using the [Mixin].
515530
///
516531
/// If this [InheritingContainer] has a private implementor, then that is
517532
/// counted as a proxy for any public implementors of that private container.
@@ -527,16 +542,17 @@ mixin TypeImplementing on InheritingContainer {
527542
if (implementor.isPublicAndPackageDocumented) {
528543
result.add(implementor);
529544
} else {
530-
model_utils
531-
.findCanonicalFor(
532-
packageGraph.implementors[implementor] ?? const [])
533-
.forEach(addToResult);
545+
var implementors = packageGraph.implementors[implementor];
546+
if (implementors != null) {
547+
model_utils.findCanonicalFor(implementors).forEach(addToResult);
548+
}
534549
}
535550
}
536551

537-
model_utils
538-
.findCanonicalFor(packageGraph.implementors[this] ?? const [])
539-
.forEach(addToResult);
552+
var immediateImplementors = packageGraph.implementors[this];
553+
if (immediateImplementors != null) {
554+
model_utils.findCanonicalFor(immediateImplementors).forEach(addToResult);
555+
}
540556
return result;
541557
}
542558

@@ -587,11 +603,14 @@ extension on InterfaceElement {
587603
}
588604

589605
extension DefinedElementTypeIterableExtension on Iterable<DefinedElementType> {
590-
/// Expands the [ModelElement] for each element to its inheritance chain.
591-
Iterable<InheritingContainer> get expandInheritanceChain =>
592-
expand((e) => (e.modelElement as InheritingContainer).inheritanceChain);
593-
594-
/// Returns the [ModelElement] for each element.
606+
/// The [ModelElement] for each element.
595607
Iterable<InheritingContainer> get modelElements =>
596608
map((e) => e.modelElement as InheritingContainer);
597609
}
610+
611+
extension InheritingContainerIterableExtension
612+
on Iterable<InheritingContainer> {
613+
/// Expands each element to its inheritance chain.
614+
Iterable<InheritingContainer> get expandInheritanceChain =>
615+
expand((e) => e.inheritanceChain);
616+
}

lib/src/model/mixin.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,14 @@ class Mixin extends InheritingContainer with TypeImplementing {
3131
this,
3232

3333
// Mix-in interfaces come before other interfaces.
34-
...superclassConstraints.expandInheritanceChain,
34+
...superclassConstraints.modelElements.expandInheritanceChain,
3535

3636
for (var container in superChain.modelElements)
3737
...container.inheritanceChain,
3838

3939
// Interfaces need to come last, because classes in the superChain might
4040
// implement them even when they aren't mentioned.
41-
...interfaces.expandInheritanceChain,
41+
...interfaceElements.expandInheritanceChain,
4242
];
4343

4444
Mixin(this.element, super.library, super.packageGraph);

lib/src/model/package_graph.dart

Lines changed: 25 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -139,8 +139,9 @@ class PackageGraph with CommentReferable, Nameable, ModelBuilder {
139139
// all packages are picked up.
140140
for (var package in _documentedPackages) {
141141
for (var library in package.libraries) {
142-
_addToImplementors(library.allClasses);
143-
_addToImplementors(library.mixins);
142+
_addToImplementers(library.allClasses);
143+
_addToImplementers(library.mixins);
144+
_addToImplementers(library.extensionTypes);
144145
_extensions.addAll(library.extensions);
145146
}
146147
if (package.isLocal && !package.hasPublicLibraries) {
@@ -580,7 +581,7 @@ class PackageGraph with CommentReferable, Nameable, ModelBuilder {
580581
return hrefMap;
581582
}
582583

583-
void _addToImplementors(Iterable<InheritingContainer> containers) {
584+
void _addToImplementers(Iterable<InheritingContainer> containers) {
584585
assert(!allImplementorsAdded);
585586

586587
// Private containers may not be included in documentation, but may still be
@@ -589,7 +590,7 @@ class PackageGraph with CommentReferable, Nameable, ModelBuilder {
589590
var privates = <InheritingContainer>[];
590591

591592
void checkAndAddContainer(
592-
InheritingContainer implemented, InheritingContainer implementor) {
593+
InheritingContainer implemented, InheritingContainer implementer) {
593594
if (!implemented.isPublic) {
594595
privates.add(implemented);
595596
}
@@ -598,36 +599,40 @@ class PackageGraph with CommentReferable, Nameable, ModelBuilder {
598599
var list = _implementors.putIfAbsent(implemented, () => []);
599600
// TODO(srawlins): This would be more efficient if we created a
600601
// SplayTreeSet keyed off of `.element`.
601-
if (!list.any((l) => l.element == implementor.element)) {
602-
list.add(implementor);
602+
if (!list.any((l) => l.element == implementer.element)) {
603+
list.add(implementer);
603604
}
604605
}
605606

606-
void addImplementor(InheritingContainer clazz) {
607-
var supertype = clazz.supertype;
607+
void addImplementer(InheritingContainer container) {
608+
var supertype = container.supertype;
608609
if (supertype != null) {
609610
checkAndAddContainer(
610-
supertype.modelElement as InheritingContainer, clazz);
611+
supertype.modelElement as InheritingContainer, container);
611612
}
612-
if (clazz is Class) {
613-
for (var type in clazz.mixedInTypes) {
614-
checkAndAddContainer(type.modelElement as InheritingContainer, clazz);
613+
if (container is Class) {
614+
for (var element in container.mixedInElements) {
615+
checkAndAddContainer(element, container);
615616
}
616-
for (var type in clazz.interfaces) {
617-
checkAndAddContainer(type.modelElement as InheritingContainer, clazz);
617+
for (var element in container.interfaceElements) {
618+
checkAndAddContainer(element, container);
619+
}
620+
} else if (container is ExtensionType) {
621+
for (var element in container.interfaceElements) {
622+
checkAndAddContainer(element, container);
618623
}
619624
}
620-
for (var type in clazz.publicInterfaces) {
621-
checkAndAddContainer(type.modelElement as InheritingContainer, clazz);
625+
for (var element in container.publicInterfaceElements) {
626+
checkAndAddContainer(element, container);
622627
}
623628
}
624629

625-
containers.forEach(addImplementor);
630+
containers.forEach(addImplementer);
626631

627632
// [privates] may grow while processing; use a for loop, rather than a
628633
// for-each loop, to avoid concurrent modification errors.
629634
for (var i = 0; i < privates.length; i++) {
630-
addImplementor(privates[i]);
635+
addImplementer(privates[i]);
631636
}
632637
}
633638

@@ -661,10 +666,10 @@ class PackageGraph with CommentReferable, Nameable, ModelBuilder {
661666
?.linkedName ??
662667
'Object';
663668

664-
/// The set of [Class]es which should _not_ be presented as implementors.
669+
/// The set of [Class]es which should _not_ be presented as implementers.
665670
///
666671
/// Add classes here if they are similar to Interceptor in that they are to be
667-
/// ignored even when they are the implementors of [Inheritable]s, and the
672+
/// ignored even when they are the implementers of [Inheritable]s, and the
668673
/// class these inherit from should instead claim implementation.
669674
late final Set<Class> inheritThrough = () {
670675
var interceptorSpecialClass = specialClasses[SpecialClass.interceptor];

test/end2end/model_test.dart

Lines changed: 28 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1820,8 +1820,8 @@ void main() {
18201820

18211821
test('Verify inheritance/mixin structure and type inference', () {
18221822
expect(
1823-
TypeInferenceMixedIn.mixedInTypes
1824-
.map<String>((DefinedElementType t) => t.modelElement.name),
1823+
TypeInferenceMixedIn.mixedInElements
1824+
.map<String>((element) => element.name),
18251825
orderedEquals(['GenericMixin']));
18261826
expect(
18271827
TypeInferenceMixedIn.mixedInTypes.first.typeArguments
@@ -1983,15 +1983,15 @@ void main() {
19831983
});
19841984

19851985
test('mixins', () {
1986-
expect(Apple.mixedInTypes, hasLength(0));
1986+
expect(Apple.mixedInElements, hasLength(0));
19871987
});
19881988

19891989
test('mixins private', () {
1990-
expect(F.mixedInTypes, hasLength(1));
1990+
expect(F.mixedInElements, hasLength(1));
19911991
});
19921992

19931993
test('interfaces', () {
1994-
var interfaces = Dog.interfaces;
1994+
var interfaces = Dog.interfaceElements;
19951995
expect(interfaces, hasLength(2));
19961996
expect(interfaces[0].name, 'Cat');
19971997
expect(interfaces[1].name, 'E');
@@ -4399,28 +4399,37 @@ String? topLevelFunction(int param1, bool param2, Cool coolBeans,
43994399

44004400
test('a class that implements Future<void>', () {
44014401
expect(
4402-
ImplementsFutureVoid.linkedName,
4403-
equals(
4404-
'<a href="${htmlBasePlaceholder}fake/ImplementsFutureVoid-class.html">ImplementsFutureVoid</a>'));
4402+
ImplementsFutureVoid.linkedName,
4403+
equals(
4404+
'<a href="${htmlBasePlaceholder}fake/ImplementsFutureVoid-class.html">ImplementsFutureVoid</a>',
4405+
),
4406+
);
44054407
var FutureVoid =
4406-
ImplementsFutureVoid.interfaces.firstWhere((c) => c.name == 'Future');
4408+
ImplementsFutureVoid.interfaces.firstWhere((e) => e.name == 'Future');
44074409
expect(
4408-
FutureVoid.linkedName,
4409-
equals(
4410-
'Future<span class="signature">&lt;<wbr><span class="type-parameter">void</span>&gt;</span>'));
4410+
FutureVoid.linkedName,
4411+
equals(
4412+
'Future<span class="signature">&lt;<wbr><span class="type-parameter">void</span>&gt;</span>',
4413+
),
4414+
);
44114415
});
44124416

44134417
test('Verify that a mixin with a void type parameter works', () {
44144418
expect(
4415-
ATypeTakingClassMixedIn.linkedName,
4416-
equals(
4417-
'<a href="${htmlBasePlaceholder}fake/ATypeTakingClassMixedIn-class.html">ATypeTakingClassMixedIn</a>'));
4419+
ATypeTakingClassMixedIn.linkedName,
4420+
equals(
4421+
'<a href="${htmlBasePlaceholder}fake/ATypeTakingClassMixedIn-class.html">ATypeTakingClassMixedIn</a>',
4422+
),
4423+
);
44184424
var ATypeTakingClassVoid = ATypeTakingClassMixedIn.mixedInTypes
4419-
.firstWhere((c) => c.name == 'ATypeTakingClass');
4425+
.firstWhere((e) => e.name == 'ATypeTakingClass');
44204426
expect(
4421-
ATypeTakingClassVoid.linkedName,
4422-
equals(
4423-
'<a href="${htmlBasePlaceholder}fake/ATypeTakingClass-class.html">ATypeTakingClass</a><span class="signature">&lt;<wbr><span class="type-parameter">void</span>&gt;</span>'));
4427+
ATypeTakingClassVoid.linkedName,
4428+
equals(
4429+
'<a href="${htmlBasePlaceholder}fake/ATypeTakingClass-class.html">ATypeTakingClass</a>'
4430+
'<span class="signature">&lt;<wbr><span class="type-parameter">void</span>&gt;</span>',
4431+
),
4432+
);
44244433
});
44254434
});
44264435

0 commit comments

Comments
 (0)