OLD | NEW |
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 library services.search_engine; | 5 library services.search_engine; |
6 | 6 |
7 import 'dart:async'; | 7 import 'dart:async'; |
8 | 8 |
9 import 'package:analyzer/dart/element/element.dart'; | 9 import 'package:analyzer/dart/element/element.dart'; |
10 import 'package:analyzer/dart/element/visitor.dart'; | |
11 import 'package:analyzer/src/dart/element/element.dart'; | |
12 import 'package:analyzer/src/generated/engine.dart' show AnalysisContext; | |
13 import 'package:analyzer/src/generated/source.dart'; | 10 import 'package:analyzer/src/generated/source.dart'; |
14 import 'package:analyzer/src/generated/utilities_general.dart'; | |
15 | 11 |
16 /** | 12 /** |
17 * Instances of the enum [MatchKind] represent the kind of reference that was | 13 * Instances of the enum [MatchKind] represent the kind of reference that was |
18 * found when a match represents a reference to an element. | 14 * found when a match represents a reference to an element. |
19 */ | 15 */ |
20 class MatchKind { | 16 class MatchKind { |
21 /** | 17 /** |
22 * A declaration of an element. | 18 * A declaration of an element. |
23 */ | 19 */ |
24 static const MatchKind DECLARATION = const MatchKind('DECLARATION'); | 20 static const MatchKind DECLARATION = const MatchKind('DECLARATION'); |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
103 * [pattern] the regular expression used to match the names of the | 99 * [pattern] the regular expression used to match the names of the |
104 * declarations to be found. | 100 * declarations to be found. |
105 */ | 101 */ |
106 Future<List<SearchMatch>> searchTopLevelDeclarations(String pattern); | 102 Future<List<SearchMatch>> searchTopLevelDeclarations(String pattern); |
107 } | 103 } |
108 | 104 |
109 /** | 105 /** |
110 * Instances of the class [SearchMatch] represent a match found by | 106 * Instances of the class [SearchMatch] represent a match found by |
111 * [SearchEngine]. | 107 * [SearchEngine]. |
112 */ | 108 */ |
113 class SearchMatch { | 109 abstract class SearchMatch { |
114 /** | |
115 * The [AnalysisContext] containing the match. | |
116 */ | |
117 final AnalysisContext context; | |
118 | |
119 /** | |
120 * The URI of the source of the library containing the match. | |
121 */ | |
122 final String libraryUri; | |
123 | |
124 /** | |
125 * The URI of the source of the unit containing the match. | |
126 */ | |
127 final String unitUri; | |
128 | |
129 /** | |
130 * The kind of the match. | |
131 */ | |
132 final MatchKind kind; | |
133 | |
134 /** | |
135 * The source range that was matched. | |
136 */ | |
137 final SourceRange sourceRange; | |
138 | |
139 /** | |
140 * Is `true` if the match is a resolved reference to some [Element]. | |
141 */ | |
142 final bool isResolved; | |
143 | |
144 /** | |
145 * Is `true` if field or method access is done using qualifier. | |
146 */ | |
147 final bool isQualified; | |
148 | |
149 Source _librarySource; | |
150 Source _unitSource; | |
151 LibraryElement _libraryElement; | |
152 Element _element; | |
153 | |
154 SearchMatch(this.context, this.libraryUri, this.unitUri, this.kind, | |
155 this.sourceRange, this.isResolved, this.isQualified); | |
156 | |
157 /** | 110 /** |
158 * Return the [Element] containing the match. Can return `null` if the unit | 111 * Return the [Element] containing the match. Can return `null` if the unit |
159 * does not exist, or its element was invalidated, or the element cannot be | 112 * does not exist, or its element was invalidated, or the element cannot be |
160 * found, etc. | 113 * found, etc. |
161 */ | 114 */ |
162 Element get element { | 115 Element get element; |
163 if (_element == null) { | |
164 CompilationUnitElement unitElement = | |
165 context.getCompilationUnitElement(unitSource, librarySource); | |
166 if (unitElement != null) { | |
167 _ContainingElementFinder finder = | |
168 new _ContainingElementFinder(sourceRange.offset); | |
169 unitElement.accept(finder); | |
170 _element = finder.containingElement; | |
171 } | |
172 } | |
173 return _element; | |
174 } | |
175 | 116 |
176 /** | 117 /** |
177 * The absolute path of the file containing the match. | 118 * The absolute path of the file containing the match. |
178 */ | 119 */ |
179 String get file => unitSource.fullName; | 120 String get file; |
180 | 121 |
181 @override | 122 /** |
182 int get hashCode { | 123 * Is `true` if field or method access is done using qualifier. |
183 return JenkinsSmiHash.hash4(libraryUri.hashCode, unitUri.hashCode, | 124 */ |
184 kind.hashCode, sourceRange.hashCode); | 125 bool get isQualified; |
185 } | 126 |
| 127 /** |
| 128 * Is `true` if the match is a resolved reference to some [Element]. |
| 129 */ |
| 130 bool get isResolved; |
| 131 |
| 132 /** |
| 133 * The kind of the match. |
| 134 */ |
| 135 MatchKind get kind; |
186 | 136 |
187 /** | 137 /** |
188 * Return the [LibraryElement] for the [libraryUri] in the [context]. | 138 * Return the [LibraryElement] for the [libraryUri] in the [context]. |
189 */ | 139 */ |
190 LibraryElement get libraryElement { | 140 LibraryElement get libraryElement; |
191 _libraryElement ??= context.getLibraryElement(librarySource); | |
192 return _libraryElement; | |
193 } | |
194 | 141 |
195 /** | 142 /** |
196 * The library [Source] of the reference. | 143 * The library [Source] of the reference. |
197 */ | 144 */ |
198 Source get librarySource { | 145 Source get librarySource; |
199 _librarySource ??= context.sourceFactory.forUri(libraryUri); | 146 |
200 return _librarySource; | 147 /** |
201 } | 148 * The source range that was matched. |
| 149 */ |
| 150 SourceRange get sourceRange; |
202 | 151 |
203 /** | 152 /** |
204 * The unit [Source] of the reference. | 153 * The unit [Source] of the reference. |
205 */ | 154 */ |
206 Source get unitSource { | 155 Source get unitSource; |
207 _unitSource ??= context.sourceFactory.forUri(unitUri); | |
208 return _unitSource; | |
209 } | |
210 | |
211 @override | |
212 bool operator ==(Object object) { | |
213 if (identical(object, this)) { | |
214 return true; | |
215 } | |
216 if (object is SearchMatch) { | |
217 return kind == object.kind && | |
218 libraryUri == object.libraryUri && | |
219 unitUri == object.unitUri && | |
220 isResolved == object.isResolved && | |
221 isQualified == object.isQualified && | |
222 sourceRange == object.sourceRange; | |
223 } | |
224 return false; | |
225 } | |
226 | |
227 @override | |
228 String toString() { | |
229 StringBuffer buffer = new StringBuffer(); | |
230 buffer.write("SearchMatch(kind="); | |
231 buffer.write(kind); | |
232 buffer.write(", libraryUri="); | |
233 buffer.write(libraryUri); | |
234 buffer.write(", unitUri="); | |
235 buffer.write(unitUri); | |
236 buffer.write(", range="); | |
237 buffer.write(sourceRange); | |
238 buffer.write(", isResolved="); | |
239 buffer.write(isResolved); | |
240 buffer.write(", isQualified="); | |
241 buffer.write(isQualified); | |
242 buffer.write(")"); | |
243 return buffer.toString(); | |
244 } | |
245 | 156 |
246 /** | 157 /** |
247 * Return elements of [matches] which has not-null elements. | 158 * Return elements of [matches] which has not-null elements. |
248 * | 159 * |
249 * When [SearchMatch.element] is not `null` we cache its value, so it cannot | 160 * When [SearchMatch.element] is not `null` we cache its value, so it cannot |
250 * become `null` later. | 161 * become `null` later. |
251 */ | 162 */ |
252 static List<SearchMatch> withNotNullElement(List<SearchMatch> matches) { | 163 static List<SearchMatch> withNotNullElement(List<SearchMatch> matches) { |
253 return matches.where((match) => match.element != null).toList(); | 164 return matches.where((match) => match.element != null).toList(); |
254 } | 165 } |
255 } | 166 } |
256 | |
257 /** | |
258 * A visitor that finds the deep-most [Element] that contains the [offset]. | |
259 */ | |
260 class _ContainingElementFinder extends GeneralizingElementVisitor { | |
261 final int offset; | |
262 Element containingElement; | |
263 | |
264 _ContainingElementFinder(this.offset); | |
265 | |
266 visitElement(Element element) { | |
267 if (element is ElementImpl) { | |
268 if (element.codeOffset != null && | |
269 element.codeOffset <= offset && | |
270 offset <= element.codeOffset + element.codeLength) { | |
271 containingElement = element; | |
272 super.visitElement(element); | |
273 } | |
274 } | |
275 } | |
276 } | |
OLD | NEW |