Chromium Code Reviews| OLD | NEW | 
|---|---|
| (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 } | |
| OLD | NEW |