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

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

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

Powered by Google App Engine
This is Rietveld 408576698