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

Unified Diff: packages/analyzer/lib/src/task/incremental_element_builder.dart

Issue 2990843002: Removed fixed dependencies (Closed)
Patch Set: Created 3 years, 5 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
« no previous file with comments | « packages/analyzer/lib/src/task/html_work_manager.dart ('k') | packages/analyzer/lib/src/task/inputs.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: packages/analyzer/lib/src/task/incremental_element_builder.dart
diff --git a/packages/analyzer/lib/src/task/incremental_element_builder.dart b/packages/analyzer/lib/src/task/incremental_element_builder.dart
index d6a0c1418d4569dc4e9c10db954daba9031b1055..6ae19ff630dcf1151a712895a07898786c242285 100644
--- a/packages/analyzer/lib/src/task/incremental_element_builder.dart
+++ b/packages/analyzer/lib/src/task/incremental_element_builder.dart
@@ -6,11 +6,65 @@ library analyzer.src.task.incremental_element_builder;
import 'dart:collection';
-import 'package:analyzer/src/generated/ast.dart';
-import 'package:analyzer/src/generated/element.dart';
+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/scanner.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].
@@ -30,6 +84,12 @@ class CompilationUnitElementDelta {
* 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>{};
}
/**
@@ -42,7 +102,10 @@ class IncrementalCompilationUnitElementBuilder {
final CompilationUnit oldUnit;
final CompilationUnitElementImpl unitElement;
final CompilationUnit newUnit;
- final ElementHolder holder = new ElementHolder();
+ final ElementHolder unitElementHolder = new ElementHolder();
+
+ final List<ConstantEvaluationTarget> unitConstants =
+ <ConstantEvaluationTarget>[];
/**
* The change between element models of [oldUnit] and [newUnit].
@@ -69,30 +132,265 @@ class IncrementalCompilationUnitElementBuilder {
* Fills [unitDelta] with added/remove elements.
*/
void build() {
+ _materializeLazyElements();
new CompilationUnitBuilder()
.buildCompilationUnit(unitSource, newUnit, librarySource);
+ newUnit.accept(new EnumMemberBuilder(unitElement.context.typeProvider));
_processDirectives();
_processUnitMembers();
- newUnit.element = unitElement;
_replaceUnitContents(oldUnit, newUnit);
+ _findConstants();
+ newUnit.element = unitElement;
+ unitElement.setCodeRange(0, newUnit.endToken.end);
}
- void _addElementToHolder(Element element) {
- if (element is PropertyAccessorElement) {
- holder.addAccessor(element);
- } else if (element is ClassElement) {
+ void _addElementToUnitHolder(Element element) {
+ if (element is ClassElement) {
if (element.isEnum) {
- holder.addEnum(element);
+ unitElementHolder.addEnum(element);
} else {
- holder.addType(element);
+ unitElementHolder.addType(element);
}
} else if (element is FunctionElement) {
- holder.addFunction(element);
+ unitElementHolder.addFunction(element);
} else if (element is FunctionTypeAliasElement) {
- holder.addTypeAlias(element);
+ unitElementHolder.addTypeAlias(element);
+ } else if (element is PropertyAccessorElement) {
+ unitElementHolder.addAccessor(element);
} else if (element is TopLevelVariableElement) {
- holder.addTopLevelVariable(element);
+ 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.synthetic = 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() {
@@ -114,7 +412,11 @@ class IncrementalCompilationUnitElementBuilder {
// URI's must be resolved to the same sources.
if (newDirective is UriBasedDirective &&
oldDirective is UriBasedDirective) {
- if (oldDirective.source != newDirective.source) {
+ Source source(UriBasedDirective directive) =>
+ directive is NamespaceDirective
+ ? directive.selectedSource
+ : directive.uriSource;
+ if (source(oldDirective) != source(newDirective)) {
continue;
}
}
@@ -131,9 +433,14 @@ class IncrementalCompilationUnitElementBuilder {
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>();
@@ -146,29 +453,43 @@ class IncrementalCompilationUnitElementBuilder {
// Replace new nodes with the identical old nodes.
for (CompilationUnitMember newNode in newUnit.declarations) {
String code = TokenUtils.getFullCode(newNode);
- // Prepare an old node.
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(_addElementToHolder);
+ elements.forEach(_addElementToUnitHolder);
elements.forEach(unitDelta.addedDeclarations.add);
continue;
}
// Do replacement.
_replaceNode(newNode, oldNode);
List<Element> elements = _getElements(oldNode);
- elements.forEach(_addElementToHolder);
+ elements.forEach(_addElementToUnitHolder);
elements.forEach(removedElements.remove);
}
unitDelta.removedDeclarations.addAll(removedElements);
// Update CompilationUnitElement.
- unitElement.accessors = holder.accessors;
- unitElement.enums = holder.enums;
- unitElement.functions = holder.functions;
- unitElement.typeAliases = holder.typeAliases;
- unitElement.types = holder.types;
- unitElement.topLevelVariables = holder.topLevelVariables;
- holder.validate();
+ 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();
}
/**
@@ -179,16 +500,14 @@ class IncrementalCompilationUnitElementBuilder {
// Replace node.
NodeReplacer.replace(newNode, oldNode);
// Replace tokens.
- {
- Token oldBeginToken = TokenUtils.getBeginTokenNotComment(newNode);
- Token newBeginToken = TokenUtils.getBeginTokenNotComment(oldNode);
- oldBeginToken.previous.setNext(newBeginToken);
- oldNode.endToken.setNext(newNode.endToken.next);
- }
+ 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, oldNode.beginToken,
- newNode.beginToken, oldNode.endToken, newNode.endToken, true);
+ TokenUtils.copyTokenOffsets(offsetMap, oldBeginToken, newBeginToken,
+ oldNode.endToken, newNode.endToken);
// Change elements offsets.
{
var visitor = new _UpdateElementOffsetsVisitor(offsetMap);
@@ -208,21 +527,29 @@ class IncrementalCompilationUnitElementBuilder {
*/
static List<Element> _getElements(AstNode node) {
List<Element> elements = <Element>[];
- if (node is TopLevelVariableDeclaration) {
- VariableDeclarationList variableList = node.variables;
+ void addPropertyAccessors(VariableDeclarationList variableList) {
if (variableList != null) {
for (VariableDeclaration variable in variableList.variables) {
- TopLevelVariableElement element = variable.element;
- elements.add(element);
- if (element.getter != null) {
- elements.add(element.getter);
- }
- if (element.setter != null) {
- elements.add(element.setter);
+ 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) {
@@ -236,7 +563,7 @@ class IncrementalCompilationUnitElementBuilder {
}
/**
- * Replaces contents of the [to] unit with the contenxts of the [from] unit.
+ * Replaces contents of the [to] unit with the contexts of the [from] unit.
*/
static void _replaceUnitContents(CompilationUnit to, CompilationUnit from) {
to.directives.clear();
@@ -247,6 +574,7 @@ class IncrementalCompilationUnitElementBuilder {
to.declarations.addAll(from.declarations);
to.element = to.element;
to.lineInfo = from.lineInfo;
+ to.endToken = from.endToken;
}
}
@@ -260,16 +588,37 @@ class TokenUtils {
* Copy offsets from [newToken]s to [oldToken]s.
*/
static void copyTokenOffsets(Map<int, int> offsetMap, Token oldToken,
- Token newToken, Token oldEndToken, Token newEndToken,
- [bool goUpComment = false]) {
+ Token newToken, Token oldEndToken, Token newEndToken) {
if (oldToken is CommentToken && newToken is CommentToken) {
- if (goUpComment) {
- copyTokenOffsets(offsetMap, (oldToken as CommentToken).parent,
- (newToken as CommentToken).parent, oldEndToken, newEndToken);
- }
+ // 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;
}
@@ -284,7 +633,12 @@ class TokenUtils {
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;
@@ -297,27 +651,44 @@ class TokenUtils {
static Token getBeginTokenNotComment(AstNode node) {
Token oldBeginToken = node.beginToken;
if (oldBeginToken is CommentToken) {
- oldBeginToken = (oldBeginToken as CommentToken).parent;
+ return oldBeginToken.parent;
}
return oldBeginToken;
}
/**
- * Return the token string of all the [node] tokens.
+ * 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);
}
/**
- * Returns all tokends (including comments) of the given [node].
+ * 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;
@@ -349,18 +720,65 @@ class _UpdateElementOffsetsVisitor extends GeneralizingElementVisitor {
_UpdateElementOffsetsVisitor(this.map);
void visitElement(Element element) {
- if (element is CompilationUnitElement) {
- return;
- }
- if (element.isSynthetic) {
- return;
- }
- int oldOffset = element.nameOffset;
- int newOffset = map[oldOffset];
- assert(newOffset != null);
- (element as ElementImpl).nameOffset = newOffset;
- if (element is! LibraryElement) {
- super.visitElement(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);
}
}
« no previous file with comments | « packages/analyzer/lib/src/task/html_work_manager.dart ('k') | packages/analyzer/lib/src/task/inputs.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698