| Index: pkg/analysis_server/lib/src/services/index2/index2.dart
|
| diff --git a/pkg/analysis_server/lib/src/services/index2/index2.dart b/pkg/analysis_server/lib/src/services/index2/index2.dart
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..55feaea60f627d86565e169f98ffba9a6df38eef
|
| --- /dev/null
|
| +++ b/pkg/analysis_server/lib/src/services/index2/index2.dart
|
| @@ -0,0 +1,268 @@
|
| +// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
|
| +// for details. All rights reserved. Use of this source code is governed by a
|
| +// BSD-style license that can be found in the LICENSE file.
|
| +
|
| +import 'dart:async';
|
| +
|
| +import 'package:analyzer/dart/ast/ast.dart';
|
| +import 'package:analyzer/dart/element/element.dart';
|
| +import 'package:analyzer/src/generated/source.dart';
|
| +import 'package:analyzer/src/summary/format.dart';
|
| +import 'package:analyzer/src/summary/idl.dart';
|
| +import 'package:analyzer/src/summary/index_unit.dart';
|
| +import 'package:collection/collection.dart';
|
| +
|
| +/**
|
| + * Interface for storing and requesting relations.
|
| + */
|
| +class Index2 {
|
| + final PackageIndexStore _store;
|
| +
|
| + Index2(this._store);
|
| +
|
| + /**
|
| + * Complete with a list of locations where the given [element] has relation
|
| + * of the given [kind].
|
| + */
|
| + Future<List<Location>> getRelations(
|
| + Element element, IndexRelationKind kind) async {
|
| + List<Location> locations = <Location>[];
|
| + Iterable<PackageIndexId> ids = await _store.getIds();
|
| + for (PackageIndexId id in ids) {
|
| + PackageIndex index = await _store.getIndex(id);
|
| + _PackageIndexRequester requester = new _PackageIndexRequester(index);
|
| + List<Location> packageLocations = requester.getRelations(element, kind);
|
| + locations.addAll(packageLocations);
|
| + }
|
| + return locations;
|
| + }
|
| +
|
| + /**
|
| + * Index the given fully resolved [unit].
|
| + */
|
| + void indexUnit(CompilationUnit unit) {
|
| + PackageIndexAssembler assembler = new PackageIndexAssembler();
|
| + assembler.index(unit);
|
| + PackageIndexBuilder indexBuilder = assembler.assemble();
|
| + String unitLibraryUri = unit.element.library.source.uri.toString();
|
| + String unitUnitUri = unit.element.source.uri.toString();
|
| + _store.putIndex(unitLibraryUri, unitUnitUri, indexBuilder);
|
| + }
|
| +}
|
| +
|
| +/**
|
| + * Information about location of a single relation in the index.
|
| + *
|
| + * The location is expressed as a library specific unit containing the index
|
| + * relation, offset within this [Source] and length.
|
| + *
|
| + * Clients may not extend, implement or mix-in this class.
|
| + */
|
| +class Location {
|
| + /**
|
| + * The URI of the source of the library containing this location.
|
| + */
|
| + final String libraryUri;
|
| +
|
| + /**
|
| + * The URI of the source of the unit containing this location.
|
| + */
|
| + final String unitUri;
|
| +
|
| + /**
|
| + * The offset of this location within the [unitUri].
|
| + */
|
| + final int offset;
|
| +
|
| + /**
|
| + * The length of this location.
|
| + */
|
| + final int length;
|
| +
|
| + /**
|
| + * Is `true` if this location is qualified.
|
| + */
|
| + final bool isQualified;
|
| +
|
| + Location(this.libraryUri, this.unitUri, this.offset, this.length,
|
| + this.isQualified);
|
| +
|
| + @override
|
| + String toString() => 'Location{librarySourceUri: $libraryUri, '
|
| + 'unitSourceUri: $unitUri, offset: $offset, length: $length, '
|
| + 'isQualified: $isQualified}';
|
| +}
|
| +
|
| +/**
|
| + * Opaque identifier of a [PackageIndex].
|
| + */
|
| +abstract class PackageIndexId {}
|
| +
|
| +/**
|
| + * Storage of [PackageIndex] objects.
|
| + */
|
| +abstract class PackageIndexStore {
|
| + /**
|
| + * Complete with identifiers of all [PackageIndex] objects.
|
| + */
|
| + Future<Iterable<PackageIndexId>> getIds();
|
| +
|
| + /**
|
| + * Complete with the [PackageIndex] with the given [id].
|
| + */
|
| + Future<PackageIndex> getIndex(PackageIndexId id);
|
| +
|
| + /**
|
| + * Put the given [indexBuilder] into the store.
|
| + */
|
| + void putIndex(String unitLibraryUri, String unitUnitUri,
|
| + PackageIndexBuilder indexBuilder);
|
| +}
|
| +
|
| +/**
|
| + * Helper for requesting information from a single [PackageIndex].
|
| + */
|
| +class _PackageIndexRequester {
|
| + final PackageIndex index;
|
| +
|
| + _PackageIndexRequester(this.index);
|
| +
|
| + /**
|
| + * Return the [element]'s identifier in the [index] or `null` if the
|
| + * [element] is not referenced in the [index].
|
| + */
|
| + int findElementId(Element element) {
|
| + int unitId = getUnitId(element);
|
| + int offset = element.nameOffset;
|
| + if (element is LibraryElement || element is CompilationUnitElement) {
|
| + offset = 0;
|
| + }
|
| + IndexSyntheticElementKind kind =
|
| + PackageIndexAssembler.getIndexElementKind(element);
|
| + for (int elementId = 0;
|
| + elementId < index.elementUnits.length;
|
| + elementId++) {
|
| + if (index.elementUnits[elementId] == unitId &&
|
| + index.elementOffsets[elementId] == offset &&
|
| + index.elementKinds[elementId] == kind) {
|
| + return elementId;
|
| + }
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + /**
|
| + * Complete with a list of locations where the given [element] has relation
|
| + * of the given [kind].
|
| + */
|
| + List<Location> getRelations(Element element, IndexRelationKind kind) {
|
| + int elementId = findElementId(element);
|
| + if (elementId == null) {
|
| + return const <Location>[];
|
| + }
|
| + List<Location> locations = <Location>[];
|
| + for (UnitIndex unitIndex in index.units) {
|
| + _UnitIndexRequester requester = new _UnitIndexRequester(this, unitIndex);
|
| + List<Location> unitLocations = requester.getRelations(elementId, kind);
|
| + locations.addAll(unitLocations);
|
| + }
|
| + return locations;
|
| + }
|
| +
|
| + /**
|
| + * Return the identifier of [str] in the [index] or `-1` if [str] is not used
|
| + * in the [index].
|
| + */
|
| + int getStringId(String str) {
|
| + return index.strings.indexOf(str);
|
| + }
|
| +
|
| + /**
|
| + * Return the identifier of the [CompilationUnitElement] containing the
|
| + * [element] in the [index] or `-1` if not found.
|
| + */
|
| + int getUnitId(Element element) {
|
| + CompilationUnitElement unitElement =
|
| + PackageIndexAssembler.getUnitElement(element);
|
| + int libraryUriId = getUriId(unitElement.library.source.uri);
|
| + int unitUriId = getUriId(unitElement.source.uri);
|
| + for (int i = 0; i < index.unitLibraryUris.length; i++) {
|
| + if (index.unitLibraryUris[i] == libraryUriId &&
|
| + index.unitUnitUris[i] == unitUriId) {
|
| + return i;
|
| + }
|
| + }
|
| + return -1;
|
| + }
|
| +
|
| + /**
|
| + * Return the URI of the library source of the library specific [unit].
|
| + */
|
| + String getUnitLibraryUri(int unit) {
|
| + int id = index.unitLibraryUris[unit];
|
| + return index.strings[id];
|
| + }
|
| +
|
| + /**
|
| + * Return the URI of the unit source of the library specific [unit].
|
| + */
|
| + String getUnitUnitUri(int unit) {
|
| + int id = index.unitUnitUris[unit];
|
| + return index.strings[id];
|
| + }
|
| +
|
| + /**
|
| + * Return the identifier of the [uri] in the [index] or `-1` if the [uri] is
|
| + * not used in the [index].
|
| + */
|
| + int getUriId(Uri uri) {
|
| + String str = uri.toString();
|
| + return getStringId(str);
|
| + }
|
| +}
|
| +
|
| +/**
|
| + * Helper for requesting information from a single [UnitIndex].
|
| + */
|
| +class _UnitIndexRequester {
|
| + final _PackageIndexRequester packageRequester;
|
| + final UnitIndex unitIndex;
|
| +
|
| + _UnitIndexRequester(this.packageRequester, this.unitIndex);
|
| +
|
| + /**
|
| + * Return a list of locations where an element with the given [elementId] has
|
| + * relation of the given [kind].
|
| + */
|
| + List<Location> getRelations(int elementId, IndexRelationKind kind) {
|
| + // Find a usage of the element.
|
| + int i = binarySearch(unitIndex.usedElements, elementId);
|
| + if (i == -1) {
|
| + return const <Location>[];
|
| + }
|
| + // Find the first usage of the element.
|
| + while (i > 0 && unitIndex.usedElements[i - 1] == elementId) {
|
| + i--;
|
| + }
|
| + // Create locations for every usage of the element.
|
| + List<Location> locations = <Location>[];
|
| + String unitLibraryUri = null;
|
| + String unitUnitUri = null;
|
| + for (;
|
| + i < unitIndex.usedElements.length &&
|
| + unitIndex.usedElements[i] == elementId;
|
| + i++) {
|
| + if (unitIndex.usedElementKinds[i] == kind) {
|
| + unitLibraryUri ??= packageRequester.getUnitLibraryUri(unitIndex.unit);
|
| + unitUnitUri ??= packageRequester.getUnitUnitUri(unitIndex.unit);
|
| + locations.add(new Location(
|
| + unitLibraryUri,
|
| + unitUnitUri,
|
| + unitIndex.usedElementOffsets[i],
|
| + unitIndex.usedElementLengths[i],
|
| + unitIndex.usedElementIsQualifiedFlags[i]));
|
| + }
|
| + }
|
| + return locations;
|
| + }
|
| +}
|
|
|