Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(148)

Side by Side Diff: pkg/analyzer/lib/src/generated/index.dart

Issue 259773005: New analyzer snapshot. Sorted unit members. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 // This code was auto-generated, is not intended to be edited, and is subject to 5 // This code was auto-generated, is not intended to be edited, and is subject to
6 // significant change. Please see the README file for more information. 6 // significant change. Please see the README file for more information.
7 7
8 library engine.index; 8 library engine.index;
9 9
10 import 'dart:collection' show Queue; 10 import 'dart:collection' show Queue;
11 import 'java_core.dart'; 11 import 'java_core.dart';
12 import 'java_engine.dart'; 12 import 'java_engine.dart';
13 import 'source.dart'; 13 import 'source.dart';
14 import 'scanner.dart' show Token; 14 import 'scanner.dart' show Token;
15 import 'ast.dart'; 15 import 'ast.dart';
16 import 'element.dart'; 16 import 'element.dart';
17 import 'resolver.dart' show Namespace, NamespaceBuilder; 17 import 'resolver.dart' show Namespace, NamespaceBuilder;
18 import 'engine.dart'; 18 import 'engine.dart';
19 import 'html.dart' as ht; 19 import 'html.dart' as ht;
20 20
21 /** 21 /**
22 * Implementation of [UniverseElement]. 22 * Visits resolved [CompilationUnit] and adds Angular specific relationships int o
23 * [IndexStore].
23 */ 24 */
24 class UniverseElementImpl extends ElementImpl implements UniverseElement { 25 class AngularDartIndexContributor extends GeneralizingAstVisitor<Object> {
25 static UniverseElementImpl INSTANCE = new UniverseElementImpl(); 26 final IndexStore _store;
26 27
27 UniverseElementImpl() : super("--universe--", -1); 28 AngularDartIndexContributor(this._store);
28 29
29 @override 30 @override
30 accept(ElementVisitor visitor) => null; 31 Object visitClassDeclaration(ClassDeclaration node) {
32 ClassElement classElement = node.element;
33 if (classElement != null) {
34 List<ToolkitObjectElement> toolkitObjects = classElement.toolkitObjects;
35 for (ToolkitObjectElement object in toolkitObjects) {
36 if (object is AngularComponentElement) {
37 _indexComponent(object);
38 }
39 if (object is AngularDecoratorElement) {
40 AngularDecoratorElement directive = object;
41 _indexDirective(directive);
42 }
43 }
44 }
45 // stop visiting
46 return null;
47 }
31 48
32 @override 49 @override
33 ElementKind get kind => ElementKind.UNIVERSE; 50 Object visitCompilationUnitMember(CompilationUnitMember node) => null;
51
52 void _indexComponent(AngularComponentElement component) {
53 _indexProperties(component.properties);
54 }
55
56 void _indexDirective(AngularDecoratorElement directive) {
57 _indexProperties(directive.properties);
58 }
59
60 /**
61 * Index [FieldElement] references from [AngularPropertyElement]s.
62 */
63 void _indexProperties(List<AngularPropertyElement> properties) {
64 for (AngularPropertyElement property in properties) {
65 FieldElement field = property.field;
66 if (field != null) {
67 int offset = property.fieldNameOffset;
68 if (offset == -1) {
69 continue;
70 }
71 int length = field.name.length;
72 Location location = new Location(property, offset, length);
73 // getter reference
74 if (property.propertyKind.callsGetter()) {
75 PropertyAccessorElement getter = field.getter;
76 if (getter != null) {
77 _store.recordRelationship(getter, IndexConstants.IS_REFERENCED_BY_QU ALIFIED, location);
78 }
79 }
80 // setter reference
81 if (property.propertyKind.callsSetter()) {
82 PropertyAccessorElement setter = field.setter;
83 if (setter != null) {
84 _store.recordRelationship(setter, IndexConstants.IS_REFERENCED_BY_QU ALIFIED, location);
85 }
86 }
87 }
88 }
89 }
34 } 90 }
35 91
36 /** 92 /**
37 * Container of information computed by the index - relationships between elemen ts.
38 */
39 abstract class IndexStore {
40 /**
41 * Notifies the index store that we are going to index the unit with the given element.
42 *
43 * If the unit is a part of a library, then all its locations are removed. If it is a defining
44 * compilation unit of a library, then index store also checks if some previou sly indexed parts of
45 * the library are not parts of the library anymore, and clears their informat ion.
46 *
47 * @param the [AnalysisContext] in which unit being indexed
48 * @param unitElement the element of the unit being indexed
49 * @return `true` the given [AnalysisContext] is active, or `false` if it was
50 * removed before, so no any unit may be indexed with it
51 */
52 bool aboutToIndexDart(AnalysisContext context, CompilationUnitElement unitElem ent);
53
54 /**
55 * Notifies the index store that we are going to index the given [HtmlElement] .
56 *
57 * @param the [AnalysisContext] in which unit being indexed
58 * @param htmlElement the [HtmlElement] being indexed
59 * @return `true` the given [AnalysisContext] is active, or `false` if it was
60 * removed before, so no any unit may be indexed with it
61 */
62 bool aboutToIndexHtml(AnalysisContext context, HtmlElement htmlElement);
63
64 /**
65 * Return the locations of the elements that have the given relationship with the given element.
66 * For example, if the element represents a method and the relationship is the is-referenced-by
67 * relationship, then the returned locations will be all of the places where t he method is
68 * invoked.
69 *
70 * @param element the the element that has the relationship with the locations to be returned
71 * @param relationship the [Relationship] between the given element and the lo cations to be
72 * returned
73 * @return the locations that have the given relationship with the given eleme nt
74 */
75 List<Location> getRelationships(Element element, Relationship relationship);
76
77 /**
78 * Answer index statistics.
79 */
80 String get statistics;
81
82 /**
83 * Record that the given element and location have the given relationship. For example, if the
84 * relationship is the is-referenced-by relationship, then the element would b e the element being
85 * referenced and the location would be the point at which it is referenced. E ach element can have
86 * the same relationship with multiple locations. In other words, if the follo wing code were
87 * executed
88 *
89 * <pre>
90 * recordRelationship(element, isReferencedBy, location1);
91 * recordRelationship(element, isReferencedBy, location2);
92 * </pre>
93 *
94 * then both relationships would be maintained in the index and the result of executing
95 *
96 * <pre>
97 * getRelationship(element, isReferencedBy);
98 * </pre>
99 *
100 * would be an array containing both <code>location1</code> and <code>location 2</code>.
101 *
102 * @param element the element that is related to the location
103 * @param relationship the [Relationship] between the element and the location
104 * @param location the [Location] where relationship happens
105 */
106 void recordRelationship(Element element, Relationship relationship, Location l ocation);
107
108 /**
109 * Remove from the index all of the information associated with [AnalysisConte xt].
110 *
111 * This method should be invoked when a context is disposed.
112 *
113 * @param the [AnalysisContext] being removed
114 */
115 void removeContext(AnalysisContext context);
116
117 /**
118 * Remove from the index all of the information associated with elements or lo cations in the given
119 * source. This includes relationships between an element in the given source and any other
120 * locations, relationships between any other elements and a location within t he given source.
121 *
122 * This method should be invoked when a source is no longer part of the code b ase.
123 *
124 * @param the [AnalysisContext] in which [Source] being removed
125 * @param source the source being removed
126 */
127 void removeSource(AnalysisContext context, Source source);
128
129 /**
130 * Remove from the index all of the information associated with elements or lo cations in the given
131 * sources. This includes relationships between an element in the given source s and any other
132 * locations, relationships between any other elements and a location within t he given sources.
133 *
134 * This method should be invoked when multiple sources are no longer part of t he code base.
135 *
136 * @param the [AnalysisContext] in which [Source]s being removed
137 * @param container the [SourceContainer] holding the sources being removed
138 */
139 void removeSources(AnalysisContext context, SourceContainer container);
140 }
141
142 /**
143 * Visits resolved [HtmlUnit] and adds relationships into [IndexStore]. 93 * Visits resolved [HtmlUnit] and adds relationships into [IndexStore].
144 */ 94 */
145 class AngularHtmlIndexContributor extends ExpressionVisitor { 95 class AngularHtmlIndexContributor extends ExpressionVisitor {
146 /** 96 /**
147 * The [IndexStore] to record relations into. 97 * The [IndexStore] to record relations into.
148 */ 98 */
149 final IndexStore _store; 99 final IndexStore _store;
150 100
151 /** 101 /**
152 * The index contributor used to index Dart [Expression]s. 102 * The index contributor used to index Dart [Expression]s.
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
216 } 166 }
217 } 167 }
218 return super.visitXmlTagNode(node); 168 return super.visitXmlTagNode(node);
219 } 169 }
220 170
221 Location _createLocationForIdentifier(SimpleIdentifier identifier) => new Loca tion(_htmlUnitElement, identifier.offset, identifier.length); 171 Location _createLocationForIdentifier(SimpleIdentifier identifier) => new Loca tion(_htmlUnitElement, identifier.offset, identifier.length);
222 172
223 Location _createLocationForToken(ht.Token token) => new Location(_htmlUnitElem ent, token.offset, token.length); 173 Location _createLocationForToken(ht.Token token) => new Location(_htmlUnitElem ent, token.offset, token.length);
224 } 174 }
225 175
226 class IndexContributor_AngularHtmlIndexContributor extends IndexContributor {
227 final AngularHtmlIndexContributor AngularHtmlIndexContributor_this;
228
229 IndexContributor_AngularHtmlIndexContributor(IndexStore arg0, this.AngularHtml IndexContributor_this) : super(arg0);
230
231 @override
232 Element peekElement() => AngularHtmlIndexContributor_this._htmlUnitElement;
233
234 @override
235 void recordRelationship(Element element, Relationship relationship, Location l ocation) {
236 AngularElement angularElement = AngularHtmlUnitResolver.getAngularElement(el ement);
237 if (angularElement != null) {
238 element = angularElement;
239 relationship = IndexConstants.ANGULAR_REFERENCE;
240 }
241 super.recordRelationship(element, relationship, location);
242 }
243 }
244
245 /** 176 /**
246 * Recursively visits [HtmlUnit] and every embedded [Expression]. 177 * Recursively visits [HtmlUnit] and every embedded [Expression].
247 */ 178 */
248 abstract class ExpressionVisitor extends ht.RecursiveXmlVisitor<Object> { 179 abstract class ExpressionVisitor extends ht.RecursiveXmlVisitor<Object> {
249 /** 180 /**
250 * Visits the given [Expression]s embedded into tag or attribute. 181 * Visits the given [Expression]s embedded into tag or attribute.
251 * 182 *
252 * @param expression the [Expression] to visit, not `null` 183 * @param expression the [Expression] to visit, not `null`
253 */ 184 */
254 void visitExpression(Expression expression); 185 void visitExpression(Expression expression);
(...skipping 24 matching lines...) Expand all
279 } 210 }
280 if (xmlExpression is ht.RawXmlExpression) { 211 if (xmlExpression is ht.RawXmlExpression) {
281 ht.RawXmlExpression rawXmlExpression = xmlExpression; 212 ht.RawXmlExpression rawXmlExpression = xmlExpression;
282 visitExpression(rawXmlExpression.expression); 213 visitExpression(rawXmlExpression.expression);
283 } 214 }
284 } 215 }
285 } 216 }
286 } 217 }
287 218
288 /** 219 /**
220 * Instances of the [GetRelationshipsOperation] implement an operation used to a ccess the
221 * locations that have a specified relationship with a specified element.
222 */
223 class GetRelationshipsOperation implements IndexOperation {
224 final IndexStore _indexStore;
225
226 final Element element;
227
228 final Relationship relationship;
229
230 final RelationshipCallback callback;
231
232 /**
233 * Initialize a newly created operation that will access the locations that ha ve a specified
234 * relationship with a specified element.
235 */
236 GetRelationshipsOperation(this._indexStore, this.element, this.relationship, t his.callback);
237
238 @override
239 bool get isQuery => true;
240
241 @override
242 void performOperation() {
243 List<Location> locations;
244 locations = _indexStore.getRelationships(element, relationship);
245 callback.hasRelationships(element, relationship, locations);
246 }
247
248 @override
249 bool removeWhenSourceRemoved(Source source) => false;
250
251 @override
252 String toString() => "GetRelationships(${element}, ${relationship})";
253 }
254
255 /**
256 * The interface [Index] defines the behavior of objects that maintain an index storing
257 * [Relationship] between [Element]. All of the operations
258 * defined on the index are asynchronous, and results, when there are any, are p rovided through a
259 * callback.
260 *
261 * Despite being asynchronous, the results of the operations are guaranteed to b e consistent with
262 * the expectation that operations are performed in the order in which they are requested.
263 * Modification operations are executed before any read operation. There is no g uarantee about the
264 * order in which the callbacks for read operations will be invoked.
265 */
266 abstract class Index {
267 /**
268 * Asynchronously invoke the given callback with an array containing all of th e locations of the
269 * elements that have the given relationship with the given element. For examp le, if the element
270 * represents a method and the relationship is the is-referenced-by relationsh ip, then the
271 * locations that will be passed into the callback will be all of the places w here the method is
272 * invoked.
273 *
274 * @param element the element that has the relationship with the locations to be returned
275 * @param relationship the relationship between the given element and the loca tions to be returned
276 * @param callback the callback that will be invoked when the locations are fo und
277 */
278 void getRelationships(Element element, Relationship relationship, Relationship Callback callback);
279
280 /**
281 * Answer index statistics.
282 */
283 String get statistics;
284
285 /**
286 * Asynchronously process the given [HtmlUnit] in order to record the relation ships.
287 *
288 * @param context the [AnalysisContext] in which [HtmlUnit] was resolved
289 * @param unit the [HtmlUnit] being indexed
290 */
291 void indexHtmlUnit(AnalysisContext context, ht.HtmlUnit unit);
292
293 /**
294 * Asynchronously process the given [CompilationUnit] in order to record the r elationships.
295 *
296 * @param context the [AnalysisContext] in which [CompilationUnit] was resolve d
297 * @param unit the [CompilationUnit] being indexed
298 */
299 void indexUnit(AnalysisContext context, CompilationUnit unit);
300
301 /**
302 * Asynchronously remove from the index all of the information associated with the given context.
303 *
304 * This method should be invoked when a context is disposed.
305 *
306 * @param context the [AnalysisContext] to remove
307 */
308 void removeContext(AnalysisContext context);
309
310 /**
311 * Asynchronously remove from the index all of the information associated with elements or
312 * locations in the given source. This includes relationships between an eleme nt in the given
313 * source and any other locations, relationships between any other elements an d a location within
314 * the given source.
315 *
316 * This method should be invoked when a source is no longer part of the code b ase.
317 *
318 * @param context the [AnalysisContext] in which [Source] being removed
319 * @param source the [Source] being removed
320 */
321 void removeSource(AnalysisContext context, Source source);
322
323 /**
324 * Asynchronously remove from the index all of the information associated with elements or
325 * locations in the given sources. This includes relationships between an elem ent in the given
326 * sources and any other locations, relationships between any other elements a nd a location within
327 * the given sources.
328 *
329 * This method should be invoked when multiple sources are no longer part of t he code base.
330 *
331 * @param the [AnalysisContext] in which [Source]s being removed
332 * @param container the [SourceContainer] holding the sources being removed
333 */
334 void removeSources(AnalysisContext context, SourceContainer container);
335
336 /**
337 * Should be called in separate [Thread] to process request in this [Index]. D oes not
338 * return until the [stop] method is called.
339 */
340 void run();
341
342 /**
343 * Should be called to stop process running [run], so stop processing requests .
344 */
345 void stop();
346 }
347
348 /**
349 * Constants used when populating and accessing the index.
350 */
351 abstract class IndexConstants {
352 /**
353 * An element used to represent the universe.
354 */
355 static final Element UNIVERSE = UniverseElement.INSTANCE;
356
357 /**
358 * The relationship used to indicate that a container (the left-operand) conta ins the definition
359 * of a class at a specific location (the right operand).
360 */
361 static final Relationship DEFINES_CLASS = Relationship.getRelationship("define s-class");
362
363 /**
364 * The relationship used to indicate that a container (the left-operand) conta ins the definition
365 * of a function at a specific location (the right operand).
366 */
367 static final Relationship DEFINES_FUNCTION = Relationship.getRelationship("def ines-function");
368
369 /**
370 * The relationship used to indicate that a container (the left-operand) conta ins the definition
371 * of a class type alias at a specific location (the right operand).
372 */
373 static final Relationship DEFINES_CLASS_ALIAS = Relationship.getRelationship(" defines-class-alias");
374
375 /**
376 * The relationship used to indicate that a container (the left-operand) conta ins the definition
377 * of a function type at a specific location (the right operand).
378 */
379 static final Relationship DEFINES_FUNCTION_TYPE = Relationship.getRelationship ("defines-function-type");
380
381 /**
382 * The relationship used to indicate that a container (the left-operand) conta ins the definition
383 * of a method at a specific location (the right operand).
384 */
385 static final Relationship DEFINES_VARIABLE = Relationship.getRelationship("def ines-variable");
386
387 /**
388 * The relationship used to indicate that a name (the left-operand) is defined at a specific
389 * location (the right operand).
390 */
391 static final Relationship IS_DEFINED_BY = Relationship.getRelationship("is-def ined-by");
392
393 /**
394 * The relationship used to indicate that a type (the left-operand) is extende d by a type at a
395 * specific location (the right operand).
396 */
397 static final Relationship IS_EXTENDED_BY = Relationship.getRelationship("is-ex tended-by");
398
399 /**
400 * The relationship used to indicate that a type (the left-operand) is impleme nted by a type at a
401 * specific location (the right operand).
402 */
403 static final Relationship IS_IMPLEMENTED_BY = Relationship.getRelationship("is -implemented-by");
404
405 /**
406 * The relationship used to indicate that a type (the left-operand) is mixed i nto a type at a
407 * specific location (the right operand).
408 */
409 static final Relationship IS_MIXED_IN_BY = Relationship.getRelationship("is-mi xed-in-by");
410
411 /**
412 * The relationship used to indicate that a parameter or variable (the left-op erand) is read at a
413 * specific location (the right operand).
414 */
415 static final Relationship IS_READ_BY = Relationship.getRelationship("is-read-b y");
416
417 /**
418 * The relationship used to indicate that a parameter or variable (the left-op erand) is both read
419 * and modified at a specific location (the right operand).
420 */
421 static final Relationship IS_READ_WRITTEN_BY = Relationship.getRelationship("i s-read-written-by");
422
423 /**
424 * The relationship used to indicate that a parameter or variable (the left-op erand) is modified
425 * (assigned to) at a specific location (the right operand).
426 */
427 static final Relationship IS_WRITTEN_BY = Relationship.getRelationship("is-wri tten-by");
428
429 /**
430 * The relationship used to indicate that an element (the left-operand) is ref erenced at a
431 * specific location (the right operand). This is used for everything except r ead/write operations
432 * for fields, parameters, and variables. Those use either [IS_REFERENCED_BY_Q UALIFIED],
433 * [IS_REFERENCED_BY_UNQUALIFIED], [IS_READ_BY], [IS_WRITTEN_BY] or
434 * [IS_READ_WRITTEN_BY], as appropriate.
435 */
436 static final Relationship IS_REFERENCED_BY = Relationship.getRelationship("is- referenced-by");
437
438 /**
439 * The relationship used to indicate that an [NameElementImpl] (the left-opera nd) is
440 * referenced at a specific location (the right operand). This is used for qua lified resolved
441 * references to methods and fields.
442 */
443 static final Relationship IS_REFERENCED_BY_QUALIFIED_RESOLVED = Relationship.g etRelationship("is-referenced-by_qualified-resolved");
444
445 /**
446 * The relationship used to indicate that an [NameElementImpl] (the left-opera nd) is
447 * referenced at a specific location (the right operand). This is used for qua lified unresolved
448 * references to methods and fields.
449 */
450 static final Relationship IS_REFERENCED_BY_QUALIFIED_UNRESOLVED = Relationship .getRelationship("is-referenced-by_qualified-unresolved");
451
452 /**
453 * The relationship used to indicate that an element (the left-operand) is ref erenced at a
454 * specific location (the right operand). This is used for field accessors and methods.
455 */
456 static final Relationship IS_REFERENCED_BY_QUALIFIED = Relationship.getRelatio nship("is-referenced-by-qualified");
457
458 /**
459 * The relationship used to indicate that an element (the left-operand) is ref erenced at a
460 * specific location (the right operand). This is used for field accessors and methods.
461 */
462 static final Relationship IS_REFERENCED_BY_UNQUALIFIED = Relationship.getRelat ionship("is-referenced-by-unqualified");
463
464 /**
465 * The relationship used to indicate that an element (the left-operand) is inv oked at a specific
466 * location (the right operand). This is used for functions.
467 */
468 static final Relationship IS_INVOKED_BY = Relationship.getRelationship("is-inv oked-by");
469
470 /**
471 * The relationship used to indicate that an element (the left-operand) is inv oked at a specific
472 * location (the right operand). This is used for methods.
473 */
474 static final Relationship IS_INVOKED_BY_QUALIFIED = Relationship.getRelationsh ip("is-invoked-by-qualified");
475
476 /**
477 * The relationship used to indicate that an element (the left-operand) is inv oked at a specific
478 * location (the right operand). This is used for methods.
479 */
480 static final Relationship IS_INVOKED_BY_UNQUALIFIED = Relationship.getRelation ship("is-invoked-by-unqualified");
481
482 /**
483 * Reference to some [AngularElement].
484 */
485 static final Relationship ANGULAR_REFERENCE = Relationship.getRelationship("an gular-reference");
486
487 /**
488 * Reference to some closing tag of an XML element.
489 */
490 static final Relationship ANGULAR_CLOSING_TAG_REFERENCE = Relationship.getRela tionship("angular-closing-tag-reference");
491 }
492
493 /**
494 * Visits resolved AST and adds relationships into [IndexStore].
495 */
496 class IndexContributor extends GeneralizingAstVisitor<Object> {
497 /**
498 * @return the [Location] representing location of the [Element].
499 */
500 static Location createLocation(Element element) {
501 if (element != null) {
502 int offset = element.nameOffset;
503 int length = element.displayName.length;
504 return new Location(element, offset, length);
505 }
506 return null;
507 }
508
509 /**
510 * @return the [ImportElement] that is referenced by this node with [PrefixEle ment],
511 * may be `null`.
512 */
513 static ImportElement getImportElement(SimpleIdentifier prefixNode) {
514 IndexContributor_ImportElementInfo info = getImportElementInfo(prefixNode);
515 return info != null ? info._element : null;
516 }
517
518 /**
519 * @return the [ImportElementInfo] with [ImportElement] that is referenced by this
520 * node with [PrefixElement], may be `null`.
521 */
522 static IndexContributor_ImportElementInfo getImportElementInfo(SimpleIdentifie r prefixNode) {
523 IndexContributor_ImportElementInfo info = new IndexContributor_ImportElement Info();
524 // prepare environment
525 AstNode parent = prefixNode.parent;
526 CompilationUnit unit = prefixNode.getAncestor((node) => node is CompilationU nit);
527 LibraryElement libraryElement = unit.element.library;
528 // prepare used element
529 Element usedElement = null;
530 if (parent is PrefixedIdentifier) {
531 PrefixedIdentifier prefixed = parent;
532 if (identical(prefixed.prefix, prefixNode)) {
533 usedElement = prefixed.staticElement;
534 info._periodEnd = prefixed.period.end;
535 }
536 }
537 if (parent is MethodInvocation) {
538 MethodInvocation invocation = parent;
539 if (identical(invocation.target, prefixNode)) {
540 usedElement = invocation.methodName.staticElement;
541 info._periodEnd = invocation.period.end;
542 }
543 }
544 // we need used Element
545 if (usedElement == null) {
546 return null;
547 }
548 // find ImportElement
549 String prefix = prefixNode.name;
550 Map<ImportElement, Set<Element>> importElementsMap = {};
551 info._element = _internalGetImportElement(libraryElement, prefix, usedElemen t, importElementsMap);
552 if (info._element == null) {
553 return null;
554 }
555 return info;
556 }
557
558 /**
559 * If the given expression has resolved type, returns the new location with th is type.
560 *
561 * @param location the base location
562 * @param expression the expression assigned at the given location
563 */
564 static Location _getLocationWithExpressionType(Location location, Expression e xpression) {
565 if (expression != null) {
566 return new LocationWithData<DartType>.con1(location, expression.bestType);
567 }
568 return location;
569 }
570
571 /**
572 * If the given node is the part of the [ConstructorFieldInitializer], returns location with
573 * type of the initializer expression.
574 */
575 static Location _getLocationWithInitializerType(SimpleIdentifier node, Locatio n location) {
576 if (node.parent is ConstructorFieldInitializer) {
577 ConstructorFieldInitializer initializer = node.parent as ConstructorFieldI nitializer;
578 if (identical(initializer.fieldName, node)) {
579 location = _getLocationWithExpressionType(location, initializer.expressi on);
580 }
581 }
582 return location;
583 }
584
585 /**
586 * If the given identifier has a synthetic [PropertyAccessorElement], i.e. acc essor for
587 * normal field, and it is LHS of assignment, then include [Type] of the assig ned value into
588 * the [Location].
589 *
590 * @param identifier the identifier to record location
591 * @param element the element of the identifier
592 * @param location the raw location
593 * @return the [Location] with the type of the assigned value
594 */
595 static Location _getLocationWithTypeAssignedToField(SimpleIdentifier identifie r, Element element, Location location) {
596 // we need accessor
597 if (element is! PropertyAccessorElement) {
598 return location;
599 }
600 PropertyAccessorElement accessor = element as PropertyAccessorElement;
601 // should be setter
602 if (!accessor.isSetter) {
603 return location;
604 }
605 // accessor should be synthetic, i.e. field normal
606 if (!accessor.isSynthetic) {
607 return location;
608 }
609 // should be LHS of assignment
610 AstNode parent;
611 {
612 AstNode node = identifier;
613 parent = node.parent;
614 // new T().field = x;
615 if (parent is PropertyAccess) {
616 PropertyAccess propertyAccess = parent as PropertyAccess;
617 if (identical(propertyAccess.propertyName, node)) {
618 node = propertyAccess;
619 parent = propertyAccess.parent;
620 }
621 }
622 // obj.field = x;
623 if (parent is PrefixedIdentifier) {
624 PrefixedIdentifier prefixedIdentifier = parent as PrefixedIdentifier;
625 if (identical(prefixedIdentifier.identifier, node)) {
626 node = prefixedIdentifier;
627 parent = prefixedIdentifier.parent;
628 }
629 }
630 }
631 // OK, remember the type
632 if (parent is AssignmentExpression) {
633 AssignmentExpression assignment = parent as AssignmentExpression;
634 Expression rhs = assignment.rightHandSide;
635 location = _getLocationWithExpressionType(location, rhs);
636 }
637 // done
638 return location;
639 }
640
641 /**
642 * @return the [ImportElement] that declares given [PrefixElement] and imports library
643 * with given "usedElement".
644 */
645 static ImportElement _internalGetImportElement(LibraryElement libraryElement, String prefix, Element usedElement, Map<ImportElement, Set<Element>> importEleme ntsMap) {
646 // validate Element
647 if (usedElement == null) {
648 return null;
649 }
650 if (usedElement.enclosingElement is! CompilationUnitElement) {
651 return null;
652 }
653 LibraryElement usedLibrary = usedElement.library;
654 // find ImportElement that imports used library with used prefix
655 List<ImportElement> candidates = null;
656 for (ImportElement importElement in libraryElement.imports) {
657 // required library
658 if (importElement.importedLibrary != usedLibrary) {
659 continue;
660 }
661 // required prefix
662 PrefixElement prefixElement = importElement.prefix;
663 if (prefix == null) {
664 if (prefixElement != null) {
665 continue;
666 }
667 } else {
668 if (prefixElement == null) {
669 continue;
670 }
671 if (prefix != prefixElement.name) {
672 continue;
673 }
674 }
675 // no combinators => only possible candidate
676 if (importElement.combinators.length == 0) {
677 return importElement;
678 }
679 // OK, we have candidate
680 if (candidates == null) {
681 candidates = [];
682 }
683 candidates.add(importElement);
684 }
685 // no candidates, probably element is defined in this library
686 if (candidates == null) {
687 return null;
688 }
689 // one candidate
690 if (candidates.length == 1) {
691 return candidates[0];
692 }
693 // ensure that each ImportElement has set of elements
694 for (ImportElement importElement in candidates) {
695 if (importElementsMap.containsKey(importElement)) {
696 continue;
697 }
698 Namespace namespace = new NamespaceBuilder().createImportNamespaceForDirec tive(importElement);
699 Set<Element> elements = new Set();
700 importElementsMap[importElement] = elements;
701 }
702 // use import namespace to choose correct one
703 for (MapEntry<ImportElement, Set<Element>> entry in getMapEntrySet(importEle mentsMap)) {
704 if (entry.getValue().contains(usedElement)) {
705 return entry.getKey();
706 }
707 }
708 // not found
709 return null;
710 }
711
712 /**
713 * @return `true` if given "node" is part of an import [Combinator].
714 */
715 static bool _isIdentifierInImportCombinator(SimpleIdentifier node) {
716 AstNode parent = node.parent;
717 return parent is Combinator;
718 }
719
720 /**
721 * @return `true` if given "node" is part of [PrefixedIdentifier] "prefix.node ".
722 */
723 static bool _isIdentifierInPrefixedIdentifier(SimpleIdentifier node) {
724 AstNode parent = node.parent;
725 return parent is PrefixedIdentifier && identical(parent.identifier, node);
726 }
727
728 /**
729 * @return `true` if given [SimpleIdentifier] is "name" part of prefixed ident ifier or
730 * method invocation.
731 */
732 static bool _isQualified(SimpleIdentifier node) {
733 AstNode parent = node.parent;
734 if (parent is PrefixedIdentifier) {
735 return identical(parent.identifier, node);
736 }
737 if (parent is PropertyAccess) {
738 return identical(parent.propertyName, node);
739 }
740 if (parent is MethodInvocation) {
741 MethodInvocation invocation = parent;
742 return invocation.realTarget != null && identical(invocation.methodName, n ode);
743 }
744 return false;
745 }
746
747 final IndexStore _store;
748
749 LibraryElement _libraryElement;
750
751 Map<ImportElement, Set<Element>> _importElementsMap = {};
752
753 /**
754 * A stack whose top element (the element with the largest index) is an elemen t representing the
755 * inner-most enclosing scope.
756 */
757 Queue<Element> _elementStack = new Queue();
758
759 IndexContributor(this._store);
760
761 /**
762 * Enter a new scope represented by the given [Element].
763 */
764 void enterScope(Element element) {
765 _elementStack.addFirst(element);
766 }
767
768 /**
769 * @return the inner-most enclosing [Element], may be `null`.
770 */
771 Element peekElement() {
772 for (Element element in _elementStack) {
773 if (element != null) {
774 return element;
775 }
776 }
777 return null;
778 }
779
780 @override
781 Object visitAssignmentExpression(AssignmentExpression node) {
782 _recordOperatorReference(node.operator, node.bestElement);
783 return super.visitAssignmentExpression(node);
784 }
785
786 @override
787 Object visitBinaryExpression(BinaryExpression node) {
788 _recordOperatorReference(node.operator, node.bestElement);
789 return super.visitBinaryExpression(node);
790 }
791
792 @override
793 Object visitClassDeclaration(ClassDeclaration node) {
794 ClassElement element = node.element;
795 enterScope(element);
796 try {
797 _recordElementDefinition(element, IndexConstants.DEFINES_CLASS);
798 {
799 ExtendsClause extendsClause = node.extendsClause;
800 if (extendsClause != null) {
801 TypeName superclassNode = extendsClause.superclass;
802 _recordSuperType(superclassNode, IndexConstants.IS_EXTENDED_BY);
803 } else {
804 InterfaceType superType = element.supertype;
805 if (superType != null) {
806 ClassElement objectElement = superType.element;
807 recordRelationship(objectElement, IndexConstants.IS_EXTENDED_BY, _cr eateLocationFromOffset(node.name.offset, 0));
808 }
809 }
810 }
811 {
812 WithClause withClause = node.withClause;
813 if (withClause != null) {
814 for (TypeName mixinNode in withClause.mixinTypes) {
815 _recordSuperType(mixinNode, IndexConstants.IS_MIXED_IN_BY);
816 }
817 }
818 }
819 {
820 ImplementsClause implementsClause = node.implementsClause;
821 if (implementsClause != null) {
822 for (TypeName interfaceNode in implementsClause.interfaces) {
823 _recordSuperType(interfaceNode, IndexConstants.IS_IMPLEMENTED_BY);
824 }
825 }
826 }
827 return super.visitClassDeclaration(node);
828 } finally {
829 _exitScope();
830 }
831 }
832
833 @override
834 Object visitClassTypeAlias(ClassTypeAlias node) {
835 ClassElement element = node.element;
836 enterScope(element);
837 try {
838 _recordElementDefinition(element, IndexConstants.DEFINES_CLASS_ALIAS);
839 {
840 TypeName superclassNode = node.superclass;
841 if (superclassNode != null) {
842 _recordSuperType(superclassNode, IndexConstants.IS_EXTENDED_BY);
843 }
844 }
845 {
846 WithClause withClause = node.withClause;
847 if (withClause != null) {
848 for (TypeName mixinNode in withClause.mixinTypes) {
849 _recordSuperType(mixinNode, IndexConstants.IS_MIXED_IN_BY);
850 }
851 }
852 }
853 {
854 ImplementsClause implementsClause = node.implementsClause;
855 if (implementsClause != null) {
856 for (TypeName interfaceNode in implementsClause.interfaces) {
857 _recordSuperType(interfaceNode, IndexConstants.IS_IMPLEMENTED_BY);
858 }
859 }
860 }
861 return super.visitClassTypeAlias(node);
862 } finally {
863 _exitScope();
864 }
865 }
866
867 @override
868 Object visitCompilationUnit(CompilationUnit node) {
869 CompilationUnitElement unitElement = node.element;
870 if (unitElement != null) {
871 _elementStack.add(unitElement);
872 _libraryElement = unitElement.enclosingElement;
873 if (_libraryElement != null) {
874 return super.visitCompilationUnit(node);
875 }
876 }
877 return null;
878 }
879
880 @override
881 Object visitConstructorDeclaration(ConstructorDeclaration node) {
882 ConstructorElement element = node.element;
883 // define
884 {
885 Location location;
886 if (node.name != null) {
887 int start = node.period.offset;
888 int end = node.name.end;
889 location = _createLocationFromOffset(start, end - start);
890 } else {
891 int start = node.returnType.end;
892 location = _createLocationFromOffset(start, 0);
893 }
894 recordRelationship(element, IndexConstants.IS_DEFINED_BY, location);
895 }
896 // visit children
897 enterScope(element);
898 try {
899 return super.visitConstructorDeclaration(node);
900 } finally {
901 _exitScope();
902 }
903 }
904
905 @override
906 Object visitConstructorName(ConstructorName node) {
907 ConstructorElement element = node.staticElement;
908 // in 'class B = A;' actually A constructors are invoked
909 if (element != null && element.isSynthetic && element.redirectedConstructor != null) {
910 element = element.redirectedConstructor;
911 }
912 // prepare location
913 Location location;
914 if (node.name != null) {
915 int start = node.period.offset;
916 int end = node.name.end;
917 location = _createLocationFromOffset(start, end - start);
918 } else {
919 int start = node.type.end;
920 location = _createLocationFromOffset(start, 0);
921 }
922 // record relationship
923 recordRelationship(element, IndexConstants.IS_REFERENCED_BY, location);
924 return super.visitConstructorName(node);
925 }
926
927 @override
928 Object visitExportDirective(ExportDirective node) {
929 ExportElement element = node.element;
930 if (element != null) {
931 LibraryElement expLibrary = element.exportedLibrary;
932 _recordLibraryReference(node, expLibrary);
933 }
934 return super.visitExportDirective(node);
935 }
936
937 @override
938 Object visitFormalParameter(FormalParameter node) {
939 ParameterElement element = node.element;
940 enterScope(element);
941 try {
942 return super.visitFormalParameter(node);
943 } finally {
944 _exitScope();
945 }
946 }
947
948 @override
949 Object visitFunctionDeclaration(FunctionDeclaration node) {
950 Element element = node.element;
951 _recordElementDefinition(element, IndexConstants.DEFINES_FUNCTION);
952 enterScope(element);
953 try {
954 return super.visitFunctionDeclaration(node);
955 } finally {
956 _exitScope();
957 }
958 }
959
960 @override
961 Object visitFunctionTypeAlias(FunctionTypeAlias node) {
962 Element element = node.element;
963 _recordElementDefinition(element, IndexConstants.DEFINES_FUNCTION_TYPE);
964 return super.visitFunctionTypeAlias(node);
965 }
966
967 @override
968 Object visitImportDirective(ImportDirective node) {
969 ImportElement element = node.element;
970 if (element != null) {
971 LibraryElement impLibrary = element.importedLibrary;
972 _recordLibraryReference(node, impLibrary);
973 }
974 return super.visitImportDirective(node);
975 }
976
977 @override
978 Object visitIndexExpression(IndexExpression node) {
979 MethodElement element = node.bestElement;
980 if (element is MethodElement) {
981 Token operator = node.leftBracket;
982 Location location = _createLocationFromToken(operator);
983 recordRelationship(element, IndexConstants.IS_INVOKED_BY_QUALIFIED, locati on);
984 }
985 return super.visitIndexExpression(node);
986 }
987
988 @override
989 Object visitMethodDeclaration(MethodDeclaration node) {
990 ExecutableElement element = node.element;
991 enterScope(element);
992 try {
993 return super.visitMethodDeclaration(node);
994 } finally {
995 _exitScope();
996 }
997 }
998
999 @override
1000 Object visitMethodInvocation(MethodInvocation node) {
1001 SimpleIdentifier name = node.methodName;
1002 Element element = name.bestElement;
1003 if (element is MethodElement) {
1004 Location location = _createLocationFromNode(name);
1005 Relationship relationship;
1006 if (node.target != null) {
1007 relationship = IndexConstants.IS_INVOKED_BY_QUALIFIED;
1008 } else {
1009 relationship = IndexConstants.IS_INVOKED_BY_UNQUALIFIED;
1010 }
1011 recordRelationship(element, relationship, location);
1012 }
1013 if (element is FunctionElement) {
1014 Location location = _createLocationFromNode(name);
1015 recordRelationship(element, IndexConstants.IS_INVOKED_BY, location);
1016 }
1017 _recordImportElementReferenceWithoutPrefix(name);
1018 return super.visitMethodInvocation(node);
1019 }
1020
1021 @override
1022 Object visitPartDirective(PartDirective node) {
1023 Element element = node.element;
1024 Location location = _createLocationFromNode(node.uri);
1025 recordRelationship(element, IndexConstants.IS_REFERENCED_BY, location);
1026 return super.visitPartDirective(node);
1027 }
1028
1029 @override
1030 Object visitPartOfDirective(PartOfDirective node) {
1031 Location location = _createLocationFromNode(node.libraryName);
1032 recordRelationship(node.element, IndexConstants.IS_REFERENCED_BY, location);
1033 return null;
1034 }
1035
1036 @override
1037 Object visitPostfixExpression(PostfixExpression node) {
1038 _recordOperatorReference(node.operator, node.bestElement);
1039 return super.visitPostfixExpression(node);
1040 }
1041
1042 @override
1043 Object visitPrefixExpression(PrefixExpression node) {
1044 _recordOperatorReference(node.operator, node.bestElement);
1045 return super.visitPrefixExpression(node);
1046 }
1047
1048 @override
1049 Object visitSimpleIdentifier(SimpleIdentifier node) {
1050 Element nameElement = new NameElementImpl(node.name);
1051 Location location = _createLocationFromNode(node);
1052 // name in declaration
1053 if (node.inDeclarationContext()) {
1054 recordRelationship(nameElement, IndexConstants.IS_DEFINED_BY, location);
1055 return null;
1056 }
1057 // prepare information
1058 Element element = node.bestElement;
1059 // qualified name reference
1060 _recordQualifiedMemberReference(node, element, nameElement, location);
1061 // stop if already handled
1062 if (_isAlreadyHandledName(node)) {
1063 return null;
1064 }
1065 // record specific relations
1066 if (element is ClassElement || element is FunctionElement || element is Func tionTypeAliasElement || element is LabelElement || element is TypeParameterEleme nt) {
1067 recordRelationship(element, IndexConstants.IS_REFERENCED_BY, location);
1068 } else if (element is FieldElement) {
1069 location = _getLocationWithInitializerType(node, location);
1070 recordRelationship(element, IndexConstants.IS_REFERENCED_BY, location);
1071 } else if (element is FieldFormalParameterElement) {
1072 FieldFormalParameterElement fieldParameter = element;
1073 FieldElement field = fieldParameter.field;
1074 recordRelationship(field, IndexConstants.IS_REFERENCED_BY_QUALIFIED, locat ion);
1075 } else if (element is PrefixElement) {
1076 _recordImportElementReferenceWithPrefix(node);
1077 } else if (element is PropertyAccessorElement || element is MethodElement) {
1078 location = _getLocationWithTypeAssignedToField(node, element, location);
1079 if (_isQualified(node)) {
1080 recordRelationship(element, IndexConstants.IS_REFERENCED_BY_QUALIFIED, l ocation);
1081 } else {
1082 recordRelationship(element, IndexConstants.IS_REFERENCED_BY_UNQUALIFIED, location);
1083 }
1084 } else if (element is ParameterElement || element is LocalVariableElement) {
1085 bool inGetterContext = node.inGetterContext();
1086 bool inSetterContext = node.inSetterContext();
1087 if (inGetterContext && inSetterContext) {
1088 recordRelationship(element, IndexConstants.IS_READ_WRITTEN_BY, location) ;
1089 } else if (inGetterContext) {
1090 recordRelationship(element, IndexConstants.IS_READ_BY, location);
1091 } else if (inSetterContext) {
1092 recordRelationship(element, IndexConstants.IS_WRITTEN_BY, location);
1093 } else {
1094 recordRelationship(element, IndexConstants.IS_REFERENCED_BY, location);
1095 }
1096 }
1097 _recordImportElementReferenceWithoutPrefix(node);
1098 return super.visitSimpleIdentifier(node);
1099 }
1100
1101 @override
1102 Object visitSuperConstructorInvocation(SuperConstructorInvocation node) {
1103 ConstructorElement element = node.staticElement;
1104 Location location;
1105 if (node.constructorName != null) {
1106 int start = node.period.offset;
1107 int end = node.constructorName.end;
1108 location = _createLocationFromOffset(start, end - start);
1109 } else {
1110 int start = node.keyword.end;
1111 location = _createLocationFromOffset(start, 0);
1112 }
1113 recordRelationship(element, IndexConstants.IS_REFERENCED_BY, location);
1114 return super.visitSuperConstructorInvocation(node);
1115 }
1116
1117 @override
1118 Object visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) {
1119 VariableDeclarationList variables = node.variables;
1120 for (VariableDeclaration variableDeclaration in variables.variables) {
1121 Element element = variableDeclaration.element;
1122 _recordElementDefinition(element, IndexConstants.DEFINES_VARIABLE);
1123 }
1124 return super.visitTopLevelVariableDeclaration(node);
1125 }
1126
1127 @override
1128 Object visitTypeParameter(TypeParameter node) {
1129 TypeParameterElement element = node.element;
1130 enterScope(element);
1131 try {
1132 return super.visitTypeParameter(node);
1133 } finally {
1134 _exitScope();
1135 }
1136 }
1137
1138 @override
1139 Object visitVariableDeclaration(VariableDeclaration node) {
1140 VariableElement element = node.element;
1141 // record declaration
1142 {
1143 SimpleIdentifier name = node.name;
1144 Location location = _createLocationFromNode(name);
1145 location = _getLocationWithExpressionType(location, node.initializer);
1146 recordRelationship(element, IndexConstants.IS_DEFINED_BY, location);
1147 }
1148 // visit
1149 enterScope(element);
1150 try {
1151 return super.visitVariableDeclaration(node);
1152 } finally {
1153 _exitScope();
1154 }
1155 }
1156
1157 @override
1158 Object visitVariableDeclarationList(VariableDeclarationList node) {
1159 NodeList<VariableDeclaration> variables = node.variables;
1160 if (variables != null) {
1161 // use first VariableDeclaration as Element for Location(s) in type
1162 {
1163 TypeName type = node.type;
1164 if (type != null) {
1165 for (VariableDeclaration variableDeclaration in variables) {
1166 enterScope(variableDeclaration.element);
1167 try {
1168 type.accept(this);
1169 } finally {
1170 _exitScope();
1171 }
1172 // only one iteration
1173 break;
1174 }
1175 }
1176 }
1177 // visit variables
1178 variables.accept(this);
1179 }
1180 return null;
1181 }
1182
1183 /**
1184 * Record the given relationship between the given [Element] and [Location].
1185 */
1186 void recordRelationship(Element element, Relationship relationship, Location l ocation) {
1187 if (element != null && location != null) {
1188 _store.recordRelationship(element, relationship, location);
1189 }
1190 }
1191
1192 /**
1193 * @return the [Location] representing location of the [AstNode].
1194 */
1195 Location _createLocationFromNode(AstNode node) => _createLocationFromOffset(no de.offset, node.length);
1196
1197 /**
1198 * @param offset the offset of the location within [Source]
1199 * @param length the length of the location
1200 * @return the [Location] representing the given offset and length within the inner-most
1201 * [Element].
1202 */
1203 Location _createLocationFromOffset(int offset, int length) {
1204 Element element = peekElement();
1205 return new Location(element, offset, length);
1206 }
1207
1208 /**
1209 * @return the [Location] representing location of the [Token].
1210 */
1211 Location _createLocationFromToken(Token token) => _createLocationFromOffset(to ken.offset, token.length);
1212
1213 /**
1214 * Exit the current scope.
1215 */
1216 void _exitScope() {
1217 _elementStack.removeFirst();
1218 }
1219
1220 /**
1221 * @return `true` if given node already indexed as more interesting reference, so it should
1222 * not be indexed again.
1223 */
1224 bool _isAlreadyHandledName(SimpleIdentifier node) {
1225 AstNode parent = node.parent;
1226 if (parent is MethodInvocation) {
1227 Element element = node.staticElement;
1228 if (element is MethodElement || element is FunctionElement) {
1229 return identical(parent.methodName, node);
1230 }
1231 }
1232 return false;
1233 }
1234
1235 /**
1236 * Records the [Element] definition in the library and universe.
1237 */
1238 void _recordElementDefinition(Element element, Relationship relationship) {
1239 Location location = createLocation(element);
1240 recordRelationship(_libraryElement, relationship, location);
1241 recordRelationship(IndexConstants.UNIVERSE, relationship, location);
1242 }
1243
1244 /**
1245 * Records [ImportElement] reference if given [SimpleIdentifier] references so me
1246 * top-level element and not qualified with import prefix.
1247 */
1248 void _recordImportElementReferenceWithoutPrefix(SimpleIdentifier node) {
1249 if (_isIdentifierInImportCombinator(node)) {
1250 return;
1251 }
1252 if (_isIdentifierInPrefixedIdentifier(node)) {
1253 return;
1254 }
1255 Element element = node.staticElement;
1256 ImportElement importElement = _internalGetImportElement(_libraryElement, nul l, element, _importElementsMap);
1257 if (importElement != null) {
1258 Location location = _createLocationFromOffset(node.offset, 0);
1259 recordRelationship(importElement, IndexConstants.IS_REFERENCED_BY, locatio n);
1260 }
1261 }
1262
1263 /**
1264 * Records [ImportElement] that declares given prefix and imports library with element used
1265 * with given prefix node.
1266 */
1267 void _recordImportElementReferenceWithPrefix(SimpleIdentifier prefixNode) {
1268 IndexContributor_ImportElementInfo info = getImportElementInfo(prefixNode);
1269 if (info != null) {
1270 int offset = prefixNode.offset;
1271 int length = info._periodEnd - offset;
1272 Location location = _createLocationFromOffset(offset, length);
1273 recordRelationship(info._element, IndexConstants.IS_REFERENCED_BY, locatio n);
1274 }
1275 }
1276
1277 /**
1278 * Records reference to defining [CompilationUnitElement] of the given
1279 * [LibraryElement].
1280 */
1281 void _recordLibraryReference(UriBasedDirective node, LibraryElement library) {
1282 if (library != null) {
1283 Location location = _createLocationFromNode(node.uri);
1284 recordRelationship(library.definingCompilationUnit, IndexConstants.IS_REFE RENCED_BY, location);
1285 }
1286 }
1287
1288 /**
1289 * Record reference to the given operator [Element] and name.
1290 */
1291 void _recordOperatorReference(Token operator, Element element) {
1292 // prepare location
1293 Location location = _createLocationFromToken(operator);
1294 // record name reference
1295 {
1296 String name = operator.lexeme;
1297 if (name == "++") {
1298 name = "+";
1299 }
1300 if (name == "--") {
1301 name = "-";
1302 }
1303 if (StringUtilities.endsWithChar(name, 0x3D) && name != "==") {
1304 name = name.substring(0, name.length - 1);
1305 }
1306 Element nameElement = new NameElementImpl(name);
1307 Relationship relationship = element != null ? IndexConstants.IS_REFERENCED _BY_QUALIFIED_RESOLVED : IndexConstants.IS_REFERENCED_BY_QUALIFIED_UNRESOLVED;
1308 recordRelationship(nameElement, relationship, location);
1309 }
1310 // record element reference
1311 if (element != null) {
1312 recordRelationship(element, IndexConstants.IS_INVOKED_BY_QUALIFIED, locati on);
1313 }
1314 }
1315
1316 /**
1317 * Records reference if the given [SimpleIdentifier] looks like a qualified pr operty access
1318 * or method invocation.
1319 */
1320 void _recordQualifiedMemberReference(SimpleIdentifier node, Element element, E lement nameElement, Location location) {
1321 if (_isQualified(node)) {
1322 Relationship relationship = element != null ? IndexConstants.IS_REFERENCED _BY_QUALIFIED_RESOLVED : IndexConstants.IS_REFERENCED_BY_QUALIFIED_UNRESOLVED;
1323 recordRelationship(nameElement, relationship, location);
1324 }
1325 }
1326
1327 /**
1328 * Records extends/implements relationships between given [ClassElement] and [ Type] of
1329 * "superNode".
1330 */
1331 void _recordSuperType(TypeName superNode, Relationship relationship) {
1332 if (superNode != null) {
1333 Identifier superName = superNode.name;
1334 if (superName != null) {
1335 Element superElement = superName.staticElement;
1336 recordRelationship(superElement, relationship, _createLocationFromNode(s uperNode));
1337 }
1338 }
1339 }
1340 }
1341
1342 class IndexContributor_AngularHtmlIndexContributor extends IndexContributor {
1343 final AngularHtmlIndexContributor AngularHtmlIndexContributor_this;
1344
1345 IndexContributor_AngularHtmlIndexContributor(IndexStore arg0, this.AngularHtml IndexContributor_this) : super(arg0);
1346
1347 @override
1348 Element peekElement() => AngularHtmlIndexContributor_this._htmlUnitElement;
1349
1350 @override
1351 void recordRelationship(Element element, Relationship relationship, Location l ocation) {
1352 AngularElement angularElement = AngularHtmlUnitResolver.getAngularElement(el ement);
1353 if (angularElement != null) {
1354 element = angularElement;
1355 relationship = IndexConstants.ANGULAR_REFERENCE;
1356 }
1357 super.recordRelationship(element, relationship, location);
1358 }
1359 }
1360
1361 /**
1362 * Information about [ImportElement] and place where it is referenced using
1363 * [PrefixElement].
1364 */
1365 class IndexContributor_ImportElementInfo {
1366 ImportElement _element;
1367
1368 int _periodEnd = 0;
1369 }
1370
1371 /**
289 * Instances of the [IndexHtmlUnitOperation] implement an operation that adds da ta to the 1372 * Instances of the [IndexHtmlUnitOperation] implement an operation that adds da ta to the
290 * index based on the resolved [HtmlUnit]. 1373 * index based on the resolved [HtmlUnit].
291 */ 1374 */
292 class IndexHtmlUnitOperation implements IndexOperation { 1375 class IndexHtmlUnitOperation implements IndexOperation {
293 /** 1376 /**
294 * The index store against which this operation is being run. 1377 * The index store against which this operation is being run.
295 */ 1378 */
296 final IndexStore _indexStore; 1379 final IndexStore _indexStore;
297 1380
298 /** 1381 /**
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
350 } 1433 }
351 1434
352 @override 1435 @override
353 bool removeWhenSourceRemoved(Source source) => this._source == source; 1436 bool removeWhenSourceRemoved(Source source) => this._source == source;
354 1437
355 @override 1438 @override
356 String toString() => "IndexHtmlUnitOperation(${_source.fullName})"; 1439 String toString() => "IndexHtmlUnitOperation(${_source.fullName})";
357 } 1440 }
358 1441
359 /** 1442 /**
360 * Visits resolved [CompilationUnit] and adds Angular specific relationships int o 1443 * The interface [IndexOperation] defines the behavior of objects used to perfor m operations
361 * [IndexStore]. 1444 * on an index.
362 */ 1445 */
363 class AngularDartIndexContributor extends GeneralizingAstVisitor<Object> { 1446 abstract class IndexOperation {
364 final IndexStore _store; 1447 /**
365 1448 * Return `true` if this operation returns information from the index.
366 AngularDartIndexContributor(this._store); 1449 *
367 1450 * @return `true` if this operation returns information from the index
368 @override 1451 */
369 Object visitClassDeclaration(ClassDeclaration node) { 1452 bool get isQuery;
370 ClassElement classElement = node.element; 1453
371 if (classElement != null) { 1454 /**
372 List<ToolkitObjectElement> toolkitObjects = classElement.toolkitObjects; 1455 * Perform the operation implemented by this operation.
373 for (ToolkitObjectElement object in toolkitObjects) { 1456 */
374 if (object is AngularComponentElement) { 1457 void performOperation();
375 _indexComponent(object); 1458
376 } 1459 /**
377 if (object is AngularDecoratorElement) { 1460 * Return `true` if this operation should be removed from the operation queue when the
378 AngularDecoratorElement directive = object; 1461 * given resource has been removed.
379 _indexDirective(directive); 1462 *
380 } 1463 * @param source the [Source] that has been removed
381 } 1464 * @return `true` if this operation should be removed from the operation queue as a
382 } 1465 * result of removing the resource
383 // stop visiting 1466 */
384 return null; 1467 bool removeWhenSourceRemoved(Source source);
385 }
386
387 @override
388 Object visitCompilationUnitMember(CompilationUnitMember node) => null;
389
390 void _indexComponent(AngularComponentElement component) {
391 _indexProperties(component.properties);
392 }
393
394 void _indexDirective(AngularDecoratorElement directive) {
395 _indexProperties(directive.properties);
396 }
397
398 /**
399 * Index [FieldElement] references from [AngularPropertyElement]s.
400 */
401 void _indexProperties(List<AngularPropertyElement> properties) {
402 for (AngularPropertyElement property in properties) {
403 FieldElement field = property.field;
404 if (field != null) {
405 int offset = property.fieldNameOffset;
406 if (offset == -1) {
407 continue;
408 }
409 int length = field.name.length;
410 Location location = new Location(property, offset, length);
411 // getter reference
412 if (property.propertyKind.callsGetter()) {
413 PropertyAccessorElement getter = field.getter;
414 if (getter != null) {
415 _store.recordRelationship(getter, IndexConstants.IS_REFERENCED_BY_QU ALIFIED, location);
416 }
417 }
418 // setter reference
419 if (property.propertyKind.callsSetter()) {
420 PropertyAccessorElement setter = field.setter;
421 if (setter != null) {
422 _store.recordRelationship(setter, IndexConstants.IS_REFERENCED_BY_QU ALIFIED, location);
423 }
424 }
425 }
426 }
427 }
428 } 1468 }
429 1469
430 /** 1470 /**
431 * Special [Element] which is used to index references to the name without speci fying concrete 1471 * Container of information computed by the index - relationships between elemen ts.
432 * kind of this name - field, method or something else.
433 */ 1472 */
434 class NameElementImpl extends ElementImpl { 1473 abstract class IndexStore {
435 NameElementImpl(String name) : super("name:${name}", -1); 1474 /**
436 1475 * Notifies the index store that we are going to index the unit with the given element.
437 @override 1476 *
438 accept(ElementVisitor visitor) => null; 1477 * If the unit is a part of a library, then all its locations are removed. If it is a defining
439 1478 * compilation unit of a library, then index store also checks if some previou sly indexed parts of
440 @override 1479 * the library are not parts of the library anymore, and clears their informat ion.
441 ElementKind get kind => ElementKind.NAME; 1480 *
442 } 1481 * @param the [AnalysisContext] in which unit being indexed
443 1482 * @param unitElement the element of the unit being indexed
444 /** 1483 * @return `true` the given [AnalysisContext] is active, or `false` if it was
445 * The interface <code>RelationshipCallback</code> defines the behavior of objec ts that are invoked 1484 * removed before, so no any unit may be indexed with it
446 * with the results of a query about a given relationship. 1485 */
447 */ 1486 bool aboutToIndexDart(AnalysisContext context, CompilationUnitElement unitElem ent);
448 abstract class RelationshipCallback { 1487
449 /** 1488 /**
450 * This method is invoked when the locations that have a specified relationshi p with a specified 1489 * Notifies the index store that we are going to index the given [HtmlElement] .
451 * element are available. For example, if the element is a field and the relat ionship is the 1490 *
452 * is-referenced-by relationship, then this method will be invoked with each l ocation at which the 1491 * @param the [AnalysisContext] in which unit being indexed
453 * field is referenced. 1492 * @param htmlElement the [HtmlElement] being indexed
454 * 1493 * @return `true` the given [AnalysisContext] is active, or `false` if it was
455 * @param element the [Element] that has the relationship with the locations 1494 * removed before, so no any unit may be indexed with it
456 * @param relationship the relationship between the given element and the loca tions 1495 */
457 * @param locations the locations that were found 1496 bool aboutToIndexHtml(AnalysisContext context, HtmlElement htmlElement);
458 */ 1497
459 void hasRelationships(Element element, Relationship relationship, List<Locatio n> locations); 1498 /**
460 } 1499 * Return the locations of the elements that have the given relationship with the given element.
461 1500 * For example, if the element represents a method and the relationship is the is-referenced-by
462 /** 1501 * relationship, then the returned locations will be all of the places where t he method is
463 * Instances of the [RemoveSourcesOperation] implement an operation that removes from the 1502 * invoked.
464 * index any data based on the content of source belonging to a [SourceContainer ]. 1503 *
465 */ 1504 * @param element the the element that has the relationship with the locations to be returned
466 class RemoveSourcesOperation implements IndexOperation { 1505 * @param relationship the [Relationship] between the given element and the lo cations to be
467 /** 1506 * returned
468 * The index store against which this operation is being run. 1507 * @return the locations that have the given relationship with the given eleme nt
469 */ 1508 */
470 final IndexStore _indexStore; 1509 List<Location> getRelationships(Element element, Relationship relationship);
471 1510
472 /** 1511 /**
473 * The context to remove container. 1512 * Answer index statistics.
474 */ 1513 */
475 final AnalysisContext _context; 1514 String get statistics;
476 1515
477 /** 1516 /**
478 * The source container to remove. 1517 * Record that the given element and location have the given relationship. For example, if the
479 */ 1518 * relationship is the is-referenced-by relationship, then the element would b e the element being
480 final SourceContainer container; 1519 * referenced and the location would be the point at which it is referenced. E ach element can have
481 1520 * the same relationship with multiple locations. In other words, if the follo wing code were
482 /** 1521 * executed
483 * Initialize a newly created operation that will remove the specified resourc e. 1522 *
484 * 1523 * <pre>
485 * @param indexStore the index store against which this operation is being run 1524 * recordRelationship(element, isReferencedBy, location1);
486 * @param context the [AnalysisContext] to remove container in 1525 * recordRelationship(element, isReferencedBy, location2);
487 * @param container the [SourceContainer] to remove from index 1526 * </pre>
488 */ 1527 *
489 RemoveSourcesOperation(this._indexStore, this._context, this.container); 1528 * then both relationships would be maintained in the index and the result of executing
490 1529 *
491 @override 1530 * <pre>
492 bool get isQuery => false; 1531 * getRelationship(element, isReferencedBy);
493 1532 * </pre>
494 @override 1533 *
495 void performOperation() { 1534 * would be an array containing both <code>location1</code> and <code>location 2</code>.
496 _indexStore.removeSources(_context, container); 1535 *
497 } 1536 * @param element the element that is related to the location
498 1537 * @param relationship the [Relationship] between the element and the location
499 @override 1538 * @param location the [Location] where relationship happens
500 bool removeWhenSourceRemoved(Source source) => false; 1539 */
501 1540 void recordRelationship(Element element, Relationship relationship, Location l ocation);
502 @override 1541
503 String toString() => "RemoveSources(${container})"; 1542 /**
1543 * Remove from the index all of the information associated with [AnalysisConte xt].
1544 *
1545 * This method should be invoked when a context is disposed.
1546 *
1547 * @param the [AnalysisContext] being removed
1548 */
1549 void removeContext(AnalysisContext context);
1550
1551 /**
1552 * Remove from the index all of the information associated with elements or lo cations in the given
1553 * source. This includes relationships between an element in the given source and any other
1554 * locations, relationships between any other elements and a location within t he given source.
1555 *
1556 * This method should be invoked when a source is no longer part of the code b ase.
1557 *
1558 * @param the [AnalysisContext] in which [Source] being removed
1559 * @param source the source being removed
1560 */
1561 void removeSource(AnalysisContext context, Source source);
1562
1563 /**
1564 * Remove from the index all of the information associated with elements or lo cations in the given
1565 * sources. This includes relationships between an element in the given source s and any other
1566 * locations, relationships between any other elements and a location within t he given sources.
1567 *
1568 * This method should be invoked when multiple sources are no longer part of t he code base.
1569 *
1570 * @param the [AnalysisContext] in which [Source]s being removed
1571 * @param container the [SourceContainer] holding the sources being removed
1572 */
1573 void removeSources(AnalysisContext context, SourceContainer container);
504 } 1574 }
505 1575
506 /** 1576 /**
507 * Instances of the [IndexUnitOperation] implement an operation that adds data t o the index 1577 * Instances of the [IndexUnitOperation] implement an operation that adds data t o the index
508 * based on the resolved [CompilationUnit]. 1578 * based on the resolved [CompilationUnit].
509 */ 1579 */
510 class IndexUnitOperation implements IndexOperation { 1580 class IndexUnitOperation implements IndexOperation {
511 /** 1581 /**
512 * The index store against which this operation is being run. 1582 * The index store against which this operation is being run.
513 */ 1583 */
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
568 } 1638 }
569 1639
570 @override 1640 @override
571 bool removeWhenSourceRemoved(Source source) => this._source == source; 1641 bool removeWhenSourceRemoved(Source source) => this._source == source;
572 1642
573 @override 1643 @override
574 String toString() => "IndexUnitOperation(${_source.fullName})"; 1644 String toString() => "IndexUnitOperation(${_source.fullName})";
575 } 1645 }
576 1646
577 /** 1647 /**
1648 * Instances of the class <code>Location</code> represent a location related to an element. The
1649 * location is expressed as an offset and length, but the offset is relative to the resource
1650 * containing the element rather than the start of the element within that resou rce.
1651 */
1652 class Location {
1653 /**
1654 * An empty array of locations.
1655 */
1656 static List<Location> EMPTY_ARRAY = new List<Location>(0);
1657
1658 /**
1659 * The element containing this location.
1660 */
1661 final Element element;
1662
1663 /**
1664 * The offset of this location within the resource containing the element.
1665 */
1666 final int offset;
1667
1668 /**
1669 * The length of this location.
1670 */
1671 final int length;
1672
1673 /**
1674 * Internal field used to hold a key that is referenced at this location.
1675 */
1676 Object internalKey;
1677
1678 /**
1679 * Initialize a newly create location to be relative to the given element at t he given offset with
1680 * the given length.
1681 *
1682 * @param element the [Element] containing this location
1683 * @param offset the offset of this location within the resource containing th e element
1684 * @param length the length of this location
1685 */
1686 Location(this.element, this.offset, this.length) {
1687 if (element == null) {
1688 throw new IllegalArgumentException("element location cannot be null");
1689 }
1690 }
1691
1692 /**
1693 * Returns a clone of this [Location].
1694 */
1695 Location newClone() => new Location(element, offset, length);
1696
1697 @override
1698 String toString() => "[${offset} - ${(offset + length)}) in ${element}";
1699 }
1700
1701 /**
1702 * [Location] with attached data.
1703 */
1704 class LocationWithData<D> extends Location {
1705 final D data;
1706
1707 LocationWithData.con1(Location location, this.data) : super(location.element, location.offset, location.length);
1708
1709 LocationWithData.con2(Element element, int offset, int length, this.data) : su per(element, offset, length);
1710
1711 @override
1712 Location newClone() => new LocationWithData<D>.con2(element, offset, length, d ata);
1713 }
1714
1715 /**
1716 * [IndexStore] which keeps all information in memory, but can write it to strea m and read
1717 * later.
1718 */
1719 abstract class MemoryIndexStore implements IndexStore {
1720 }
1721
1722 /**
578 * [IndexStore] which keeps full index in memory. 1723 * [IndexStore] which keeps full index in memory.
579 */ 1724 */
580 class MemoryIndexStoreImpl implements MemoryIndexStore { 1725 class MemoryIndexStoreImpl implements MemoryIndexStore {
581 /** 1726 /**
582 * When logging is on, [AnalysisEngine] actually creates 1727 * When logging is on, [AnalysisEngine] actually creates
583 * [InstrumentedAnalysisContextImpl], which wraps [AnalysisContextImpl] used t o create 1728 * [InstrumentedAnalysisContextImpl], which wraps [AnalysisContextImpl] used t o create
584 * actual [Element]s. So, in index we have to unwrap [InstrumentedAnalysisCont extImpl] 1729 * actual [Element]s. So, in index we have to unwrap [InstrumentedAnalysisCont extImpl]
585 * when perform any operation. 1730 * when perform any operation.
586 */ 1731 */
587 static AnalysisContext unwrapContext(AnalysisContext context) { 1732 static AnalysisContext unwrapContext(AnalysisContext context) {
(...skipping 473 matching lines...) Expand 10 before | Expand all | Expand 10 after
1061 } 2206 }
1062 2207
1063 @override 2208 @override
1064 int get hashCode => JavaArrays.makeHashCode([_librarySource, _unitSource]); 2209 int get hashCode => JavaArrays.makeHashCode([_librarySource, _unitSource]);
1065 2210
1066 @override 2211 @override
1067 String toString() => "${_librarySource} ${_unitSource}"; 2212 String toString() => "${_librarySource} ${_unitSource}";
1068 } 2213 }
1069 2214
1070 /** 2215 /**
1071 * The interface `UniverseElement` defines element to use when we want to reques t "defines" 2216 * Special [Element] which is used to index references to the name without speci fying concrete
1072 * relations without specifying exact library. 2217 * kind of this name - field, method or something else.
1073 */ 2218 */
1074 abstract class UniverseElement implements Element { 2219 class NameElementImpl extends ElementImpl {
1075 static final UniverseElement INSTANCE = UniverseElementImpl.INSTANCE; 2220 NameElementImpl(String name) : super("name:${name}", -1);
2221
2222 @override
2223 accept(ElementVisitor visitor) => null;
2224
2225 @override
2226 ElementKind get kind => ElementKind.NAME;
1076 } 2227 }
1077 2228
1078 /** 2229 /**
1079 * The enumeration <code>ProcessorState</code> represents the possible states of an operation 2230 * The enumeration <code>ProcessorState</code> represents the possible states of an operation
1080 * processor. 2231 * processor.
1081 */ 2232 */
1082 class ProcessorState extends Enum<ProcessorState> { 2233 class ProcessorState extends Enum<ProcessorState> {
1083 /** 2234 /**
1084 * The processor is ready to be run (has not been run before). 2235 * The processor is ready to be run (has not been run before).
1085 */ 2236 */
(...skipping 13 matching lines...) Expand all
1099 * The processor has stopped performing operations and cannot be used again. 2250 * The processor has stopped performing operations and cannot be used again.
1100 */ 2251 */
1101 static const ProcessorState STOPPED = const ProcessorState('STOPPED', 3); 2252 static const ProcessorState STOPPED = const ProcessorState('STOPPED', 3);
1102 2253
1103 static const List<ProcessorState> values = const [READY, RUNNING, STOP_REQESTE D, STOPPED]; 2254 static const List<ProcessorState> values = const [READY, RUNNING, STOP_REQESTE D, STOPPED];
1104 2255
1105 const ProcessorState(String name, int ordinal) : super(name, ordinal); 2256 const ProcessorState(String name, int ordinal) : super(name, ordinal);
1106 } 2257 }
1107 2258
1108 /** 2259 /**
1109 * Constants used when populating and accessing the index. 2260 * Relationship between an element and a location. Relationships are identified by a globally unique
2261 * identifier.
1110 */ 2262 */
1111 abstract class IndexConstants { 2263 class Relationship {
1112 /** 2264 /**
1113 * An element used to represent the universe. 2265 * The unique identifier for this relationship.
1114 */ 2266 */
1115 static final Element UNIVERSE = UniverseElement.INSTANCE; 2267 final String _uniqueId;
1116 2268
1117 /** 2269 /**
1118 * The relationship used to indicate that a container (the left-operand) conta ins the definition 2270 * A table mapping relationship identifiers to relationships.
1119 * of a class at a specific location (the right operand). 2271 */
1120 */ 2272 static Map<String, Relationship> _RelationshipMap = {};
1121 static final Relationship DEFINES_CLASS = Relationship.getRelationship("define s-class"); 2273
1122 2274 /**
1123 /** 2275 * Return the relationship with the given unique identifier.
1124 * The relationship used to indicate that a container (the left-operand) conta ins the definition 2276 *
1125 * of a function at a specific location (the right operand). 2277 * @param uniqueId the unique identifier for the relationship
1126 */ 2278 * @return the relationship with the given unique identifier
1127 static final Relationship DEFINES_FUNCTION = Relationship.getRelationship("def ines-function"); 2279 */
1128 2280 static Relationship getRelationship(String uniqueId) {
1129 /** 2281 Relationship relationship = _RelationshipMap[uniqueId];
1130 * The relationship used to indicate that a container (the left-operand) conta ins the definition 2282 if (relationship == null) {
1131 * of a class type alias at a specific location (the right operand). 2283 relationship = new Relationship(uniqueId);
1132 */ 2284 _RelationshipMap[uniqueId] = relationship;
1133 static final Relationship DEFINES_CLASS_ALIAS = Relationship.getRelationship(" defines-class-alias"); 2285 }
1134 2286 return relationship;
1135 /** 2287 }
1136 * The relationship used to indicate that a container (the left-operand) conta ins the definition 2288
1137 * of a function type at a specific location (the right operand). 2289 /**
1138 */ 2290 * @return all registered [Relationship]s.
1139 static final Relationship DEFINES_FUNCTION_TYPE = Relationship.getRelationship ("defines-function-type"); 2291 */
1140 2292 static Iterable<Relationship> values() => _RelationshipMap.values;
1141 /** 2293
1142 * The relationship used to indicate that a container (the left-operand) conta ins the definition 2294 /**
1143 * of a method at a specific location (the right operand). 2295 * Initialize a newly created relationship to have the given unique identifier .
1144 */ 2296 *
1145 static final Relationship DEFINES_VARIABLE = Relationship.getRelationship("def ines-variable"); 2297 * @param uniqueId the unique identifier for this relationship
1146 2298 */
1147 /** 2299 Relationship(this._uniqueId);
1148 * The relationship used to indicate that a name (the left-operand) is defined at a specific 2300
1149 * location (the right operand). 2301 /**
1150 */ 2302 * Return the unique identifier for this relationship.
1151 static final Relationship IS_DEFINED_BY = Relationship.getRelationship("is-def ined-by"); 2303 *
1152 2304 * @return the unique identifier for this relationship
1153 /** 2305 */
1154 * The relationship used to indicate that a type (the left-operand) is extende d by a type at a 2306 String get identifier => _uniqueId;
1155 * specific location (the right operand). 2307
1156 */ 2308 @override
1157 static final Relationship IS_EXTENDED_BY = Relationship.getRelationship("is-ex tended-by"); 2309 String toString() => _uniqueId;
1158
1159 /**
1160 * The relationship used to indicate that a type (the left-operand) is impleme nted by a type at a
1161 * specific location (the right operand).
1162 */
1163 static final Relationship IS_IMPLEMENTED_BY = Relationship.getRelationship("is -implemented-by");
1164
1165 /**
1166 * The relationship used to indicate that a type (the left-operand) is mixed i nto a type at a
1167 * specific location (the right operand).
1168 */
1169 static final Relationship IS_MIXED_IN_BY = Relationship.getRelationship("is-mi xed-in-by");
1170
1171 /**
1172 * The relationship used to indicate that a parameter or variable (the left-op erand) is read at a
1173 * specific location (the right operand).
1174 */
1175 static final Relationship IS_READ_BY = Relationship.getRelationship("is-read-b y");
1176
1177 /**
1178 * The relationship used to indicate that a parameter or variable (the left-op erand) is both read
1179 * and modified at a specific location (the right operand).
1180 */
1181 static final Relationship IS_READ_WRITTEN_BY = Relationship.getRelationship("i s-read-written-by");
1182
1183 /**
1184 * The relationship used to indicate that a parameter or variable (the left-op erand) is modified
1185 * (assigned to) at a specific location (the right operand).
1186 */
1187 static final Relationship IS_WRITTEN_BY = Relationship.getRelationship("is-wri tten-by");
1188
1189 /**
1190 * The relationship used to indicate that an element (the left-operand) is ref erenced at a
1191 * specific location (the right operand). This is used for everything except r ead/write operations
1192 * for fields, parameters, and variables. Those use either [IS_REFERENCED_BY_Q UALIFIED],
1193 * [IS_REFERENCED_BY_UNQUALIFIED], [IS_READ_BY], [IS_WRITTEN_BY] or
1194 * [IS_READ_WRITTEN_BY], as appropriate.
1195 */
1196 static final Relationship IS_REFERENCED_BY = Relationship.getRelationship("is- referenced-by");
1197
1198 /**
1199 * The relationship used to indicate that an [NameElementImpl] (the left-opera nd) is
1200 * referenced at a specific location (the right operand). This is used for qua lified resolved
1201 * references to methods and fields.
1202 */
1203 static final Relationship IS_REFERENCED_BY_QUALIFIED_RESOLVED = Relationship.g etRelationship("is-referenced-by_qualified-resolved");
1204
1205 /**
1206 * The relationship used to indicate that an [NameElementImpl] (the left-opera nd) is
1207 * referenced at a specific location (the right operand). This is used for qua lified unresolved
1208 * references to methods and fields.
1209 */
1210 static final Relationship IS_REFERENCED_BY_QUALIFIED_UNRESOLVED = Relationship .getRelationship("is-referenced-by_qualified-unresolved");
1211
1212 /**
1213 * The relationship used to indicate that an element (the left-operand) is ref erenced at a
1214 * specific location (the right operand). This is used for field accessors and methods.
1215 */
1216 static final Relationship IS_REFERENCED_BY_QUALIFIED = Relationship.getRelatio nship("is-referenced-by-qualified");
1217
1218 /**
1219 * The relationship used to indicate that an element (the left-operand) is ref erenced at a
1220 * specific location (the right operand). This is used for field accessors and methods.
1221 */
1222 static final Relationship IS_REFERENCED_BY_UNQUALIFIED = Relationship.getRelat ionship("is-referenced-by-unqualified");
1223
1224 /**
1225 * The relationship used to indicate that an element (the left-operand) is inv oked at a specific
1226 * location (the right operand). This is used for functions.
1227 */
1228 static final Relationship IS_INVOKED_BY = Relationship.getRelationship("is-inv oked-by");
1229
1230 /**
1231 * The relationship used to indicate that an element (the left-operand) is inv oked at a specific
1232 * location (the right operand). This is used for methods.
1233 */
1234 static final Relationship IS_INVOKED_BY_QUALIFIED = Relationship.getRelationsh ip("is-invoked-by-qualified");
1235
1236 /**
1237 * The relationship used to indicate that an element (the left-operand) is inv oked at a specific
1238 * location (the right operand). This is used for methods.
1239 */
1240 static final Relationship IS_INVOKED_BY_UNQUALIFIED = Relationship.getRelation ship("is-invoked-by-unqualified");
1241
1242 /**
1243 * Reference to some [AngularElement].
1244 */
1245 static final Relationship ANGULAR_REFERENCE = Relationship.getRelationship("an gular-reference");
1246
1247 /**
1248 * Reference to some closing tag of an XML element.
1249 */
1250 static final Relationship ANGULAR_CLOSING_TAG_REFERENCE = Relationship.getRela tionship("angular-closing-tag-reference");
1251 } 2310 }
1252 2311
1253 /** 2312 /**
1254 * Visits resolved AST and adds relationships into [IndexStore]. 2313 * The interface <code>RelationshipCallback</code> defines the behavior of objec ts that are invoked
2314 * with the results of a query about a given relationship.
1255 */ 2315 */
1256 class IndexContributor extends GeneralizingAstVisitor<Object> { 2316 abstract class RelationshipCallback {
1257 /** 2317 /**
1258 * @return the [Location] representing location of the [Element]. 2318 * This method is invoked when the locations that have a specified relationshi p with a specified
1259 */ 2319 * element are available. For example, if the element is a field and the relat ionship is the
1260 static Location createLocation(Element element) { 2320 * is-referenced-by relationship, then this method will be invoked with each l ocation at which the
1261 if (element != null) { 2321 * field is referenced.
1262 int offset = element.nameOffset; 2322 *
1263 int length = element.displayName.length; 2323 * @param element the [Element] that has the relationship with the locations
1264 return new Location(element, offset, length); 2324 * @param relationship the relationship between the given element and the loca tions
1265 } 2325 * @param locations the locations that were found
1266 return null; 2326 */
1267 } 2327 void hasRelationships(Element element, Relationship relationship, List<Locatio n> locations);
1268
1269 /**
1270 * @return the [ImportElement] that is referenced by this node with [PrefixEle ment],
1271 * may be `null`.
1272 */
1273 static ImportElement getImportElement(SimpleIdentifier prefixNode) {
1274 IndexContributor_ImportElementInfo info = getImportElementInfo(prefixNode);
1275 return info != null ? info._element : null;
1276 }
1277
1278 /**
1279 * @return the [ImportElementInfo] with [ImportElement] that is referenced by this
1280 * node with [PrefixElement], may be `null`.
1281 */
1282 static IndexContributor_ImportElementInfo getImportElementInfo(SimpleIdentifie r prefixNode) {
1283 IndexContributor_ImportElementInfo info = new IndexContributor_ImportElement Info();
1284 // prepare environment
1285 AstNode parent = prefixNode.parent;
1286 CompilationUnit unit = prefixNode.getAncestor((node) => node is CompilationU nit);
1287 LibraryElement libraryElement = unit.element.library;
1288 // prepare used element
1289 Element usedElement = null;
1290 if (parent is PrefixedIdentifier) {
1291 PrefixedIdentifier prefixed = parent;
1292 if (identical(prefixed.prefix, prefixNode)) {
1293 usedElement = prefixed.staticElement;
1294 info._periodEnd = prefixed.period.end;
1295 }
1296 }
1297 if (parent is MethodInvocation) {
1298 MethodInvocation invocation = parent;
1299 if (identical(invocation.target, prefixNode)) {
1300 usedElement = invocation.methodName.staticElement;
1301 info._periodEnd = invocation.period.end;
1302 }
1303 }
1304 // we need used Element
1305 if (usedElement == null) {
1306 return null;
1307 }
1308 // find ImportElement
1309 String prefix = prefixNode.name;
1310 Map<ImportElement, Set<Element>> importElementsMap = {};
1311 info._element = _internalGetImportElement(libraryElement, prefix, usedElemen t, importElementsMap);
1312 if (info._element == null) {
1313 return null;
1314 }
1315 return info;
1316 }
1317
1318 /**
1319 * If the given expression has resolved type, returns the new location with th is type.
1320 *
1321 * @param location the base location
1322 * @param expression the expression assigned at the given location
1323 */
1324 static Location _getLocationWithExpressionType(Location location, Expression e xpression) {
1325 if (expression != null) {
1326 return new LocationWithData<DartType>.con1(location, expression.bestType);
1327 }
1328 return location;
1329 }
1330
1331 /**
1332 * If the given node is the part of the [ConstructorFieldInitializer], returns location with
1333 * type of the initializer expression.
1334 */
1335 static Location _getLocationWithInitializerType(SimpleIdentifier node, Locatio n location) {
1336 if (node.parent is ConstructorFieldInitializer) {
1337 ConstructorFieldInitializer initializer = node.parent as ConstructorFieldI nitializer;
1338 if (identical(initializer.fieldName, node)) {
1339 location = _getLocationWithExpressionType(location, initializer.expressi on);
1340 }
1341 }
1342 return location;
1343 }
1344
1345 /**
1346 * If the given identifier has a synthetic [PropertyAccessorElement], i.e. acc essor for
1347 * normal field, and it is LHS of assignment, then include [Type] of the assig ned value into
1348 * the [Location].
1349 *
1350 * @param identifier the identifier to record location
1351 * @param element the element of the identifier
1352 * @param location the raw location
1353 * @return the [Location] with the type of the assigned value
1354 */
1355 static Location _getLocationWithTypeAssignedToField(SimpleIdentifier identifie r, Element element, Location location) {
1356 // we need accessor
1357 if (element is! PropertyAccessorElement) {
1358 return location;
1359 }
1360 PropertyAccessorElement accessor = element as PropertyAccessorElement;
1361 // should be setter
1362 if (!accessor.isSetter) {
1363 return location;
1364 }
1365 // accessor should be synthetic, i.e. field normal
1366 if (!accessor.isSynthetic) {
1367 return location;
1368 }
1369 // should be LHS of assignment
1370 AstNode parent;
1371 {
1372 AstNode node = identifier;
1373 parent = node.parent;
1374 // new T().field = x;
1375 if (parent is PropertyAccess) {
1376 PropertyAccess propertyAccess = parent as PropertyAccess;
1377 if (identical(propertyAccess.propertyName, node)) {
1378 node = propertyAccess;
1379 parent = propertyAccess.parent;
1380 }
1381 }
1382 // obj.field = x;
1383 if (parent is PrefixedIdentifier) {
1384 PrefixedIdentifier prefixedIdentifier = parent as PrefixedIdentifier;
1385 if (identical(prefixedIdentifier.identifier, node)) {
1386 node = prefixedIdentifier;
1387 parent = prefixedIdentifier.parent;
1388 }
1389 }
1390 }
1391 // OK, remember the type
1392 if (parent is AssignmentExpression) {
1393 AssignmentExpression assignment = parent as AssignmentExpression;
1394 Expression rhs = assignment.rightHandSide;
1395 location = _getLocationWithExpressionType(location, rhs);
1396 }
1397 // done
1398 return location;
1399 }
1400
1401 /**
1402 * @return the [ImportElement] that declares given [PrefixElement] and imports library
1403 * with given "usedElement".
1404 */
1405 static ImportElement _internalGetImportElement(LibraryElement libraryElement, String prefix, Element usedElement, Map<ImportElement, Set<Element>> importEleme ntsMap) {
1406 // validate Element
1407 if (usedElement == null) {
1408 return null;
1409 }
1410 if (usedElement.enclosingElement is! CompilationUnitElement) {
1411 return null;
1412 }
1413 LibraryElement usedLibrary = usedElement.library;
1414 // find ImportElement that imports used library with used prefix
1415 List<ImportElement> candidates = null;
1416 for (ImportElement importElement in libraryElement.imports) {
1417 // required library
1418 if (importElement.importedLibrary != usedLibrary) {
1419 continue;
1420 }
1421 // required prefix
1422 PrefixElement prefixElement = importElement.prefix;
1423 if (prefix == null) {
1424 if (prefixElement != null) {
1425 continue;
1426 }
1427 } else {
1428 if (prefixElement == null) {
1429 continue;
1430 }
1431 if (prefix != prefixElement.name) {
1432 continue;
1433 }
1434 }
1435 // no combinators => only possible candidate
1436 if (importElement.combinators.length == 0) {
1437 return importElement;
1438 }
1439 // OK, we have candidate
1440 if (candidates == null) {
1441 candidates = [];
1442 }
1443 candidates.add(importElement);
1444 }
1445 // no candidates, probably element is defined in this library
1446 if (candidates == null) {
1447 return null;
1448 }
1449 // one candidate
1450 if (candidates.length == 1) {
1451 return candidates[0];
1452 }
1453 // ensure that each ImportElement has set of elements
1454 for (ImportElement importElement in candidates) {
1455 if (importElementsMap.containsKey(importElement)) {
1456 continue;
1457 }
1458 Namespace namespace = new NamespaceBuilder().createImportNamespaceForDirec tive(importElement);
1459 Set<Element> elements = new Set();
1460 importElementsMap[importElement] = elements;
1461 }
1462 // use import namespace to choose correct one
1463 for (MapEntry<ImportElement, Set<Element>> entry in getMapEntrySet(importEle mentsMap)) {
1464 if (entry.getValue().contains(usedElement)) {
1465 return entry.getKey();
1466 }
1467 }
1468 // not found
1469 return null;
1470 }
1471
1472 /**
1473 * @return `true` if given "node" is part of an import [Combinator].
1474 */
1475 static bool _isIdentifierInImportCombinator(SimpleIdentifier node) {
1476 AstNode parent = node.parent;
1477 return parent is Combinator;
1478 }
1479
1480 /**
1481 * @return `true` if given "node" is part of [PrefixedIdentifier] "prefix.node ".
1482 */
1483 static bool _isIdentifierInPrefixedIdentifier(SimpleIdentifier node) {
1484 AstNode parent = node.parent;
1485 return parent is PrefixedIdentifier && identical(parent.identifier, node);
1486 }
1487
1488 /**
1489 * @return `true` if given [SimpleIdentifier] is "name" part of prefixed ident ifier or
1490 * method invocation.
1491 */
1492 static bool _isQualified(SimpleIdentifier node) {
1493 AstNode parent = node.parent;
1494 if (parent is PrefixedIdentifier) {
1495 return identical(parent.identifier, node);
1496 }
1497 if (parent is PropertyAccess) {
1498 return identical(parent.propertyName, node);
1499 }
1500 if (parent is MethodInvocation) {
1501 MethodInvocation invocation = parent;
1502 return invocation.realTarget != null && identical(invocation.methodName, n ode);
1503 }
1504 return false;
1505 }
1506
1507 final IndexStore _store;
1508
1509 LibraryElement _libraryElement;
1510
1511 Map<ImportElement, Set<Element>> _importElementsMap = {};
1512
1513 /**
1514 * A stack whose top element (the element with the largest index) is an elemen t representing the
1515 * inner-most enclosing scope.
1516 */
1517 Queue<Element> _elementStack = new Queue();
1518
1519 IndexContributor(this._store);
1520
1521 /**
1522 * Enter a new scope represented by the given [Element].
1523 */
1524 void enterScope(Element element) {
1525 _elementStack.addFirst(element);
1526 }
1527
1528 /**
1529 * @return the inner-most enclosing [Element], may be `null`.
1530 */
1531 Element peekElement() {
1532 for (Element element in _elementStack) {
1533 if (element != null) {
1534 return element;
1535 }
1536 }
1537 return null;
1538 }
1539
1540 @override
1541 Object visitAssignmentExpression(AssignmentExpression node) {
1542 _recordOperatorReference(node.operator, node.bestElement);
1543 return super.visitAssignmentExpression(node);
1544 }
1545
1546 @override
1547 Object visitBinaryExpression(BinaryExpression node) {
1548 _recordOperatorReference(node.operator, node.bestElement);
1549 return super.visitBinaryExpression(node);
1550 }
1551
1552 @override
1553 Object visitClassDeclaration(ClassDeclaration node) {
1554 ClassElement element = node.element;
1555 enterScope(element);
1556 try {
1557 _recordElementDefinition(element, IndexConstants.DEFINES_CLASS);
1558 {
1559 ExtendsClause extendsClause = node.extendsClause;
1560 if (extendsClause != null) {
1561 TypeName superclassNode = extendsClause.superclass;
1562 _recordSuperType(superclassNode, IndexConstants.IS_EXTENDED_BY);
1563 } else {
1564 InterfaceType superType = element.supertype;
1565 if (superType != null) {
1566 ClassElement objectElement = superType.element;
1567 recordRelationship(objectElement, IndexConstants.IS_EXTENDED_BY, _cr eateLocationFromOffset(node.name.offset, 0));
1568 }
1569 }
1570 }
1571 {
1572 WithClause withClause = node.withClause;
1573 if (withClause != null) {
1574 for (TypeName mixinNode in withClause.mixinTypes) {
1575 _recordSuperType(mixinNode, IndexConstants.IS_MIXED_IN_BY);
1576 }
1577 }
1578 }
1579 {
1580 ImplementsClause implementsClause = node.implementsClause;
1581 if (implementsClause != null) {
1582 for (TypeName interfaceNode in implementsClause.interfaces) {
1583 _recordSuperType(interfaceNode, IndexConstants.IS_IMPLEMENTED_BY);
1584 }
1585 }
1586 }
1587 return super.visitClassDeclaration(node);
1588 } finally {
1589 _exitScope();
1590 }
1591 }
1592
1593 @override
1594 Object visitClassTypeAlias(ClassTypeAlias node) {
1595 ClassElement element = node.element;
1596 enterScope(element);
1597 try {
1598 _recordElementDefinition(element, IndexConstants.DEFINES_CLASS_ALIAS);
1599 {
1600 TypeName superclassNode = node.superclass;
1601 if (superclassNode != null) {
1602 _recordSuperType(superclassNode, IndexConstants.IS_EXTENDED_BY);
1603 }
1604 }
1605 {
1606 WithClause withClause = node.withClause;
1607 if (withClause != null) {
1608 for (TypeName mixinNode in withClause.mixinTypes) {
1609 _recordSuperType(mixinNode, IndexConstants.IS_MIXED_IN_BY);
1610 }
1611 }
1612 }
1613 {
1614 ImplementsClause implementsClause = node.implementsClause;
1615 if (implementsClause != null) {
1616 for (TypeName interfaceNode in implementsClause.interfaces) {
1617 _recordSuperType(interfaceNode, IndexConstants.IS_IMPLEMENTED_BY);
1618 }
1619 }
1620 }
1621 return super.visitClassTypeAlias(node);
1622 } finally {
1623 _exitScope();
1624 }
1625 }
1626
1627 @override
1628 Object visitCompilationUnit(CompilationUnit node) {
1629 CompilationUnitElement unitElement = node.element;
1630 if (unitElement != null) {
1631 _elementStack.add(unitElement);
1632 _libraryElement = unitElement.enclosingElement;
1633 if (_libraryElement != null) {
1634 return super.visitCompilationUnit(node);
1635 }
1636 }
1637 return null;
1638 }
1639
1640 @override
1641 Object visitConstructorDeclaration(ConstructorDeclaration node) {
1642 ConstructorElement element = node.element;
1643 // define
1644 {
1645 Location location;
1646 if (node.name != null) {
1647 int start = node.period.offset;
1648 int end = node.name.end;
1649 location = _createLocationFromOffset(start, end - start);
1650 } else {
1651 int start = node.returnType.end;
1652 location = _createLocationFromOffset(start, 0);
1653 }
1654 recordRelationship(element, IndexConstants.IS_DEFINED_BY, location);
1655 }
1656 // visit children
1657 enterScope(element);
1658 try {
1659 return super.visitConstructorDeclaration(node);
1660 } finally {
1661 _exitScope();
1662 }
1663 }
1664
1665 @override
1666 Object visitConstructorName(ConstructorName node) {
1667 ConstructorElement element = node.staticElement;
1668 // in 'class B = A;' actually A constructors are invoked
1669 if (element != null && element.isSynthetic && element.redirectedConstructor != null) {
1670 element = element.redirectedConstructor;
1671 }
1672 // prepare location
1673 Location location;
1674 if (node.name != null) {
1675 int start = node.period.offset;
1676 int end = node.name.end;
1677 location = _createLocationFromOffset(start, end - start);
1678 } else {
1679 int start = node.type.end;
1680 location = _createLocationFromOffset(start, 0);
1681 }
1682 // record relationship
1683 recordRelationship(element, IndexConstants.IS_REFERENCED_BY, location);
1684 return super.visitConstructorName(node);
1685 }
1686
1687 @override
1688 Object visitExportDirective(ExportDirective node) {
1689 ExportElement element = node.element;
1690 if (element != null) {
1691 LibraryElement expLibrary = element.exportedLibrary;
1692 _recordLibraryReference(node, expLibrary);
1693 }
1694 return super.visitExportDirective(node);
1695 }
1696
1697 @override
1698 Object visitFormalParameter(FormalParameter node) {
1699 ParameterElement element = node.element;
1700 enterScope(element);
1701 try {
1702 return super.visitFormalParameter(node);
1703 } finally {
1704 _exitScope();
1705 }
1706 }
1707
1708 @override
1709 Object visitFunctionDeclaration(FunctionDeclaration node) {
1710 Element element = node.element;
1711 _recordElementDefinition(element, IndexConstants.DEFINES_FUNCTION);
1712 enterScope(element);
1713 try {
1714 return super.visitFunctionDeclaration(node);
1715 } finally {
1716 _exitScope();
1717 }
1718 }
1719
1720 @override
1721 Object visitFunctionTypeAlias(FunctionTypeAlias node) {
1722 Element element = node.element;
1723 _recordElementDefinition(element, IndexConstants.DEFINES_FUNCTION_TYPE);
1724 return super.visitFunctionTypeAlias(node);
1725 }
1726
1727 @override
1728 Object visitImportDirective(ImportDirective node) {
1729 ImportElement element = node.element;
1730 if (element != null) {
1731 LibraryElement impLibrary = element.importedLibrary;
1732 _recordLibraryReference(node, impLibrary);
1733 }
1734 return super.visitImportDirective(node);
1735 }
1736
1737 @override
1738 Object visitIndexExpression(IndexExpression node) {
1739 MethodElement element = node.bestElement;
1740 if (element is MethodElement) {
1741 Token operator = node.leftBracket;
1742 Location location = _createLocationFromToken(operator);
1743 recordRelationship(element, IndexConstants.IS_INVOKED_BY_QUALIFIED, locati on);
1744 }
1745 return super.visitIndexExpression(node);
1746 }
1747
1748 @override
1749 Object visitMethodDeclaration(MethodDeclaration node) {
1750 ExecutableElement element = node.element;
1751 enterScope(element);
1752 try {
1753 return super.visitMethodDeclaration(node);
1754 } finally {
1755 _exitScope();
1756 }
1757 }
1758
1759 @override
1760 Object visitMethodInvocation(MethodInvocation node) {
1761 SimpleIdentifier name = node.methodName;
1762 Element element = name.bestElement;
1763 if (element is MethodElement) {
1764 Location location = _createLocationFromNode(name);
1765 Relationship relationship;
1766 if (node.target != null) {
1767 relationship = IndexConstants.IS_INVOKED_BY_QUALIFIED;
1768 } else {
1769 relationship = IndexConstants.IS_INVOKED_BY_UNQUALIFIED;
1770 }
1771 recordRelationship(element, relationship, location);
1772 }
1773 if (element is FunctionElement) {
1774 Location location = _createLocationFromNode(name);
1775 recordRelationship(element, IndexConstants.IS_INVOKED_BY, location);
1776 }
1777 _recordImportElementReferenceWithoutPrefix(name);
1778 return super.visitMethodInvocation(node);
1779 }
1780
1781 @override
1782 Object visitPartDirective(PartDirective node) {
1783 Element element = node.element;
1784 Location location = _createLocationFromNode(node.uri);
1785 recordRelationship(element, IndexConstants.IS_REFERENCED_BY, location);
1786 return super.visitPartDirective(node);
1787 }
1788
1789 @override
1790 Object visitPartOfDirective(PartOfDirective node) {
1791 Location location = _createLocationFromNode(node.libraryName);
1792 recordRelationship(node.element, IndexConstants.IS_REFERENCED_BY, location);
1793 return null;
1794 }
1795
1796 @override
1797 Object visitPostfixExpression(PostfixExpression node) {
1798 _recordOperatorReference(node.operator, node.bestElement);
1799 return super.visitPostfixExpression(node);
1800 }
1801
1802 @override
1803 Object visitPrefixExpression(PrefixExpression node) {
1804 _recordOperatorReference(node.operator, node.bestElement);
1805 return super.visitPrefixExpression(node);
1806 }
1807
1808 @override
1809 Object visitSimpleIdentifier(SimpleIdentifier node) {
1810 Element nameElement = new NameElementImpl(node.name);
1811 Location location = _createLocationFromNode(node);
1812 // name in declaration
1813 if (node.inDeclarationContext()) {
1814 recordRelationship(nameElement, IndexConstants.IS_DEFINED_BY, location);
1815 return null;
1816 }
1817 // prepare information
1818 Element element = node.bestElement;
1819 // qualified name reference
1820 _recordQualifiedMemberReference(node, element, nameElement, location);
1821 // stop if already handled
1822 if (_isAlreadyHandledName(node)) {
1823 return null;
1824 }
1825 // record specific relations
1826 if (element is ClassElement || element is FunctionElement || element is Func tionTypeAliasElement || element is LabelElement || element is TypeParameterEleme nt) {
1827 recordRelationship(element, IndexConstants.IS_REFERENCED_BY, location);
1828 } else if (element is FieldElement) {
1829 location = _getLocationWithInitializerType(node, location);
1830 recordRelationship(element, IndexConstants.IS_REFERENCED_BY, location);
1831 } else if (element is FieldFormalParameterElement) {
1832 FieldFormalParameterElement fieldParameter = element;
1833 FieldElement field = fieldParameter.field;
1834 recordRelationship(field, IndexConstants.IS_REFERENCED_BY_QUALIFIED, locat ion);
1835 } else if (element is PrefixElement) {
1836 _recordImportElementReferenceWithPrefix(node);
1837 } else if (element is PropertyAccessorElement || element is MethodElement) {
1838 location = _getLocationWithTypeAssignedToField(node, element, location);
1839 if (_isQualified(node)) {
1840 recordRelationship(element, IndexConstants.IS_REFERENCED_BY_QUALIFIED, l ocation);
1841 } else {
1842 recordRelationship(element, IndexConstants.IS_REFERENCED_BY_UNQUALIFIED, location);
1843 }
1844 } else if (element is ParameterElement || element is LocalVariableElement) {
1845 bool inGetterContext = node.inGetterContext();
1846 bool inSetterContext = node.inSetterContext();
1847 if (inGetterContext && inSetterContext) {
1848 recordRelationship(element, IndexConstants.IS_READ_WRITTEN_BY, location) ;
1849 } else if (inGetterContext) {
1850 recordRelationship(element, IndexConstants.IS_READ_BY, location);
1851 } else if (inSetterContext) {
1852 recordRelationship(element, IndexConstants.IS_WRITTEN_BY, location);
1853 } else {
1854 recordRelationship(element, IndexConstants.IS_REFERENCED_BY, location);
1855 }
1856 }
1857 _recordImportElementReferenceWithoutPrefix(node);
1858 return super.visitSimpleIdentifier(node);
1859 }
1860
1861 @override
1862 Object visitSuperConstructorInvocation(SuperConstructorInvocation node) {
1863 ConstructorElement element = node.staticElement;
1864 Location location;
1865 if (node.constructorName != null) {
1866 int start = node.period.offset;
1867 int end = node.constructorName.end;
1868 location = _createLocationFromOffset(start, end - start);
1869 } else {
1870 int start = node.keyword.end;
1871 location = _createLocationFromOffset(start, 0);
1872 }
1873 recordRelationship(element, IndexConstants.IS_REFERENCED_BY, location);
1874 return super.visitSuperConstructorInvocation(node);
1875 }
1876
1877 @override
1878 Object visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) {
1879 VariableDeclarationList variables = node.variables;
1880 for (VariableDeclaration variableDeclaration in variables.variables) {
1881 Element element = variableDeclaration.element;
1882 _recordElementDefinition(element, IndexConstants.DEFINES_VARIABLE);
1883 }
1884 return super.visitTopLevelVariableDeclaration(node);
1885 }
1886
1887 @override
1888 Object visitTypeParameter(TypeParameter node) {
1889 TypeParameterElement element = node.element;
1890 enterScope(element);
1891 try {
1892 return super.visitTypeParameter(node);
1893 } finally {
1894 _exitScope();
1895 }
1896 }
1897
1898 @override
1899 Object visitVariableDeclaration(VariableDeclaration node) {
1900 VariableElement element = node.element;
1901 // record declaration
1902 {
1903 SimpleIdentifier name = node.name;
1904 Location location = _createLocationFromNode(name);
1905 location = _getLocationWithExpressionType(location, node.initializer);
1906 recordRelationship(element, IndexConstants.IS_DEFINED_BY, location);
1907 }
1908 // visit
1909 enterScope(element);
1910 try {
1911 return super.visitVariableDeclaration(node);
1912 } finally {
1913 _exitScope();
1914 }
1915 }
1916
1917 @override
1918 Object visitVariableDeclarationList(VariableDeclarationList node) {
1919 NodeList<VariableDeclaration> variables = node.variables;
1920 if (variables != null) {
1921 // use first VariableDeclaration as Element for Location(s) in type
1922 {
1923 TypeName type = node.type;
1924 if (type != null) {
1925 for (VariableDeclaration variableDeclaration in variables) {
1926 enterScope(variableDeclaration.element);
1927 try {
1928 type.accept(this);
1929 } finally {
1930 _exitScope();
1931 }
1932 // only one iteration
1933 break;
1934 }
1935 }
1936 }
1937 // visit variables
1938 variables.accept(this);
1939 }
1940 return null;
1941 }
1942
1943 /**
1944 * Record the given relationship between the given [Element] and [Location].
1945 */
1946 void recordRelationship(Element element, Relationship relationship, Location l ocation) {
1947 if (element != null && location != null) {
1948 _store.recordRelationship(element, relationship, location);
1949 }
1950 }
1951
1952 /**
1953 * @return the [Location] representing location of the [AstNode].
1954 */
1955 Location _createLocationFromNode(AstNode node) => _createLocationFromOffset(no de.offset, node.length);
1956
1957 /**
1958 * @param offset the offset of the location within [Source]
1959 * @param length the length of the location
1960 * @return the [Location] representing the given offset and length within the inner-most
1961 * [Element].
1962 */
1963 Location _createLocationFromOffset(int offset, int length) {
1964 Element element = peekElement();
1965 return new Location(element, offset, length);
1966 }
1967
1968 /**
1969 * @return the [Location] representing location of the [Token].
1970 */
1971 Location _createLocationFromToken(Token token) => _createLocationFromOffset(to ken.offset, token.length);
1972
1973 /**
1974 * Exit the current scope.
1975 */
1976 void _exitScope() {
1977 _elementStack.removeFirst();
1978 }
1979
1980 /**
1981 * @return `true` if given node already indexed as more interesting reference, so it should
1982 * not be indexed again.
1983 */
1984 bool _isAlreadyHandledName(SimpleIdentifier node) {
1985 AstNode parent = node.parent;
1986 if (parent is MethodInvocation) {
1987 Element element = node.staticElement;
1988 if (element is MethodElement || element is FunctionElement) {
1989 return identical(parent.methodName, node);
1990 }
1991 }
1992 return false;
1993 }
1994
1995 /**
1996 * Records the [Element] definition in the library and universe.
1997 */
1998 void _recordElementDefinition(Element element, Relationship relationship) {
1999 Location location = createLocation(element);
2000 recordRelationship(_libraryElement, relationship, location);
2001 recordRelationship(IndexConstants.UNIVERSE, relationship, location);
2002 }
2003
2004 /**
2005 * Records [ImportElement] reference if given [SimpleIdentifier] references so me
2006 * top-level element and not qualified with import prefix.
2007 */
2008 void _recordImportElementReferenceWithoutPrefix(SimpleIdentifier node) {
2009 if (_isIdentifierInImportCombinator(node)) {
2010 return;
2011 }
2012 if (_isIdentifierInPrefixedIdentifier(node)) {
2013 return;
2014 }
2015 Element element = node.staticElement;
2016 ImportElement importElement = _internalGetImportElement(_libraryElement, nul l, element, _importElementsMap);
2017 if (importElement != null) {
2018 Location location = _createLocationFromOffset(node.offset, 0);
2019 recordRelationship(importElement, IndexConstants.IS_REFERENCED_BY, locatio n);
2020 }
2021 }
2022
2023 /**
2024 * Records [ImportElement] that declares given prefix and imports library with element used
2025 * with given prefix node.
2026 */
2027 void _recordImportElementReferenceWithPrefix(SimpleIdentifier prefixNode) {
2028 IndexContributor_ImportElementInfo info = getImportElementInfo(prefixNode);
2029 if (info != null) {
2030 int offset = prefixNode.offset;
2031 int length = info._periodEnd - offset;
2032 Location location = _createLocationFromOffset(offset, length);
2033 recordRelationship(info._element, IndexConstants.IS_REFERENCED_BY, locatio n);
2034 }
2035 }
2036
2037 /**
2038 * Records reference to defining [CompilationUnitElement] of the given
2039 * [LibraryElement].
2040 */
2041 void _recordLibraryReference(UriBasedDirective node, LibraryElement library) {
2042 if (library != null) {
2043 Location location = _createLocationFromNode(node.uri);
2044 recordRelationship(library.definingCompilationUnit, IndexConstants.IS_REFE RENCED_BY, location);
2045 }
2046 }
2047
2048 /**
2049 * Record reference to the given operator [Element] and name.
2050 */
2051 void _recordOperatorReference(Token operator, Element element) {
2052 // prepare location
2053 Location location = _createLocationFromToken(operator);
2054 // record name reference
2055 {
2056 String name = operator.lexeme;
2057 if (name == "++") {
2058 name = "+";
2059 }
2060 if (name == "--") {
2061 name = "-";
2062 }
2063 if (StringUtilities.endsWithChar(name, 0x3D) && name != "==") {
2064 name = name.substring(0, name.length - 1);
2065 }
2066 Element nameElement = new NameElementImpl(name);
2067 Relationship relationship = element != null ? IndexConstants.IS_REFERENCED _BY_QUALIFIED_RESOLVED : IndexConstants.IS_REFERENCED_BY_QUALIFIED_UNRESOLVED;
2068 recordRelationship(nameElement, relationship, location);
2069 }
2070 // record element reference
2071 if (element != null) {
2072 recordRelationship(element, IndexConstants.IS_INVOKED_BY_QUALIFIED, locati on);
2073 }
2074 }
2075
2076 /**
2077 * Records reference if the given [SimpleIdentifier] looks like a qualified pr operty access
2078 * or method invocation.
2079 */
2080 void _recordQualifiedMemberReference(SimpleIdentifier node, Element element, E lement nameElement, Location location) {
2081 if (_isQualified(node)) {
2082 Relationship relationship = element != null ? IndexConstants.IS_REFERENCED _BY_QUALIFIED_RESOLVED : IndexConstants.IS_REFERENCED_BY_QUALIFIED_UNRESOLVED;
2083 recordRelationship(nameElement, relationship, location);
2084 }
2085 }
2086
2087 /**
2088 * Records extends/implements relationships between given [ClassElement] and [ Type] of
2089 * "superNode".
2090 */
2091 void _recordSuperType(TypeName superNode, Relationship relationship) {
2092 if (superNode != null) {
2093 Identifier superName = superNode.name;
2094 if (superName != null) {
2095 Element superElement = superName.staticElement;
2096 recordRelationship(superElement, relationship, _createLocationFromNode(s uperNode));
2097 }
2098 }
2099 }
2100 } 2328 }
2101 2329
2102 /** 2330 /**
2103 * Information about [ImportElement] and place where it is referenced using
2104 * [PrefixElement].
2105 */
2106 class IndexContributor_ImportElementInfo {
2107 ImportElement _element;
2108
2109 int _periodEnd = 0;
2110 }
2111
2112 /**
2113 * The interface [Index] defines the behavior of objects that maintain an index storing
2114 * [Relationship] between [Element]. All of the operations
2115 * defined on the index are asynchronous, and results, when there are any, are p rovided through a
2116 * callback.
2117 *
2118 * Despite being asynchronous, the results of the operations are guaranteed to b e consistent with
2119 * the expectation that operations are performed in the order in which they are requested.
2120 * Modification operations are executed before any read operation. There is no g uarantee about the
2121 * order in which the callbacks for read operations will be invoked.
2122 */
2123 abstract class Index {
2124 /**
2125 * Asynchronously invoke the given callback with an array containing all of th e locations of the
2126 * elements that have the given relationship with the given element. For examp le, if the element
2127 * represents a method and the relationship is the is-referenced-by relationsh ip, then the
2128 * locations that will be passed into the callback will be all of the places w here the method is
2129 * invoked.
2130 *
2131 * @param element the element that has the relationship with the locations to be returned
2132 * @param relationship the relationship between the given element and the loca tions to be returned
2133 * @param callback the callback that will be invoked when the locations are fo und
2134 */
2135 void getRelationships(Element element, Relationship relationship, Relationship Callback callback);
2136
2137 /**
2138 * Answer index statistics.
2139 */
2140 String get statistics;
2141
2142 /**
2143 * Asynchronously process the given [HtmlUnit] in order to record the relation ships.
2144 *
2145 * @param context the [AnalysisContext] in which [HtmlUnit] was resolved
2146 * @param unit the [HtmlUnit] being indexed
2147 */
2148 void indexHtmlUnit(AnalysisContext context, ht.HtmlUnit unit);
2149
2150 /**
2151 * Asynchronously process the given [CompilationUnit] in order to record the r elationships.
2152 *
2153 * @param context the [AnalysisContext] in which [CompilationUnit] was resolve d
2154 * @param unit the [CompilationUnit] being indexed
2155 */
2156 void indexUnit(AnalysisContext context, CompilationUnit unit);
2157
2158 /**
2159 * Asynchronously remove from the index all of the information associated with the given context.
2160 *
2161 * This method should be invoked when a context is disposed.
2162 *
2163 * @param context the [AnalysisContext] to remove
2164 */
2165 void removeContext(AnalysisContext context);
2166
2167 /**
2168 * Asynchronously remove from the index all of the information associated with elements or
2169 * locations in the given source. This includes relationships between an eleme nt in the given
2170 * source and any other locations, relationships between any other elements an d a location within
2171 * the given source.
2172 *
2173 * This method should be invoked when a source is no longer part of the code b ase.
2174 *
2175 * @param context the [AnalysisContext] in which [Source] being removed
2176 * @param source the [Source] being removed
2177 */
2178 void removeSource(AnalysisContext context, Source source);
2179
2180 /**
2181 * Asynchronously remove from the index all of the information associated with elements or
2182 * locations in the given sources. This includes relationships between an elem ent in the given
2183 * sources and any other locations, relationships between any other elements a nd a location within
2184 * the given sources.
2185 *
2186 * This method should be invoked when multiple sources are no longer part of t he code base.
2187 *
2188 * @param the [AnalysisContext] in which [Source]s being removed
2189 * @param container the [SourceContainer] holding the sources being removed
2190 */
2191 void removeSources(AnalysisContext context, SourceContainer container);
2192
2193 /**
2194 * Should be called in separate [Thread] to process request in this [Index]. D oes not
2195 * return until the [stop] method is called.
2196 */
2197 void run();
2198
2199 /**
2200 * Should be called to stop process running [run], so stop processing requests .
2201 */
2202 void stop();
2203 }
2204
2205 /**
2206 * Instances of the [RemoveContextOperation] implement an operation that removes from the 2331 * Instances of the [RemoveContextOperation] implement an operation that removes from the
2207 * index any data based on the specified [AnalysisContext]. 2332 * index any data based on the specified [AnalysisContext].
2208 */ 2333 */
2209 class RemoveContextOperation implements IndexOperation { 2334 class RemoveContextOperation implements IndexOperation {
2210 /** 2335 /**
2211 * The index store against which this operation is being run. 2336 * The index store against which this operation is being run.
2212 */ 2337 */
2213 final IndexStore _indexStore; 2338 final IndexStore _indexStore;
2214 2339
2215 /** 2340 /**
(...skipping 18 matching lines...) Expand all
2234 } 2359 }
2235 2360
2236 @override 2361 @override
2237 bool removeWhenSourceRemoved(Source source) => false; 2362 bool removeWhenSourceRemoved(Source source) => false;
2238 2363
2239 @override 2364 @override
2240 String toString() => "RemoveContext(${context})"; 2365 String toString() => "RemoveContext(${context})";
2241 } 2366 }
2242 2367
2243 /** 2368 /**
2244 * Instances of the [GetRelationshipsOperation] implement an operation used to a ccess the
2245 * locations that have a specified relationship with a specified element.
2246 */
2247 class GetRelationshipsOperation implements IndexOperation {
2248 final IndexStore _indexStore;
2249
2250 final Element element;
2251
2252 final Relationship relationship;
2253
2254 final RelationshipCallback callback;
2255
2256 /**
2257 * Initialize a newly created operation that will access the locations that ha ve a specified
2258 * relationship with a specified element.
2259 */
2260 GetRelationshipsOperation(this._indexStore, this.element, this.relationship, t his.callback);
2261
2262 @override
2263 bool get isQuery => true;
2264
2265 @override
2266 void performOperation() {
2267 List<Location> locations;
2268 locations = _indexStore.getRelationships(element, relationship);
2269 callback.hasRelationships(element, relationship, locations);
2270 }
2271
2272 @override
2273 bool removeWhenSourceRemoved(Source source) => false;
2274
2275 @override
2276 String toString() => "GetRelationships(${element}, ${relationship})";
2277 }
2278
2279 /**
2280 * Instances of the [RemoveSourceOperation] implement an operation that removes from the index 2369 * Instances of the [RemoveSourceOperation] implement an operation that removes from the index
2281 * any data based on the content of a specified source. 2370 * any data based on the content of a specified source.
2282 */ 2371 */
2283 class RemoveSourceOperation implements IndexOperation { 2372 class RemoveSourceOperation implements IndexOperation {
2284 /** 2373 /**
2285 * The index store against which this operation is being run. 2374 * The index store against which this operation is being run.
2286 */ 2375 */
2287 final IndexStore _indexStore; 2376 final IndexStore _indexStore;
2288 2377
2289 /** 2378 /**
(...skipping 24 matching lines...) Expand all
2314 } 2403 }
2315 2404
2316 @override 2405 @override
2317 bool removeWhenSourceRemoved(Source source) => false; 2406 bool removeWhenSourceRemoved(Source source) => false;
2318 2407
2319 @override 2408 @override
2320 String toString() => "RemoveSource(${source.fullName})"; 2409 String toString() => "RemoveSource(${source.fullName})";
2321 } 2410 }
2322 2411
2323 /** 2412 /**
2324 * The interface [IndexOperation] defines the behavior of objects used to perfor m operations 2413 * Instances of the [RemoveSourcesOperation] implement an operation that removes from the
2325 * on an index. 2414 * index any data based on the content of source belonging to a [SourceContainer ].
2326 */ 2415 */
2327 abstract class IndexOperation { 2416 class RemoveSourcesOperation implements IndexOperation {
2328 /** 2417 /**
2329 * Return `true` if this operation returns information from the index. 2418 * The index store against which this operation is being run.
2330 *
2331 * @return `true` if this operation returns information from the index
2332 */ 2419 */
2333 bool get isQuery; 2420 final IndexStore _indexStore;
2334 2421
2335 /** 2422 /**
2336 * Perform the operation implemented by this operation. 2423 * The context to remove container.
2337 */ 2424 */
2338 void performOperation(); 2425 final AnalysisContext _context;
2339 2426
2340 /** 2427 /**
2341 * Return `true` if this operation should be removed from the operation queue when the 2428 * The source container to remove.
2342 * given resource has been removed. 2429 */
2430 final SourceContainer container;
2431
2432 /**
2433 * Initialize a newly created operation that will remove the specified resourc e.
2343 * 2434 *
2344 * @param source the [Source] that has been removed 2435 * @param indexStore the index store against which this operation is being run
2345 * @return `true` if this operation should be removed from the operation queue as a 2436 * @param context the [AnalysisContext] to remove container in
2346 * result of removing the resource 2437 * @param container the [SourceContainer] to remove from index
2347 */ 2438 */
2348 bool removeWhenSourceRemoved(Source source); 2439 RemoveSourcesOperation(this._indexStore, this._context, this.container);
2440
2441 @override
2442 bool get isQuery => false;
2443
2444 @override
2445 void performOperation() {
2446 _indexStore.removeSources(_context, container);
2447 }
2448
2449 @override
2450 bool removeWhenSourceRemoved(Source source) => false;
2451
2452 @override
2453 String toString() => "RemoveSources(${container})";
2349 } 2454 }
2350 2455
2351 /** 2456 /**
2352 * [IndexStore] which keeps all information in memory, but can write it to strea m and read 2457 * The interface `UniverseElement` defines element to use when we want to reques t "defines"
2353 * later. 2458 * relations without specifying exact library.
2354 */ 2459 */
2355 abstract class MemoryIndexStore implements IndexStore { 2460 abstract class UniverseElement implements Element {
2461 static final UniverseElement INSTANCE = UniverseElementImpl.INSTANCE;
2356 } 2462 }
2357 2463
2358 /** 2464 /**
2359 * [Location] with attached data. 2465 * Implementation of [UniverseElement].
2360 */ 2466 */
2361 class LocationWithData<D> extends Location { 2467 class UniverseElementImpl extends ElementImpl implements UniverseElement {
2362 final D data; 2468 static UniverseElementImpl INSTANCE = new UniverseElementImpl();
2363 2469
2364 LocationWithData.con1(Location location, this.data) : super(location.element, location.offset, location.length); 2470 UniverseElementImpl() : super("--universe--", -1);
2365
2366 LocationWithData.con2(Element element, int offset, int length, this.data) : su per(element, offset, length);
2367 2471
2368 @override 2472 @override
2369 Location newClone() => new LocationWithData<D>.con2(element, offset, length, d ata); 2473 accept(ElementVisitor visitor) => null;
2370 }
2371
2372 /**
2373 * Relationship between an element and a location. Relationships are identified by a globally unique
2374 * identifier.
2375 */
2376 class Relationship {
2377 /**
2378 * The unique identifier for this relationship.
2379 */
2380 final String _uniqueId;
2381
2382 /**
2383 * A table mapping relationship identifiers to relationships.
2384 */
2385 static Map<String, Relationship> _RelationshipMap = {};
2386
2387 /**
2388 * Return the relationship with the given unique identifier.
2389 *
2390 * @param uniqueId the unique identifier for the relationship
2391 * @return the relationship with the given unique identifier
2392 */
2393 static Relationship getRelationship(String uniqueId) {
2394 Relationship relationship = _RelationshipMap[uniqueId];
2395 if (relationship == null) {
2396 relationship = new Relationship(uniqueId);
2397 _RelationshipMap[uniqueId] = relationship;
2398 }
2399 return relationship;
2400 }
2401
2402 /**
2403 * @return all registered [Relationship]s.
2404 */
2405 static Iterable<Relationship> values() => _RelationshipMap.values;
2406
2407 /**
2408 * Initialize a newly created relationship to have the given unique identifier .
2409 *
2410 * @param uniqueId the unique identifier for this relationship
2411 */
2412 Relationship(this._uniqueId);
2413
2414 /**
2415 * Return the unique identifier for this relationship.
2416 *
2417 * @return the unique identifier for this relationship
2418 */
2419 String get identifier => _uniqueId;
2420 2474
2421 @override 2475 @override
2422 String toString() => _uniqueId; 2476 ElementKind get kind => ElementKind.UNIVERSE;
2423 }
2424
2425 /**
2426 * Instances of the class <code>Location</code> represent a location related to an element. The
2427 * location is expressed as an offset and length, but the offset is relative to the resource
2428 * containing the element rather than the start of the element within that resou rce.
2429 */
2430 class Location {
2431 /**
2432 * An empty array of locations.
2433 */
2434 static List<Location> EMPTY_ARRAY = new List<Location>(0);
2435
2436 /**
2437 * The element containing this location.
2438 */
2439 final Element element;
2440
2441 /**
2442 * The offset of this location within the resource containing the element.
2443 */
2444 final int offset;
2445
2446 /**
2447 * The length of this location.
2448 */
2449 final int length;
2450
2451 /**
2452 * Internal field used to hold a key that is referenced at this location.
2453 */
2454 Object internalKey;
2455
2456 /**
2457 * Initialize a newly create location to be relative to the given element at t he given offset with
2458 * the given length.
2459 *
2460 * @param element the [Element] containing this location
2461 * @param offset the offset of this location within the resource containing th e element
2462 * @param length the length of this location
2463 */
2464 Location(this.element, this.offset, this.length) {
2465 if (element == null) {
2466 throw new IllegalArgumentException("element location cannot be null");
2467 }
2468 }
2469
2470 /**
2471 * Returns a clone of this [Location].
2472 */
2473 Location newClone() => new Location(element, offset, length);
2474
2475 @override
2476 String toString() => "[${offset} - ${(offset + length)}) in ${element}";
2477 } 2477 }
OLDNEW
« no previous file with comments | « pkg/analyzer/lib/src/generated/html.dart ('k') | pkg/analyzer/lib/src/generated/instrumentation.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698