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

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

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

Powered by Google App Engine
This is Rietveld 408576698