@@ -10,17 +10,37 @@ library dartdoc.src.model.comment_reference;
1010import 'dart:core' ;
1111
1212import 'package:analyzer/dart/element/element.dart' ;
13+ import 'package:analyzer/dart/element/scope.dart' ;
1314import 'package:dartdoc/dartdoc.dart' ;
1415import 'package:meta/meta.dart' ;
1516
1617class ReferenceChildrenLookup {
1718 final String lookup;
1819 final List <String > remaining;
20+
1921 ReferenceChildrenLookup (this .lookup, this .remaining);
22+
23+ @override
24+ String toString () => '$lookup .${remaining .join ("." )}' ;
25+ }
26+
27+ extension on Scope {
28+ /// Prefer the getter for a bundled lookup if both exist.
29+ Element lookupPreferGetter (String id) {
30+ var result = lookup (id);
31+ return result.getter ?? result.setter;
32+ }
2033}
2134
2235/// Support comment reference lookups on a Nameable object.
2336mixin CommentReferable implements Nameable {
37+ PackageGraph packageGraph;
38+
39+ /// For any [CommentReferable] where an analyzer [Scope] exists (or can
40+ /// be constructed), implement this. This will take priority over
41+ /// lookups via [referenceChildren] . Can be cached.
42+ Scope get scope => null ;
43+
2444 /// Look up a comment reference by its component parts. If [tryParents] is
2545 /// true, try looking up the same reference in any parents of [this] .
2646 /// Will skip over results that do not pass a given [filter] and keep
@@ -37,20 +57,14 @@ mixin CommentReferable implements Nameable {
3757
3858 /// Search for the reference.
3959 for (var referenceLookup in childLookups (reference)) {
60+ if (scope != null ) {
61+ result = lookupViaScope (referenceLookup, filter);
62+ if (result != null ) break ;
63+ }
4064 if (referenceChildren.containsKey (referenceLookup.lookup)) {
41- result = referenceChildren[referenceLookup.lookup];
42- if (referenceLookup.remaining.isNotEmpty) {
43- result = result? .referenceBy (referenceLookup.remaining,
44- tryParents: false , filter: filter);
45- } else if (! filter (result)) {
46- result = result? .referenceBy ([referenceLookup.lookup],
47- tryParents: false , filter: filter);
48- }
49- if (! filter (result)) {
50- result = null ;
51- }
65+ result = _lookupViaReferenceChildren (referenceLookup, filter);
66+ if (result != null ) break ;
5267 }
53- if (result != null ) break ;
5468 }
5569 // If we can't find it in children, try searching parents if allowed.
5670 if (result == null && tryParents) {
@@ -62,6 +76,51 @@ mixin CommentReferable implements Nameable {
6276 return result;
6377 }
6478
79+ /// Looks up references by [scope] , skipping over results that do not match
80+ /// the given filter.
81+ ///
82+ /// Override if [Scope.lookup] may return a [PrefixElement] or other elements
83+ /// not corresponding to a [CommentReferable] , but you still want to have
84+ /// an implementation of [scope] .
85+ CommentReferable lookupViaScope (ReferenceChildrenLookup referenceLookup,
86+ bool Function (CommentReferable ) filter) {
87+ var resultElement = scope.lookupPreferGetter (referenceLookup.lookup);
88+ if (resultElement is PrefixElement ) {
89+ assert (false ,
90+ 'PrefixElement detected, override [lookupViaScope] in subclass' );
91+ return null ;
92+ }
93+ return recurseChildrenAndFilter (referenceLookup,
94+ ModelElement .fromElement (resultElement, packageGraph), filter);
95+ }
96+
97+ CommentReferable _lookupViaReferenceChildren (
98+ ReferenceChildrenLookup referenceLookup,
99+ bool Function (CommentReferable ) filter) =>
100+ recurseChildrenAndFilter (
101+ referenceLookup, referenceChildren[referenceLookup.lookup], filter);
102+
103+ /// Given a [result] found in an implementation of [lookupViaScope] or
104+ /// [_lookupViaReferenceChildren] , recurse through children, skipping over
105+ /// results that do not match the filter.
106+ CommentReferable recurseChildrenAndFilter (
107+ ReferenceChildrenLookup referenceLookup,
108+ CommentReferable result,
109+ bool Function (CommentReferable ) filter) {
110+ assert (result != null );
111+ if (referenceLookup.remaining.isNotEmpty) {
112+ result = result.referenceBy (referenceLookup.remaining,
113+ tryParents: false , filter: filter);
114+ } else if (! filter (result)) {
115+ result = result.referenceBy ([referenceLookup.lookup],
116+ tryParents: false , filter: filter);
117+ }
118+ if (! filter (result)) {
119+ result = null ;
120+ }
121+ return result;
122+ }
123+
65124 /// A list of lookups that should be attempted on children based on
66125 /// [reference] . This allows us to deal with libraries that may have
67126 /// separators in them. [referenceBy] stops at the first one found.
@@ -71,8 +130,10 @@ mixin CommentReferable implements Nameable {
71130 ];
72131
73132 /// Map of name to the elements that are a member of [this] , but
74- /// not this model element itself.
75- /// Can be cached.
133+ /// not this model element itself. Can be cached.
134+ ///
135+ /// There is no need to duplicate references here that can be found via
136+ /// [scope] .
76137 Map <String , CommentReferable > get referenceChildren;
77138
78139 /// Iterable of immediate "parents" to try resolving component parts.
0 commit comments