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

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

Issue 363373002: IndexStore, Index and SearchEngine APIs and partial implementatons. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4
5 // This code was auto-generated, is not intended to be edited, and is subject to
6 // significant change. Please see the README file for more information.
7
8 library engine.src.index;
9
10 import 'dart:collection' show Queue;
11
12 import 'package:analyzer/index/index.dart';
13 import 'package:analyzer/index/index_store.dart';
14 import 'package:analyzer/src/generated/ast.dart';
15 import 'package:analyzer/src/generated/element.dart';
16 import 'package:analyzer/src/generated/engine.dart';
17 import 'package:analyzer/src/generated/html.dart' as ht;
18 import 'package:analyzer/src/generated/java_core.dart';
19 import 'package:analyzer/src/generated/java_engine.dart';
20 import 'package:analyzer/src/generated/resolver.dart';
21 import 'package:analyzer/src/generated/scanner.dart';
22 import 'package:analyzer/src/generated/source.dart';
23
24
25 /**
26 * Adds data to [store] based on the resolved Dart [unit].
27 */
28 void indexDartUnit(IndexStore store, AnalysisContext context,
29 CompilationUnit unit) {
30 CompilationUnitElement unitElement = unit.element;
31 bool mayIndex = store.aboutToIndexDart(context, unitElement);
32 if (!mayIndex) {
33 return;
34 }
35 unit.accept(new _IndexContributor(store));
36 unit.accept(new _AngularDartIndexContributor(store));
37 store.doneIndex();
38 }
39
40
41 /**
42 * Adds data to [store] based on the resolved HTML [unit].
43 */
44 void indexHtmlUnit(IndexStore store, AnalysisContext context, ht.HtmlUnit unit)
45 {
46 HtmlElement unitElement = unit.element;
47 bool mayIndex = store.aboutToIndexHtml(context, unitElement);
48 if (!mayIndex) {
49 return;
50 }
51 unit.accept(new _AngularHtmlIndexContributor(store));
52 store.doneIndex();
53 }
54
55
56 /**
57 * Visits resolved [CompilationUnit] and adds Angular specific relationships
58 * into [IndexStore].
59 */
60 class _AngularDartIndexContributor extends GeneralizingAstVisitor<Object> {
61 final IndexStore _store;
62
63 _AngularDartIndexContributor(this._store);
64
65 @override
66 Object visitClassDeclaration(ClassDeclaration node) {
67 ClassElement classElement = node.element;
68 if (classElement != null) {
69 List<ToolkitObjectElement> toolkitObjects = classElement.toolkitObjects;
70 for (ToolkitObjectElement object in toolkitObjects) {
71 if (object is AngularComponentElement) {
72 _indexComponent(object);
73 }
74 if (object is AngularDecoratorElement) {
75 AngularDecoratorElement directive = object;
76 _indexDirective(directive);
77 }
78 }
79 }
80 // stop visiting
81 return null;
82 }
83
84 @override
85 Object visitCompilationUnitMember(CompilationUnitMember node) => null;
86
87 void _indexComponent(AngularComponentElement component) {
88 _indexProperties(component.properties);
89 }
90
91 void _indexDirective(AngularDecoratorElement directive) {
92 _indexProperties(directive.properties);
93 }
94
95 /**
96 * Index [FieldElement] references from [AngularPropertyElement]s.
97 */
98 void _indexProperties(List<AngularPropertyElement> properties) {
99 for (AngularPropertyElement property in properties) {
100 FieldElement field = property.field;
101 if (field != null) {
102 int offset = property.fieldNameOffset;
103 if (offset == -1) {
104 continue;
105 }
106 int length = field.name.length;
107 Location location = new Location(property, offset, length);
108 // getter reference
109 if (property.propertyKind.callsGetter()) {
110 PropertyAccessorElement getter = field.getter;
111 if (getter != null) {
112 _store.recordRelationship(getter,
113 IndexConstants.IS_REFERENCED_BY_QUALIFIED, location);
114 }
115 }
116 // setter reference
117 if (property.propertyKind.callsSetter()) {
118 PropertyAccessorElement setter = field.setter;
119 if (setter != null) {
120 _store.recordRelationship(setter,
121 IndexConstants.IS_REFERENCED_BY_QUALIFIED, location);
122 }
123 }
124 }
125 }
126 }
127 }
128
129
130 /**
131 * Visits resolved [HtmlUnit] and adds relationships into [IndexStore].
132 */
133 class _AngularHtmlIndexContributor extends _ExpressionVisitor {
134 /**
135 * The [IndexStore] to record relations into.
136 */
137 final IndexStore _store;
138
139 /**
140 * The index contributor used to index Dart [Expression]s.
141 */
142 _IndexContributor _indexContributor;
143
144 HtmlElement _htmlUnitElement;
145
146 /**
147 * Initialize a newly created Angular HTML index contributor.
148 *
149 * @param store the [IndexStore] to record relations into.
150 */
151 _AngularHtmlIndexContributor(this._store) {
152 _indexContributor = new _AngularHtmlIndexContributor_forEmbeddedDart(_store,
153 this);
154 }
155
156 @override
157 void visitExpression(Expression expression) {
158 // Formatter
159 if (expression is SimpleIdentifier) {
160 SimpleIdentifier identifier = expression;
Brian Wilkerson 2014/07/03 18:58:13 I'm not sure what the value of this local variable
scheglov 2014/07/03 19:06:16 Fixed. Should it be a hint?
Brian Wilkerson 2014/07/03 20:48:19 Perhaps. If the original variable and the new vari
161 Element element = identifier.bestElement;
162 if (element is AngularElement) {
163 _store.recordRelationship(element, IndexConstants.ANGULAR_REFERENCE,
164 _createLocationForIdentifier(identifier));
165 return;
166 }
167 }
168 // index as a normal Dart expression
169 expression.accept(_indexContributor);
170 }
171
172 @override
173 Object visitHtmlUnit(ht.HtmlUnit node) {
174 _htmlUnitElement = node.element;
175 CompilationUnitElement dartUnitElement =
176 _htmlUnitElement.angularCompilationUnit;
177 _indexContributor.enterScope(dartUnitElement);
178 return super.visitHtmlUnit(node);
179 }
180
181 @override
182 Object visitXmlAttributeNode(ht.XmlAttributeNode node) {
183 Element element = node.element;
184 if (element != null) {
185 ht.Token nameToken = node.nameToken;
186 Location location = _createLocationForToken(nameToken);
187 _store.recordRelationship(element, IndexConstants.ANGULAR_REFERENCE,
188 location);
189 }
190 return super.visitXmlAttributeNode(node);
191 }
192
193 @override
194 Object visitXmlTagNode(ht.XmlTagNode node) {
195 Element element = node.element;
196 if (element != null) {
197 // tag
198 {
199 ht.Token tagToken = node.tagToken;
200 Location location = _createLocationForToken(tagToken);
201 _store.recordRelationship(element, IndexConstants.ANGULAR_REFERENCE,
202 location);
203 }
204 // maybe add closing tag range
205 ht.Token closingTag = node.closingTag;
206 if (closingTag != null) {
207 Location location = _createLocationForToken(closingTag);
208 _store.recordRelationship(element,
209 IndexConstants.ANGULAR_CLOSING_TAG_REFERENCE, location);
210 }
211 }
212 return super.visitXmlTagNode(node);
213 }
214
215 Location _createLocationForIdentifier(SimpleIdentifier identifier) =>
216 new Location(_htmlUnitElement, identifier.offset, identifier.length);
217
218 Location _createLocationForToken(ht.Token token) => new Location(
219 _htmlUnitElement, token.offset, token.length);
220 }
221
222
223 class _AngularHtmlIndexContributor_forEmbeddedDart extends _IndexContributor {
224 final _AngularHtmlIndexContributor angularContributor;
225
226 _AngularHtmlIndexContributor_forEmbeddedDart(IndexStore store,
227 this.angularContributor) : super(store);
228
229 @override
230 Element peekElement() => angularContributor._htmlUnitElement;
231
232 @override
233 void recordRelationship(Element element, Relationship relationship,
234 Location location) {
235 AngularElement angularElement = AngularHtmlUnitResolver.getAngularElement(
236 element);
237 if (angularElement != null) {
238 element = angularElement;
239 relationship = IndexConstants.ANGULAR_REFERENCE;
240 }
241 super.recordRelationship(element, relationship, location);
242 }
243 }
244
245
246 /**
247 * Recursively visits [HtmlUnit] and every embedded [Expression].
Brian Wilkerson 2014/07/03 18:58:13 "visits" --> "visits an"
scheglov 2014/07/03 19:06:16 Done.
248 */
249 abstract class _ExpressionVisitor extends ht.RecursiveXmlVisitor<Object> {
250 /**
251 * Visits the given [Expression]s embedded into tag or attribute.
252 *
253 * @param expression the [Expression] to visit, not `null`
254 */
255 void visitExpression(Expression expression);
256
257 @override
258 Object visitXmlAttributeNode(ht.XmlAttributeNode node) {
259 _visitExpressions(node.expressions);
260 return super.visitXmlAttributeNode(node);
261 }
262
263 @override
264 Object visitXmlTagNode(ht.XmlTagNode node) {
265 _visitExpressions(node.expressions);
266 return super.visitXmlTagNode(node);
267 }
268
269 /**
270 * Visits [Expression]s of the given [XmlExpression]s.
271 */
272 void _visitExpressions(List<ht.XmlExpression> expressions) {
273 for (ht.XmlExpression xmlExpression in expressions) {
274 if (xmlExpression is AngularXmlExpression) {
275 AngularXmlExpression angularXmlExpression = xmlExpression;
276 List<Expression> dartExpressions =
277 angularXmlExpression.expression.expressions;
278 for (Expression dartExpression in dartExpressions) {
279 visitExpression(dartExpression);
280 }
281 }
282 if (xmlExpression is ht.RawXmlExpression) {
283 ht.RawXmlExpression rawXmlExpression = xmlExpression;
284 visitExpression(rawXmlExpression.expression);
285 }
286 }
287 }
288 }
289
290
291 /**
292 * Information about [ImportElement] and place where it is referenced using
293 * [PrefixElement].
294 */
295 class _ImportElementInfo {
296 ImportElement _element;
297
298 int _periodEnd = 0;
299 }
300
301
302 /**
303 * Visits resolved AST and adds relationships into [IndexStore].
304 */
305 class _IndexContributor extends GeneralizingAstVisitor<Object> {
306 final IndexStore _store;
307
308 LibraryElement _libraryElement;
309
310 Map<ImportElement, Set<Element>> _importElementsMap = {};
311
312 /**
313 * A stack whose top element (the element with the largest index) is an elemen t representing the
314 * inner-most enclosing scope.
315 */
316 Queue<Element> _elementStack = new Queue();
317
318 _IndexContributor(this._store);
319
320 /**
321 * Enter a new scope represented by the given [Element].
322 */
323 void enterScope(Element element) {
324 _elementStack.addFirst(element);
325 }
326
327 /**
328 * @return the inner-most enclosing [Element], may be `null`.
329 */
330 Element peekElement() {
331 for (Element element in _elementStack) {
332 if (element != null) {
333 return element;
334 }
335 }
336 return null;
337 }
338
339 /**
340 * Record the given relationship between the given [Element] and [Location].
341 */
342 void recordRelationship(Element element, Relationship relationship,
343 Location location) {
344 if (element != null && location != null) {
345 _store.recordRelationship(element, relationship, location);
346 }
347 }
348
349 @override
350 Object visitAssignmentExpression(AssignmentExpression node) {
351 _recordOperatorReference(node.operator, node.bestElement);
352 return super.visitAssignmentExpression(node);
353 }
354
355 @override
356 Object visitBinaryExpression(BinaryExpression node) {
357 _recordOperatorReference(node.operator, node.bestElement);
358 return super.visitBinaryExpression(node);
359 }
360
361 @override
362 Object visitClassDeclaration(ClassDeclaration node) {
363 ClassElement element = node.element;
364 enterScope(element);
365 try {
366 _recordElementDefinition(element, IndexConstants.DEFINES_CLASS);
367 {
368 ExtendsClause extendsClause = node.extendsClause;
369 if (extendsClause != null) {
370 TypeName superclassNode = extendsClause.superclass;
371 _recordSuperType(superclassNode, IndexConstants.IS_EXTENDED_BY);
372 } else {
373 InterfaceType superType = element.supertype;
374 if (superType != null) {
375 ClassElement objectElement = superType.element;
376 recordRelationship(objectElement, IndexConstants.IS_EXTENDED_BY,
377 _createLocationFromOffset(node.name.offset, 0));
378 }
379 }
380 }
381 {
382 WithClause withClause = node.withClause;
383 if (withClause != null) {
384 for (TypeName mixinNode in withClause.mixinTypes) {
385 _recordSuperType(mixinNode, IndexConstants.IS_MIXED_IN_BY);
386 }
387 }
388 }
389 {
390 ImplementsClause implementsClause = node.implementsClause;
391 if (implementsClause != null) {
392 for (TypeName interfaceNode in implementsClause.interfaces) {
393 _recordSuperType(interfaceNode, IndexConstants.IS_IMPLEMENTED_BY);
394 }
395 }
396 }
397 return super.visitClassDeclaration(node);
398 } finally {
399 _exitScope();
400 }
401 }
402
403 @override
404 Object visitClassTypeAlias(ClassTypeAlias node) {
405 ClassElement element = node.element;
406 enterScope(element);
407 try {
408 _recordElementDefinition(element, IndexConstants.DEFINES_CLASS_ALIAS);
409 {
410 TypeName superclassNode = node.superclass;
411 if (superclassNode != null) {
412 _recordSuperType(superclassNode, IndexConstants.IS_EXTENDED_BY);
413 }
414 }
415 {
416 WithClause withClause = node.withClause;
417 if (withClause != null) {
418 for (TypeName mixinNode in withClause.mixinTypes) {
419 _recordSuperType(mixinNode, IndexConstants.IS_MIXED_IN_BY);
420 }
421 }
422 }
423 {
424 ImplementsClause implementsClause = node.implementsClause;
425 if (implementsClause != null) {
426 for (TypeName interfaceNode in implementsClause.interfaces) {
427 _recordSuperType(interfaceNode, IndexConstants.IS_IMPLEMENTED_BY);
428 }
429 }
430 }
431 return super.visitClassTypeAlias(node);
432 } finally {
433 _exitScope();
434 }
435 }
436
437 @override
438 Object visitCompilationUnit(CompilationUnit node) {
439 CompilationUnitElement unitElement = node.element;
440 if (unitElement != null) {
441 _elementStack.add(unitElement);
442 _libraryElement = unitElement.enclosingElement;
443 if (_libraryElement != null) {
444 return super.visitCompilationUnit(node);
445 }
446 }
447 return null;
448 }
449
450 @override
451 Object visitConstructorDeclaration(ConstructorDeclaration node) {
452 ConstructorElement element = node.element;
453 // define
454 {
455 Location location;
456 if (node.name != null) {
457 int start = node.period.offset;
458 int end = node.name.end;
459 location = _createLocationFromOffset(start, end - start);
460 } else {
461 int start = node.returnType.end;
462 location = _createLocationFromOffset(start, 0);
463 }
464 recordRelationship(element, IndexConstants.IS_DEFINED_BY, location);
465 }
466 // visit children
467 enterScope(element);
468 try {
469 return super.visitConstructorDeclaration(node);
470 } finally {
471 _exitScope();
472 }
473 }
474
475 @override
476 Object visitConstructorName(ConstructorName node) {
477 ConstructorElement element = node.staticElement;
478 // in 'class B = A;' actually A constructors are invoked
479 if (element != null && element.isSynthetic && element.redirectedConstructor
480 != null) {
481 element = element.redirectedConstructor;
482 }
483 // prepare location
484 Location location;
485 if (node.name != null) {
486 int start = node.period.offset;
487 int end = node.name.end;
488 location = _createLocationFromOffset(start, end - start);
489 } else {
490 int start = node.type.end;
491 location = _createLocationFromOffset(start, 0);
492 }
493 // record relationship
494 recordRelationship(element, IndexConstants.IS_REFERENCED_BY, location);
495 return super.visitConstructorName(node);
496 }
497
498 @override
499 Object visitExportDirective(ExportDirective node) {
500 ExportElement element = node.element;
501 if (element != null) {
502 LibraryElement expLibrary = element.exportedLibrary;
503 _recordLibraryReference(node, expLibrary);
504 }
505 return super.visitExportDirective(node);
506 }
507
508 @override
509 Object visitFormalParameter(FormalParameter node) {
510 ParameterElement element = node.element;
511 enterScope(element);
512 try {
513 return super.visitFormalParameter(node);
514 } finally {
515 _exitScope();
516 }
517 }
518
519 @override
520 Object visitFunctionDeclaration(FunctionDeclaration node) {
521 Element element = node.element;
522 _recordElementDefinition(element, IndexConstants.DEFINES_FUNCTION);
523 enterScope(element);
524 try {
525 return super.visitFunctionDeclaration(node);
526 } finally {
527 _exitScope();
528 }
529 }
530
531 @override
532 Object visitFunctionTypeAlias(FunctionTypeAlias node) {
533 Element element = node.element;
534 _recordElementDefinition(element, IndexConstants.DEFINES_FUNCTION_TYPE);
535 return super.visitFunctionTypeAlias(node);
536 }
537
538 @override
539 Object visitImportDirective(ImportDirective node) {
540 ImportElement element = node.element;
541 if (element != null) {
542 LibraryElement impLibrary = element.importedLibrary;
543 _recordLibraryReference(node, impLibrary);
544 }
545 return super.visitImportDirective(node);
546 }
547
548 @override
549 Object visitIndexExpression(IndexExpression node) {
550 MethodElement element = node.bestElement;
551 if (element is MethodElement) {
552 Token operator = node.leftBracket;
553 Location location = _createLocationFromToken(operator);
554 recordRelationship(element, IndexConstants.IS_INVOKED_BY_QUALIFIED,
555 location);
556 }
557 return super.visitIndexExpression(node);
558 }
559
560 @override
561 Object visitMethodDeclaration(MethodDeclaration node) {
562 ExecutableElement element = node.element;
563 enterScope(element);
564 try {
565 return super.visitMethodDeclaration(node);
566 } finally {
567 _exitScope();
568 }
569 }
570
571 @override
572 Object visitMethodInvocation(MethodInvocation node) {
573 SimpleIdentifier name = node.methodName;
574 Element element = name.bestElement;
575 if (element is MethodElement || element is PropertyAccessorElement) {
576 Location location = _createLocationFromNode(name);
577 Relationship relationship;
578 if (node.target != null) {
579 relationship = IndexConstants.IS_INVOKED_BY_QUALIFIED;
580 } else {
581 relationship = IndexConstants.IS_INVOKED_BY_UNQUALIFIED;
582 }
583 recordRelationship(element, relationship, location);
584 }
585 if (element is FunctionElement || element is VariableElement) {
586 Location location = _createLocationFromNode(name);
587 recordRelationship(element, IndexConstants.IS_INVOKED_BY, location);
588 }
589 // name invocation
590 {
591 Element nameElement = new NameElement(name.name);
592 Location location = _createLocationFromNode(name);
593 Relationship kind = element != null ?
594 IndexConstants.NAME_IS_INVOKED_BY_RESOLVED :
595 IndexConstants.NAME_IS_INVOKED_BY_UNRESOLVED;
596 _store.recordRelationship(nameElement, kind, location);
597 }
598 _recordImportElementReferenceWithoutPrefix(name);
599 return super.visitMethodInvocation(node);
600 }
601
602 @override
603 Object visitPartDirective(PartDirective node) {
604 Element element = node.element;
605 Location location = _createLocationFromNode(node.uri);
606 recordRelationship(element, IndexConstants.IS_REFERENCED_BY, location);
607 return super.visitPartDirective(node);
608 }
609
610 @override
611 Object visitPartOfDirective(PartOfDirective node) {
612 Location location = _createLocationFromNode(node.libraryName);
613 recordRelationship(node.element, IndexConstants.IS_REFERENCED_BY, location);
614 return null;
615 }
616
617 @override
618 Object visitPostfixExpression(PostfixExpression node) {
619 _recordOperatorReference(node.operator, node.bestElement);
620 return super.visitPostfixExpression(node);
621 }
622
623 @override
624 Object visitPrefixExpression(PrefixExpression node) {
625 _recordOperatorReference(node.operator, node.bestElement);
626 return super.visitPrefixExpression(node);
627 }
628
629 @override
630 Object visitSimpleIdentifier(SimpleIdentifier node) {
631 Element nameElement = new NameElement(node.name);
632 Location location = _createLocationFromNode(node);
633 // name in declaration
634 if (node.inDeclarationContext()) {
635 recordRelationship(nameElement, IndexConstants.IS_DEFINED_BY, location);
636 return null;
637 }
638 // prepare information
639 Element element = node.bestElement;
640 // qualified name reference
641 _recordQualifiedMemberReference(node, element, nameElement, location);
642 // stop if already handled
643 if (_isAlreadyHandledName(node)) {
644 return null;
645 }
646 // record name read/write
647 {
648 bool inGetterContext = node.inGetterContext();
649 bool inSetterContext = node.inSetterContext();
650 if (inGetterContext && inSetterContext) {
651 Relationship kind = element != null ?
652 IndexConstants.NAME_IS_READ_WRITTEN_BY_RESOLVED :
653 IndexConstants.NAME_IS_READ_WRITTEN_BY_UNRESOLVED;
654 _store.recordRelationship(nameElement, kind, location);
655 } else if (inGetterContext) {
656 Relationship kind = element != null ?
657 IndexConstants.NAME_IS_READ_BY_RESOLVED :
658 IndexConstants.NAME_IS_READ_BY_UNRESOLVED;
659 _store.recordRelationship(nameElement, kind, location);
660 } else if (inSetterContext) {
661 Relationship kind = element != null ?
662 IndexConstants.NAME_IS_WRITTEN_BY_RESOLVED :
663 IndexConstants.NAME_IS_WRITTEN_BY_UNRESOLVED;
664 _store.recordRelationship(nameElement, kind, location);
665 }
666 }
667 // record specific relations
668 if (element is ClassElement || element is FunctionElement || element is
669 FunctionTypeAliasElement || element is LabelElement || element is
670 TypeParameterElement) {
671 recordRelationship(element, IndexConstants.IS_REFERENCED_BY, location);
672 } else if (element is FieldElement) {
673 location = _getLocationWithInitializerType(node, location);
674 recordRelationship(element, IndexConstants.IS_REFERENCED_BY, location);
675 } else if (element is FieldFormalParameterElement) {
676 FieldFormalParameterElement fieldParameter = element;
677 FieldElement field = fieldParameter.field;
678 recordRelationship(field, IndexConstants.IS_REFERENCED_BY_QUALIFIED,
679 location);
680 } else if (element is PrefixElement) {
681 _recordImportElementReferenceWithPrefix(node);
682 } else if (element is PropertyAccessorElement || element is MethodElement) {
683 location = _getLocationWithTypeAssignedToField(node, element, location);
684 if (node.isQualified) {
685 recordRelationship(element, IndexConstants.IS_REFERENCED_BY_QUALIFIED,
686 location);
687 } else {
688 recordRelationship(element, IndexConstants.IS_REFERENCED_BY_UNQUALIFIED,
689 location);
690 }
691 } else if (element is ParameterElement || element is LocalVariableElement) {
692 bool inGetterContext = node.inGetterContext();
693 bool inSetterContext = node.inSetterContext();
694 if (inGetterContext && inSetterContext) {
695 recordRelationship(element, IndexConstants.IS_READ_WRITTEN_BY,
696 location);
697 } else if (inGetterContext) {
698 recordRelationship(element, IndexConstants.IS_READ_BY, location);
699 } else if (inSetterContext) {
700 recordRelationship(element, IndexConstants.IS_WRITTEN_BY, location);
701 } else {
702 recordRelationship(element, IndexConstants.IS_REFERENCED_BY, location);
703 }
704 }
705 _recordImportElementReferenceWithoutPrefix(node);
706 return super.visitSimpleIdentifier(node);
707 }
708
709 @override
710 Object visitSuperConstructorInvocation(SuperConstructorInvocation node) {
711 ConstructorElement element = node.staticElement;
712 Location location;
713 if (node.constructorName != null) {
714 int start = node.period.offset;
715 int end = node.constructorName.end;
716 location = _createLocationFromOffset(start, end - start);
717 } else {
718 int start = node.keyword.end;
719 location = _createLocationFromOffset(start, 0);
720 }
721 recordRelationship(element, IndexConstants.IS_REFERENCED_BY, location);
722 return super.visitSuperConstructorInvocation(node);
723 }
724
725 @override
726 Object visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) {
727 VariableDeclarationList variables = node.variables;
728 for (VariableDeclaration variableDeclaration in variables.variables) {
729 Element element = variableDeclaration.element;
730 _recordElementDefinition(element, IndexConstants.DEFINES_VARIABLE);
731 }
732 return super.visitTopLevelVariableDeclaration(node);
733 }
734
735 @override
736 Object visitTypeParameter(TypeParameter node) {
737 TypeParameterElement element = node.element;
738 enterScope(element);
739 try {
740 return super.visitTypeParameter(node);
741 } finally {
742 _exitScope();
743 }
744 }
745
746 @override
747 Object visitVariableDeclaration(VariableDeclaration node) {
748 VariableElement element = node.element;
749 // record declaration
750 {
751 SimpleIdentifier name = node.name;
752 Location location = _createLocationFromNode(name);
753 location = _getLocationWithExpressionType(location, node.initializer);
754 recordRelationship(element, IndexConstants.IS_DEFINED_BY, location);
755 }
756 // visit
757 enterScope(element);
758 try {
759 return super.visitVariableDeclaration(node);
760 } finally {
761 _exitScope();
762 }
763 }
764
765 @override
766 Object visitVariableDeclarationList(VariableDeclarationList node) {
767 NodeList<VariableDeclaration> variables = node.variables;
768 if (variables != null) {
769 // use first VariableDeclaration as Element for Location(s) in type
770 {
771 TypeName type = node.type;
772 if (type != null) {
773 for (VariableDeclaration variableDeclaration in variables) {
774 enterScope(variableDeclaration.element);
775 try {
776 type.accept(this);
777 } finally {
778 _exitScope();
779 }
780 // only one iteration
781 break;
782 }
783 }
784 }
785 // visit variables
786 variables.accept(this);
787 }
788 return null;
789 }
790
791 /**
792 * @return the [Location] representing location of the [AstNode].
793 */
794 Location _createLocationFromNode(AstNode node) => _createLocationFromOffset(
795 node.offset, node.length);
796
797 /**
798 * @param offset the offset of the location within [Source]
799 * @param length the length of the location
800 * @return the [Location] representing the given offset and length within the inner-most
801 * [Element].
802 */
803 Location _createLocationFromOffset(int offset, int length) {
804 Element element = peekElement();
805 return new Location(element, offset, length);
806 }
807
808 /**
809 * @return the [Location] representing location of the [Token].
810 */
811 Location _createLocationFromToken(Token token) => _createLocationFromOffset(
812 token.offset, token.length);
813
814 /**
815 * Exit the current scope.
816 */
817 void _exitScope() {
818 _elementStack.removeFirst();
819 }
820
821 /**
822 * @return `true` if given node already indexed as more interesting reference, so it should
823 * not be indexed again.
824 */
825 bool _isAlreadyHandledName(SimpleIdentifier node) {
826 AstNode parent = node.parent;
827 if (parent is MethodInvocation) {
828 return identical(parent.methodName, node);
829 }
830 return false;
831 }
832
833 /**
834 * Records the [Element] definition in the library and universe.
835 */
836 void _recordElementDefinition(Element element, Relationship relationship) {
837 Location location = createLocation(element);
838 recordRelationship(_libraryElement, relationship, location);
839 recordRelationship(IndexConstants.UNIVERSE, relationship, location);
840 }
841
842 /**
843 * Records [ImportElement] that declares given prefix and imports library with element used
844 * with given prefix node.
845 */
846 void _recordImportElementReferenceWithPrefix(SimpleIdentifier prefixNode) {
847 _ImportElementInfo info = getImportElementInfo(prefixNode);
848 if (info != null) {
849 int offset = prefixNode.offset;
850 int length = info._periodEnd - offset;
851 Location location = _createLocationFromOffset(offset, length);
852 recordRelationship(info._element, IndexConstants.IS_REFERENCED_BY,
853 location);
854 }
855 }
856
857 /**
858 * Records [ImportElement] reference if given [SimpleIdentifier] references so me
859 * top-level element and not qualified with import prefix.
860 */
861 void _recordImportElementReferenceWithoutPrefix(SimpleIdentifier node) {
862 if (_isIdentifierInImportCombinator(node)) {
863 return;
864 }
865 if (_isIdentifierInPrefixedIdentifier(node)) {
866 return;
867 }
868 Element element = node.staticElement;
869 ImportElement importElement = _internalGetImportElement(_libraryElement,
870 null, element, _importElementsMap);
871 if (importElement != null) {
872 Location location = _createLocationFromOffset(node.offset, 0);
873 recordRelationship(importElement, IndexConstants.IS_REFERENCED_BY,
874 location);
875 }
876 }
877
878 /**
879 * Records reference to defining [CompilationUnitElement] of the given
880 * [LibraryElement].
881 */
882 void _recordLibraryReference(UriBasedDirective node, LibraryElement library) {
883 if (library != null) {
884 Location location = _createLocationFromNode(node.uri);
885 recordRelationship(library.definingCompilationUnit,
886 IndexConstants.IS_REFERENCED_BY, location);
887 }
888 }
889
890 /**
891 * Record reference to the given operator [Element] and name.
892 */
893 void _recordOperatorReference(Token operator, Element element) {
894 // prepare location
895 Location location = _createLocationFromToken(operator);
896 // record name reference
897 {
898 String name = operator.lexeme;
899 if (name == "++") {
900 name = "+";
901 }
902 if (name == "--") {
903 name = "-";
904 }
905 if (StringUtilities.endsWithChar(name, 0x3D) && name != "==") {
906 name = name.substring(0, name.length - 1);
907 }
908 Element nameElement = new NameElement(name);
909 Relationship relationship = element != null ?
910 IndexConstants.IS_REFERENCED_BY_QUALIFIED_RESOLVED :
911 IndexConstants.IS_REFERENCED_BY_QUALIFIED_UNRESOLVED;
912 recordRelationship(nameElement, relationship, location);
913 }
914 // record element reference
915 if (element != null) {
916 recordRelationship(element, IndexConstants.IS_INVOKED_BY_QUALIFIED,
917 location);
918 }
919 }
920
921 /**
922 * Records reference if the given [SimpleIdentifier] looks like a qualified pr operty access
923 * or method invocation.
924 */
925 void _recordQualifiedMemberReference(SimpleIdentifier node, Element element,
926 Element nameElement, Location location) {
927 if (node.isQualified) {
928 Relationship relationship = element != null ?
929 IndexConstants.IS_REFERENCED_BY_QUALIFIED_RESOLVED :
930 IndexConstants.IS_REFERENCED_BY_QUALIFIED_UNRESOLVED;
931 recordRelationship(nameElement, relationship, location);
932 }
933 }
934
935 /**
936 * Records extends/implements relationships between given [ClassElement] and [ Type] of
937 * "superNode".
938 */
939 void _recordSuperType(TypeName superNode, Relationship relationship) {
940 if (superNode != null) {
941 Identifier superName = superNode.name;
942 if (superName != null) {
943 Element superElement = superName.staticElement;
944 recordRelationship(superElement, relationship, _createLocationFromNode(
945 superNode));
946 }
947 }
948 }
949
950 /**
951 * @return the [Location] representing location of the [Element].
952 */
953 static Location createLocation(Element element) {
954 if (element != null) {
955 int offset = element.nameOffset;
956 int length = element.displayName.length;
957 return new Location(element, offset, length);
958 }
959 return null;
960 }
961
962 /**
963 * @return the [ImportElement] that is referenced by this node with [PrefixEle ment],
964 * may be `null`.
965 */
966 static ImportElement getImportElement(SimpleIdentifier prefixNode) {
967 _ImportElementInfo info = getImportElementInfo(prefixNode);
968 return info != null ? info._element : null;
969 }
970
971 /**
972 * @return the [ImportElementInfo] with [ImportElement] that is referenced by this
973 * node with [PrefixElement], may be `null`.
974 */
975 static _ImportElementInfo getImportElementInfo(SimpleIdentifier prefixNode) {
976 _ImportElementInfo info = new _ImportElementInfo();
977 // prepare environment
978 AstNode parent = prefixNode.parent;
979 CompilationUnit unit = prefixNode.getAncestor((node) => node is
980 CompilationUnit);
981 LibraryElement libraryElement = unit.element.library;
982 // prepare used element
983 Element usedElement = null;
984 if (parent is PrefixedIdentifier) {
985 PrefixedIdentifier prefixed = parent;
986 if (identical(prefixed.prefix, prefixNode)) {
987 usedElement = prefixed.staticElement;
988 info._periodEnd = prefixed.period.end;
989 }
990 }
991 if (parent is MethodInvocation) {
992 MethodInvocation invocation = parent;
993 if (identical(invocation.target, prefixNode)) {
994 usedElement = invocation.methodName.staticElement;
995 info._periodEnd = invocation.period.end;
996 }
997 }
998 // we need used Element
999 if (usedElement == null) {
1000 return null;
1001 }
1002 // find ImportElement
1003 String prefix = prefixNode.name;
1004 Map<ImportElement, Set<Element>> importElementsMap = {};
1005 info._element = _internalGetImportElement(libraryElement, prefix,
1006 usedElement, importElementsMap);
1007 if (info._element == null) {
1008 return null;
1009 }
1010 return info;
1011 }
1012
1013 /**
1014 * If the given expression has resolved type, returns the new location with th is type.
1015 *
1016 * @param location the base location
1017 * @param expression the expression assigned at the given location
1018 */
1019 static Location _getLocationWithExpressionType(Location location,
1020 Expression expression) {
1021 if (expression != null) {
1022 return new LocationWithData<DartType>(location, expression.bestType);
1023 }
1024 return location;
1025 }
1026
1027 /**
1028 * If the given node is the part of the [ConstructorFieldInitializer], returns location with
1029 * type of the initializer expression.
1030 */
1031 static Location _getLocationWithInitializerType(SimpleIdentifier node,
1032 Location location) {
1033 if (node.parent is ConstructorFieldInitializer) {
1034 ConstructorFieldInitializer initializer = node.parent as
1035 ConstructorFieldInitializer;
1036 if (identical(initializer.fieldName, node)) {
1037 location = _getLocationWithExpressionType(location,
1038 initializer.expression);
1039 }
1040 }
1041 return location;
1042 }
1043
1044 /**
1045 * If the given identifier has a synthetic [PropertyAccessorElement], i.e. acc essor for
1046 * normal field, and it is LHS of assignment, then include [Type] of the assig ned value into
1047 * the [Location].
1048 *
1049 * @param identifier the identifier to record location
1050 * @param element the element of the identifier
1051 * @param location the raw location
1052 * @return the [Location] with the type of the assigned value
1053 */
1054 static Location
1055 _getLocationWithTypeAssignedToField(SimpleIdentifier identifier,
1056 Element element, Location location) {
1057 // we need accessor
1058 if (element is! PropertyAccessorElement) {
1059 return location;
1060 }
1061 PropertyAccessorElement accessor = element as PropertyAccessorElement;
1062 // should be setter
1063 if (!accessor.isSetter) {
1064 return location;
1065 }
1066 // accessor should be synthetic, i.e. field normal
1067 if (!accessor.isSynthetic) {
1068 return location;
1069 }
1070 // should be LHS of assignment
1071 AstNode parent;
1072 {
1073 AstNode node = identifier;
1074 parent = node.parent;
1075 // new T().field = x;
1076 if (parent is PropertyAccess) {
1077 PropertyAccess propertyAccess = parent as PropertyAccess;
1078 if (identical(propertyAccess.propertyName, node)) {
1079 node = propertyAccess;
1080 parent = propertyAccess.parent;
1081 }
1082 }
1083 // obj.field = x;
1084 if (parent is PrefixedIdentifier) {
1085 PrefixedIdentifier prefixedIdentifier = parent as PrefixedIdentifier;
1086 if (identical(prefixedIdentifier.identifier, node)) {
1087 node = prefixedIdentifier;
1088 parent = prefixedIdentifier.parent;
1089 }
1090 }
1091 }
1092 // OK, remember the type
1093 if (parent is AssignmentExpression) {
1094 AssignmentExpression assignment = parent as AssignmentExpression;
1095 Expression rhs = assignment.rightHandSide;
1096 location = _getLocationWithExpressionType(location, rhs);
1097 }
1098 // done
1099 return location;
1100 }
1101
1102 /**
1103 * @return the [ImportElement] that declares given [PrefixElement] and imports library
1104 * with given "usedElement".
1105 */
1106 static ImportElement _internalGetImportElement(LibraryElement libraryElement,
1107 String prefix, Element usedElement, Map<ImportElement,
1108 Set<Element>> importElementsMap) {
1109 // validate Element
1110 if (usedElement == null) {
1111 return null;
1112 }
1113 if (usedElement.enclosingElement is! CompilationUnitElement) {
1114 return null;
1115 }
1116 LibraryElement usedLibrary = usedElement.library;
1117 // find ImportElement that imports used library with used prefix
1118 List<ImportElement> candidates = null;
1119 for (ImportElement importElement in libraryElement.imports) {
1120 // required library
1121 if (importElement.importedLibrary != usedLibrary) {
1122 continue;
1123 }
1124 // required prefix
1125 PrefixElement prefixElement = importElement.prefix;
1126 if (prefix == null) {
1127 if (prefixElement != null) {
1128 continue;
1129 }
1130 } else {
1131 if (prefixElement == null) {
1132 continue;
1133 }
1134 if (prefix != prefixElement.name) {
1135 continue;
1136 }
1137 }
1138 // no combinators => only possible candidate
1139 if (importElement.combinators.length == 0) {
1140 return importElement;
1141 }
1142 // OK, we have candidate
1143 if (candidates == null) {
1144 candidates = [];
1145 }
1146 candidates.add(importElement);
1147 }
1148 // no candidates, probably element is defined in this library
1149 if (candidates == null) {
1150 return null;
1151 }
1152 // one candidate
1153 if (candidates.length == 1) {
1154 return candidates[0];
1155 }
1156 // ensure that each ImportElement has set of elements
1157 for (ImportElement importElement in candidates) {
1158 if (importElementsMap.containsKey(importElement)) {
1159 continue;
1160 }
1161 Namespace namespace = new NamespaceBuilder(
1162 ).createImportNamespaceForDirective(importElement);
1163 Set<Element> elements = new Set();
1164 importElementsMap[importElement] = elements;
1165 }
1166 // use import namespace to choose correct one
1167 for (MapEntry<ImportElement, Set<Element>> entry in getMapEntrySet(
1168 importElementsMap)) {
1169 if (entry.getValue().contains(usedElement)) {
1170 return entry.getKey();
1171 }
1172 }
1173 // not found
1174 return null;
1175 }
1176
1177 /**
1178 * @return `true` if given "node" is part of an import [Combinator].
1179 */
1180 static bool _isIdentifierInImportCombinator(SimpleIdentifier node) {
1181 AstNode parent = node.parent;
1182 return parent is Combinator;
1183 }
1184
1185 /**
1186 * @return `true` if given "node" is part of [PrefixedIdentifier] "prefix.node ".
1187 */
1188 static bool _isIdentifierInPrefixedIdentifier(SimpleIdentifier node) {
1189 AstNode parent = node.parent;
1190 return parent is PrefixedIdentifier && identical(parent.identifier, node);
1191 }
1192 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698