Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lib/src/generator/templates.runtime_renderers.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26267,6 +26267,7 @@ const _invisibleGetters = {
'libraries',
'libraryCount',
'libraryExports',
'libraryExports2',
'localPackages',
'localPublicLibraries',
'name',
Expand Down
82 changes: 65 additions & 17 deletions lib/src/model/canonicalization.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,30 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

// ignore_for_file: analyzer_use_new_elements

import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/element2.dart';
// ignore: implementation_imports
import 'package:analyzer/src/dart/element/element.dart';
import 'package:dartdoc/src/model/model.dart';
import 'package:dartdoc/src/warnings.dart';

const int _separatorChar = 0x3B;

/// Searches [PackageGraph.libraryExports] for a public, documented library
/// which exports this [ModelElement], ideally in its library's package.
Library? canonicalLibraryCandidate(ModelElement modelElement) {
var thisAndExported =
modelElement.packageGraph.libraryExports[modelElement.library.element];
modelElement.packageGraph.libraryExports[modelElement.library.element2];
if (thisAndExported == null) {
return null;
}

// Since we're looking for a library, find the [Element] immediately
// contained by a [CompilationUnitElement] in the tree.
var topLevelElement = modelElement.element;
while (topLevelElement.enclosingElement3 is! LibraryElement &&
topLevelElement.enclosingElement3 is! CompilationUnitElement &&
topLevelElement.enclosingElement3 != null) {
topLevelElement = topLevelElement.enclosingElement3!;
// Since we're looking for a library, go up in the tree until we find it.
var topLevelElement = modelElement.element2;
while (topLevelElement.enclosingElement2 is! LibraryElement2 &&
topLevelElement.enclosingElement2 != null) {
topLevelElement = topLevelElement.enclosingElement2!;
}
var topLevelElementName = topLevelElement.name;
var topLevelElementName = topLevelElement.name3;
if (topLevelElementName == null) {
// Any member of an unnamed extension is not public, and has no
// canonical library.
Expand All @@ -36,9 +36,9 @@ Library? canonicalLibraryCandidate(ModelElement modelElement) {
if (!l.isPublic) return false;
if (l.package.documentedWhere == DocumentLocation.missing) return false;
if (modelElement is Library) return true;
var lookup = l.element.exportNamespace.definedNames[topLevelElementName];
var lookup = l.element2.exportNamespace.definedNames2[topLevelElementName];
return topLevelElement ==
(lookup is PropertyAccessorElement ? lookup.variable2 : lookup);
(lookup is PropertyAccessorElement2 ? lookup.variable3 : lookup);
}).toList(growable: true);

if (candidateLibraries.isEmpty) {
Expand All @@ -58,7 +58,7 @@ Library? canonicalLibraryCandidate(ModelElement modelElement) {
}

var topLevelModelElement =
ModelElement.forElement(topLevelElement, modelElement.packageGraph);
ModelElement.forElement2(topLevelElement, modelElement.packageGraph);

return _Canonicalization(topLevelModelElement)
.canonicalLibraryCandidate(candidateLibraries);
Expand All @@ -74,10 +74,56 @@ final class _Canonicalization {

_Canonicalization(this._element);

/// Append an encoded form of the given [component] to the given [buffer].
void _encode(StringBuffer buffer, String component) {
var length = component.length;
for (var i = 0; i < length; i++) {
var currentChar = component.codeUnitAt(i);
if (currentChar == _separatorChar) {
buffer.writeCharCode(_separatorChar);
}
buffer.writeCharCode(currentChar);
}
}

String _getElementLocation(Element2 element) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we add a comment about where this comes from, so that we can look to the other implementation if bugs arise?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added

var components = <String>[];
Element2? ancestor = element;
while (ancestor != null) {
if (ancestor is! ElementImpl2) {
if (ancestor is LibraryElementImpl) {
components.insert(0, ancestor.identifier);
} else if (ancestor is AugmentableElement) {
components.insert(0, ancestor.identifier);
} else {
throw Exception('${ancestor.runtimeType} is not an ElementImpl2');
}
ancestor = ancestor.enclosingElement2;
} else {
components.insert(0, ancestor.identifier);
if (ancestor is LocalFunctionElementImpl) {
ancestor = (ancestor.wrappedElement.enclosingElement2
as ExecutableElementImpl)
.element;
} else {
ancestor = ancestor.enclosingElement2;
}
}
}
var buffer = StringBuffer();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not formatted?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done.

var length = components.length;
for (var i = 0; i < length; i++) {
if (i > 0) {
buffer.writeCharCode(_separatorChar);
}
_encode(buffer, components[i]);
}
return buffer.toString();
}

/// Calculates a candidate for the canonical library of [_element], among [libraries].
Library canonicalLibraryCandidate(Iterable<Library> libraries) {
var locationPieces = _element.element.location
.toString()
var locationPieces = _getElementLocation(_element.element2)
.split(_locationSplitter)
.where((s) => s.isNotEmpty)
.toSet();
Expand Down Expand Up @@ -221,3 +267,5 @@ enum _Reason {

const _Reason(this.text);
}


2 changes: 1 addition & 1 deletion lib/src/model/model_element.dart
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,7 @@ abstract class ModelElement
TypeAliasElement(aliasedType: FunctionType()) =>
FunctionTypedef(e, library, packageGraph),
TypeAliasElement()
when e.aliasedType.documentableElement is InterfaceElement =>
when e.aliasedType.documentableElement2.asElement is InterfaceElement =>
ClassTypedef(e, library, packageGraph),
TypeAliasElement() => GeneralizedTypedef(e, library, packageGraph),
MethodElement(isOperator: true) when enclosingContainer == null =>
Expand Down
47 changes: 34 additions & 13 deletions lib/src/model/package_graph.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import 'dart:collection';

import 'package:analyzer/dart/analysis/analysis_context.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/element2.dart';
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/source/source.dart';
// ignore: implementation_imports
Expand Down Expand Up @@ -510,16 +511,16 @@ class PackageGraph with CommentReferable, Nameable {
packages.where((p) => p.documentedWhere != DocumentLocation.missing);

/// A mapping from a [LibraryElement] to all of the [Library]s that export it.
Map<LibraryElement, Set<Library>> _libraryExports = {};
Map<LibraryElement2, Set<Library>> _libraryExports = {};

/// Marks [publicLibrary] as a library that exports [libraryElement] and all
/// libraries that [libraryElement] transitively exports.
///
/// [alreadyTagged] is used internall to prevent visiting in cycles.
void _tagExportsFor(
final Library publicLibrary,
final LibraryElement libraryElement, {
Set<(Library, LibraryElement)>? alreadyTagged,
final LibraryElement2 libraryElement, {
Set<(Library, LibraryElement2)>? alreadyTagged,
}) {
alreadyTagged ??= {};
var key = (publicLibrary, libraryElement);
Expand All @@ -529,14 +530,15 @@ class PackageGraph with CommentReferable, Nameable {
alreadyTagged.add(key);
// Mark that `publicLibrary` exports `libraryElement`.
_libraryExports.putIfAbsent(libraryElement, () => {}).add(publicLibrary);
for (var exportedElement
in libraryElement.definingCompilationUnit.libraryExports) {
var exportedLibrary = exportedElement.exportedLibrary;
if (exportedLibrary != null) {
// Follow the exports down; as `publicLibrary` exports `libraryElement`,
// it also exports each `exportedLibrary`.
_tagExportsFor(publicLibrary, exportedLibrary,
alreadyTagged: alreadyTagged);
for (var fragment in libraryElement.fragments) {
for (var exportedElement in fragment.libraryExports2) {
var exportedLibrary = exportedElement.exportedLibrary2;
if (exportedLibrary != null) {
// Follow the exports down; as `publicLibrary` exports `libraryElement`,
// it also exports each `exportedLibrary`.
_tagExportsFor(publicLibrary, exportedLibrary,
alreadyTagged: alreadyTagged);
}
}
}
}
Expand All @@ -545,7 +547,26 @@ class PackageGraph with CommentReferable, Nameable {

/// A mapping from a [LibraryElement] to all of the [Library]s that export it,
/// which is created if it is not yet populated.
Map<LibraryElement, Set<Library>> get libraryExports {
Map<LibraryElement2, Set<Library>> get libraryExports {
// The map must be reset if we're still in the middle of adding libraries
// (though this shouldn't happen).
if (_allLibraries.keys.length != _previousSizeOfAllLibraries) {
assert(
_previousSizeOfAllLibraries == 0,
'Re-entered `libraryExports` while building all libraries',
);
_previousSizeOfAllLibraries = _allLibraries.keys.length;
_libraryExports = {};
for (var library in publicLibraries) {
_tagExportsFor(library, library.element2);
}
}
return _libraryExports;
}

/// A mapping from a [LibraryElement] to all of the [Library]s that export it,
/// which is created if it is not yet populated.
Map<LibraryElement2, Set<Library>> get libraryExports2 {
// The map must be reset if we're still in the middle of adding libraries
// (though this shouldn't happen).
if (_allLibraries.keys.length != _previousSizeOfAllLibraries) {
Expand All @@ -556,7 +577,7 @@ class PackageGraph with CommentReferable, Nameable {
_previousSizeOfAllLibraries = _allLibraries.keys.length;
_libraryExports = {};
for (var library in publicLibraries) {
_tagExportsFor(library, library.element);
_tagExportsFor(library, library.element2);
}
}
return _libraryExports;
Expand Down
17 changes: 0 additions & 17 deletions lib/src/type_utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,10 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

// ignore_for_file: analyzer_use_new_elements

import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/element2.dart';
import 'package:analyzer/dart/element/type.dart';

extension DartTypeExtension on DartType {
/// The static element associataed with this type, where documentable, and
/// `null` otherwise.
///
/// For example, the documentable element of [DynamicType] is `null`, as there
/// is no documentation for `dynamic` which we can link to.
TypeDefiningElement? get documentableElement {
final self = this;
return switch (self) {
InterfaceType() => self.element,
NeverType() => self.element as TypeDefiningElement,
TypeParameterType() => self.element,
_ => null
};
}

/// The static element associataed with this type, where documentable, and
/// `null` otherwise.
Expand Down
34 changes: 1 addition & 33 deletions test/mustachio/builder_test_base.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,11 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

// ignore_for_file: analyzer_use_new_elements

import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/element2.dart';
import 'package:analyzer/file_system/physical_file_system.dart';
import 'package:analyzer/src/dart/analysis/analysis_context_collection.dart'
show AnalysisContextCollectionImpl;
import 'package:collection/collection.dart';
import 'package:path/path.dart' as path;
import 'package:test_descriptor/test_descriptor.dart' as d;

Expand Down Expand Up @@ -83,26 +79,6 @@ $sourceLibraryContent
root: path.join(d.sandbox, 'foo_package'));
}

Future<LibraryElement> resolveGeneratedLibrary(String libraryPath) async {
var contextCollection = AnalysisContextCollectionImpl(
includedPaths: [d.sandbox],
// TODO(jcollins-g): should we pass excluded directories here instead of
// handling it ourselves?
resourceProvider: PhysicalResourceProvider.INSTANCE,
sdkPath: sdkPath,
);
var analysisContext = contextCollection.contextFor(d.sandbox);
final libraryResult =
await analysisContext.currentSession.getResolvedLibrary(libraryPath);
if (libraryResult is! ResolvedLibraryResult) {
throw StateError(
'Expected library result to be ResolvedLibraryResult, but is '
'${libraryResult.runtimeType}');
}

return libraryResult.element;
}

Future<LibraryElement2> resolveGeneratedLibrary2(String libraryPath) async {
var contextCollection = AnalysisContextCollectionImpl(
includedPaths: [d.sandbox],
Expand All @@ -121,12 +97,4 @@ Future<LibraryElement2> resolveGeneratedLibrary2(String libraryPath) async {
}

return libraryResult.element2;
}

extension LibraryExtensions on LibraryElement {
/// Returns the top-level function in `this` library, named [name], or `null`
/// if no function is found.
FunctionElement? getTopLevelFunction(String name) => topLevelElements
.whereType<FunctionElement>()
.firstWhereOrNull((element) => element.name == name);
}
}
4 changes: 2 additions & 2 deletions tool/mustachio/codegen_runtime_renderer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ String buildRuntimeRenderers(Set<RendererSpec> specs, Uri sourceUri,
var visibleElements = specs
.map((spec) => spec.visibleTypes)
.reduce((value, element) => value.union(element))
.map((type) => type.documentableElement!)
.map((type) => type.documentableElement2.asElement!)
.toSet();
var raw = RuntimeRenderersBuilder(
sourceUri, typeProvider, typeSystem, visibleElements,
Expand Down Expand Up @@ -539,7 +539,7 @@ renderVariable:
// TODO(srawlins): Find a solution for this. We can track all of the
// concrete types substituted for `E` for example.
if (innerType is! TypeParameterType) {
var innerTypeElement = innerType.documentableElement;
var innerTypeElement = innerType.documentableElement2.asElement;
var renderFunctionName = _typeToRenderFunctionName[innerTypeElement];
String renderCall;
if (renderFunctionName == null) {
Expand Down
Loading