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

Side by Side Diff: packages/analyzer/lib/src/generated/incremental_resolver.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) 2014, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2014, 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 engine.incremental_resolver; 5 library analyzer.src.generated.incremental_resolver;
6 6
7 import 'dart:collection'; 7 import 'dart:collection';
8 import 'dart:math' as math; 8 import 'dart:math' as math;
9 9
10 import 'package:analyzer/src/context/cache.dart' 10 import 'package:analyzer/dart/ast/ast.dart';
11 show CacheEntry, Delta, DeltaResult; 11 import 'package:analyzer/dart/ast/token.dart';
12 import 'package:analyzer/dart/element/element.dart';
13 import 'package:analyzer/dart/element/visitor.dart';
14 import 'package:analyzer/error/error.dart';
15 import 'package:analyzer/error/listener.dart';
16 import 'package:analyzer/exception/exception.dart';
17 import 'package:analyzer/src/context/cache.dart';
18 import 'package:analyzer/src/dart/ast/token.dart';
19 import 'package:analyzer/src/dart/ast/utilities.dart';
20 import 'package:analyzer/src/dart/element/builder.dart';
21 import 'package:analyzer/src/dart/element/element.dart';
22 import 'package:analyzer/src/dart/resolver/inheritance_manager.dart';
23 import 'package:analyzer/src/dart/scanner/reader.dart';
24 import 'package:analyzer/src/dart/scanner/scanner.dart';
12 import 'package:analyzer/src/generated/constant.dart'; 25 import 'package:analyzer/src/generated/constant.dart';
26 import 'package:analyzer/src/generated/engine.dart';
27 import 'package:analyzer/src/generated/error_verifier.dart';
28 import 'package:analyzer/src/generated/incremental_logger.dart'
29 show logger, LoggingTimer;
30 import 'package:analyzer/src/generated/parser.dart';
31 import 'package:analyzer/src/generated/resolver.dart';
32 import 'package:analyzer/src/generated/source.dart';
33 import 'package:analyzer/src/generated/utilities_dart.dart';
13 import 'package:analyzer/src/task/dart.dart'; 34 import 'package:analyzer/src/task/dart.dart';
14 import 'package:analyzer/task/dart.dart'; 35 import 'package:analyzer/task/dart.dart';
15 import 'package:analyzer/task/general.dart' show CONTENT, LINE_INFO; 36 import 'package:analyzer/task/general.dart' show CONTENT, LINE_INFO;
16 import 'package:analyzer/task/model.dart' 37 import 'package:analyzer/task/model.dart';
17 show AnalysisTarget, ResultDescriptor, TargetedResult, TaskDescriptor;
18
19 import 'ast.dart';
20 import 'element.dart';
21 import 'engine.dart'
22 show
23 AnalysisContext,
24 AnalysisOptions,
25 CacheState,
26 DartEntry,
27 DataDescriptor,
28 InternalAnalysisContext,
29 RecordingErrorListener,
30 SourceEntry;
31 import 'error.dart';
32 import 'error_verifier.dart';
33 import 'incremental_logger.dart' show logger, LoggingTimer;
34 import 'java_engine.dart';
35 import 'parser.dart';
36 import 'resolver.dart';
37 import 'scanner.dart';
38 import 'source.dart';
39 import 'utilities_dart.dart';
40
41 /**
42 * If `true`, an attempt to resolve API-changing modifications is made.
43 */
44 bool _resolveApiChanges = false;
45
46 /**
47 * This method is used to enable/disable API-changing modifications resolution.
48 */
49 void set test_resolveApiChanges(bool value) {
50 _resolveApiChanges = value;
51 }
52
53 /**
54 * Instances of the class [DeclarationMatcher] determine whether the element
55 * model defined by a given AST structure matches an existing element model.
56 */
57 class DeclarationMatcher extends RecursiveAstVisitor {
58 /**
59 * The libary containing the AST nodes being visited.
60 */
61 LibraryElement _enclosingLibrary;
62
63 /**
64 * The compilation unit containing the AST nodes being visited.
65 */
66 CompilationUnitElement _enclosingUnit;
67
68 /**
69 * The function type alias containing the AST nodes being visited, or `null` i f we are not
70 * in the scope of a function type alias.
71 */
72 FunctionTypeAliasElement _enclosingAlias;
73
74 /**
75 * The class containing the AST nodes being visited, or `null` if we are not
76 * in the scope of a class.
77 */
78 ClassElementImpl _enclosingClass;
79
80 /**
81 * The parameter containing the AST nodes being visited, or `null` if we are n ot in the
82 * scope of a parameter.
83 */
84 ParameterElement _enclosingParameter;
85
86 FieldDeclaration _enclosingFieldNode = null;
87 bool _inTopLevelVariableDeclaration = false;
88
89 /**
90 * Is `true` if the current class declaration has a constructor.
91 */
92 bool _hasConstructor = false;
93
94 /**
95 * A set containing all of the elements in the element model that were defined by the old AST node
96 * corresponding to the AST node being visited.
97 */
98 HashSet<Element> _allElements = new HashSet<Element>();
99
100 /**
101 * A set containing all of the elements were defined in the old element model,
102 * but are not defined in the new element model.
103 */
104 HashSet<Element> _removedElements = new HashSet<Element>();
105
106 /**
107 * A set containing all of the elements are defined in the new element model,
108 * but were not defined in the old element model.
109 */
110 HashSet<Element> _addedElements = new HashSet<Element>();
111
112 /**
113 * Determines how elements model corresponding to the given [node] differs
114 * from the [element].
115 */
116 DeclarationMatchKind matches(AstNode node, Element element) {
117 logger.enter('match $element @ ${element.nameOffset}');
118 try {
119 _captureEnclosingElements(element);
120 _gatherElements(element);
121 node.accept(this);
122 } on _DeclarationMismatchException {
123 return DeclarationMatchKind.MISMATCH;
124 } finally {
125 logger.exit();
126 }
127 // no API changes
128 if (_removedElements.isEmpty && _addedElements.isEmpty) {
129 return DeclarationMatchKind.MATCH;
130 }
131 // simple API change
132 logger.log('_removedElements: $_removedElements');
133 logger.log('_addedElements: $_addedElements');
134 _removedElements.forEach(_removeElement);
135 if (_removedElements.length <= 1 && _addedElements.length == 1) {
136 return DeclarationMatchKind.MISMATCH_OK;
137 }
138 // something more complex
139 return DeclarationMatchKind.MISMATCH;
140 }
141
142 @override
143 visitBlockFunctionBody(BlockFunctionBody node) {
144 // ignore bodies
145 }
146
147 @override
148 visitClassDeclaration(ClassDeclaration node) {
149 String name = node.name.name;
150 ClassElement element = _findElement(_enclosingUnit.types, name);
151 _enclosingClass = element;
152 _processElement(element);
153 _assertSameAnnotations(node, element);
154 _assertSameTypeParameters(node.typeParameters, element.typeParameters);
155 // check for missing clauses
156 if (node.extendsClause == null) {
157 _assertTrue(element.supertype.name == 'Object');
158 }
159 if (node.implementsClause == null) {
160 _assertTrue(element.interfaces.isEmpty);
161 }
162 if (node.withClause == null) {
163 _assertTrue(element.mixins.isEmpty);
164 }
165 // process clauses and members
166 _hasConstructor = false;
167 super.visitClassDeclaration(node);
168 // process default constructor
169 if (!_hasConstructor) {
170 ConstructorElement constructor = element.unnamedConstructor;
171 _processElement(constructor);
172 if (!constructor.isSynthetic) {
173 _assertEquals(constructor.parameters.length, 0);
174 }
175 }
176 }
177
178 @override
179 visitClassTypeAlias(ClassTypeAlias node) {
180 String name = node.name.name;
181 ClassElement element = _findElement(_enclosingUnit.types, name);
182 _enclosingClass = element;
183 _processElement(element);
184 _assertSameTypeParameters(node.typeParameters, element.typeParameters);
185 super.visitClassTypeAlias(node);
186 }
187
188 @override
189 visitCompilationUnit(CompilationUnit node) {
190 _processElement(_enclosingUnit);
191 super.visitCompilationUnit(node);
192 }
193
194 @override
195 visitConstructorDeclaration(ConstructorDeclaration node) {
196 _hasConstructor = true;
197 SimpleIdentifier constructorName = node.name;
198 ConstructorElementImpl element = constructorName == null
199 ? _enclosingClass.unnamedConstructor
200 : _enclosingClass.getNamedConstructor(constructorName.name);
201 _processElement(element);
202 _assertEquals(node.constKeyword != null, element.isConst);
203 _assertEquals(node.factoryKeyword != null, element.isFactory);
204 _assertCompatibleParameters(node.parameters, element.parameters);
205 // matches, update the existing element
206 ExecutableElement newElement = node.element;
207 node.element = element;
208 _setLocalElements(element, newElement);
209 }
210
211 @override
212 visitEnumConstantDeclaration(EnumConstantDeclaration node) {
213 String name = node.name.name;
214 FieldElement element = _findElement(_enclosingClass.fields, name);
215 _processElement(element);
216 }
217
218 @override
219 visitEnumDeclaration(EnumDeclaration node) {
220 String name = node.name.name;
221 ClassElement element = _findElement(_enclosingUnit.enums, name);
222 _enclosingClass = element;
223 _processElement(element);
224 _assertTrue(element.isEnum);
225 super.visitEnumDeclaration(node);
226 }
227
228 @override
229 visitExportDirective(ExportDirective node) {
230 String uri = _getStringValue(node.uri);
231 if (uri != null) {
232 ExportElement element =
233 _findUriReferencedElement(_enclosingLibrary.exports, uri);
234 _processElement(element);
235 _assertCombinators(node.combinators, element.combinators);
236 }
237 }
238
239 @override
240 visitExpressionFunctionBody(ExpressionFunctionBody node) {
241 // ignore bodies
242 }
243
244 @override
245 visitExtendsClause(ExtendsClause node) {
246 _assertSameType(node.superclass, _enclosingClass.supertype);
247 }
248
249 @override
250 visitFieldDeclaration(FieldDeclaration node) {
251 _enclosingFieldNode = node;
252 try {
253 super.visitFieldDeclaration(node);
254 } finally {
255 _enclosingFieldNode = null;
256 }
257 }
258
259 @override
260 visitFunctionDeclaration(FunctionDeclaration node) {
261 // prepare element name
262 String name = node.name.name;
263 if (node.isSetter) {
264 name += '=';
265 }
266 // prepare element
267 Token property = node.propertyKeyword;
268 ExecutableElementImpl element;
269 if (property == null) {
270 element = _findElement(_enclosingUnit.functions, name);
271 } else {
272 element = _findElement(_enclosingUnit.accessors, name);
273 }
274 // process element
275 _processElement(element);
276 _assertSameAnnotations(node, element);
277 _assertFalse(element.isSynthetic);
278 _assertSameType(node.returnType, element.returnType);
279 _assertCompatibleParameters(
280 node.functionExpression.parameters, element.parameters);
281 _assertBody(node.functionExpression.body, element);
282 // matches, update the existing element
283 ExecutableElement newElement = node.element;
284 node.name.staticElement = element;
285 node.functionExpression.element = element;
286 _setLocalElements(element, newElement);
287 }
288
289 @override
290 visitFunctionTypeAlias(FunctionTypeAlias node) {
291 String name = node.name.name;
292 FunctionTypeAliasElement element =
293 _findElement(_enclosingUnit.functionTypeAliases, name);
294 _processElement(element);
295 _assertSameTypeParameters(node.typeParameters, element.typeParameters);
296 _assertSameType(node.returnType, element.returnType);
297 _assertCompatibleParameters(node.parameters, element.parameters);
298 }
299
300 @override
301 visitImplementsClause(ImplementsClause node) {
302 List<TypeName> nodes = node.interfaces;
303 List<InterfaceType> types = _enclosingClass.interfaces;
304 _assertSameTypes(nodes, types);
305 }
306
307 @override
308 visitImportDirective(ImportDirective node) {
309 String uri = _getStringValue(node.uri);
310 if (uri != null) {
311 ImportElement element =
312 _findUriReferencedElement(_enclosingLibrary.imports, uri);
313 _processElement(element);
314 // match the prefix
315 SimpleIdentifier prefixNode = node.prefix;
316 PrefixElement prefixElement = element.prefix;
317 if (prefixNode == null) {
318 _assertNull(prefixElement);
319 } else {
320 _assertNotNull(prefixElement);
321 _assertEquals(prefixNode.name, prefixElement.name);
322 }
323 // match combinators
324 _assertCombinators(node.combinators, element.combinators);
325 }
326 }
327
328 @override
329 visitMethodDeclaration(MethodDeclaration node) {
330 // prepare element name
331 String name = node.name.name;
332 if (name == TokenType.MINUS.lexeme &&
333 node.parameters.parameters.length == 0) {
334 name = "unary-";
335 }
336 if (node.isSetter) {
337 name += '=';
338 }
339 // prepare element
340 Token property = node.propertyKeyword;
341 ExecutableElementImpl element;
342 if (property == null) {
343 element = _findElement(_enclosingClass.methods, name);
344 } else {
345 element = _findElement(_enclosingClass.accessors, name);
346 }
347 // process element
348 ExecutableElement newElement = node.element;
349 try {
350 _assertNotNull(element);
351 _assertSameAnnotations(node, element);
352 _assertEquals(node.isStatic, element.isStatic);
353 _assertSameType(node.returnType, element.returnType);
354 _assertCompatibleParameters(node.parameters, element.parameters);
355 _assertBody(node.body, element);
356 _removedElements.remove(element);
357 // matches, update the existing element
358 node.name.staticElement = element;
359 _setLocalElements(element, newElement);
360 } on _DeclarationMismatchException {
361 _removeElement(element);
362 // add new element
363 if (newElement != null) {
364 _addedElements.add(newElement);
365 if (newElement is MethodElement) {
366 List<MethodElement> methods = _enclosingClass.methods;
367 methods.add(newElement);
368 _enclosingClass.methods = methods;
369 } else {
370 List<PropertyAccessorElement> accessors = _enclosingClass.accessors;
371 accessors.add(newElement);
372 _enclosingClass.accessors = accessors;
373 }
374 }
375 }
376 }
377
378 @override
379 visitPartDirective(PartDirective node) {
380 String uri = _getStringValue(node.uri);
381 if (uri != null) {
382 CompilationUnitElement element =
383 _findUriReferencedElement(_enclosingLibrary.parts, uri);
384 _processElement(element);
385 }
386 super.visitPartDirective(node);
387 }
388
389 @override
390 visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) {
391 _inTopLevelVariableDeclaration = true;
392 try {
393 super.visitTopLevelVariableDeclaration(node);
394 } finally {
395 _inTopLevelVariableDeclaration = false;
396 }
397 }
398
399 @override
400 visitVariableDeclaration(VariableDeclaration node) {
401 // prepare variable
402 String name = node.name.name;
403 PropertyInducingElement element;
404 if (_inTopLevelVariableDeclaration) {
405 element = _findElement(_enclosingUnit.topLevelVariables, name);
406 } else {
407 element = _findElement(_enclosingClass.fields, name);
408 }
409 // verify
410 PropertyInducingElement newElement = node.name.staticElement;
411 _processElement(element);
412 _assertSameAnnotations(node, element);
413 _assertEquals(node.isConst, element.isConst);
414 _assertEquals(node.isFinal, element.isFinal);
415 if (_enclosingFieldNode != null) {
416 _assertEquals(_enclosingFieldNode.isStatic, element.isStatic);
417 }
418 _assertSameType(
419 (node.parent as VariableDeclarationList).type, element.type);
420 // matches, restore the existing element
421 node.name.staticElement = element;
422 if (element is VariableElementImpl) {
423 (element as VariableElementImpl).initializer = newElement.initializer;
424 }
425 }
426
427 @override
428 visitWithClause(WithClause node) {
429 List<TypeName> nodes = node.mixinTypes;
430 List<InterfaceType> types = _enclosingClass.mixins;
431 _assertSameTypes(nodes, types);
432 }
433
434 /**
435 * Assert that the given [body] is compatible with the given [element].
436 * It should not be empty if the [element] is not an abstract class member.
437 * If it is present, it should have the same async / generator modifiers.
438 */
439 void _assertBody(FunctionBody body, ExecutableElementImpl element) {
440 if (body is EmptyFunctionBody) {
441 _assertTrue(element.isAbstract);
442 } else {
443 _assertFalse(element.isAbstract);
444 _assertEquals(body.isSynchronous, element.isSynchronous);
445 _assertEquals(body.isGenerator, element.isGenerator);
446 }
447 }
448
449 void _assertCombinators(List<Combinator> nodeCombinators,
450 List<NamespaceCombinator> elementCombinators) {
451 // prepare shown/hidden names in the element
452 Set<String> showNames = new Set<String>();
453 Set<String> hideNames = new Set<String>();
454 for (NamespaceCombinator combinator in elementCombinators) {
455 if (combinator is ShowElementCombinator) {
456 showNames.addAll(combinator.shownNames);
457 } else if (combinator is HideElementCombinator) {
458 hideNames.addAll(combinator.hiddenNames);
459 }
460 }
461 // match combinators with the node
462 for (Combinator combinator in nodeCombinators) {
463 if (combinator is ShowCombinator) {
464 for (SimpleIdentifier nameNode in combinator.shownNames) {
465 String name = nameNode.name;
466 _assertTrue(showNames.remove(name));
467 }
468 } else if (combinator is HideCombinator) {
469 for (SimpleIdentifier nameNode in combinator.hiddenNames) {
470 String name = nameNode.name;
471 _assertTrue(hideNames.remove(name));
472 }
473 }
474 }
475 _assertTrue(showNames.isEmpty);
476 _assertTrue(hideNames.isEmpty);
477 }
478
479 void _assertCompatibleParameter(
480 FormalParameter node, ParameterElement element) {
481 _assertEquals(node.kind, element.parameterKind);
482 if (node.kind == ParameterKind.NAMED) {
483 _assertEquals(node.identifier.name, element.name);
484 }
485 // check parameter type specific properties
486 if (node is DefaultFormalParameter) {
487 Expression nodeDefault = node.defaultValue;
488 if (nodeDefault == null) {
489 _assertNull(element.defaultValueCode);
490 } else {
491 _assertEquals(nodeDefault.toSource(), element.defaultValueCode);
492 }
493 _assertCompatibleParameter(node.parameter, element);
494 } else if (node is FieldFormalParameter) {
495 _assertTrue(element.isInitializingFormal);
496 DartType parameterType = element.type;
497 if (node.type == null && node.parameters == null) {
498 FieldFormalParameterElement parameterElement = element;
499 if (!parameterElement.hasImplicitType) {
500 _assertTrue(parameterType == null || parameterType.isDynamic);
501 }
502 if (parameterElement.field != null) {
503 _assertEquals(node.identifier.name, element.name);
504 }
505 } else {
506 if (node.parameters != null) {
507 _assertTrue(parameterType is FunctionType);
508 FunctionType parameterFunctionType = parameterType;
509 _assertSameType(node.type, parameterFunctionType.returnType);
510 } else {
511 _assertSameType(node.type, parameterType);
512 }
513 }
514 _assertCompatibleParameters(node.parameters, element.parameters);
515 } else if (node is FunctionTypedFormalParameter) {
516 _assertFalse(element.isInitializingFormal);
517 _assertTrue(element.type is FunctionType);
518 FunctionType elementType = element.type;
519 _assertCompatibleParameters(node.parameters, element.parameters);
520 _assertSameType(node.returnType, elementType.returnType);
521 } else if (node is SimpleFormalParameter) {
522 _assertFalse(element.isInitializingFormal);
523 _assertSameType(node.type, element.type);
524 }
525 }
526
527 void _assertCompatibleParameters(
528 FormalParameterList nodes, List<ParameterElement> elements) {
529 if (nodes == null) {
530 return _assertEquals(elements.length, 0);
531 }
532 List<FormalParameter> parameters = nodes.parameters;
533 int length = parameters.length;
534 _assertEquals(length, elements.length);
535 for (int i = 0; i < length; i++) {
536 _assertCompatibleParameter(parameters[i], elements[i]);
537 }
538 }
539
540 /**
541 * Asserts that there is an import with the same prefix as the given
542 * [prefixNode], which exposes the given [element].
543 */
544 void _assertElementVisibleWithPrefix(
545 SimpleIdentifier prefixNode, Element element) {
546 if (prefixNode == null) {
547 return;
548 }
549 String prefixName = prefixNode.name;
550 for (ImportElement import in _enclosingLibrary.imports) {
551 if (import.prefix != null && import.prefix.name == prefixName) {
552 Namespace namespace =
553 new NamespaceBuilder().createImportNamespaceForDirective(import);
554 Iterable<Element> visibleElements = namespace.definedNames.values;
555 if (visibleElements.contains(element)) {
556 return;
557 }
558 }
559 }
560 _assertTrue(false);
561 }
562
563 void _assertEquals(Object a, Object b) {
564 if (a != b) {
565 throw new _DeclarationMismatchException();
566 }
567 }
568
569 void _assertFalse(bool condition) {
570 if (condition) {
571 throw new _DeclarationMismatchException();
572 }
573 }
574
575 void _assertNotNull(Object object) {
576 if (object == null) {
577 throw new _DeclarationMismatchException();
578 }
579 }
580
581 void _assertNull(Object object) {
582 if (object != null) {
583 throw new _DeclarationMismatchException();
584 }
585 }
586
587 void _assertSameAnnotation(Annotation node, ElementAnnotation annotation) {
588 Element element = annotation.element;
589 if (element is ConstructorElement) {
590 _assertTrue(node.name is SimpleIdentifier);
591 _assertNull(node.constructorName);
592 TypeName nodeType = new TypeName(node.name, null);
593 _assertSameType(nodeType, element.returnType);
594 // TODO(scheglov) validate arguments
595 }
596 if (element is PropertyAccessorElement) {
597 _assertTrue(node.name is SimpleIdentifier);
598 String nodeName = node.name.name;
599 String elementName = element.displayName;
600 _assertEquals(nodeName, elementName);
601 }
602 }
603
604 void _assertSameAnnotations(AnnotatedNode node, Element element) {
605 List<Annotation> nodeAnnotaitons = node.metadata;
606 List<ElementAnnotation> elementAnnotations = element.metadata;
607 int length = nodeAnnotaitons.length;
608 _assertEquals(elementAnnotations.length, length);
609 for (int i = 0; i < length; i++) {
610 _assertSameAnnotation(nodeAnnotaitons[i], elementAnnotations[i]);
611 }
612 }
613
614 void _assertSameType(TypeName node, DartType type) {
615 // no type == dynamic
616 if (node == null) {
617 return _assertTrue(type == null || type.isDynamic);
618 }
619 if (type == null) {
620 return _assertTrue(false);
621 }
622 // prepare name
623 SimpleIdentifier prefixIdentifier = null;
624 Identifier nameIdentifier = node.name;
625 if (nameIdentifier is PrefixedIdentifier) {
626 PrefixedIdentifier prefixedIdentifier = nameIdentifier;
627 prefixIdentifier = prefixedIdentifier.prefix;
628 nameIdentifier = prefixedIdentifier.identifier;
629 }
630 String nodeName = nameIdentifier.name;
631 // check specific type kinds
632 if (type is ParameterizedType) {
633 _assertEquals(nodeName, type.name);
634 _assertElementVisibleWithPrefix(prefixIdentifier, type.element);
635 // check arguments
636 TypeArgumentList nodeArgumentList = node.typeArguments;
637 List<DartType> typeArguments = type.typeArguments;
638 if (nodeArgumentList == null) {
639 // Node doesn't have type arguments, so all type arguments of the
640 // element must be "dynamic".
641 for (DartType typeArgument in typeArguments) {
642 _assertTrue(typeArgument.isDynamic);
643 }
644 } else {
645 List<TypeName> nodeArguments = nodeArgumentList.arguments;
646 _assertSameTypes(nodeArguments, typeArguments);
647 }
648 } else if (type is TypeParameterType) {
649 _assertEquals(nodeName, type.name);
650 // TODO(scheglov) it should be possible to rename type parameters
651 } else if (type.isVoid) {
652 _assertEquals(nodeName, 'void');
653 } else if (type.isDynamic) {
654 _assertEquals(nodeName, 'dynamic');
655 } else {
656 // TODO(scheglov) support other types
657 logger.log('node: $node type: $type type.type: ${type.runtimeType}');
658 _assertTrue(false);
659 }
660 }
661
662 void _assertSameTypeParameter(
663 TypeParameter node, TypeParameterElement element) {
664 _assertSameType(node.bound, element.bound);
665 }
666
667 void _assertSameTypeParameters(
668 TypeParameterList nodesList, List<TypeParameterElement> elements) {
669 if (nodesList == null) {
670 return _assertEquals(elements.length, 0);
671 }
672 List<TypeParameter> nodes = nodesList.typeParameters;
673 int length = nodes.length;
674 _assertEquals(length, elements.length);
675 for (int i = 0; i < length; i++) {
676 _assertSameTypeParameter(nodes[i], elements[i]);
677 }
678 }
679
680 void _assertSameTypes(List<TypeName> nodes, List<DartType> types) {
681 int length = nodes.length;
682 _assertEquals(length, types.length);
683 for (int i = 0; i < length; i++) {
684 _assertSameType(nodes[i], types[i]);
685 }
686 }
687
688 void _assertTrue(bool condition) {
689 if (!condition) {
690 throw new _DeclarationMismatchException();
691 }
692 }
693
694 /**
695 * Given that the comparison is to begin with the given [element], capture
696 * the enclosing elements that might be used while performing the comparison.
697 */
698 void _captureEnclosingElements(Element element) {
699 Element parent =
700 element is CompilationUnitElement ? element : element.enclosingElement;
701 while (parent != null) {
702 if (parent is CompilationUnitElement) {
703 _enclosingUnit = parent;
704 _enclosingLibrary = element.library;
705 } else if (parent is ClassElement) {
706 if (_enclosingClass == null) {
707 _enclosingClass = parent;
708 }
709 } else if (parent is FunctionTypeAliasElement) {
710 if (_enclosingAlias == null) {
711 _enclosingAlias = parent;
712 }
713 } else if (parent is ParameterElement) {
714 if (_enclosingParameter == null) {
715 _enclosingParameter = parent;
716 }
717 }
718 parent = parent.enclosingElement;
719 }
720 }
721
722 void _gatherElements(Element element) {
723 _ElementsGatherer gatherer = new _ElementsGatherer(this);
724 element.accept(gatherer);
725 // TODO(scheglov) what if a change in a directive?
726 if (identical(element, _enclosingLibrary.definingCompilationUnit)) {
727 gatherer.addElements(_enclosingLibrary.imports);
728 gatherer.addElements(_enclosingLibrary.exports);
729 gatherer.addElements(_enclosingLibrary.parts);
730 }
731 }
732
733 void _processElement(Element element) {
734 _assertNotNull(element);
735 if (!_allElements.contains(element)) {
736 throw new _DeclarationMismatchException();
737 }
738 _removedElements.remove(element);
739 }
740
741 void _removeElement(Element element) {
742 if (element != null) {
743 Element enclosingElement = element.enclosingElement;
744 if (element is MethodElement) {
745 ClassElement classElement = enclosingElement;
746 _removeIdenticalElement(classElement.methods, element);
747 } else if (element is PropertyAccessorElement) {
748 if (enclosingElement is ClassElement) {
749 _removeIdenticalElement(enclosingElement.accessors, element);
750 }
751 if (enclosingElement is CompilationUnitElement) {
752 _removeIdenticalElement(enclosingElement.accessors, element);
753 }
754 }
755 }
756 }
757
758 /**
759 * Return the [Element] in [elements] with the given [name].
760 */
761 static Element _findElement(List<Element> elements, String name) {
762 for (Element element in elements) {
763 if (element.name == name) {
764 return element;
765 }
766 }
767 return null;
768 }
769
770 /**
771 * Return the [UriReferencedElement] from [elements] with the given [uri], or
772 * `null` if there is no such element.
773 */
774 static UriReferencedElement _findUriReferencedElement(
775 List<UriReferencedElement> elements, String uri) {
776 for (UriReferencedElement element in elements) {
777 if (element.uri == uri) {
778 return element;
779 }
780 }
781 return null;
782 }
783
784 /**
785 * Return the value of [literal], or `null` if the string is not a constant
786 * string without any string interpolation.
787 */
788 static String _getStringValue(StringLiteral literal) {
789 if (literal is StringInterpolation) {
790 return null;
791 }
792 return literal.stringValue;
793 }
794
795 /**
796 * Removes the first element identical to the given [element] from [elements].
797 */
798 static void _removeIdenticalElement(List elements, Object element) {
799 int length = elements.length;
800 for (int i = 0; i < length; i++) {
801 if (identical(elements[i], element)) {
802 elements.removeAt(i);
803 return;
804 }
805 }
806 }
807
808 static void _setLocalElements(
809 ExecutableElementImpl to, ExecutableElement from) {
810 if (from != null) {
811 to.functions = from.functions;
812 to.labels = from.labels;
813 to.localVariables = from.localVariables;
814 to.parameters = from.parameters;
815 }
816 }
817 }
818
819 /**
820 * Describes how declarations match an existing elements model.
821 */
822 class DeclarationMatchKind {
823 /**
824 * Complete match, no API changes.
825 */
826 static const MATCH = const DeclarationMatchKind('MATCH');
827
828 /**
829 * Has API changes that we might be able to resolve incrementally.
830 */
831 static const MISMATCH_OK = const DeclarationMatchKind('MISMATCH_OK');
832
833 /**
834 * Has API changes that we cannot resolve incrementally.
835 */
836 static const MISMATCH = const DeclarationMatchKind('MISMATCH');
837
838 final String name;
839
840 const DeclarationMatchKind(this.name);
841
842 @override
843 String toString() => name;
844 }
845 38
846 /** 39 /**
847 * The [Delta] implementation used by incremental resolver. 40 * The [Delta] implementation used by incremental resolver.
848 * It keeps Dart results that are either don't change or are updated. 41 * It keeps Dart results that are either don't change or are updated.
849 */ 42 */
850 class IncrementalBodyDelta extends Delta { 43 class IncrementalBodyDelta extends Delta {
851 /** 44 /**
852 * The offset of the changed contents. 45 * The offset of the changed contents.
853 */ 46 */
854 final int updateOffset; 47 final int updateOffset;
(...skipping 12 matching lines...) Expand all
867 * The delta between [updateEndNew] and [updateEndOld]. 60 * The delta between [updateEndNew] and [updateEndOld].
868 */ 61 */
869 final int updateDelta; 62 final int updateDelta;
870 63
871 IncrementalBodyDelta(Source source, this.updateOffset, this.updateEndOld, 64 IncrementalBodyDelta(Source source, this.updateOffset, this.updateEndOld,
872 this.updateEndNew, this.updateDelta) 65 this.updateEndNew, this.updateDelta)
873 : super(source); 66 : super(source);
874 67
875 @override 68 @override
876 DeltaResult validate(InternalAnalysisContext context, AnalysisTarget target, 69 DeltaResult validate(InternalAnalysisContext context, AnalysisTarget target,
877 ResultDescriptor descriptor) { 70 ResultDescriptor descriptor, Object value) {
878 // A body change delta should never leak outside its source. 71 // A body change delta should never leak outside its source.
879 // It can cause invalidation of results (e.g. hints) in other sources, 72 // It can cause invalidation of results (e.g. hints) in other sources,
880 // but only when a result in the updated source is INVALIDATE_NO_DELTA. 73 // but only when a result in the updated source is INVALIDATE_NO_DELTA.
881 if (target.source != source) { 74 if (target.source != source) {
882 return DeltaResult.STOP; 75 return DeltaResult.STOP;
883 } 76 }
884 // don't invalidate results of standard Dart tasks 77 // don't invalidate results of standard Dart tasks
885 bool isByTask(TaskDescriptor taskDescriptor) { 78 bool isByTask(TaskDescriptor taskDescriptor) {
886 return taskDescriptor.results.contains(descriptor); 79 return taskDescriptor.results.contains(descriptor);
887 } 80 }
81
888 if (descriptor == CONTENT) { 82 if (descriptor == CONTENT) {
889 return DeltaResult.KEEP_CONTINUE; 83 return DeltaResult.KEEP_CONTINUE;
890 } 84 }
891 if (target is LibrarySpecificUnit && target.unit != source) { 85 if (target is LibrarySpecificUnit && target.unit != source) {
892 if (isByTask(GatherUsedLocalElementsTask.DESCRIPTOR) || 86 if (isByTask(GatherUsedLocalElementsTask.DESCRIPTOR) ||
893 isByTask(GatherUsedImportedElementsTask.DESCRIPTOR)) { 87 isByTask(GatherUsedImportedElementsTask.DESCRIPTOR)) {
894 return DeltaResult.KEEP_CONTINUE; 88 return DeltaResult.KEEP_CONTINUE;
895 } 89 }
896 } 90 }
897 if (isByTask(BuildCompilationUnitElementTask.DESCRIPTOR) || 91 if (isByTask(BuildCompilationUnitElementTask.DESCRIPTOR) ||
898 isByTask(BuildDirectiveElementsTask.DESCRIPTOR) || 92 isByTask(BuildDirectiveElementsTask.DESCRIPTOR) ||
899 isByTask(BuildEnumMemberElementsTask.DESCRIPTOR) || 93 isByTask(BuildEnumMemberElementsTask.DESCRIPTOR) ||
900 isByTask(BuildExportNamespaceTask.DESCRIPTOR) || 94 isByTask(BuildExportNamespaceTask.DESCRIPTOR) ||
901 isByTask(BuildLibraryElementTask.DESCRIPTOR) || 95 isByTask(BuildLibraryElementTask.DESCRIPTOR) ||
902 isByTask(BuildPublicNamespaceTask.DESCRIPTOR) || 96 isByTask(BuildPublicNamespaceTask.DESCRIPTOR) ||
903 isByTask(BuildSourceExportClosureTask.DESCRIPTOR) || 97 isByTask(BuildSourceExportClosureTask.DESCRIPTOR) ||
904 isByTask(BuildSourceImportExportClosureTask.DESCRIPTOR) ||
905 isByTask(ComputeConstantDependenciesTask.DESCRIPTOR) || 98 isByTask(ComputeConstantDependenciesTask.DESCRIPTOR) ||
906 isByTask(ComputeConstantValueTask.DESCRIPTOR) || 99 isByTask(ComputeConstantValueTask.DESCRIPTOR) ||
100 isByTask(ComputeInferableStaticVariableDependenciesTask.DESCRIPTOR) ||
907 isByTask(ComputeLibraryCycleTask.DESCRIPTOR) || 101 isByTask(ComputeLibraryCycleTask.DESCRIPTOR) ||
908 isByTask(DartErrorsTask.DESCRIPTOR) || 102 isByTask(DartErrorsTask.DESCRIPTOR) ||
103 isByTask(ReadyLibraryElement2Task.DESCRIPTOR) ||
104 isByTask(ReadyLibraryElement5Task.DESCRIPTOR) ||
105 isByTask(ReadyLibraryElement7Task.DESCRIPTOR) ||
106 isByTask(ReadyResolvedUnitTask.DESCRIPTOR) ||
909 isByTask(EvaluateUnitConstantsTask.DESCRIPTOR) || 107 isByTask(EvaluateUnitConstantsTask.DESCRIPTOR) ||
910 isByTask(GenerateHintsTask.DESCRIPTOR) || 108 isByTask(GenerateHintsTask.DESCRIPTOR) ||
911 isByTask(InferInstanceMembersInUnitTask.DESCRIPTOR) || 109 isByTask(InferInstanceMembersInUnitTask.DESCRIPTOR) ||
912 isByTask(InferStaticVariableTypesInUnitTask.DESCRIPTOR) || 110 isByTask(InferStaticVariableTypesInUnitTask.DESCRIPTOR) ||
111 isByTask(InferStaticVariableTypeTask.DESCRIPTOR) ||
913 isByTask(LibraryErrorsReadyTask.DESCRIPTOR) || 112 isByTask(LibraryErrorsReadyTask.DESCRIPTOR) ||
914 isByTask(LibraryUnitErrorsTask.DESCRIPTOR) || 113 isByTask(LibraryUnitErrorsTask.DESCRIPTOR) ||
915 isByTask(ParseDartTask.DESCRIPTOR) || 114 isByTask(ParseDartTask.DESCRIPTOR) ||
916 isByTask(PartiallyResolveUnitReferencesTask.DESCRIPTOR) || 115 isByTask(PartiallyResolveUnitReferencesTask.DESCRIPTOR) ||
917 isByTask(ScanDartTask.DESCRIPTOR) || 116 isByTask(ScanDartTask.DESCRIPTOR) ||
117 isByTask(ResolveConstantExpressionTask.DESCRIPTOR) ||
118 isByTask(ResolveDirectiveElementsTask.DESCRIPTOR) ||
119 isByTask(ResolvedUnit7InLibraryClosureTask.DESCRIPTOR) ||
120 isByTask(ResolvedUnit7InLibraryTask.DESCRIPTOR) ||
918 isByTask(ResolveInstanceFieldsInUnitTask.DESCRIPTOR) || 121 isByTask(ResolveInstanceFieldsInUnitTask.DESCRIPTOR) ||
919 isByTask(ResolveLibraryReferencesTask.DESCRIPTOR) || 122 isByTask(ResolveLibraryReferencesTask.DESCRIPTOR) ||
123 isByTask(ResolveLibraryTask.DESCRIPTOR) ||
920 isByTask(ResolveLibraryTypeNamesTask.DESCRIPTOR) || 124 isByTask(ResolveLibraryTypeNamesTask.DESCRIPTOR) ||
125 isByTask(ResolveTopLevelLibraryTypeBoundsTask.DESCRIPTOR) ||
126 isByTask(ResolveTopLevelUnitTypeBoundsTask.DESCRIPTOR) ||
921 isByTask(ResolveUnitTask.DESCRIPTOR) || 127 isByTask(ResolveUnitTask.DESCRIPTOR) ||
922 isByTask(ResolveUnitTypeNamesTask.DESCRIPTOR) || 128 isByTask(ResolveUnitTypeNamesTask.DESCRIPTOR) ||
923 isByTask(ResolveVariableReferencesTask.DESCRIPTOR) || 129 isByTask(ResolveVariableReferencesTask.DESCRIPTOR) ||
924 isByTask(StrongModeVerifyUnitTask.DESCRIPTOR) || 130 isByTask(StrongModeVerifyUnitTask.DESCRIPTOR) ||
925 isByTask(VerifyUnitTask.DESCRIPTOR)) { 131 isByTask(VerifyUnitTask.DESCRIPTOR)) {
926 return DeltaResult.KEEP_CONTINUE; 132 return DeltaResult.KEEP_CONTINUE;
927 } 133 }
928 // invalidate all the other results 134 // invalidate all the other results
929 return DeltaResult.INVALIDATE_NO_DELTA; 135 return DeltaResult.INVALIDATE_NO_DELTA;
930 } 136 }
931 } 137 }
932 138
933 /** 139 /**
934 * Instances of the class [IncrementalResolver] resolve the smallest portion of 140 * Instances of the class [IncrementalResolver] resolve the smallest portion of
935 * an AST structure that we currently know how to resolve. 141 * an AST structure that we currently know how to resolve.
936 */ 142 */
937 class IncrementalResolver { 143 class IncrementalResolver {
938 /** 144 /**
939 * The element of the compilation unit being resolved. 145 * The element of the compilation unit being resolved.
940 */ 146 */
941 final CompilationUnitElementImpl _definingUnit; 147 final CompilationUnitElementImpl _definingUnit;
942 148
943 /** 149 /**
944 * The context the compilation unit being resolved in. 150 * The context the compilation unit being resolved in.
945 */ 151 */
946 AnalysisContext _context; 152 final AnalysisContext _context;
947 153
948 /** 154 /**
949 * The object used to access the types from the core library. 155 * The object used to access the types from the core library.
950 */ 156 */
951 TypeProvider _typeProvider; 157 final TypeProvider _typeProvider;
952 158
953 /** 159 /**
954 * The type system primitives. 160 * The type system primitives.
955 */ 161 */
956 TypeSystem _typeSystem; 162 final TypeSystem _typeSystem;
957 163
958 /** 164 /**
959 * The element for the library containing the compilation unit being resolved. 165 * The element for the library containing the compilation unit being resolved.
960 */ 166 */
961 LibraryElementImpl _definingLibrary; 167 final LibraryElementImpl _definingLibrary;
962 168
963 /** 169 final AnalysisCache _cache;
964 * The [DartEntry] corresponding to the source being resolved.
965 */
966 DartEntry oldEntry;
967 170
968 /** 171 /**
969 * The [CacheEntry] corresponding to the source being resolved. 172 * The [CacheEntry] corresponding to the source being resolved.
970 */ 173 */
971 CacheEntry newSourceEntry; 174 final CacheEntry newSourceEntry;
972 175
973 /** 176 /**
974 * The [CacheEntry] corresponding to the [LibrarySpecificUnit] being resolved. 177 * The [CacheEntry] corresponding to the [LibrarySpecificUnit] being resolved.
975 */ 178 */
976 CacheEntry newUnitEntry; 179 final CacheEntry newUnitEntry;
977 180
978 /** 181 /**
979 * The source representing the compilation unit being visited. 182 * The source representing the compilation unit being visited.
980 */ 183 */
981 Source _source; 184 final Source _source;
982 185
983 /** 186 /**
984 * The source representing the library of the compilation unit being visited. 187 * The source representing the library of the compilation unit being visited.
985 */ 188 */
986 Source _librarySource; 189 final Source _librarySource;
987 190
988 /** 191 /**
989 * The offset of the changed contents. 192 * The offset of the changed contents.
990 */ 193 */
991 final int _updateOffset; 194 final int _updateOffset;
992 195
993 /** 196 /**
994 * The end of the changed contents in the old unit. 197 * The end of the changed contents in the old unit.
995 */ 198 */
996 final int _updateEndOld; 199 final int _updateEndOld;
997 200
998 /** 201 /**
999 * The end of the changed contents in the new unit. 202 * The end of the changed contents in the new unit.
1000 */ 203 */
1001 final int _updateEndNew; 204 final int _updateEndNew;
1002 205
1003 /** 206 /**
1004 * The delta between [_updateEndNew] and [_updateEndOld]. 207 * The delta between [_updateEndNew] and [_updateEndOld].
1005 */ 208 */
1006 int _updateDelta; 209 final int _updateDelta;
1007 210
1008 /** 211 /**
1009 * The set of [AnalysisError]s that have been already shifted. 212 * The set of [AnalysisError]s that have been already shifted.
1010 */ 213 */
1011 Set<AnalysisError> _alreadyShiftedErrors = new HashSet.identity(); 214 final Set<AnalysisError> _alreadyShiftedErrors = new HashSet.identity();
1012 215
1013 RecordingErrorListener errorListener = new RecordingErrorListener(); 216 final RecordingErrorListener errorListener = new RecordingErrorListener();
1014 ResolutionContext _resolutionContext; 217 ResolutionContext _resolutionContext;
1015 218
1016 List<AnalysisError> _resolveErrors = AnalysisError.NO_ERRORS; 219 List<AnalysisError> _resolveErrors = AnalysisError.NO_ERRORS;
1017 List<AnalysisError> _verifyErrors = AnalysisError.NO_ERRORS; 220 List<AnalysisError> _verifyErrors = AnalysisError.NO_ERRORS;
1018 221
1019 /** 222 /**
1020 * Initialize a newly created incremental resolver to resolve a node in the 223 * Initialize a newly created incremental resolver to resolve a node in the
1021 * given source in the given library. 224 * given source in the given library.
1022 */ 225 */
1023 IncrementalResolver( 226 IncrementalResolver(
1024 this.oldEntry, 227 this._cache,
1025 this.newSourceEntry, 228 this.newSourceEntry,
1026 this.newUnitEntry, 229 this.newUnitEntry,
1027 this._definingUnit, 230 CompilationUnitElementImpl definingUnit,
1028 this._updateOffset, 231 this._updateOffset,
1029 this._updateEndOld, 232 int updateEndOld,
1030 this._updateEndNew) { 233 int updateEndNew)
1031 _updateDelta = _updateEndNew - _updateEndOld; 234 : _definingUnit = definingUnit,
1032 _definingLibrary = _definingUnit.library; 235 _context = definingUnit.context,
1033 _librarySource = _definingLibrary.source; 236 _typeProvider = definingUnit.context.typeProvider,
1034 _source = _definingUnit.source; 237 _typeSystem = definingUnit.context.typeSystem,
1035 _context = _definingUnit.context; 238 _definingLibrary = definingUnit.library,
1036 _typeProvider = _context.typeProvider; 239 _source = definingUnit.source,
1037 _typeSystem = _context.typeSystem; 240 _librarySource = definingUnit.library.source,
1038 } 241 _updateEndOld = updateEndOld,
242 _updateEndNew = updateEndNew,
243 _updateDelta = updateEndNew - updateEndOld;
1039 244
1040 /** 245 /**
1041 * Resolve [node], reporting any errors or warnings to the given listener. 246 * Resolve [body], reporting any errors or warnings to the given listener.
1042 * 247 *
1043 * [node] - the root of the AST structure to be resolved. 248 * [body] - the root of the AST structure to be resolved.
1044 *
1045 * Returns `true` if resolution was successful.
1046 */ 249 */
1047 bool resolve(AstNode node) { 250 void resolve(BlockFunctionBody body) {
1048 logger.enter('resolve: $_definingUnit'); 251 logger.enter('resolve: $_definingUnit');
1049 try { 252 try {
1050 AstNode rootNode = _findResolutionRoot(node); 253 Declaration executable = _findResolutionRoot(body);
1051 _prepareResolutionContext(rootNode); 254 _prepareResolutionContext(executable);
1052 // update elements 255 // update elements
1053 _updateCache(); 256 _updateCache();
1054 _updateElementNameOffsets(); 257 _updateElementNameOffsets();
1055 _buildElements(rootNode); 258 _buildElements(executable, body);
1056 if (!_canBeIncrementallyResolved(rootNode)) {
1057 return false;
1058 }
1059 // resolve 259 // resolve
1060 _resolveReferences(rootNode); 260 _resolveReferences(executable);
1061 _computeConstants(rootNode); 261 _computeConstants(executable);
1062 _resolveErrors = errorListener.getErrorsForSource(_source); 262 _resolveErrors = errorListener.getErrorsForSource(_source);
1063 // verify 263 // verify
1064 _verify(rootNode); 264 _verify(executable);
1065 _context.invalidateLibraryHints(_librarySource); 265 _context.invalidateLibraryHints(_librarySource);
1066 // update entry errors 266 // update entry errors
1067 _updateEntry(); 267 _updateEntry();
1068 // OK
1069 return true;
1070 } finally { 268 } finally {
1071 logger.exit(); 269 logger.exit();
1072 } 270 }
1073 } 271 }
1074 272
1075 void _buildElements(AstNode node) { 273 void _buildElements(Declaration executable, AstNode node) {
1076 LoggingTimer timer = logger.startTimer(); 274 LoggingTimer timer = logger.startTimer();
1077 try { 275 try {
1078 ElementHolder holder = new ElementHolder(); 276 ElementHolder holder = new ElementHolder();
1079 ElementBuilder builder = new ElementBuilder(holder); 277 ElementBuilder builder = new ElementBuilder(holder, _definingUnit);
1080 if (_resolutionContext.enclosingClassDeclaration != null) { 278 builder.initForFunctionBodyIncrementalResolution();
1081 builder.visitClassDeclarationIncrementally(
1082 _resolutionContext.enclosingClassDeclaration);
1083 }
1084 node.accept(builder); 279 node.accept(builder);
280 // Move local elements into the ExecutableElementImpl.
281 ExecutableElementImpl executableElement =
282 executable.element as ExecutableElementImpl;
283 executableElement.localVariables = holder.localVariables;
284 executableElement.functions = holder.functions;
285 executableElement.labels = holder.labels;
286 holder.validate();
1085 } finally { 287 } finally {
1086 timer.stop('build elements'); 288 timer.stop('build elements');
1087 } 289 }
1088 } 290 }
1089 291
1090 /** 292 /**
1091 * Return `true` if [node] does not have element model changes, or these
1092 * changes can be incrementally propagated.
1093 */
1094 bool _canBeIncrementallyResolved(AstNode node) {
1095 // If we are replacing the whole declaration, this means that its signature
1096 // is changed. It might be an API change, or not.
1097 //
1098 // If, for example, a required parameter is changed, it is not an API
1099 // change, but we want to find the existing corresponding Element in the
1100 // enclosing one, set it for the node and update as needed.
1101 //
1102 // If, for example, the name of a method is changed, it is an API change,
1103 // we need to know the old Element and the new Element. Again, we need to
1104 // check the whole enclosing Element.
1105 if (node is Declaration) {
1106 node = node.parent;
1107 }
1108 Element element = _getElement(node);
1109 DeclarationMatcher matcher = new DeclarationMatcher();
1110 DeclarationMatchKind matchKind = matcher.matches(node, element);
1111 if (matchKind == DeclarationMatchKind.MATCH) {
1112 return true;
1113 }
1114 // mismatch that cannot be incrementally fixed
1115 return false;
1116 }
1117
1118 /**
1119 * Return `true` if the given node can be resolved independently of any other
1120 * nodes.
1121 *
1122 * *Note*: This method needs to be kept in sync with
1123 * [ScopeBuilder.ContextBuilder].
1124 *
1125 * [node] - the node being tested.
1126 */
1127 bool _canBeResolved(AstNode node) => node is ClassDeclaration ||
1128 node is ClassTypeAlias ||
1129 node is CompilationUnit ||
1130 node is ConstructorDeclaration ||
1131 node is FunctionDeclaration ||
1132 node is FunctionTypeAlias ||
1133 node is MethodDeclaration ||
1134 node is TopLevelVariableDeclaration;
1135
1136 /**
1137 * Compute a value for all of the constants in the given [node]. 293 * Compute a value for all of the constants in the given [node].
1138 */ 294 */
1139 void _computeConstants(AstNode node) { 295 void _computeConstants(AstNode node) {
1140 // compute values 296 // compute values
1141 { 297 {
1142 CompilationUnit unit = node.getAncestor((n) => n is CompilationUnit); 298 CompilationUnit unit = node.getAncestor((n) => n is CompilationUnit);
1143 ConstantValueComputer computer = new ConstantValueComputer(_context, 299 ConstantValueComputer computer = new ConstantValueComputer(
1144 _typeProvider, _context.declaredVariables, null, _typeSystem); 300 _typeProvider, _context.declaredVariables, null, _typeSystem);
1145 computer.add(unit, _source, _librarySource); 301 computer.add(unit);
1146 computer.computeValues(); 302 computer.computeValues();
1147 } 303 }
1148 // validate 304 // validate
1149 { 305 {
1150 ErrorReporter errorReporter = new ErrorReporter(errorListener, _source); 306 ErrorReporter errorReporter = new ErrorReporter(errorListener, _source);
1151 ConstantVerifier constantVerifier = new ConstantVerifier(errorReporter, 307 ConstantVerifier constantVerifier = new ConstantVerifier(errorReporter,
1152 _definingLibrary, _typeProvider, _context.declaredVariables); 308 _definingLibrary, _typeProvider, _context.declaredVariables);
1153 node.accept(constantVerifier); 309 node.accept(constantVerifier);
1154 } 310 }
1155 } 311 }
1156 312
1157 /** 313 /**
1158 * Starting at [node], find the smallest AST node that can be resolved 314 * Starting at [node], find the smallest AST node that can be resolved
1159 * independently of any other nodes. Return the node that was found. 315 * independently of any other nodes. Return the node that was found.
1160 * 316 *
1161 * [node] - the node at which the search is to begin 317 * [node] - the node at which the search is to begin
1162 * 318 *
1163 * Throws [AnalysisException] if there is no such node. 319 * Throws [AnalysisException] if there is no such node.
1164 */ 320 */
1165 AstNode _findResolutionRoot(AstNode node) { 321 Declaration _findResolutionRoot(AstNode node) {
1166 while (node != null) { 322 while (node != null) {
1167 if (_canBeResolved(node)) { 323 if (node is ConstructorDeclaration ||
324 node is FunctionDeclaration ||
325 node is MethodDeclaration) {
1168 return node; 326 return node;
1169 } 327 }
1170 node = node.parent; 328 node = node.parent;
1171 } 329 }
1172 throw new AnalysisException("Cannot resolve node: no resolvable node"); 330 throw new AnalysisException("Cannot resolve node: no resolvable node");
1173 } 331 }
1174 332
1175 /**
1176 * Return the element defined by [node], or `null` if the node does not
1177 * define an element.
1178 */
1179 Element _getElement(AstNode node) {
1180 if (node is Declaration) {
1181 return node.element;
1182 } else if (node is CompilationUnit) {
1183 return node.element;
1184 }
1185 return null;
1186 }
1187
1188 void _prepareResolutionContext(AstNode node) { 333 void _prepareResolutionContext(AstNode node) {
1189 if (_resolutionContext == null) { 334 if (_resolutionContext == null) {
1190 _resolutionContext = 335 _resolutionContext = ResolutionContextBuilder.contextFor(node);
1191 ResolutionContextBuilder.contextFor(node, errorListener);
1192 } 336 }
1193 } 337 }
1194 338
1195 _resolveReferences(AstNode node) { 339 _resolveReferences(AstNode node) {
1196 LoggingTimer timer = logger.startTimer(); 340 LoggingTimer timer = logger.startTimer();
1197 try { 341 try {
1198 _prepareResolutionContext(node); 342 _prepareResolutionContext(node);
1199 Scope scope = _resolutionContext.scope; 343 Scope scope = _resolutionContext.scope;
1200 // resolve types 344 // resolve types
1201 { 345 {
(...skipping 24 matching lines...) Expand all
1226 } 370 }
1227 visitor.initForIncrementalResolution(); 371 visitor.initForIncrementalResolution();
1228 node.accept(visitor); 372 node.accept(visitor);
1229 } 373 }
1230 } finally { 374 } finally {
1231 timer.stop('resolve references'); 375 timer.stop('resolve references');
1232 } 376 }
1233 } 377 }
1234 378
1235 void _shiftEntryErrors() { 379 void _shiftEntryErrors() {
1236 if (oldEntry != null) {
1237 _shiftEntryErrors_OLD();
1238 } else {
1239 _shiftEntryErrors_NEW();
1240 }
1241 }
1242
1243 void _shiftEntryErrors_NEW() {
1244 _shiftErrors_NEW(HINTS); 380 _shiftErrors_NEW(HINTS);
1245 _shiftErrors_NEW(LINTS); 381 _shiftErrors_NEW(LINTS);
1246 _shiftErrors_NEW(LIBRARY_UNIT_ERRORS); 382 _shiftErrors_NEW(LIBRARY_UNIT_ERRORS);
1247 _shiftErrors_NEW(RESOLVE_TYPE_NAMES_ERRORS); 383 _shiftErrors_NEW(RESOLVE_TYPE_NAMES_ERRORS);
384 _shiftErrors_NEW(RESOLVE_TYPE_BOUNDS_ERRORS);
1248 _shiftErrors_NEW(RESOLVE_UNIT_ERRORS); 385 _shiftErrors_NEW(RESOLVE_UNIT_ERRORS);
386 _shiftErrors_NEW(STATIC_VARIABLE_RESOLUTION_ERRORS_IN_UNIT);
1249 _shiftErrors_NEW(STRONG_MODE_ERRORS); 387 _shiftErrors_NEW(STRONG_MODE_ERRORS);
1250 _shiftErrors_NEW(VARIABLE_REFERENCE_ERRORS); 388 _shiftErrors_NEW(VARIABLE_REFERENCE_ERRORS);
1251 _shiftErrors_NEW(VERIFY_ERRORS); 389 _shiftErrors_NEW(VERIFY_ERRORS);
1252 } 390 }
1253 391
1254 void _shiftEntryErrors_OLD() {
1255 _shiftErrors_OLD(DartEntry.RESOLUTION_ERRORS);
1256 _shiftErrors_OLD(DartEntry.VERIFICATION_ERRORS);
1257 _shiftErrors_OLD(DartEntry.HINTS);
1258 _shiftErrors_OLD(DartEntry.LINTS);
1259 }
1260
1261 void _shiftErrors(List<AnalysisError> errors) { 392 void _shiftErrors(List<AnalysisError> errors) {
1262 for (AnalysisError error in errors) { 393 for (AnalysisError error in errors) {
1263 if (_alreadyShiftedErrors.add(error)) { 394 if (_alreadyShiftedErrors.add(error)) {
1264 int errorOffset = error.offset; 395 int errorOffset = error.offset;
1265 if (errorOffset > _updateOffset) { 396 if (errorOffset > _updateOffset) {
1266 error.offset += _updateDelta; 397 error.offset += _updateDelta;
1267 } 398 }
1268 } 399 }
1269 } 400 }
1270 } 401 }
1271 402
1272 void _shiftErrors_NEW(ResultDescriptor<List<AnalysisError>> descriptor) { 403 void _shiftErrors_NEW(ResultDescriptor<List<AnalysisError>> descriptor) {
1273 List<AnalysisError> errors = newUnitEntry.getValue(descriptor); 404 List<AnalysisError> errors = newUnitEntry.getValue(descriptor);
1274 _shiftErrors(errors); 405 _shiftErrors(errors);
1275 } 406 }
1276 407
1277 void _shiftErrors_OLD(DataDescriptor<List<AnalysisError>> descriptor) {
1278 List<AnalysisError> errors =
1279 oldEntry.getValueInLibrary(descriptor, _librarySource);
1280 _shiftErrors(errors);
1281 }
1282
1283 void _updateCache() { 408 void _updateCache() {
1284 if (newSourceEntry != null) { 409 if (newSourceEntry != null) {
1285 LoggingTimer timer = logger.startTimer(); 410 LoggingTimer timer = logger.startTimer();
1286 try { 411 try {
1287 newSourceEntry.setState(CONTENT, CacheState.INVALID, 412 newSourceEntry.setState(CONTENT, CacheState.INVALID,
1288 delta: new IncrementalBodyDelta(_source, _updateOffset, 413 delta: new IncrementalBodyDelta(_source, _updateOffset,
1289 _updateEndOld, _updateEndNew, _updateDelta)); 414 _updateEndOld, _updateEndNew, _updateDelta));
1290 } finally { 415 } finally {
1291 timer.stop('invalidate cache with delta'); 416 timer.stop('invalidate cache with delta');
1292 } 417 }
1293 } 418 }
1294 } 419 }
1295 420
1296 void _updateElementNameOffsets() { 421 void _updateElementNameOffsets() {
1297 LoggingTimer timer = logger.startTimer(); 422 LoggingTimer timer = logger.startTimer();
1298 try { 423 try {
1299 _definingUnit 424 _definingUnit.accept(
1300 .accept(new _ElementNameOffsetUpdater(_updateOffset, _updateDelta)); 425 new _ElementOffsetUpdater(_updateOffset, _updateDelta, _cache));
1301 _definingUnit.afterIncrementalResolution(); 426 _definingUnit.afterIncrementalResolution();
1302 } finally { 427 } finally {
1303 timer.stop('update element offsets'); 428 timer.stop('update element offsets');
1304 } 429 }
1305 } 430 }
1306 431
1307 void _updateEntry() { 432 void _updateEntry() {
1308 if (oldEntry != null) {
1309 _updateEntry_OLD();
1310 } else {
1311 _updateEntry_NEW();
1312 }
1313 }
1314
1315 void _updateEntry_NEW() {
1316 _updateErrors_NEW(RESOLVE_TYPE_NAMES_ERRORS, []); 433 _updateErrors_NEW(RESOLVE_TYPE_NAMES_ERRORS, []);
434 _updateErrors_NEW(RESOLVE_TYPE_BOUNDS_ERRORS, []);
1317 _updateErrors_NEW(RESOLVE_UNIT_ERRORS, _resolveErrors); 435 _updateErrors_NEW(RESOLVE_UNIT_ERRORS, _resolveErrors);
1318 _updateErrors_NEW(VARIABLE_REFERENCE_ERRORS, []); 436 _updateErrors_NEW(VARIABLE_REFERENCE_ERRORS, []);
1319 _updateErrors_NEW(VERIFY_ERRORS, _verifyErrors); 437 _updateErrors_NEW(VERIFY_ERRORS, _verifyErrors);
1320 // invalidate results we don't update incrementally 438 // invalidate results we don't update incrementally
1321 newUnitEntry.setState(STRONG_MODE_ERRORS, CacheState.INVALID); 439 newUnitEntry.setState(STRONG_MODE_ERRORS, CacheState.INVALID);
1322 newUnitEntry.setState(USED_IMPORTED_ELEMENTS, CacheState.INVALID); 440 newUnitEntry.setState(USED_IMPORTED_ELEMENTS, CacheState.INVALID);
1323 newUnitEntry.setState(USED_LOCAL_ELEMENTS, CacheState.INVALID); 441 newUnitEntry.setState(USED_LOCAL_ELEMENTS, CacheState.INVALID);
1324 newUnitEntry.setState(HINTS, CacheState.INVALID); 442 newUnitEntry.setState(HINTS, CacheState.INVALID);
1325 newUnitEntry.setState(LINTS, CacheState.INVALID); 443 newUnitEntry.setState(LINTS, CacheState.INVALID);
1326 } 444 }
1327 445
1328 void _updateEntry_OLD() {
1329 _updateErrors_OLD(DartEntry.RESOLUTION_ERRORS, _resolveErrors);
1330 _updateErrors_OLD(DartEntry.VERIFICATION_ERRORS, _verifyErrors);
1331 }
1332
1333 List<AnalysisError> _updateErrors( 446 List<AnalysisError> _updateErrors(
1334 List<AnalysisError> oldErrors, List<AnalysisError> newErrors) { 447 List<AnalysisError> oldErrors, List<AnalysisError> newErrors) {
1335 List<AnalysisError> errors = new List<AnalysisError>(); 448 List<AnalysisError> errors = new List<AnalysisError>();
1336 // add updated old errors 449 // add updated old errors
1337 for (AnalysisError error in oldErrors) { 450 for (AnalysisError error in oldErrors) {
1338 int errorOffset = error.offset; 451 int errorOffset = error.offset;
1339 if (errorOffset < _updateOffset) { 452 if (errorOffset < _updateOffset) {
1340 errors.add(error); 453 errors.add(error);
1341 } else if (errorOffset > _updateEndOld) { 454 } else if (errorOffset > _updateEndOld) {
1342 error.offset += _updateDelta; 455 error.offset += _updateDelta;
(...skipping 11 matching lines...) Expand all
1354 return errors; 467 return errors;
1355 } 468 }
1356 469
1357 void _updateErrors_NEW(ResultDescriptor<List<AnalysisError>> descriptor, 470 void _updateErrors_NEW(ResultDescriptor<List<AnalysisError>> descriptor,
1358 List<AnalysisError> newErrors) { 471 List<AnalysisError> newErrors) {
1359 List<AnalysisError> oldErrors = newUnitEntry.getValue(descriptor); 472 List<AnalysisError> oldErrors = newUnitEntry.getValue(descriptor);
1360 List<AnalysisError> errors = _updateErrors(oldErrors, newErrors); 473 List<AnalysisError> errors = _updateErrors(oldErrors, newErrors);
1361 newUnitEntry.setValueIncremental(descriptor, errors, true); 474 newUnitEntry.setValueIncremental(descriptor, errors, true);
1362 } 475 }
1363 476
1364 void _updateErrors_OLD(DataDescriptor<List<AnalysisError>> descriptor,
1365 List<AnalysisError> newErrors) {
1366 List<AnalysisError> oldErrors =
1367 oldEntry.getValueInLibrary(descriptor, _librarySource);
1368 List<AnalysisError> errors = _updateErrors(oldErrors, newErrors);
1369 oldEntry.setValueInLibrary(descriptor, _librarySource, errors);
1370 }
1371
1372 void _verify(AstNode node) { 477 void _verify(AstNode node) {
1373 LoggingTimer timer = logger.startTimer(); 478 LoggingTimer timer = logger.startTimer();
1374 try { 479 try {
1375 RecordingErrorListener errorListener = new RecordingErrorListener(); 480 RecordingErrorListener errorListener = new RecordingErrorListener();
1376 ErrorReporter errorReporter = new ErrorReporter(errorListener, _source); 481 ErrorReporter errorReporter = new ErrorReporter(errorListener, _source);
1377 ErrorVerifier errorVerifier = new ErrorVerifier( 482 ErrorVerifier errorVerifier = new ErrorVerifier(
1378 errorReporter, 483 errorReporter,
1379 _definingLibrary, 484 _definingLibrary,
1380 _typeProvider, 485 _typeProvider,
1381 new InheritanceManager(_definingLibrary), 486 new InheritanceManager(_definingLibrary),
1382 _context.analysisOptions.enableSuperMixins); 487 _context.analysisOptions.enableSuperMixins,
488 _context.analysisOptions.enableAssertMessage);
1383 if (_resolutionContext.enclosingClassDeclaration != null) { 489 if (_resolutionContext.enclosingClassDeclaration != null) {
1384 errorVerifier.visitClassDeclarationIncrementally( 490 errorVerifier.visitClassDeclarationIncrementally(
1385 _resolutionContext.enclosingClassDeclaration); 491 _resolutionContext.enclosingClassDeclaration);
1386 } 492 }
1387 node.accept(errorVerifier); 493 node.accept(errorVerifier);
1388 _verifyErrors = errorListener.getErrorsForSource(_source); 494 _verifyErrors = errorListener.getErrorsForSource(_source);
1389 } finally { 495 } finally {
1390 timer.stop('verify'); 496 timer.stop('verify');
1391 } 497 }
1392 } 498 }
1393 } 499 }
1394 500
1395 class PoorMansIncrementalResolver { 501 class PoorMansIncrementalResolver {
1396 final TypeProvider _typeProvider; 502 final TypeProvider _typeProvider;
1397 final Source _unitSource; 503 final Source _unitSource;
1398 504 final AnalysisCache _cache;
1399 /**
1400 * The [DartEntry] corresponding to the source being resolved.
1401 */
1402 DartEntry _oldEntry;
1403 505
1404 /** 506 /**
1405 * The [CacheEntry] corresponding to the source being resolved. 507 * The [CacheEntry] corresponding to the source being resolved.
1406 */ 508 */
1407 CacheEntry _newSourceEntry; 509 final CacheEntry _sourceEntry;
1408 510
1409 /** 511 /**
1410 * The [CacheEntry] corresponding to the [LibrarySpecificUnit] being resolved. 512 * The [CacheEntry] corresponding to the [LibrarySpecificUnit] being resolved.
1411 */ 513 */
1412 CacheEntry _newUnitEntry; 514 final CacheEntry _unitEntry;
1413 515
1414 final CompilationUnit _oldUnit; 516 final CompilationUnit _oldUnit;
1415 CompilationUnitElement _unitElement; 517 CompilationUnitElement _unitElement;
1416 518
1417 int _updateOffset; 519 int _updateOffset;
1418 int _updateDelta; 520 int _updateDelta;
1419 int _updateEndOld; 521 int _updateEndOld;
1420 int _updateEndNew; 522 int _updateEndNew;
1421 523
1422 LineInfo _newLineInfo; 524 LineInfo _newLineInfo;
1423 List<AnalysisError> _newScanErrors = <AnalysisError>[]; 525 List<AnalysisError> _newScanErrors = <AnalysisError>[];
1424 List<AnalysisError> _newParseErrors = <AnalysisError>[]; 526 List<AnalysisError> _newParseErrors = <AnalysisError>[];
1425 527
1426 PoorMansIncrementalResolver( 528 PoorMansIncrementalResolver(
1427 this._typeProvider, 529 this._typeProvider,
1428 this._unitSource, 530 this._unitSource,
1429 this._oldEntry, 531 this._cache,
1430 this._newSourceEntry, 532 this._sourceEntry,
1431 this._newUnitEntry, 533 this._unitEntry,
1432 this._oldUnit, 534 this._oldUnit,
1433 bool resolveApiChanges) { 535 bool resolveApiChanges);
1434 _resolveApiChanges = resolveApiChanges;
1435 }
1436 536
1437 /** 537 /**
1438 * Attempts to update [_oldUnit] to the state corresponding to [newCode]. 538 * Attempts to update [_oldUnit] to the state corresponding to [newCode].
1439 * Returns `true` if success, or `false` otherwise. 539 * Returns `true` if success, or `false` otherwise.
1440 * The [_oldUnit] might be damaged. 540 * The [_oldUnit] might be damaged.
1441 */ 541 */
1442 bool resolve(String newCode) { 542 bool resolve(String newCode) {
1443 logger.enter('diff/resolve $_unitSource'); 543 logger.enter('diff/resolve $_unitSource');
1444 try { 544 try {
1445 // prepare old unit 545 // prepare old unit
(...skipping 15 matching lines...) Expand all
1461 _findLastDifferentToken(_oldUnit.endToken, newUnit.endToken); 561 _findLastDifferentToken(_oldUnit.endToken, newUnit.endToken);
1462 if (firstPair != null && lastPair != null) { 562 if (firstPair != null && lastPair != null) {
1463 int firstOffsetOld = firstPair.oldToken.offset; 563 int firstOffsetOld = firstPair.oldToken.offset;
1464 int firstOffsetNew = firstPair.newToken.offset; 564 int firstOffsetNew = firstPair.newToken.offset;
1465 int lastOffsetOld = lastPair.oldToken.end; 565 int lastOffsetOld = lastPair.oldToken.end;
1466 int lastOffsetNew = lastPair.newToken.end; 566 int lastOffsetNew = lastPair.newToken.end;
1467 int beginOffsetOld = math.min(firstOffsetOld, lastOffsetOld); 567 int beginOffsetOld = math.min(firstOffsetOld, lastOffsetOld);
1468 int endOffsetOld = math.max(firstOffsetOld, lastOffsetOld); 568 int endOffsetOld = math.max(firstOffsetOld, lastOffsetOld);
1469 int beginOffsetNew = math.min(firstOffsetNew, lastOffsetNew); 569 int beginOffsetNew = math.min(firstOffsetNew, lastOffsetNew);
1470 int endOffsetNew = math.max(firstOffsetNew, lastOffsetNew); 570 int endOffsetNew = math.max(firstOffsetNew, lastOffsetNew);
1471 // check for a whitespace only change 571 // A pure whitespace change.
1472 if (identical(lastPair.oldToken, firstPair.oldToken) && 572 if (identical(firstPair.oldToken, lastPair.oldToken) &&
1473 identical(lastPair.newToken, firstPair.newToken)) { 573 identical(firstPair.newToken, lastPair.newToken) &&
574 firstPair.kind == _TokenDifferenceKind.OFFSET) {
1474 _updateOffset = beginOffsetOld - 1; 575 _updateOffset = beginOffsetOld - 1;
1475 _updateEndOld = endOffsetOld; 576 _updateEndOld = endOffsetOld;
1476 _updateEndNew = endOffsetNew; 577 _updateEndNew = endOffsetNew;
1477 _updateDelta = newUnit.length - _oldUnit.length; 578 _updateDelta = newUnit.length - _oldUnit.length;
1478 // A Dart documentation comment change. 579 logger.log('Whitespace change.');
1479 if (firstPair.kind == _TokenDifferenceKind.COMMENT_DOC) { 580 _shiftTokens(firstPair.oldToken, true);
1480 bool success = _resolveCommentDoc(newUnit, firstPair); 581 IncrementalResolver incrementalResolver = new IncrementalResolver(
582 _cache,
583 _sourceEntry,
584 _unitEntry,
585 _unitElement,
586 _updateOffset,
587 _updateEndOld,
588 _updateEndNew);
589 incrementalResolver._updateCache();
590 incrementalResolver._updateElementNameOffsets();
591 incrementalResolver._shiftEntryErrors();
592 _updateEntry();
593 logger.log('Success.');
594 return true;
595 }
596 // A Dart documentation comment change.
597 {
598 Token firstOldToken = firstPair.oldToken;
599 Token firstNewToken = firstPair.newToken;
600 Token lastOldToken = lastPair.oldToken;
601 Token lastNewToken = lastPair.newToken;
602 if (firstOldToken is DocumentationCommentToken &&
603 firstNewToken is DocumentationCommentToken &&
604 lastOldToken is DocumentationCommentToken &&
605 lastNewToken is DocumentationCommentToken &&
606 identical(firstOldToken.parent, lastOldToken.parent) &&
607 identical(firstNewToken.parent, lastNewToken.parent)) {
608 _updateOffset = beginOffsetOld;
609 _updateEndOld = firstOldToken.parent.offset;
610 _updateEndNew = firstNewToken.parent.offset;
611 _updateDelta = newUnit.length - _oldUnit.length;
612 bool success =
613 _resolveCommentDoc(newUnit, firstOldToken, firstNewToken);
1481 logger.log('Documentation comment resolved: $success'); 614 logger.log('Documentation comment resolved: $success');
1482 return success; 615 return success;
1483 } 616 }
1484 // A pure whitespace change.
1485 if (firstPair.kind == _TokenDifferenceKind.OFFSET) {
1486 logger.log('Whitespace change.');
1487 _shiftTokens(firstPair.oldToken);
1488 {
1489 IncrementalResolver incrementalResolver = new IncrementalResolver(
1490 _oldEntry,
1491 _newSourceEntry,
1492 _newUnitEntry,
1493 _unitElement,
1494 _updateOffset,
1495 _updateEndOld,
1496 _updateEndNew);
1497 incrementalResolver._updateCache();
1498 incrementalResolver._updateElementNameOffsets();
1499 incrementalResolver._shiftEntryErrors();
1500 }
1501 _updateEntry();
1502 logger.log('Success.');
1503 return true;
1504 }
1505 // fall-through, end-of-line comment
1506 } 617 }
1507 // Find nodes covering the "old" and "new" token ranges. 618 // Find nodes covering the "old" and "new" token ranges.
1508 AstNode oldNode = 619 AstNode oldNode =
1509 _findNodeCovering(_oldUnit, beginOffsetOld, endOffsetOld - 1); 620 _findNodeCovering(_oldUnit, beginOffsetOld, endOffsetOld - 1);
1510 AstNode newNode = 621 AstNode newNode =
1511 _findNodeCovering(newUnit, beginOffsetNew, endOffsetNew - 1); 622 _findNodeCovering(newUnit, beginOffsetNew, endOffsetNew - 1);
1512 logger.log(() => 'oldNode: $oldNode'); 623 logger.log(() => 'oldNode: $oldNode');
1513 logger.log(() => 'newNode: $newNode'); 624 logger.log(() => 'newNode: $newNode');
1514 // Try to find the smallest common node, a FunctionBody currently. 625 // Try to find the smallest common node, a FunctionBody currently.
1515 { 626 {
1516 List<AstNode> oldParents = _getParents(oldNode); 627 List<AstNode> oldParents = _getParents(oldNode);
1517 List<AstNode> newParents = _getParents(newNode); 628 List<AstNode> newParents = _getParents(newNode);
629 // fail if an initializer change
630 if (oldParents.any((n) => n is ConstructorInitializer) ||
631 newParents.any((n) => n is ConstructorInitializer)) {
632 logger.log('Failure: a change in a constructor initializer');
633 return false;
634 }
635 // find matching methods / bodies
1518 int length = math.min(oldParents.length, newParents.length); 636 int length = math.min(oldParents.length, newParents.length);
1519 bool found = false; 637 bool found = false;
1520 for (int i = 0; i < length; i++) { 638 for (int i = 0; i < length; i++) {
1521 AstNode oldParent = oldParents[i]; 639 AstNode oldParent = oldParents[i];
1522 AstNode newParent = newParents[i]; 640 AstNode newParent = newParents[i];
1523 if (oldParent is ConstructorInitializer || 641 if (oldParent is CompilationUnit && newParent is CompilationUnit) {
1524 newParent is ConstructorInitializer) { 642 int oldLength = oldParent.declarations.length;
1525 logger.log('Failure: changes in constant constructor initializers' 643 int newLength = newParent.declarations.length;
1526 ' may cause external changes in constant objects.'); 644 if (oldLength != newLength) {
1527 return false; 645 logger.log(
1528 } 646 'Failure: unit declarations mismatch $oldLength vs. $newLeng th');
1529 if (oldParent is FunctionDeclaration && 647 return false;
648 }
649 } else if (oldParent is ClassDeclaration &&
650 newParent is ClassDeclaration) {
651 int oldLength = oldParent.members.length;
652 int newLength = newParent.members.length;
653 if (oldLength != newLength) {
654 logger.log(
655 'Failure: class declarations mismatch $oldLength vs. $newLen gth');
656 return false;
657 }
658 } else if (oldParent is FunctionDeclaration &&
1530 newParent is FunctionDeclaration || 659 newParent is FunctionDeclaration ||
660 oldParent is ConstructorDeclaration &&
661 newParent is ConstructorDeclaration ||
1531 oldParent is MethodDeclaration && 662 oldParent is MethodDeclaration &&
1532 newParent is MethodDeclaration || 663 newParent is MethodDeclaration) {
1533 oldParent is ConstructorDeclaration && 664 if (oldParents.length == i || newParents.length == i) {
1534 newParent is ConstructorDeclaration) { 665 return false;
1535 Element oldElement = (oldParent as Declaration).element; 666 }
1536 if (new DeclarationMatcher().matches(newParent, oldElement) == 667 } else if (oldParent is FunctionBody && newParent is FunctionBody) {
1537 DeclarationMatchKind.MATCH) { 668 if (oldParent is BlockFunctionBody &&
669 newParent is BlockFunctionBody) {
1538 oldNode = oldParent; 670 oldNode = oldParent;
1539 newNode = newParent; 671 newNode = newParent;
1540 found = true; 672 found = true;
673 break;
1541 } 674 }
1542 } 675 logger.log('Failure: not a block function body.');
1543 if (oldParent is BlockFunctionBody && 676 return false;
1544 newParent is BlockFunctionBody) { 677 } else if (oldParent is FunctionExpression &&
1545 oldNode = oldParent; 678 newParent is FunctionExpression) {
1546 newNode = newParent; 679 // skip
1547 found = true; 680 } else {
1548 break; 681 logger.log('Failure: old and new parent mismatch'
682 ' ${oldParent.runtimeType} vs. ${newParent.runtimeType}');
683 return false;
1549 } 684 }
1550 } 685 }
1551 if (!found) { 686 if (!found) {
1552 logger.log('Failure: no enclosing function body or executable.'); 687 logger.log('Failure: no enclosing function body or executable.');
1553 return false; 688 return false;
1554 } 689 }
1555 // fail if a comment change outside the bodies
1556 if (firstPair.kind == _TokenDifferenceKind.COMMENT) {
1557 if (beginOffsetOld <= oldNode.offset ||
1558 beginOffsetNew <= newNode.offset) {
1559 logger.log('Failure: comment outside a function body.');
1560 return false;
1561 }
1562 }
1563 } 690 }
1564 logger.log(() => 'oldNode: $oldNode'); 691 logger.log(() => 'oldNode: $oldNode');
1565 logger.log(() => 'newNode: $newNode'); 692 logger.log(() => 'newNode: $newNode');
1566 // prepare update range 693 // prepare update range
1567 _updateOffset = oldNode.offset; 694 _updateOffset = oldNode.offset;
1568 _updateEndOld = oldNode.end; 695 _updateEndOld = oldNode.end;
1569 _updateEndNew = newNode.end; 696 _updateEndNew = newNode.end;
1570 _updateDelta = _updateEndNew - _updateEndOld; 697 _updateDelta = _updateEndNew - _updateEndOld;
1571 // replace node 698 // replace node
1572 NodeReplacer.replace(oldNode, newNode); 699 NodeReplacer.replace(oldNode, newNode);
1573 // update token references 700 // update token references
1574 { 701 {
1575 Token oldBeginToken = _getBeginTokenNotComment(oldNode); 702 Token oldBeginToken = _getBeginTokenNotComment(oldNode);
1576 Token newBeginToken = _getBeginTokenNotComment(newNode); 703 Token newBeginToken = _getBeginTokenNotComment(newNode);
1577 if (oldBeginToken.previous.type == TokenType.EOF) { 704 if (oldBeginToken.previous.type == TokenType.EOF) {
1578 _oldUnit.beginToken = newBeginToken; 705 _oldUnit.beginToken = newBeginToken;
1579 } else { 706 } else {
1580 oldBeginToken.previous.setNext(newBeginToken); 707 oldBeginToken.previous.setNext(newBeginToken);
1581 } 708 }
1582 newNode.endToken.setNext(oldNode.endToken.next); 709 newNode.endToken.setNext(oldNode.endToken.next);
1583 _shiftTokens(oldNode.endToken.next); 710 _shiftTokens(oldNode.endToken.next);
1584 } 711 }
1585 // perform incremental resolution 712 // perform incremental resolution
1586 IncrementalResolver incrementalResolver = new IncrementalResolver( 713 IncrementalResolver incrementalResolver = new IncrementalResolver(
1587 _oldEntry, 714 _cache,
1588 _newSourceEntry, 715 _sourceEntry,
1589 _newUnitEntry, 716 _unitEntry,
1590 _unitElement, 717 _unitElement,
1591 _updateOffset, 718 _updateOffset,
1592 _updateEndOld, 719 _updateEndOld,
1593 _updateEndNew); 720 _updateEndNew);
1594 bool success = incrementalResolver.resolve(newNode); 721 incrementalResolver.resolve(newNode);
1595 // check if success
1596 if (!success) {
1597 logger.log('Failure: element model changed.');
1598 return false;
1599 }
1600 // update DartEntry 722 // update DartEntry
1601 _updateEntry(); 723 _updateEntry();
1602 logger.log('Success.'); 724 logger.log('Success.');
1603 return true; 725 return true;
1604 } 726 }
1605 } catch (e, st) { 727 } catch (e, st) {
1606 logger.log(e); 728 logger.logException(e, st);
1607 logger.log(st);
1608 logger.log('Failure: exception.'); 729 logger.log('Failure: exception.');
730 // The incremental resolver log is usually turned off,
731 // so also log the exception to the instrumentation log.
732 AnalysisEngine.instance.logger.logError(
733 'Failure in incremental resolver', new CaughtException(e, st));
1609 } finally { 734 } finally {
1610 logger.exit(); 735 logger.exit();
1611 } 736 }
1612 return false; 737 return false;
1613 } 738 }
1614 739
1615 CompilationUnit _parseUnit(String code) { 740 CompilationUnit _parseUnit(String code) {
1616 LoggingTimer timer = logger.startTimer(); 741 LoggingTimer timer = logger.startTimer();
1617 try { 742 try {
1618 Token token = _scan(code); 743 Token token = _scan(code);
1619 RecordingErrorListener errorListener = new RecordingErrorListener(); 744 RecordingErrorListener errorListener = new RecordingErrorListener();
1620 Parser parser = new Parser(_unitSource, errorListener); 745 Parser parser = new Parser(_unitSource, errorListener);
1621 AnalysisOptions options = _unitElement.context.analysisOptions; 746 AnalysisOptions options = _unitElement.context.analysisOptions;
747 parser.parseGenericMethodComments = options.strongMode;
1622 parser.parseGenericMethods = options.enableGenericMethods; 748 parser.parseGenericMethods = options.enableGenericMethods;
1623 CompilationUnit unit = parser.parseCompilationUnit(token); 749 CompilationUnit unit = parser.parseCompilationUnit(token);
1624 _newParseErrors = errorListener.errors; 750 _newParseErrors = errorListener.errors;
1625 return unit; 751 return unit;
1626 } finally { 752 } finally {
1627 timer.stop('parse'); 753 timer.stop('parse');
1628 } 754 }
1629 } 755 }
1630 756
1631 /** 757 /**
1632 * Attempts to resolve a documentation comment change. 758 * Attempts to resolve a documentation comment change.
1633 * Returns `true` if success. 759 * Returns `true` if success.
1634 */ 760 */
1635 bool _resolveCommentDoc(CompilationUnit newUnit, _TokenPair firstPair) { 761 bool _resolveCommentDoc(
1636 Token oldToken = firstPair.oldToken; 762 CompilationUnit newUnit, CommentToken oldToken, CommentToken newToken) {
1637 Token newToken = firstPair.newToken; 763 if (oldToken == null || newToken == null) {
1638 CommentToken oldComments = oldToken.precedingComments;
1639 CommentToken newComments = newToken.precedingComments;
1640 if (oldComments == null || newComments == null) {
1641 return false; 764 return false;
1642 } 765 }
1643 // find nodes 766 // find nodes
1644 int offset = oldComments.offset; 767 int offset = oldToken.offset;
1645 logger.log('offset: $offset'); 768 logger.log('offset: $offset');
1646 Comment oldComment = _findNodeCovering(_oldUnit, offset, offset); 769 AstNode oldNode = _findNodeCovering(_oldUnit, offset, offset);
1647 Comment newComment = _findNodeCovering(newUnit, offset, offset); 770 AstNode newNode = _findNodeCovering(newUnit, offset, offset);
771 if (oldNode is! Comment || newNode is! Comment) {
772 return false;
773 }
774 Comment oldComment = oldNode;
775 Comment newComment = newNode;
1648 logger.log('oldComment.beginToken: ${oldComment.beginToken}'); 776 logger.log('oldComment.beginToken: ${oldComment.beginToken}');
1649 logger.log('newComment.beginToken: ${newComment.beginToken}'); 777 logger.log('newComment.beginToken: ${newComment.beginToken}');
1650 _updateOffset = oldToken.offset - 1;
1651 // update token references 778 // update token references
1652 _shiftTokens(firstPair.oldToken); 779 _shiftTokens(oldToken.parent);
1653 _setPrecedingComments(oldToken, newComment.tokens.first); 780 _setPrecedingComments(oldToken.parent, newComment.tokens.first);
1654 // replace node 781 // replace node
1655 NodeReplacer.replace(oldComment, newComment); 782 NodeReplacer.replace(oldComment, newComment);
1656 // update elements 783 // update elements
1657 IncrementalResolver incrementalResolver = new IncrementalResolver( 784 IncrementalResolver incrementalResolver = new IncrementalResolver(
1658 _oldEntry, 785 _cache,
1659 _newSourceEntry, 786 _sourceEntry,
1660 _newUnitEntry, 787 _unitEntry,
1661 _unitElement, 788 _unitElement,
1662 _updateOffset, 789 _updateOffset,
1663 _updateEndOld, 790 _updateEndOld,
1664 _updateEndNew); 791 _updateEndNew);
1665 incrementalResolver._updateCache(); 792 incrementalResolver._updateCache();
1666 incrementalResolver._updateElementNameOffsets(); 793 incrementalResolver._updateElementNameOffsets();
1667 incrementalResolver._shiftEntryErrors(); 794 incrementalResolver._shiftEntryErrors();
1668 _updateEntry(); 795 _updateEntry();
1669 // resolve references in the comment 796 // resolve references in the comment
1670 incrementalResolver._resolveReferences(newComment); 797 incrementalResolver._resolveReferences(newComment);
798 // update 'documentationComment' of the parent element(s)
799 {
800 AstNode parent = newComment.parent;
801 if (parent is AnnotatedNode) {
802 setElementDocumentationForVariables(VariableDeclarationList list) {
803 for (VariableDeclaration variable in list.variables) {
804 Element variableElement = variable.element;
805 if (variableElement is ElementImpl) {
806 setElementDocumentationComment(variableElement, parent);
807 }
808 }
809 }
810
811 Element parentElement = ElementLocator.locate(newComment.parent);
812 if (parentElement is ElementImpl) {
813 setElementDocumentationComment(parentElement, parent);
814 } else if (parent is FieldDeclaration) {
815 setElementDocumentationForVariables(parent.fields);
816 } else if (parent is TopLevelVariableDeclaration) {
817 setElementDocumentationForVariables(parent.variables);
818 }
819 }
820 }
1671 // OK 821 // OK
1672 return true; 822 return true;
1673 } 823 }
1674 824
1675 Token _scan(String code) { 825 Token _scan(String code) {
1676 RecordingErrorListener errorListener = new RecordingErrorListener(); 826 RecordingErrorListener errorListener = new RecordingErrorListener();
1677 CharSequenceReader reader = new CharSequenceReader(code); 827 CharSequenceReader reader = new CharSequenceReader(code);
1678 Scanner scanner = new Scanner(_unitSource, reader, errorListener); 828 Scanner scanner = new Scanner(_unitSource, reader, errorListener);
829 AnalysisOptions options = _unitElement.context.analysisOptions;
830 scanner.scanGenericMethodComments = options.strongMode;
1679 Token token = scanner.tokenize(); 831 Token token = scanner.tokenize();
1680 _newLineInfo = new LineInfo(scanner.lineStarts); 832 _newLineInfo = new LineInfo(scanner.lineStarts);
1681 _newScanErrors = errorListener.errors; 833 _newScanErrors = errorListener.errors;
1682 return token; 834 return token;
1683 } 835 }
1684 836
1685 /** 837 /**
1686 * Set the given [comment] as a "precedingComments" for [token]. 838 * Set the given [comment] as a "precedingComments" for [token].
1687 */ 839 */
1688 void _setPrecedingComments(Token token, CommentToken comment) { 840 void _setPrecedingComments(Token token, CommentToken comment) {
1689 if (token is BeginTokenWithComment) { 841 if (token is BeginTokenWithComment) {
1690 token.precedingComments = comment; 842 token.precedingComments = comment;
1691 } else if (token is KeywordTokenWithComment) { 843 } else if (token is KeywordTokenWithComment) {
1692 token.precedingComments = comment; 844 token.precedingComments = comment;
1693 } else if (token is StringTokenWithComment) { 845 } else if (token is StringTokenWithComment) {
1694 token.precedingComments = comment; 846 token.precedingComments = comment;
1695 } else if (token is TokenWithComment) { 847 } else if (token is TokenWithComment) {
1696 token.precedingComments = comment; 848 token.precedingComments = comment;
1697 } else { 849 } else {
1698 Type parentType = token != null ? token.runtimeType : null; 850 Type parentType = token?.runtimeType;
1699 throw new AnalysisException('Uknown parent token type: $parentType'); 851 throw new AnalysisException('Uknown parent token type: $parentType');
1700 } 852 }
1701 } 853 }
1702 854
1703 void _shiftTokens(Token token) { 855 void _shiftTokens(Token token, [bool goUpComment = false]) {
1704 while (token != null) { 856 while (token != null) {
857 if (goUpComment && token is CommentToken) {
858 token = (token as CommentToken).parent;
859 }
1705 if (token.offset > _updateOffset) { 860 if (token.offset > _updateOffset) {
1706 token.offset += _updateDelta; 861 token.offset += _updateDelta;
1707 } 862 }
1708 // comments 863 // comments
1709 _shiftTokens(token.precedingComments); 864 _shiftTokens(token.precedingComments);
1710 if (token is DocumentationCommentToken) { 865 if (token is DocumentationCommentToken) {
1711 for (Token reference in token.references) { 866 for (Token reference in token.references) {
1712 _shiftTokens(reference); 867 _shiftTokens(reference);
1713 } 868 }
1714 } 869 }
1715 // next 870 // next
1716 if (token.type == TokenType.EOF) { 871 if (token.type == TokenType.EOF) {
1717 break; 872 break;
1718 } 873 }
1719 token = token.next; 874 token = token.next;
1720 } 875 }
1721 } 876 }
1722 877
1723 void _updateEntry() { 878 void _updateEntry() {
1724 if (_oldEntry != null) {
1725 _updateEntry_OLD();
1726 } else {
1727 _updateEntry_NEW();
1728 }
1729 }
1730
1731 void _updateEntry_NEW() {
1732 // scan results 879 // scan results
1733 _newSourceEntry.setValueIncremental(SCAN_ERRORS, _newScanErrors, true); 880 _sourceEntry.setValueIncremental(SCAN_ERRORS, _newScanErrors, true);
1734 _newSourceEntry.setValueIncremental(LINE_INFO, _newLineInfo, false); 881 _sourceEntry.setValueIncremental(LINE_INFO, _newLineInfo, false);
1735 // parse results 882 // parse results
1736 _newSourceEntry.setValueIncremental(PARSE_ERRORS, _newParseErrors, true); 883 _sourceEntry.setValueIncremental(PARSE_ERRORS, _newParseErrors, true);
1737 _newSourceEntry.setValueIncremental(PARSED_UNIT, _oldUnit, false); 884 _sourceEntry.setValueIncremental(PARSED_UNIT, _oldUnit, false);
1738 } 885 // referenced names
1739 886 ReferencedNames referencedNames = new ReferencedNames(_unitSource);
1740 void _updateEntry_OLD() { 887 new ReferencedNamesBuilder(referencedNames).build(_oldUnit);
1741 _oldEntry.setValue(SourceEntry.LINE_INFO, _newLineInfo); 888 _sourceEntry.setValueIncremental(REFERENCED_NAMES, referencedNames, false);
1742 _oldEntry.setValue(DartEntry.SCAN_ERRORS, _newScanErrors);
1743 _oldEntry.setValue(DartEntry.PARSE_ERRORS, _newParseErrors);
1744 } 889 }
1745 890
1746 /** 891 /**
1747 * Checks if [token] has a balanced number of open and closed curly brackets. 892 * Checks if [token] has a balanced number of open and closed curly brackets.
1748 */ 893 */
1749 static bool _areCurlyBracketsBalanced(Token token) { 894 static bool _areCurlyBracketsBalanced(Token token) {
1750 int numOpen = _getTokenCount(token, TokenType.OPEN_CURLY_BRACKET); 895 int numOpen = _getTokenCount(token, TokenType.OPEN_CURLY_BRACKET);
1751 int numOpen2 = 896 int numOpen2 =
1752 _getTokenCount(token, TokenType.STRING_INTERPOLATION_EXPRESSION); 897 _getTokenCount(token, TokenType.STRING_INTERPOLATION_EXPRESSION);
1753 int numClosed = _getTokenCount(token, TokenType.CLOSE_CURLY_BRACKET); 898 int numClosed = _getTokenCount(token, TokenType.CLOSE_CURLY_BRACKET);
1754 return numOpen + numOpen2 == numClosed; 899 return numOpen + numOpen2 == numClosed;
1755 } 900 }
1756 901
1757 static _TokenDifferenceKind _compareToken( 902 static _TokenDifferenceKind _compareToken(
1758 Token oldToken, Token newToken, int delta, bool forComment) { 903 Token oldToken, Token newToken, int delta) {
1759 while (true) { 904 if (oldToken == null && newToken == null) {
1760 if (oldToken == null && newToken == null) { 905 return null;
1761 return null; 906 }
1762 } 907 if (oldToken == null || newToken == null) {
1763 if (oldToken == null || newToken == null) { 908 return _TokenDifferenceKind.CONTENT;
1764 return _TokenDifferenceKind.CONTENT; 909 }
1765 } 910 if (oldToken.type != newToken.type) {
1766 if (oldToken.type != newToken.type) { 911 return _TokenDifferenceKind.CONTENT;
1767 return _TokenDifferenceKind.CONTENT; 912 }
1768 } 913 if (oldToken.lexeme != newToken.lexeme) {
1769 if (oldToken.lexeme != newToken.lexeme) { 914 return _TokenDifferenceKind.CONTENT;
1770 return _TokenDifferenceKind.CONTENT; 915 }
1771 } 916 if (newToken.offset - oldToken.offset != delta) {
1772 if (newToken.offset - oldToken.offset != delta) { 917 return _TokenDifferenceKind.OFFSET;
1773 return _TokenDifferenceKind.OFFSET;
1774 }
1775 // continue if comment tokens are being checked
1776 if (!forComment) {
1777 break;
1778 }
1779 oldToken = oldToken.next;
1780 newToken = newToken.next;
1781 } 918 }
1782 return null; 919 return null;
1783 } 920 }
1784 921
1785 static _TokenPair _findFirstDifferentToken(Token oldToken, Token newToken) { 922 static _TokenPair _findFirstDifferentToken(Token oldToken, Token newToken) {
1786 while (true) { 923 while (oldToken.type != TokenType.EOF || newToken.type != TokenType.EOF) {
1787 if (oldToken.type == TokenType.EOF && newToken.type == TokenType.EOF) {
1788 return null;
1789 }
1790 if (oldToken.type == TokenType.EOF || newToken.type == TokenType.EOF) { 924 if (oldToken.type == TokenType.EOF || newToken.type == TokenType.EOF) {
1791 return new _TokenPair(_TokenDifferenceKind.CONTENT, oldToken, newToken); 925 return new _TokenPair(_TokenDifferenceKind.CONTENT, oldToken, newToken);
1792 } 926 }
1793 // compare comments 927 // compare comments
1794 { 928 {
1795 Token oldComment = oldToken.precedingComments; 929 Token oldComment = oldToken.precedingComments;
1796 Token newComment = newToken.precedingComments; 930 Token newComment = newToken.precedingComments;
1797 if (_compareToken(oldComment, newComment, 0, true) != null) { 931 while (true) {
1798 _TokenDifferenceKind diffKind = _TokenDifferenceKind.COMMENT; 932 _TokenDifferenceKind diffKind =
1799 if (oldComment is DocumentationCommentToken || 933 _compareToken(oldComment, newComment, 0);
1800 newComment is DocumentationCommentToken) { 934 if (diffKind != null) {
1801 diffKind = _TokenDifferenceKind.COMMENT_DOC; 935 return new _TokenPair(
936 diffKind, oldComment ?? oldToken, newComment ?? newToken);
1802 } 937 }
1803 return new _TokenPair(diffKind, oldToken, newToken); 938 if (oldComment == null && newComment == null) {
939 break;
940 }
941 oldComment = oldComment.next;
942 newComment = newComment.next;
1804 } 943 }
1805 } 944 }
1806 // compare tokens 945 // compare tokens
1807 _TokenDifferenceKind diffKind = 946 _TokenDifferenceKind diffKind = _compareToken(oldToken, newToken, 0);
1808 _compareToken(oldToken, newToken, 0, false);
1809 if (diffKind != null) { 947 if (diffKind != null) {
1810 return new _TokenPair(diffKind, oldToken, newToken); 948 return new _TokenPair(diffKind, oldToken, newToken);
1811 } 949 }
1812 // next tokens 950 // next tokens
1813 oldToken = oldToken.next; 951 oldToken = oldToken.next;
1814 newToken = newToken.next; 952 newToken = newToken.next;
1815 } 953 }
1816 // no difference 954 // no difference
1817 return null; 955 return null;
1818 } 956 }
1819 957
1820 static _TokenPair _findLastDifferentToken(Token oldToken, Token newToken) { 958 static _TokenPair _findLastDifferentToken(Token oldToken, Token newToken) {
1821 int delta = newToken.offset - oldToken.offset; 959 int delta = newToken.offset - oldToken.offset;
960 Token prevOldToken;
961 Token prevNewToken;
1822 while (oldToken.previous != oldToken && newToken.previous != newToken) { 962 while (oldToken.previous != oldToken && newToken.previous != newToken) {
1823 // compare tokens 963 // compare tokens
1824 _TokenDifferenceKind diffKind = 964 _TokenDifferenceKind diffKind = _compareToken(oldToken, newToken, delta);
1825 _compareToken(oldToken, newToken, delta, false);
1826 if (diffKind != null) { 965 if (diffKind != null) {
1827 return new _TokenPair(diffKind, oldToken.next, newToken.next); 966 return new _TokenPair(diffKind, prevOldToken, prevNewToken);
1828 } 967 }
968 prevOldToken = oldToken;
969 prevNewToken = newToken;
1829 // compare comments 970 // compare comments
1830 { 971 {
1831 Token oldComment = oldToken.precedingComments; 972 Token oldComment = oldToken.precedingComments;
1832 Token newComment = newToken.precedingComments; 973 Token newComment = newToken.precedingComments;
1833 if (_compareToken(oldComment, newComment, delta, true) != null) { 974 while (oldComment?.next != null) {
1834 _TokenDifferenceKind diffKind = _TokenDifferenceKind.COMMENT; 975 oldComment = oldComment.next;
1835 if (oldComment is DocumentationCommentToken || 976 }
1836 newComment is DocumentationCommentToken) { 977 while (newComment?.next != null) {
1837 diffKind = _TokenDifferenceKind.COMMENT_DOC; 978 newComment = newComment.next;
979 }
980 while (true) {
981 _TokenDifferenceKind diffKind =
982 _compareToken(oldComment, newComment, delta);
983 if (diffKind != null) {
984 return new _TokenPair(
985 diffKind, oldComment ?? oldToken, newComment ?? newToken);
1838 } 986 }
1839 return new _TokenPair(diffKind, oldToken, newToken); 987 if (oldComment == null && newComment == null) {
988 break;
989 }
990 prevOldToken = oldComment;
991 prevNewToken = newComment;
992 oldComment = oldComment.previous;
993 newComment = newComment.previous;
1840 } 994 }
1841 } 995 }
1842 // next tokens 996 // next tokens
1843 oldToken = oldToken.previous; 997 oldToken = oldToken.previous;
1844 newToken = newToken.previous; 998 newToken = newToken.previous;
1845 } 999 }
1846 return null; 1000 return null;
1847 } 1001 }
1848 1002
1849 static AstNode _findNodeCovering(AstNode root, int offset, int end) { 1003 static AstNode _findNodeCovering(AstNode root, int offset, int end) {
1850 NodeLocator nodeLocator = new NodeLocator(offset, end); 1004 NodeLocator nodeLocator = new NodeLocator(offset, end);
1851 return nodeLocator.searchWithin(root); 1005 return nodeLocator.searchWithin(root);
1852 } 1006 }
1853 1007
1854 static Token _getBeginTokenNotComment(AstNode node) { 1008 static Token _getBeginTokenNotComment(AstNode node) {
1855 Token oldBeginToken = node.beginToken; 1009 Token oldBeginToken = node.beginToken;
1856 if (oldBeginToken is CommentToken) { 1010 if (oldBeginToken is CommentToken) {
1857 oldBeginToken = (oldBeginToken as CommentToken).parent; 1011 return oldBeginToken.parent;
1858 } 1012 }
1859 return oldBeginToken; 1013 return oldBeginToken;
1860 } 1014 }
1861 1015
1862 static List<AstNode> _getParents(AstNode node) { 1016 static List<AstNode> _getParents(AstNode node) {
1863 List<AstNode> parents = <AstNode>[]; 1017 List<AstNode> parents = <AstNode>[];
1864 while (node != null) { 1018 while (node != null) {
1865 parents.insert(0, node); 1019 parents.insert(0, node);
1866 node = node.parent; 1020 node = node.parent;
1867 } 1021 }
(...skipping 25 matching lines...) Expand all
1893 Scope scope; 1047 Scope scope;
1894 } 1048 }
1895 1049
1896 /** 1050 /**
1897 * Instances of the class [ResolutionContextBuilder] build the context for a 1051 * Instances of the class [ResolutionContextBuilder] build the context for a
1898 * given node in an AST structure. At the moment, this class only handles 1052 * given node in an AST structure. At the moment, this class only handles
1899 * top-level and class-level declarations. 1053 * top-level and class-level declarations.
1900 */ 1054 */
1901 class ResolutionContextBuilder { 1055 class ResolutionContextBuilder {
1902 /** 1056 /**
1903 * The listener to which analysis errors will be reported.
1904 */
1905 final AnalysisErrorListener _errorListener;
1906
1907 /**
1908 * The class containing the enclosing [CompilationUnitElement]. 1057 * The class containing the enclosing [CompilationUnitElement].
1909 */ 1058 */
1910 CompilationUnitElement _enclosingUnit; 1059 CompilationUnitElement _enclosingUnit;
1911 1060
1912 /** 1061 /**
1913 * The class containing the enclosing [ClassDeclaration], or `null` if we are 1062 * The class containing the enclosing [ClassDeclaration], or `null` if we are
1914 * not in the scope of a class. 1063 * not in the scope of a class.
1915 */ 1064 */
1916 ClassDeclaration _enclosingClassDeclaration; 1065 ClassDeclaration _enclosingClassDeclaration;
1917 1066
1918 /** 1067 /**
1919 * The class containing the enclosing [ClassElement], or `null` if we are not 1068 * The class containing the enclosing [ClassElement], or `null` if we are not
1920 * in the scope of a class. 1069 * in the scope of a class.
1921 */ 1070 */
1922 ClassElement _enclosingClass; 1071 ClassElement _enclosingClass;
1923 1072
1924 /**
1925 * Initialize a newly created scope builder to generate a scope that will
1926 * report errors to the given listener.
1927 */
1928 ResolutionContextBuilder(this._errorListener);
1929
1930 Scope _scopeFor(AstNode node) { 1073 Scope _scopeFor(AstNode node) {
1931 if (node is CompilationUnit) { 1074 if (node is CompilationUnit) {
1932 return _scopeForAstNode(node); 1075 return _scopeForAstNode(node);
1933 } 1076 }
1934 AstNode parent = node.parent; 1077 AstNode parent = node.parent;
1935 if (parent == null) { 1078 if (parent == null) {
1936 throw new AnalysisException( 1079 throw new AnalysisException(
1937 "Cannot create scope: node is not part of a CompilationUnit"); 1080 "Cannot create scope: node is not part of a CompilationUnit");
1938 } 1081 }
1939 return _scopeForAstNode(parent); 1082 return _scopeForAstNode(parent);
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
2013 _enclosingUnit = node.element; 1156 _enclosingUnit = node.element;
2014 if (_enclosingUnit == null) { 1157 if (_enclosingUnit == null) {
2015 throw new AnalysisException( 1158 throw new AnalysisException(
2016 "Cannot create scope: compilation unit is not resolved"); 1159 "Cannot create scope: compilation unit is not resolved");
2017 } 1160 }
2018 LibraryElement libraryElement = _enclosingUnit.library; 1161 LibraryElement libraryElement = _enclosingUnit.library;
2019 if (libraryElement == null) { 1162 if (libraryElement == null) {
2020 throw new AnalysisException( 1163 throw new AnalysisException(
2021 "Cannot create scope: compilation unit is not part of a library"); 1164 "Cannot create scope: compilation unit is not part of a library");
2022 } 1165 }
2023 return new LibraryScope(libraryElement, _errorListener); 1166 return new LibraryScope(libraryElement);
2024 } 1167 }
2025 1168
2026 /** 1169 /**
2027 * Return the context in which the given AST structure should be resolved. 1170 * Return the context in which the given AST structure should be resolved.
2028 * 1171 *
2029 * [node] - the root of the AST structure to be resolved. 1172 * [node] - the root of the AST structure to be resolved.
2030 * [errorListener] - the listener to which analysis errors will be reported.
2031 * 1173 *
2032 * Throws [AnalysisException] if the AST structure has not been resolved or 1174 * Throws [AnalysisException] if the AST structure has not been resolved or
2033 * is not part of a [CompilationUnit] 1175 * is not part of a [CompilationUnit]
2034 */ 1176 */
2035 static ResolutionContext contextFor( 1177 static ResolutionContext contextFor(AstNode node) {
2036 AstNode node, AnalysisErrorListener errorListener) {
2037 if (node == null) { 1178 if (node == null) {
2038 throw new AnalysisException("Cannot create context: node is null"); 1179 throw new AnalysisException("Cannot create context: node is null");
2039 } 1180 }
2040 // build scope 1181 // build scope
2041 ResolutionContextBuilder builder = 1182 ResolutionContextBuilder builder = new ResolutionContextBuilder();
2042 new ResolutionContextBuilder(errorListener);
2043 Scope scope = builder._scopeFor(node); 1183 Scope scope = builder._scopeFor(node);
2044 // prepare context 1184 // prepare context
2045 ResolutionContext context = new ResolutionContext(); 1185 ResolutionContext context = new ResolutionContext();
2046 context.scope = scope; 1186 context.scope = scope;
2047 context.enclosingUnit = builder._enclosingUnit; 1187 context.enclosingUnit = builder._enclosingUnit;
2048 context.enclosingClassDeclaration = builder._enclosingClassDeclaration; 1188 context.enclosingClassDeclaration = builder._enclosingClassDeclaration;
2049 context.enclosingClass = builder._enclosingClass; 1189 context.enclosingClass = builder._enclosingClass;
2050 return context; 1190 return context;
2051 } 1191 }
2052 } 1192 }
2053 1193
2054 /** 1194 /**
2055 * Instances of the class [_DeclarationMismatchException] represent an exception 1195 * Adjusts the location of each Element that moved.
2056 * that is thrown when the element model defined by a given AST structure does 1196 *
2057 * not match an existing element model. 1197 * Since `==` and `hashCode` of a local variable or function Element are based
1198 * on the element name offsets, we also need to remove these elements from the
1199 * cache to avoid a memory leak. TODO(scheglov) fix and remove this
2058 */ 1200 */
2059 class _DeclarationMismatchException {} 1201 class _ElementOffsetUpdater extends GeneralizingElementVisitor {
2060
2061 class _ElementNameOffsetUpdater extends GeneralizingElementVisitor {
2062 final int updateOffset; 1202 final int updateOffset;
2063 final int updateDelta; 1203 final int updateDelta;
1204 final AnalysisCache cache;
2064 1205
2065 _ElementNameOffsetUpdater(this.updateOffset, this.updateDelta); 1206 _ElementOffsetUpdater(this.updateOffset, this.updateDelta, this.cache);
2066 1207
2067 @override 1208 @override
2068 visitElement(Element element) { 1209 visitElement(Element element) {
1210 // name offset
2069 int nameOffset = element.nameOffset; 1211 int nameOffset = element.nameOffset;
2070 if (nameOffset > updateOffset) { 1212 if (nameOffset > updateOffset) {
2071 (element as ElementImpl).nameOffset = nameOffset + updateDelta; 1213 (element as ElementImpl).nameOffset = nameOffset + updateDelta;
1214 if (element is ConstVariableElement) {
1215 Expression initializer = element.constantInitializer;
1216 if (initializer != null) {
1217 _shiftTokens(initializer.beginToken);
1218 }
1219 _shiftErrors(element.evaluationResult?.errors);
1220 }
1221 }
1222 // code range
1223 if (element is ElementImpl) {
1224 int oldOffset = element.codeOffset;
1225 int oldLength = element.codeLength;
1226 if (oldOffset != null) {
1227 int newOffset = oldOffset;
1228 int newLength = oldLength;
1229 newOffset += oldOffset > updateOffset ? updateDelta : 0;
1230 if (oldOffset <= updateOffset && updateOffset < oldOffset + oldLength) {
1231 newLength += updateDelta;
1232 }
1233 if (newOffset != oldOffset || newLength != oldLength) {
1234 element.setCodeRange(newOffset, newLength);
1235 }
1236 }
1237 }
1238 // visible range
1239 if (element is LocalElement) {
1240 SourceRange visibleRange = element.visibleRange;
1241 if (visibleRange != null) {
1242 int oldOffset = visibleRange.offset;
1243 int oldLength = visibleRange.length;
1244 int newOffset = oldOffset;
1245 int newLength = oldLength;
1246 newOffset += oldOffset > updateOffset ? updateDelta : 0;
1247 newLength += visibleRange.contains(updateOffset) ? updateDelta : 0;
1248 if (newOffset != oldOffset || newLength != oldLength) {
1249 if (element is FunctionElementImpl) {
1250 element.setVisibleRange(newOffset, newLength);
1251 } else if (element is LocalVariableElementImpl) {
1252 element.setVisibleRange(newOffset, newLength);
1253 } else if (element is ParameterElementImpl) {
1254 element.setVisibleRange(newOffset, newLength);
1255 }
1256 }
1257 }
2072 } 1258 }
2073 super.visitElement(element); 1259 super.visitElement(element);
2074 } 1260 }
2075 }
2076 1261
2077 class _ElementsGatherer extends GeneralizingElementVisitor { 1262 void _shiftErrors(List<AnalysisError> errors) {
2078 final DeclarationMatcher matcher; 1263 if (errors != null) {
2079 1264 for (AnalysisError error in errors) {
2080 _ElementsGatherer(this.matcher); 1265 int errorOffset = error.offset;
2081 1266 if (errorOffset > updateOffset) {
2082 void addElements(List<Element> elements) { 1267 error.offset += updateDelta;
2083 for (Element element in elements) { 1268 }
2084 if (!element.isSynthetic) {
2085 _addElement(element);
2086 } 1269 }
2087 } 1270 }
2088 } 1271 }
2089 1272
2090 @override 1273 void _shiftTokens(Token token) {
2091 visitElement(Element element) { 1274 while (token != null) {
2092 _addElement(element); 1275 if (token.offset > updateOffset) {
2093 super.visitElement(element); 1276 token.offset += updateDelta;
2094 } 1277 }
2095 1278 // comments
2096 @override 1279 _shiftTokens(token.precedingComments);
2097 visitExecutableElement(ExecutableElement element) { 1280 if (token is DocumentationCommentToken) {
2098 _addElement(element); 1281 for (Token reference in token.references) {
2099 } 1282 _shiftTokens(reference);
2100 1283 }
2101 @override 1284 }
2102 visitParameterElement(ParameterElement element) {} 1285 // next
2103 1286 if (token.type == TokenType.EOF) {
2104 @override 1287 break;
2105 visitPropertyAccessorElement(PropertyAccessorElement element) { 1288 }
2106 if (!element.isSynthetic) { 1289 token = token.next;
2107 _addElement(element);
2108 }
2109 // Don't visit children (such as synthetic setter parameters).
2110 }
2111
2112 @override
2113 visitPropertyInducingElement(PropertyInducingElement element) {
2114 if (!element.isSynthetic) {
2115 _addElement(element);
2116 }
2117 // Don't visit children (such as property accessors).
2118 }
2119
2120 @override
2121 visitTypeParameterElement(TypeParameterElement element) {}
2122
2123 void _addElement(Element element) {
2124 if (element != null) {
2125 matcher._allElements.add(element);
2126 matcher._removedElements.add(element);
2127 } 1290 }
2128 } 1291 }
2129 } 1292 }
2130 1293
2131 /** 1294 /**
2132 * Describes how two [Token]s are different. 1295 * Describes how two [Token]s are different.
2133 */ 1296 */
2134 class _TokenDifferenceKind { 1297 class _TokenDifferenceKind {
2135 static const COMMENT = const _TokenDifferenceKind('COMMENT');
2136 static const COMMENT_DOC = const _TokenDifferenceKind('COMMENT_DOC');
2137 static const CONTENT = const _TokenDifferenceKind('CONTENT'); 1298 static const CONTENT = const _TokenDifferenceKind('CONTENT');
2138 static const OFFSET = const _TokenDifferenceKind('OFFSET'); 1299 static const OFFSET = const _TokenDifferenceKind('OFFSET');
2139 1300
2140 final String name; 1301 final String name;
2141 1302
2142 const _TokenDifferenceKind(this.name); 1303 const _TokenDifferenceKind(this.name);
2143 1304
2144 @override 1305 @override
2145 String toString() => name; 1306 String toString() => name;
2146 } 1307 }
2147 1308
2148 class _TokenPair { 1309 class _TokenPair {
2149 final _TokenDifferenceKind kind; 1310 final _TokenDifferenceKind kind;
2150 final Token oldToken; 1311 final Token oldToken;
2151 final Token newToken; 1312 final Token newToken;
2152 _TokenPair(this.kind, this.oldToken, this.newToken); 1313 _TokenPair(this.kind, this.oldToken, this.newToken);
2153 } 1314 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698