@@ -10,17 +10,37 @@ library dartdoc.src.model.comment_reference;
10
10
import 'dart:core' ;
11
11
12
12
import 'package:analyzer/dart/element/element.dart' ;
13
+ import 'package:analyzer/dart/element/scope.dart' ;
13
14
import 'package:dartdoc/dartdoc.dart' ;
14
15
import 'package:meta/meta.dart' ;
15
16
16
17
class ReferenceChildrenLookup {
17
18
final String lookup;
18
19
final List <String > remaining;
20
+
19
21
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
+ }
20
33
}
21
34
22
35
/// Support comment reference lookups on a Nameable object.
23
36
mixin 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
+
24
44
/// Look up a comment reference by its component parts. If [tryParents] is
25
45
/// true, try looking up the same reference in any parents of [this] .
26
46
/// Will skip over results that do not pass a given [filter] and keep
@@ -37,20 +57,14 @@ mixin CommentReferable implements Nameable {
37
57
38
58
/// Search for the reference.
39
59
for (var referenceLookup in childLookups (reference)) {
60
+ if (scope != null ) {
61
+ result = lookupViaScope (referenceLookup, filter);
62
+ if (result != null ) break ;
63
+ }
40
64
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 ;
52
67
}
53
- if (result != null ) break ;
54
68
}
55
69
// If we can't find it in children, try searching parents if allowed.
56
70
if (result == null && tryParents) {
@@ -62,6 +76,51 @@ mixin CommentReferable implements Nameable {
62
76
return result;
63
77
}
64
78
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
+
65
124
/// A list of lookups that should be attempted on children based on
66
125
/// [reference] . This allows us to deal with libraries that may have
67
126
/// separators in them. [referenceBy] stops at the first one found.
@@ -71,8 +130,10 @@ mixin CommentReferable implements Nameable {
71
130
];
72
131
73
132
/// 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] .
76
137
Map <String , CommentReferable > get referenceChildren;
77
138
78
139
/// Iterable of immediate "parents" to try resolving component parts.
0 commit comments