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

Side by Side Diff: pkg/analysis_services/lib/src/index/index_contributor.dart

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

Powered by Google App Engine
This is Rietveld 408576698