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