| Index: pkg/analyzer/lib/src/task/incremental_element_builder.dart
|
| diff --git a/pkg/analyzer/lib/src/task/incremental_element_builder.dart b/pkg/analyzer/lib/src/task/incremental_element_builder.dart
|
| deleted file mode 100644
|
| index bbb460ee0b64ffd1e958b57ffbdeb2779e6fa4d4..0000000000000000000000000000000000000000
|
| --- a/pkg/analyzer/lib/src/task/incremental_element_builder.dart
|
| +++ /dev/null
|
| @@ -1,784 +0,0 @@
|
| -// Copyright (c) 2015, 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 analyzer.src.task.incremental_element_builder;
|
| -
|
| -import 'dart:collection';
|
| -
|
| -import 'package:analyzer/dart/ast/ast.dart';
|
| -import 'package:analyzer/dart/ast/token.dart';
|
| -import 'package:analyzer/dart/element/element.dart';
|
| -import 'package:analyzer/dart/element/visitor.dart';
|
| -import 'package:analyzer/src/dart/ast/token.dart';
|
| -import 'package:analyzer/src/dart/ast/utilities.dart';
|
| -import 'package:analyzer/src/dart/constant/utilities.dart';
|
| -import 'package:analyzer/src/dart/element/builder.dart';
|
| -import 'package:analyzer/src/dart/element/element.dart';
|
| -import 'package:analyzer/src/generated/resolver.dart';
|
| -import 'package:analyzer/src/generated/source.dart';
|
| -import 'package:analyzer/src/task/dart.dart';
|
| -
|
| -/**
|
| - * The change of a single [ClassElement].
|
| - */
|
| -class ClassElementDelta {
|
| - final ClassElement _element;
|
| - final Source librarySource;
|
| - final String name;
|
| -
|
| - final Set<ClassElementDelta> superDeltas = new Set<ClassElementDelta>();
|
| -
|
| - bool hasAnnotationChanges = false;
|
| -
|
| - final List<PropertyAccessorElement> addedAccessors =
|
| - <PropertyAccessorElement>[];
|
| - final List<PropertyAccessorElement> removedAccessors =
|
| - <PropertyAccessorElement>[];
|
| -
|
| - final List<ConstructorElement> addedConstructors = <ConstructorElement>[];
|
| - final List<ConstructorElement> removedConstructors = <ConstructorElement>[];
|
| - bool hasUnnamedConstructorChange = false;
|
| -
|
| - final List<MethodElement> addedMethods = <MethodElement>[];
|
| - final List<MethodElement> removedMethods = <MethodElement>[];
|
| -
|
| - ClassElementDelta(this._element, this.librarySource, this.name);
|
| -
|
| - /**
|
| - * Return `true` if this delta has changes to the [name] visible in the
|
| - * given [librarySource].
|
| - */
|
| - bool hasChanges(Source librarySource, String name) {
|
| - if (Identifier.isPrivateName(name) && librarySource != this.librarySource) {
|
| - return false;
|
| - }
|
| - return _hasElementWithName(addedAccessors, name) ||
|
| - _hasElementWithName(removedAccessors, name) ||
|
| - _hasElementWithName(addedConstructors, name) ||
|
| - _hasElementWithName(removedConstructors, name) ||
|
| - _hasElementWithName(addedMethods, name) ||
|
| - _hasElementWithName(removedMethods, name);
|
| - }
|
| -
|
| - static bool _hasElementWithName(List<Element> elements, String name) {
|
| - return elements.any((e) => e.displayName == name);
|
| - }
|
| -}
|
| -
|
| -/**
|
| - * The change of a single [CompilationUnitElement].
|
| - */
|
| -class CompilationUnitElementDelta {
|
| - /**
|
| - * One or more directives were added/removed.
|
| - */
|
| - bool hasDirectiveChange = false;
|
| -
|
| - /**
|
| - * The list of added top-level element.
|
| - */
|
| - final List<Element> addedDeclarations = <Element>[];
|
| -
|
| - /**
|
| - * The list of removed top-level elements.
|
| - */
|
| - final List<Element> removedDeclarations = <Element>[];
|
| -
|
| - /**
|
| - * The map from names of changed classes to the change deltas.
|
| - */
|
| - final Map<String, ClassElementDelta> classDeltas =
|
| - <String, ClassElementDelta>{};
|
| -}
|
| -
|
| -/**
|
| - * Incrementally updates the existing [unitElement] and builds elements for
|
| - * the [newUnit].
|
| - */
|
| -class IncrementalCompilationUnitElementBuilder {
|
| - final Source unitSource;
|
| - final Source librarySource;
|
| - final CompilationUnit oldUnit;
|
| - final CompilationUnitElementImpl unitElement;
|
| - final CompilationUnit newUnit;
|
| - final ElementHolder unitElementHolder = new ElementHolder();
|
| -
|
| - final List<ConstantEvaluationTarget> unitConstants =
|
| - <ConstantEvaluationTarget>[];
|
| -
|
| - /**
|
| - * The change between element models of [oldUnit] and [newUnit].
|
| - */
|
| - final CompilationUnitElementDelta unitDelta =
|
| - new CompilationUnitElementDelta();
|
| -
|
| - factory IncrementalCompilationUnitElementBuilder(
|
| - CompilationUnit oldUnit, CompilationUnit newUnit) {
|
| - CompilationUnitElementImpl unitElement = oldUnit.element;
|
| - return new IncrementalCompilationUnitElementBuilder._(unitElement.source,
|
| - unitElement.librarySource, oldUnit, newUnit, unitElement);
|
| - }
|
| -
|
| - IncrementalCompilationUnitElementBuilder._(this.unitSource,
|
| - this.librarySource, this.oldUnit, this.newUnit, this.unitElement);
|
| -
|
| - /**
|
| - * Updates [oldUnit] to have the same directives and declarations, in the
|
| - * same order as in [newUnit]. Existing resolution is kept where possible.
|
| - *
|
| - * Updates [unitElement] by adding/removing elements as needed.
|
| - *
|
| - * Fills [unitDelta] with added/remove elements.
|
| - */
|
| - void build() {
|
| - _materializeLazyElements();
|
| - new CompilationUnitBuilder()
|
| - .buildCompilationUnit(unitSource, newUnit, librarySource);
|
| - newUnit.accept(new EnumMemberBuilder(unitElement.context.typeProvider));
|
| - _processDirectives();
|
| - _processUnitMembers();
|
| - _replaceUnitContents(oldUnit, newUnit);
|
| - _findConstants();
|
| - newUnit.element = unitElement;
|
| - unitElement.setCodeRange(0, newUnit.endToken.end);
|
| - }
|
| -
|
| - void _addElementToUnitHolder(Element element) {
|
| - if (element is ClassElement) {
|
| - if (element.isEnum) {
|
| - unitElementHolder.addEnum(element);
|
| - } else {
|
| - unitElementHolder.addType(element);
|
| - }
|
| - } else if (element is FunctionElement) {
|
| - unitElementHolder.addFunction(element);
|
| - } else if (element is FunctionTypeAliasElement) {
|
| - unitElementHolder.addTypeAlias(element);
|
| - } else if (element is PropertyAccessorElement) {
|
| - unitElementHolder.addAccessor(element);
|
| - } else if (element is TopLevelVariableElement) {
|
| - unitElementHolder.addTopLevelVariable(element);
|
| - }
|
| - }
|
| -
|
| - void _findConstants() {
|
| - ConstantFinder finder = new ConstantFinder();
|
| - oldUnit.accept(finder);
|
| - unitConstants.addAll(finder.constantsToCompute);
|
| - // Update annotation constants to using the old unit element.
|
| - for (ConstantEvaluationTarget constant in unitConstants) {
|
| - if (constant is ElementAnnotationImpl) {
|
| - constant.compilationUnit = unitElement;
|
| - }
|
| - }
|
| - }
|
| -
|
| - void _materializeLazyElements() {
|
| - unitElement.accept(new RecursiveElementVisitor());
|
| - }
|
| -
|
| - ClassElementDelta _processClassMembers(
|
| - ClassDeclaration oldClass, ClassDeclaration newClass) {
|
| - // If the class hierarchy or type parameters are changed,
|
| - // then the class changed too much - don't compute the delta.
|
| - if (newClass.abstractKeyword != null && oldClass.abstractKeyword == null ||
|
| - newClass.abstractKeyword == null && oldClass.abstractKeyword != null ||
|
| - TokenUtils.getFullCode(newClass.typeParameters) !=
|
| - TokenUtils.getFullCode(oldClass.typeParameters) ||
|
| - TokenUtils.getFullCode(newClass.extendsClause) !=
|
| - TokenUtils.getFullCode(oldClass.extendsClause) ||
|
| - TokenUtils.getFullCode(newClass.withClause) !=
|
| - TokenUtils.getFullCode(oldClass.withClause) ||
|
| - TokenUtils.getFullCode(newClass.implementsClause) !=
|
| - TokenUtils.getFullCode(oldClass.implementsClause)) {
|
| - return null;
|
| - }
|
| - // Build the old class members map.
|
| - Map<String, ClassMember> oldNodeMap = new HashMap<String, ClassMember>();
|
| - for (ClassMember oldNode in oldClass.members) {
|
| - String code = TokenUtils.getFullCode(oldNode);
|
| - oldNodeMap[code] = oldNode;
|
| - }
|
| - // Prepare elements.
|
| - ClassElement newElement = newClass.element;
|
| - ClassElement oldElement = oldClass.element;
|
| - // Use the old element for the new node.
|
| - newClass.name.staticElement = oldElement;
|
| - if (newElement is ClassElementImpl && oldElement is ClassElementImpl) {
|
| - oldElement.nameOffset = newElement.nameOffset;
|
| - oldElement.setCodeRange(newElement.codeOffset, newElement.codeLength);
|
| - oldElement.typeParameters = newElement.typeParameters;
|
| - }
|
| - // Prepare delta.
|
| - ClassElementImpl classElement = oldClass.element;
|
| - ElementHolder classElementHolder = new ElementHolder();
|
| - ClassElementDelta classDelta =
|
| - new ClassElementDelta(classElement, librarySource, classElement.name);
|
| - // Check for annotation changes.
|
| - {
|
| - String oldAnnotationsCode =
|
| - TokenUtils.getFullCodeOfList(oldClass.metadata);
|
| - String newAnnotationsCode =
|
| - TokenUtils.getFullCodeOfList(newClass.metadata);
|
| - classDelta.hasAnnotationChanges =
|
| - oldAnnotationsCode != newAnnotationsCode;
|
| - }
|
| - // Prepare all old member elements.
|
| - var removedAccessors = new Set<PropertyAccessorElement>.identity();
|
| - var removedConstructors = new Set<ConstructorElement>.identity();
|
| - var removedMethods = new Set<MethodElement>.identity();
|
| - removedAccessors.addAll(classElement.accessors);
|
| - removedConstructors.addAll(classElement.constructors);
|
| - removedMethods.addAll(classElement.methods);
|
| - // Utilities.
|
| - void processConstructorDeclaration(
|
| - ConstructorDeclaration node, bool isNew) {
|
| - ConstructorElement element = node.element;
|
| - if (element != null) {
|
| - classElementHolder.addConstructor(element);
|
| - if (isNew) {
|
| - classDelta.addedConstructors.add(element);
|
| - } else {
|
| - removedConstructors.remove(element);
|
| - }
|
| - }
|
| - }
|
| -
|
| - void processFieldDeclaration(FieldDeclaration node, bool isNew) {
|
| - for (VariableDeclaration field in node.fields.variables) {
|
| - PropertyInducingElement element = field.element;
|
| - if (element != null) {
|
| - PropertyAccessorElement getter = element.getter;
|
| - PropertyAccessorElement setter = element.setter;
|
| - if (getter != null) {
|
| - classElementHolder.addAccessor(getter);
|
| - if (isNew) {
|
| - classDelta.addedAccessors.add(getter);
|
| - } else {
|
| - removedAccessors.remove(getter);
|
| - }
|
| - }
|
| - if (setter != null) {
|
| - classElementHolder.addAccessor(setter);
|
| - if (isNew) {
|
| - classDelta.addedAccessors.add(setter);
|
| - } else {
|
| - removedAccessors.remove(setter);
|
| - }
|
| - }
|
| - }
|
| - }
|
| - }
|
| -
|
| - void processMethodDeclaration(MethodDeclaration node, bool isNew) {
|
| - Element element = node.element;
|
| - if (element is MethodElement) {
|
| - classElementHolder.addMethod(element);
|
| - if (isNew) {
|
| - classDelta.addedMethods.add(element);
|
| - } else {
|
| - removedMethods.remove(element);
|
| - }
|
| - } else if (element is PropertyAccessorElement) {
|
| - classElementHolder.addAccessor(element);
|
| - if (isNew) {
|
| - classDelta.addedAccessors.add(element);
|
| - } else {
|
| - removedAccessors.remove(element);
|
| - }
|
| - }
|
| - }
|
| -
|
| - // Replace new nodes with the identical old nodes.
|
| - bool newHasConstructor = false;
|
| - for (ClassMember newNode in newClass.members) {
|
| - String code = TokenUtils.getFullCode(newNode);
|
| - ClassMember oldNode = oldNodeMap.remove(code);
|
| - // When we type a name before a constructor with a documentation
|
| - // comment, this makes the comment disappear from AST. So, even though
|
| - // tokens are the same, the nodes are not the same.
|
| - if (oldNode != null) {
|
| - if (oldNode.documentationComment == null &&
|
| - newNode.documentationComment != null ||
|
| - oldNode.documentationComment != null &&
|
| - newNode.documentationComment == null) {
|
| - oldNode = null;
|
| - }
|
| - }
|
| - // Add the new element.
|
| - if (oldNode == null) {
|
| - if (newNode is ConstructorDeclaration) {
|
| - newHasConstructor = true;
|
| - processConstructorDeclaration(newNode, true);
|
| - }
|
| - if (newNode is FieldDeclaration) {
|
| - processFieldDeclaration(newNode, true);
|
| - }
|
| - if (newNode is MethodDeclaration) {
|
| - processMethodDeclaration(newNode, true);
|
| - }
|
| - continue;
|
| - }
|
| - // Do replacement.
|
| - _replaceNode(newNode, oldNode);
|
| - if (oldNode is ConstructorDeclaration) {
|
| - processConstructorDeclaration(oldNode, false);
|
| - }
|
| - if (oldNode is FieldDeclaration) {
|
| - processFieldDeclaration(oldNode, false);
|
| - }
|
| - if (oldNode is MethodDeclaration) {
|
| - processMethodDeclaration(oldNode, false);
|
| - }
|
| - }
|
| - // If the class had only a default synthetic constructor, and there are
|
| - // no explicit constructors in the new AST, keep the constructor.
|
| - if (!newHasConstructor) {
|
| - List<ConstructorElement> constructors = classElement.constructors;
|
| - if (constructors.length == 1) {
|
| - ConstructorElement constructor = constructors[0];
|
| - if (constructor.isSynthetic && constructor.isDefaultConstructor) {
|
| - classElementHolder.addConstructor(constructor);
|
| - removedConstructors.remove(constructor);
|
| - }
|
| - }
|
| - }
|
| - // Update the delta.
|
| - classDelta.removedAccessors.addAll(removedAccessors);
|
| - classDelta.removedConstructors.addAll(removedConstructors);
|
| - classDelta.removedMethods.addAll(removedMethods);
|
| - // Prepare fields.
|
| - List<PropertyAccessorElement> newAccessors = classElementHolder.accessors;
|
| - Map<String, FieldElement> newFields = <String, FieldElement>{};
|
| - for (PropertyAccessorElement accessor in newAccessors) {
|
| - newFields[accessor.displayName] = accessor.variable;
|
| - }
|
| - // Update references to fields from constructors.
|
| - for (ClassMember member in newClass.members) {
|
| - if (member is ConstructorDeclaration) {
|
| - for (FormalParameter parameter in member.parameters.parameters) {
|
| - FormalParameter normalParameter = parameter;
|
| - if (parameter is DefaultFormalParameter) {
|
| - normalParameter = parameter.parameter;
|
| - }
|
| - if (normalParameter is FieldFormalParameter) {
|
| - FieldFormalParameterElementImpl parameterElement =
|
| - normalParameter.element as FieldFormalParameterElementImpl;
|
| - parameterElement.field = newFields[parameterElement.name];
|
| - }
|
| - }
|
| - }
|
| - }
|
| - // Update ClassElement.
|
| - classElement.metadata = newElement.metadata;
|
| - classElement.accessors = newAccessors;
|
| - classElement.constructors = classElementHolder.constructors;
|
| - classElement.fields = newFields.values.toList();
|
| - classElement.methods = classElementHolder.methods;
|
| - classElement.version++;
|
| - classElementHolder.validate();
|
| - // Ensure at least a default synthetic constructor.
|
| - if (classElement.constructors.isEmpty) {
|
| - ConstructorElementImpl constructor =
|
| - new ConstructorElementImpl.forNode(null);
|
| - constructor.isSynthetic = true;
|
| - classElement.constructors = <ConstructorElement>[constructor];
|
| - classDelta.addedConstructors.add(constructor);
|
| - }
|
| - classDelta.hasUnnamedConstructorChange =
|
| - classDelta.addedConstructors.any((c) => c.name == '') ||
|
| - classDelta.removedConstructors.any((c) => c.name == '');
|
| - // OK
|
| - return classDelta;
|
| - }
|
| -
|
| - void _processDirectives() {
|
| - Map<String, Directive> oldDirectiveMap = new HashMap<String, Directive>();
|
| - for (Directive oldDirective in oldUnit.directives) {
|
| - String code = TokenUtils.getFullCode(oldDirective);
|
| - oldDirectiveMap[code] = oldDirective;
|
| - }
|
| - // Replace new nodes with the identical old nodes.
|
| - Set<Directive> removedDirectives = oldUnit.directives.toSet();
|
| - for (Directive newDirective in newUnit.directives) {
|
| - String code = TokenUtils.getFullCode(newDirective);
|
| - // Prepare an old directive.
|
| - Directive oldDirective = oldDirectiveMap[code];
|
| - if (oldDirective == null) {
|
| - unitDelta.hasDirectiveChange = true;
|
| - continue;
|
| - }
|
| - // URI's must be resolved to the same sources.
|
| - if (newDirective is UriBasedDirective &&
|
| - oldDirective is UriBasedDirective) {
|
| - Source source(UriBasedDirective directive) =>
|
| - directive is NamespaceDirective
|
| - ? directive.selectedSource
|
| - : directive.uriSource;
|
| - if (source(oldDirective) != source(newDirective)) {
|
| - continue;
|
| - }
|
| - }
|
| - // Do replacement.
|
| - _replaceNode(newDirective, oldDirective);
|
| - removedDirectives.remove(oldDirective);
|
| - }
|
| - // If there are any directives left, then these directives were removed.
|
| - if (removedDirectives.isNotEmpty) {
|
| - unitDelta.hasDirectiveChange = true;
|
| - }
|
| - }
|
| -
|
| - void _processUnitMembers() {
|
| - Map<String, CompilationUnitMember> oldNodeMap =
|
| - new HashMap<String, CompilationUnitMember>();
|
| - Map<String, ClassDeclaration> nameToOldClassMap =
|
| - new HashMap<String, ClassDeclaration>();
|
| - for (CompilationUnitMember oldNode in oldUnit.declarations) {
|
| - String code = TokenUtils.getFullCode(oldNode);
|
| - oldNodeMap[code] = oldNode;
|
| - if (oldNode is ClassDeclaration) {
|
| - nameToOldClassMap[oldNode.name.name] = oldNode;
|
| - }
|
| - }
|
| - // Prepare all old top-level elements.
|
| - Set<Element> removedElements = new Set<Element>();
|
| - removedElements.addAll(unitElement.accessors);
|
| - removedElements.addAll(unitElement.enums);
|
| - removedElements.addAll(unitElement.functions);
|
| - removedElements.addAll(unitElement.functionTypeAliases);
|
| - removedElements.addAll(unitElement.types);
|
| - removedElements.addAll(unitElement.topLevelVariables);
|
| - // Replace new nodes with the identical old nodes.
|
| - for (CompilationUnitMember newNode in newUnit.declarations) {
|
| - String code = TokenUtils.getFullCode(newNode);
|
| - CompilationUnitMember oldNode = oldNodeMap[code];
|
| - // Add the new element.
|
| - if (oldNode == null) {
|
| - // Compute a delta for the class.
|
| - if (newNode is ClassDeclaration) {
|
| - ClassDeclaration oldClass = nameToOldClassMap[newNode.name.name];
|
| - if (oldClass != null) {
|
| - ClassElementDelta delta = _processClassMembers(oldClass, newNode);
|
| - if (delta != null) {
|
| - unitDelta.classDeltas[delta._element.name] = delta;
|
| - _addElementToUnitHolder(delta._element);
|
| - removedElements.remove(delta._element);
|
| - continue;
|
| - }
|
| - }
|
| - }
|
| - // Add the new node elements.
|
| - List<Element> elements = _getElements(newNode);
|
| - elements.forEach(_addElementToUnitHolder);
|
| - elements.forEach(unitDelta.addedDeclarations.add);
|
| - continue;
|
| - }
|
| - // Do replacement.
|
| - _replaceNode(newNode, oldNode);
|
| - List<Element> elements = _getElements(oldNode);
|
| - elements.forEach(_addElementToUnitHolder);
|
| - elements.forEach(removedElements.remove);
|
| - }
|
| - unitDelta.removedDeclarations.addAll(removedElements);
|
| - // Update CompilationUnitElement.
|
| - unitElement.accessors = unitElementHolder.accessors;
|
| - unitElement.enums = unitElementHolder.enums;
|
| - unitElement.functions = unitElementHolder.functions;
|
| - unitElement.typeAliases = unitElementHolder.typeAliases;
|
| - unitElement.types = unitElementHolder.types;
|
| - unitElement.topLevelVariables = unitElementHolder.topLevelVariables;
|
| - unitElementHolder.validate();
|
| - }
|
| -
|
| - /**
|
| - * Replaces [newNode] with [oldNode], updates tokens and elements.
|
| - * The nodes must have the same tokens, but offsets may be different.
|
| - */
|
| - void _replaceNode(AstNode newNode, AstNode oldNode) {
|
| - // Replace node.
|
| - NodeReplacer.replace(newNode, oldNode);
|
| - // Replace tokens.
|
| - Token oldBeginToken = TokenUtils.getBeginTokenNotComment(oldNode);
|
| - Token newBeginToken = TokenUtils.getBeginTokenNotComment(newNode);
|
| - newBeginToken.previous.setNext(oldBeginToken);
|
| - oldNode.endToken.setNext(newNode.endToken.next);
|
| - // Change tokens offsets.
|
| - Map<int, int> offsetMap = new HashMap<int, int>();
|
| - TokenUtils.copyTokenOffsets(offsetMap, oldBeginToken, newBeginToken,
|
| - oldNode.endToken, newNode.endToken);
|
| - // Change elements offsets.
|
| - {
|
| - var visitor = new _UpdateElementOffsetsVisitor(offsetMap);
|
| - List<Element> elements = _getElements(oldNode);
|
| - for (Element element in elements) {
|
| - element.accept(visitor);
|
| - }
|
| - }
|
| - }
|
| -
|
| - /**
|
| - * Returns [Element]s that are declared directly by the given [node].
|
| - * This does not include any child elements - parameters, local variables.
|
| - *
|
| - * Usually just one [Element] is returned, but [VariableDeclarationList]
|
| - * nodes may declare more than one.
|
| - */
|
| - static List<Element> _getElements(AstNode node) {
|
| - List<Element> elements = <Element>[];
|
| - void addPropertyAccessors(VariableDeclarationList variableList) {
|
| - if (variableList != null) {
|
| - for (VariableDeclaration variable in variableList.variables) {
|
| - PropertyInducingElement element = variable.element;
|
| - if (element != null) {
|
| - elements.add(element);
|
| - if (element.getter != null) {
|
| - elements.add(element.getter);
|
| - }
|
| - if (element.setter != null) {
|
| - elements.add(element.setter);
|
| - }
|
| - }
|
| - }
|
| - }
|
| - }
|
| -
|
| - if (node is FieldDeclaration) {
|
| - addPropertyAccessors(node.fields);
|
| - } else if (node is TopLevelVariableDeclaration) {
|
| - addPropertyAccessors(node.variables);
|
| - } else if (node is PartDirective || node is PartOfDirective) {
|
| - // Ignore.
|
| - } else if (node is Directive && node.element != null) {
|
| - elements.add(node.element);
|
| - } else if (node is Declaration && node.element != null) {
|
| - Element element = node.element;
|
| - elements.add(element);
|
| - if (element is PropertyAccessorElement) {
|
| - elements.add(element.variable);
|
| - }
|
| - }
|
| - return elements;
|
| - }
|
| -
|
| - /**
|
| - * Replaces contents of the [to] unit with the contexts of the [from] unit.
|
| - */
|
| - static void _replaceUnitContents(CompilationUnit to, CompilationUnit from) {
|
| - to.directives.clear();
|
| - to.declarations.clear();
|
| - to.beginToken = from.beginToken;
|
| - to.scriptTag = from.scriptTag;
|
| - to.directives.addAll(from.directives);
|
| - to.declarations.addAll(from.declarations);
|
| - to.element = to.element;
|
| - to.lineInfo = from.lineInfo;
|
| - to.endToken = from.endToken;
|
| - }
|
| -}
|
| -
|
| -/**
|
| - * Utilities for [Token] manipulations.
|
| - */
|
| -class TokenUtils {
|
| - static const String _SEPARATOR = "\uFFFF";
|
| -
|
| - /**
|
| - * Copy offsets from [newToken]s to [oldToken]s.
|
| - */
|
| - static void copyTokenOffsets(Map<int, int> offsetMap, Token oldToken,
|
| - Token newToken, Token oldEndToken, Token newEndToken) {
|
| - if (oldToken is CommentToken && newToken is CommentToken) {
|
| - // Update documentation tokens.
|
| - while (oldToken != null) {
|
| - offsetMap[oldToken.offset] = newToken.offset;
|
| - offsetMap[oldToken.end] = newToken.end;
|
| - oldToken.offset = newToken.offset;
|
| - // Update (otherwise unlinked) reference tokens in documentation.
|
| - if (oldToken is DocumentationCommentToken &&
|
| - newToken is DocumentationCommentToken) {
|
| - List<Token> oldReferences = oldToken.references;
|
| - List<Token> newReferences = newToken.references;
|
| - assert(oldReferences.length == newReferences.length);
|
| - for (int i = 0; i < oldReferences.length; i++) {
|
| - Token oldToken = oldReferences[i];
|
| - Token newToken = newReferences[i];
|
| - // For [new Name] the 'Name' token is the reference.
|
| - // But we need to process all tokens, including 'new'.
|
| - while (oldToken.previous != null &&
|
| - oldToken.previous.type != TokenType.EOF) {
|
| - oldToken = oldToken.previous;
|
| - }
|
| - while (newToken.previous != null &&
|
| - newToken.previous.type != TokenType.EOF) {
|
| - newToken = newToken.previous;
|
| - }
|
| - copyTokenOffsets(
|
| - offsetMap, oldToken, newToken, oldEndToken, newEndToken);
|
| - }
|
| - }
|
| - // Next tokens.
|
| - oldToken = oldToken.next;
|
| - newToken = newToken.next;
|
| - }
|
| - assert(oldToken == null);
|
| - assert(newToken == null);
|
| - return;
|
| - }
|
| - while (true) {
|
| - if (oldToken.precedingComments != null) {
|
| - assert(newToken.precedingComments != null);
|
| - copyTokenOffsets(offsetMap, oldToken.precedingComments,
|
| - newToken.precedingComments, oldEndToken, newEndToken);
|
| - }
|
| - offsetMap[oldToken.offset] = newToken.offset;
|
| - offsetMap[oldToken.end] = newToken.end;
|
| - oldToken.offset = newToken.offset;
|
| - if (oldToken.type == TokenType.EOF) {
|
| - assert(newToken.type == TokenType.EOF);
|
| - break;
|
| - }
|
| - if (oldToken == oldEndToken) {
|
| - assert(newToken == newEndToken);
|
| - break;
|
| - }
|
| - oldToken = oldToken.next;
|
| - newToken = newToken.next;
|
| - }
|
| - }
|
| -
|
| - static Token getBeginTokenNotComment(AstNode node) {
|
| - Token oldBeginToken = node.beginToken;
|
| - if (oldBeginToken is CommentToken) {
|
| - return oldBeginToken.parent;
|
| - }
|
| - return oldBeginToken;
|
| - }
|
| -
|
| - /**
|
| - * Return the token string of all the [node].
|
| - */
|
| - static String getFullCode(AstNode node) {
|
| - if (node == null) {
|
| - return '';
|
| - }
|
| - List<Token> tokens = getTokens(node);
|
| - return joinTokens(tokens);
|
| - }
|
| -
|
| - /**
|
| - * Return the token string of all the [nodes].
|
| - */
|
| - static String getFullCodeOfList(List<AstNode> nodes) {
|
| - if (nodes == null) {
|
| - return '';
|
| - }
|
| - return nodes.map(getFullCode).join(_SEPARATOR);
|
| - }
|
| -
|
| - /**
|
| - * Returns all tokens (including comments) of the given [node].
|
| - */
|
| - static List<Token> getTokens(AstNode node) {
|
| - List<Token> tokens = <Token>[];
|
| - Token token = getBeginTokenNotComment(node);
|
| - Token endToken = node.endToken;
|
| - while (true) {
|
| - // stop if past the end token
|
| - if (token.offset > endToken.end) {
|
| - break;
|
| - }
|
| - // append comment tokens
|
| - for (Token commentToken = token.precedingComments;
|
| - commentToken != null;
|
| - commentToken = commentToken.next) {
|
| - tokens.add(commentToken);
|
| - }
|
| - // append token
|
| - tokens.add(token);
|
| - // next token
|
| - if (token == endToken) {
|
| - break;
|
| - }
|
| - token = token.next;
|
| - }
|
| - return tokens;
|
| - }
|
| -
|
| - static String joinTokens(List<Token> tokens) {
|
| - return tokens.map((token) => token.lexeme).join(_SEPARATOR);
|
| - }
|
| -}
|
| -
|
| -/**
|
| - * Updates name offsets of [Element]s according to the [map].
|
| - */
|
| -class _UpdateElementOffsetsVisitor extends GeneralizingElementVisitor {
|
| - final Map<int, int> map;
|
| -
|
| - _UpdateElementOffsetsVisitor(this.map);
|
| -
|
| - void visitElement(Element element) {
|
| - if (element is ElementImpl) {
|
| - // name offset
|
| - {
|
| - int oldOffset = element.nameOffset;
|
| - int newOffset = map[oldOffset];
|
| - // Some synthetic elements have new offsets, e.g. synthetic accessors
|
| - // of property inducing elements. But some are purely synthetic, e.g.
|
| - // synthetic enum fields and their accessors.
|
| - // PrefixElement(s) can be shared between import directives, so
|
| - // their name offsets are outside of the second and subsequent import
|
| - // directives. But we update the name offsets while visiting the first
|
| - // import directive.
|
| - if (newOffset == null) {
|
| - assert(element.isSynthetic || element is PrefixElement);
|
| - return;
|
| - }
|
| - element.nameOffset = newOffset;
|
| - }
|
| - // stop here for LibraryElement
|
| - if (element is LibraryElementImpl) {
|
| - return;
|
| - }
|
| - // code range
|
| - {
|
| - int oldOffset = element.codeOffset;
|
| - if (oldOffset != null) {
|
| - int oldEnd = oldOffset + element.codeLength;
|
| - int newOffset = map[oldOffset];
|
| - int newEnd = map[oldEnd];
|
| - assert(newOffset != null);
|
| - assert(newEnd != null);
|
| - int newLength = newEnd - newOffset;
|
| - element.setCodeRange(newOffset, newLength);
|
| - }
|
| - }
|
| - // visible range
|
| - if (element is LocalElement) {
|
| - SourceRange oldVisibleRange = (element as LocalElement).visibleRange;
|
| - if (oldVisibleRange != null) {
|
| - int oldOffset = oldVisibleRange.offset;
|
| - int oldLength = oldVisibleRange.length;
|
| - int oldEnd = oldOffset + oldLength;
|
| - int newOffset = map[oldOffset];
|
| - int newEnd = map[oldEnd];
|
| - assert(newOffset != null);
|
| - assert(newEnd != null);
|
| - int newLength = newEnd - newOffset;
|
| - if (newOffset != oldOffset || newLength != oldLength) {
|
| - if (element is FunctionElementImpl) {
|
| - element.setVisibleRange(newOffset, newLength);
|
| - } else if (element is LocalVariableElementImpl) {
|
| - element.setVisibleRange(newOffset, newLength);
|
| - } else if (element is ParameterElementImpl) {
|
| - element.setVisibleRange(newOffset, newLength);
|
| - }
|
| - }
|
| - }
|
| - }
|
| - }
|
| - super.visitElement(element);
|
| - }
|
| -}
|
|
|