diff --git a/lib/src/generator/templates.runtime_renderers.dart b/lib/src/generator/templates.runtime_renderers.dart index cc66871e53..0af6eef2bc 100644 --- a/lib/src/generator/templates.runtime_renderers.dart +++ b/lib/src/generator/templates.runtime_renderers.dart @@ -12715,7 +12715,7 @@ class _Renderer_Package extends RendererBase { } } -String renderSearchPage(PackageTemplateData context, Template template) { +String renderIndex(PackageTemplateData context, Template template) { var buffer = StringBuffer(); _render_PackageTemplateData(context, template.ast, template, buffer); return buffer.toString(); @@ -12953,7 +12953,7 @@ class _Renderer_PackageTemplateData extends RendererBase { } } -String renderIndex(PackageTemplateData context, Template template) { +String renderSearchPage(PackageTemplateData context, Template template) { var buffer = StringBuffer(); _render_PackageTemplateData(context, template.ast, template, buffer); return buffer.toString(); diff --git a/lib/src/model/accessor.dart b/lib/src/model/accessor.dart index 1cb9b48670..11a230f625 100644 --- a/lib/src/model/accessor.dart +++ b/lib/src/model/accessor.dart @@ -56,10 +56,15 @@ class Accessor extends ModelElement implements EnclosedElement { late final GetterSetterCombo definingCombo = modelBuilder.fromElement(element.variable) as GetterSetterCombo; - late final String _sourceCode = isSynthetic - ? _sourceCodeRenderer.renderSourceCode( - packageGraph.getModelNodeFor(definingCombo.element)!.sourceCode) - : super.sourceCode; + String get _sourceCode { + if (!isSynthetic) { + return super.sourceCode; + } + var modelNode = packageGraph.getModelNodeFor(definingCombo.element); + return modelNode == null + ? '' + : _sourceCodeRenderer.renderSourceCode(modelNode.sourceCode); + } @override String get sourceCode => _sourceCode; diff --git a/lib/src/model/library.dart b/lib/src/model/library.dart index d982cd15ca..bebc6577c2 100644 --- a/lib/src/model/library.dart +++ b/lib/src/model/library.dart @@ -7,7 +7,6 @@ import 'dart:collection'; import 'package:analyzer/dart/element/element.dart'; import 'package:analyzer/dart/element/scope.dart'; import 'package:analyzer/dart/element/type_system.dart'; -import 'package:analyzer/dart/element/visitor.dart'; import 'package:analyzer/source/line_info.dart'; // ignore: implementation_imports import 'package:analyzer/src/generated/sdk.dart' show SdkLibrary; @@ -16,116 +15,6 @@ import 'package:dartdoc/src/model/model.dart'; import 'package:dartdoc/src/package_meta.dart' show PackageMeta; import 'package:dartdoc/src/warnings.dart'; -/// Finds all hashable children of a given element that are defined in the -/// [LibraryElement] given at initialization. -// TODO(srawlins): Do we not need to visit the parameters in -// [ConstructorElement], [FunctionElement], [MethodElement], -// [PropertyAccessorElement], [TypeAliasElement]? -class _HashableChildLibraryElementVisitor - extends RecursiveElementVisitor { - final DartDocResolvedLibrary resolvedLibrary; - final PackageGraph packageGraph; - - _HashableChildLibraryElementVisitor(this.resolvedLibrary, this.packageGraph); - - @override - void visitClassElement(ClassElement element) { - packageGraph.populateModelNodeFor(element, resolvedLibrary); - super.visitClassElement(element); - } - - @override - void visitConstructorElement(ConstructorElement element) { - packageGraph.populateModelNodeFor(element, resolvedLibrary); - } - - @override - void visitEnumElement(EnumElement element) { - packageGraph.populateModelNodeFor(element, resolvedLibrary); - super.visitEnumElement(element); - } - - @override - void visitExtensionElement(ExtensionElement element) { - packageGraph.populateModelNodeFor(element, resolvedLibrary); - super.visitExtensionElement(element); - } - - @override - void visitFieldElement(FieldElement element) { - packageGraph.populateModelNodeFor(element, resolvedLibrary); - } - - @override - void visitFieldFormalParameterElement(FieldFormalParameterElement element) { - packageGraph.populateModelNodeFor(element, resolvedLibrary); - } - - @override - void visitFunctionElement(FunctionElement element) { - packageGraph.populateModelNodeFor(element, resolvedLibrary); - } - - @override - void visitLibraryElement(LibraryElement element) { - packageGraph.populateModelNodeFor(element, resolvedLibrary); - super.visitLibraryElement(element); - } - - @override - void visitMixinElement(MixinElement element) { - packageGraph.populateModelNodeFor(element, resolvedLibrary); - super.visitMixinElement(element); - } - - @override - void visitMultiplyDefinedElement(MultiplyDefinedElement element) { - packageGraph.populateModelNodeFor(element, resolvedLibrary); - super.visitMultiplyDefinedElement(element); - } - - @override - void visitMethodElement(MethodElement element) { - packageGraph.populateModelNodeFor(element, resolvedLibrary); - } - - @override - void visitParameterElement(ParameterElement element) { - // [ParameterElement]s without names do not provide sufficiently distinct - // hashes / comparison, so just skip them all. (dart-lang/sdk#30146) - } - - @override - void visitPrefixElement(PrefixElement element) { - packageGraph.populateModelNodeFor(element, resolvedLibrary); - } - - @override - void visitPropertyAccessorElement(PropertyAccessorElement element) { - packageGraph.populateModelNodeFor(element, resolvedLibrary); - } - - @override - void visitSuperFormalParameterElement(SuperFormalParameterElement element) { - packageGraph.populateModelNodeFor(element, resolvedLibrary); - } - - @override - void visitTopLevelVariableElement(TopLevelVariableElement element) { - packageGraph.populateModelNodeFor(element, resolvedLibrary); - } - - @override - void visitTypeAliasElement(TypeAliasElement element) { - packageGraph.populateModelNodeFor(element, resolvedLibrary); - } - - @override - void visitTypeParameterElement(TypeParameterElement element) { - packageGraph.populateModelNodeFor(element, resolvedLibrary); - } -} - class _LibrarySentinel implements Library { @override dynamic noSuchMethod(Invocation invocation) => @@ -165,10 +54,9 @@ class Library extends ModelElement factory Library.fromLibraryResult(DartDocResolvedLibrary resolvedLibrary, PackageGraph packageGraph, Package package) { - var element = resolvedLibrary.element; + packageGraph.gatherModelNodes(resolvedLibrary); - _HashableChildLibraryElementVisitor(resolvedLibrary, packageGraph) - .visitLibraryElement(element); + var element = resolvedLibrary.element; var exportedAndLocalElements = { // Initialize the list of elements defined in this library and diff --git a/lib/src/model/model_element.dart b/lib/src/model/model_element.dart index 167e9756d4..b3840db1d8 100644 --- a/lib/src/model/model_element.dart +++ b/lib/src/model/model_element.dart @@ -385,7 +385,7 @@ abstract class ModelElement extends Canonicalization Iterable get displayedCategories => const []; @override - late final ModelNode? modelNode = packageGraph.getModelNodeFor(element); + ModelNode? get modelNode => packageGraph.getModelNodeFor(element); /// This element's [Annotation]s. /// diff --git a/lib/src/model/package_builder.dart b/lib/src/model/package_builder.dart index c6bc71d127..70259ee554 100644 --- a/lib/src/model/package_builder.dart +++ b/lib/src/model/package_builder.dart @@ -16,8 +16,6 @@ import 'package:analyzer/src/context/builder.dart' show EmbedderYamlLocator; import 'package:analyzer/src/dart/analysis/analysis_context_collection.dart' show AnalysisContextCollectionImpl; // ignore: implementation_imports -import 'package:analyzer/src/dart/ast/utilities.dart' show NodeLocator2; -// ignore: implementation_imports import 'package:analyzer/src/dart/sdk/sdk.dart' show EmbedderSdk, FolderBasedDartSdk; // ignore: implementation_imports @@ -479,27 +477,9 @@ class PubPackageBuilder implements PackageBuilder { /// the library. class DartDocResolvedLibrary { final LibraryElement element; - final Map _units; + final List units; DartDocResolvedLibrary(ResolvedLibraryResult result) : element = result.element, - _units = { - for (var unit in result.units) unit.path: unit.unit, - }; - - /// Returns the [AstNode] for a given [Element]. - /// - /// Uses a precomputed map of `element.source.fullName` to [CompilationUnit] - /// to avoid linear traversal in - /// `ResolvedLibraryElementImpl.getElementDeclaration`. - AstNode? getAstNode(Element element) { - var fullName = element.source?.fullName; - if (fullName != null && !element.isSynthetic && element.nameOffset != -1) { - var unit = _units[fullName]; - if (unit != null) { - return NodeLocator2(element.nameOffset).searchWithin(unit); - } - } - return null; - } + units = result.units.map((unit) => unit.unit).toList(); } diff --git a/lib/src/model/package_graph.dart b/lib/src/model/package_graph.dart index fb5ff2028c..1dc5e989c8 100644 --- a/lib/src/model/package_graph.dart +++ b/lib/src/model/package_graph.dart @@ -4,6 +4,7 @@ import 'dart:collection'; +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 @@ -170,15 +171,76 @@ class PackageGraph with CommentReferable, Nameable, ModelBuilder { // than once for them. final Map _modelNodes = {}; - void populateModelNodeFor( - Element element, DartDocResolvedLibrary resolvedLibrary) { + /// Populate's [_modelNodes] with elements in [resolvedLibrary]. + /// + /// This is done as [Library] model objects are created, while we are holding + /// onto [resolvedLibrary] objects. + // TODO(srawlins): I suspect we populate this mapping with way too many + // objects, too eagerly. They are only needed when writing the source code of + // an element to HTML, and maybe for resolving doc comments. We should find a + // way to get this data only when needed. But it's not immediately obvious to + // me how, because the data is on AST nodes, not the element model. + void gatherModelNodes(DartDocResolvedLibrary resolvedLibrary) { + for (var unit in resolvedLibrary.units) { + for (var declaration in unit.declarations) { + _populateModelNodeFor(declaration); + switch (declaration) { + case ClassDeclaration(): + for (var member in declaration.members) { + _populateModelNodeFor(member); + } + case EnumDeclaration(): + if (declaration.declaredElement?.isPublic ?? false) { + for (var member in declaration.members) { + _populateModelNodeFor(member); + } + } + case MixinDeclaration(): + for (var member in declaration.members) { + _populateModelNodeFor(member); + } + case ExtensionDeclaration(): + if (declaration.declaredElement?.isPublic ?? false) { + for (var member in declaration.members) { + _populateModelNodeFor(member); + } + } + case ExtensionTypeDeclaration(): + if (declaration.declaredElement?.isPublic ?? false) { + for (var member in declaration.members) { + _populateModelNodeFor(member); + } + } + } + } + } + } + + void _populateModelNodeFor(Declaration declaration) { + if (declaration is FieldDeclaration) { + var fields = declaration.fields.variables; + for (var field in fields) { + var element = field.declaredElement!; + _modelNodes.putIfAbsent( + element, () => ModelNode(field, element, resourceProvider)); + } + return; + } + if (declaration is TopLevelVariableDeclaration) { + var fields = declaration.variables.variables; + for (var field in fields) { + var element = field.declaredElement!; + _modelNodes.putIfAbsent( + element, () => ModelNode(field, element, resourceProvider)); + } + return; + } + var element = declaration.declaredElement!; _modelNodes.putIfAbsent( - element, - () => ModelNode( - resolvedLibrary.getAstNode(element), element, resourceProvider)); + element, () => ModelNode(declaration, element, resourceProvider)); } - ModelNode? getModelNodeFor(Element? element) => _modelNodes[element!]; + ModelNode? getModelNodeFor(Element element) => _modelNodes[element]; late SpecialClasses specialClasses;