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

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

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

Powered by Google App Engine
This is Rietveld 408576698