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

Unified Diff: pkg/analyzer/lib/src/dart/analysis/index.dart

Issue 2519733002: Add CompilationUnit indexer implementation. (Closed)
Patch Set: Created 4 years, 1 month 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/analyzer/lib/src/dart/analysis/index.dart
diff --git a/pkg/analyzer/lib/src/dart/analysis/index.dart b/pkg/analyzer/lib/src/dart/analysis/index.dart
new file mode 100644
index 0000000000000000000000000000000000000000..282b4e3bb9d4f64225f9098f85289b14f0274777
--- /dev/null
+++ b/pkg/analyzer/lib/src/dart/analysis/index.dart
@@ -0,0 +1,795 @@
+// 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 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/token.dart';
+import 'package:analyzer/dart/ast/visitor.dart';
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/src/dart/element/member.dart';
+import 'package:analyzer/src/generated/utilities_dart.dart';
+import 'package:analyzer/src/summary/format.dart'
+ show AnalysisDriverUnitIndexBuilder;
+import 'package:analyzer/src/summary/idl.dart';
+
+/**
+ * Return the [CompilationUnitElement] that should be used for [element].
+ * Throw [StateError] if the [element] is not linked into a unit.
+ */
+CompilationUnitElement getUnitElement(Element element) {
+ for (Element e = element; e != null; e = e.enclosingElement) {
+ if (e is CompilationUnitElement) {
+ return e;
+ }
+ if (e is LibraryElement) {
+ return e.definingCompilationUnit;
+ }
+ }
+ throw new StateError(element.toString());
Brian Wilkerson 2016/11/21 15:48:27 Perhaps a more informative message, such as 'Eleme
+}
+
+/**
+ * Index the [unit] into a new [AnalysisDriverUnitIndexBuilder].
+ */
+AnalysisDriverUnitIndexBuilder indexUnit(CompilationUnit unit) {
+ return new _IndexAssembler().assemble(unit);
+}
+
+/**
+ * Information about an element that is actually put into index for some other
+ * related element. For example for a synthetic getter this is the corresponding
+ * non-synthetic field and [IndexSyntheticElementKind.getter] as the [kind].
+ */
+class IndexElementInfo {
+ final Element element;
+ final IndexSyntheticElementKind kind;
+
+ factory IndexElementInfo(Element element) {
+ IndexSyntheticElementKind kind = IndexSyntheticElementKind.notSynthetic;
+ if (element is LibraryElement || element is CompilationUnitElement) {
+ kind = IndexSyntheticElementKind.unit;
+ } else if (element.isSynthetic) {
+ if (element is ConstructorElement) {
Paul Berry 2016/11/21 13:46:57 All these "is" checks look expensive. Why not swi
scheglov 2016/11/21 17:27:29 Done.
+ kind = IndexSyntheticElementKind.constructor;
+ element = element.enclosingElement;
+ } else if (element is FunctionElement && element.name == 'loadLibrary') {
+ kind = IndexSyntheticElementKind.loadLibrary;
+ element = element.library;
+ } else if (element is FieldElement) {
+ FieldElement field = element;
+ kind = IndexSyntheticElementKind.field;
+ element = field.getter;
Paul Berry 2016/11/21 13:46:57 Nit: IMO `element = field.getter ?? field.setter;`
scheglov 2016/11/21 17:27:29 Done.
+ element ??= field.setter;
+ } else if (element is PropertyAccessorElement) {
+ PropertyAccessorElement accessor = element;
+ Element enclosing = element.enclosingElement;
+ bool isEnumGetter = enclosing is ClassElement && enclosing.isEnum;
+ if (isEnumGetter && accessor.name == 'index') {
+ kind = IndexSyntheticElementKind.enumIndex;
+ element = enclosing;
+ } else if (isEnumGetter && accessor.name == 'values') {
+ kind = IndexSyntheticElementKind.enumValues;
+ element = enclosing;
+ } else {
+ kind = accessor.isGetter
+ ? IndexSyntheticElementKind.getter
+ : IndexSyntheticElementKind.setter;
+ element = accessor.variable;
+ }
+ } else if (element is TopLevelVariableElement) {
+ TopLevelVariableElement property = element;
+ kind = IndexSyntheticElementKind.topLevelVariable;
+ element = property.getter;
Paul Berry 2016/11/21 13:46:57 Ditto
scheglov 2016/11/21 17:27:30 Done.
+ element ??= property.setter;
+ } else {
+ throw new ArgumentError(
+ 'Unsupported synthetic element ${element.runtimeType}');
+ }
+ }
+ return new IndexElementInfo._(element, kind);
+ }
+
+ IndexElementInfo._(this.element, this.kind);
+}
+
+/**
+ * Information about an element referenced in index.
+ */
+class _ElementInfo {
+ /**
+ * The identifier of the [CompilationUnitElement] containing this element.
+ */
+ final int unitId;
+
+ /**
+ * The identifier of the top-level name, or `null` if the element is a
+ * reference to the unit.
+ */
+ final _StringInfo nameIdUnitMember;
+
+ /**
+ * The identifier of the class member name, or `null` if the element is not a
+ * class member or a named parameter of a class member.
+ */
+ final _StringInfo nameIdClassMember;
+
+ /**
+ * The identifier of the named parameter name, or `null` if the element is not
+ * a named parameter.
+ */
+ final _StringInfo nameIdParameter;
+
+ /**
+ * The kind of the element.
+ */
+ final IndexSyntheticElementKind kind;
+
+ /**
+ * The unique id of the element. It is set after indexing of the whole
+ * package is done and we are assembling the full package index.
+ */
+ int id;
+
+ _ElementInfo(this.unitId, this.nameIdUnitMember, this.nameIdClassMember,
+ this.nameIdParameter, this.kind);
+}
+
+/**
+ * Information about a single relation in a single compilation unit.
+ */
+class _ElementRelationInfo {
+ final _ElementInfo elementInfo;
+ final IndexRelationKind kind;
+ final int offset;
+ final int length;
+ final bool isQualified;
Brian Wilkerson 2016/11/21 15:48:27 Perhaps document what these fields mean? It's not
+
+ _ElementRelationInfo(
+ this.elementInfo, this.kind, this.offset, this.length, this.isQualified);
+}
+
+/**
+ * Assembler of a single [CompilationUnit] index.
+ *
+ * The intended usage sequence:
+ *
+ * - Call [addElementRelation] for each element relation found in the unit.
+ * - Call [addNameRelation] for each name relation found in the unit.
+ * - Assign ids to all the [_ElementInfo] in [elementRelations].
+ * - Call [assemble] to produce the final unit index.
+ */
+class _IndexAssembler {
+ /**
+ * The string to use place of the `null` string.
Brian Wilkerson 2016/11/21 15:48:27 "place" --> "in place"
scheglov 2016/11/21 17:27:30 Done.
+ */
+ static const NULL_STRING = '--nullString--';
+
+ /**
+ * Map associating referenced elements with their [_ElementInfo]s.
+ */
+ final Map<Element, _ElementInfo> elementMap = {};
+
+ /**
+ * Map associating [CompilationUnitElement]s with their identifiers, which
+ * are indices into [unitLibraryUris] and [unitUnitUris].
+ */
+ final Map<CompilationUnitElement, int> unitMap = {};
+
+ /**
+ * Each item of this list corresponds to the library URI of a unique
+ * [CompilationUnitElement].
+ */
+ final List<_StringInfo> unitLibraryUris = [];
+
+ /**
+ * Each item of this list corresponds to the unit URI of a unique
+ * [CompilationUnitElement].
+ */
+ final List<_StringInfo> unitUnitUris = [];
Brian Wilkerson 2016/11/21 15:48:27 Perhaps we could drop one of the "unit"s from this
scheglov 2016/11/21 17:27:30 Done.
+
+ /**
+ * Map associating strings with their [_StringInfo]s.
+ */
+ final Map<String, _StringInfo> stringMap = {};
+
+ /**
+ * All element relations.
+ */
+ final List<_ElementRelationInfo> elementRelations = [];
+
+ /**
+ * All unresolved name relations.
+ */
+ final List<_NameRelationInfo> nameRelations = [];
+
+ /**
+ * The [_StringInfo] to use for `null` strings.
+ */
+ _StringInfo nullString;
+
+ _IndexAssembler() {
+ nullString = _getStringInfo(NULL_STRING);
+ }
+
+ void addElementRelation(Element element, IndexRelationKind kind, int offset,
+ int length, bool isQualified) {
+ try {
+ _ElementInfo elementInfo = _getElementInfo(element);
+ elementRelations.add(new _ElementRelationInfo(
+ elementInfo, kind, offset, length, isQualified));
+ } on StateError {}
Paul Berry 2016/11/21 13:46:57 This seems like it would cover up bugs. Why is th
scheglov 2016/11/21 17:27:30 Removed.
+ }
+
+ void addNameRelation(
+ String name, IndexRelationKind kind, int offset, bool isQualified) {
+ _StringInfo nameId = _getStringInfo(name);
+ nameRelations.add(new _NameRelationInfo(nameId, kind, offset, isQualified));
+ }
+
+ /**
+ * Index the [unit] and assemble a new [AnalysisDriverUnitIndexBuilder].
+ */
+ AnalysisDriverUnitIndexBuilder assemble(CompilationUnit unit) {
+ unit.accept(new _IndexContributor(this));
+ // sort strings end set IDs
+ List<_StringInfo> stringInfoList = stringMap.values.toList();
+ stringInfoList.sort((a, b) {
+ return a.value.compareTo(b.value);
+ });
+ for (int i = 0; i < stringInfoList.length; i++) {
+ stringInfoList[i].id = i;
+ }
+ // sort elements and set IDs
+ List<_ElementInfo> elementInfoList = elementMap.values.toList();
+ elementInfoList.sort((a, b) {
+ int delta;
+ delta = a.nameIdUnitMember.id - b.nameIdUnitMember.id;
+ if (delta != null) {
+ return delta;
+ }
+ delta = a.nameIdClassMember.id - b.nameIdClassMember.id;
+ if (delta != null) {
+ return delta;
+ }
+ return a.nameIdParameter.id - b.nameIdParameter.id;
+ });
+ for (int i = 0; i < elementInfoList.length; i++) {
+ elementInfoList[i].id = i;
+ }
+ // Sort element and name relations.
+ elementRelations.sort((a, b) {
+ return a.elementInfo.id - b.elementInfo.id;
+ });
+ nameRelations.sort((a, b) {
+ return a.nameInfo.id - b.nameInfo.id;
+ });
+ return new AnalysisDriverUnitIndexBuilder(
+ strings: stringInfoList.map((s) => s.value).toList(),
+ nullStringId: nullString.id,
+ unitLibraryUris: unitLibraryUris.map((s) => s.id).toList(),
+ unitUnitUris: unitUnitUris.map((s) => s.id).toList(),
+ elementKinds: elementInfoList.map((e) => e.kind).toList(),
+ elementUnits: elementInfoList.map((e) => e.unitId).toList(),
+ elementNameUnitMemberIds:
+ elementInfoList.map((e) => e.nameIdUnitMember.id).toList(),
+ elementNameClassMemberIds:
+ elementInfoList.map((e) => e.nameIdClassMember.id).toList(),
+ elementNameParameterIds:
+ elementInfoList.map((e) => e.nameIdParameter.id).toList(),
+ usedElements: elementRelations.map((r) => r.elementInfo.id).toList(),
+ usedElementKinds: elementRelations.map((r) => r.kind).toList(),
+ usedElementOffsets: elementRelations.map((r) => r.offset).toList(),
+ usedElementLengths: elementRelations.map((r) => r.length).toList(),
+ usedElementIsQualifiedFlags:
+ elementRelations.map((r) => r.isQualified).toList(),
+ usedNames: nameRelations.map((r) => r.nameInfo.id).toList(),
+ usedNameKinds: nameRelations.map((r) => r.kind).toList(),
+ usedNameOffsets: nameRelations.map((r) => r.offset).toList(),
+ usedNameIsQualifiedFlags:
+ nameRelations.map((r) => r.isQualified).toList());
+ }
+
+ /**
+ * Return the unique [_ElementInfo] corresponding the [element]. The field
+ * [_ElementInfo.id] is filled by [assemble] during final sorting.
+ */
+ _ElementInfo _getElementInfo(Element element) {
+ if (element is Member) {
+ element = (element as Member).baseElement;
+ }
+ return elementMap.putIfAbsent(element, () {
+ CompilationUnitElement unitElement = getUnitElement(element);
+ int unitId = _getUnitId(unitElement);
+ return _newElementInfo(unitId, element);
+ });
+ }
+
+ /**
+ * Return the unique [_StringInfo] corresponding the [str]. The field
+ * [_StringInfo.id] is filled by [assemble] during final sorting.
+ */
+ _StringInfo _getStringInfo(String str) {
Brian Wilkerson 2016/11/21 15:48:27 "str" --> "string"
scheglov 2016/11/21 17:27:30 Done.
+ return stringMap.putIfAbsent(str, () {
+ return new _StringInfo(str);
+ });
+ }
+
+ /**
+ * Add information about [unitElement] to [unitUnitUris] and
+ * [unitLibraryUris] if necessary, and return the location in those
+ * arrays representing [unitElement].
+ */
+ int _getUnitId(CompilationUnitElement unitElement) {
+ return unitMap.putIfAbsent(unitElement, () {
+ assert(unitLibraryUris.length == unitUnitUris.length);
+ int id = unitUnitUris.length;
+ unitLibraryUris.add(_getUriInfo(unitElement.library.source.uri));
+ unitUnitUris.add(_getUriInfo(unitElement.source.uri));
+ return id;
+ });
+ }
+
+ /**
+ * Return the unique [_StringInfo] corresponding [uri]. The field
+ * [_StringInfo.id] is filled by [assemble] during final sorting.
+ */
+ _StringInfo _getUriInfo(Uri uri) {
+ String str = uri.toString();
+ return _getStringInfo(str);
+ }
+
+ /**
+ * Return a new [_ElementInfo] for the given [element] in the given [unitId].
+ * This method is static, so it cannot add any information to the index.
+ */
+ _ElementInfo _newElementInfo(int unitId, Element element) {
+ IndexElementInfo info = new IndexElementInfo(element);
+ element = info.element;
+ // Prepare name identifiers.
+ _StringInfo nameIdParameter = nullString;
+ _StringInfo nameIdClassMember = nullString;
+ _StringInfo nameIdUnitMember = nullString;
+ if (element is ParameterElement) {
+ nameIdParameter = _getStringInfo(element.name);
+ element = element.enclosingElement;
+ }
+ if (element?.enclosingElement is ClassElement) {
+ nameIdClassMember = _getStringInfo(element.name);
+ element = element.enclosingElement;
+ }
+ if (element?.enclosingElement is CompilationUnitElement) {
+ nameIdUnitMember = _getStringInfo(element.name);
+ }
+ return new _ElementInfo(unitId, nameIdUnitMember, nameIdClassMember,
+ nameIdParameter, info.kind);
+ }
+}
+
+/**
+ * Visits a resolved AST and adds relationships into the [assembler].
+ */
+class _IndexContributor extends GeneralizingAstVisitor {
+ final _IndexAssembler assembler;
+
+ _IndexContributor(this.assembler);
+
+ void recordIsAncestorOf(Element descendant) {
+ _recordIsAncestorOf(descendant, descendant, false, <ClassElement>[]);
+ }
+
+ /**
+ * Record that the name [node] has a relation of the given [kind].
+ */
+ void recordNameRelation(
+ SimpleIdentifier node, IndexRelationKind kind, bool isQualified) {
+ if (node != null) {
+ assembler.addNameRelation(node.name, kind, node.offset, isQualified);
+ }
+ }
+
+ /**
+ * Record reference to the given operator [Element].
+ */
+ void recordOperatorReference(Token operator, Element element) {
+ recordRelationToken(element, IndexRelationKind.IS_INVOKED_BY, operator);
+ }
+
+ /**
+ * Record that [element] has a relation of the given [kind] at the location
+ * of the given [node]. The flag [isQualified] is `true` if [node] has an
+ * explicit or implicit qualifier, so cannot be shadowed by a local
+ * declaration.
+ */
+ void recordRelation(
+ Element element, IndexRelationKind kind, AstNode node, bool isQualified) {
+ if (element != null && node != null) {
+ recordRelationOffset(
+ element, kind, node.offset, node.length, isQualified);
+ }
+ }
+
+ /**
+ * Record that [element] has a relation of the given [kind] at the given
+ * [offset] and [length]. The flag [isQualified] is `true` if the relation
+ * has an explicit or implicit qualifier, so [element] cannot be shadowed by
+ * a local declaration.
+ */
+ void recordRelationOffset(Element element, IndexRelationKind kind, int offset,
+ int length, bool isQualified) {
+ // Ignore elements that can't be referenced outside of the unit.
+ ElementKind elementKind = element?.kind;
+ if (elementKind == null ||
+ elementKind == ElementKind.DYNAMIC ||
+ elementKind == ElementKind.LABEL ||
+ elementKind == ElementKind.LOCAL_VARIABLE ||
+ elementKind == ElementKind.PREFIX ||
+ elementKind == ElementKind.TYPE_PARAMETER ||
+ elementKind == ElementKind.FUNCTION &&
+ element is FunctionElement &&
+ element.enclosingElement is ExecutableElement ||
+ elementKind == ElementKind.PARAMETER &&
+ element is ParameterElement &&
+ element.parameterKind != ParameterKind.NAMED ||
+ false) {
+ return;
+ }
+ // Add the relation.
+ assembler.addElementRelation(element, kind, offset, length, isQualified);
+ }
+
+ /**
+ * Record that [element] has a relation of the given [kind] at the location
+ * of the given [token].
+ */
+ void recordRelationToken(
+ Element element, IndexRelationKind kind, Token token) {
+ if (element != null && token != null) {
+ recordRelationOffset(element, kind, token.offset, token.length, true);
+ }
+ }
+
+ /**
+ * Record a relation between a super [typeName] and its [Element].
+ */
+ void recordSuperType(TypeName typeName, IndexRelationKind kind) {
Brian Wilkerson 2016/11/21 15:48:27 Document 'kind'.
+ Identifier name = typeName?.name;
+ if (name != null) {
+ Element element = name.staticElement;
+ bool isQualified;
+ SimpleIdentifier relNode;
+ if (name is PrefixedIdentifier) {
+ isQualified = true;
+ relNode = name.identifier;
+ } else {
+ isQualified = false;
+ relNode = name;
+ }
+ recordRelation(element, kind, relNode, isQualified);
+ recordRelation(
+ element, IndexRelationKind.IS_REFERENCED_BY, relNode, isQualified);
+ typeName.typeArguments?.accept(this);
+ }
+ }
+
+ void recordUriReference(Element element, UriBasedDirective directive) {
+ recordRelation(
+ element, IndexRelationKind.IS_REFERENCED_BY, directive.uri, true);
+ }
+
+ @override
+ visitAssignmentExpression(AssignmentExpression node) {
+ recordOperatorReference(node.operator, node.bestElement);
+ super.visitAssignmentExpression(node);
+ }
+
+ @override
+ visitBinaryExpression(BinaryExpression node) {
+ recordOperatorReference(node.operator, node.bestElement);
+ super.visitBinaryExpression(node);
+ }
+
+ @override
+ visitClassDeclaration(ClassDeclaration node) {
+ if (node.extendsClause == null) {
+ ClassElement objectElement = node.element.supertype?.element;
+ recordRelationOffset(objectElement, IndexRelationKind.IS_EXTENDED_BY,
+ node.name.offset, 0, true);
+ }
+ recordIsAncestorOf(node.element);
+ super.visitClassDeclaration(node);
+ }
+
+ @override
+ visitClassTypeAlias(ClassTypeAlias node) {
+ recordIsAncestorOf(node.element);
+ super.visitClassTypeAlias(node);
+ }
+
+ @override
+ visitConstructorFieldInitializer(ConstructorFieldInitializer node) {
+ SimpleIdentifier fieldName = node.fieldName;
+ if (fieldName != null) {
+ Element element = fieldName.staticElement;
+ recordRelation(element, IndexRelationKind.IS_WRITTEN_BY, fieldName, true);
+ }
+ node.expression?.accept(this);
+ }
+
+ @override
+ visitConstructorName(ConstructorName node) {
+ ConstructorElement element = node.staticElement;
+ element = _getActualConstructorElement(element);
+ // record relation
+ if (node.name != null) {
+ int offset = node.period.offset;
+ int length = node.name.end - offset;
+ recordRelationOffset(
+ element, IndexRelationKind.IS_REFERENCED_BY, offset, length, true);
+ } else {
+ int offset = node.type.end;
+ recordRelationOffset(
+ element, IndexRelationKind.IS_REFERENCED_BY, offset, 0, true);
+ }
+ node.type.accept(this);
+ }
+
+ @override
+ visitExportDirective(ExportDirective node) {
+ ExportElement element = node.element;
+ recordUriReference(element?.exportedLibrary, node);
+ super.visitExportDirective(node);
+ }
+
+ @override
+ visitExtendsClause(ExtendsClause node) {
+ recordSuperType(node.superclass, IndexRelationKind.IS_EXTENDED_BY);
+ }
+
+ @override
+ visitImplementsClause(ImplementsClause node) {
+ for (TypeName typeName in node.interfaces) {
+ recordSuperType(typeName, IndexRelationKind.IS_IMPLEMENTED_BY);
+ }
+ }
+
+ @override
+ visitImportDirective(ImportDirective node) {
+ ImportElement element = node.element;
+ recordUriReference(element?.importedLibrary, node);
+ super.visitImportDirective(node);
+ }
+
+ @override
+ visitIndexExpression(IndexExpression node) {
+ MethodElement element = node.bestElement;
+ if (element is MethodElement) {
+ Token operator = node.leftBracket;
+ recordRelationToken(element, IndexRelationKind.IS_INVOKED_BY, operator);
+ }
+ super.visitIndexExpression(node);
+ }
+
+ @override
+ visitLibraryIdentifier(LibraryIdentifier node) {}
+
+ @override
+ visitMethodInvocation(MethodInvocation node) {
+ SimpleIdentifier name = node.methodName;
+ Element element = name.bestElement;
+ // unresolved name invocation
+ bool isQualified = node.realTarget != null;
+ if (element == null) {
+ recordNameRelation(name, IndexRelationKind.IS_INVOKED_BY, isQualified);
+ }
+ // element invocation
+ IndexRelationKind kind = element is ClassElement
+ ? IndexRelationKind.IS_REFERENCED_BY
+ : IndexRelationKind.IS_INVOKED_BY;
+ recordRelation(element, kind, name, isQualified);
+ node.target?.accept(this);
+ node.argumentList?.accept(this);
+ }
+
+ @override
+ visitPartDirective(PartDirective node) {
+ Element element = node.element;
+ recordUriReference(element, node);
+ super.visitPartDirective(node);
+ }
+
+ @override
+ visitPostfixExpression(PostfixExpression node) {
+ recordOperatorReference(node.operator, node.bestElement);
+ super.visitPostfixExpression(node);
+ }
+
+ @override
+ visitPrefixExpression(PrefixExpression node) {
+ recordOperatorReference(node.operator, node.bestElement);
+ super.visitPrefixExpression(node);
+ }
+
+ @override
+ visitRedirectingConstructorInvocation(RedirectingConstructorInvocation node) {
+ ConstructorElement element = node.staticElement;
+ if (node.constructorName != null) {
+ int offset = node.period.offset;
+ int length = node.constructorName.end - offset;
+ recordRelationOffset(
+ element, IndexRelationKind.IS_REFERENCED_BY, offset, length, true);
+ } else {
+ int offset = node.thisKeyword.end;
+ recordRelationOffset(
+ element, IndexRelationKind.IS_REFERENCED_BY, offset, 0, true);
+ }
+ super.visitRedirectingConstructorInvocation(node);
+ }
+
+ @override
+ visitSimpleIdentifier(SimpleIdentifier node) {
+ // name in declaration
+ if (node.inDeclarationContext()) {
+ return;
+ }
+ Element element = node.bestElement;
+ // record unresolved name reference
+ bool isQualified = _isQualified(node);
+ if (element == null) {
+ bool inGetterContext = node.inGetterContext();
+ bool inSetterContext = node.inSetterContext();
+ IndexRelationKind kind;
+ if (inGetterContext && inSetterContext) {
+ kind = IndexRelationKind.IS_READ_WRITTEN_BY;
+ } else if (inGetterContext) {
+ kind = IndexRelationKind.IS_READ_BY;
+ } else {
+ kind = IndexRelationKind.IS_WRITTEN_BY;
+ }
+ recordNameRelation(node, kind, isQualified);
+ }
+ // this.field parameter
+ if (element is FieldFormalParameterElement) {
+ AstNode parent = node.parent;
+ IndexRelationKind kind =
+ parent is FieldFormalParameter && parent.identifier == node
+ ? IndexRelationKind.IS_WRITTEN_BY
+ : IndexRelationKind.IS_REFERENCED_BY;
+ recordRelation(element.field, kind, node, true);
+ return;
+ }
+ // ignore a local reference to a parameter
+ if (element is ParameterElement && node.parent is! Label) {
+ return;
+ }
+ // record specific relations
+ recordRelation(
+ element, IndexRelationKind.IS_REFERENCED_BY, node, isQualified);
+ }
+
+ @override
+ visitSuperConstructorInvocation(SuperConstructorInvocation node) {
+ ConstructorElement element = node.staticElement;
+ if (node.constructorName != null) {
+ int offset = node.period.offset;
+ int length = node.constructorName.end - offset;
+ recordRelationOffset(
+ element, IndexRelationKind.IS_REFERENCED_BY, offset, length, true);
+ } else {
+ int offset = node.superKeyword.end;
+ recordRelationOffset(
+ element, IndexRelationKind.IS_REFERENCED_BY, offset, 0, true);
+ }
+ node.argumentList?.accept(this);
+ }
+
+ @override
+ visitTypeName(TypeName node) {
+ AstNode parent = node.parent;
+ if (parent is ClassTypeAlias && parent.superclass == node) {
+ recordSuperType(node, IndexRelationKind.IS_EXTENDED_BY);
+ } else {
+ super.visitTypeName(node);
+ }
+ }
+
+ @override
+ visitWithClause(WithClause node) {
+ for (TypeName typeName in node.mixinTypes) {
+ recordSuperType(typeName, IndexRelationKind.IS_MIXED_IN_BY);
+ }
+ }
+
+ /**
+ * If the given [constructor] is a synthetic constructor created for a
+ * [ClassTypeAlias], return the actual constructor of a [ClassDeclaration]
+ * which is invoked. Return `null` if a redirection cycle is detected.
+ */
+ ConstructorElement _getActualConstructorElement(
+ ConstructorElement constructor) {
+ Set<ConstructorElement> seenConstructors = new Set<ConstructorElement>();
+ while (constructor != null &&
+ constructor.isSynthetic &&
+ constructor.redirectedConstructor != null) {
+ constructor = constructor.redirectedConstructor;
+ // fail if a cycle is detected
+ if (!seenConstructors.add(constructor)) {
+ return null;
+ }
+ }
+ return constructor;
+ }
+
+ /**
+ * Return `true` if [node] has an explicit or implicit qualifier, so that it
+ * cannot be shadowed by a local declaration.
+ */
+ bool _isQualified(SimpleIdentifier node) {
+ if (node.isQualified) {
+ return true;
+ }
+ AstNode parent = node.parent;
+ return parent is Combinator || parent is Label;
+ }
+
+ void _recordIsAncestorOf(Element descendant, ClassElement ancestor,
+ bool includeThis, List<ClassElement> visitedElements) {
+ if (ancestor == null) {
+ return;
+ }
+ if (visitedElements.contains(ancestor)) {
+ return;
+ }
+ visitedElements.add(ancestor);
+ if (includeThis) {
+ int offset = descendant.nameOffset;
+ int length = descendant.nameLength;
+ assembler.addElementRelation(
+ ancestor, IndexRelationKind.IS_ANCESTOR_OF, offset, length, false);
+ }
+ {
+ InterfaceType superType = ancestor.supertype;
+ if (superType != null) {
+ _recordIsAncestorOf(
+ descendant, superType.element, true, visitedElements);
+ }
+ }
+ for (InterfaceType mixinType in ancestor.mixins) {
+ _recordIsAncestorOf(descendant, mixinType.element, true, visitedElements);
+ }
+ for (InterfaceType implementedType in ancestor.interfaces) {
+ _recordIsAncestorOf(
+ descendant, implementedType.element, true, visitedElements);
+ }
+ }
+}
+
+/**
+ * Information about a single name relation in single compilation unit.
+ */
+class _NameRelationInfo {
+ final _StringInfo nameInfo;
+ final IndexRelationKind kind;
+ final int offset;
+ final bool isQualified;
Brian Wilkerson 2016/11/21 15:48:27 Document these fields.
+
+ _NameRelationInfo(this.nameInfo, this.kind, this.offset, this.isQualified);
+}
+
+/**
+ * Information about a string referenced in the index.
+ */
+class _StringInfo {
+ /**
+ * The value of the string.
+ */
+ final String value;
+
+ /**
+ * The unique id of the string. It is set after indexing of the whole
+ * package is done and we are assembling the full package index.
+ */
+ int id;
+
+ _StringInfo(this.value);
+}
« no previous file with comments | « no previous file | pkg/analyzer/lib/src/summary/format.dart » ('j') | pkg/analyzer/test/src/dart/analysis/index_test.dart » ('J')

Powered by Google App Engine
This is Rietveld 408576698