Rearrange comment references into a class (#1831)
diff --git a/lib/src/markdown_processor.dart b/lib/src/markdown_processor.dart
index c29222e..d8a8cac 100644
--- a/lib/src/markdown_processor.dart
+++ b/lib/src/markdown_processor.dart
@@ -199,23 +199,7 @@
if (refModelElement == null && element is ModelElement) {
Class preferredClass = _getPreferredClass(element);
refModelElement =
- _findRefElementInLibrary(codeRef, element, commentRefs, preferredClass);
- }
-
- // This is faster but does not know about libraries without imports in the
- // current context; try only as a last resort.
- // TODO(jcollins-g): make analyzer comment references dartdoc-canonicalization-aware?
- if (refModelElement == null) {
- Element refElement = _getRefElementFromCommentRefs(commentRefs, codeRef);
- if (refElement != null) {
- refModelElement = new ModelElement.fromElement(
- _getRefElementFromCommentRefs(commentRefs, codeRef),
- element.packageGraph);
- refModelElement =
- refModelElement.canonicalModelElement ?? refModelElement;
- }
- } else {
- assert(refModelElement is! Accessor);
+ new _MarkdownCommentReference(codeRef, element, commentRefs, preferredClass).computeReferredElement();
}
// Did not find it anywhere.
@@ -285,155 +269,159 @@
return null;
}
-/// Returns true if this is a constructor we should consider in
-/// _findRefElementInLibrary, or if this isn't a constructor.
-bool _ConsiderIfConstructor(String codeRef, ModelElement modelElement) {
- if (modelElement is! Constructor) return true;
- if (codeRef.contains(isConstructor)) return true;
- Constructor aConstructor = modelElement;
- List<String> codeRefParts = codeRef.split('.');
- if (codeRefParts.length > 1) {
- // Pick the last two parts, in case a specific library was part of the
- // codeRef.
- if (codeRefParts[codeRefParts.length - 1] ==
- codeRefParts[codeRefParts.length - 2]) {
- // Foobar.Foobar -- assume they really do mean the constructor for this class.
+
+/// Represents a single comment reference.
+class _MarkdownCommentReference {
+ /// The code reference text.
+ final String codeRef;
+ /// The element containing the code reference.
+ final Warnable element;
+ /// A list of [CommentReference]s from the analyzer.
+ final List<CommentReference> commentRefs;
+ /// Disambiguate inheritance with this class.
+ final Class preferredClass;
+ /// Current results. Input/output of all _find and _reduce methods.
+ Set<ModelElement> results;
+ /// codeRef with any leading constructor string, stripped.
+ String codeRefChomped;
+ /// Library associated with this element.
+ Library library;
+ /// PackageGraph associated with this element.
+ PackageGraph packageGraph;
+
+ _MarkdownCommentReference(this.codeRef, this.element, this.commentRefs, this.preferredClass) {
+ assert(element != null);
+ assert(element.packageGraph.allLibrariesAdded);
+
+ codeRefChomped = codeRef.replaceFirst(isConstructor, '');
+ library = element is ModelElement ? (element as ModelElement).library : null;
+ packageGraph = library.packageGraph;
+ }
+
+ /// Calculate reference to a ModelElement.
+ ///
+ /// Uses a series of calls to the _find* methods in this class to get one
+ /// or more possible [ModelElement] matches, then uses the _reduce* methods
+ /// in this class to try to bring it to a single ModelElement. Calls
+ /// [element.warn] for [PackageWarning.ambiguousDocReference] if there
+ /// are more than one, but does not warn otherwise.
+ ModelElement computeReferredElement() {
+ results = new Set();
+ // TODO(jcollins-g): A complex package winds up spending a lot of cycles in here. Optimize.
+ for (void Function() findMethod in [
+ // This might be an operator. Strip the operator prefix and try again.
+ _findWithoutOperatorPrefix,
+ // Oh, and someone might have some type parameters or other garbage.
+ _findWithoutTrailingIgnoreStuff,
+ // Oh, and someone might have thrown on a 'const' or 'final' in front.
+ _findWithoutLeadingIgnoreStuff,
+ // Maybe this ModelElement has parameters, and this is one of them.
+ // We don't link these, but this keeps us from emitting warnings. Be sure to
+ // get members of parameters too.
+ _findParameters,
+ // Maybe this ModelElement has type parameters, and this is one of them.
+ _findTypeParameters,
+ // This could be local to the class, look there first.
+ _findWithinTryClasses,
+ // We now need the ref element cache to keep from repeatedly searching [Package.allModelElements].
+ // But if not, look for a fully qualified match. (That only makes sense
+ // if the codeRef might be qualified, and contains periods.)
+ _findWithinRefElementCache,
+ // Only look for partially qualified matches if we didn't find a fully qualified one.
+ _findPartiallyQualifiedMatches,
+ // Only look for partially qualified matches if we didn't find a fully qualified one.
+ _findGlobalWithinRefElementCache,
+ // This could conceivably be a reference to an enum member. They don't show up in allModelElements.
+ _findEnumReferences,
+ // Use the analyzer to resolve a comment reference.
+ _findAnalyzerReferences]) {
+ findMethod();
+ // Remove any "null" objects after each step of trying to add to results.
+ // TODO(jcollins-g): Eliminate all situations where nulls can be added
+ // to the results set.
+ results.remove(null);
+ if (results.isNotEmpty) break;
+ }
+
+ if (results.length > 1) {
+ // This isn't C++. References to class methods are slightly expensive
+ // in Dart so don't build that list unless you need to.
+ for (void Function() reduceMethod in [
+ // If this name could refer to a class or a constructor, prefer the class.
+ _reducePreferClass,
+ // If a result is actually in this library, prefer that.
+ _reducePreferResultsInSameLibrary,
+ // If a result is accessible in this library, prefer that.
+ _reducePreferResultsAccessibleInSameLibrary,
+ // This may refer to an element with the same name in multiple libraries
+ // in an external package, e.g. Matrix4 in vector_math and vector_math_64.
+ // Disambiguate by attempting to figure out which of them our package
+ // is actually using by checking the import/export graph.
+ _reducePreferLibrariesInLocalImportExportGraph,
+ // If a result's fully qualified name has pieces of the comment reference,
+ // prefer that.
+ _reducePreferReferencesIncludingFullyQualifiedName,
+ // Prefer the Dart analyzer's resolution of comment references. We can't
+ // start from this because of the differences in Dartdoc canonicalization.
+ _reducePreferAnalyzerResolution,
+ ]) {
+ reduceMethod();
+ if (results.length <= 1) break;
+ }
+ }
+
+ ModelElement result;
+ // TODO(jcollins-g): further disambiguations based on package information?
+ if (results.isEmpty) {
+ result = null;
+ } else if (results.length == 1) {
+ result = results.first;
+ } else {
+ // Squelch ambiguous doc reference warnings for parameters, because we
+ // don't link those anyway.
+ if (!results.every((r) => r is Parameter)) {
+ element.warn(PackageWarning.ambiguousDocReference,
+ message:
+ "[$codeRef] => ${results.map((r) => "'${r.fullyQualifiedName}'").join(", ")}");
+ }
+ result = results.first;
+ }
+ return result;
+ }
+
+ /// Returns true if this is a constructor we should consider due to its
+ /// name and the code reference, or if this isn't a constructor. False
+ /// otherwise.
+ bool _ConsiderIfConstructor(ModelElement modelElement) {
+ // TODO(jcollins-g): Rewrite this to handle constructors in a less hacky way
+ if (modelElement is! Constructor) return true;
+ if (codeRef.contains(isConstructor)) return true;
+ Constructor aConstructor = modelElement;
+ List<String> codeRefParts = codeRef.split('.');
+ if (codeRefParts.length > 1) {
+ // Pick the last two parts, in case a specific library was part of the
+ // codeRef.
+ if (codeRefParts[codeRefParts.length - 1] ==
+ codeRefParts[codeRefParts.length - 2]) {
+ // Foobar.Foobar -- assume they really do mean the constructor for this class.
+ return true;
+ }
+ }
+ if (aConstructor.name != aConstructor.enclosingElement.name) {
+ // This isn't a default constructor so treat it like any other member.
return true;
}
- }
- if (aConstructor.name != aConstructor.enclosingElement.name) {
- // This isn't a default constructor so treat it like any other member.
- return true;
- }
- return false;
-}
-
-// Basic map of reference to ModelElement, for cases where we're searching
-// outside of scope.
-// TODO(jcollins-g): Rewrite this to handle constructors in a less hacky way
-// TODO(jcollins-g): This function breaks down naturally into many helpers, extract them
-// TODO(jcollins-g): Subcomponents of this function shouldn't be adding nulls to results, strip the
-// removes out that are gratuitous and debug the individual pieces.
-// TODO(jcollins-g): A complex package winds up spending a lot of cycles in here. Optimize.
-ModelElement _findRefElementInLibrary(String codeRef, Warnable element,
- List<CommentReference> commentRefs, Class preferredClass) {
- assert(element != null);
- assert(element.packageGraph.allLibrariesAdded);
-
- String codeRefChomped = codeRef.replaceFirst(isConstructor, '');
-
- final Library library = element is ModelElement ? element.library : null;
- final PackageGraph packageGraph = library.packageGraph;
- final Set<ModelElement> results = new Set();
-
- // This might be an operator. Strip the operator prefix and try again.
- if (results.isEmpty && codeRef.startsWith(operatorPrefix)) {
- String newCodeRef = codeRef.replaceFirst(operatorPrefix, '');
- return _findRefElementInLibrary(
- newCodeRef, element, commentRefs, preferredClass);
+ return false;
}
- // Remove any "null" objects after each step of trying to add to results.
- // TODO(jcollins-g): Eliminate all situations where nulls can be added
- // to the results set.
- results.remove(null);
- // Oh, and someone might have some type parameters or other garbage.
- if (results.isEmpty && codeRef.contains(trailingIgnoreStuff)) {
- String newCodeRef = codeRef.replaceFirst(trailingIgnoreStuff, '');
- return _findRefElementInLibrary(
- newCodeRef, element, commentRefs, preferredClass);
- }
-
- results.remove(null);
- // Oh, and someone might have thrown on a 'const' or 'final' in front.
- if (results.isEmpty && codeRef.contains(leadingIgnoreStuff)) {
- String newCodeRef = codeRef.replaceFirst(leadingIgnoreStuff, '');
- return _findRefElementInLibrary(
- newCodeRef, element, commentRefs, preferredClass);
- }
-
- // Maybe this ModelElement has parameters, and this is one of them.
- // We don't link these, but this keeps us from emitting warnings. Be sure to
- // get members of parameters too.
- // TODO(jcollins-g): link to classes that are the types of parameters, where known
- if (element is ModelElement) {
- results.addAll(element.allParameters.where((p) =>
- p.name == codeRefChomped || codeRefChomped.startsWith("${p.name}.")));
- }
-
- results.remove(null);
- // Maybe this ModelElement has type parameters, and this is one of them.
- if (results.isEmpty) {
- if (element is TypeParameters) {
- results.addAll(element.typeParameters.where((p) =>
- p.name == codeRefChomped || codeRefChomped.startsWith("${p.name}.")));
- }
- }
- results.remove(null);
-
- // This could be local to the class, look there first.
- _findWithinTryClasses(results, preferredClass, element, codeRefChomped, codeRef, packageGraph);
- results.remove(null);
-
- // We now need the ref element cache to keep from repeatedly searching [Package.allModelElements].
- // But if not, look for a fully qualified match. (That only makes sense
- // if the codeRef might be qualified, and contains periods.)
- _findWithinRefElementCache(results, codeRefChomped, packageGraph, codeRef);
- results.remove(null);
-
- // Only look for partially qualified matches if we didn't find a fully qualified one.
- _findPartiallyQualifiedMatches(results, library, codeRef, codeRefChomped, packageGraph, preferredClass);
- results.remove(null);
-
- // And if we still haven't found anything, just search the whole ball-of-wax.
- _findGlobalWithinRefElementCache(results, packageGraph, codeRefChomped);
- results.remove(null);
-
- // This could conceivably be a reference to an enum member. They don't show up in allModelElements.
- // TODO(jcollins-g): Put enum members in allModelElements with useful hrefs without blowing up other assumptions about what that means.
- // TODO(jcollins-g): This doesn't provide good warnings if an enum and class have the same name in different libraries in the same package. Fix that.
- _findEnumReferences(results, codeRefChomped, packageGraph);
- results.remove(null);
-
- if (results.length > 1) {
- // If this name could refer to a class or a constructor, prefer the class.
- if (results.any((r) => r is Class)) {
- results.removeWhere((r) => r is Constructor);
+ void _reducePreferAnalyzerResolution() {
+ Element refElement = _getRefElementFromCommentRefs(commentRefs, codeRef);
+ if (results.any((me) => me.element == refElement)) {
+ results.removeWhere((me) => me.element != refElement);
}
}
- if (results.length > 1) {
- if (results.any((r) => r.library?.packageName == library.packageName)) {
- results.removeWhere((r) => r.library?.packageName != library.packageName);
- }
- }
-
- if (results.length > 1 && element is ModelElement) {
- // Attempt to disambiguate using the library.
- // TODO(jcollins-g): we could have saved ourselves some work by using the analyzer
- // to search the namespace, somehow. Do that instead.
- if (results.any((r) => r.element.isAccessibleIn(element.library.element))) {
- results.removeWhere(
- (r) => !r.element.isAccessibleIn(element.library.element));
- }
- }
-
- if (results.length > 1) {
- // This may refer to an element with the same name in multiple libraries
- // in an external package, e.g. Matrix4 in vector_math and vector_math_64.
- // Disambiguate by attempting to figure out which of them our package
- // is actually using by checking the import/export graph.
- if (results.any(
- (r) => library.packageImportedExportedLibraries.contains(r.library))) {
- results.removeWhere(
- (r) => !library.packageImportedExportedLibraries.contains(r.library));
- }
- }
-
- // TODO(jcollins-g): This is only necessary because we had to jettison commentRefs
- // as a way to figure this out. We could reintroduce commentRefs, or we could
- // compute this via other means.
- if (results.length > 1) {
+ void _reducePreferReferencesIncludingFullyQualifiedName() {
String startName = "${element.fullyQualifiedName}.";
String realName = "${element.fullyQualifiedName}.${codeRefChomped}";
if (results.any((r) => r.fullyQualifiedName == realName)) {
@@ -444,39 +432,76 @@
}
}
- // TODO(jcollins-g): As a last resort, try disambiguation with commentRefs.
- // Maybe one of these is the same as what's resolvable with
- // the analyzer, and if so, drop the others. We can't
- // do this in reverse order because commentRefs don't know
- // about dartdoc canonicalization.
- if (results.length > 1) {
- Element refElement = _getRefElementFromCommentRefs(commentRefs, codeRef);
- if (results.any((me) => me.element == refElement)) {
- results.removeWhere((me) => me.element != refElement);
+ void _reducePreferLibrariesInLocalImportExportGraph() {
+ if (results.any(
+ (r) => library.packageImportedExportedLibraries.contains(r.library))) {
+ results.removeWhere(
+ (r) => !library.packageImportedExportedLibraries.contains(r.library));
}
}
- ModelElement result;
- // TODO(jcollins-g): further disambiguations based on package information?
- if (results.isEmpty) {
- result = null;
- } else if (results.length == 1) {
- result = results.first;
- } else {
- // Squelch ambiguous doc reference warnings for parameters, because we
- // don't link those anyway.
- if (!results.every((r) => r is Parameter)) {
- element.warn(PackageWarning.ambiguousDocReference,
- message:
- "[$codeRef] => ${results.map((r) => "'${r.fullyQualifiedName}'").join(", ")}");
+ void _reducePreferResultsAccessibleInSameLibrary() {
+ // TODO(jcollins-g): we could have saved ourselves some work by using the analyzer
+ // to search the namespace, somehow. Do that instead.
+ if (element is ModelElement && results.any((r) => r.element.isAccessibleIn((element as ModelElement).library.element))) {
+ results.removeWhere(
+ (r) => !r.element.isAccessibleIn((element as ModelElement).library.element));
}
- result = results.first;
}
- return result;
-}
-void _findEnumReferences(Set<ModelElement> results, String codeRefChomped, PackageGraph packageGraph) {
- if (results.isEmpty) {
+ void _reducePreferResultsInSameLibrary() {
+ if (results.any((r) => r.library?.packageName == library.packageName)) {
+ results.removeWhere((r) => r.library?.packageName != library.packageName);
+ }
+ }
+
+ void _reducePreferClass() {
+ if (results.any((r) => r is Class)) {
+ results.removeWhere((r) => r is Constructor);
+ }
+ }
+
+ void _findTypeParameters() {
+ if (element is TypeParameters) {
+ results.addAll((element as TypeParameters).typeParameters.where((p) =>
+ p.name == codeRefChomped || codeRefChomped.startsWith("${p.name}.")));
+ }
+ }
+
+ void _findParameters() {
+ if (element is ModelElement) {
+ results.addAll((element as ModelElement).allParameters.where((p) =>
+ p.name == codeRefChomped || codeRefChomped.startsWith("${p.name}.")));
+ }
+ }
+
+ void _findWithoutLeadingIgnoreStuff() {
+ if (codeRef.contains(leadingIgnoreStuff)) {
+ String newCodeRef = codeRef.replaceFirst(leadingIgnoreStuff, '');
+ results.add(new _MarkdownCommentReference(
+ newCodeRef, element, commentRefs, preferredClass).computeReferredElement());
+ }
+ }
+
+ void _findWithoutTrailingIgnoreStuff() {
+ if (codeRef.contains(trailingIgnoreStuff)) {
+ String newCodeRef = codeRef.replaceFirst(trailingIgnoreStuff, '');
+ results.add(new _MarkdownCommentReference(
+ newCodeRef, element, commentRefs, preferredClass).computeReferredElement());
+ }
+ }
+
+ void _findWithoutOperatorPrefix() {
+ if (codeRef.startsWith(operatorPrefix)) {
+ String newCodeRef = codeRef.replaceFirst(operatorPrefix, '');
+ results.add(new _MarkdownCommentReference(
+ newCodeRef, element, commentRefs, preferredClass).computeReferredElement());
+ }
+ }
+
+ void _findEnumReferences() {
+ // TODO(jcollins-g): Put enum members in allModelElements with useful hrefs without blowing up other assumptions about what that means.
+ // TODO(jcollins-g): This doesn't provide good warnings if an enum and class have the same name in different libraries in the same package. Fix that.
List<String> codeRefChompedParts = codeRefChomped.split('.');
if (codeRefChompedParts.length >= 2) {
String maybeEnumName = codeRefChompedParts
@@ -485,7 +510,7 @@
String maybeEnumMember = codeRefChompedParts.last;
if (packageGraph.findRefElementCache.containsKey(maybeEnumName)) {
for (final modelElement
- in packageGraph.findRefElementCache[maybeEnumName]) {
+ in packageGraph.findRefElementCache[maybeEnumName]) {
if (modelElement is Enum) {
if (modelElement.constants.any((e) => e.name == maybeEnumMember)) {
results.add(modelElement);
@@ -496,77 +521,72 @@
}
}
}
-}
-void _findGlobalWithinRefElementCache(Set<ModelElement> results, PackageGraph packageGraph, String codeRefChomped) {
- if (results.isEmpty &&
- packageGraph.findRefElementCache.containsKey(codeRefChomped)) {
- for (final modelElement
- in packageGraph.findRefElementCache[codeRefChomped]) {
- if (codeRefChomped == modelElement.fullyQualifiedNameWithoutLibrary ||
- (modelElement is Library &&
- codeRefChomped == modelElement.fullyQualifiedName)) {
- results.add(
- packageGraph.findCanonicalModelElementFor(modelElement.element));
+ void _findGlobalWithinRefElementCache() {
+ if (packageGraph.findRefElementCache.containsKey(codeRefChomped)) {
+ for (final modelElement
+ in packageGraph.findRefElementCache[codeRefChomped]) {
+ if (codeRefChomped == modelElement.fullyQualifiedNameWithoutLibrary ||
+ (modelElement is Library &&
+ codeRefChomped == modelElement.fullyQualifiedName)) {
+ results.add(
+ packageGraph.findCanonicalModelElementFor(modelElement.element));
+ }
}
}
}
-}
-void _findPartiallyQualifiedMatches(Set<ModelElement> results, Library library, String codeRef, String codeRefChomped, PackageGraph packageGraph, Class preferredClass) {
- // Only look for partially qualified matches if we didn't find a fully qualified one.
- if (results.isEmpty && library.modelElementsNameMap.containsKey(codeRefChomped)) {
- for (final modelElement in library.modelElementsNameMap[codeRefChomped]) {
- if (!_ConsiderIfConstructor(codeRef, modelElement)) continue;
- results.add(packageGraph.findCanonicalModelElementFor(
- modelElement.element,
- preferredClass: preferredClass));
+ void _findPartiallyQualifiedMatches() {
+ // Only look for partially qualified matches if we didn't find a fully qualified one.
+ if (library.modelElementsNameMap.containsKey(codeRefChomped)) {
+ for (final modelElement in library.modelElementsNameMap[codeRefChomped]) {
+ if (!_ConsiderIfConstructor(modelElement)) continue;
+ results.add(packageGraph.findCanonicalModelElementFor(
+ modelElement.element,
+ preferredClass: preferredClass));
+ }
}
}
-}
-void _findWithinRefElementCache(Set<ModelElement> results, String codeRefChomped, PackageGraph packageGraph, String codeRef) {
- // We now need the ref element cache to keep from repeatedly searching [Package.allModelElements].
- // But if not, look for a fully qualified match. (That only makes sense
- // if the codeRef might be qualified, and contains periods.)
- if (results.isEmpty &&
- codeRefChomped.contains('.') &&
- packageGraph.findRefElementCache.containsKey(codeRefChomped)) {
- for (final ModelElement modelElement
- in packageGraph.findRefElementCache[codeRefChomped]) {
- if (!_ConsiderIfConstructor(codeRef, modelElement)) continue;
- // For fully qualified matches, the original preferredClass passed
- // might make no sense. Instead, use the enclosing class from the
- // element in [_findRefElementCache], because that element's enclosing
- // class will be preferred from [codeRefChomped]'s perspective.
- results.add(packageGraph.findCanonicalModelElementFor(
- modelElement.element,
- preferredClass: modelElement.enclosingElement is Class
- ? modelElement.enclosingElement
- : null));
+ void _findWithinRefElementCache() {
+ // We now need the ref element cache to keep from repeatedly searching [Package.allModelElements].
+ // But if not, look for a fully qualified match. (That only makes sense
+ // if the codeRef might be qualified, and contains periods.)
+ if (
+ codeRefChomped.contains('.') &&
+ packageGraph.findRefElementCache.containsKey(codeRefChomped)) {
+ for (final ModelElement modelElement in packageGraph.findRefElementCache[codeRefChomped]) {
+ if (!_ConsiderIfConstructor(modelElement)) continue;
+ // For fully qualified matches, the original preferredClass passed
+ // might make no sense. Instead, use the enclosing class from the
+ // element in [packageGraph.findRefElementCache], because that element's
+ // enclosing class will be preferred from [codeRefChomped]'s perspective.
+ results.add(packageGraph.findCanonicalModelElementFor(
+ modelElement.element,
+ preferredClass: modelElement.enclosingElement is Class
+ ? modelElement.enclosingElement
+ : null));
+ }
}
}
-}
-void _findWithinTryClasses(Set<ModelElement> results, Class preferredClass, Warnable element, String codeRefChomped, String codeRef, PackageGraph packageGraph) {
- if (results.isEmpty) {
+ void _findWithinTryClasses() {
// Maybe this is local to a class.
// TODO(jcollins-g): tryClasses is a strict subset of the superclass chain. Optimize.
List<Class> tryClasses = [preferredClass];
Class realClass = tryClasses.first;
if (element is Inheritable) {
- Inheritable overriddenElement = element.overriddenElement;
+ Inheritable overriddenElement = (element as Inheritable).overriddenElement;
while (overriddenElement != null) {
tryClasses.add(
- (element.overriddenElement as EnclosedElement).enclosingElement);
+ ((element as Inheritable).overriddenElement as EnclosedElement).enclosingElement);
overriddenElement = overriddenElement.overriddenElement;
}
}
for (Class tryClass in tryClasses) {
if (tryClass != null) {
- _getResultsForClass(
- tryClass, codeRefChomped, results, codeRef, packageGraph);
+ _getResultsForClass(tryClass);
}
results.remove(null);
if (results.isNotEmpty) break;
@@ -574,96 +594,107 @@
if (results.isEmpty && realClass != null) {
for (Class superClass
- in realClass.publicSuperChain.map((et) => et.element as Class)) {
+ in realClass.publicSuperChain.map((et) => et.element as Class)) {
if (!tryClasses.contains(superClass)) {
- _getResultsForClass(
- superClass, codeRefChomped, results, codeRef, packageGraph);
+ _getResultsForClass(superClass);
}
results.remove(null);
if (results.isNotEmpty) break;
}
}
}
-}
-// _getResultsForClass assumes codeRefChomped might be a member of tryClass (inherited or not)
-// and will add to [results]
-void _getResultsForClass(Class tryClass, String codeRefChomped,
- Set<ModelElement> results, String codeRef, PackageGraph packageGraph) {
- // This might be part of the type arguments for the class, if so, add them.
- // Otherwise, search the class.
- if ((tryClass.modelType.typeArguments.map((e) => e.name))
- .contains(codeRefChomped)) {
- results.add((tryClass.modelType.typeArguments.firstWhere(
- (e) => e.name == codeRefChomped && e is DefinedElementType)
- as DefinedElementType)
- .element);
- } else {
- // People like to use 'this' in docrefs too.
- if (codeRef == 'this') {
- results.add(packageGraph.findCanonicalModelElementFor(tryClass.element));
+ void _findAnalyzerReferences() {
+ Element refElement = _getRefElementFromCommentRefs(commentRefs, codeRef);
+ if (refElement != null) {
+ ModelElement refModelElement = new ModelElement.fromElement(
+ _getRefElementFromCommentRefs(commentRefs, codeRef),
+ element.packageGraph);
+ if (refModelElement is Accessor) {
+ refModelElement = (refModelElement as Accessor).enclosingCombo;
+ }
+ refModelElement = refModelElement.canonicalModelElement ?? refModelElement;
+ results.add(refModelElement);
+ }
+ }
+
+ /// _getResultsForClass assumes codeRefChomped might be a member of tryClass (inherited or not)
+ /// and will add to [results]
+ void _getResultsForClass(Class tryClass) {
+ // This might be part of the type arguments for the class, if so, add them.
+ // Otherwise, search the class.
+ if ((tryClass.modelType.typeArguments.map((e) => e.name))
+ .contains(codeRefChomped)) {
+ results.add((tryClass.modelType.typeArguments.firstWhere(
+ (e) => e.name == codeRefChomped && e is DefinedElementType)
+ as DefinedElementType)
+ .element);
} else {
- // TODO(jcollins-g): get rid of reimplementation of identifier resolution
- // or integrate into ModelElement in a simpler way.
- List<Class> superChain = [tryClass];
- superChain.addAll(tryClass.interfaces.map((t) => t.element as Class));
- // This seems duplicitous with our caller, but the preferredClass
- // hint matters with findCanonicalModelElementFor.
- // TODO(jcollins-g): This makes our caller ~O(n^2) vs length of superChain.
- // Fortunately superChains are short, but optimize this if it matters.
- superChain.addAll(tryClass.superChain.map((t) => t.element as Class));
- List<String> codeRefParts = codeRefChomped.split('.');
- for (final c in superChain) {
- // TODO(jcollins-g): add a hash-map-enabled lookup function to Class?
- for (final modelElement in c.allModelElements) {
- if (!_ConsiderIfConstructor(codeRef, modelElement)) continue;
- String namePart = modelElement.fullyQualifiedName.split('.').last;
- if (modelElement is Accessor) {
- // TODO(jcollins-g): Individual classes should be responsible for
- // this name comparison munging.
- namePart = namePart.split('=').first;
- }
- // TODO(jcollins-g): fix operators so we can use 'name' here or similar.
- if (codeRefChomped == namePart) {
- results.add(packageGraph.findCanonicalModelElementFor(
- modelElement.element,
- preferredClass: tryClass));
- continue;
- }
- // Handle non-documented class documentation being imported into a
- // documented class when it refers to itself (with help from caller's
- // iteration on tryClasses).
- // TODO(jcollins-g): Fix partial qualifications in _findRefElementInLibrary so it can tell
- // when it is referenced from a non-documented element?
- // TODO(jcollins-g): We could probably check this early.
- if (codeRefParts.first == c.name && codeRefParts.last == namePart) {
- results.add(packageGraph.findCanonicalModelElementFor(
- modelElement.element,
- preferredClass: tryClass));
- continue;
- }
- if (modelElement is Constructor) {
- // Constructor names don't include the class, so we might miss them in the above search.
- List<String> codeRefParts = codeRefChomped.split('.');
- if (codeRefParts.length > 1) {
- String codeRefClass = codeRefParts[codeRefParts.length - 2];
- String codeRefConstructor = codeRefParts.last;
- if (codeRefClass == c.name &&
- codeRefConstructor ==
- modelElement.fullyQualifiedName.split('.').last) {
- results.add(packageGraph.findCanonicalModelElementFor(
- modelElement.element,
- preferredClass: tryClass));
- continue;
+ // People like to use 'this' in docrefs too.
+ if (codeRef == 'this') {
+ results.add(packageGraph.findCanonicalModelElementFor(tryClass.element));
+ } else {
+ // TODO(jcollins-g): get rid of reimplementation of identifier resolution
+ // or integrate into ModelElement in a simpler way.
+ List<Class> superChain = [tryClass];
+ superChain.addAll(tryClass.interfaces.map((t) => t.element as Class));
+ // This seems duplicitous with our caller, but the preferredClass
+ // hint matters with findCanonicalModelElementFor.
+ // TODO(jcollins-g): This makes our caller ~O(n^2) vs length of superChain.
+ // Fortunately superChains are short, but optimize this if it matters.
+ superChain.addAll(tryClass.superChain.map((t) => t.element as Class));
+ List<String> codeRefParts = codeRefChomped.split('.');
+ for (final c in superChain) {
+ // TODO(jcollins-g): add a hash-map-enabled lookup function to Class?
+ for (final modelElement in c.allModelElements) {
+ if (!_ConsiderIfConstructor(modelElement)) continue;
+ String namePart = modelElement.fullyQualifiedName.split('.').last;
+ if (modelElement is Accessor) {
+ // TODO(jcollins-g): Individual classes should be responsible for
+ // this name comparison munging.
+ namePart = namePart.split('=').first;
+ }
+ // TODO(jcollins-g): fix operators so we can use 'name' here or similar.
+ if (codeRefChomped == namePart) {
+ results.add(packageGraph.findCanonicalModelElementFor(
+ modelElement.element,
+ preferredClass: tryClass));
+ continue;
+ }
+ // Handle non-documented class documentation being imported into a
+ // documented class when it refers to itself (with help from caller's
+ // iteration on tryClasses).
+ // TODO(jcollins-g): Fix partial qualifications in _findRefElementInLibrary so it can tell
+ // when it is referenced from a non-documented element?
+ // TODO(jcollins-g): We could probably check this early.
+ if (codeRefParts.first == c.name && codeRefParts.last == namePart) {
+ results.add(packageGraph.findCanonicalModelElementFor(
+ modelElement.element,
+ preferredClass: tryClass));
+ continue;
+ }
+ if (modelElement is Constructor) {
+ // Constructor names don't include the class, so we might miss them in the above search.
+ if (codeRefParts.length > 1) {
+ String codeRefClass = codeRefParts[codeRefParts.length - 2];
+ String codeRefConstructor = codeRefParts.last;
+ if (codeRefClass == c.name &&
+ codeRefConstructor ==
+ modelElement.fullyQualifiedName.split('.').last) {
+ results.add(packageGraph.findCanonicalModelElementFor(
+ modelElement.element,
+ preferredClass: tryClass));
+ continue;
+ }
}
}
}
- }
- results.remove(null);
- if (results.isNotEmpty) break;
- if (c.fullyQualifiedNameWithoutLibrary == codeRefChomped) {
- results.add(c);
- break;
+ results.remove(null);
+ if (results.isNotEmpty) break;
+ if (c.fullyQualifiedNameWithoutLibrary == codeRefChomped) {
+ results.add(c);
+ break;
+ }
}
}
}