Chromium Code Reviews| Index: pkg/analyzer/lib/src/summary/index_unit.dart |
| diff --git a/pkg/analyzer/lib/src/summary/index_unit.dart b/pkg/analyzer/lib/src/summary/index_unit.dart |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..2e842b6de50bb5dd37a90101d783988c3f779de3 |
| --- /dev/null |
| +++ b/pkg/analyzer/lib/src/summary/index_unit.dart |
| @@ -0,0 +1,622 @@ |
| +// 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/generated/utilities_dart.dart'; |
| +import 'package:analyzer/src/summary/format.dart'; |
| +import 'package:analyzer/src/summary/idl.dart'; |
| + |
| +/** |
| + * Object that gathers information about the whole package index and then uses |
| + * it to assemble a new [PackageIndexBuilder]. |
|
Paul Berry
2016/02/25 23:05:13
It would be helpful to have a comment here explain
scheglov
2016/02/26 04:54:03
Done.
|
| + */ |
| +class PackageIndexAssembler { |
| + final Map<Element, _ElementInfo> _elementMap = <Element, _ElementInfo>{}; |
| + |
| + final Map<CompilationUnitElement, int> _elementUnitMap = |
|
Paul Berry
2016/02/25 23:05:12
Please add doc comments for all these fields. I'v
scheglov
2016/02/26 04:54:02
Done.
|
| + <CompilationUnitElement, int>{}; |
| + final List<int> _elementLibraryUris = <int>[]; |
| + final List<int> _elementUnitUris = <int>[]; |
| + |
| + final Map<String, int> _uriMap = <String, int>{}; |
| + final List<String> _uris = <String>[]; |
| + |
| + final List<_UnitIndexAssembler> _units = <_UnitIndexAssembler>[]; |
| + |
| + PackageIndexAssembler(); |
| + |
| + /** |
| + * Assemble a new [PackageIndexBuilder] using the gathered information. |
|
Paul Berry
2016/02/25 23:05:12
s/using the gathered information/using the informa
scheglov
2016/02/26 04:54:02
Done.
|
| + */ |
| + PackageIndexBuilder assemble() { |
| + List<_ElementInfo> elements = _elementMap.values.toList(); |
|
Paul Berry
2016/02/25 23:05:12
Suggestion: rename this to "elementInfos" to avoid
scheglov
2016/02/26 04:54:02
Done.
|
| + elements.sort((a, b) { |
| + return a.offset - b.offset; |
| + }); |
| + for (int i = 0; i < elements.length; i++) { |
| + elements[i].id = i; |
| + } |
| + return new PackageIndexBuilder( |
| + elementLibraryUris: _elementLibraryUris, |
| + elementUnitUris: _elementUnitUris, |
| + elementUnits: elements.map((e) => e.unitId).toList(), |
| + elementOffsets: elements.map((e) => e.offset).toList(), |
| + uris: _uris, |
| + units: _units.map((unit) => unit.assemble()).toList()); |
| + } |
| + |
| + /** |
| + * Index the given fully resolved [unit]. |
| + */ |
| + void index(CompilationUnit unit) { |
| + CompilationUnitElement unitElement = unit.element; |
| + _UnitIndexAssembler assembler = new _UnitIndexAssembler(this, unitElement); |
| + _units.add(assembler); |
| + unit.accept(new _IndexContributor(assembler)); |
| + } |
| + |
| + _ElementInfo _getElementInfo(Element element) { |
| + return _elementMap.putIfAbsent(element, () { |
| + CompilationUnitElement unitElement = getUnitElement(element); |
| + int unitId = _getUnitElementId(unitElement); |
| + return new _ElementInfo(element, unitId); |
| + }); |
| + } |
| + |
| + int _getUnitElementId(CompilationUnitElement element) { |
|
Paul Berry
2016/02/25 23:05:12
Documentation on these private methods would be he
scheglov
2016/02/26 04:54:03
Done.
|
| + return _elementUnitMap.putIfAbsent(element, () { |
| + assert(_elementLibraryUris.length == _elementUnitUris.length); |
| + int id = _elementUnitUris.length; |
| + _elementLibraryUris.add(_getUriId(element.library.source.uri)); |
| + _elementUnitUris.add(_getUriId(element.source.uri)); |
| + return id; |
| + }); |
| + } |
| + |
| + int _getUriId(Uri uri) { |
| + String str = uri.toString(); |
| + return _uriMap.putIfAbsent(str, () { |
| + int id = _uris.length; |
| + _uris.add(str); |
| + return id; |
| + }); |
| + } |
| + |
| + /** |
| + * Return the [CompilationUnitElement] that should be used for [element]. |
| + */ |
| + static CompilationUnitElement getUnitElement(Element element) { |
|
Paul Berry
2016/02/25 23:05:13
It looks like this is only used by other code in t
scheglov
2016/02/26 04:54:03
It is used in tests.
And it also will be used in i
|
| + CompilationUnitElement unitElement; |
| + for (Element e = element; e != null; e = e.enclosingElement) { |
| + if (e is CompilationUnitElement) { |
| + unitElement = e; |
| + break; |
| + } |
| + if (e is LibraryElement) { |
| + unitElement = e.definingCompilationUnit; |
| + break; |
| + } |
| + } |
| + assert(unitElement != null); |
| + return unitElement; |
| + } |
| +} |
| + |
| +/** |
| + * Information about an element referenced in index. |
| + */ |
| +class _ElementInfo { |
| + final Element element; |
|
Paul Berry
2016/02/25 23:05:13
It looks like this is only used by the [offset] ge
scheglov
2016/02/26 04:54:03
Done.
|
| + |
| + /** |
| + * The identifier of the [CompilationUnitElement] containing [element]. |
| + */ |
| + final int unitId; |
| + |
| + /** |
| + * The unique id of the [element] in the [PackageIndex]. It is set after |
| + * after indexing of the whole package is done and we are assembling the |
| + * full package index. |
| + */ |
| + int id; |
| + |
| + _ElementInfo(this.element, this.unitId); |
| + |
| + int get offset => element.nameOffset; |
| +} |
| + |
| +/** |
| + * Visits a resolved AST and adds relationships into [InternalIndexStore]. |
| + */ |
| +class _IndexContributor extends GeneralizingAstVisitor { |
| + final _UnitIndexAssembler assembler; |
| + |
| + _IndexContributor(this.assembler); |
| + |
| + /** |
| + * Record that [element] has a relation of the given [kind] at the location |
| + * of the given [node]. |
| + */ |
| + void recordRelation(Element element, IndexRelationKind kind, AstNode node) { |
| + if (element != null && node != null) { |
| + recordRelationOffset(element, kind, node.offset, node.length); |
| + } |
| + } |
| + |
| + /** |
| + * Record that [element] has a relation of the given [kind] at the given |
| + * [offset] and [length]. |
| + */ |
| + void recordRelationOffset( |
| + Element element, IndexRelationKind kind, int offset, int length) { |
| + // Ignore elements that can't be referenced outside of the unit. |
| + if (element == null || |
| + element is LocalVariableElement || |
| + element is ParameterElement && |
| + element.parameterKind != ParameterKind.NAMED || |
| + element is FunctionElement && |
| + element.enclosingElement is ExecutableElement) { |
| + return; |
| + } |
| + // Add the relation. |
| + assembler.addRelation(element, kind, offset, length); |
| + } |
| + |
| + /** |
| + * 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); |
| + } |
| + } |
| + |
| + @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) { |
| + ClassElement element = node.element; |
| + _recordTopLevelElementDefinition(element); |
| + { |
| + ExtendsClause extendsClause = node.extendsClause; |
| + if (extendsClause != null) { |
| + TypeName superclassNode = extendsClause.superclass; |
| + _recordSuperType(superclassNode, IndexRelationKind.IS_EXTENDED_BY); |
| + } else { |
| + InterfaceType superType = element.supertype; |
| + if (superType != null) { |
| + ClassElement objectElement = superType.element; |
| + recordRelationOffset(objectElement, IndexRelationKind.IS_EXTENDED_BY, |
| + node.name.offset, 0); |
| + } |
| + } |
| + } |
| + { |
| + WithClause withClause = node.withClause; |
| + if (withClause != null) { |
| + for (TypeName mixinNode in withClause.mixinTypes) { |
| + _recordSuperType(mixinNode, IndexRelationKind.IS_MIXED_IN_BY); |
| + } |
| + } |
| + } |
| + { |
| + ImplementsClause implementsClause = node.implementsClause; |
| + if (implementsClause != null) { |
| + for (TypeName interfaceNode in implementsClause.interfaces) { |
| + _recordSuperType(interfaceNode, IndexRelationKind.IS_IMPLEMENTED_BY); |
| + } |
| + } |
| + } |
| + super.visitClassDeclaration(node); |
| + } |
| + |
| + @override |
| + visitClassTypeAlias(ClassTypeAlias node) { |
| + ClassElement element = node.element; |
|
Paul Berry
2016/02/25 23:05:12
There's a lot of common code between this method a
scheglov
2016/02/26 04:54:02
Done.
|
| + _recordTopLevelElementDefinition(element); |
| + { |
| + TypeName superclassNode = node.superclass; |
| + if (superclassNode != null) { |
| + _recordSuperType(superclassNode, IndexRelationKind.IS_EXTENDED_BY); |
| + } |
| + } |
| + { |
| + WithClause withClause = node.withClause; |
| + if (withClause != null) { |
| + for (TypeName mixinNode in withClause.mixinTypes) { |
| + _recordSuperType(mixinNode, IndexRelationKind.IS_MIXED_IN_BY); |
| + } |
| + } |
| + } |
| + { |
| + ImplementsClause implementsClause = node.implementsClause; |
| + if (implementsClause != null) { |
| + for (TypeName interfaceNode in implementsClause.interfaces) { |
| + _recordSuperType(interfaceNode, IndexRelationKind.IS_IMPLEMENTED_BY); |
| + } |
| + } |
| + } |
| + super.visitClassTypeAlias(node); |
| + } |
| + |
| + @override |
| + visitConstructorFieldInitializer(ConstructorFieldInitializer node) { |
| + SimpleIdentifier fieldName = node.fieldName; |
| + Expression expression = node.expression; |
| + // field reference is write here |
|
Paul Berry
2016/02/25 23:05:12
I don't understand this comment. Do you mean "rig
scheglov
2016/02/26 04:54:03
Initially the code was using IndexRelationKind.IS_
|
| + if (fieldName != null) { |
| + Element element = fieldName.staticElement; |
| + recordRelation(element, IndexRelationKind.IS_REFERENCED_BY, fieldName); |
| + } |
| + // index expression |
| + if (expression != null) { |
| + expression.accept(this); |
| + } |
| + } |
| + |
| + @override |
| + visitConstructorName(ConstructorName node) { |
| + ConstructorElement element = node.staticElement; |
| + // in 'class B = A;' actually A constructors are invoked |
| + if (element != null && |
| + element.isSynthetic && |
| + element.redirectedConstructor != null) { |
| + element = element.redirectedConstructor; |
|
Paul Berry
2016/02/25 23:05:13
What if there are multiple levels of indirection?
scheglov
2016/02/26 04:54:03
I will add TODO and test/fix it in the next CL.
|
| + } |
| + // 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); |
| + } else { |
| + int offset = node.type.end; |
| + recordRelationOffset( |
| + element, IndexRelationKind.IS_REFERENCED_BY, offset, 0); |
| + } |
| + super.visitConstructorName(node); |
| + } |
| + |
| + @override |
| + visitEnumDeclaration(EnumDeclaration node) { |
| + ClassElement element = node.element; |
| + _recordTopLevelElementDefinition(element); |
| + super.visitEnumDeclaration(node); |
| + } |
| + |
| + @override |
| + visitExportDirective(ExportDirective node) { |
| + ExportElement element = node.element; |
| + if (element != null) { |
| + LibraryElement expLibrary = element.exportedLibrary; |
| + _recordLibraryReference(node, expLibrary); |
| + } |
| + _recordUriFileReference(node); |
| + super.visitExportDirective(node); |
| + } |
| + |
| + @override |
| + visitFunctionDeclaration(FunctionDeclaration node) { |
| + Element element = node.element; |
| + _recordTopLevelElementDefinition(element); |
| + super.visitFunctionDeclaration(node); |
| + } |
| + |
| + @override |
| + visitFunctionTypeAlias(FunctionTypeAlias node) { |
| + Element element = node.element; |
| + _recordTopLevelElementDefinition(element); |
| + super.visitFunctionTypeAlias(node); |
| + } |
| + |
| + @override |
| + visitImportDirective(ImportDirective node) { |
| + ImportElement element = node.element; |
| + if (element != null) { |
| + LibraryElement impLibrary = element.importedLibrary; |
| + _recordLibraryReference(node, impLibrary); |
| + } |
| + _recordUriFileReference(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 |
| + visitMethodInvocation(MethodInvocation node) { |
| + SimpleIdentifier name = node.methodName; |
| + // TODO(scheglov) do we need this? |
| +// LocationImpl location = _createLocationForNode(name); |
| +// // name invocation |
| +// recordRelationshipIndexable( |
| +// new IndexableName(name.name), IndexConstants.IS_INVOKED_BY, location); |
| + // element invocation |
| + Element element = name.bestElement; |
| + if (element is MethodElement || |
| + element is PropertyAccessorElement || |
| + element is FunctionElement || |
| + element is VariableElement) { |
| + recordRelation(element, IndexRelationKind.IS_INVOKED_BY, node); |
| + } else if (element is ClassElement) { |
| + recordRelation(element, IndexRelationKind.IS_REFERENCED_BY, node); |
| + } |
| + node.target?.accept(this); |
| + node.argumentList?.accept(this); |
| + } |
| + |
| + @override |
| + visitPartDirective(PartDirective node) { |
| + recordRelation(node.element, IndexRelationKind.IS_REFERENCED_BY, node); |
| + _recordUriFileReference(node); |
| + super.visitPartDirective(node); |
| + } |
| + |
| + @override |
| + visitPartOfDirective(PartOfDirective node) { |
| + recordRelation(node.element, IndexRelationKind.IS_REFERENCED_BY, 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); |
| + } else { |
| + int offset = node.thisKeyword.end; |
| + recordRelationOffset( |
| + element, IndexRelationKind.IS_REFERENCED_BY, offset, 0); |
| + } |
| + super.visitRedirectingConstructorInvocation(node); |
| + } |
| + |
| + @override |
| + visitSimpleIdentifier(SimpleIdentifier node) { |
| + // TODO(scheglov) do we need this? |
| +// IndexableName indexableName = new IndexableName(node.name); |
| +// LocationImpl location = _createLocationForNode(node); |
| +// if (location == null) { |
| +// return; |
| +// } |
| + // name in declaration |
| + if (node.inDeclarationContext()) { |
| + // TODO(scheglov) do we need this? |
| +// recordRelationshipIndexable( |
| +// indexableName, IndexConstants.NAME_IS_DEFINED_BY, location); |
| + return; |
| + } |
| + // name in an extends/with/implements clause |
| + if (_isInExtendsWithImplementsClause(node)) { |
| + return; |
| + } |
| + Element element = node.bestElement; |
| + // this.field parameter |
| + if (element is FieldFormalParameterElement) { |
| + recordRelation(element.field, IndexRelationKind.IS_REFERENCED_BY, node); |
| + return; |
| + } |
| + // record specific relations |
| + if (element is ClassElement || |
| + element is FunctionElement || |
| + element is FunctionTypeAliasElement || |
| + element is LabelElement || |
| + element is MethodElement || |
| + element is PropertyAccessorElement || |
| + element is PropertyInducingElement || |
| + element is TypeParameterElement) { |
| + recordRelation(element, IndexRelationKind.IS_REFERENCED_BY, node); |
| + } else if (element is PrefixElement) { |
|
Paul Berry
2016/02/25 23:05:13
This clause can be combined with the "if" clause a
scheglov
2016/02/26 04:54:03
Done.
|
| + recordRelation(element, IndexRelationKind.IS_REFERENCED_BY, node); |
| + } |
| + super.visitSimpleIdentifier(node); |
| + } |
| + |
| + @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); |
| + } else { |
| + int offset = node.superKeyword.end; |
| + recordRelationOffset( |
| + element, IndexRelationKind.IS_REFERENCED_BY, offset, 0); |
| + } |
| + super.visitSuperConstructorInvocation(node); |
| + } |
| + |
| + @override |
| + visitVariableDeclaration(VariableDeclaration node) { |
| + VariableElement element = node.element; |
| + _recordTopLevelElementDefinition(element); |
| + // TODO(scheglov) do we need this? |
| +// // record declaration |
| +// { |
| +// SimpleIdentifier name = node.name; |
| +// LocationImpl location = _createLocationForNode(name); |
| +// location = _getLocationWithExpressionType(location, node.initializer); |
| +// recordRelationshipElement( |
| +// element, IndexConstants.NAME_IS_DEFINED_BY, location); |
| +// } |
| + super.visitVariableDeclaration(node); |
| + } |
| + |
| + /** |
| + * Records reference to defining [CompilationUnitElement] of the given |
| + * [LibraryElement]. |
| + */ |
| + void _recordLibraryReference(UriBasedDirective node, LibraryElement library) { |
|
Paul Berry
2016/02/25 23:05:13
All methods in this class are inherently private s
scheglov
2016/02/26 04:54:03
Done.
|
| + recordRelation(library, IndexRelationKind.IS_REFERENCED_BY, node?.uri); |
| + } |
| + |
| + /** |
| + * Record reference to the given operator [Element] and name. |
| + */ |
| + void _recordOperatorReference(Token operator, Element element) { |
| + recordRelationToken(element, IndexRelationKind.IS_INVOKED_BY, operator); |
| + // TODO(scheglov) do we need this? |
| +// // prepare location |
| +// LocationImpl location = _createLocationForToken(operator, element != null); |
| +// // record name reference |
| +// { |
| +// String name = operator.lexeme; |
| +// if (name == "++") { |
| +// name = "+"; |
| +// } |
| +// if (name == "--") { |
| +// name = "-"; |
| +// } |
| +// if (StringUtilities.endsWithChar(name, 0x3D) && name != "==") { |
| +// name = name.substring(0, name.length - 1); |
| +// } |
| +// IndexableName indexableName = new IndexableName(name); |
| +// recordRelationshipIndexable( |
| +// indexableName, IndexConstants.IS_INVOKED_BY, location); |
| +// } |
| +// // record element reference |
| +// if (element != null) { |
| +// recordRelationshipElement( |
| +// element, IndexConstants.IS_INVOKED_BY, location); |
| +// } |
| + } |
| + |
| + /** |
| + * Records a relation between [superNode] and its [Element]. |
| + */ |
| + void _recordSuperType(TypeName superNode, IndexRelationKind kind) { |
| + if (superNode != null) { |
| + Identifier superName = superNode.name; |
| + if (superName != null) { |
| + Element superElement = superName.staticElement; |
| + recordRelation(superElement, kind, superName); |
| + } |
| + } |
| + } |
| + |
| + /** |
| + * Record the top-level [element] definition. |
| + */ |
| + void _recordTopLevelElementDefinition(Element element) { |
| + // TODO(scheglov) do we need this? |
| +// if (element?.enclosingElement is CompilationUnitElement) { |
| +// IndexableElement indexable = new IndexableElement(element); |
| +// int offset = element.nameOffset; |
| +// int length = element.nameLength; |
| +// LocationImpl location = new LocationImpl(indexable, offset, length); |
| +// recordRelationshipElement( |
| +// _libraryElement, IndexConstants.DEFINES, location); |
| +// _store.recordTopLevelDeclaration(element); |
| +// } |
| + } |
| + |
| + void _recordUriFileReference(UriBasedDirective directive) { |
| + Element element = directive.element; |
| + recordRelation(element, IndexRelationKind.IS_REFERENCED_BY, directive.uri); |
| + } |
| + |
| + static bool _isInExtendsWithImplementsClause(SimpleIdentifier node) { |
| + TypeName typeName; |
| + AstNode parent = node?.parent; |
| + AstNode parent2 = parent?.parent; |
| + if (parent is TypeName && parent.name == node) { |
| + typeName = parent; |
| + } else if (parent is PrefixedIdentifier && |
| + parent.identifier == node && |
| + parent2 is TypeName && |
| + parent2.name == node) { |
| + typeName = parent2; |
| + } else { |
| + return false; |
| + } |
| + AstNode clause = typeName.parent; |
| + return clause is ExtendsClause || |
| + clause is WithClause || |
| + clause is ImplementsClause; |
| + } |
| +} |
| + |
| +/** |
| + * Information about a single relation. |
|
Paul Berry
2016/02/25 23:05:12
Add a comment explaining that [_RelationInfo] alwa
scheglov
2016/02/26 04:54:03
Done.
|
| + */ |
| +class _RelationInfo { |
| + final _ElementInfo element; |
|
Paul Berry
2016/02/25 23:05:13
Rename to "elementInfo". Otherwise it's easy to b
scheglov
2016/02/26 04:54:03
Done.
|
| + final IndexRelationKind kind; |
| + final int offset; |
| + final int length; |
| + |
| + _RelationInfo(this.element, this.kind, this.offset, this.length); |
| +} |
| + |
| +/** |
| + * Assembler of a single [CompilationUnit] index. |
| + */ |
|
Paul Berry
2016/02/25 23:05:13
As with [PackageIndexAssembler], it would be helpf
scheglov
2016/02/26 04:54:03
Done.
|
| +class _UnitIndexAssembler { |
| + final PackageIndexAssembler pkg; |
| + final CompilationUnitElement unitElement; |
| + final List<_RelationInfo> relations = <_RelationInfo>[]; |
| + |
| + _UnitIndexAssembler(this.pkg, this.unitElement); |
| + |
| + void addRelation( |
| + Element element, IndexRelationKind kind, int offset, int length) { |
| + _ElementInfo elementInfo = pkg._getElementInfo(element); |
| + relations.add(new _RelationInfo(elementInfo, kind, offset, length)); |
| + } |
| + |
| + /** |
| + * Assemble a new [UnitIndexBuilder] using the gathered information. |
|
Paul Berry
2016/02/25 23:05:12
s/using the gathered information/using the informa
scheglov
2016/02/26 04:54:03
Done.
|
| + */ |
| + UnitIndexBuilder assemble() { |
| + relations.sort((a, b) { |
| + return a.element.id - b.element.id; |
| + }); |
| + return new UnitIndexBuilder( |
| + elements: relations.map((r) => r.element.id).toList(), |
| + kinds: relations.map((r) => r.kind).toList(), |
| + locationOffsets: relations.map((r) => r.offset).toList(), |
| + locationLengths: relations.map((r) => r.length).toList(), |
| + libraryUri: pkg._getUriId(unitElement.library.source.uri), |
| + unitUri: pkg._getUriId(unitElement.source.uri)); |
| + } |
| +} |