diff --git a/lib/src/generator/templates.runtime_renderers.dart b/lib/src/generator/templates.runtime_renderers.dart index dccea51ec6..5873b61e8c 100644 --- a/lib/src/generator/templates.runtime_renderers.dart +++ b/lib/src/generator/templates.runtime_renderers.dart @@ -5394,18 +5394,7 @@ class _Renderer_ExtensionType extends RendererBase { () => { ..._Renderer_InheritingContainer.propertyMap(), ..._Renderer_Constructable.propertyMap(), - 'allFields': Property( - getValue: (CT_ c) => c.allFields, - renderVariable: (CT_ c, Property self, - List remainingNames) => - self.renderSimpleVariable( - c, remainingNames, 'List'), - renderIterable: (CT_ c, RendererBase r, - List ast, StringSink sink) { - return c.allFields.map((e) => - _render_Field(e, ast, r.template, sink, parent: r)); - }, - ), + ..._Renderer_TypeImplementing.propertyMap(), 'allModelElements': Property( getValue: (CT_ c) => c.allModelElements, renderVariable: (CT_ c, Property self, @@ -5489,13 +5478,6 @@ class _Renderer_ExtensionType extends RendererBase { parent: r); }, ), - 'hasPublicInterfaces': Property( - getValue: (CT_ c) => c.hasPublicInterfaces, - renderVariable: (CT_ c, Property self, - List remainingNames) => - self.renderSimpleVariable(c, remainingNames, 'bool'), - getBool: (CT_ c) => c.hasPublicInterfaces == true, - ), 'inheritanceChain': Property( getValue: (CT_ c) => c.inheritanceChain, renderVariable: (CT_ c, Property self, @@ -5509,30 +5491,6 @@ class _Renderer_ExtensionType extends RendererBase { parent: r)); }, ), - 'inheritedMethods': Property( - getValue: (CT_ c) => c.inheritedMethods, - renderVariable: (CT_ c, Property self, - List remainingNames) => - self.renderSimpleVariable( - c, remainingNames, 'Iterable'), - renderIterable: (CT_ c, RendererBase r, - List ast, StringSink sink) { - return c.inheritedMethods.map((e) => - _render_Method(e, ast, r.template, sink, parent: r)); - }, - ), - 'inheritedOperators': Property( - getValue: (CT_ c) => c.inheritedOperators, - renderVariable: (CT_ c, Property self, - List remainingNames) => - self.renderSimpleVariable( - c, remainingNames, 'List'), - renderIterable: (CT_ c, RendererBase r, - List ast, StringSink sink) { - return c.inheritedOperators.map((e) => - _render_Operator(e, ast, r.template, sink, parent: r)); - }, - ), 'isAbstract': Property( getValue: (CT_ c) => c.isAbstract, renderVariable: (CT_ c, Property self, @@ -5580,19 +5538,6 @@ class _Renderer_ExtensionType extends RendererBase { parent: r, getters: _invisibleGetters['Kind']!); }, ), - 'publicInterfaces': Property( - getValue: (CT_ c) => c.publicInterfaces, - renderVariable: (CT_ c, Property self, - List remainingNames) => - self.renderSimpleVariable( - c, remainingNames, 'List'), - renderIterable: (CT_ c, RendererBase r, - List ast, StringSink sink) { - return c.publicInterfaces.map((e) => - _render_DefinedElementType(e, ast, r.template, sink, - parent: r)); - }, - ), 'referenceChildren': Property( getValue: (CT_ c) => c.referenceChildren, renderVariable: (CT_ c, Property self, @@ -17003,6 +16948,7 @@ const _invisibleGetters = { 'hashCode', 'implementors', 'inheritThrough', + 'inheritanceManager', 'invisibleAnnotations', 'libraries', 'libraryCount', diff --git a/lib/src/model/container_member.dart b/lib/src/model/container_member.dart index 6e8791806d..2a574c682f 100644 --- a/lib/src/model/container_member.dart +++ b/lib/src/model/container_member.dart @@ -38,13 +38,13 @@ mixin ContainerMember on ModelElement implements EnclosedElement { Container? computeCanonicalEnclosingContainer() { final enclosingElement = this.enclosingElement; - if (enclosingElement is! Extension) { - return packageGraph.findCanonicalModelElementFor(element.enclosingElement) - as Container?; - } - // TODO(jcollins-g): move Extension specific code to [Extendable] - return packageGraph.findCanonicalModelElementFor(enclosingElement.element) - as Container?; + return switch (enclosingElement) { + Extension() => + packageGraph.findCanonicalModelElementFor(enclosingElement.element), + ExtensionType() => + packageGraph.findCanonicalModelElementFor(enclosingElement.element), + _ => packageGraph.findCanonicalModelElementFor(element.enclosingElement), + } as Container?; } @override diff --git a/lib/src/model/extension_type.dart b/lib/src/model/extension_type.dart index 1f6566b537..98b9577d09 100644 --- a/lib/src/model/extension_type.dart +++ b/lib/src/model/extension_type.dart @@ -8,7 +8,8 @@ import 'package:dartdoc/src/model/comment_referable.dart'; import 'package:dartdoc/src/model/model.dart'; import 'package:meta/meta.dart'; -class ExtensionType extends InheritingContainer with Constructable { +class ExtensionType extends InheritingContainer + with Constructable, TypeImplementing { @override final ExtensionTypeElement element; @@ -38,25 +39,6 @@ class ExtensionType extends InheritingContainer with Constructable { @override bool get isSealed => false; - bool get hasPublicInterfaces => publicInterfaces.isNotEmpty; - - @override - List get publicInterfaces { - var interfaces = []; - for (var interface in element.interfaces) { - var elementType = - modelBuilder.typeFrom(interface, library) as DefinedElementType; - - if (elementType.modelElement.canonicalModelElement != null) { - interfaces.add(elementType); - continue; - } - - // TODO(srawlins): Work through intermediate, private, interfaces. - } - return interfaces; - } - @override late final List declaredFields = element.fields.map((field) { Accessor? getter, setter; @@ -79,20 +61,10 @@ class ExtensionType extends InheritingContainer with Constructable { ]; @override - // TODO(srawlins): Implement. - List get allFields => []; - - @override - // TODO(srawlins): Implement. - Iterable get inheritedMethods => []; - - @override - // TODO(srawlins): Implement. - List get inheritedOperators => []; - - @override - // TODO(srawlins): Implement. It might just be empty... - List get inheritanceChain => []; + late final List inheritanceChain = [ + this, + ...interfaces.expandInheritanceChain, + ]; @override String get filePath => '${library.dirName}/${fileStructure.fileName}'; diff --git a/lib/src/model/inheritable.dart b/lib/src/model/inheritable.dart index 50dfb454af..1403f67424 100644 --- a/lib/src/model/inheritable.dart +++ b/lib/src/model/inheritable.dart @@ -8,15 +8,16 @@ import 'package:dartdoc/src/model/attribute.dart'; import 'package:dartdoc/src/model/model.dart'; import 'package:dartdoc/src/special_elements.dart'; -/// Mixin for subclasses of ModelElement representing Elements that can be +/// Mixin for subclasses of [ModelElement] representing elements that can be /// inherited from one class to another. /// /// We can search the inheritance chain between this instance and /// [definingEnclosingContainer] in [Inheritable.canonicalEnclosingContainer], /// for the canonical [Class] closest to where this member was defined. We -/// can then know that when we find [Inheritable.modelElement] inside that [Class]'s -/// namespace, that's the one we should treat as canonical and implementors -/// of this class can use that knowledge to determine canonicalization. +/// can then know that when we find [Inheritable.modelElement] inside that +/// [Class]'s namespace, that's the one we should treat as canonical and +/// implementors of this class can use that knowledge to determine +/// canonicalization. /// /// We pick the class closest to the [definingEnclosingContainer] so that all /// children of that class inheriting the same member will point to the same @@ -89,7 +90,10 @@ mixin Inheritable on ContainerMember { // classes. if (definingEnclosingContainer.isCanonical && definingEnclosingContainer.isPublic) { - assert(definingEnclosingContainer == found); + assert( + definingEnclosingContainer == found, + 'For $element, expected $definingEnclosingContainer to be Object ' + 'or $found, but was neither.'); } if (found != null) { return found; @@ -106,13 +110,13 @@ mixin Inheritable on ContainerMember { var inheritance = [ ...(enclosingElement as InheritingContainer).inheritanceChain, ]; - var object = packageGraph.specialClasses[SpecialClass.object]; + var object = packageGraph.specialClasses[SpecialClass.object]!; + assert(definingEnclosingContainer == object || inheritance.contains(definingEnclosingContainer)); - - // Unless the code explicitly extends dart-core's Object, we won't get + // Unless the code explicitly extends dart:core's Object, we won't get // an entry here. So add it. - if (inheritance.last != object && object != null) { + if (inheritance.last != object) { inheritance.add(object); } assert(inheritance.where((e) => e == object).length == 1); diff --git a/lib/src/model/inheriting_container.dart b/lib/src/model/inheriting_container.dart index 1a7613f968..d03d36fd2e 100644 --- a/lib/src/model/inheriting_container.dart +++ b/lib/src/model/inheriting_container.dart @@ -4,9 +4,6 @@ import 'package:analyzer/dart/element/element.dart'; import 'package:analyzer/dart/element/type.dart'; -// ignore: implementation_imports -import 'package:analyzer/src/dart/element/inheritance_manager3.dart' - show InheritanceManager3; import 'package:collection/collection.dart' show IterableExtension; import 'package:dartdoc/src/element_type.dart'; import 'package:dartdoc/src/model/comment_referable.dart'; @@ -154,8 +151,9 @@ abstract class InheritingContainer extends Container } final concreteInheritenceMap = - _inheritanceManager.getInheritedConcreteMap2(element); - final inheritenceMap = _inheritanceManager.getInheritedMap2(element); + packageGraph.inheritanceManager.getInheritedConcreteMap2(element); + final inheritenceMap = + packageGraph.inheritanceManager.getInheritedMap2(element); List? inheritanceChainElements; @@ -195,8 +193,6 @@ abstract class InheritingContainer extends Container return combinedMap.values.toList(growable: false); } - static final InheritanceManager3 _inheritanceManager = InheritanceManager3(); - /// All fields defined on this container, _including inherited fields_. List get allFields { var inheritedAccessorElements = { diff --git a/lib/src/model/package_graph.dart b/lib/src/model/package_graph.dart index cc68c84293..0dceb65876 100644 --- a/lib/src/model/package_graph.dart +++ b/lib/src/model/package_graph.dart @@ -8,6 +8,9 @@ import 'package:analyzer/dart/ast/ast.dart'; import 'package:analyzer/dart/element/element.dart'; import 'package:analyzer/file_system/file_system.dart'; // ignore: implementation_imports +import 'package:analyzer/src/dart/element/inheritance_manager3.dart' + show InheritanceManager3; +// ignore: implementation_imports import 'package:analyzer/src/generated/sdk.dart' show DartSdk, SdkLibrary; // ignore: implementation_imports import 'package:analyzer/src/generated/source.dart' show Source; @@ -43,6 +46,8 @@ class PackageGraph with CommentReferable, Nameable, ModelBuilder { Package.fromPackageMeta(packageMeta, this); } + final InheritanceManager3 inheritanceManager = InheritanceManager3(); + void dispose() { // Clear out any cached tool snapshots and temporary directories. // TODO(jcollins-g): Consider ownership change for these objects diff --git a/test/templates/extension_type_test.dart b/test/templates/extension_type_test.dart index b748b2a219..ecd52eba7f 100644 --- a/test/templates/extension_type_test.dart +++ b/test/templates/extension_type_test.dart @@ -73,7 +73,13 @@ analyzer: ''', libFiles: [ d.file('lib.dart', ''' -class Base1 {} +class Base1 { + // An inherited method. + void m2() {} + + // An inherited field. + int get field1 => 1; +} class Base2 {} @@ -81,7 +87,7 @@ class Foo extends Base1, Base2 {} class FooSub extends Foo {} -extension type One(Foo e) { +extension type One(Foo it) { /// A named constructor. MyIterable.named(Foo e); @@ -109,7 +115,7 @@ extension type One(Foo e) { extension type TwoWithBase(Foo it) implements Base1, Base2 {} -extension type ThreeWithOne(FooSub it) implements One {} +extension type ThreeWithOne(FooSub it3) implements One {} '''), ], dartdocOptions: ''' @@ -216,8 +222,66 @@ dartdoc: }, ); - test('page contains instance operators', () async { + test('page contains representation field', () async { + oneLines.expectMainContentContainsAllInOrder([ + matches('

Properties

'), + matches('it'), + matches('An operator.'), + ]); + }); + + test('page contains inherited representation field', () async { + threeLines.expectMainContentContainsAllInOrder([ + matches('

Properties

'), + matches('it'), + ]); + }); + + test('page contains inherited getters', () async { + twoLines.expectMainContentContainsAllInOrder([ + matches('

Properties

'), + matches('field1'), + ]); + }); + + test('page contains instance methods', () async { oneLines.expectMainContentContainsAllInOrder([ + matches('

Methods

'), + matches('
'), + matches('m1'), + matches('An instance method.'), + ]); + }); + + test('page contains methods inherited from a class super-interface', + () async { + twoLines.expectMainContentContainsAllInOrder([ + matches('

Methods

'), + matches('
'), + matches('m2'), + ]); + }); + + test( + 'page contains methods inherited from an extension type ' + 'super-interface', () async { + threeLines.expectMainContentContainsAllInOrder([ + matches('

Methods

'), + matches('
'), + matches('m1'), + ]); + }); + + test('page contains operators', () async { + oneLines.expectMainContentContainsAllInOrder([ + matches('

Operators

'), + matches('operator >'), + matches('An operator.'), + ]); + }); + + test('page contains inherited operators', () async { + threeLines.expectMainContentContainsAllInOrder([ matches('

Operators

'), matches('operator >'), matches('An operator.'),