OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. |
| 4 |
| 5 library engine.index; |
| 6 |
| 7 import 'dart:async'; |
| 8 |
| 9 import 'package:analyzer/src/generated/ast.dart'; |
| 10 import 'package:analyzer/src/generated/element.dart'; |
| 11 import 'package:analyzer/src/generated/engine.dart'; |
| 12 import 'package:analyzer/src/generated/html.dart'; |
| 13 import 'package:analyzer/src/generated/source.dart'; |
| 14 |
| 15 |
| 16 /** |
| 17 * The interface [Index] defines the behavior of objects that maintain an index |
| 18 * storing relations between [Element]s. |
| 19 * |
| 20 * Any modification operations are executed before any read operation. |
| 21 * There is no guarantee about the order in which the [Future]s for read |
| 22 * operations will complete. |
| 23 */ |
| 24 abstract class Index { |
| 25 /** |
| 26 * Answers index statistics. |
| 27 */ |
| 28 String get statistics; |
| 29 |
| 30 /** |
| 31 * Removes from the index all the information. |
| 32 */ |
| 33 void clear(); |
| 34 |
| 35 /** |
| 36 * Asynchronously returns a list containing all of the locations of the |
| 37 * elements that have the given [relationship] with the given [element]. |
| 38 * |
| 39 * For example, if the element represents a function and the relationship is |
| 40 * the `is-invoked-by` relationship, then the locations will be all of the |
| 41 * places where the function is invoked. |
| 42 * |
| 43 * [element] - the element that has the relationship with the locations to be |
| 44 * returned. |
| 45 * |
| 46 * [relationship] - the relationship between the given element and the |
| 47 * locations to be returned. |
| 48 */ |
| 49 Future<List<Location>> getRelationships(Element element, |
| 50 Relationship relationship); |
| 51 |
| 52 /** |
| 53 * Processes the given [HtmlUnit] in order to record the relationships. |
| 54 * |
| 55 * [context] - the [AnalysisContext] in which [HtmlUnit] was resolved. |
| 56 * [unit] - the [HtmlUnit] being indexed. |
| 57 */ |
| 58 void indexHtmlUnit(AnalysisContext context, HtmlUnit unit); |
| 59 |
| 60 /** |
| 61 * Processes the given [CompilationUnit] in order to record the relationships. |
| 62 * |
| 63 * [context] - the [AnalysisContext] in which [CompilationUnit] was resolved. |
| 64 * [unit] - the [CompilationUnit] being indexed. |
| 65 */ |
| 66 void indexUnit(AnalysisContext context, CompilationUnit unit); |
| 67 |
| 68 /** |
| 69 * Removes from the index all of the information associated with [context]. |
| 70 * |
| 71 * This method should be invoked when [context] is disposed. |
| 72 */ |
| 73 void removeContext(AnalysisContext context); |
| 74 |
| 75 /** |
| 76 * Removes from the index all of the information associated with elements or |
| 77 * locations in [source]. This includes relationships between an element in |
| 78 * [source] and any other locations, relationships between any other elements |
| 79 * and a location within [source]. |
| 80 * |
| 81 * This method should be invoked when [source] is no longer part of the code |
| 82 * base. |
| 83 * |
| 84 * [context] - the [AnalysisContext] in which [source] being removed |
| 85 * [source] - the [Source] being removed |
| 86 */ |
| 87 void removeSource(AnalysisContext context, Source source); |
| 88 |
| 89 /** |
| 90 * Removes from the index all of the information associated with elements or |
| 91 * locations in the given sources. This includes relationships between an |
| 92 * element in the given sources and any other locations, relationships between |
| 93 * any other elements and a location within the given sources. |
| 94 * |
| 95 * This method should be invoked when multiple sources are no longer part of |
| 96 * the code base. |
| 97 * |
| 98 * [context] - the [AnalysisContext] in which [Source]s being removed. |
| 99 * [container] - the [SourceContainer] holding the sources being removed. |
| 100 */ |
| 101 void removeSources(AnalysisContext context, SourceContainer container); |
| 102 |
| 103 /** |
| 104 * Starts the index. |
| 105 * Should be called before any other method. |
| 106 */ |
| 107 void run(); |
| 108 |
| 109 /** |
| 110 * Stops the index. |
| 111 * After calling this method operations may not be executed. |
| 112 */ |
| 113 void stop(); |
| 114 } |
| 115 |
| 116 |
| 117 /** |
| 118 * Constants used when populating and accessing the index. |
| 119 */ |
| 120 class IndexConstants { |
| 121 /** |
| 122 * Reference to some closing tag of an XML element. |
| 123 */ |
| 124 static final Relationship ANGULAR_CLOSING_TAG_REFERENCE = |
| 125 Relationship.getRelationship("angular-closing-tag-reference"); |
| 126 |
| 127 /** |
| 128 * Reference to some [AngularElement]. |
| 129 */ |
| 130 static final Relationship ANGULAR_REFERENCE = Relationship.getRelationship( |
| 131 "angular-reference"); |
| 132 |
| 133 /** |
| 134 * The relationship used to indicate that a container (the left-operand) |
| 135 * contains the definition of a class at a specific location (the right |
| 136 * operand). |
| 137 */ |
| 138 static final Relationship DEFINES_CLASS = Relationship.getRelationship( |
| 139 "defines-class"); |
| 140 |
| 141 /** |
| 142 * The relationship used to indicate that a container (the left-operand) |
| 143 * contains the definition of a class type alias at a specific location (the |
| 144 * right operand). |
| 145 */ |
| 146 static final Relationship DEFINES_CLASS_ALIAS = Relationship.getRelationship( |
| 147 "defines-class-alias"); |
| 148 |
| 149 /** |
| 150 * The relationship used to indicate that a container (the left-operand) |
| 151 * contains the definition of a function at a specific location (the right |
| 152 * operand). |
| 153 */ |
| 154 static final Relationship DEFINES_FUNCTION = Relationship.getRelationship( |
| 155 "defines-function"); |
| 156 |
| 157 /** |
| 158 * The relationship used to indicate that a container (the left-operand) |
| 159 * contains the definition of a function type at a specific location (the |
| 160 * right operand). |
| 161 */ |
| 162 static final Relationship DEFINES_FUNCTION_TYPE = |
| 163 Relationship.getRelationship("defines-function-type"); |
| 164 |
| 165 /** |
| 166 * The relationship used to indicate that a container (the left-operand) |
| 167 * contains the definition of a method at a specific location (the right |
| 168 * operand). |
| 169 */ |
| 170 static final Relationship DEFINES_VARIABLE = Relationship.getRelationship( |
| 171 "defines-variable"); |
| 172 |
| 173 /** |
| 174 * The relationship used to indicate that a name (the left-operand) is defined |
| 175 * at a specific location (the right operand). |
| 176 */ |
| 177 static final Relationship IS_DEFINED_BY = Relationship.getRelationship( |
| 178 "is-defined-by"); |
| 179 |
| 180 /** |
| 181 * The relationship used to indicate that a type (the left-operand) is |
| 182 * extended by a type at a specific location (the right operand). |
| 183 */ |
| 184 static final Relationship IS_EXTENDED_BY = Relationship.getRelationship( |
| 185 "is-extended-by"); |
| 186 |
| 187 /** |
| 188 * The relationship used to indicate that a type (the left-operand) is |
| 189 * implemented by a type at a specific location (the right operand). |
| 190 */ |
| 191 static final Relationship IS_IMPLEMENTED_BY = Relationship.getRelationship( |
| 192 "is-implemented-by"); |
| 193 |
| 194 /** |
| 195 * The relationship used to indicate that an element (the left-operand) is |
| 196 * invoked at a specific location (the right operand). This is used for |
| 197 * functions. |
| 198 */ |
| 199 static final Relationship IS_INVOKED_BY = Relationship.getRelationship( |
| 200 "is-invoked-by"); |
| 201 |
| 202 /** |
| 203 * The relationship used to indicate that an element (the left-operand) is |
| 204 * invoked at a specific location (the right operand). This is used for |
| 205 * methods. |
| 206 */ |
| 207 static final Relationship IS_INVOKED_BY_QUALIFIED = |
| 208 Relationship.getRelationship("is-invoked-by-qualified"); |
| 209 |
| 210 /** |
| 211 * The relationship used to indicate that an element (the left-operand) is |
| 212 * invoked at a specific location (the right operand). This is used for |
| 213 * methods. |
| 214 */ |
| 215 static final Relationship IS_INVOKED_BY_UNQUALIFIED = |
| 216 Relationship.getRelationship("is-invoked-by-unqualified"); |
| 217 |
| 218 /** |
| 219 * The relationship used to indicate that a type (the left-operand) is mixed |
| 220 * into a type at a specific location (the right operand). |
| 221 */ |
| 222 static final Relationship IS_MIXED_IN_BY = Relationship.getRelationship( |
| 223 "is-mixed-in-by"); |
| 224 |
| 225 /** |
| 226 * The relationship used to indicate that a parameter or variable (the |
| 227 * left-operand) is read at a specific location (the right operand). |
| 228 */ |
| 229 static final Relationship IS_READ_BY = Relationship.getRelationship( |
| 230 "is-read-by"); |
| 231 |
| 232 /** |
| 233 * The relationship used to indicate that a parameter or variable (the |
| 234 * left-operand) is both read and modified at a specific location (the right |
| 235 * operand). |
| 236 */ |
| 237 static final Relationship IS_READ_WRITTEN_BY = Relationship.getRelationship( |
| 238 "is-read-written-by"); |
| 239 |
| 240 /** |
| 241 * The relationship used to indicate that an element (the left-operand) is |
| 242 * referenced at a specific location (the right operand). This is used for |
| 243 * everything except read/write operations for fields, parameters, and |
| 244 * variables. Those use either [IS_REFERENCED_BY_QUALIFIED], |
| 245 * [IS_REFERENCED_BY_UNQUALIFIED], [IS_READ_BY], [IS_WRITTEN_BY] or |
| 246 * [IS_READ_WRITTEN_BY], as appropriate. |
| 247 */ |
| 248 static final Relationship IS_REFERENCED_BY = Relationship.getRelationship( |
| 249 "is-referenced-by"); |
| 250 |
| 251 /** |
| 252 * The relationship used to indicate that an element (the left-operand) is |
| 253 * referenced at a specific location (the right operand). This is used for |
| 254 * field accessors and methods. |
| 255 */ |
| 256 static final Relationship IS_REFERENCED_BY_QUALIFIED = |
| 257 Relationship.getRelationship("is-referenced-by-qualified"); |
| 258 |
| 259 /** |
| 260 * The relationship used to indicate that a [NameElement] (the left-operand) |
| 261 * is referenced at a specific location (the right operand). This is used for |
| 262 * qualified resolved references to methods and fields. |
| 263 */ |
| 264 static final Relationship IS_REFERENCED_BY_QUALIFIED_RESOLVED = |
| 265 Relationship.getRelationship("is-referenced-by-qualified-resolved"); |
| 266 |
| 267 /** |
| 268 * The relationship used to indicate that an [NameElement] (the left-operand) |
| 269 * is referenced at a specific location (the right operand). This is used for |
| 270 * qualified unresolved references to methods and fields. |
| 271 */ |
| 272 static final Relationship IS_REFERENCED_BY_QUALIFIED_UNRESOLVED = |
| 273 Relationship.getRelationship("is-referenced-by-qualified-unresolved"); |
| 274 |
| 275 /** |
| 276 * The relationship used to indicate that an element (the left-operand) is |
| 277 * referenced at a specific location (the right operand). This is used for |
| 278 * field accessors and methods. |
| 279 */ |
| 280 static final Relationship IS_REFERENCED_BY_UNQUALIFIED = |
| 281 Relationship.getRelationship("is-referenced-by-unqualified"); |
| 282 |
| 283 /** |
| 284 * The relationship used to indicate that a parameter or variable (the |
| 285 * left-operand) is modified (assigned to) at a specific location (the right |
| 286 * operand). |
| 287 */ |
| 288 static final Relationship IS_WRITTEN_BY = Relationship.getRelationship( |
| 289 "is-written-by"); |
| 290 |
| 291 /** |
| 292 * The relationship used to indicate that a [NameElement] (the left-operand) |
| 293 * is invoked at a specific location (the right operand). This is used for |
| 294 * resolved invocations. |
| 295 */ |
| 296 static final Relationship NAME_IS_INVOKED_BY_RESOLVED = |
| 297 Relationship.getRelationship("name-is-invoked-by-resolved"); |
| 298 |
| 299 /** |
| 300 * The relationship used to indicate that a [NameElement] (the left-operand) |
| 301 * is invoked at a specific location (the right operand). This is used for |
| 302 * unresolved invocations. |
| 303 */ |
| 304 static final Relationship NAME_IS_INVOKED_BY_UNRESOLVED = |
| 305 Relationship.getRelationship("name-is-invoked-by-unresolved"); |
| 306 |
| 307 /** |
| 308 * The relationship used to indicate that a [NameElement] (the left-operand) |
| 309 * is read at a specific location (the right operand). |
| 310 */ |
| 311 static final Relationship NAME_IS_READ_BY_RESOLVED = |
| 312 Relationship.getRelationship("name-is-read-by-resolved"); |
| 313 |
| 314 /** |
| 315 * The relationship used to indicate that a [NameElement] (the left-operand) |
| 316 * is read at a specific location (the right operand). |
| 317 */ |
| 318 static final Relationship NAME_IS_READ_BY_UNRESOLVED = |
| 319 Relationship.getRelationship("name-is-read-by-unresolved"); |
| 320 |
| 321 /** |
| 322 * The relationship used to indicate that a [NameElement] (the left-operand) |
| 323 * is both read and written at a specific location (the right operand). |
| 324 */ |
| 325 static final Relationship NAME_IS_READ_WRITTEN_BY_RESOLVED = |
| 326 Relationship.getRelationship("name-is-read-written-by-resolved"); |
| 327 |
| 328 /** |
| 329 * The relationship used to indicate that a [NameElement] (the left-operand) |
| 330 * is both read and written at a specific location (the right operand). |
| 331 */ |
| 332 static final Relationship NAME_IS_READ_WRITTEN_BY_UNRESOLVED = |
| 333 Relationship.getRelationship("name-is-read-written-by-unresolved"); |
| 334 |
| 335 /** |
| 336 * The relationship used to indicate that a [NameElement] (the left-operand) |
| 337 * is written at a specific location (the right operand). |
| 338 */ |
| 339 static final Relationship NAME_IS_WRITTEN_BY_RESOLVED = |
| 340 Relationship.getRelationship("name-is-written-by-resolved"); |
| 341 |
| 342 /** |
| 343 * The relationship used to indicate that a [NameElement] (the left-operand) |
| 344 * is written at a specific location (the right operand). |
| 345 */ |
| 346 static final Relationship NAME_IS_WRITTEN_BY_UNRESOLVED = |
| 347 Relationship.getRelationship("name-is-written-by-unresolved"); |
| 348 |
| 349 /** |
| 350 * An element used to represent the universe. |
| 351 */ |
| 352 static final Element UNIVERSE = UniverseElement.INSTANCE; |
| 353 |
| 354 IndexConstants._(); |
| 355 } |
| 356 |
| 357 |
| 358 /** |
| 359 * Instances of the class [Location] represent a location related to an element. |
| 360 * |
| 361 * The location is expressed as an offset and length, but the offset is relative |
| 362 * to the resource containing the element rather than the start of the element |
| 363 * within that resource. |
| 364 */ |
| 365 class Location { |
| 366 /** |
| 367 * An empty array of locations. |
| 368 */ |
| 369 static const List<Location> EMPTY_ARRAY = const <Location>[]; |
| 370 |
| 371 /** |
| 372 * The element containing this location. |
| 373 */ |
| 374 final Element element; |
| 375 |
| 376 /** |
| 377 * The offset of this location within the resource containing the element. |
| 378 */ |
| 379 final int offset; |
| 380 |
| 381 /** |
| 382 * The length of this location. |
| 383 */ |
| 384 final int length; |
| 385 |
| 386 /** |
| 387 * Initializes a newly create location to be relative to the given element at |
| 388 * the given [offset] with the given [length]. |
| 389 * |
| 390 * [element] - the [Element] containing this location. |
| 391 * [offset] - the offset within the resource containing the [element]. |
| 392 * [length] - the length of this location |
| 393 */ |
| 394 Location(this.element, this.offset, this.length) { |
| 395 if (element == null) { |
| 396 throw new ArgumentError("element location cannot be null"); |
| 397 } |
| 398 } |
| 399 |
| 400 @override |
| 401 String toString() => "[${offset} - ${(offset + length)}) in ${element}"; |
| 402 } |
| 403 |
| 404 |
| 405 /** |
| 406 * A [Location] with attached data. |
| 407 */ |
| 408 class LocationWithData<D> extends Location { |
| 409 final D data; |
| 410 |
| 411 LocationWithData(Location location, this.data) : super(location.element, |
| 412 location.offset, location.length); |
| 413 } |
| 414 |
| 415 |
| 416 /** |
| 417 * An [Element] which is used to index references to the name without specifying |
| 418 * a concrete kind of this name - field, method or something else. |
| 419 */ |
| 420 class NameElement extends ElementImpl { |
| 421 NameElement(String name) : super("name:${name}", -1); |
| 422 |
| 423 @override |
| 424 ElementKind get kind => ElementKind.NAME; |
| 425 |
| 426 @override |
| 427 accept(ElementVisitor visitor) => null; |
| 428 } |
| 429 |
| 430 |
| 431 /** |
| 432 * Relationship between an element and a location. Relationships are identified |
| 433 * by a globally unique identifier. |
| 434 */ |
| 435 class Relationship { |
| 436 /** |
| 437 * A table mapping relationship identifiers to relationships. |
| 438 */ |
| 439 static Map<String, Relationship> _RELATIONSHIP_MAP = {}; |
| 440 |
| 441 /** |
| 442 * The unique identifier for this relationship. |
| 443 */ |
| 444 final String identifier; |
| 445 |
| 446 /** |
| 447 * Initialize a newly created relationship with the given unique identifier. |
| 448 */ |
| 449 Relationship(this.identifier); |
| 450 |
| 451 @override |
| 452 String toString() => identifier; |
| 453 |
| 454 /** |
| 455 * Returns the relationship with the given unique [identifier]. |
| 456 */ |
| 457 static Relationship getRelationship(String identifier) { |
| 458 Relationship relationship = _RELATIONSHIP_MAP[identifier]; |
| 459 if (relationship == null) { |
| 460 relationship = new Relationship(identifier); |
| 461 _RELATIONSHIP_MAP[identifier] = relationship; |
| 462 } |
| 463 return relationship; |
| 464 } |
| 465 } |
| 466 |
| 467 |
| 468 /** |
| 469 * An element to use when we want to request "defines" relations without |
| 470 * specifying an exact library. |
| 471 */ |
| 472 class UniverseElement extends ElementImpl { |
| 473 static final UniverseElement INSTANCE = new UniverseElement._(); |
| 474 |
| 475 UniverseElement._() : super("--universe--", -1); |
| 476 |
| 477 @override |
| 478 ElementKind get kind => ElementKind.UNIVERSE; |
| 479 |
| 480 @override |
| 481 accept(ElementVisitor visitor) => null; |
| 482 } |
OLD | NEW |