| Index: pkg/analysis_server/lib/src/services/index/index.dart
|
| diff --git a/pkg/analysis_server/lib/src/services/index/index.dart b/pkg/analysis_server/lib/src/services/index/index.dart
|
| index d86b32247eb563cc5e49b9b8acc8d269538a550a..5e866bc35c164c01e3dd6fcb6cfa510177f2c438 100644
|
| --- a/pkg/analysis_server/lib/src/services/index/index.dart
|
| +++ b/pkg/analysis_server/lib/src/services/index/index.dart
|
| @@ -1,371 +1,559 @@
|
| -// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
|
| +// 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.
|
|
|
| -library services.index;
|
| -
|
| import 'dart:async';
|
|
|
| -import 'package:analysis_server/src/provisional/index/index_core.dart';
|
| -import 'package:analysis_server/src/services/index/indexable_element.dart';
|
| +import 'package:analyzer/dart/ast/ast.dart';
|
| import 'package:analyzer/dart/element/element.dart';
|
| -import 'package:analyzer/src/generated/engine.dart';
|
| +import 'package:analyzer/src/generated/engine.dart' show AnalysisContext;
|
| +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';
|
|
|
| /**
|
| - * A filter for [Element] names.
|
| + * Return a new [Index] instance that keeps information in memory.
|
| */
|
| -typedef bool ElementNameFilter(String name);
|
| +Index createMemoryIndex() {
|
| + return new Index._();
|
| +}
|
|
|
| /**
|
| - * The interface [Index] defines the behavior of objects that maintain an index
|
| - * storing relations between indexable objects.
|
| - *
|
| - * Any modification operations are executed before any read operation.
|
| - * There is no guarantee about the order in which the [Future]s for read
|
| - * operations will complete.
|
| + * Return the index of the first occurrence of the [value] in the [sortedList],
|
| + * or `-1` if the [value] is not in the list.
|
| */
|
| -abstract class Index implements IndexStore {
|
| - /**
|
| - * Set the index contributors used by this index to the given list of
|
| - * [contributors].
|
| - */
|
| - void set contributors(List<IndexContributor> contributors);
|
| +int _findFirstOccurrence(List<int> sortedList, int value) {
|
| + // Find an occurrence.
|
| + int i = binarySearch(sortedList, value);
|
| + if (i == -1) {
|
| + return -1;
|
| + }
|
| + // Find the first occurrence.
|
| + while (i > 0 && sortedList[i - 1] == value) {
|
| + i--;
|
| + }
|
| + return i;
|
| +}
|
|
|
| - /**
|
| - * Answers index statistics.
|
| - */
|
| - String get statistics;
|
| +/**
|
| + * Interface for storing and requesting relations.
|
| + */
|
| +class Index {
|
| + final Map<AnalysisContext, _ContextIndex> _contextIndexMap =
|
| + <AnalysisContext, _ContextIndex>{};
|
|
|
| - /**
|
| - * Returns top-level [Element]s whose names satisfy to [nameFilter].
|
| - */
|
| - List<Element> getTopLevelDeclarations(ElementNameFilter nameFilter);
|
| + Index._();
|
|
|
| /**
|
| - * Processes the given [object] in order to record the relationships.
|
| - *
|
| - * [context] - the [AnalysisContext] in which the [object] being indexed.
|
| - * [object] - the object being indexed.
|
| + * Complete with a list of locations where elements of the given [kind] with
|
| + * names satisfying the given [regExp] are defined.
|
| */
|
| - void index(AnalysisContext context, Object object);
|
| + Future<List<Location>> getDefinedNames(RegExp regExp, IndexNameKind kind) {
|
| + return _mergeLocations((_ContextIndex index) {
|
| + return index.getDefinedNames(regExp, kind);
|
| + });
|
| + }
|
|
|
| /**
|
| - * Starts the index.
|
| - * Should be called before any other method.
|
| + * Complete with a list of locations where the given [element] has relation
|
| + * of the given [kind].
|
| */
|
| - void run();
|
| + Future<List<Location>> getRelations(Element element, IndexRelationKind kind) {
|
| + return _mergeLocations((_ContextIndex index) {
|
| + return index.getRelations(element, kind);
|
| + });
|
| + }
|
|
|
| /**
|
| - * Stops the index.
|
| - * After calling this method operations may not be executed.
|
| + * Complete with a list of locations where a class members with the given
|
| + * [name] is referenced with a qualifier, but is not resolved.
|
| */
|
| - void stop();
|
| -}
|
| + Future<List<Location>> getUnresolvedMemberReferences(String name) {
|
| + return _mergeLocations((_ContextIndex index) {
|
| + return index.getUnresolvedMemberReferences(name);
|
| + });
|
| + }
|
|
|
| -/**
|
| - * An [Element] which is used to index references to the name without specifying
|
| - * a concrete kind of this name - field, method or something else.
|
| - */
|
| -class IndexableName implements IndexableObject {
|
| /**
|
| - * The name to be indexed.
|
| + * Index the given fully resolved [unit].
|
| */
|
| - final String name;
|
| + void indexUnit(CompilationUnit unit) {
|
| + if (unit == null || unit.element == null) {
|
| + return;
|
| + }
|
| + AnalysisContext context = unit.element.context;
|
| + _getContextIndex(context).indexUnit(unit);
|
| + }
|
|
|
| /**
|
| - * Initialize a newly created indexable name to represent the given [name].
|
| + * Remove all index information for the given [context].
|
| */
|
| - IndexableName(this.name);
|
| -
|
| - @override
|
| - String get filePath => null;
|
| -
|
| - @override
|
| - IndexableNameKind get kind => IndexableNameKind.INSTANCE;
|
| -
|
| - @override
|
| - int get offset {
|
| - return -1;
|
| + void removeContext(AnalysisContext context) {
|
| + _contextIndexMap.remove(context);
|
| }
|
|
|
| - @override
|
| - bool operator ==(Object object) =>
|
| - object is IndexableName && object.name == name;
|
| -
|
| - @override
|
| - String toString() => name;
|
| -}
|
| -
|
| -/**
|
| - * The kind of an indexable name.
|
| - */
|
| -class IndexableNameKind implements IndexableObjectKind<IndexableName> {
|
| /**
|
| - * The unique instance of this class.
|
| + * Remove index information about the unit in the given [context].
|
| */
|
| - static final IndexableNameKind INSTANCE =
|
| - new IndexableNameKind._(IndexableObjectKind.nextIndex);
|
| + void removeUnit(
|
| + AnalysisContext context, Source librarySource, Source unitSource) {
|
| + _contextIndexMap[context]?.removeUnit(librarySource, unitSource);
|
| + }
|
|
|
| /**
|
| - * The index uniquely identifying this kind.
|
| + * Notify the index that the client is going to stop using it.
|
| */
|
| - final int index;
|
| + void stop() {}
|
|
|
| /**
|
| - * Initialize a newly created kind to have the given [index].
|
| + * Return the [_ContextIndex] instance for the given [context].
|
| */
|
| - IndexableNameKind._(this.index) {
|
| - IndexableObjectKind.register(this);
|
| - }
|
| -
|
| - @override
|
| - IndexableName decode(AnalysisContext context, String filePath, int offset) {
|
| - throw new UnsupportedError(
|
| - 'Indexable names cannot be decoded through their kind');
|
| + _ContextIndex _getContextIndex(AnalysisContext context) {
|
| + return _contextIndexMap.putIfAbsent(context, () {
|
| + return new _ContextIndex(context);
|
| + });
|
| }
|
|
|
| - @override
|
| - int encodeHash(StringToInt stringToInt, IndexableName indexable) {
|
| - String name = indexable.name;
|
| - return stringToInt(name);
|
| + /**
|
| + * Complete with a list of all results returned by the [callback] for every
|
| + * context specific index.
|
| + */
|
| + Future<List<Location>> _mergeLocations(
|
| + Future<List<Location>> callback(_ContextIndex index)) async {
|
| + List<Location> locations = <Location>[];
|
| + for (_ContextIndex index in _contextIndexMap.values) {
|
| + List<Location> contextLocations = await callback(index);
|
| + locations.addAll(contextLocations);
|
| + }
|
| + return locations;
|
| }
|
| }
|
|
|
| /**
|
| - * Constants used when populating and accessing the index.
|
| + * 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 IndexConstants {
|
| +class Location {
|
| /**
|
| - * Left: the Universe or a Library.
|
| - * Defines an Element.
|
| - * Right: an Element declaration.
|
| + * The [AnalysisContext] containing this location.
|
| */
|
| - static final RelationshipImpl DEFINES =
|
| - RelationshipImpl.getRelationship("defines");
|
| + final AnalysisContext context;
|
|
|
| /**
|
| - * Left: class.
|
| - * Has ancestor (extended or implemented, directly or indirectly).
|
| - * Right: other class declaration.
|
| + * The URI of the source of the library containing this location.
|
| */
|
| - static final RelationshipImpl HAS_ANCESTOR =
|
| - RelationshipImpl.getRelationship("has-ancestor");
|
| + final String libraryUri;
|
|
|
| /**
|
| - * Left: class.
|
| - * Is extended by.
|
| - * Right: other class declaration.
|
| + * The URI of the source of the unit containing this location.
|
| */
|
| - static final RelationshipImpl IS_EXTENDED_BY =
|
| - RelationshipImpl.getRelationship("is-extended-by");
|
| + final String unitUri;
|
|
|
| /**
|
| - * Left: class.
|
| - * Is implemented by.
|
| - * Right: other class declaration.
|
| + * The kind of usage at this location.
|
| */
|
| - static final RelationshipImpl IS_IMPLEMENTED_BY =
|
| - RelationshipImpl.getRelationship("is-implemented-by");
|
| + final IndexRelationKind kind;
|
|
|
| /**
|
| - * Left: class.
|
| - * Is mixed into.
|
| - * Right: other class declaration.
|
| + * The offset of this location within the [unitUri].
|
| */
|
| - static final RelationshipImpl IS_MIXED_IN_BY =
|
| - RelationshipImpl.getRelationship("is-mixed-in-by");
|
| + final int offset;
|
|
|
| /**
|
| - * Left: local variable, parameter.
|
| - * Is read at.
|
| - * Right: location.
|
| + * The length of this location.
|
| */
|
| - static final RelationshipImpl IS_READ_BY =
|
| - RelationshipImpl.getRelationship("is-read-by");
|
| + final int length;
|
|
|
| /**
|
| - * Left: local variable, parameter.
|
| - * Is both read and written at.
|
| - * Right: location.
|
| + * Is `true` if this location is qualified.
|
| */
|
| - static final RelationshipImpl IS_READ_WRITTEN_BY =
|
| - RelationshipImpl.getRelationship("is-read-written-by");
|
| + final bool isQualified;
|
|
|
| /**
|
| - * Left: local variable, parameter.
|
| - * Is written at.
|
| - * Right: location.
|
| + * Is `true` if this location is resolved.
|
| */
|
| - static final RelationshipImpl IS_WRITTEN_BY =
|
| - RelationshipImpl.getRelationship("is-written-by");
|
| + final bool isResolved;
|
| +
|
| + Location(this.context, this.libraryUri, this.unitUri, this.kind, this.offset,
|
| + this.length, this.isQualified, this.isResolved);
|
|
|
| + @override
|
| + String toString() => 'Location{librarySourceUri: $libraryUri, '
|
| + 'unitSourceUri: $unitUri, offset: $offset, length: $length, '
|
| + 'isQualified: $isQualified}, isResolved: $isResolved}';
|
| +}
|
| +
|
| +/**
|
| + * Opaque identifier of a [PackageIndex].
|
| + */
|
| +abstract class PackageIndexId {}
|
| +
|
| +/**
|
| + * Storage of [PackageIndex] objects.
|
| + */
|
| +abstract class PackageIndexStore {
|
| /**
|
| - * Left: function, method, variable, getter.
|
| - * Is invoked at.
|
| - * Right: location.
|
| + * Complete with identifiers of all [PackageIndex] objects.
|
| */
|
| - static final RelationshipImpl IS_INVOKED_BY =
|
| - RelationshipImpl.getRelationship("is-invoked-by");
|
| + Future<Iterable<PackageIndexId>> getIds();
|
|
|
| /**
|
| - * Left: function, function type, class, field, method.
|
| - * Is referenced (and not invoked, read/written) at.
|
| - * Right: location.
|
| + * Complete with the [PackageIndex] with the given [id].
|
| */
|
| - static final RelationshipImpl IS_REFERENCED_BY =
|
| - RelationshipImpl.getRelationship("is-referenced-by");
|
| + Future<PackageIndex> getIndex(PackageIndexId id);
|
|
|
| /**
|
| - * Left: name element.
|
| - * Is defined by.
|
| - * Right: concrete element declaration.
|
| + * Put the given [indexBuilder] into the store.
|
| */
|
| - static final RelationshipImpl NAME_IS_DEFINED_BY =
|
| - RelationshipImpl.getRelationship("name-is-defined-by");
|
| -
|
| - IndexConstants._();
|
| + void putIndex(String unitLibraryUri, String unitUnitUri,
|
| + PackageIndexBuilder indexBuilder);
|
| }
|
|
|
| /**
|
| - * Instances of the class [LocationImpl] represent a location related to an
|
| - * element.
|
| - *
|
| - * The location is expressed as an offset and length, but the offset is relative
|
| - * to the resource containing the element rather than the start of the element
|
| - * within that resource.
|
| + * The [AnalysisContext] specific index.
|
| */
|
| -class LocationImpl implements Location {
|
| - static const int _FLAG_QUALIFIED = 1 << 0;
|
| - static const int _FLAG_RESOLVED = 1 << 1;
|
| +class _ContextIndex {
|
| + final AnalysisContext context;
|
| + final Map<String, PackageIndex> indexMap = <String, PackageIndex>{};
|
| +
|
| + _ContextIndex(this.context);
|
|
|
| /**
|
| - * An empty array of locations.
|
| + * Complete with a list of locations where elements of the given [kind] with
|
| + * names satisfying the given [regExp] are defined.
|
| */
|
| - static const List<LocationImpl> EMPTY_LIST = const <LocationImpl>[];
|
| + Future<List<Location>> getDefinedNames(
|
| + RegExp regExp, IndexNameKind kind) async {
|
| + return _mergeLocations((_PackageIndexRequester requester) {
|
| + return requester.getDefinedNames(context, regExp, kind);
|
| + });
|
| + }
|
|
|
| /**
|
| - * The indexable object containing this location.
|
| + * Complete with a list of locations where the given [element] has relation
|
| + * of the given [kind].
|
| */
|
| - final IndexableObject indexable;
|
| + Future<List<Location>> getRelations(Element element, IndexRelationKind kind) {
|
| + return _mergeLocations((_PackageIndexRequester requester) {
|
| + return requester.getRelations(context, element, kind);
|
| + });
|
| + }
|
|
|
| /**
|
| - * The offset of this location within the resource containing the element.
|
| + * Complete with a list of locations where a class members with the given
|
| + * [name] is referenced with a qualifier, but is not resolved.
|
| */
|
| - final int offset;
|
| + Future<List<Location>> getUnresolvedMemberReferences(String name) async {
|
| + return _mergeLocations((_PackageIndexRequester requester) {
|
| + return requester.getUnresolvedMemberReferences(context, name);
|
| + });
|
| + }
|
|
|
| /**
|
| - * The length of this location.
|
| + * Index the given fully resolved [unit].
|
| */
|
| - final int length;
|
| + void indexUnit(CompilationUnit unit) {
|
| + // Index the unit.
|
| + PackageIndexAssembler assembler = new PackageIndexAssembler();
|
| + assembler.index(unit);
|
| + PackageIndexBuilder indexBuilder = assembler.assemble();
|
| + // Put the index into the map.
|
| + List<int> indexBytes = indexBuilder.toBuffer();
|
| + PackageIndex index = new PackageIndex.fromBuffer(indexBytes);
|
| + String key = _getUnitKeyForElement(unit.element);
|
| + indexMap[key] = index;
|
| + }
|
|
|
| /**
|
| - * The flags of this location.
|
| + * Remove index information about the unit.
|
| */
|
| - int _flags;
|
| + void removeUnit(Source librarySource, Source unitSource) {
|
| + String key = _getUnitKeyForSource(librarySource, unitSource);
|
| + indexMap.remove(key);
|
| + }
|
| +
|
| + String _getUnitKeyForElement(CompilationUnitElement unitElement) {
|
| + Source librarySource = unitElement.library.source;
|
| + Source unitSource = unitElement.source;
|
| + return _getUnitKeyForSource(librarySource, unitSource);
|
| + }
|
| +
|
| + String _getUnitKeyForSource(Source librarySource, Source unitSource) {
|
| + String unitLibraryUri = librarySource.uri.toString();
|
| + String unitUnitUri = unitSource.uri.toString();
|
| + return '$unitLibraryUri;$unitUnitUri';
|
| + }
|
| +
|
| + Future<List<Location>> _mergeLocations(
|
| + List<Location> callback(_PackageIndexRequester requester)) async {
|
| + List<Location> locations = <Location>[];
|
| + for (PackageIndex index in indexMap.values) {
|
| + _PackageIndexRequester requester = new _PackageIndexRequester(index);
|
| + List<Location> indexLocations = callback(requester);
|
| + locations.addAll(indexLocations);
|
| + }
|
| + return locations;
|
| + }
|
| +}
|
| +
|
| +/**
|
| + * Helper for requesting information from a single [PackageIndex].
|
| + */
|
| +class _PackageIndexRequester {
|
| + final PackageIndex index;
|
| +
|
| + _PackageIndexRequester(this.index);
|
|
|
| /**
|
| - * Initializes a newly created location to be relative to the given
|
| - * [indexable] object at the given [offset] with the given [length].
|
| + * Return the [element]'s identifier in the [index] or `-1` if the
|
| + * [element] is not referenced in the [index].
|
| */
|
| - LocationImpl(this.indexable, this.offset, this.length,
|
| - {bool isQualified: false, bool isResolved: true}) {
|
| - if (indexable == null) {
|
| - throw new ArgumentError("indexable object cannot be null");
|
| + int findElementId(Element element) {
|
| + // Find the id of the element's unit.
|
| + int unitId = getUnitId(element);
|
| + if (unitId == -1) {
|
| + return -1;
|
| }
|
| - _flags = 0;
|
| - if (isQualified) {
|
| - _flags |= _FLAG_QUALIFIED;
|
| + // Prepare information about the element.
|
| + ElementInfo info = PackageIndexAssembler.newElementInfo(unitId, element);
|
| + // Find the first occurrence of an element with the same offset.
|
| + int elementId = _findFirstOccurrence(index.elementOffsets, info.offset);
|
| + if (elementId == -1) {
|
| + return -1;
|
| }
|
| - if (isResolved) {
|
| - _flags |= _FLAG_RESOLVED;
|
| + // Try to find the element id using offset, unit and kind.
|
| + for (;
|
| + elementId < index.elementOffsets.length &&
|
| + index.elementOffsets[elementId] == info.offset;
|
| + elementId++) {
|
| + if (index.elementUnits[elementId] == unitId &&
|
| + index.elementKinds[elementId] == info.kind) {
|
| + return elementId;
|
| + }
|
| }
|
| + return -1;
|
| }
|
|
|
| /**
|
| - * The element containing this location.
|
| + * Complete with a list of locations where elements of the given [kind] with
|
| + * names satisfying the given [regExp] are defined.
|
| */
|
| - @deprecated
|
| - Element get element {
|
| - if (indexable is IndexableElement) {
|
| - return (indexable as IndexableElement).element;
|
| + List<Location> getDefinedNames(
|
| + AnalysisContext context, RegExp regExp, IndexNameKind kind) {
|
| + List<Location> locations = <Location>[];
|
| + for (UnitIndex unitIndex in index.units) {
|
| + _UnitIndexRequester requester = new _UnitIndexRequester(this, unitIndex);
|
| + List<Location> unitLocations =
|
| + requester.getDefinedNames(context, regExp, kind);
|
| + locations.addAll(unitLocations);
|
| }
|
| - return null;
|
| + return locations;
|
| }
|
|
|
| - @override
|
| - bool get isQualified => (_flags & _FLAG_QUALIFIED) != 0;
|
| -
|
| - @override
|
| - bool get isResolved => (_flags & _FLAG_RESOLVED) != 0;
|
| -
|
| - @override
|
| - String toString() {
|
| - String flagsStr = '';
|
| - if (isQualified) {
|
| - flagsStr += ' qualified';
|
| + /**
|
| + * Complete with a list of locations where the given [element] has relation
|
| + * of the given [kind].
|
| + */
|
| + List<Location> getRelations(
|
| + AnalysisContext context, Element element, IndexRelationKind kind) {
|
| + int elementId = findElementId(element);
|
| + if (elementId == -1) {
|
| + return const <Location>[];
|
| }
|
| - if (isResolved) {
|
| - flagsStr += ' resolved';
|
| + List<Location> locations = <Location>[];
|
| + for (UnitIndex unitIndex in index.units) {
|
| + _UnitIndexRequester requester = new _UnitIndexRequester(this, unitIndex);
|
| + List<Location> unitLocations =
|
| + requester.getRelations(context, elementId, kind);
|
| + locations.addAll(unitLocations);
|
| }
|
| - return '[$offset - ${offset + length}) $flagsStr in $indexable';
|
| + return locations;
|
| }
|
| -}
|
| -
|
| -/**
|
| - * A [LocationImpl] with attached data.
|
| - */
|
| -class LocationWithData<D> extends LocationImpl {
|
| - final D data;
|
|
|
| - LocationWithData(LocationImpl location, this.data)
|
| - : super(location.indexable, location.offset, location.length);
|
| -}
|
| + /**
|
| + * Return the identifier of [str] in the [index] or `-1` if [str] is not used
|
| + * in the [index].
|
| + */
|
| + int getStringId(String str) {
|
| + return binarySearch(index.strings, str);
|
| + }
|
|
|
| -/**
|
| - * Relationship between an element and a location. Relationships are identified
|
| - * by a globally unique identifier.
|
| - */
|
| -class RelationshipImpl implements Relationship {
|
| /**
|
| - * A table mapping relationship identifiers to relationships.
|
| + * Return the identifier of the [CompilationUnitElement] containing the
|
| + * [element] in the [index] or `-1` if not found.
|
| */
|
| - static Map<String, RelationshipImpl> _RELATIONSHIP_MAP = {};
|
| + int getUnitId(Element element) {
|
| + CompilationUnitElement unitElement =
|
| + PackageIndexAssembler.getUnitElement(element);
|
| + int libraryUriId = getUriId(unitElement.library.source.uri);
|
| + if (libraryUriId == -1) {
|
| + return -1;
|
| + }
|
| + int unitUriId = getUriId(unitElement.source.uri);
|
| + if (unitUriId == -1) {
|
| + return -1;
|
| + }
|
| + for (int i = 0; i < index.unitLibraryUris.length; i++) {
|
| + if (index.unitLibraryUris[i] == libraryUriId &&
|
| + index.unitUnitUris[i] == unitUriId) {
|
| + return i;
|
| + }
|
| + }
|
| + return -1;
|
| + }
|
|
|
| /**
|
| - * The next artificial hash code.
|
| + * Return the URI of the library source of the library specific [unit].
|
| */
|
| - static int _NEXT_HASH_CODE = 0;
|
| + String getUnitLibraryUri(int unit) {
|
| + int id = index.unitLibraryUris[unit];
|
| + return index.strings[id];
|
| + }
|
|
|
| /**
|
| - * The artificial hash code for this object.
|
| + * Return the URI of the unit source of the library specific [unit].
|
| */
|
| - final int _hashCode = _NEXT_HASH_CODE++;
|
| + String getUnitUnitUri(int unit) {
|
| + int id = index.unitUnitUris[unit];
|
| + return index.strings[id];
|
| + }
|
|
|
| /**
|
| - * The unique identifier for this relationship.
|
| + * Complete with a list of locations where a class members with the given
|
| + * [name] is referenced with a qualifier, but is not resolved.
|
| */
|
| - final String identifier;
|
| + List<Location> getUnresolvedMemberReferences(
|
| + AnalysisContext context, String name) {
|
| + List<Location> locations = <Location>[];
|
| + for (UnitIndex unitIndex in index.units) {
|
| + _UnitIndexRequester requester = new _UnitIndexRequester(this, unitIndex);
|
| + List<Location> unitLocations =
|
| + requester.getUnresolvedMemberReferences(context, name);
|
| + locations.addAll(unitLocations);
|
| + }
|
| + return locations;
|
| + }
|
|
|
| /**
|
| - * Initialize a newly created relationship with the given unique identifier.
|
| + * Return the identifier of the [uri] in the [index] or `-1` if the [uri] is
|
| + * not used in the [index].
|
| */
|
| - RelationshipImpl(this.identifier);
|
| + int getUriId(Uri uri) {
|
| + String str = uri.toString();
|
| + return getStringId(str);
|
| + }
|
| +}
|
|
|
| - @override
|
| - int get hashCode => _hashCode;
|
| +/**
|
| + * Helper for requesting information from a single [UnitIndex].
|
| + */
|
| +class _UnitIndexRequester {
|
| + final _PackageIndexRequester packageRequester;
|
| + final UnitIndex unitIndex;
|
| +
|
| + _UnitIndexRequester(this.packageRequester, this.unitIndex);
|
| +
|
| + /**
|
| + * Complete with a list of locations where elements of the given [kind] with
|
| + * names satisfying the given [regExp] are defined.
|
| + */
|
| + List<Location> getDefinedNames(
|
| + AnalysisContext context, RegExp regExp, IndexNameKind kind) {
|
| + List<Location> locations = <Location>[];
|
| + String unitLibraryUri = null;
|
| + String unitUnitUri = null;
|
| + for (int i = 0; i < unitIndex.definedNames.length; i++) {
|
| + if (unitIndex.definedNameKinds[i] == kind) {
|
| + int nameIndex = unitIndex.definedNames[i];
|
| + String name = packageRequester.index.strings[nameIndex];
|
| + if (regExp.matchAsPrefix(name) != null) {
|
| + unitLibraryUri ??= packageRequester.getUnitLibraryUri(unitIndex.unit);
|
| + unitUnitUri ??= packageRequester.getUnitUnitUri(unitIndex.unit);
|
| + locations.add(new Location(context, unitLibraryUri, unitUnitUri, null,
|
| + unitIndex.definedNameOffsets[i], name.length, false, true));
|
| + }
|
| + }
|
| + }
|
| + return locations;
|
| + }
|
|
|
| - @override
|
| - String toString() => identifier;
|
| + /**
|
| + * Return a list of locations where an element with the given [elementId] has
|
| + * relation of the given [kind].
|
| + */
|
| + List<Location> getRelations(
|
| + AnalysisContext context, int elementId, IndexRelationKind kind) {
|
| + // Find the first usage of the element.
|
| + int i = _findFirstOccurrence(unitIndex.usedElements, elementId);
|
| + if (i == -1) {
|
| + return const <Location>[];
|
| + }
|
| + // 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(
|
| + context,
|
| + unitLibraryUri,
|
| + unitUnitUri,
|
| + kind,
|
| + unitIndex.usedElementOffsets[i],
|
| + unitIndex.usedElementLengths[i],
|
| + unitIndex.usedElementIsQualifiedFlags[i],
|
| + true));
|
| + }
|
| + }
|
| + return locations;
|
| + }
|
|
|
| /**
|
| - * Returns the relationship with the given unique [identifier].
|
| + * Complete with a list of locations where a class members with the given
|
| + * [name] is referenced with a qualifier, but is not resolved.
|
| */
|
| - static RelationshipImpl getRelationship(String identifier) {
|
| - RelationshipImpl relationship = _RELATIONSHIP_MAP[identifier];
|
| - if (relationship == null) {
|
| - relationship = new RelationshipImpl(identifier);
|
| - _RELATIONSHIP_MAP[identifier] = relationship;
|
| + List<Location> getUnresolvedMemberReferences(
|
| + AnalysisContext context, String name) {
|
| + // Find the name ID in the package index.
|
| + int nameId = packageRequester.getStringId(name);
|
| + if (nameId == -1) {
|
| + return const <Location>[];
|
| + }
|
| + // Find the first usage of the name.
|
| + int i = _findFirstOccurrence(unitIndex.usedNames, nameId);
|
| + if (i == -1) {
|
| + return const <Location>[];
|
| + }
|
| + // Create locations for every usage of the name.
|
| + List<Location> locations = <Location>[];
|
| + String unitLibraryUri = null;
|
| + String unitUnitUri = null;
|
| + for (;
|
| + i < unitIndex.usedNames.length && unitIndex.usedNames[i] == nameId;
|
| + i++) {
|
| + unitLibraryUri ??= packageRequester.getUnitLibraryUri(unitIndex.unit);
|
| + unitUnitUri ??= packageRequester.getUnitUnitUri(unitIndex.unit);
|
| + locations.add(new Location(
|
| + context,
|
| + unitLibraryUri,
|
| + unitUnitUri,
|
| + unitIndex.usedNameKinds[i],
|
| + unitIndex.usedNameOffsets[i],
|
| + name.length,
|
| + unitIndex.usedNameIsQualifiedFlags[i],
|
| + false));
|
| }
|
| - return relationship;
|
| + return locations;
|
| }
|
| }
|
|
|