diff --git a/lib/src/generator/generator_frontend.dart b/lib/src/generator/generator_frontend.dart index 37143b2b7f..802cf1ef1a 100644 --- a/lib/src/generator/generator_frontend.dart +++ b/lib/src/generator/generator_frontend.dart @@ -72,66 +72,66 @@ class GeneratorFrontEnd implements Generator { var indexAccumulator = []; var multiplePackages = packageGraph.localPackages.length > 1; - void generateConstants(Container container) { + void generateConstants(Container container, Library library) { for (var constant in container.constantFields.whereDocumented) { if (!constant.isCanonical) continue; indexAccumulator.add(constant); _generatorBackend.generateProperty( - packageGraph, container.library, container, constant); + packageGraph, library, container, constant); } } - void generateConstructors(Constructable constructable) { + void generateConstructors(Constructable constructable, Library library) { for (var constructor in constructable.constructors.whereDocumented) { if (!constructor.isCanonical) continue; indexAccumulator.add(constructor); _generatorBackend.generateConstructor( - packageGraph, constructable.library, constructable, constructor); + packageGraph, library, constructable, constructor); } } - void generateInstanceMethods(Container container) { + void generateInstanceMethods(Container container, Library library) { for (var method in container.instanceMethods.whereDocumented) { if (!method.isCanonical) continue; indexAccumulator.add(method); _generatorBackend.generateMethod( - packageGraph, container.library, container, method); + packageGraph, library, container, method); } } - void generateInstanceOperators(Container container) { + void generateInstanceOperators(Container container, Library library) { for (var operator in container.instanceOperators.whereDocumented) { if (!operator.isCanonical) continue; indexAccumulator.add(operator); _generatorBackend.generateMethod( - packageGraph, container.library, container, operator); + packageGraph, library, container, operator); } } - void generateInstanceProperties(Container container) { + void generateInstanceProperties(Container container, Library library) { for (var property in container.instanceFields.whereDocumented) { if (!property.isCanonical) continue; indexAccumulator.add(property); _generatorBackend.generateProperty( - packageGraph, container.library, container, property); + packageGraph, library, container, property); } } - void generateStaticMethods(Container container) { + void generateStaticMethods(Container container, Library library) { for (var method in container.staticMethods.whereDocumented) { if (!method.isCanonical) continue; indexAccumulator.add(method); _generatorBackend.generateMethod( - packageGraph, container.library, container, method); + packageGraph, library, container, method); } } - void generateStaticProperties(Container container) { + void generateStaticProperties(Container container, Library library) { for (var property in container.variableStaticFields.whereDocumented) { if (!property.isCanonical) continue; indexAccumulator.add(property); _generatorBackend.generateProperty( - packageGraph, container.library, container, property); + packageGraph, library, container, property); } } @@ -157,88 +157,93 @@ class GeneratorFrontEnd implements Generator { indexAccumulator.add(lib); _generatorBackend.generateLibrary(packageGraph, lib); - for (var class_ in lib.classesAndExceptions.whereDocumented) { + for (var class_ in lib.classesAndExceptions.whereDocumentedIn(lib)) { indexAccumulator.add(class_); _generatorBackend.generateClass(packageGraph, lib, class_); - generateConstants(class_); - generateConstructors(class_); - generateInstanceMethods(class_); - generateInstanceOperators(class_); - generateInstanceProperties(class_); - generateStaticMethods(class_); - generateStaticProperties(class_); + var canonicalLibrary = class_.canonicalLibraryOrThrow; + generateConstants(class_, canonicalLibrary); + generateConstructors(class_, canonicalLibrary); + generateInstanceMethods(class_, canonicalLibrary); + generateInstanceOperators(class_, canonicalLibrary); + generateInstanceProperties(class_, canonicalLibrary); + generateStaticMethods(class_, canonicalLibrary); + generateStaticProperties(class_, canonicalLibrary); } - for (var extension in lib.extensions.whereDocumented) { + for (var extension in lib.extensions.whereDocumentedIn(lib)) { indexAccumulator.add(extension); _generatorBackend.generateExtension(packageGraph, lib, extension); - generateConstants(extension); - generateInstanceMethods(extension); - generateInstanceOperators(extension); - generateInstanceProperties(extension); - generateStaticMethods(extension); - generateStaticProperties(extension); + var canonicalLibrary = extension.canonicalLibraryOrThrow; + generateConstants(extension, canonicalLibrary); + generateInstanceMethods(extension, canonicalLibrary); + generateInstanceOperators(extension, canonicalLibrary); + generateInstanceProperties(extension, canonicalLibrary); + generateStaticMethods(extension, canonicalLibrary); + generateStaticProperties(extension, canonicalLibrary); } - for (var extensionType in lib.extensionTypes.whereDocumented) { + for (var extensionType in lib.extensionTypes.whereDocumentedIn(lib)) { indexAccumulator.add(extensionType); _generatorBackend.generateExtensionType( packageGraph, lib, extensionType); - generateConstants(extensionType); - generateConstructors(extensionType); - generateInstanceMethods(extensionType); - generateInstanceOperators(extensionType); - generateInstanceProperties(extensionType); - generateStaticMethods(extensionType); - generateStaticProperties(extensionType); + var canonicalLibrary = extensionType.canonicalLibraryOrThrow; + generateConstants(extensionType, canonicalLibrary); + generateConstructors(extensionType, canonicalLibrary); + generateInstanceMethods(extensionType, canonicalLibrary); + generateInstanceOperators(extensionType, canonicalLibrary); + generateInstanceProperties(extensionType, canonicalLibrary); + generateStaticMethods(extensionType, canonicalLibrary); + generateStaticProperties(extensionType, canonicalLibrary); } - for (var mixin in lib.mixins.whereDocumented) { + for (var mixin in lib.mixins.whereDocumentedIn(lib)) { indexAccumulator.add(mixin); _generatorBackend.generateMixin(packageGraph, lib, mixin); - generateConstants(mixin); - generateInstanceMethods(mixin); - generateInstanceOperators(mixin); - generateInstanceProperties(mixin); - generateStaticMethods(mixin); - generateStaticProperties(mixin); + var canonicalLibrary = mixin.canonicalLibraryOrThrow; + generateConstants(mixin, canonicalLibrary); + generateInstanceMethods(mixin, canonicalLibrary); + generateInstanceOperators(mixin, canonicalLibrary); + generateInstanceProperties(mixin, canonicalLibrary); + generateStaticMethods(mixin, canonicalLibrary); + generateStaticProperties(mixin, canonicalLibrary); } - for (var enum_ in lib.enums.whereDocumented) { + for (var enum_ in lib.enums.whereDocumentedIn(lib)) { indexAccumulator.add(enum_); _generatorBackend.generateEnum(packageGraph, lib, enum_); - generateConstants(enum_); - generateConstructors(enum_); - generateInstanceMethods(enum_); - generateInstanceOperators(enum_); - generateInstanceProperties(enum_); - generateStaticMethods(enum_); - generateStaticProperties(enum_); + var canonicalLibrary = enum_.canonicalLibraryOrThrow; + generateConstants(enum_, canonicalLibrary); + generateConstructors(enum_, canonicalLibrary); + generateInstanceMethods(enum_, canonicalLibrary); + generateInstanceOperators(enum_, canonicalLibrary); + generateInstanceProperties(enum_, canonicalLibrary); + generateStaticMethods(enum_, canonicalLibrary); + generateStaticProperties(enum_, canonicalLibrary); } - for (var constant in lib.constants.whereDocumented) { + for (var constant in lib.constants.whereDocumentedIn(lib)) { indexAccumulator.add(constant); _generatorBackend.generateTopLevelProperty( packageGraph, lib, constant); } - for (var property in lib.properties.whereDocumented) { + for (var property in lib.properties.whereDocumentedIn(lib)) { indexAccumulator.add(property); _generatorBackend.generateTopLevelProperty( packageGraph, lib, property); } - for (var function in lib.functions.whereDocumented) { + for (var function in lib.functions.whereDocumentedIn(lib)) { indexAccumulator.add(function); _generatorBackend.generateFunction(packageGraph, lib, function); } - for (var typeDef in lib.typedefs.whereDocumented) { + for (var typeDef in lib.typedefs.whereDocumentedIn(lib)) { indexAccumulator.add(typeDef); _generatorBackend.generateTypeDef(packageGraph, lib, typeDef); } diff --git a/lib/src/generator/generator_utils.dart b/lib/src/generator/generator_utils.dart index 94c4c9aef5..907a82f5cc 100644 --- a/lib/src/generator/generator_utils.dart +++ b/lib/src/generator/generator_utils.dart @@ -7,6 +7,7 @@ import 'dart:convert'; import 'package:collection/collection.dart'; import 'package:dartdoc/src/model/directives/categorization.dart'; import 'package:dartdoc/src/model/indexable.dart'; +import 'package:dartdoc/src/model/library.dart'; import 'package:dartdoc/src/model/model_element.dart'; String generateCategoryJson(Iterable categories, bool pretty) { @@ -15,7 +16,7 @@ String generateCategoryJson(Iterable categories, bool pretty) { in categories.sorted(_compareElementRepresentations)) { 'name': categorization.name, - 'qualifiedName': categorization.fullyQualifiedName, + 'qualifiedName': categorization.canonicalQualifiedName, 'href': categorization.href, // TODO(srawlins): Rename to 'kind'. 'type': categorization.kind.toString(), @@ -42,7 +43,7 @@ String generateSearchIndexJson(Iterable indexedElements, for (final item in indexedElements.sorted(_compareElementRepresentations)) { 'name': item.name, - 'qualifiedName': item.fullyQualifiedName, + 'qualifiedName': item.canonicalQualifiedName, 'href': item.href, 'kind': item.kind.index, // TODO(srawlins): Only include this for [Inheritable] items. @@ -112,9 +113,24 @@ final _htmlTagPattern = // Compares two elements, first by fully qualified name, then by kind. int _compareElementRepresentations(Indexable a, Indexable b) { - final value = compareNatural(a.fullyQualifiedName, b.fullyQualifiedName); + final value = + compareNatural(a.canonicalQualifiedName, b.canonicalQualifiedName); if (value == 0) { return compareNatural(a.kind.toString(), b.kind.toString()); } return value; } + +extension on Indexable { + /// The fully qualified name of this element, but using the canonical library, + /// if it has one. + String get canonicalQualifiedName { + var self = this; + if (self is Library) return name; + if (self is ModelElement) { + var library = self.canonicalLibrary ?? self.library; + return '${library.name}.${self.qualifiedName}'; + } + return name; + } +} diff --git a/lib/src/generator/templates.runtime_renderers.dart b/lib/src/generator/templates.runtime_renderers.dart index 83df2b9adb..a054eb4405 100644 --- a/lib/src/generator/templates.runtime_renderers.dart +++ b/lib/src/generator/templates.runtime_renderers.dart @@ -1128,28 +1128,6 @@ class _Renderer_Category extends RendererBase { parent: r); }, ), - 'fullyQualifiedName': Property( - getValue: (CT_ c) => c.fullyQualifiedName, - renderVariable: - (CT_ c, Property self, List remainingNames) { - if (remainingNames.isEmpty) { - return self.getValue(c).toString(); - } - var name = remainingNames.first; - var nextProperty = - _Renderer_String.propertyMap().getValue(name); - return nextProperty.renderVariable( - self.getValue(c) as String, - nextProperty, - [...remainingNames.skip(1)]); - }, - isNullValue: (CT_ c) => false, - renderValue: (CT_ c, RendererBase r, - List ast, StringSink sink) { - _render_String(c.fullyQualifiedName, ast, r.template, sink, - parent: r); - }, - ), 'functions': Property( getValue: (CT_ c) => c.functions, renderVariable: (CT_ c, Property self, @@ -2114,28 +2092,6 @@ class _Renderer_Constructor extends RendererBase { parent: r); }, ), - 'filePath': Property( - getValue: (CT_ c) => c.filePath, - renderVariable: - (CT_ c, Property self, List remainingNames) { - if (remainingNames.isEmpty) { - return self.getValue(c).toString(); - } - var name = remainingNames.first; - var nextProperty = - _Renderer_String.propertyMap().getValue(name); - return nextProperty.renderVariable( - self.getValue(c) as String, - nextProperty, - [...remainingNames.skip(1)]); - }, - isNullValue: (CT_ c) => false, - renderValue: (CT_ c, RendererBase r, - List ast, StringSink sink) { - _render_String(c.filePath, ast, r.template, sink, - parent: r); - }, - ), 'fullKind': Property( getValue: (CT_ c) => c.fullKind, renderVariable: @@ -3405,6 +3361,28 @@ class _Renderer_ContainerMember extends RendererBase { parent: r); }, ), + 'filePath': Property( + getValue: (CT_ c) => c.filePath, + renderVariable: + (CT_ c, Property self, List remainingNames) { + if (remainingNames.isEmpty) { + return self.getValue(c).toString(); + } + var name = remainingNames.first; + var nextProperty = + _Renderer_String.propertyMap().getValue(name); + return nextProperty.renderVariable( + self.getValue(c) as String, + nextProperty, + [...remainingNames.skip(1)]); + }, + isNullValue: (CT_ c) => false, + renderValue: (CT_ c, RendererBase r, + List ast, StringSink sink) { + _render_String(c.filePath, ast, r.template, sink, + parent: r); + }, + ), 'isExtended': Property( getValue: (CT_ c) => c.isExtended, renderVariable: (CT_ c, Property self, @@ -5771,28 +5749,6 @@ class _Renderer_Field extends RendererBase { parent: r); }, ), - 'filePath': Property( - getValue: (CT_ c) => c.filePath, - renderVariable: - (CT_ c, Property self, List remainingNames) { - if (remainingNames.isEmpty) { - return self.getValue(c).toString(); - } - var name = remainingNames.first; - var nextProperty = - _Renderer_String.propertyMap().getValue(name); - return nextProperty.renderVariable( - self.getValue(c) as String, - nextProperty, - [...remainingNames.skip(1)]); - }, - isNullValue: (CT_ c) => false, - renderValue: (CT_ c, RendererBase r, - List ast, StringSink sink) { - _render_String(c.filePath, ast, r.template, sink, - parent: r); - }, - ), 'fullkind': Property( getValue: (CT_ c) => c.fullkind, renderVariable: @@ -9195,28 +9151,6 @@ class _Renderer_Method extends RendererBase { parent: r); }, ), - 'filePath': Property( - getValue: (CT_ c) => c.filePath, - renderVariable: - (CT_ c, Property self, List remainingNames) { - if (remainingNames.isEmpty) { - return self.getValue(c).toString(); - } - var name = remainingNames.first; - var nextProperty = - _Renderer_String.propertyMap().getValue(name); - return nextProperty.renderVariable( - self.getValue(c) as String, - nextProperty, - [...remainingNames.skip(1)]); - }, - isNullValue: (CT_ c) => false, - renderValue: (CT_ c, RendererBase r, - List ast, StringSink sink) { - _render_String(c.filePath, ast, r.template, sink, - parent: r); - }, - ), 'fullkind': Property( getValue: (CT_ c) => c.fullkind, renderVariable: @@ -10066,6 +10000,29 @@ class _Renderer_ModelElement extends RendererBase { parent: r); }, ), + 'canonicalLibraryOrThrow': Property( + getValue: (CT_ c) => c.canonicalLibraryOrThrow, + renderVariable: + (CT_ c, Property self, List remainingNames) { + if (remainingNames.isEmpty) { + return self.getValue(c).toString(); + } + var name = remainingNames.first; + var nextProperty = + _Renderer_Library.propertyMap().getValue(name); + return nextProperty.renderVariable( + self.getValue(c) as Library, + nextProperty, + [...remainingNames.skip(1)]); + }, + isNullValue: (CT_ c) => false, + renderValue: (CT_ c, RendererBase r, + List ast, StringSink sink) { + _render_Library( + c.canonicalLibraryOrThrow, ast, r.template, sink, + parent: r); + }, + ), 'canonicalModelElement': Property( getValue: (CT_ c) => c.canonicalModelElement, renderVariable: @@ -10132,28 +10089,6 @@ class _Renderer_ModelElement extends RendererBase { getters: _invisibleGetters['DartdocOptionContext']!); }, ), - 'definingLibrary': Property( - getValue: (CT_ c) => c.definingLibrary, - renderVariable: - (CT_ c, Property self, List remainingNames) { - if (remainingNames.isEmpty) { - return self.getValue(c).toString(); - } - var name = remainingNames.first; - var nextProperty = - _Renderer_Library.propertyMap().getValue(name); - return nextProperty.renderVariable( - self.getValue(c) as Library, - nextProperty, - [...remainingNames.skip(1)]); - }, - isNullValue: (CT_ c) => false, - renderValue: (CT_ c, RendererBase r, - List ast, StringSink sink) { - _render_Library(c.definingLibrary, ast, r.template, sink, - parent: r); - }, - ), 'displayedCategories': Property( getValue: (CT_ c) => c.displayedCategories, renderVariable: (CT_ c, Property self, @@ -12203,7 +12138,7 @@ class _Renderer_Package extends RendererBase { } } -String renderError(PackageTemplateData context, Template template) { +String renderSearchPage(PackageTemplateData context, Template template) { var buffer = StringBuffer(); _render_PackageTemplateData(context, template.ast, template, buffer); return buffer.toString(); @@ -12447,7 +12382,7 @@ String renderIndex(PackageTemplateData context, Template template) { return buffer.toString(); } -String renderSearchPage(PackageTemplateData context, Template template) { +String renderError(PackageTemplateData context, Template template) { var buffer = StringBuffer(); _render_PackageTemplateData(context, template.ast, template, buffer); return buffer.toString(); diff --git a/lib/src/model/canonicalization.dart b/lib/src/model/canonicalization.dart index 61121ca229..e51805ff11 100644 --- a/lib/src/model/canonicalization.dart +++ b/lib/src/model/canonicalization.dart @@ -5,7 +5,7 @@ import 'package:dartdoc/src/model/model.dart'; import 'package:dartdoc/src/warnings.dart'; -/// Classes extending this class have canonicalization support in Dartdoc. +/// Canonicalization support in Dartdoc. /// /// This provides heuristic scoring to determine which library a human likely /// considers this element to be primarily 'from', and therefore, canonical. @@ -15,6 +15,7 @@ final class Canonicalization { Canonicalization(this._element); + /// Calculates a candidate for the canonical library of [_element], among [libraries]. Library calculateCanonicalCandidate(Iterable libraries) { var locationPieces = _element.element.location .toString() diff --git a/lib/src/model/category.dart b/lib/src/model/category.dart index 4a15d64d53..f2081eb62b 100644 --- a/lib/src/model/category.dart +++ b/lib/src/model/category.dart @@ -21,6 +21,8 @@ class Category TopLevelContainer, Indexable implements Documentable { + /// The package in which this category is contained. + /// /// All libraries in [libraries] must come from [package]. @override final Package package; @@ -103,9 +105,6 @@ class Category late final bool isDocumented = documentedWhere != DocumentLocation.missing && documentationFile != null; - @override - String get fullyQualifiedName => name; - String get filePath => 'topics/$name-topic.html'; @override diff --git a/lib/src/model/class.dart b/lib/src/model/class.dart index 23df4ee4cf..acbbb19a0a 100644 --- a/lib/src/model/class.dart +++ b/lib/src/model/class.dart @@ -23,7 +23,8 @@ class Class extends InheritingContainer with Constructable, MixedInTypes { ]; @override - String get sidebarPath => '${library.dirName}/$name-class-sidebar.html'; + String get sidebarPath => + '${canonicalLibraryOrThrow.dirName}/$name-class-sidebar.html'; @override late final List inheritanceChain = [ diff --git a/lib/src/model/constructor.dart b/lib/src/model/constructor.dart index 94b229cdf5..f9ab062554 100644 --- a/lib/src/model/constructor.dart +++ b/lib/src/model/constructor.dart @@ -55,10 +55,6 @@ class Constructor extends ModelElement with ContainerMember, TypeParameters { Container get enclosingElement => getModelFor(element.enclosingElement, library) as Container; - @override - String get filePath => - '${enclosingElement.library.dirName}/${enclosingElement.name}/$fileName'; - @override String get aboveSidebarPath => enclosingElement.sidebarPath; diff --git a/lib/src/model/container.dart b/lib/src/model/container.dart index 644381b5ea..a4ace6017e 100644 --- a/lib/src/model/container.dart +++ b/lib/src/model/container.dart @@ -229,10 +229,10 @@ abstract class Container extends ModelElement }; @override - Iterable get referenceParents => [definingLibrary, library]; + Iterable get referenceParents => [library]; @override - String get filePath => '${library.dirName}/$fileName'; + String get filePath => '${canonicalLibraryOrThrow.dirName}/$fileName'; /// The full path of this element's sidebar file. String get sidebarPath; diff --git a/lib/src/model/container_member.dart b/lib/src/model/container_member.dart index 80e54eae6a..8480ed5f5a 100644 --- a/lib/src/model/container_member.dart +++ b/lib/src/model/container_member.dart @@ -21,6 +21,10 @@ mixin ContainerMember on ModelElement { @override Container get enclosingElement; + @override + String get filePath => + '${canonicalLibraryOrThrow.dirName}/${enclosingElement.name}/$fileName'; + /// The container that contains this member. @protected @visibleForTesting @@ -60,7 +64,7 @@ mixin ContainerMember on ModelElement { // and resolve the pieces with different scopes. dart-lang/dartdoc#2693. // Until then, just pretend we're handling this correctly. [ - (documentationFrom.first as ModelElement).definingLibrary, + (documentationFrom.first as ModelElement).library, if (this case Field(:var getter, :var setter)) packageGraph.findCanonicalModelElementFor(getter ?? setter)?.library else diff --git a/lib/src/model/documentation_comment.dart b/lib/src/model/documentation_comment.dart index 35dbb5ef95..cbbd350e7f 100644 --- a/lib/src/model/documentation_comment.dart +++ b/lib/src/model/documentation_comment.dart @@ -9,6 +9,7 @@ import 'package:dartdoc/src/model/documentable.dart'; import 'package:dartdoc/src/model/documentation.dart'; import 'package:dartdoc/src/model/inheritable.dart'; import 'package:dartdoc/src/model/locatable.dart'; +import 'package:dartdoc/src/model/model_element.dart'; import 'package:dartdoc/src/model/source_code_mixin.dart'; import 'package:dartdoc/src/utils.dart'; import 'package:dartdoc/src/warnings.dart'; @@ -273,6 +274,10 @@ mixin DocumentationComment /// The environment variables to use when running a tool. Map _toolsEnvironment({required int invocationIndex}) { + var self = this; + var library = self is ModelElement + ? (self.canonicalLibrary ?? this.library) + : this.library; var env = { 'SOURCE_LINE': characterLocation?.lineNumber.toString(), 'SOURCE_COLUMN': characterLocation?.columnNumber.toString(), diff --git a/lib/src/model/enum.dart b/lib/src/model/enum.dart index 84e2701f92..914240b258 100644 --- a/lib/src/model/enum.dart +++ b/lib/src/model/enum.dart @@ -31,7 +31,8 @@ class Enum extends InheritingContainer with Constructable, MixedInTypes { ]; @override - String get sidebarPath => '${library.dirName}/$name-enum-sidebar.html'; + String get sidebarPath => + '${canonicalLibraryOrThrow.dirName}/$name-enum-sidebar.html'; @override Kind get kind => Kind.enum_; @@ -110,7 +111,6 @@ class EnumField extends Field { if (!identical(canonicalModelElement, this)) { return canonicalModelElement?.href; } - assert(canonicalLibrary == library); assert(canonicalEnclosingContainer == enclosingElement); // TODO(jcollins-g): EnumField should not depend on enclosingElement, but // we sort of have to while we are half-converted to [FileStructure]. diff --git a/lib/src/model/extension.dart b/lib/src/model/extension.dart index f32b03374f..4d501bb1b2 100644 --- a/lib/src/model/extension.dart +++ b/lib/src/model/extension.dart @@ -93,7 +93,8 @@ class Extension extends Container { ]; @override - String get sidebarPath => '${library.dirName}/$name-extension-sidebar.html'; + String get sidebarPath => + '${canonicalLibraryOrThrow.dirName}/$name-extension-sidebar.html'; Map? _referenceChildren; @override diff --git a/lib/src/model/extension_type.dart b/lib/src/model/extension_type.dart index f463efe3b7..3a50e9ee13 100644 --- a/lib/src/model/extension_type.dart +++ b/lib/src/model/extension_type.dart @@ -70,7 +70,7 @@ class ExtensionType extends InheritingContainer with Constructable { @override String get sidebarPath => - '${library.dirName}/$name-extension-type-sidebar.html'; + '${canonicalLibraryOrThrow.dirName}/$name-extension-type-sidebar.html'; Map? _referenceChildren; @override diff --git a/lib/src/model/field.dart b/lib/src/model/field.dart index 27c4a87275..afe87bda33 100644 --- a/lib/src/model/field.dart +++ b/lib/src/model/field.dart @@ -76,10 +76,6 @@ class Field extends ModelElement return super.documentation; } - @override - String get filePath => - '${enclosingElement.library.dirName}/${enclosingElement.name}/$fileName'; - @override String? get href { assert(!identical(canonicalModelElement, this) || diff --git a/lib/src/model/inheritable.dart b/lib/src/model/inheritable.dart index e671dc147b..6979abeeff 100644 --- a/lib/src/model/inheritable.dart +++ b/lib/src/model/inheritable.dart @@ -86,19 +86,6 @@ mixin Inheritable on ContainerMember { previousNonSkippable = c; } } - // This is still OK because we're never supposed to cloak public - // classes. - if (definingEnclosingContainer.isCanonical && - definingEnclosingContainer.isPublic) { - assert( - definingEnclosingContainer == found, - "For '$element' (${element.hashCode}) " - "(search element: '$searchElement', ${searchElement?.hashCode}, in " - "'${searchElement?.enclosingElement}'), expected " - "'$definingEnclosingContainer', which is canonical, to be '$found'," - "but was not. Here's the inheritance chain: " - '${inheritance.reversed}.'); - } if (found != null) { return found; } diff --git a/lib/src/model/inheriting_container.dart b/lib/src/model/inheriting_container.dart index 018273459f..98a9df6fa6 100644 --- a/lib/src/model/inheriting_container.dart +++ b/lib/src/model/inheriting_container.dart @@ -288,7 +288,7 @@ abstract class InheritingContainer extends Container { /// The [InheritingContainer] with the library in which [element] is defined. InheritingContainer get definingContainer => - getModelFor(element, definingLibrary) as InheritingContainer; + getModelFor(element, library) as InheritingContainer; @override InterfaceElement get element; diff --git a/lib/src/model/library.dart b/lib/src/model/library.dart index b58301d2ad..ac8a50d31b 100644 --- a/lib/src/model/library.dart +++ b/lib/src/model/library.dart @@ -21,7 +21,13 @@ class Library extends ModelElement @override final LibraryElement element; - final Set _exportedAndLocalElements; + /// The set of [Element]s declared directly in this library. + final Set _localElements; + + /// The set of [Element]s exported by this library but not directly declared + /// in this library. + final Set _exportedElements; + final String _restoredUri; @override @@ -40,7 +46,7 @@ class Library extends ModelElement static final Library sentinel = _LibrarySentinel(); Library._(this.element, PackageGraph packageGraph, this.package, - this._restoredUri, this._exportedAndLocalElements) + this._restoredUri, this._localElements, this._exportedElements) : super(sentinel, packageGraph); factory Library.fromLibraryResult(DartDocResolvedLibrary resolvedLibrary, @@ -49,10 +55,7 @@ class Library extends ModelElement var element = resolvedLibrary.element; - var exportedAndLocalElements = { - // Initialize the list of elements defined in this library and - // exported via its export directives. - ...element.exportNamespace.definedNames.values, + var localElements = { // TODO(jcollins-g): Consider switch to `element.topLevelElements`. ..._getDefinedElements(element.definingCompilationUnit), ...element.parts @@ -60,12 +63,16 @@ class Library extends ModelElement .whereType() .map((part) => part.unit) }; + var exportedElements = {...element.exportNamespace.definedNames.values} + .difference(localElements); var library = Library._( - element, - packageGraph, - package, - resolvedLibrary.element.source.uri.toString(), - exportedAndLocalElements); + element, + packageGraph, + package, + resolvedLibrary.element.source.uri.toString(), + localElements, + exportedElements, + ); package.allLibraries.add(library); return library; @@ -286,19 +293,26 @@ class Library extends ModelElement late final PackageMeta? packageMeta = packageGraph.packageMetaProvider.fromElement(element, config.sdkDir); - late final List classesAndExceptions = - _elementsOfType(); + late final List classesAndExceptions = [ + ..._localElementsOfType(), + ..._exportedElementsOfType(), + ]; @override Iterable get classes => classesAndExceptions.where((c) => !c.isErrorOrException); @override - Iterable get constants => - _variables.where((v) => v.isConst); + late final Iterable constants = [ + ..._localVariables.where((v) => v.isConst), + ..._exportedVariables.where((v) => v.isConst), + ]; @override - late final List enums = _elementsOfType(); + late final List enums = [ + ..._localElementsOfType(), + ..._exportedElementsOfType(), + ]; @override late final List exceptions = classesAndExceptions @@ -306,59 +320,91 @@ class Library extends ModelElement .toList(growable: false); @override - late final List extensions = - _elementsOfType(); + late final List extensions = [ + ..._localElementsOfType(), + ..._exportedElementsOfType(), + ]; @override - late final List extensionTypes = - _elementsOfType(); + late final List extensionTypes = [ + ..._localElementsOfType(), + ..._exportedElementsOfType(), + ]; @override - late final List functions = - _elementsOfType(); + late final List functions = [ + ..._localElementsOfType(), + ..._exportedElementsOfType(), + ]; @override - late final List mixins = _elementsOfType(); + late final List mixins = [ + ..._localElementsOfType(), + ..._exportedElementsOfType(), + ]; @override - late final List properties = - _variables.where((v) => !v.isConst).toList(growable: false); + late final List properties = [ + ..._localVariables.where((v) => !v.isConst), + ..._exportedVariables.where((v) => !v.isConst), + ]; @override - late final List typedefs = - _elementsOfType(); - - List _elementsOfType() => - _exportedAndLocalElements - .whereType() - .map((e) => packageGraph.getModelFor(e, this) as U) - .toList(growable: false); - - /// All top-level variables, including "properties" and constants. - List get _variables { - var elements = { - ..._exportedAndLocalElements.whereType(), - ..._exportedAndLocalElements + late final List typedefs = [ + ..._localElementsOfType(), + ..._exportedElementsOfType(), + ]; + + Iterable + _localElementsOfType() => + _localElements + .whereType() + .map((e) => packageGraph.getModelFor(e, this) as U); + + Iterable + _exportedElementsOfType() => + _exportedElements.whereType().map((e) { + var library = e.library; + if (library == null) { + throw StateError("The library of '$e' is null!"); + } + return packageGraph.getModelFor( + e, + packageGraph.getModelForElement(library) as Library, + ) as U; + }); + + Iterable get _localVariables { + return { + ..._localElements.whereType(), + ..._localElements .whereType() - .map((a) => a.variable2! as TopLevelVariableElement) - }; - var variables = []; - for (var element in elements) { - Accessor? getter; - var elementGetter = element.getter; - if (elementGetter != null) { - getter = packageGraph.getModelFor(elementGetter, this) as Accessor; - } - Accessor? setter; - var elementSetter = element.setter; - if (elementSetter != null) { - setter = packageGraph.getModelFor(elementSetter, this) as Accessor; - } - var me = getModelForPropertyInducingElement(element, this, - getter: getter, setter: setter); - variables.add(me as TopLevelVariable); + .map((a) => a.variable2! as TopLevelVariableElement), + }.map(_topLevelVariableFor); + } + + Iterable get _exportedVariables { + return { + ..._exportedElements.whereType(), + ..._exportedElements + .whereType() + .map((a) => a.variable2! as TopLevelVariableElement), + }.map(_topLevelVariableFor); + } + + TopLevelVariable _topLevelVariableFor(TopLevelVariableElement element) { + Accessor? getter; + var elementGetter = element.getter; + if (elementGetter != null) { + getter = packageGraph.getModelFor(elementGetter, this) as Accessor; + } + Accessor? setter; + var elementSetter = element.setter; + if (elementSetter != null) { + setter = packageGraph.getModelFor(elementSetter, this) as Accessor; } - return variables; + return getModelForPropertyInducingElement(element, this, + getter: getter, setter: setter) as TopLevelVariable; } /// All [ModelElement]s, direct and indirect, which are part of this library's diff --git a/lib/src/model/method.dart b/lib/src/model/method.dart index 0f1537d925..9f6e4012e3 100644 --- a/lib/src/model/method.dart +++ b/lib/src/model/method.dart @@ -58,10 +58,6 @@ class Method extends ModelElement Container get enclosingElement => _enclosingContainer ??= getModelFor(element.enclosingElement, library) as Container; - @override - String get filePath => - '${enclosingElement.library.dirName}/${enclosingElement.name}/$fileName'; - @override String get aboveSidebarPath => enclosingElement.sidebarPath; diff --git a/lib/src/model/mixin.dart b/lib/src/model/mixin.dart index d6d3fa9263..ab7756bd92 100644 --- a/lib/src/model/mixin.dart +++ b/lib/src/model/mixin.dart @@ -27,7 +27,8 @@ class Mixin extends InheritingContainer { String get fileName => '$name-mixin.html'; @override - String get sidebarPath => '${library.dirName}/$name-mixin-sidebar.html'; + String get sidebarPath => + '${canonicalLibraryOrThrow.dirName}/$name-mixin-sidebar.html'; @override late final List inheritanceChain = [ diff --git a/lib/src/model/model_element.dart b/lib/src/model/model_element.dart index 753adaed66..0af2b4ce24 100644 --- a/lib/src/model/model_element.dart +++ b/lib/src/model/model_element.dart @@ -129,7 +129,7 @@ abstract class ModelElement // Return the cached ModelElement if it exists. var cachedModelElement = packageGraph.allConstructedModelElements[ - ConstructedModelElementsKey(e, library, enclosingContainer)]; + ConstructedModelElementsKey(e, enclosingContainer)]; if (cachedModelElement != null) { return cachedModelElement; } @@ -215,7 +215,7 @@ abstract class ModelElement } // Return the cached ModelElement if it exists. - var key = ConstructedModelElementsKey(e, library, enclosingContainer); + var key = ConstructedModelElementsKey(e, enclosingContainer); var cachedModelElement = packageGraph.allConstructedModelElements[key]; if (cachedModelElement != null) { return cachedModelElement; @@ -256,7 +256,7 @@ abstract class ModelElement '$enclosingContainer.library != $library'); if (library != Library.sentinel && newModelElement is! Parameter) { runtimeStats.incrementAccumulator('modelElementCacheInsertion'); - var key = ConstructedModelElementsKey(e, library, enclosingContainer); + var key = ConstructedModelElementsKey(e, enclosingContainer); library.packageGraph.allConstructedModelElements[key] = newModelElement; if (newModelElement is Inheritable) { library.packageGraph.allInheritableElements @@ -378,9 +378,13 @@ abstract class ModelElement if (name.isEmpty) { return false; } - if (this is! Library && - (library == Library.sentinel || !library.isPublic)) { - return false; + if (this is! Library) { + final canonicalLibrary = this.canonicalLibrary; + var isLibraryOrCanonicalLibraryPrivate = !library.isPublic && + (canonicalLibrary == null || !canonicalLibrary.isPublic); + if (library == Library.sentinel || isLibraryOrCanonicalLibraryPrivate) { + return false; + } } if (enclosingElement is Class && !(enclosingElement as Class).isPublic) { return false; @@ -448,15 +452,17 @@ abstract class ModelElement late final String sourceHref = SourceLinker.fromElement(this).href(); - /// The library in which [element] is declared. - /// - /// This is different from [library] if this [ModelElement] is derived from - /// a library that exports [element] from another library. - Library get definingLibrary => - getModelForElement(element.library!) as Library; + Library get canonicalLibraryOrThrow { + final canonicalLibrary = this.canonicalLibrary; + if (canonicalLibrary == null) { + throw StateError( + "Expected the canonical library of '$fullyQualifiedName' to be non-null."); + } + return canonicalLibrary; + } /// A public, documented library which exports this [ModelElement], ideally in - /// [definingLibrary]'s package. + /// [library]'s package. late final Library? canonicalLibrary = () { if (element.hasPrivateName) { // Privately named elements can never have a canonical library. @@ -467,10 +473,9 @@ abstract class ModelElement assert(packageGraph.allLibrariesAdded); var definingLibraryIsLocalPublic = - packageGraph.localPublicLibraries.contains(definingLibrary); - var possibleCanonicalLibrary = definingLibraryIsLocalPublic - ? definingLibrary - : _searchForCanonicalLibrary(); + packageGraph.localPublicLibraries.contains(library); + var possibleCanonicalLibrary = + definingLibraryIsLocalPublic ? library : _searchForCanonicalLibrary(); if (possibleCanonicalLibrary != null) return possibleCanonicalLibrary; @@ -488,9 +493,9 @@ abstract class ModelElement }(); /// Searches [PackageGraph.libraryExports] for a public, documented library - /// which exports this [ModelElement], ideally in [definingLibrary]'s package. + /// which exports this [ModelElement], ideally in [library]'s package. Library? _searchForCanonicalLibrary() { - var thisAndExported = packageGraph.libraryExports[definingLibrary.element]; + var thisAndExported = packageGraph.libraryExports[library.element]; if (thisAndExported == null) { return null; } @@ -510,10 +515,9 @@ abstract class ModelElement return null; } - final candidateLibraries = thisAndExported - .where((l) => - l.isPublic && l.package.documentedWhere != DocumentLocation.missing) - .where((l) { + final candidateLibraries = thisAndExported.where((l) { + if (!l.isPublic) return false; + if (l.package.documentedWhere == DocumentLocation.missing) return false; var lookup = l.element.exportNamespace.definedNames[topLevelElementName]; return topLevelElement == (lookup is PropertyAccessorElement ? lookup.variable2 : lookup); @@ -535,7 +539,7 @@ abstract class ModelElement @override bool get isCanonical { if (!isPublic) return false; - if (library != canonicalLibrary) return false; + if (this is Library && library != canonicalLibrary) return false; // If there's no inheritance to deal with, we're done. if (this is! Inheritable) return true; final self = this as Inheritable; @@ -574,7 +578,7 @@ abstract class ModelElement @override String get fullyQualifiedName => - this is Library ? qualifiedName : '${library.name}.$qualifiedName'; + this is Library ? name : '${library.name}.$qualifiedName'; @override late final String qualifiedName = () { @@ -621,7 +625,6 @@ abstract class ModelElement if (!identical(canonicalModelElement, this)) { return canonicalModelElement?.href; } - assert(canonicalLibrary == library); var packageBaseHref = package.baseHref; return '$packageBaseHref$filePath'; } diff --git a/lib/src/model/model_function.dart b/lib/src/model/model_function.dart index d1f777bee4..255e1c319f 100644 --- a/lib/src/model/model_function.dart +++ b/lib/src/model/model_function.dart @@ -48,7 +48,7 @@ class ModelFunctionTyped extends ModelElement with TypeParameters { Library get enclosingElement => library; @override - String get filePath => '${library.dirName}/$fileName'; + String get filePath => '${canonicalLibrary?.dirName}/$fileName'; @override String get aboveSidebarPath => enclosingElement.sidebarPath; @@ -61,7 +61,6 @@ class ModelFunctionTyped extends ModelElement with TypeParameters { if (!identical(canonicalModelElement, this)) { return canonicalModelElement?.href; } - assert(canonicalLibrary == library); return '${package.baseHref}$filePath'; } @@ -78,7 +77,7 @@ class ModelFunctionTyped extends ModelElement with TypeParameters { }; @override - Iterable get referenceParents => [definingLibrary]; + Iterable get referenceParents => [library]; late final Callable modelType = getTypeFor(element.type, library) as Callable; } diff --git a/lib/src/model/nameable.dart b/lib/src/model/nameable.dart index b8229554ff..2daffabb6b 100644 --- a/lib/src/model/nameable.dart +++ b/lib/src/model/nameable.dart @@ -16,9 +16,8 @@ import 'package:dartdoc/src/model/package_graph.dart'; mixin Nameable { String get name; - /// A "fully" qualified name, mostly for use in the web search functionality, - /// and for warnings printed in the terminal; not for display use in rendered - /// HTML. + /// A "fully" qualified name, used for things like for warnings printed in the + /// terminal; not for display use in rendered HTML. /// /// "Fully" means the name is qualified through the library. For example, a /// method named 'baz' in a class named 'Bar' in a library named 'foo' has a diff --git a/lib/src/model/package_graph.dart b/lib/src/model/package_graph.dart index a8663dbd72..07fbf18440 100644 --- a/lib/src/model/package_graph.dart +++ b/lib/src/model/package_graph.dart @@ -827,12 +827,12 @@ class PackageGraph with CommentReferable, Nameable { var candidates = {}; if (lib != null) { var constructedWithKey = allConstructedModelElements[ - ConstructedModelElementsKey(element, lib, null)]; + ConstructedModelElementsKey(element, null)]; if (constructedWithKey != null) { candidates.add(constructedWithKey); } var constructedWithKeyWithClass = allConstructedModelElements[ - ConstructedModelElementsKey(element, lib, preferredClass)]; + ConstructedModelElementsKey(element, preferredClass)]; if (constructedWithKeyWithClass != null) { candidates.add(constructedWithKeyWithClass); } @@ -1044,20 +1044,17 @@ class PackageGraph with CommentReferable, Nameable { class ConstructedModelElementsKey { final Element element; - final Library library; final Container? enclosingElement; - ConstructedModelElementsKey( - this.element, this.library, this.enclosingElement); + ConstructedModelElementsKey(this.element, this.enclosingElement); @override - late final int hashCode = Object.hash(element, library, enclosingElement); + late final int hashCode = Object.hash(element, enclosingElement); @override bool operator ==(Object other) { if (other is! ConstructedModelElementsKey) return false; return other.element == element && - other.library == library && other.enclosingElement == enclosingElement; } } diff --git a/lib/src/model/prefix.dart b/lib/src/model/prefix.dart index 9c4d6d6881..e048a3a5f4 100644 --- a/lib/src/model/prefix.dart +++ b/lib/src/model/prefix.dart @@ -48,5 +48,5 @@ class Prefix extends ModelElement with HasNoPage { Map get referenceChildren => {}; @override - Iterable get referenceParents => [definingLibrary]; + Iterable get referenceParents => [library]; } diff --git a/lib/src/model/top_level_variable.dart b/lib/src/model/top_level_variable.dart index 6d90674bab..cc10f58daa 100644 --- a/lib/src/model/top_level_variable.dart +++ b/lib/src/model/top_level_variable.dart @@ -42,7 +42,7 @@ class TopLevelVariable extends ModelElement Library get enclosingElement => library; @override - String get filePath => '${library.dirName}/$fileName'; + String get filePath => '${canonicalLibraryOrThrow.dirName}/$fileName'; @override String get aboveSidebarPath => enclosingElement.sidebarPath; @@ -55,7 +55,6 @@ class TopLevelVariable extends ModelElement if (!identical(canonicalModelElement, this)) { return canonicalModelElement?.href; } - assert(canonicalLibrary == library); return '${package.baseHref}$filePath'; } @@ -80,5 +79,5 @@ class TopLevelVariable extends ModelElement Set get attributes => {...super.attributes, ...comboAttributes}; @override - Iterable get referenceParents => [definingLibrary]; + Iterable get referenceParents => [library]; } diff --git a/lib/src/model/typedef.dart b/lib/src/model/typedef.dart index 899cd59ced..e245371fb2 100644 --- a/lib/src/model/typedef.dart +++ b/lib/src/model/typedef.dart @@ -32,7 +32,7 @@ abstract class Typedef extends ModelElement String get linkedGenericParameters => _renderTypeParameters(isLinked: true); @override - String get filePath => '${library.dirName}/$fileName'; + String get filePath => '${canonicalLibraryOrThrow.dirName}/$fileName'; @override String get aboveSidebarPath => enclosingElement.sidebarPath; @@ -49,7 +49,6 @@ abstract class Typedef extends ModelElement if (!identical(canonicalModelElement, this)) { return canonicalModelElement?.href; } - assert(canonicalLibrary == library); return '${package.baseHref}$filePath'; } @@ -65,7 +64,7 @@ abstract class Typedef extends ModelElement .toList(growable: false); @override - Iterable get referenceParents => [definingLibrary]; + Iterable get referenceParents => [library]; late final Map _referenceChildren = { ...typeParameters.explicitOnCollisionWith(this), diff --git a/lib/src/model_utils.dart b/lib/src/model_utils.dart index 10a617884b..9d73320dd0 100644 --- a/lib/src/model_utils.dart +++ b/lib/src/model_utils.dart @@ -98,3 +98,9 @@ extension IterableOfDocumentableExtension extension IterableOfNameableExtension on Iterable { Iterable get wherePublic => where((e) => e.isPublic); } + +extension IterableOfModelElementExtension + on Iterable { + Iterable whereDocumentedIn(Library library) => + whereDocumented.where((e) => e.canonicalLibrary == library); +} diff --git a/test/end2end/model_special_cases_test.dart b/test/end2end/model_special_cases_test.dart index aad403fd67..3f085cbbc2 100644 --- a/test/end2end/model_special_cases_test.dart +++ b/test/end2end/model_special_cases_test.dart @@ -370,27 +370,6 @@ void main() { expect(IAmAClassWithCategories.displayedCategories, isEmpty); }); - // For flutter, we allow reexports to pick up categories from the package - // they are exposed in. - test('Verify that reexported classes pick up categories', () { - var IAmAClassWithCategoriesReexport = ginormousPackageGraph.localPackages - .firstWhere((p) => p.name == 'test_package') - .libraries - .wherePublic - .named('fake') - .classes - .wherePublic - .named('IAmAClassWithCategories'); - expect(IAmAClassWithCategoriesReexport.hasCategoryNames, isTrue); - expect(IAmAClassWithCategoriesReexport.categories, hasLength(1)); - expect(IAmAClassWithCategoriesReexport.categories.first.name, - equals('Superb')); - expect(IAmAClassWithCategoriesReexport.displayedCategories, isNotEmpty); - var category = IAmAClassWithCategoriesReexport.displayedCategories.first; - expect(category.categoryIndex, equals(0)); - expect(category.isDocumented, isTrue); - }); - test('Verify that multiple categories work correctly', () { var fakeLibrary = ginormousPackageGraph.localPackages .firstWhere((p) => p.name == 'test_package') diff --git a/test/end2end/model_test.dart b/test/end2end/model_test.dart index 5af9cef3e6..a4ec522094 100644 --- a/test/end2end/model_test.dart +++ b/test/end2end/model_test.dart @@ -520,46 +520,26 @@ void main() async { group('Tools', () { late final Class toolUser; - late final Class NonCanonicalToolUser, - CanonicalToolUser, - PrivateLibraryToolUser; late final Class ImplementingClassForTool, CanonicalPrivateInheritedToolUser; late final Method invokeTool; late final Method invokeToolNoInput; late final Method invokeToolMultipleSections; - late final Method invokeToolNonCanonical, invokeToolNonCanonicalSubclass; - late final Method invokeToolPrivateLibrary, - invokeToolPrivateLibraryOriginal; late final Method invokeToolParentDoc, invokeToolParentDocOriginal; // ignore: omit_local_variable_types final RegExp packageInvocationIndexRegexp = RegExp(r'PACKAGE_INVOCATION_INDEX: (\d+)'); setUpAll(() { - NonCanonicalToolUser = fakeLibrary.classes.named('_NonCanonicalToolUser'); - CanonicalToolUser = fakeLibrary.classes.named('CanonicalToolUser'); - PrivateLibraryToolUser = - fakeLibrary.classes.named('PrivateLibraryToolUser'); ImplementingClassForTool = fakeLibrary.classes.named('ImplementingClassForTool'); CanonicalPrivateInheritedToolUser = fakeLibrary.classes.named('CanonicalPrivateInheritedToolUser'); toolUser = exLibrary.classes.named('ToolUser'); invokeTool = toolUser.instanceMethods.named('invokeTool'); - invokeToolNonCanonical = - NonCanonicalToolUser.instanceMethods.named('invokeToolNonCanonical'); - invokeToolNonCanonicalSubclass = - CanonicalToolUser.instanceMethods.named('invokeToolNonCanonical'); invokeToolNoInput = toolUser.instanceMethods.named('invokeToolNoInput'); invokeToolMultipleSections = toolUser.instanceMethods.named('invokeToolMultipleSections'); - invokeToolPrivateLibrary = PrivateLibraryToolUser.instanceMethods - .named('invokeToolPrivateLibrary'); - invokeToolPrivateLibraryOriginal = - (invokeToolPrivateLibrary.definingEnclosingContainer as Class) - .instanceMethods - .named('invokeToolPrivateLibrary'); invokeToolParentDoc = CanonicalPrivateInheritedToolUser.instanceMethods .named('invokeToolParentDoc'); invokeToolParentDocOriginal = @@ -587,23 +567,7 @@ void main() async { }); group('does _not_ invoke a tool multiple times unnecessarily', () { - test('non-canonical subclass case', () { - expect(invokeToolNonCanonical.isCanonical, isFalse); - expect(invokeToolNonCanonicalSubclass.isCanonical, isTrue); - expect( - packageInvocationIndexRegexp - .firstMatch(invokeToolNonCanonical.documentation)! - .group(1), - equals(packageInvocationIndexRegexp - .firstMatch(invokeToolNonCanonicalSubclass.documentation)! - .group(1))); - expect( - invokeToolPrivateLibrary.documentation, isNot(contains('{@tool'))); - expect( - invokeToolPrivateLibraryOriginal.documentation, contains('{@tool')); - }); - - test('Documentation borrowed from implementer case', () { + test('for documentation inherited from the implementer', () { expect( packageInvocationIndexRegexp .firstMatch(invokeToolParentDoc.documentation)! @@ -915,17 +879,18 @@ void main() async { test('with ambiguous reexport warnings', () { final warningMsg = '(reexport_one, reexport_two) -> reexport_two (confidence 0.000)'; - // Unicorn class has a warning because two @canonicalFors cancel each other out. + // Unicorn class has a warning because two `@canonicalFor`s cancel each + // other out. expect( packageGraph.packageWarningCounter.hasWarning( AUnicornClass, PackageWarning.ambiguousReexport, warningMsg), isTrue); - // This class is ambiguous without a @canonicalFor + // This class is ambiguous without a `@canonicalFor`. expect( packageGraph.packageWarningCounter.hasWarning( YetAnotherClass, PackageWarning.ambiguousReexport, warningMsg), isTrue); - // These two classes have a @canonicalFor + // These two classes have a `@canonicalFor`. expect( packageGraph.packageWarningCounter.hasWarning( SomeClass, PackageWarning.ambiguousReexport, warningMsg), @@ -959,7 +924,7 @@ void main() async { }); test('with correct show/hide behavior', () { - expect(ADuplicateClass.definingLibrary.name, equals('shadowing_lib')); + expect(ADuplicateClass.library.name, equals('shadowing_lib')); }); }); @@ -985,7 +950,6 @@ void main() async { }); test('via reexport does not leave behind template crumbs', () { - expect(ClassTemplateOneLiner.isCanonical, isFalse); expect( ClassTemplateOneLiner.oneLineDoc, equals( @@ -2138,8 +2102,8 @@ void main() async { expect(methods[1].name, equals('addAll')); }); - test('ExtendingClass is in the right library', () { - expect(ExtendingClass.library.name, equals('two_exports')); + test('ExtendingClass is in the right canonical library', () { + expect(ExtendingClass.canonicalLibrary!.name, equals('two_exports')); }); // because both the sub and super classes, though from different libraries, @@ -2148,10 +2112,8 @@ void main() async { () { // The real implementation of BaseClass is private, but it is exported. expect(ExtendingClass.superChain.first.name, equals('BaseClass')); - expect(ExtendingClass.superChain.first.modelElement.isCanonical, - equals(false)); - expect( - ExtendingClass.superChain.first.modelElement.isPublic, equals(false)); + expect(ExtendingClass.superChain.first.modelElement.isCanonical, isTrue); + expect(ExtendingClass.superChain.first.modelElement.isPublic, isTrue); // And it should still show up in the publicSuperChain, because it is // exported. expect( @@ -2801,7 +2763,7 @@ void main() async { }); }); - group('Extension', () { + group('Extensions', () { late final Extension arm, leg, ext, fancyList, uphill; late final Extension documentOnceReexportOne, documentOnceReexportTwo; late final Extension staticFieldExtension; @@ -2856,7 +2818,6 @@ void main() async { }); test('basic canonicalization for extensions', () { - expect(documentOnceReexportOne.isCanonical, isFalse); expect( documentOnceReexportOne.href, equals(documentOnceReexportTwo.href)); expect(documentOnceReexportTwo.isCanonical, isTrue); @@ -2864,8 +2825,6 @@ void main() async { test('classes know about applicableExtensions', () { expect(apple.potentiallyApplicableExtensionsSorted, orderedEquals([ext])); - expect(string.potentiallyApplicableExtensionsSorted, - isNot(contains(documentOnceReexportOne))); expect(string.potentiallyApplicableExtensionsSorted, contains(documentOnceReexportTwo)); expect(baseTest.potentiallyApplicableExtensionsSorted, isEmpty); diff --git a/test/search_index_test.dart b/test/search_index_test.dart index 0192d5b619..23e1369f1d 100644 --- a/test/search_index_test.dart +++ b/test/search_index_test.dart @@ -6,6 +6,7 @@ import 'dart:convert'; import 'package:dartdoc/src/generator/generator_utils.dart'; import 'package:dartdoc/src/model/model.dart'; +import 'package:dartdoc/src/model_utils.dart'; import 'package:test/test.dart'; import 'package:test_reflective_loader/test_reflective_loader.dart'; @@ -50,8 +51,16 @@ class SearchIndexTest extends DartdocTestBase { ...library.packageGraph.libraries .where((l) => l.name.startsWith('dart:')), ]; + // TODO(srawlins): `Library.allModelElements` is not a great fit for this + // test, because we can only calculate the `href` properties of canonical, + // documented elements. But this filter gets us approximately what we want. + var elements = libraries.expand((library) => library.allModelElements + .whereDocumentedIn(library) + .where((e) => e is ContainerMember + ? e.enclosingElement.canonicalLibrary != null + : e.canonicalLibrary != null)); var text = generateSearchIndexJson( - libraries.expand((library) => library.allModelElements), + elements, packageOrder: actAsFlutter ? const ['flutter', 'Dart'] : const [], pretty: false, ); diff --git a/test/src/utils.dart b/test/src/utils.dart index d84ecf6ef2..7028b0d553 100644 --- a/test/src/utils.dart +++ b/test/src/utils.dart @@ -380,12 +380,12 @@ extension IterableStringExtension on Iterable { extension PackageExtension on Package { /// Gathers all extensions found across a package. - Iterable get extensions => - libraries.expand((library) => library.extensions.whereDocumented); + Iterable get extensions => libraries.wherePublic + .expand((library) => library.extensions.whereDocumented); /// Gathers all functions found across a package. - Iterable get functions => - libraries.expand((library) => library.functions.whereDocumented); + Iterable get functions => libraries.wherePublic + .expand((library) => library.functions.whereDocumented); } /// Extension methods just for tests. diff --git a/testing/test_package/lib/fake.dart b/testing/test_package/lib/fake.dart index 7b0097afc7..458cb2c3b1 100644 --- a/testing/test_package/lib/fake.dart +++ b/testing/test_package/lib/fake.dart @@ -1163,17 +1163,6 @@ abstract class MIEEThing { void operator []=(K key, V value); } -abstract class _NonCanonicalToolUser { - /// Invokes a tool without the $INPUT token or args. - /// - /// {@tool drill} - /// Some text in the drill that references [noInvokeTool]. - /// {@end-tool} - void invokeToolNonCanonical(); -} - -abstract class CanonicalToolUser extends _NonCanonicalToolUser {} - abstract class ImplementingClassForTool { /// Invokes a tool from inherited documentation via `implemented` /// diff --git a/testing/test_package/lib/src/tool.dart b/testing/test_package/lib/src/tool.dart index d08a33dd0d..e0e1e13efc 100644 --- a/testing/test_package/lib/src/tool.dart +++ b/testing/test_package/lib/src/tool.dart @@ -1,14 +1,5 @@ library test_package.tool; -abstract class PrivateLibraryToolUser { - /// Invokes a tool from a private library. - /// - /// {@tool drill} - /// Some text in the drill. - /// {@end-tool} - void invokeToolPrivateLibrary(); -} - abstract class GenericSuperProperty {} abstract class GenericSuperValue extends GenericSuperProperty {} diff --git a/tool/task.dart b/tool/task.dart index de40c21ddd..e8212ab537 100644 --- a/tool/task.dart +++ b/tool/task.dart @@ -913,15 +913,18 @@ Future validateSdkDocs() async { } print('$foundSubLibCount index.html dart: entries in categories found'); - // check for the existence of certain files/dirs - var libsCount = - _sdkDocsDir.listSync().where((fs) => fs.path.contains('dart-')).length; - if (!expectedTotalCounts.contains(libsCount)) { - throw StateError('Docs not generated for all the SDK libraries; expected ' - '$expectedTotalCounts directories, but $libsCount directories were ' - 'generated'); - } - print("Found $libsCount 'dart:' libraries"); + // Check for the existence of certain files and directories. + var libraries = + _sdkDocsDir.listSync().where((fs) => fs.path.contains('dart-')); + var libraryCount = libraries.length; + if (!expectedTotalCounts.contains(libraryCount)) { + var libraryNames = + libraries.map((l) => "'${path.basename(l.path)}'").join(', '); + throw StateError('Unexpected docs generated for SDK libraries; expected ' + '$expectedTotalCounts directories, but $libraryCount directories were ' + 'generated: $libraryNames'); + } + print("Found $libraryCount 'dart:' libraries"); var futureConstructorFile = File(path.join(_sdkDocsDir.path, 'dart-async', 'Future', 'Future.html'));