Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(269)

Unified Diff: pkg/analysis_server/lib/src/services/index/index.dart

Issue 1801883002: Remove old index and search implementations. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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;
}
}

Powered by Google App Engine
This is Rietveld 408576698