| 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 services.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 * Left: an Angular element. | |
| 123 * Is referenced at. | |
| 124 * Right: location. | |
| 125 */ | |
| 126 static final Relationship ANGULAR_REFERENCE = | |
| 127 Relationship.getRelationship("angular-reference"); | |
| 128 | |
| 129 /** | |
| 130 * Left: an Angular component. | |
| 131 * Is closed "/>" at. | |
| 132 * Right: location. | |
| 133 */ | |
| 134 static final Relationship ANGULAR_CLOSING_TAG_REFERENCE = | |
| 135 Relationship.getRelationship("angular-closing-tag-reference"); | |
| 136 | |
| 137 /** | |
| 138 * Left: the Universe or a Library. | |
| 139 * Defines an Element. | |
| 140 * Right: an Element declaration. | |
| 141 */ | |
| 142 static final Relationship DEFINES = Relationship.getRelationship("defines"); | |
| 143 | |
| 144 /** | |
| 145 * Left: class. | |
| 146 * Is extended by. | |
| 147 * Right: other class declaration. | |
| 148 */ | |
| 149 static final Relationship IS_EXTENDED_BY = | |
| 150 Relationship.getRelationship("is-extended-by"); | |
| 151 | |
| 152 /** | |
| 153 * Left: class. | |
| 154 * Is implemented by. | |
| 155 * Right: other class declaration. | |
| 156 */ | |
| 157 static final Relationship IS_IMPLEMENTED_BY = | |
| 158 Relationship.getRelationship("is-implemented-by"); | |
| 159 | |
| 160 /** | |
| 161 * Left: class. | |
| 162 * Is mixed into. | |
| 163 * Right: other class declaration. | |
| 164 */ | |
| 165 static final Relationship IS_MIXED_IN_BY = | |
| 166 Relationship.getRelationship("is-mixed-in-by"); | |
| 167 | |
| 168 /** | |
| 169 * Left: local variable, parameter. | |
| 170 * Is read at. | |
| 171 * Right: location. | |
| 172 */ | |
| 173 static final Relationship IS_READ_BY = | |
| 174 Relationship.getRelationship("is-read-by"); | |
| 175 | |
| 176 /** | |
| 177 * Left: local variable, parameter. | |
| 178 * Is both read and written at. | |
| 179 * Right: location. | |
| 180 */ | |
| 181 static final Relationship IS_READ_WRITTEN_BY = | |
| 182 Relationship.getRelationship("is-read-written-by"); | |
| 183 | |
| 184 /** | |
| 185 * Left: local variable, parameter. | |
| 186 * Is written at. | |
| 187 * Right: location. | |
| 188 */ | |
| 189 static final Relationship IS_WRITTEN_BY = | |
| 190 Relationship.getRelationship("is-written-by"); | |
| 191 | |
| 192 /** | |
| 193 * Left: function, method, variable, getter. | |
| 194 * Is invoked at. | |
| 195 * Right: location. | |
| 196 */ | |
| 197 static final Relationship IS_INVOKED_BY = | |
| 198 Relationship.getRelationship("is-invoked-by"); | |
| 199 | |
| 200 /** | |
| 201 * Left: function, function type, class, field, method. | |
| 202 * Is referenced (and not invoked, read/written) at. | |
| 203 * Right: location. | |
| 204 */ | |
| 205 static final Relationship IS_REFERENCED_BY = | |
| 206 Relationship.getRelationship("is-referenced-by"); | |
| 207 | |
| 208 /** | |
| 209 * Left: name element. | |
| 210 * Is defined by. | |
| 211 * Right: concrete element declaration. | |
| 212 */ | |
| 213 static final Relationship NAME_IS_DEFINED_BY = | |
| 214 Relationship.getRelationship("name-is-defined-by"); | |
| 215 | |
| 216 IndexConstants._(); | |
| 217 } | |
| 218 | |
| 219 | |
| 220 /** | |
| 221 * Instances of the class [Location] represent a location related to an element. | |
| 222 * | |
| 223 * The location is expressed as an offset and length, but the offset is relative | |
| 224 * to the resource containing the element rather than the start of the element | |
| 225 * within that resource. | |
| 226 */ | |
| 227 class Location { | |
| 228 static const int _FLAG_QUALIFIED = 1 << 0; | |
| 229 static const int _FLAG_RESOLVED = 1 << 1; | |
| 230 | |
| 231 /** | |
| 232 * An empty array of locations. | |
| 233 */ | |
| 234 static const List<Location> EMPTY_ARRAY = const <Location>[]; | |
| 235 | |
| 236 /** | |
| 237 * The element containing this location. | |
| 238 */ | |
| 239 final Element element; | |
| 240 | |
| 241 /** | |
| 242 * The offset of this location within the resource containing the element. | |
| 243 */ | |
| 244 final int offset; | |
| 245 | |
| 246 /** | |
| 247 * The length of this location. | |
| 248 */ | |
| 249 final int length; | |
| 250 | |
| 251 /** | |
| 252 * The flags of this location. | |
| 253 */ | |
| 254 int _flags; | |
| 255 | |
| 256 /** | |
| 257 * Initializes a newly created location to be relative to the given element at | |
| 258 * the given [offset] with the given [length]. | |
| 259 * | |
| 260 * [element] - the [Element] containing this location. | |
| 261 * [offset] - the offset within the resource containing [element]. | |
| 262 * [length] - the length of this location | |
| 263 */ | |
| 264 Location(this.element, this.offset, this.length, {bool isQualified: false, | |
| 265 bool isResolved: true}) { | |
| 266 if (element == null) { | |
| 267 throw new ArgumentError("element location cannot be null"); | |
| 268 } | |
| 269 _flags = 0; | |
| 270 if (isQualified) { | |
| 271 _flags |= _FLAG_QUALIFIED; | |
| 272 } | |
| 273 if (isResolved) { | |
| 274 _flags |= _FLAG_RESOLVED; | |
| 275 } | |
| 276 } | |
| 277 | |
| 278 /** | |
| 279 * Returns `true` if this location is a qualified reference. | |
| 280 */ | |
| 281 bool get isQualified => (_flags & _FLAG_QUALIFIED) != 0; | |
| 282 | |
| 283 /** | |
| 284 * Returns `true` if this location is a resolved reference. | |
| 285 */ | |
| 286 bool get isResolved => (_flags & _FLAG_RESOLVED) != 0; | |
| 287 | |
| 288 @override | |
| 289 String toString() { | |
| 290 String flagsStr = ''; | |
| 291 if (isQualified) { | |
| 292 flagsStr += ' qualified'; | |
| 293 } | |
| 294 if (isResolved) { | |
| 295 flagsStr += ' resolved'; | |
| 296 } | |
| 297 return '[${offset} - ${(offset + length)}) $flagsStr in ${element}'; | |
| 298 } | |
| 299 } | |
| 300 | |
| 301 | |
| 302 /** | |
| 303 * A [Location] with attached data. | |
| 304 */ | |
| 305 class LocationWithData<D> extends Location { | |
| 306 final D data; | |
| 307 | |
| 308 LocationWithData(Location location, this.data) | |
| 309 : super(location.element, location.offset, location.length); | |
| 310 } | |
| 311 | |
| 312 | |
| 313 /** | |
| 314 * An [Element] which is used to index references to the name without specifying | |
| 315 * a concrete kind of this name - field, method or something else. | |
| 316 */ | |
| 317 class NameElement extends ElementImpl { | |
| 318 NameElement(String name) : super("name:${name}", -1); | |
| 319 | |
| 320 @override | |
| 321 ElementKind get kind => ElementKind.NAME; | |
| 322 | |
| 323 @override | |
| 324 accept(ElementVisitor visitor) => null; | |
| 325 } | |
| 326 | |
| 327 | |
| 328 /** | |
| 329 * Relationship between an element and a location. Relationships are identified | |
| 330 * by a globally unique identifier. | |
| 331 */ | |
| 332 class Relationship { | |
| 333 /** | |
| 334 * A table mapping relationship identifiers to relationships. | |
| 335 */ | |
| 336 static Map<String, Relationship> _RELATIONSHIP_MAP = {}; | |
| 337 | |
| 338 /** | |
| 339 * The unique identifier for this relationship. | |
| 340 */ | |
| 341 final String identifier; | |
| 342 | |
| 343 /** | |
| 344 * Initialize a newly created relationship with the given unique identifier. | |
| 345 */ | |
| 346 Relationship(this.identifier); | |
| 347 | |
| 348 @override | |
| 349 String toString() => identifier; | |
| 350 | |
| 351 /** | |
| 352 * Returns the relationship with the given unique [identifier]. | |
| 353 */ | |
| 354 static Relationship getRelationship(String identifier) { | |
| 355 Relationship relationship = _RELATIONSHIP_MAP[identifier]; | |
| 356 if (relationship == null) { | |
| 357 relationship = new Relationship(identifier); | |
| 358 _RELATIONSHIP_MAP[identifier] = relationship; | |
| 359 } | |
| 360 return relationship; | |
| 361 } | |
| 362 } | |
| 363 | |
| 364 | |
| 365 /** | |
| 366 * An element to use when we want to request "defines" relations without | |
| 367 * specifying an exact library. | |
| 368 */ | |
| 369 class UniverseElement extends ElementImpl { | |
| 370 static final UniverseElement INSTANCE = new UniverseElement._(); | |
| 371 | |
| 372 UniverseElement._() : super("--universe--", -1); | |
| 373 | |
| 374 @override | |
| 375 ElementKind get kind => ElementKind.UNIVERSE; | |
| 376 | |
| 377 @override | |
| 378 accept(ElementVisitor visitor) => null; | |
| 379 } | |
| OLD | NEW |