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

Side by Side Diff: packages/analyzer/lib/src/task/incremental_element_builder.dart

Issue 2990843002: Removed fixed dependencies (Closed)
Patch Set: Created 3 years, 4 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 unified diff | Download patch
OLDNEW
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 library analyzer.src.task.incremental_element_builder; 5 library analyzer.src.task.incremental_element_builder;
6 6
7 import 'dart:collection'; 7 import 'dart:collection';
8 8
9 import 'package:analyzer/src/generated/ast.dart'; 9 import 'package:analyzer/dart/ast/ast.dart';
10 import 'package:analyzer/src/generated/element.dart'; 10 import 'package:analyzer/dart/ast/token.dart';
11 import 'package:analyzer/dart/element/element.dart';
12 import 'package:analyzer/dart/element/visitor.dart';
13 import 'package:analyzer/src/dart/ast/token.dart';
14 import 'package:analyzer/src/dart/ast/utilities.dart';
15 import 'package:analyzer/src/dart/constant/utilities.dart';
16 import 'package:analyzer/src/dart/element/builder.dart';
17 import 'package:analyzer/src/dart/element/element.dart';
11 import 'package:analyzer/src/generated/resolver.dart'; 18 import 'package:analyzer/src/generated/resolver.dart';
12 import 'package:analyzer/src/generated/scanner.dart';
13 import 'package:analyzer/src/generated/source.dart'; 19 import 'package:analyzer/src/generated/source.dart';
20 import 'package:analyzer/src/task/dart.dart';
21
22 /**
23 * The change of a single [ClassElement].
24 */
25 class ClassElementDelta {
26 final ClassElement _element;
27 final Source librarySource;
28 final String name;
29
30 final Set<ClassElementDelta> superDeltas = new Set<ClassElementDelta>();
31
32 bool hasAnnotationChanges = false;
33
34 final List<PropertyAccessorElement> addedAccessors =
35 <PropertyAccessorElement>[];
36 final List<PropertyAccessorElement> removedAccessors =
37 <PropertyAccessorElement>[];
38
39 final List<ConstructorElement> addedConstructors = <ConstructorElement>[];
40 final List<ConstructorElement> removedConstructors = <ConstructorElement>[];
41 bool hasUnnamedConstructorChange = false;
42
43 final List<MethodElement> addedMethods = <MethodElement>[];
44 final List<MethodElement> removedMethods = <MethodElement>[];
45
46 ClassElementDelta(this._element, this.librarySource, this.name);
47
48 /**
49 * Return `true` if this delta has changes to the [name] visible in the
50 * given [librarySource].
51 */
52 bool hasChanges(Source librarySource, String name) {
53 if (Identifier.isPrivateName(name) && librarySource != this.librarySource) {
54 return false;
55 }
56 return _hasElementWithName(addedAccessors, name) ||
57 _hasElementWithName(removedAccessors, name) ||
58 _hasElementWithName(addedConstructors, name) ||
59 _hasElementWithName(removedConstructors, name) ||
60 _hasElementWithName(addedMethods, name) ||
61 _hasElementWithName(removedMethods, name);
62 }
63
64 static bool _hasElementWithName(List<Element> elements, String name) {
65 return elements.any((e) => e.displayName == name);
66 }
67 }
14 68
15 /** 69 /**
16 * The change of a single [CompilationUnitElement]. 70 * The change of a single [CompilationUnitElement].
17 */ 71 */
18 class CompilationUnitElementDelta { 72 class CompilationUnitElementDelta {
19 /** 73 /**
20 * One or more directives were added/removed. 74 * One or more directives were added/removed.
21 */ 75 */
22 bool hasDirectiveChange = false; 76 bool hasDirectiveChange = false;
23 77
24 /** 78 /**
25 * The list of added top-level element. 79 * The list of added top-level element.
26 */ 80 */
27 final List<Element> addedDeclarations = <Element>[]; 81 final List<Element> addedDeclarations = <Element>[];
28 82
29 /** 83 /**
30 * The list of removed top-level elements. 84 * The list of removed top-level elements.
31 */ 85 */
32 final List<Element> removedDeclarations = <Element>[]; 86 final List<Element> removedDeclarations = <Element>[];
87
88 /**
89 * The map from names of changed classes to the change deltas.
90 */
91 final Map<String, ClassElementDelta> classDeltas =
92 <String, ClassElementDelta>{};
33 } 93 }
34 94
35 /** 95 /**
36 * Incrementally updates the existing [unitElement] and builds elements for 96 * Incrementally updates the existing [unitElement] and builds elements for
37 * the [newUnit]. 97 * the [newUnit].
38 */ 98 */
39 class IncrementalCompilationUnitElementBuilder { 99 class IncrementalCompilationUnitElementBuilder {
40 final Source unitSource; 100 final Source unitSource;
41 final Source librarySource; 101 final Source librarySource;
42 final CompilationUnit oldUnit; 102 final CompilationUnit oldUnit;
43 final CompilationUnitElementImpl unitElement; 103 final CompilationUnitElementImpl unitElement;
44 final CompilationUnit newUnit; 104 final CompilationUnit newUnit;
45 final ElementHolder holder = new ElementHolder(); 105 final ElementHolder unitElementHolder = new ElementHolder();
106
107 final List<ConstantEvaluationTarget> unitConstants =
108 <ConstantEvaluationTarget>[];
46 109
47 /** 110 /**
48 * The change between element models of [oldUnit] and [newUnit]. 111 * The change between element models of [oldUnit] and [newUnit].
49 */ 112 */
50 final CompilationUnitElementDelta unitDelta = 113 final CompilationUnitElementDelta unitDelta =
51 new CompilationUnitElementDelta(); 114 new CompilationUnitElementDelta();
52 115
53 factory IncrementalCompilationUnitElementBuilder( 116 factory IncrementalCompilationUnitElementBuilder(
54 CompilationUnit oldUnit, CompilationUnit newUnit) { 117 CompilationUnit oldUnit, CompilationUnit newUnit) {
55 CompilationUnitElementImpl unitElement = oldUnit.element; 118 CompilationUnitElementImpl unitElement = oldUnit.element;
56 return new IncrementalCompilationUnitElementBuilder._(unitElement.source, 119 return new IncrementalCompilationUnitElementBuilder._(unitElement.source,
57 unitElement.librarySource, oldUnit, newUnit, unitElement); 120 unitElement.librarySource, oldUnit, newUnit, unitElement);
58 } 121 }
59 122
60 IncrementalCompilationUnitElementBuilder._(this.unitSource, 123 IncrementalCompilationUnitElementBuilder._(this.unitSource,
61 this.librarySource, this.oldUnit, this.newUnit, this.unitElement); 124 this.librarySource, this.oldUnit, this.newUnit, this.unitElement);
62 125
63 /** 126 /**
64 * Updates [oldUnit] to have the same directives and declarations, in the 127 * Updates [oldUnit] to have the same directives and declarations, in the
65 * same order as in [newUnit]. Existing resolution is kept where possible. 128 * same order as in [newUnit]. Existing resolution is kept where possible.
66 * 129 *
67 * Updates [unitElement] by adding/removing elements as needed. 130 * Updates [unitElement] by adding/removing elements as needed.
68 * 131 *
69 * Fills [unitDelta] with added/remove elements. 132 * Fills [unitDelta] with added/remove elements.
70 */ 133 */
71 void build() { 134 void build() {
135 _materializeLazyElements();
72 new CompilationUnitBuilder() 136 new CompilationUnitBuilder()
73 .buildCompilationUnit(unitSource, newUnit, librarySource); 137 .buildCompilationUnit(unitSource, newUnit, librarySource);
138 newUnit.accept(new EnumMemberBuilder(unitElement.context.typeProvider));
74 _processDirectives(); 139 _processDirectives();
75 _processUnitMembers(); 140 _processUnitMembers();
141 _replaceUnitContents(oldUnit, newUnit);
142 _findConstants();
76 newUnit.element = unitElement; 143 newUnit.element = unitElement;
77 _replaceUnitContents(oldUnit, newUnit); 144 unitElement.setCodeRange(0, newUnit.endToken.end);
78 } 145 }
79 146
80 void _addElementToHolder(Element element) { 147 void _addElementToUnitHolder(Element element) {
81 if (element is PropertyAccessorElement) { 148 if (element is ClassElement) {
82 holder.addAccessor(element);
83 } else if (element is ClassElement) {
84 if (element.isEnum) { 149 if (element.isEnum) {
85 holder.addEnum(element); 150 unitElementHolder.addEnum(element);
86 } else { 151 } else {
87 holder.addType(element); 152 unitElementHolder.addType(element);
88 } 153 }
89 } else if (element is FunctionElement) { 154 } else if (element is FunctionElement) {
90 holder.addFunction(element); 155 unitElementHolder.addFunction(element);
91 } else if (element is FunctionTypeAliasElement) { 156 } else if (element is FunctionTypeAliasElement) {
92 holder.addTypeAlias(element); 157 unitElementHolder.addTypeAlias(element);
158 } else if (element is PropertyAccessorElement) {
159 unitElementHolder.addAccessor(element);
93 } else if (element is TopLevelVariableElement) { 160 } else if (element is TopLevelVariableElement) {
94 holder.addTopLevelVariable(element); 161 unitElementHolder.addTopLevelVariable(element);
95 } 162 }
163 }
164
165 void _findConstants() {
166 ConstantFinder finder = new ConstantFinder();
167 oldUnit.accept(finder);
168 unitConstants.addAll(finder.constantsToCompute);
169 // Update annotation constants to using the old unit element.
170 for (ConstantEvaluationTarget constant in unitConstants) {
171 if (constant is ElementAnnotationImpl) {
172 constant.compilationUnit = unitElement;
173 }
174 }
175 }
176
177 void _materializeLazyElements() {
178 unitElement.accept(new RecursiveElementVisitor());
179 }
180
181 ClassElementDelta _processClassMembers(
182 ClassDeclaration oldClass, ClassDeclaration newClass) {
183 // If the class hierarchy or type parameters are changed,
184 // then the class changed too much - don't compute the delta.
185 if (newClass.abstractKeyword != null && oldClass.abstractKeyword == null ||
186 newClass.abstractKeyword == null && oldClass.abstractKeyword != null ||
187 TokenUtils.getFullCode(newClass.typeParameters) !=
188 TokenUtils.getFullCode(oldClass.typeParameters) ||
189 TokenUtils.getFullCode(newClass.extendsClause) !=
190 TokenUtils.getFullCode(oldClass.extendsClause) ||
191 TokenUtils.getFullCode(newClass.withClause) !=
192 TokenUtils.getFullCode(oldClass.withClause) ||
193 TokenUtils.getFullCode(newClass.implementsClause) !=
194 TokenUtils.getFullCode(oldClass.implementsClause)) {
195 return null;
196 }
197 // Build the old class members map.
198 Map<String, ClassMember> oldNodeMap = new HashMap<String, ClassMember>();
199 for (ClassMember oldNode in oldClass.members) {
200 String code = TokenUtils.getFullCode(oldNode);
201 oldNodeMap[code] = oldNode;
202 }
203 // Prepare elements.
204 ClassElement newElement = newClass.element;
205 ClassElement oldElement = oldClass.element;
206 // Use the old element for the new node.
207 newClass.name.staticElement = oldElement;
208 if (newElement is ClassElementImpl && oldElement is ClassElementImpl) {
209 oldElement.nameOffset = newElement.nameOffset;
210 oldElement.setCodeRange(newElement.codeOffset, newElement.codeLength);
211 oldElement.typeParameters = newElement.typeParameters;
212 }
213 // Prepare delta.
214 ClassElementImpl classElement = oldClass.element;
215 ElementHolder classElementHolder = new ElementHolder();
216 ClassElementDelta classDelta =
217 new ClassElementDelta(classElement, librarySource, classElement.name);
218 // Check for annotation changes.
219 {
220 String oldAnnotationsCode =
221 TokenUtils.getFullCodeOfList(oldClass.metadata);
222 String newAnnotationsCode =
223 TokenUtils.getFullCodeOfList(newClass.metadata);
224 classDelta.hasAnnotationChanges =
225 oldAnnotationsCode != newAnnotationsCode;
226 }
227 // Prepare all old member elements.
228 var removedAccessors = new Set<PropertyAccessorElement>.identity();
229 var removedConstructors = new Set<ConstructorElement>.identity();
230 var removedMethods = new Set<MethodElement>.identity();
231 removedAccessors.addAll(classElement.accessors);
232 removedConstructors.addAll(classElement.constructors);
233 removedMethods.addAll(classElement.methods);
234 // Utilities.
235 void processConstructorDeclaration(
236 ConstructorDeclaration node, bool isNew) {
237 ConstructorElement element = node.element;
238 if (element != null) {
239 classElementHolder.addConstructor(element);
240 if (isNew) {
241 classDelta.addedConstructors.add(element);
242 } else {
243 removedConstructors.remove(element);
244 }
245 }
246 }
247
248 void processFieldDeclaration(FieldDeclaration node, bool isNew) {
249 for (VariableDeclaration field in node.fields.variables) {
250 PropertyInducingElement element = field.element;
251 if (element != null) {
252 PropertyAccessorElement getter = element.getter;
253 PropertyAccessorElement setter = element.setter;
254 if (getter != null) {
255 classElementHolder.addAccessor(getter);
256 if (isNew) {
257 classDelta.addedAccessors.add(getter);
258 } else {
259 removedAccessors.remove(getter);
260 }
261 }
262 if (setter != null) {
263 classElementHolder.addAccessor(setter);
264 if (isNew) {
265 classDelta.addedAccessors.add(setter);
266 } else {
267 removedAccessors.remove(setter);
268 }
269 }
270 }
271 }
272 }
273
274 void processMethodDeclaration(MethodDeclaration node, bool isNew) {
275 Element element = node.element;
276 if (element is MethodElement) {
277 classElementHolder.addMethod(element);
278 if (isNew) {
279 classDelta.addedMethods.add(element);
280 } else {
281 removedMethods.remove(element);
282 }
283 } else if (element is PropertyAccessorElement) {
284 classElementHolder.addAccessor(element);
285 if (isNew) {
286 classDelta.addedAccessors.add(element);
287 } else {
288 removedAccessors.remove(element);
289 }
290 }
291 }
292
293 // Replace new nodes with the identical old nodes.
294 bool newHasConstructor = false;
295 for (ClassMember newNode in newClass.members) {
296 String code = TokenUtils.getFullCode(newNode);
297 ClassMember oldNode = oldNodeMap.remove(code);
298 // When we type a name before a constructor with a documentation
299 // comment, this makes the comment disappear from AST. So, even though
300 // tokens are the same, the nodes are not the same.
301 if (oldNode != null) {
302 if (oldNode.documentationComment == null &&
303 newNode.documentationComment != null ||
304 oldNode.documentationComment != null &&
305 newNode.documentationComment == null) {
306 oldNode = null;
307 }
308 }
309 // Add the new element.
310 if (oldNode == null) {
311 if (newNode is ConstructorDeclaration) {
312 newHasConstructor = true;
313 processConstructorDeclaration(newNode, true);
314 }
315 if (newNode is FieldDeclaration) {
316 processFieldDeclaration(newNode, true);
317 }
318 if (newNode is MethodDeclaration) {
319 processMethodDeclaration(newNode, true);
320 }
321 continue;
322 }
323 // Do replacement.
324 _replaceNode(newNode, oldNode);
325 if (oldNode is ConstructorDeclaration) {
326 processConstructorDeclaration(oldNode, false);
327 }
328 if (oldNode is FieldDeclaration) {
329 processFieldDeclaration(oldNode, false);
330 }
331 if (oldNode is MethodDeclaration) {
332 processMethodDeclaration(oldNode, false);
333 }
334 }
335 // If the class had only a default synthetic constructor, and there are
336 // no explicit constructors in the new AST, keep the constructor.
337 if (!newHasConstructor) {
338 List<ConstructorElement> constructors = classElement.constructors;
339 if (constructors.length == 1) {
340 ConstructorElement constructor = constructors[0];
341 if (constructor.isSynthetic && constructor.isDefaultConstructor) {
342 classElementHolder.addConstructor(constructor);
343 removedConstructors.remove(constructor);
344 }
345 }
346 }
347 // Update the delta.
348 classDelta.removedAccessors.addAll(removedAccessors);
349 classDelta.removedConstructors.addAll(removedConstructors);
350 classDelta.removedMethods.addAll(removedMethods);
351 // Prepare fields.
352 List<PropertyAccessorElement> newAccessors = classElementHolder.accessors;
353 Map<String, FieldElement> newFields = <String, FieldElement>{};
354 for (PropertyAccessorElement accessor in newAccessors) {
355 newFields[accessor.displayName] = accessor.variable;
356 }
357 // Update references to fields from constructors.
358 for (ClassMember member in newClass.members) {
359 if (member is ConstructorDeclaration) {
360 for (FormalParameter parameter in member.parameters.parameters) {
361 FormalParameter normalParameter = parameter;
362 if (parameter is DefaultFormalParameter) {
363 normalParameter = parameter.parameter;
364 }
365 if (normalParameter is FieldFormalParameter) {
366 FieldFormalParameterElementImpl parameterElement =
367 normalParameter.element as FieldFormalParameterElementImpl;
368 parameterElement.field = newFields[parameterElement.name];
369 }
370 }
371 }
372 }
373 // Update ClassElement.
374 classElement.metadata = newElement.metadata;
375 classElement.accessors = newAccessors;
376 classElement.constructors = classElementHolder.constructors;
377 classElement.fields = newFields.values.toList();
378 classElement.methods = classElementHolder.methods;
379 classElement.version++;
380 classElementHolder.validate();
381 // Ensure at least a default synthetic constructor.
382 if (classElement.constructors.isEmpty) {
383 ConstructorElementImpl constructor =
384 new ConstructorElementImpl.forNode(null);
385 constructor.synthetic = true;
386 classElement.constructors = <ConstructorElement>[constructor];
387 classDelta.addedConstructors.add(constructor);
388 }
389 classDelta.hasUnnamedConstructorChange =
390 classDelta.addedConstructors.any((c) => c.name == '') ||
391 classDelta.removedConstructors.any((c) => c.name == '');
392 // OK
393 return classDelta;
96 } 394 }
97 395
98 void _processDirectives() { 396 void _processDirectives() {
99 Map<String, Directive> oldDirectiveMap = new HashMap<String, Directive>(); 397 Map<String, Directive> oldDirectiveMap = new HashMap<String, Directive>();
100 for (Directive oldDirective in oldUnit.directives) { 398 for (Directive oldDirective in oldUnit.directives) {
101 String code = TokenUtils.getFullCode(oldDirective); 399 String code = TokenUtils.getFullCode(oldDirective);
102 oldDirectiveMap[code] = oldDirective; 400 oldDirectiveMap[code] = oldDirective;
103 } 401 }
104 // Replace new nodes with the identical old nodes. 402 // Replace new nodes with the identical old nodes.
105 Set<Directive> removedDirectives = oldUnit.directives.toSet(); 403 Set<Directive> removedDirectives = oldUnit.directives.toSet();
106 for (Directive newDirective in newUnit.directives) { 404 for (Directive newDirective in newUnit.directives) {
107 String code = TokenUtils.getFullCode(newDirective); 405 String code = TokenUtils.getFullCode(newDirective);
108 // Prepare an old directive. 406 // Prepare an old directive.
109 Directive oldDirective = oldDirectiveMap[code]; 407 Directive oldDirective = oldDirectiveMap[code];
110 if (oldDirective == null) { 408 if (oldDirective == null) {
111 unitDelta.hasDirectiveChange = true; 409 unitDelta.hasDirectiveChange = true;
112 continue; 410 continue;
113 } 411 }
114 // URI's must be resolved to the same sources. 412 // URI's must be resolved to the same sources.
115 if (newDirective is UriBasedDirective && 413 if (newDirective is UriBasedDirective &&
116 oldDirective is UriBasedDirective) { 414 oldDirective is UriBasedDirective) {
117 if (oldDirective.source != newDirective.source) { 415 Source source(UriBasedDirective directive) =>
416 directive is NamespaceDirective
417 ? directive.selectedSource
418 : directive.uriSource;
419 if (source(oldDirective) != source(newDirective)) {
118 continue; 420 continue;
119 } 421 }
120 } 422 }
121 // Do replacement. 423 // Do replacement.
122 _replaceNode(newDirective, oldDirective); 424 _replaceNode(newDirective, oldDirective);
123 removedDirectives.remove(oldDirective); 425 removedDirectives.remove(oldDirective);
124 } 426 }
125 // If there are any directives left, then these directives were removed. 427 // If there are any directives left, then these directives were removed.
126 if (removedDirectives.isNotEmpty) { 428 if (removedDirectives.isNotEmpty) {
127 unitDelta.hasDirectiveChange = true; 429 unitDelta.hasDirectiveChange = true;
128 } 430 }
129 } 431 }
130 432
131 void _processUnitMembers() { 433 void _processUnitMembers() {
132 Map<String, CompilationUnitMember> oldNodeMap = 434 Map<String, CompilationUnitMember> oldNodeMap =
133 new HashMap<String, CompilationUnitMember>(); 435 new HashMap<String, CompilationUnitMember>();
436 Map<String, ClassDeclaration> nameToOldClassMap =
437 new HashMap<String, ClassDeclaration>();
134 for (CompilationUnitMember oldNode in oldUnit.declarations) { 438 for (CompilationUnitMember oldNode in oldUnit.declarations) {
135 String code = TokenUtils.getFullCode(oldNode); 439 String code = TokenUtils.getFullCode(oldNode);
136 oldNodeMap[code] = oldNode; 440 oldNodeMap[code] = oldNode;
441 if (oldNode is ClassDeclaration) {
442 nameToOldClassMap[oldNode.name.name] = oldNode;
443 }
137 } 444 }
138 // Prepare all old top-level elements. 445 // Prepare all old top-level elements.
139 Set<Element> removedElements = new Set<Element>(); 446 Set<Element> removedElements = new Set<Element>();
140 removedElements.addAll(unitElement.accessors); 447 removedElements.addAll(unitElement.accessors);
141 removedElements.addAll(unitElement.enums); 448 removedElements.addAll(unitElement.enums);
142 removedElements.addAll(unitElement.functions); 449 removedElements.addAll(unitElement.functions);
143 removedElements.addAll(unitElement.functionTypeAliases); 450 removedElements.addAll(unitElement.functionTypeAliases);
144 removedElements.addAll(unitElement.types); 451 removedElements.addAll(unitElement.types);
145 removedElements.addAll(unitElement.topLevelVariables); 452 removedElements.addAll(unitElement.topLevelVariables);
146 // Replace new nodes with the identical old nodes. 453 // Replace new nodes with the identical old nodes.
147 for (CompilationUnitMember newNode in newUnit.declarations) { 454 for (CompilationUnitMember newNode in newUnit.declarations) {
148 String code = TokenUtils.getFullCode(newNode); 455 String code = TokenUtils.getFullCode(newNode);
149 // Prepare an old node.
150 CompilationUnitMember oldNode = oldNodeMap[code]; 456 CompilationUnitMember oldNode = oldNodeMap[code];
457 // Add the new element.
151 if (oldNode == null) { 458 if (oldNode == null) {
459 // Compute a delta for the class.
460 if (newNode is ClassDeclaration) {
461 ClassDeclaration oldClass = nameToOldClassMap[newNode.name.name];
462 if (oldClass != null) {
463 ClassElementDelta delta = _processClassMembers(oldClass, newNode);
464 if (delta != null) {
465 unitDelta.classDeltas[delta._element.name] = delta;
466 _addElementToUnitHolder(delta._element);
467 removedElements.remove(delta._element);
468 continue;
469 }
470 }
471 }
472 // Add the new node elements.
152 List<Element> elements = _getElements(newNode); 473 List<Element> elements = _getElements(newNode);
153 elements.forEach(_addElementToHolder); 474 elements.forEach(_addElementToUnitHolder);
154 elements.forEach(unitDelta.addedDeclarations.add); 475 elements.forEach(unitDelta.addedDeclarations.add);
155 continue; 476 continue;
156 } 477 }
157 // Do replacement. 478 // Do replacement.
158 _replaceNode(newNode, oldNode); 479 _replaceNode(newNode, oldNode);
159 List<Element> elements = _getElements(oldNode); 480 List<Element> elements = _getElements(oldNode);
160 elements.forEach(_addElementToHolder); 481 elements.forEach(_addElementToUnitHolder);
161 elements.forEach(removedElements.remove); 482 elements.forEach(removedElements.remove);
162 } 483 }
163 unitDelta.removedDeclarations.addAll(removedElements); 484 unitDelta.removedDeclarations.addAll(removedElements);
164 // Update CompilationUnitElement. 485 // Update CompilationUnitElement.
165 unitElement.accessors = holder.accessors; 486 unitElement.accessors = unitElementHolder.accessors;
166 unitElement.enums = holder.enums; 487 unitElement.enums = unitElementHolder.enums;
167 unitElement.functions = holder.functions; 488 unitElement.functions = unitElementHolder.functions;
168 unitElement.typeAliases = holder.typeAliases; 489 unitElement.typeAliases = unitElementHolder.typeAliases;
169 unitElement.types = holder.types; 490 unitElement.types = unitElementHolder.types;
170 unitElement.topLevelVariables = holder.topLevelVariables; 491 unitElement.topLevelVariables = unitElementHolder.topLevelVariables;
171 holder.validate(); 492 unitElementHolder.validate();
172 } 493 }
173 494
174 /** 495 /**
175 * Replaces [newNode] with [oldNode], updates tokens and elements. 496 * Replaces [newNode] with [oldNode], updates tokens and elements.
176 * The nodes must have the same tokens, but offsets may be different. 497 * The nodes must have the same tokens, but offsets may be different.
177 */ 498 */
178 void _replaceNode(AstNode newNode, AstNode oldNode) { 499 void _replaceNode(AstNode newNode, AstNode oldNode) {
179 // Replace node. 500 // Replace node.
180 NodeReplacer.replace(newNode, oldNode); 501 NodeReplacer.replace(newNode, oldNode);
181 // Replace tokens. 502 // Replace tokens.
182 { 503 Token oldBeginToken = TokenUtils.getBeginTokenNotComment(oldNode);
183 Token oldBeginToken = TokenUtils.getBeginTokenNotComment(newNode); 504 Token newBeginToken = TokenUtils.getBeginTokenNotComment(newNode);
184 Token newBeginToken = TokenUtils.getBeginTokenNotComment(oldNode); 505 newBeginToken.previous.setNext(oldBeginToken);
185 oldBeginToken.previous.setNext(newBeginToken); 506 oldNode.endToken.setNext(newNode.endToken.next);
186 oldNode.endToken.setNext(newNode.endToken.next);
187 }
188 // Change tokens offsets. 507 // Change tokens offsets.
189 Map<int, int> offsetMap = new HashMap<int, int>(); 508 Map<int, int> offsetMap = new HashMap<int, int>();
190 TokenUtils.copyTokenOffsets(offsetMap, oldNode.beginToken, 509 TokenUtils.copyTokenOffsets(offsetMap, oldBeginToken, newBeginToken,
191 newNode.beginToken, oldNode.endToken, newNode.endToken, true); 510 oldNode.endToken, newNode.endToken);
192 // Change elements offsets. 511 // Change elements offsets.
193 { 512 {
194 var visitor = new _UpdateElementOffsetsVisitor(offsetMap); 513 var visitor = new _UpdateElementOffsetsVisitor(offsetMap);
195 List<Element> elements = _getElements(oldNode); 514 List<Element> elements = _getElements(oldNode);
196 for (Element element in elements) { 515 for (Element element in elements) {
197 element.accept(visitor); 516 element.accept(visitor);
198 } 517 }
199 } 518 }
200 } 519 }
201 520
202 /** 521 /**
203 * Returns [Element]s that are declared directly by the given [node]. 522 * Returns [Element]s that are declared directly by the given [node].
204 * This does not include any child elements - parameters, local variables. 523 * This does not include any child elements - parameters, local variables.
205 * 524 *
206 * Usually just one [Element] is returned, but [VariableDeclarationList] 525 * Usually just one [Element] is returned, but [VariableDeclarationList]
207 * nodes may declare more than one. 526 * nodes may declare more than one.
208 */ 527 */
209 static List<Element> _getElements(AstNode node) { 528 static List<Element> _getElements(AstNode node) {
210 List<Element> elements = <Element>[]; 529 List<Element> elements = <Element>[];
211 if (node is TopLevelVariableDeclaration) { 530 void addPropertyAccessors(VariableDeclarationList variableList) {
212 VariableDeclarationList variableList = node.variables;
213 if (variableList != null) { 531 if (variableList != null) {
214 for (VariableDeclaration variable in variableList.variables) { 532 for (VariableDeclaration variable in variableList.variables) {
215 TopLevelVariableElement element = variable.element; 533 PropertyInducingElement element = variable.element;
216 elements.add(element); 534 if (element != null) {
217 if (element.getter != null) { 535 elements.add(element);
218 elements.add(element.getter); 536 if (element.getter != null) {
219 } 537 elements.add(element.getter);
220 if (element.setter != null) { 538 }
221 elements.add(element.setter); 539 if (element.setter != null) {
540 elements.add(element.setter);
541 }
222 } 542 }
223 } 543 }
224 } 544 }
545 }
546
547 if (node is FieldDeclaration) {
548 addPropertyAccessors(node.fields);
549 } else if (node is TopLevelVariableDeclaration) {
550 addPropertyAccessors(node.variables);
225 } else if (node is PartDirective || node is PartOfDirective) { 551 } else if (node is PartDirective || node is PartOfDirective) {
552 // Ignore.
226 } else if (node is Directive && node.element != null) { 553 } else if (node is Directive && node.element != null) {
227 elements.add(node.element); 554 elements.add(node.element);
228 } else if (node is Declaration && node.element != null) { 555 } else if (node is Declaration && node.element != null) {
229 Element element = node.element; 556 Element element = node.element;
230 elements.add(element); 557 elements.add(element);
231 if (element is PropertyAccessorElement) { 558 if (element is PropertyAccessorElement) {
232 elements.add(element.variable); 559 elements.add(element.variable);
233 } 560 }
234 } 561 }
235 return elements; 562 return elements;
236 } 563 }
237 564
238 /** 565 /**
239 * Replaces contents of the [to] unit with the contenxts of the [from] unit. 566 * Replaces contents of the [to] unit with the contexts of the [from] unit.
240 */ 567 */
241 static void _replaceUnitContents(CompilationUnit to, CompilationUnit from) { 568 static void _replaceUnitContents(CompilationUnit to, CompilationUnit from) {
242 to.directives.clear(); 569 to.directives.clear();
243 to.declarations.clear(); 570 to.declarations.clear();
244 to.beginToken = from.beginToken; 571 to.beginToken = from.beginToken;
245 to.scriptTag = from.scriptTag; 572 to.scriptTag = from.scriptTag;
246 to.directives.addAll(from.directives); 573 to.directives.addAll(from.directives);
247 to.declarations.addAll(from.declarations); 574 to.declarations.addAll(from.declarations);
248 to.element = to.element; 575 to.element = to.element;
249 to.lineInfo = from.lineInfo; 576 to.lineInfo = from.lineInfo;
577 to.endToken = from.endToken;
250 } 578 }
251 } 579 }
252 580
253 /** 581 /**
254 * Utilities for [Token] manipulations. 582 * Utilities for [Token] manipulations.
255 */ 583 */
256 class TokenUtils { 584 class TokenUtils {
257 static const String _SEPARATOR = "\uFFFF"; 585 static const String _SEPARATOR = "\uFFFF";
258 586
259 /** 587 /**
260 * Copy offsets from [newToken]s to [oldToken]s. 588 * Copy offsets from [newToken]s to [oldToken]s.
261 */ 589 */
262 static void copyTokenOffsets(Map<int, int> offsetMap, Token oldToken, 590 static void copyTokenOffsets(Map<int, int> offsetMap, Token oldToken,
263 Token newToken, Token oldEndToken, Token newEndToken, 591 Token newToken, Token oldEndToken, Token newEndToken) {
264 [bool goUpComment = false]) {
265 if (oldToken is CommentToken && newToken is CommentToken) { 592 if (oldToken is CommentToken && newToken is CommentToken) {
266 if (goUpComment) { 593 // Update documentation tokens.
267 copyTokenOffsets(offsetMap, (oldToken as CommentToken).parent,
268 (newToken as CommentToken).parent, oldEndToken, newEndToken);
269 }
270 while (oldToken != null) { 594 while (oldToken != null) {
271 offsetMap[oldToken.offset] = newToken.offset; 595 offsetMap[oldToken.offset] = newToken.offset;
596 offsetMap[oldToken.end] = newToken.end;
272 oldToken.offset = newToken.offset; 597 oldToken.offset = newToken.offset;
598 // Update (otherwise unlinked) reference tokens in documentation.
599 if (oldToken is DocumentationCommentToken &&
600 newToken is DocumentationCommentToken) {
601 List<Token> oldReferences = oldToken.references;
602 List<Token> newReferences = newToken.references;
603 assert(oldReferences.length == newReferences.length);
604 for (int i = 0; i < oldReferences.length; i++) {
605 Token oldToken = oldReferences[i];
606 Token newToken = newReferences[i];
607 // For [new Name] the 'Name' token is the reference.
608 // But we need to process all tokens, including 'new'.
609 while (oldToken.previous != null &&
610 oldToken.previous.type != TokenType.EOF) {
611 oldToken = oldToken.previous;
612 }
613 while (newToken.previous != null &&
614 newToken.previous.type != TokenType.EOF) {
615 newToken = newToken.previous;
616 }
617 copyTokenOffsets(
618 offsetMap, oldToken, newToken, oldEndToken, newEndToken);
619 }
620 }
621 // Next tokens.
273 oldToken = oldToken.next; 622 oldToken = oldToken.next;
274 newToken = newToken.next; 623 newToken = newToken.next;
275 } 624 }
276 assert(oldToken == null); 625 assert(oldToken == null);
277 assert(newToken == null); 626 assert(newToken == null);
278 return; 627 return;
279 } 628 }
280 while (true) { 629 while (true) {
281 if (oldToken.precedingComments != null) { 630 if (oldToken.precedingComments != null) {
282 assert(newToken.precedingComments != null); 631 assert(newToken.precedingComments != null);
283 copyTokenOffsets(offsetMap, oldToken.precedingComments, 632 copyTokenOffsets(offsetMap, oldToken.precedingComments,
284 newToken.precedingComments, oldEndToken, newEndToken); 633 newToken.precedingComments, oldEndToken, newEndToken);
285 } 634 }
286 offsetMap[oldToken.offset] = newToken.offset; 635 offsetMap[oldToken.offset] = newToken.offset;
636 offsetMap[oldToken.end] = newToken.end;
287 oldToken.offset = newToken.offset; 637 oldToken.offset = newToken.offset;
638 if (oldToken.type == TokenType.EOF) {
639 assert(newToken.type == TokenType.EOF);
640 break;
641 }
288 if (oldToken == oldEndToken) { 642 if (oldToken == oldEndToken) {
289 assert(newToken == newEndToken); 643 assert(newToken == newEndToken);
290 break; 644 break;
291 } 645 }
292 oldToken = oldToken.next; 646 oldToken = oldToken.next;
293 newToken = newToken.next; 647 newToken = newToken.next;
294 } 648 }
295 } 649 }
296 650
297 static Token getBeginTokenNotComment(AstNode node) { 651 static Token getBeginTokenNotComment(AstNode node) {
298 Token oldBeginToken = node.beginToken; 652 Token oldBeginToken = node.beginToken;
299 if (oldBeginToken is CommentToken) { 653 if (oldBeginToken is CommentToken) {
300 oldBeginToken = (oldBeginToken as CommentToken).parent; 654 return oldBeginToken.parent;
301 } 655 }
302 return oldBeginToken; 656 return oldBeginToken;
303 } 657 }
304 658
305 /** 659 /**
306 * Return the token string of all the [node] tokens. 660 * Return the token string of all the [node].
307 */ 661 */
308 static String getFullCode(AstNode node) { 662 static String getFullCode(AstNode node) {
663 if (node == null) {
664 return '';
665 }
309 List<Token> tokens = getTokens(node); 666 List<Token> tokens = getTokens(node);
310 return joinTokens(tokens); 667 return joinTokens(tokens);
311 } 668 }
312 669
313 /** 670 /**
314 * Returns all tokends (including comments) of the given [node]. 671 * Return the token string of all the [nodes].
672 */
673 static String getFullCodeOfList(List<AstNode> nodes) {
674 if (nodes == null) {
675 return '';
676 }
677 return nodes.map(getFullCode).join(_SEPARATOR);
678 }
679
680 /**
681 * Returns all tokens (including comments) of the given [node].
315 */ 682 */
316 static List<Token> getTokens(AstNode node) { 683 static List<Token> getTokens(AstNode node) {
317 List<Token> tokens = <Token>[]; 684 List<Token> tokens = <Token>[];
318 Token token = getBeginTokenNotComment(node); 685 Token token = getBeginTokenNotComment(node);
319 Token endToken = node.endToken; 686 Token endToken = node.endToken;
320 while (true) { 687 while (true) {
688 // stop if past the end token
689 if (token.offset > endToken.end) {
690 break;
691 }
321 // append comment tokens 692 // append comment tokens
322 for (Token commentToken = token.precedingComments; 693 for (Token commentToken = token.precedingComments;
323 commentToken != null; 694 commentToken != null;
324 commentToken = commentToken.next) { 695 commentToken = commentToken.next) {
325 tokens.add(commentToken); 696 tokens.add(commentToken);
326 } 697 }
327 // append token 698 // append token
328 tokens.add(token); 699 tokens.add(token);
329 // next token 700 // next token
330 if (token == endToken) { 701 if (token == endToken) {
(...skipping 11 matching lines...) Expand all
342 713
343 /** 714 /**
344 * Updates name offsets of [Element]s according to the [map]. 715 * Updates name offsets of [Element]s according to the [map].
345 */ 716 */
346 class _UpdateElementOffsetsVisitor extends GeneralizingElementVisitor { 717 class _UpdateElementOffsetsVisitor extends GeneralizingElementVisitor {
347 final Map<int, int> map; 718 final Map<int, int> map;
348 719
349 _UpdateElementOffsetsVisitor(this.map); 720 _UpdateElementOffsetsVisitor(this.map);
350 721
351 void visitElement(Element element) { 722 void visitElement(Element element) {
352 if (element is CompilationUnitElement) { 723 if (element is ElementImpl) {
353 return; 724 // name offset
725 {
726 int oldOffset = element.nameOffset;
727 int newOffset = map[oldOffset];
728 // Some synthetic elements have new offsets, e.g. synthetic accessors
729 // of property inducing elements. But some are purely synthetic, e.g.
730 // synthetic enum fields and their accessors.
731 // PrefixElement(s) can be shared between import directives, so
732 // their name offsets are outside of the second and subsequent import
733 // directives. But we update the name offsets while visiting the first
734 // import directive.
735 if (newOffset == null) {
736 assert(element.isSynthetic || element is PrefixElement);
737 return;
738 }
739 element.nameOffset = newOffset;
740 }
741 // stop here for LibraryElement
742 if (element is LibraryElementImpl) {
743 return;
744 }
745 // code range
746 {
747 int oldOffset = element.codeOffset;
748 if (oldOffset != null) {
749 int oldEnd = oldOffset + element.codeLength;
750 int newOffset = map[oldOffset];
751 int newEnd = map[oldEnd];
752 assert(newOffset != null);
753 assert(newEnd != null);
754 int newLength = newEnd - newOffset;
755 element.setCodeRange(newOffset, newLength);
756 }
757 }
758 // visible range
759 if (element is LocalElement) {
760 SourceRange oldVisibleRange = (element as LocalElement).visibleRange;
761 if (oldVisibleRange != null) {
762 int oldOffset = oldVisibleRange.offset;
763 int oldLength = oldVisibleRange.length;
764 int oldEnd = oldOffset + oldLength;
765 int newOffset = map[oldOffset];
766 int newEnd = map[oldEnd];
767 assert(newOffset != null);
768 assert(newEnd != null);
769 int newLength = newEnd - newOffset;
770 if (newOffset != oldOffset || newLength != oldLength) {
771 if (element is FunctionElementImpl) {
772 element.setVisibleRange(newOffset, newLength);
773 } else if (element is LocalVariableElementImpl) {
774 element.setVisibleRange(newOffset, newLength);
775 } else if (element is ParameterElementImpl) {
776 element.setVisibleRange(newOffset, newLength);
777 }
778 }
779 }
780 }
354 } 781 }
355 if (element.isSynthetic) { 782 super.visitElement(element);
356 return;
357 }
358 int oldOffset = element.nameOffset;
359 int newOffset = map[oldOffset];
360 assert(newOffset != null);
361 (element as ElementImpl).nameOffset = newOffset;
362 if (element is! LibraryElement) {
363 super.visitElement(element);
364 }
365 } 783 }
366 } 784 }
OLDNEW
« 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