| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2016, 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 import 'dart:async'; | |
| 6 | |
| 7 import 'package:analyzer/dart/ast/ast.dart'; | |
| 8 import 'package:analyzer/dart/element/element.dart'; | |
| 9 import 'package:analyzer/src/generated/engine.dart' show AnalysisContext; | |
| 10 import 'package:analyzer/src/generated/source.dart'; | |
| 11 import 'package:analyzer/src/summary/format.dart'; | |
| 12 import 'package:analyzer/src/summary/idl.dart'; | |
| 13 import 'package:analyzer/src/summary/index_unit.dart'; | |
| 14 import 'package:collection/collection.dart'; | |
| 15 | |
| 16 /** | |
| 17 * Return a new [Index2] instance that keeps information in memory. | |
| 18 */ | |
| 19 Index2 createMemoryIndex2() { | |
| 20 return new Index2._(); | |
| 21 } | |
| 22 | |
| 23 /** | |
| 24 * Return the index of the first occurrence of the [value] in the [sortedList], | |
| 25 * or `-1` if the [value] is not in the list. | |
| 26 */ | |
| 27 int _findFirstOccurrence(List<int> sortedList, int value) { | |
| 28 // Find an occurrence. | |
| 29 int i = binarySearch(sortedList, value); | |
| 30 if (i == -1) { | |
| 31 return -1; | |
| 32 } | |
| 33 // Find the first occurrence. | |
| 34 while (i > 0 && sortedList[i - 1] == value) { | |
| 35 i--; | |
| 36 } | |
| 37 return i; | |
| 38 } | |
| 39 | |
| 40 /** | |
| 41 * Interface for storing and requesting relations. | |
| 42 */ | |
| 43 class Index2 { | |
| 44 final Map<AnalysisContext, _ContextIndex> _contextIndexMap = | |
| 45 <AnalysisContext, _ContextIndex>{}; | |
| 46 | |
| 47 Index2._(); | |
| 48 | |
| 49 /** | |
| 50 * Complete with a list of locations where elements of the given [kind] with | |
| 51 * names satisfying the given [regExp] are defined. | |
| 52 */ | |
| 53 Future<List<Location>> getDefinedNames(RegExp regExp, IndexNameKind kind) { | |
| 54 return _mergeLocations((_ContextIndex index) { | |
| 55 return index.getDefinedNames(regExp, kind); | |
| 56 }); | |
| 57 } | |
| 58 | |
| 59 /** | |
| 60 * Complete with a list of locations where the given [element] has relation | |
| 61 * of the given [kind]. | |
| 62 */ | |
| 63 Future<List<Location>> getRelations(Element element, IndexRelationKind kind) { | |
| 64 return _mergeLocations((_ContextIndex index) { | |
| 65 return index.getRelations(element, kind); | |
| 66 }); | |
| 67 } | |
| 68 | |
| 69 /** | |
| 70 * Complete with a list of locations where a class members with the given | |
| 71 * [name] is referenced with a qualifier, but is not resolved. | |
| 72 */ | |
| 73 Future<List<Location>> getUnresolvedMemberReferences(String name) { | |
| 74 return _mergeLocations((_ContextIndex index) { | |
| 75 return index.getUnresolvedMemberReferences(name); | |
| 76 }); | |
| 77 } | |
| 78 | |
| 79 /** | |
| 80 * Index the given fully resolved [unit]. | |
| 81 */ | |
| 82 void indexUnit(CompilationUnit unit) { | |
| 83 if (unit == null || unit.element == null) { | |
| 84 return; | |
| 85 } | |
| 86 AnalysisContext context = unit.element.context; | |
| 87 _getContextIndex(context).indexUnit(unit); | |
| 88 } | |
| 89 | |
| 90 /** | |
| 91 * Remove all index information for the given [context]. | |
| 92 */ | |
| 93 void removeContext(AnalysisContext context) { | |
| 94 _contextIndexMap.remove(context); | |
| 95 } | |
| 96 | |
| 97 /** | |
| 98 * Remove index information about the unit in the given [context]. | |
| 99 */ | |
| 100 void removeUnit( | |
| 101 AnalysisContext context, Source librarySource, Source unitSource) { | |
| 102 _contextIndexMap[context]?.removeUnit(librarySource, unitSource); | |
| 103 } | |
| 104 | |
| 105 /** | |
| 106 * Return the [_ContextIndex] instance for the given [context]. | |
| 107 */ | |
| 108 _ContextIndex _getContextIndex(AnalysisContext context) { | |
| 109 return _contextIndexMap.putIfAbsent(context, () { | |
| 110 return new _ContextIndex(context); | |
| 111 }); | |
| 112 } | |
| 113 | |
| 114 /** | |
| 115 * Complete with a list of all results returned by the [callback] for every | |
| 116 * context specific index. | |
| 117 */ | |
| 118 Future<List<Location>> _mergeLocations( | |
| 119 Future<List<Location>> callback(_ContextIndex index)) async { | |
| 120 List<Location> locations = <Location>[]; | |
| 121 for (_ContextIndex index in _contextIndexMap.values) { | |
| 122 List<Location> contextLocations = await callback(index); | |
| 123 locations.addAll(contextLocations); | |
| 124 } | |
| 125 return locations; | |
| 126 } | |
| 127 } | |
| 128 | |
| 129 /** | |
| 130 * Information about location of a single relation in the index. | |
| 131 * | |
| 132 * The location is expressed as a library specific unit containing the index | |
| 133 * relation, offset within this [Source] and length. | |
| 134 * | |
| 135 * Clients may not extend, implement or mix-in this class. | |
| 136 */ | |
| 137 class Location { | |
| 138 /** | |
| 139 * The [AnalysisContext] containing this location. | |
| 140 */ | |
| 141 final AnalysisContext context; | |
| 142 | |
| 143 /** | |
| 144 * The URI of the source of the library containing this location. | |
| 145 */ | |
| 146 final String libraryUri; | |
| 147 | |
| 148 /** | |
| 149 * The URI of the source of the unit containing this location. | |
| 150 */ | |
| 151 final String unitUri; | |
| 152 | |
| 153 /** | |
| 154 * The kind of usage at this location. | |
| 155 */ | |
| 156 final IndexRelationKind kind; | |
| 157 | |
| 158 /** | |
| 159 * The offset of this location within the [unitUri]. | |
| 160 */ | |
| 161 final int offset; | |
| 162 | |
| 163 /** | |
| 164 * The length of this location. | |
| 165 */ | |
| 166 final int length; | |
| 167 | |
| 168 /** | |
| 169 * Is `true` if this location is qualified. | |
| 170 */ | |
| 171 final bool isQualified; | |
| 172 | |
| 173 /** | |
| 174 * Is `true` if this location is resolved. | |
| 175 */ | |
| 176 final bool isResolved; | |
| 177 | |
| 178 Location(this.context, this.libraryUri, this.unitUri, this.kind, this.offset, | |
| 179 this.length, this.isQualified, this.isResolved); | |
| 180 | |
| 181 @override | |
| 182 String toString() => 'Location{librarySourceUri: $libraryUri, ' | |
| 183 'unitSourceUri: $unitUri, offset: $offset, length: $length, ' | |
| 184 'isQualified: $isQualified}, isResolved: $isResolved}'; | |
| 185 } | |
| 186 | |
| 187 /** | |
| 188 * Opaque identifier of a [PackageIndex]. | |
| 189 */ | |
| 190 abstract class PackageIndexId {} | |
| 191 | |
| 192 /** | |
| 193 * Storage of [PackageIndex] objects. | |
| 194 */ | |
| 195 abstract class PackageIndexStore { | |
| 196 /** | |
| 197 * Complete with identifiers of all [PackageIndex] objects. | |
| 198 */ | |
| 199 Future<Iterable<PackageIndexId>> getIds(); | |
| 200 | |
| 201 /** | |
| 202 * Complete with the [PackageIndex] with the given [id]. | |
| 203 */ | |
| 204 Future<PackageIndex> getIndex(PackageIndexId id); | |
| 205 | |
| 206 /** | |
| 207 * Put the given [indexBuilder] into the store. | |
| 208 */ | |
| 209 void putIndex(String unitLibraryUri, String unitUnitUri, | |
| 210 PackageIndexBuilder indexBuilder); | |
| 211 } | |
| 212 | |
| 213 /** | |
| 214 * The [AnalysisContext] specific index. | |
| 215 */ | |
| 216 class _ContextIndex { | |
| 217 final AnalysisContext context; | |
| 218 final Map<String, PackageIndex> indexMap = <String, PackageIndex>{}; | |
| 219 | |
| 220 _ContextIndex(this.context); | |
| 221 | |
| 222 /** | |
| 223 * Complete with a list of locations where elements of the given [kind] with | |
| 224 * names satisfying the given [regExp] are defined. | |
| 225 */ | |
| 226 Future<List<Location>> getDefinedNames( | |
| 227 RegExp regExp, IndexNameKind kind) async { | |
| 228 return _mergeLocations((_PackageIndexRequester requester) { | |
| 229 return requester.getDefinedNames(context, regExp, kind); | |
| 230 }); | |
| 231 } | |
| 232 | |
| 233 /** | |
| 234 * Complete with a list of locations where the given [element] has relation | |
| 235 * of the given [kind]. | |
| 236 */ | |
| 237 Future<List<Location>> getRelations(Element element, IndexRelationKind kind) { | |
| 238 return _mergeLocations((_PackageIndexRequester requester) { | |
| 239 return requester.getRelations(context, element, kind); | |
| 240 }); | |
| 241 } | |
| 242 | |
| 243 /** | |
| 244 * Complete with a list of locations where a class members with the given | |
| 245 * [name] is referenced with a qualifier, but is not resolved. | |
| 246 */ | |
| 247 Future<List<Location>> getUnresolvedMemberReferences(String name) async { | |
| 248 return _mergeLocations((_PackageIndexRequester requester) { | |
| 249 return requester.getUnresolvedMemberReferences(context, name); | |
| 250 }); | |
| 251 } | |
| 252 | |
| 253 /** | |
| 254 * Index the given fully resolved [unit]. | |
| 255 */ | |
| 256 void indexUnit(CompilationUnit unit) { | |
| 257 // Index the unit. | |
| 258 PackageIndexAssembler assembler = new PackageIndexAssembler(); | |
| 259 assembler.index(unit); | |
| 260 PackageIndexBuilder indexBuilder = assembler.assemble(); | |
| 261 // Put the index into the map. | |
| 262 List<int> indexBytes = indexBuilder.toBuffer(); | |
| 263 PackageIndex index = new PackageIndex.fromBuffer(indexBytes); | |
| 264 String key = _getUnitKeyForElement(unit.element); | |
| 265 indexMap[key] = index; | |
| 266 } | |
| 267 | |
| 268 /** | |
| 269 * Remove index information about the unit. | |
| 270 */ | |
| 271 void removeUnit(Source librarySource, Source unitSource) { | |
| 272 String key = _getUnitKeyForSource(librarySource, unitSource); | |
| 273 indexMap.remove(key); | |
| 274 } | |
| 275 | |
| 276 String _getUnitKeyForElement(CompilationUnitElement unitElement) { | |
| 277 Source librarySource = unitElement.library.source; | |
| 278 Source unitSource = unitElement.source; | |
| 279 return _getUnitKeyForSource(librarySource, unitSource); | |
| 280 } | |
| 281 | |
| 282 String _getUnitKeyForSource(Source librarySource, Source unitSource) { | |
| 283 String unitLibraryUri = librarySource.uri.toString(); | |
| 284 String unitUnitUri = unitSource.uri.toString(); | |
| 285 return '$unitLibraryUri;$unitUnitUri'; | |
| 286 } | |
| 287 | |
| 288 Future<List<Location>> _mergeLocations( | |
| 289 List<Location> callback(_PackageIndexRequester requester)) async { | |
| 290 List<Location> locations = <Location>[]; | |
| 291 for (PackageIndex index in indexMap.values) { | |
| 292 _PackageIndexRequester requester = new _PackageIndexRequester(index); | |
| 293 List<Location> indexLocations = callback(requester); | |
| 294 locations.addAll(indexLocations); | |
| 295 } | |
| 296 return locations; | |
| 297 } | |
| 298 } | |
| 299 | |
| 300 /** | |
| 301 * Helper for requesting information from a single [PackageIndex]. | |
| 302 */ | |
| 303 class _PackageIndexRequester { | |
| 304 final PackageIndex index; | |
| 305 | |
| 306 _PackageIndexRequester(this.index); | |
| 307 | |
| 308 /** | |
| 309 * Return the [element]'s identifier in the [index] or `-1` if the | |
| 310 * [element] is not referenced in the [index]. | |
| 311 */ | |
| 312 int findElementId(Element element) { | |
| 313 // Find the id of the element's unit. | |
| 314 int unitId = getUnitId(element); | |
| 315 if (unitId == -1) { | |
| 316 return -1; | |
| 317 } | |
| 318 // Prepare information about the element. | |
| 319 ElementInfo info = PackageIndexAssembler.newElementInfo(unitId, element); | |
| 320 // Find the first occurrence of an element with the same offset. | |
| 321 int elementId = _findFirstOccurrence(index.elementOffsets, info.offset); | |
| 322 if (elementId == -1) { | |
| 323 return -1; | |
| 324 } | |
| 325 // Try to find the element id using offset, unit and kind. | |
| 326 for (; | |
| 327 elementId < index.elementOffsets.length && | |
| 328 index.elementOffsets[elementId] == info.offset; | |
| 329 elementId++) { | |
| 330 if (index.elementUnits[elementId] == unitId && | |
| 331 index.elementKinds[elementId] == info.kind) { | |
| 332 return elementId; | |
| 333 } | |
| 334 } | |
| 335 return -1; | |
| 336 } | |
| 337 | |
| 338 /** | |
| 339 * Complete with a list of locations where elements of the given [kind] with | |
| 340 * names satisfying the given [regExp] are defined. | |
| 341 */ | |
| 342 List<Location> getDefinedNames( | |
| 343 AnalysisContext context, RegExp regExp, IndexNameKind kind) { | |
| 344 List<Location> locations = <Location>[]; | |
| 345 for (UnitIndex unitIndex in index.units) { | |
| 346 _UnitIndexRequester requester = new _UnitIndexRequester(this, unitIndex); | |
| 347 List<Location> unitLocations = | |
| 348 requester.getDefinedNames(context, regExp, kind); | |
| 349 locations.addAll(unitLocations); | |
| 350 } | |
| 351 return locations; | |
| 352 } | |
| 353 | |
| 354 /** | |
| 355 * Complete with a list of locations where the given [element] has relation | |
| 356 * of the given [kind]. | |
| 357 */ | |
| 358 List<Location> getRelations( | |
| 359 AnalysisContext context, Element element, IndexRelationKind kind) { | |
| 360 int elementId = findElementId(element); | |
| 361 if (elementId == -1) { | |
| 362 return const <Location>[]; | |
| 363 } | |
| 364 List<Location> locations = <Location>[]; | |
| 365 for (UnitIndex unitIndex in index.units) { | |
| 366 _UnitIndexRequester requester = new _UnitIndexRequester(this, unitIndex); | |
| 367 List<Location> unitLocations = | |
| 368 requester.getRelations(context, elementId, kind); | |
| 369 locations.addAll(unitLocations); | |
| 370 } | |
| 371 return locations; | |
| 372 } | |
| 373 | |
| 374 /** | |
| 375 * Return the identifier of [str] in the [index] or `-1` if [str] is not used | |
| 376 * in the [index]. | |
| 377 */ | |
| 378 int getStringId(String str) { | |
| 379 return binarySearch(index.strings, str); | |
| 380 } | |
| 381 | |
| 382 /** | |
| 383 * Return the identifier of the [CompilationUnitElement] containing the | |
| 384 * [element] in the [index] or `-1` if not found. | |
| 385 */ | |
| 386 int getUnitId(Element element) { | |
| 387 CompilationUnitElement unitElement = | |
| 388 PackageIndexAssembler.getUnitElement(element); | |
| 389 int libraryUriId = getUriId(unitElement.library.source.uri); | |
| 390 if (libraryUriId == -1) { | |
| 391 return -1; | |
| 392 } | |
| 393 int unitUriId = getUriId(unitElement.source.uri); | |
| 394 if (unitUriId == -1) { | |
| 395 return -1; | |
| 396 } | |
| 397 for (int i = 0; i < index.unitLibraryUris.length; i++) { | |
| 398 if (index.unitLibraryUris[i] == libraryUriId && | |
| 399 index.unitUnitUris[i] == unitUriId) { | |
| 400 return i; | |
| 401 } | |
| 402 } | |
| 403 return -1; | |
| 404 } | |
| 405 | |
| 406 /** | |
| 407 * Return the URI of the library source of the library specific [unit]. | |
| 408 */ | |
| 409 String getUnitLibraryUri(int unit) { | |
| 410 int id = index.unitLibraryUris[unit]; | |
| 411 return index.strings[id]; | |
| 412 } | |
| 413 | |
| 414 /** | |
| 415 * Return the URI of the unit source of the library specific [unit]. | |
| 416 */ | |
| 417 String getUnitUnitUri(int unit) { | |
| 418 int id = index.unitUnitUris[unit]; | |
| 419 return index.strings[id]; | |
| 420 } | |
| 421 | |
| 422 /** | |
| 423 * Complete with a list of locations where a class members with the given | |
| 424 * [name] is referenced with a qualifier, but is not resolved. | |
| 425 */ | |
| 426 List<Location> getUnresolvedMemberReferences( | |
| 427 AnalysisContext context, String name) { | |
| 428 List<Location> locations = <Location>[]; | |
| 429 for (UnitIndex unitIndex in index.units) { | |
| 430 _UnitIndexRequester requester = new _UnitIndexRequester(this, unitIndex); | |
| 431 List<Location> unitLocations = | |
| 432 requester.getUnresolvedMemberReferences(context, name); | |
| 433 locations.addAll(unitLocations); | |
| 434 } | |
| 435 return locations; | |
| 436 } | |
| 437 | |
| 438 /** | |
| 439 * Return the identifier of the [uri] in the [index] or `-1` if the [uri] is | |
| 440 * not used in the [index]. | |
| 441 */ | |
| 442 int getUriId(Uri uri) { | |
| 443 String str = uri.toString(); | |
| 444 return getStringId(str); | |
| 445 } | |
| 446 } | |
| 447 | |
| 448 /** | |
| 449 * Helper for requesting information from a single [UnitIndex]. | |
| 450 */ | |
| 451 class _UnitIndexRequester { | |
| 452 final _PackageIndexRequester packageRequester; | |
| 453 final UnitIndex unitIndex; | |
| 454 | |
| 455 _UnitIndexRequester(this.packageRequester, this.unitIndex); | |
| 456 | |
| 457 /** | |
| 458 * Complete with a list of locations where elements of the given [kind] with | |
| 459 * names satisfying the given [regExp] are defined. | |
| 460 */ | |
| 461 List<Location> getDefinedNames( | |
| 462 AnalysisContext context, RegExp regExp, IndexNameKind kind) { | |
| 463 List<Location> locations = <Location>[]; | |
| 464 String unitLibraryUri = null; | |
| 465 String unitUnitUri = null; | |
| 466 for (int i = 0; i < unitIndex.definedNames.length; i++) { | |
| 467 if (unitIndex.definedNameKinds[i] == kind) { | |
| 468 int nameIndex = unitIndex.definedNames[i]; | |
| 469 String name = packageRequester.index.strings[nameIndex]; | |
| 470 if (regExp.matchAsPrefix(name) != null) { | |
| 471 unitLibraryUri ??= packageRequester.getUnitLibraryUri(unitIndex.unit); | |
| 472 unitUnitUri ??= packageRequester.getUnitUnitUri(unitIndex.unit); | |
| 473 locations.add(new Location(context, unitLibraryUri, unitUnitUri, null, | |
| 474 unitIndex.definedNameOffsets[i], name.length, false, true)); | |
| 475 } | |
| 476 } | |
| 477 } | |
| 478 return locations; | |
| 479 } | |
| 480 | |
| 481 /** | |
| 482 * Return a list of locations where an element with the given [elementId] has | |
| 483 * relation of the given [kind]. | |
| 484 */ | |
| 485 List<Location> getRelations( | |
| 486 AnalysisContext context, int elementId, IndexRelationKind kind) { | |
| 487 // Find the first usage of the element. | |
| 488 int i = _findFirstOccurrence(unitIndex.usedElements, elementId); | |
| 489 if (i == -1) { | |
| 490 return const <Location>[]; | |
| 491 } | |
| 492 // Create locations for every usage of the element. | |
| 493 List<Location> locations = <Location>[]; | |
| 494 String unitLibraryUri = null; | |
| 495 String unitUnitUri = null; | |
| 496 for (; | |
| 497 i < unitIndex.usedElements.length && | |
| 498 unitIndex.usedElements[i] == elementId; | |
| 499 i++) { | |
| 500 if (unitIndex.usedElementKinds[i] == kind) { | |
| 501 unitLibraryUri ??= packageRequester.getUnitLibraryUri(unitIndex.unit); | |
| 502 unitUnitUri ??= packageRequester.getUnitUnitUri(unitIndex.unit); | |
| 503 locations.add(new Location( | |
| 504 context, | |
| 505 unitLibraryUri, | |
| 506 unitUnitUri, | |
| 507 kind, | |
| 508 unitIndex.usedElementOffsets[i], | |
| 509 unitIndex.usedElementLengths[i], | |
| 510 unitIndex.usedElementIsQualifiedFlags[i], | |
| 511 true)); | |
| 512 } | |
| 513 } | |
| 514 return locations; | |
| 515 } | |
| 516 | |
| 517 /** | |
| 518 * Complete with a list of locations where a class members with the given | |
| 519 * [name] is referenced with a qualifier, but is not resolved. | |
| 520 */ | |
| 521 List<Location> getUnresolvedMemberReferences( | |
| 522 AnalysisContext context, String name) { | |
| 523 // Find the name ID in the package index. | |
| 524 int nameId = packageRequester.getStringId(name); | |
| 525 if (nameId == -1) { | |
| 526 return const <Location>[]; | |
| 527 } | |
| 528 // Find the first usage of the name. | |
| 529 int i = _findFirstOccurrence(unitIndex.usedNames, nameId); | |
| 530 if (i == -1) { | |
| 531 return const <Location>[]; | |
| 532 } | |
| 533 // Create locations for every usage of the name. | |
| 534 List<Location> locations = <Location>[]; | |
| 535 String unitLibraryUri = null; | |
| 536 String unitUnitUri = null; | |
| 537 for (; | |
| 538 i < unitIndex.usedNames.length && unitIndex.usedNames[i] == nameId; | |
| 539 i++) { | |
| 540 unitLibraryUri ??= packageRequester.getUnitLibraryUri(unitIndex.unit); | |
| 541 unitUnitUri ??= packageRequester.getUnitUnitUri(unitIndex.unit); | |
| 542 locations.add(new Location( | |
| 543 context, | |
| 544 unitLibraryUri, | |
| 545 unitUnitUri, | |
| 546 unitIndex.usedNameKinds[i], | |
| 547 unitIndex.usedNameOffsets[i], | |
| 548 name.length, | |
| 549 unitIndex.usedNameIsQualifiedFlags[i], | |
| 550 false)); | |
| 551 } | |
| 552 return locations; | |
| 553 } | |
| 554 } | |
| OLD | NEW |