OLD | NEW |
| (Empty) |
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 | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 library services.index; | |
6 | |
7 import 'dart:async'; | |
8 | |
9 import 'package:analyzer/src/generated/ast.dart'; | |
10 import 'package:analyzer/src/generated/element.dart'; | |
11 import 'package:analyzer/src/generated/engine.dart'; | |
12 import 'package:analyzer/src/generated/html.dart'; | |
13 import 'package:analyzer/src/generated/source.dart'; | |
14 | |
15 | |
16 /** | |
17 * The interface [Index] defines the behavior of objects that maintain an index | |
18 * storing relations between [Element]s. | |
19 * | |
20 * Any modification operations are executed before any read operation. | |
21 * There is no guarantee about the order in which the [Future]s for read | |
22 * operations will complete. | |
23 */ | |
24 abstract class Index { | |
25 /** | |
26 * Answers index statistics. | |
27 */ | |
28 String get statistics; | |
29 | |
30 /** | |
31 * Removes from the index all the information. | |
32 */ | |
33 void clear(); | |
34 | |
35 /** | |
36 * Asynchronously returns a list containing all of the locations of the | |
37 * elements that have the given [relationship] with the given [element]. | |
38 * | |
39 * For example, if the element represents a function and the relationship is | |
40 * the `is-invoked-by` relationship, then the locations will be all of the | |
41 * places where the function is invoked. | |
42 * | |
43 * [element] - the element that has the relationship with the locations to be | |
44 * returned. | |
45 * | |
46 * [relationship] - the relationship between the given element and the | |
47 * locations to be returned. | |
48 */ | |
49 Future<List<Location>> getRelationships(Element element, | |
50 Relationship relationship); | |
51 | |
52 /** | |
53 * Processes the given [HtmlUnit] in order to record the relationships. | |
54 * | |
55 * [context] - the [AnalysisContext] in which [HtmlUnit] was resolved. | |
56 * [unit] - the [HtmlUnit] being indexed. | |
57 */ | |
58 void indexHtmlUnit(AnalysisContext context, HtmlUnit unit); | |
59 | |
60 /** | |
61 * Processes the given [CompilationUnit] in order to record the relationships. | |
62 * | |
63 * [context] - the [AnalysisContext] in which [CompilationUnit] was resolved. | |
64 * [unit] - the [CompilationUnit] being indexed. | |
65 */ | |
66 void indexUnit(AnalysisContext context, CompilationUnit unit); | |
67 | |
68 /** | |
69 * Removes from the index all of the information associated with [context]. | |
70 * | |
71 * This method should be invoked when [context] is disposed. | |
72 */ | |
73 void removeContext(AnalysisContext context); | |
74 | |
75 /** | |
76 * Removes from the index all of the information associated with elements or | |
77 * locations in [source]. This includes relationships between an element in | |
78 * [source] and any other locations, relationships between any other elements | |
79 * and a location within [source]. | |
80 * | |
81 * This method should be invoked when [source] is no longer part of the code | |
82 * base. | |
83 * | |
84 * [context] - the [AnalysisContext] in which [source] being removed | |
85 * [source] - the [Source] being removed | |
86 */ | |
87 void removeSource(AnalysisContext context, Source source); | |
88 | |
89 /** | |
90 * Removes from the index all of the information associated with elements or | |
91 * locations in the given sources. This includes relationships between an | |
92 * element in the given sources and any other locations, relationships between | |
93 * any other elements and a location within the given sources. | |
94 * | |
95 * This method should be invoked when multiple sources are no longer part of | |
96 * the code base. | |
97 * | |
98 * [context] - the [AnalysisContext] in which [Source]s being removed. | |
99 * [container] - the [SourceContainer] holding the sources being removed. | |
100 */ | |
101 void removeSources(AnalysisContext context, SourceContainer container); | |
102 | |
103 /** | |
104 * Starts the index. | |
105 * Should be called before any other method. | |
106 */ | |
107 void run(); | |
108 | |
109 /** | |
110 * Stops the index. | |
111 * After calling this method operations may not be executed. | |
112 */ | |
113 void stop(); | |
114 } | |
115 | |
116 | |
117 /** | |
118 * Constants used when populating and accessing the index. | |
119 */ | |
120 class IndexConstants { | |
121 /** | |
122 * Left: an Angular element. | |
123 * Is referenced at. | |
124 * Right: location. | |
125 */ | |
126 static final Relationship ANGULAR_REFERENCE = | |
127 Relationship.getRelationship("angular-reference"); | |
128 | |
129 /** | |
130 * Left: an Angular component. | |
131 * Is closed "/>" at. | |
132 * Right: location. | |
133 */ | |
134 static final Relationship ANGULAR_CLOSING_TAG_REFERENCE = | |
135 Relationship.getRelationship("angular-closing-tag-reference"); | |
136 | |
137 /** | |
138 * Left: the Universe or a Library. | |
139 * Defines an Element. | |
140 * Right: an Element declaration. | |
141 */ | |
142 static final Relationship DEFINES = Relationship.getRelationship("defines"); | |
143 | |
144 /** | |
145 * Left: class. | |
146 * Is extended by. | |
147 * Right: other class declaration. | |
148 */ | |
149 static final Relationship IS_EXTENDED_BY = | |
150 Relationship.getRelationship("is-extended-by"); | |
151 | |
152 /** | |
153 * Left: class. | |
154 * Is implemented by. | |
155 * Right: other class declaration. | |
156 */ | |
157 static final Relationship IS_IMPLEMENTED_BY = | |
158 Relationship.getRelationship("is-implemented-by"); | |
159 | |
160 /** | |
161 * Left: class. | |
162 * Is mixed into. | |
163 * Right: other class declaration. | |
164 */ | |
165 static final Relationship IS_MIXED_IN_BY = | |
166 Relationship.getRelationship("is-mixed-in-by"); | |
167 | |
168 /** | |
169 * Left: local variable, parameter. | |
170 * Is read at. | |
171 * Right: location. | |
172 */ | |
173 static final Relationship IS_READ_BY = | |
174 Relationship.getRelationship("is-read-by"); | |
175 | |
176 /** | |
177 * Left: local variable, parameter. | |
178 * Is both read and written at. | |
179 * Right: location. | |
180 */ | |
181 static final Relationship IS_READ_WRITTEN_BY = | |
182 Relationship.getRelationship("is-read-written-by"); | |
183 | |
184 /** | |
185 * Left: local variable, parameter. | |
186 * Is written at. | |
187 * Right: location. | |
188 */ | |
189 static final Relationship IS_WRITTEN_BY = | |
190 Relationship.getRelationship("is-written-by"); | |
191 | |
192 /** | |
193 * Left: function, method, variable, getter. | |
194 * Is invoked at. | |
195 * Right: location. | |
196 */ | |
197 static final Relationship IS_INVOKED_BY = | |
198 Relationship.getRelationship("is-invoked-by"); | |
199 | |
200 /** | |
201 * Left: function, function type, class, field, method. | |
202 * Is referenced (and not invoked, read/written) at. | |
203 * Right: location. | |
204 */ | |
205 static final Relationship IS_REFERENCED_BY = | |
206 Relationship.getRelationship("is-referenced-by"); | |
207 | |
208 /** | |
209 * Left: name element. | |
210 * Is defined by. | |
211 * Right: concrete element declaration. | |
212 */ | |
213 static final Relationship NAME_IS_DEFINED_BY = | |
214 Relationship.getRelationship("name-is-defined-by"); | |
215 | |
216 IndexConstants._(); | |
217 } | |
218 | |
219 | |
220 /** | |
221 * Instances of the class [Location] represent a location related to an element. | |
222 * | |
223 * The location is expressed as an offset and length, but the offset is relative | |
224 * to the resource containing the element rather than the start of the element | |
225 * within that resource. | |
226 */ | |
227 class Location { | |
228 static const int _FLAG_QUALIFIED = 1 << 0; | |
229 static const int _FLAG_RESOLVED = 1 << 1; | |
230 | |
231 /** | |
232 * An empty array of locations. | |
233 */ | |
234 static const List<Location> EMPTY_ARRAY = const <Location>[]; | |
235 | |
236 /** | |
237 * The element containing this location. | |
238 */ | |
239 final Element element; | |
240 | |
241 /** | |
242 * The offset of this location within the resource containing the element. | |
243 */ | |
244 final int offset; | |
245 | |
246 /** | |
247 * The length of this location. | |
248 */ | |
249 final int length; | |
250 | |
251 /** | |
252 * The flags of this location. | |
253 */ | |
254 int _flags; | |
255 | |
256 /** | |
257 * Initializes a newly created location to be relative to the given element at | |
258 * the given [offset] with the given [length]. | |
259 * | |
260 * [element] - the [Element] containing this location. | |
261 * [offset] - the offset within the resource containing [element]. | |
262 * [length] - the length of this location | |
263 */ | |
264 Location(this.element, this.offset, this.length, {bool isQualified: false, | |
265 bool isResolved: true}) { | |
266 if (element == null) { | |
267 throw new ArgumentError("element location cannot be null"); | |
268 } | |
269 _flags = 0; | |
270 if (isQualified) { | |
271 _flags |= _FLAG_QUALIFIED; | |
272 } | |
273 if (isResolved) { | |
274 _flags |= _FLAG_RESOLVED; | |
275 } | |
276 } | |
277 | |
278 /** | |
279 * Returns `true` if this location is a qualified reference. | |
280 */ | |
281 bool get isQualified => (_flags & _FLAG_QUALIFIED) != 0; | |
282 | |
283 /** | |
284 * Returns `true` if this location is a resolved reference. | |
285 */ | |
286 bool get isResolved => (_flags & _FLAG_RESOLVED) != 0; | |
287 | |
288 @override | |
289 String toString() { | |
290 String flagsStr = ''; | |
291 if (isQualified) { | |
292 flagsStr += ' qualified'; | |
293 } | |
294 if (isResolved) { | |
295 flagsStr += ' resolved'; | |
296 } | |
297 return '[${offset} - ${(offset + length)}) $flagsStr in ${element}'; | |
298 } | |
299 } | |
300 | |
301 | |
302 /** | |
303 * A [Location] with attached data. | |
304 */ | |
305 class LocationWithData<D> extends Location { | |
306 final D data; | |
307 | |
308 LocationWithData(Location location, this.data) | |
309 : super(location.element, location.offset, location.length); | |
310 } | |
311 | |
312 | |
313 /** | |
314 * An [Element] which is used to index references to the name without specifying | |
315 * a concrete kind of this name - field, method or something else. | |
316 */ | |
317 class NameElement extends ElementImpl { | |
318 NameElement(String name) : super("name:${name}", -1); | |
319 | |
320 @override | |
321 ElementKind get kind => ElementKind.NAME; | |
322 | |
323 @override | |
324 accept(ElementVisitor visitor) => null; | |
325 } | |
326 | |
327 | |
328 /** | |
329 * Relationship between an element and a location. Relationships are identified | |
330 * by a globally unique identifier. | |
331 */ | |
332 class Relationship { | |
333 /** | |
334 * A table mapping relationship identifiers to relationships. | |
335 */ | |
336 static Map<String, Relationship> _RELATIONSHIP_MAP = {}; | |
337 | |
338 /** | |
339 * The unique identifier for this relationship. | |
340 */ | |
341 final String identifier; | |
342 | |
343 /** | |
344 * Initialize a newly created relationship with the given unique identifier. | |
345 */ | |
346 Relationship(this.identifier); | |
347 | |
348 @override | |
349 String toString() => identifier; | |
350 | |
351 /** | |
352 * Returns the relationship with the given unique [identifier]. | |
353 */ | |
354 static Relationship getRelationship(String identifier) { | |
355 Relationship relationship = _RELATIONSHIP_MAP[identifier]; | |
356 if (relationship == null) { | |
357 relationship = new Relationship(identifier); | |
358 _RELATIONSHIP_MAP[identifier] = relationship; | |
359 } | |
360 return relationship; | |
361 } | |
362 } | |
363 | |
364 | |
365 /** | |
366 * An element to use when we want to request "defines" relations without | |
367 * specifying an exact library. | |
368 */ | |
369 class UniverseElement extends ElementImpl { | |
370 static final UniverseElement INSTANCE = new UniverseElement._(); | |
371 | |
372 UniverseElement._() : super("--universe--", -1); | |
373 | |
374 @override | |
375 ElementKind get kind => ElementKind.UNIVERSE; | |
376 | |
377 @override | |
378 accept(ElementVisitor visitor) => null; | |
379 } | |
OLD | NEW |