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/source.dart'; |
| 10 import 'package:analyzer/src/summary/format.dart'; |
| 11 import 'package:analyzer/src/summary/idl.dart'; |
| 12 import 'package:analyzer/src/summary/index_unit.dart'; |
| 13 import 'package:collection/collection.dart'; |
| 14 |
| 15 /** |
| 16 * Interface for storing and requesting relations. |
| 17 */ |
| 18 class Index2 { |
| 19 final PackageIndexStore _store; |
| 20 |
| 21 Index2(this._store); |
| 22 |
| 23 /** |
| 24 * Complete with a list of locations where the given [element] has relation |
| 25 * of the given [kind]. |
| 26 */ |
| 27 Future<List<Location>> getRelations( |
| 28 Element element, IndexRelationKind kind) async { |
| 29 List<Location> locations = <Location>[]; |
| 30 Iterable<PackageIndexId> ids = await _store.getIds(); |
| 31 for (PackageIndexId id in ids) { |
| 32 PackageIndex index = await _store.getIndex(id); |
| 33 _PackageIndexRequester requester = new _PackageIndexRequester(index); |
| 34 List<Location> packageLocations = requester.getRelations(element, kind); |
| 35 locations.addAll(packageLocations); |
| 36 } |
| 37 return locations; |
| 38 } |
| 39 |
| 40 /** |
| 41 * Index the given fully resolved [unit]. |
| 42 */ |
| 43 void indexUnit(CompilationUnit unit) { |
| 44 PackageIndexAssembler assembler = new PackageIndexAssembler(); |
| 45 assembler.index(unit); |
| 46 PackageIndexBuilder indexBuilder = assembler.assemble(); |
| 47 String unitLibraryUri = unit.element.library.source.uri.toString(); |
| 48 String unitUnitUri = unit.element.source.uri.toString(); |
| 49 _store.putIndex(unitLibraryUri, unitUnitUri, indexBuilder); |
| 50 } |
| 51 } |
| 52 |
| 53 /** |
| 54 * Information about location of a single relation in the index. |
| 55 * |
| 56 * The location is expressed as a library specific unit containing the index |
| 57 * relation, offset within this [Source] and length. |
| 58 * |
| 59 * Clients may not extend, implement or mix-in this class. |
| 60 */ |
| 61 class Location { |
| 62 /** |
| 63 * The URI of the source of the library containing this location. |
| 64 */ |
| 65 final String libraryUri; |
| 66 |
| 67 /** |
| 68 * The URI of the source of the unit containing this location. |
| 69 */ |
| 70 final String unitUri; |
| 71 |
| 72 /** |
| 73 * The offset of this location within the [unitUri]. |
| 74 */ |
| 75 final int offset; |
| 76 |
| 77 /** |
| 78 * The length of this location. |
| 79 */ |
| 80 final int length; |
| 81 |
| 82 /** |
| 83 * Is `true` if this location is qualified. |
| 84 */ |
| 85 final bool isQualified; |
| 86 |
| 87 Location(this.libraryUri, this.unitUri, this.offset, this.length, |
| 88 this.isQualified); |
| 89 |
| 90 @override |
| 91 String toString() => 'Location{librarySourceUri: $libraryUri, ' |
| 92 'unitSourceUri: $unitUri, offset: $offset, length: $length, ' |
| 93 'isQualified: $isQualified}'; |
| 94 } |
| 95 |
| 96 /** |
| 97 * Opaque identifier of a [PackageIndex]. |
| 98 */ |
| 99 abstract class PackageIndexId {} |
| 100 |
| 101 /** |
| 102 * Storage of [PackageIndex] objects. |
| 103 */ |
| 104 abstract class PackageIndexStore { |
| 105 /** |
| 106 * Complete with identifiers of all [PackageIndex] objects. |
| 107 */ |
| 108 Future<Iterable<PackageIndexId>> getIds(); |
| 109 |
| 110 /** |
| 111 * Complete with the [PackageIndex] with the given [id]. |
| 112 */ |
| 113 Future<PackageIndex> getIndex(PackageIndexId id); |
| 114 |
| 115 /** |
| 116 * Put the given [indexBuilder] into the store. |
| 117 */ |
| 118 void putIndex(String unitLibraryUri, String unitUnitUri, |
| 119 PackageIndexBuilder indexBuilder); |
| 120 } |
| 121 |
| 122 /** |
| 123 * Helper for requesting information from a single [PackageIndex]. |
| 124 */ |
| 125 class _PackageIndexRequester { |
| 126 final PackageIndex index; |
| 127 |
| 128 _PackageIndexRequester(this.index); |
| 129 |
| 130 /** |
| 131 * Return the [element]'s identifier in the [index] or `null` if the |
| 132 * [element] is not referenced in the [index]. |
| 133 */ |
| 134 int findElementId(Element element) { |
| 135 int unitId = getUnitId(element); |
| 136 int offset = element.nameOffset; |
| 137 if (element is LibraryElement || element is CompilationUnitElement) { |
| 138 offset = 0; |
| 139 } |
| 140 IndexSyntheticElementKind kind = |
| 141 PackageIndexAssembler.getIndexElementKind(element); |
| 142 for (int elementId = 0; |
| 143 elementId < index.elementUnits.length; |
| 144 elementId++) { |
| 145 if (index.elementUnits[elementId] == unitId && |
| 146 index.elementOffsets[elementId] == offset && |
| 147 index.elementKinds[elementId] == kind) { |
| 148 return elementId; |
| 149 } |
| 150 } |
| 151 return null; |
| 152 } |
| 153 |
| 154 /** |
| 155 * Complete with a list of locations where the given [element] has relation |
| 156 * of the given [kind]. |
| 157 */ |
| 158 List<Location> getRelations(Element element, IndexRelationKind kind) { |
| 159 int elementId = findElementId(element); |
| 160 if (elementId == null) { |
| 161 return const <Location>[]; |
| 162 } |
| 163 List<Location> locations = <Location>[]; |
| 164 for (UnitIndex unitIndex in index.units) { |
| 165 _UnitIndexRequester requester = new _UnitIndexRequester(this, unitIndex); |
| 166 List<Location> unitLocations = requester.getRelations(elementId, kind); |
| 167 locations.addAll(unitLocations); |
| 168 } |
| 169 return locations; |
| 170 } |
| 171 |
| 172 /** |
| 173 * Return the identifier of [str] in the [index] or `-1` if [str] is not used |
| 174 * in the [index]. |
| 175 */ |
| 176 int getStringId(String str) { |
| 177 return index.strings.indexOf(str); |
| 178 } |
| 179 |
| 180 /** |
| 181 * Return the identifier of the [CompilationUnitElement] containing the |
| 182 * [element] in the [index] or `-1` if not found. |
| 183 */ |
| 184 int getUnitId(Element element) { |
| 185 CompilationUnitElement unitElement = |
| 186 PackageIndexAssembler.getUnitElement(element); |
| 187 int libraryUriId = getUriId(unitElement.library.source.uri); |
| 188 int unitUriId = getUriId(unitElement.source.uri); |
| 189 for (int i = 0; i < index.unitLibraryUris.length; i++) { |
| 190 if (index.unitLibraryUris[i] == libraryUriId && |
| 191 index.unitUnitUris[i] == unitUriId) { |
| 192 return i; |
| 193 } |
| 194 } |
| 195 return -1; |
| 196 } |
| 197 |
| 198 /** |
| 199 * Return the URI of the library source of the library specific [unit]. |
| 200 */ |
| 201 String getUnitLibraryUri(int unit) { |
| 202 int id = index.unitLibraryUris[unit]; |
| 203 return index.strings[id]; |
| 204 } |
| 205 |
| 206 /** |
| 207 * Return the URI of the unit source of the library specific [unit]. |
| 208 */ |
| 209 String getUnitUnitUri(int unit) { |
| 210 int id = index.unitUnitUris[unit]; |
| 211 return index.strings[id]; |
| 212 } |
| 213 |
| 214 /** |
| 215 * Return the identifier of the [uri] in the [index] or `-1` if the [uri] is |
| 216 * not used in the [index]. |
| 217 */ |
| 218 int getUriId(Uri uri) { |
| 219 String str = uri.toString(); |
| 220 return getStringId(str); |
| 221 } |
| 222 } |
| 223 |
| 224 /** |
| 225 * Helper for requesting information from a single [UnitIndex]. |
| 226 */ |
| 227 class _UnitIndexRequester { |
| 228 final _PackageIndexRequester packageRequester; |
| 229 final UnitIndex unitIndex; |
| 230 |
| 231 _UnitIndexRequester(this.packageRequester, this.unitIndex); |
| 232 |
| 233 /** |
| 234 * Return a list of locations where an element with the given [elementId] has |
| 235 * relation of the given [kind]. |
| 236 */ |
| 237 List<Location> getRelations(int elementId, IndexRelationKind kind) { |
| 238 // Find a usage of the element. |
| 239 int i = binarySearch(unitIndex.usedElements, elementId); |
| 240 if (i == -1) { |
| 241 return const <Location>[]; |
| 242 } |
| 243 // Find the first usage of the element. |
| 244 while (i > 0 && unitIndex.usedElements[i - 1] == elementId) { |
| 245 i--; |
| 246 } |
| 247 // Create locations for every usage of the element. |
| 248 List<Location> locations = <Location>[]; |
| 249 String unitLibraryUri = null; |
| 250 String unitUnitUri = null; |
| 251 for (; |
| 252 i < unitIndex.usedElements.length && |
| 253 unitIndex.usedElements[i] == elementId; |
| 254 i++) { |
| 255 if (unitIndex.usedElementKinds[i] == kind) { |
| 256 unitLibraryUri ??= packageRequester.getUnitLibraryUri(unitIndex.unit); |
| 257 unitUnitUri ??= packageRequester.getUnitUnitUri(unitIndex.unit); |
| 258 locations.add(new Location( |
| 259 unitLibraryUri, |
| 260 unitUnitUri, |
| 261 unitIndex.usedElementOffsets[i], |
| 262 unitIndex.usedElementLengths[i], |
| 263 unitIndex.usedElementIsQualifiedFlags[i])); |
| 264 } |
| 265 } |
| 266 return locations; |
| 267 } |
| 268 } |
OLD | NEW |