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

Side by Side Diff: pkg/analyzer/lib/src/generated/incremental_resolver.dart

Issue 2096763004: Remove DeclarationMarcher - incrementally resolve only BlockFunctionBody. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 4 years, 6 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 analyzer.src.generated.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/dart/ast/ast.dart'; 10 import 'package:analyzer/dart/ast/ast.dart';
11 import 'package:analyzer/dart/ast/token.dart'; 11 import 'package:analyzer/dart/ast/token.dart';
12 import 'package:analyzer/dart/ast/visitor.dart';
13 import 'package:analyzer/dart/element/element.dart'; 12 import 'package:analyzer/dart/element/element.dart';
14 import 'package:analyzer/dart/element/type.dart';
15 import 'package:analyzer/dart/element/visitor.dart'; 13 import 'package:analyzer/dart/element/visitor.dart';
16 import 'package:analyzer/src/context/cache.dart'; 14 import 'package:analyzer/src/context/cache.dart';
17 import 'package:analyzer/src/dart/ast/token.dart'; 15 import 'package:analyzer/src/dart/ast/token.dart';
18 import 'package:analyzer/src/dart/ast/utilities.dart'; 16 import 'package:analyzer/src/dart/ast/utilities.dart';
19 import 'package:analyzer/src/dart/element/builder.dart'; 17 import 'package:analyzer/src/dart/element/builder.dart';
20 import 'package:analyzer/src/dart/element/element.dart'; 18 import 'package:analyzer/src/dart/element/element.dart';
21 import 'package:analyzer/src/dart/resolver/inheritance_manager.dart'; 19 import 'package:analyzer/src/dart/resolver/inheritance_manager.dart';
22 import 'package:analyzer/src/dart/scanner/reader.dart'; 20 import 'package:analyzer/src/dart/scanner/reader.dart';
23 import 'package:analyzer/src/dart/scanner/scanner.dart'; 21 import 'package:analyzer/src/dart/scanner/scanner.dart';
24 import 'package:analyzer/src/generated/constant.dart'; 22 import 'package:analyzer/src/generated/constant.dart';
(...skipping 18 matching lines...) Expand all
43 bool _resolveApiChanges = false; 41 bool _resolveApiChanges = false;
44 42
45 /** 43 /**
46 * This method is used to enable/disable API-changing modifications resolution. 44 * This method is used to enable/disable API-changing modifications resolution.
47 */ 45 */
48 void set test_resolveApiChanges(bool value) { 46 void set test_resolveApiChanges(bool value) {
49 _resolveApiChanges = value; 47 _resolveApiChanges = value;
50 } 48 }
51 49
52 /** 50 /**
53 * Instances of the class [DeclarationMatcher] determine whether the element
54 * model defined by a given AST structure matches an existing element model.
55 */
56 class DeclarationMatcher extends RecursiveAstVisitor {
57 /**
58 * The library containing the AST nodes being visited.
59 */
60 LibraryElement _enclosingLibrary;
61
62 /**
63 * The compilation unit containing the AST nodes being visited.
64 */
65 CompilationUnitElement _enclosingUnit;
66
67 /**
68 * The function type alias containing the AST nodes being visited, or `null` i f we are not
69 * in the scope of a function type alias.
70 */
71 FunctionTypeAliasElement _enclosingAlias;
72
73 /**
74 * The class containing the AST nodes being visited, or `null` if we are not
75 * in the scope of a class.
76 */
77 ClassElementImpl _enclosingClass;
78
79 /**
80 * The enum containing the AST nodes being visited, or `null` if we are not
81 * in the scope of an enum.
82 */
83 EnumElementImpl _enclosingEnum;
84
85 /**
86 * The parameter containing the AST nodes being visited, or `null` if we are n ot in the
87 * scope of a parameter.
88 */
89 ParameterElement _enclosingParameter;
90
91 FieldDeclaration _enclosingFieldNode = null;
92 bool _inTopLevelVariableDeclaration = false;
93
94 /**
95 * Is `true` if the current class declaration has a constructor.
96 */
97 bool _hasConstructor = false;
98
99 /**
100 * A set containing all of the elements in the element model that were defined by the old AST node
101 * corresponding to the AST node being visited.
102 */
103 HashSet<Element> _allElements = new HashSet<Element>();
104
105 /**
106 * A set containing all of the elements were defined in the old element model,
107 * but are not defined in the new element model.
108 */
109 HashSet<Element> _removedElements = new HashSet<Element>();
110
111 /**
112 * A set containing all of the elements are defined in the new element model,
113 * but were not defined in the old element model.
114 */
115 HashSet<Element> _addedElements = new HashSet<Element>();
116
117 /**
118 * Determines how elements model corresponding to the given [node] differs
119 * from the [element].
120 */
121 DeclarationMatchKind matches(AstNode node, Element element) {
122 logger.enter('match $element @ ${element.nameOffset}');
123 try {
124 _captureEnclosingElements(element);
125 _gatherElements(element);
126 node.accept(this);
127 } on _DeclarationMismatchException {
128 logger.log("mismatched");
129 return DeclarationMatchKind.MISMATCH;
130 } finally {
131 logger.exit();
132 }
133 // no API changes
134 if (_removedElements.isEmpty && _addedElements.isEmpty) {
135 logger.log("no API changes");
136 return DeclarationMatchKind.MATCH;
137 }
138 // simple API change
139 logger.log('_removedElements: $_removedElements');
140 logger.log('_addedElements: $_addedElements');
141 _removedElements.forEach(_removeElement);
142 if (_removedElements.length <= 1 && _addedElements.length == 1) {
143 return DeclarationMatchKind.MISMATCH_OK;
144 }
145 // something more complex
146 return DeclarationMatchKind.MISMATCH;
147 }
148
149 @override
150 visitBlockFunctionBody(BlockFunctionBody node) {
151 // ignore bodies
152 }
153
154 @override
155 visitClassDeclaration(ClassDeclaration node) {
156 String name = node.name.name;
157 ClassElement element = _findElement(_enclosingUnit.types, name);
158 _enclosingClass = element;
159 _processElement(element);
160 _assertSameAnnotations(node, element);
161 _assertSameTypeParameters(node.typeParameters, element.typeParameters);
162 // check for missing clauses
163 if (node.extendsClause == null) {
164 _assertTrue(element.supertype.name == 'Object');
165 }
166 if (node.implementsClause == null) {
167 _assertTrue(element.interfaces.isEmpty);
168 }
169 if (node.withClause == null) {
170 _assertTrue(element.mixins.isEmpty);
171 }
172 // process clauses and members
173 _hasConstructor = false;
174 super.visitClassDeclaration(node);
175 // process default constructor
176 if (!_hasConstructor) {
177 ConstructorElement constructor = element.unnamedConstructor;
178 _processElement(constructor);
179 if (!constructor.isSynthetic) {
180 _assertEquals(constructor.parameters.length, 0);
181 }
182 }
183 // matches, set the element
184 node.name.staticElement = element;
185 }
186
187 @override
188 visitClassTypeAlias(ClassTypeAlias node) {
189 String name = node.name.name;
190 ClassElement element = _findElement(_enclosingUnit.types, name);
191 _enclosingClass = element;
192 _processElement(element);
193 _assertSameTypeParameters(node.typeParameters, element.typeParameters);
194 super.visitClassTypeAlias(node);
195 }
196
197 @override
198 visitCompilationUnit(CompilationUnit node) {
199 _processElement(_enclosingUnit);
200 super.visitCompilationUnit(node);
201 }
202
203 @override
204 visitConstructorDeclaration(ConstructorDeclaration node) {
205 _hasConstructor = true;
206 SimpleIdentifier constructorName = node.name;
207 ConstructorElementImpl element = constructorName == null
208 ? _enclosingClass.unnamedConstructor
209 : _enclosingClass.getNamedConstructor(constructorName.name);
210 _processElement(element);
211 _assertEquals(node.constKeyword != null, element.isConst);
212 _assertEquals(node.factoryKeyword != null, element.isFactory);
213 _assertCompatibleParameters(node.parameters, element.parameters);
214 // matches, update the existing element
215 ExecutableElement newElement = node.element;
216 node.element = element;
217 _setLocalElements(element, newElement);
218 }
219
220 @override
221 visitEnumConstantDeclaration(EnumConstantDeclaration node) {
222 String name = node.name.name;
223 FieldElement element = _findElement(_enclosingEnum.fields, name);
224 _processElement(element);
225 }
226
227 @override
228 visitEnumDeclaration(EnumDeclaration node) {
229 String name = node.name.name;
230 ClassElement element = _findElement(_enclosingUnit.enums, name);
231 _enclosingEnum = element;
232 _processElement(element);
233 _assertTrue(element.isEnum);
234 super.visitEnumDeclaration(node);
235 }
236
237 @override
238 visitExportDirective(ExportDirective node) {
239 String uri = _getStringValue(node.uri);
240 if (uri != null) {
241 ExportElement element =
242 _findUriReferencedElement(_enclosingLibrary.exports, uri);
243 _processElement(element);
244 _assertCombinators(node.combinators, element.combinators);
245 }
246 }
247
248 @override
249 visitExpressionFunctionBody(ExpressionFunctionBody node) {
250 // ignore bodies
251 }
252
253 @override
254 visitExtendsClause(ExtendsClause node) {
255 _assertSameType(node.superclass, _enclosingClass.supertype);
256 }
257
258 @override
259 visitFieldDeclaration(FieldDeclaration node) {
260 _enclosingFieldNode = node;
261 try {
262 super.visitFieldDeclaration(node);
263 } finally {
264 _enclosingFieldNode = null;
265 }
266 }
267
268 @override
269 visitFunctionDeclaration(FunctionDeclaration node) {
270 // prepare element name
271 String name = node.name.name;
272 if (node.isSetter) {
273 name += '=';
274 }
275 // prepare element
276 Token property = node.propertyKeyword;
277 ExecutableElementImpl element;
278 if (property == null) {
279 element = _findElement(_enclosingUnit.functions, name);
280 } else {
281 element = _findElement(_enclosingUnit.accessors, name);
282 }
283 // process element
284 _processElement(element);
285 _assertSameAnnotations(node, element);
286 _assertFalse(element.isSynthetic);
287 _assertSameType(node.returnType, element.returnType);
288 _assertCompatibleParameters(
289 node.functionExpression.parameters, element.parameters);
290 _assertBody(node.functionExpression.body, element);
291 // matches, update the existing element
292 ExecutableElement newElement = node.element;
293 node.name.staticElement = element;
294 node.functionExpression.element = element;
295 _setLocalElements(element, newElement);
296 }
297
298 @override
299 visitFunctionTypeAlias(FunctionTypeAlias node) {
300 String name = node.name.name;
301 FunctionTypeAliasElement element =
302 _findElement(_enclosingUnit.functionTypeAliases, name);
303 _processElement(element);
304 _assertSameTypeParameters(node.typeParameters, element.typeParameters);
305 _assertSameType(node.returnType, element.returnType);
306 _assertCompatibleParameters(node.parameters, element.parameters);
307 }
308
309 @override
310 visitImplementsClause(ImplementsClause node) {
311 List<TypeName> nodes = node.interfaces;
312 List<InterfaceType> types = _enclosingClass.interfaces;
313 _assertSameTypes(nodes, types);
314 }
315
316 @override
317 visitImportDirective(ImportDirective node) {
318 String uri = _getStringValue(node.uri);
319 if (uri != null) {
320 ImportElement element =
321 _findUriReferencedElement(_enclosingLibrary.imports, uri);
322 _processElement(element);
323 // match the prefix
324 SimpleIdentifier prefixNode = node.prefix;
325 PrefixElement prefixElement = element.prefix;
326 if (prefixNode == null) {
327 _assertNull(prefixElement);
328 } else {
329 _assertNotNull(prefixElement);
330 _assertEquals(prefixNode.name, prefixElement.name);
331 }
332 // match combinators
333 _assertCombinators(node.combinators, element.combinators);
334 }
335 }
336
337 @override
338 visitMethodDeclaration(MethodDeclaration node) {
339 // prepare element name
340 String name = node.name.name;
341 if (name == TokenType.MINUS.lexeme &&
342 node.parameters.parameters.length == 0) {
343 name = "unary-";
344 }
345 if (node.isSetter) {
346 name += '=';
347 }
348 // prepare element
349 Token property = node.propertyKeyword;
350 ExecutableElementImpl element;
351 if (property == null) {
352 element = _findElement(_enclosingClass.methods, name);
353 } else {
354 element = _findElement(_enclosingClass.accessors, name);
355 }
356 // process element
357 ExecutableElement newElement = node.element;
358 try {
359 _assertNotNull(element);
360 _assertSameAnnotations(node, element);
361 _assertEquals(node.isStatic, element.isStatic);
362 _assertSameType(node.returnType, element.returnType);
363 _assertCompatibleParameters(node.parameters, element.parameters);
364 _assertBody(node.body, element);
365 _removedElements.remove(element);
366 // matches, update the existing element
367 node.name.staticElement = element;
368 _setLocalElements(element, newElement);
369 } on _DeclarationMismatchException {
370 _removeElement(element);
371 // add new element
372 if (newElement != null) {
373 _addedElements.add(newElement);
374 if (newElement is MethodElement) {
375 List<MethodElement> methods = _enclosingClass.methods.toList();
376 methods.add(newElement);
377 _enclosingClass.methods = methods;
378 } else {
379 List<PropertyAccessorElement> accessors =
380 _enclosingClass.accessors.toList();
381 accessors.add(newElement);
382 _enclosingClass.accessors = accessors;
383 }
384 }
385 }
386 }
387
388 @override
389 visitPartDirective(PartDirective node) {
390 String uri = _getStringValue(node.uri);
391 if (uri != null) {
392 CompilationUnitElement element =
393 _findUriReferencedElement(_enclosingLibrary.parts, uri);
394 _processElement(element);
395 }
396 super.visitPartDirective(node);
397 }
398
399 @override
400 visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) {
401 _inTopLevelVariableDeclaration = true;
402 try {
403 super.visitTopLevelVariableDeclaration(node);
404 } finally {
405 _inTopLevelVariableDeclaration = false;
406 }
407 }
408
409 @override
410 visitVariableDeclaration(VariableDeclaration node) {
411 // prepare variable
412 String name = node.name.name;
413 PropertyInducingElement element;
414 if (_inTopLevelVariableDeclaration) {
415 element = _findElement(_enclosingUnit.topLevelVariables, name);
416 } else {
417 element = _findElement(_enclosingClass.fields, name);
418 }
419 // verify
420 PropertyInducingElement newElement = node.name.staticElement;
421 _processElement(element);
422 _assertSameAnnotations(node, element);
423 _assertEquals(node.isConst, element.isConst);
424 _assertEquals(node.isFinal, element.isFinal);
425 if (_enclosingFieldNode != null) {
426 _assertEquals(_enclosingFieldNode.isStatic, element.isStatic);
427 }
428 _assertSameType(
429 (node.parent as VariableDeclarationList).type, element.type);
430 // matches, restore the existing element
431 node.name.staticElement = element;
432 Element variable = element;
433 if (variable is VariableElementImpl) {
434 variable.initializer = newElement.initializer;
435 }
436 }
437
438 @override
439 visitWithClause(WithClause node) {
440 List<TypeName> nodes = node.mixinTypes;
441 List<InterfaceType> types = _enclosingClass.mixins;
442 _assertSameTypes(nodes, types);
443 }
444
445 /**
446 * Assert that the given [body] is compatible with the given [element].
447 * It should not be empty if the [element] is not an abstract class member.
448 * If it is present, it should have the same async / generator modifiers.
449 */
450 void _assertBody(FunctionBody body, ExecutableElementImpl element) {
451 if (body is EmptyFunctionBody) {
452 _assertTrue(element.isAbstract);
453 } else {
454 _assertFalse(element.isAbstract);
455 _assertEquals(body.isSynchronous, element.isSynchronous);
456 _assertEquals(body.isGenerator, element.isGenerator);
457 }
458 }
459
460 void _assertCombinators(List<Combinator> nodeCombinators,
461 List<NamespaceCombinator> elementCombinators) {
462 // prepare shown/hidden names in the element
463 Set<String> showNames = new Set<String>();
464 Set<String> hideNames = new Set<String>();
465 for (NamespaceCombinator combinator in elementCombinators) {
466 if (combinator is ShowElementCombinator) {
467 showNames.addAll(combinator.shownNames);
468 } else if (combinator is HideElementCombinator) {
469 hideNames.addAll(combinator.hiddenNames);
470 }
471 }
472 // match combinators with the node
473 for (Combinator combinator in nodeCombinators) {
474 if (combinator is ShowCombinator) {
475 for (SimpleIdentifier nameNode in combinator.shownNames) {
476 String name = nameNode.name;
477 _assertTrue(showNames.remove(name));
478 }
479 } else if (combinator is HideCombinator) {
480 for (SimpleIdentifier nameNode in combinator.hiddenNames) {
481 String name = nameNode.name;
482 _assertTrue(hideNames.remove(name));
483 }
484 }
485 }
486 _assertTrue(showNames.isEmpty);
487 _assertTrue(hideNames.isEmpty);
488 }
489
490 void _assertCompatibleParameter(
491 FormalParameter node, ParameterElement element) {
492 _assertEquals(node.kind, element.parameterKind);
493 if (node.kind == ParameterKind.NAMED ||
494 element.enclosingElement is ConstructorElement) {
495 _assertEquals(node.identifier.name, element.name);
496 }
497 // check parameter type specific properties
498 if (node is DefaultFormalParameter) {
499 Expression nodeDefault = node.defaultValue;
500 if (nodeDefault == null) {
501 _assertNull(element.defaultValueCode);
502 } else {
503 _assertEquals(nodeDefault.toSource(), element.defaultValueCode);
504 }
505 _assertCompatibleParameter(node.parameter, element);
506 } else if (node is FieldFormalParameter) {
507 _assertTrue(element.isInitializingFormal);
508 DartType parameterType = element.type;
509 if (node.type == null && node.parameters == null) {
510 FieldFormalParameterElement parameterElement = element;
511 if (!parameterElement.hasImplicitType) {
512 _assertTrue(parameterType == null || parameterType.isDynamic);
513 }
514 if (parameterElement.field != null) {
515 _assertEquals(node.identifier.name, element.name);
516 }
517 } else {
518 if (node.parameters != null) {
519 _assertTrue(parameterType is FunctionType);
520 FunctionType parameterFunctionType = parameterType;
521 _assertSameType(node.type, parameterFunctionType.returnType);
522 } else {
523 _assertSameType(node.type, parameterType);
524 }
525 }
526 _assertCompatibleParameters(node.parameters, element.parameters);
527 } else if (node is FunctionTypedFormalParameter) {
528 _assertFalse(element.isInitializingFormal);
529 _assertTrue(element.type is FunctionType);
530 FunctionType elementType = element.type;
531 _assertCompatibleParameters(node.parameters, element.parameters);
532 _assertSameType(node.returnType, elementType.returnType);
533 } else if (node is SimpleFormalParameter) {
534 _assertFalse(element.isInitializingFormal);
535 _assertSameType(node.type, element.type);
536 }
537 }
538
539 void _assertCompatibleParameters(
540 FormalParameterList nodes, List<ParameterElement> elements) {
541 if (nodes == null) {
542 return _assertEquals(elements.length, 0);
543 }
544 List<FormalParameter> parameters = nodes.parameters;
545 int length = parameters.length;
546 _assertEquals(length, elements.length);
547 for (int i = 0; i < length; i++) {
548 _assertCompatibleParameter(parameters[i], elements[i]);
549 }
550 }
551
552 /**
553 * Asserts that there is an import with the same prefix as the given
554 * [prefixNode], which exposes the given [element].
555 */
556 void _assertElementVisibleWithPrefix(
557 SimpleIdentifier prefixNode, Element element) {
558 if (prefixNode == null) {
559 return;
560 }
561 String prefixName = prefixNode.name;
562 for (ImportElement import in _enclosingLibrary.imports) {
563 if (import.prefix != null && import.prefix.name == prefixName) {
564 Namespace namespace =
565 new NamespaceBuilder().createImportNamespaceForDirective(import);
566 Iterable<Element> visibleElements = namespace.definedNames.values;
567 if (visibleElements.contains(element)) {
568 return;
569 }
570 }
571 }
572 _assertTrue(false);
573 }
574
575 void _assertEquals(Object a, Object b) {
576 if (a != b) {
577 throw new _DeclarationMismatchException();
578 }
579 }
580
581 void _assertFalse(bool condition) {
582 if (condition) {
583 throw new _DeclarationMismatchException();
584 }
585 }
586
587 void _assertNotNull(Object object) {
588 if (object == null) {
589 throw new _DeclarationMismatchException();
590 }
591 }
592
593 void _assertNull(Object object) {
594 if (object != null) {
595 throw new _DeclarationMismatchException();
596 }
597 }
598
599 void _assertSameAnnotation(Annotation node, ElementAnnotation annotation) {
600 Element element = annotation.element;
601 if (element is ConstructorElement) {
602 _assertTrue(node.name is SimpleIdentifier);
603 _assertNull(node.constructorName);
604 TypeName nodeType = new TypeName(node.name, null);
605 _assertSameType(nodeType, element.returnType);
606 // TODO(scheglov) validate arguments
607 }
608 if (element is PropertyAccessorElement) {
609 _assertTrue(node.name is SimpleIdentifier);
610 String nodeName = node.name.name;
611 String elementName = element.displayName;
612 _assertEquals(nodeName, elementName);
613 }
614 }
615
616 void _assertSameAnnotations(AnnotatedNode node, Element element) {
617 List<Annotation> nodeAnnotations = node.metadata;
618 List<ElementAnnotation> elementAnnotations = element.metadata;
619 int length = nodeAnnotations.length;
620 _assertEquals(elementAnnotations.length, length);
621 for (int i = 0; i < length; i++) {
622 _assertSameAnnotation(nodeAnnotations[i], elementAnnotations[i]);
623 }
624 }
625
626 void _assertSameType(TypeName node, DartType type) {
627 // no type == dynamic
628 if (node == null) {
629 return _assertTrue(type == null || type.isDynamic);
630 }
631 if (type == null) {
632 return _assertTrue(false);
633 }
634 // prepare name
635 SimpleIdentifier prefixIdentifier = null;
636 Identifier nameIdentifier = node.name;
637 if (nameIdentifier is PrefixedIdentifier) {
638 PrefixedIdentifier prefixedIdentifier = nameIdentifier;
639 prefixIdentifier = prefixedIdentifier.prefix;
640 nameIdentifier = prefixedIdentifier.identifier;
641 }
642 String nodeName = nameIdentifier.name;
643 // check specific type kinds
644 if (type is ParameterizedType) {
645 _assertEquals(nodeName, type.name);
646 _assertElementVisibleWithPrefix(prefixIdentifier, type.element);
647 // check arguments
648 TypeArgumentList nodeArgumentList = node.typeArguments;
649 List<DartType> typeArguments = type.typeArguments;
650 if (nodeArgumentList == null) {
651 // Node doesn't have type arguments, so all type arguments of the
652 // element must be "dynamic".
653 for (DartType typeArgument in typeArguments) {
654 _assertTrue(typeArgument.isDynamic);
655 }
656 } else {
657 List<TypeName> nodeArguments = nodeArgumentList.arguments;
658 _assertSameTypes(nodeArguments, typeArguments);
659 }
660 } else if (type is TypeParameterType) {
661 _assertEquals(nodeName, type.name);
662 // TODO(scheglov) it should be possible to rename type parameters
663 } else if (type.isVoid) {
664 _assertEquals(nodeName, 'void');
665 } else if (type.isDynamic) {
666 _assertEquals(nodeName, 'dynamic');
667 } else {
668 // TODO(scheglov) support other types
669 logger.log('node: $node type: $type type.type: ${type.runtimeType}');
670 _assertTrue(false);
671 }
672 }
673
674 void _assertSameTypeParameter(
675 TypeParameter node, TypeParameterElement element) {
676 _assertSameType(node.bound, element.bound);
677 }
678
679 void _assertSameTypeParameters(
680 TypeParameterList nodesList, List<TypeParameterElement> elements) {
681 if (nodesList == null) {
682 return _assertEquals(elements.length, 0);
683 }
684 List<TypeParameter> nodes = nodesList.typeParameters;
685 int length = nodes.length;
686 _assertEquals(length, elements.length);
687 for (int i = 0; i < length; i++) {
688 _assertSameTypeParameter(nodes[i], elements[i]);
689 }
690 }
691
692 void _assertSameTypes(List<TypeName> nodes, List<DartType> types) {
693 int length = nodes.length;
694 _assertEquals(length, types.length);
695 for (int i = 0; i < length; i++) {
696 _assertSameType(nodes[i], types[i]);
697 }
698 }
699
700 void _assertTrue(bool condition) {
701 if (!condition) {
702 throw new _DeclarationMismatchException();
703 }
704 }
705
706 /**
707 * Given that the comparison is to begin with the given [element], capture
708 * the enclosing elements that might be used while performing the comparison.
709 */
710 void _captureEnclosingElements(Element element) {
711 Element parent =
712 element is CompilationUnitElement ? element : element.enclosingElement;
713 while (parent != null) {
714 if (parent is CompilationUnitElement) {
715 _enclosingUnit = parent;
716 _enclosingLibrary = element.library;
717 } else if (parent is ClassElement) {
718 if (_enclosingClass == null) {
719 _enclosingClass = parent;
720 }
721 } else if (parent is FunctionTypeAliasElement) {
722 if (_enclosingAlias == null) {
723 _enclosingAlias = parent;
724 }
725 } else if (parent is ParameterElement) {
726 if (_enclosingParameter == null) {
727 _enclosingParameter = parent;
728 }
729 }
730 parent = parent.enclosingElement;
731 }
732 }
733
734 void _gatherElements(Element element) {
735 _ElementsGatherer gatherer = new _ElementsGatherer(this);
736 element.accept(gatherer);
737 // TODO(scheglov) what if a change in a directive?
738 if (identical(element, _enclosingLibrary.definingCompilationUnit)) {
739 gatherer.addElements(_enclosingLibrary.imports);
740 gatherer.addElements(_enclosingLibrary.exports);
741 gatherer.addElements(_enclosingLibrary.parts);
742 }
743 }
744
745 void _processElement(Element element) {
746 _assertNotNull(element);
747 if (!_allElements.contains(element)) {
748 throw new _DeclarationMismatchException();
749 }
750 _removedElements.remove(element);
751 }
752
753 void _removeElement(Element element) {
754 if (element != null) {
755 Element enclosingElement = element.enclosingElement;
756 if (element is MethodElement) {
757 ClassElement classElement = enclosingElement;
758 _removeIdenticalElement(classElement.methods, element);
759 } else if (element is PropertyAccessorElement) {
760 if (enclosingElement is ClassElement) {
761 _removeIdenticalElement(enclosingElement.accessors, element);
762 }
763 if (enclosingElement is CompilationUnitElement) {
764 _removeIdenticalElement(enclosingElement.accessors, element);
765 }
766 }
767 }
768 }
769
770 /**
771 * Return the [Element] in [elements] with the given [name].
772 */
773 static Element _findElement(List<Element> elements, String name) {
774 for (Element element in elements) {
775 if (element.name == name) {
776 return element;
777 }
778 }
779 return null;
780 }
781
782 /**
783 * Return the [UriReferencedElement] from [elements] with the given [uri], or
784 * `null` if there is no such element.
785 */
786 static UriReferencedElement _findUriReferencedElement(
787 List<UriReferencedElement> elements, String uri) {
788 for (UriReferencedElement element in elements) {
789 if (element.uri == uri) {
790 return element;
791 }
792 }
793 return null;
794 }
795
796 /**
797 * Return the value of [literal], or `null` if the string is not a constant
798 * string without any string interpolation.
799 */
800 static String _getStringValue(StringLiteral literal) {
801 if (literal is StringInterpolation) {
802 return null;
803 }
804 return literal.stringValue;
805 }
806
807 /**
808 * Removes the first element identical to the given [element] from [elements].
809 */
810 static void _removeIdenticalElement(List elements, Object element) {
811 int length = elements.length;
812 for (int i = 0; i < length; i++) {
813 if (identical(elements[i], element)) {
814 elements.removeAt(i);
815 return;
816 }
817 }
818 }
819
820 static void _setLocalElements(
821 ExecutableElementImpl to, ExecutableElement from) {
822 if (from != null) {
823 to.functions = from.functions;
824 to.labels = from.labels;
825 to.localVariables = from.localVariables;
826 to.parameters = from.parameters;
827 }
828 }
829 }
830
831 /**
832 * Describes how declarations match an existing elements model.
833 */
834 class DeclarationMatchKind {
835 /**
836 * Complete match, no API changes.
837 */
838 static const MATCH = const DeclarationMatchKind('MATCH');
839
840 /**
841 * Has API changes that we might be able to resolve incrementally.
842 */
843 static const MISMATCH_OK = const DeclarationMatchKind('MISMATCH_OK');
844
845 /**
846 * Has API changes that we cannot resolve incrementally.
847 */
848 static const MISMATCH = const DeclarationMatchKind('MISMATCH');
849
850 final String name;
851
852 const DeclarationMatchKind(this.name);
853
854 @override
855 String toString() => name;
856 }
857
858 /**
859 * The [Delta] implementation used by incremental resolver. 51 * The [Delta] implementation used by incremental resolver.
860 * It keeps Dart results that are either don't change or are updated. 52 * It keeps Dart results that are either don't change or are updated.
861 */ 53 */
862 class IncrementalBodyDelta extends Delta { 54 class IncrementalBodyDelta extends Delta {
863 /** 55 /**
864 * The offset of the changed contents. 56 * The offset of the changed contents.
865 */ 57 */
866 final int updateOffset; 58 final int updateOffset;
867 59
868 /** 60 /**
(...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after
1055 _typeProvider = definingUnit.context.typeProvider, 247 _typeProvider = definingUnit.context.typeProvider,
1056 _typeSystem = definingUnit.context.typeSystem, 248 _typeSystem = definingUnit.context.typeSystem,
1057 _definingLibrary = definingUnit.library, 249 _definingLibrary = definingUnit.library,
1058 _source = definingUnit.source, 250 _source = definingUnit.source,
1059 _librarySource = definingUnit.library.source, 251 _librarySource = definingUnit.library.source,
1060 _updateEndOld = updateEndOld, 252 _updateEndOld = updateEndOld,
1061 _updateEndNew = updateEndNew, 253 _updateEndNew = updateEndNew,
1062 _updateDelta = updateEndNew - updateEndOld; 254 _updateDelta = updateEndNew - updateEndOld;
1063 255
1064 /** 256 /**
1065 * Resolve [node], reporting any errors or warnings to the given listener. 257 * Resolve [body], reporting any errors or warnings to the given listener.
1066 * 258 *
1067 * [node] - the root of the AST structure to be resolved. 259 * [body] - the root of the AST structure to be resolved.
1068 * 260 *
1069 * Returns `true` if resolution was successful. 261 * Returns `true` if resolution was successful.
1070 */ 262 */
1071 bool resolve(AstNode node) { 263 bool resolve(BlockFunctionBody body) {
1072 logger.enter('resolve: $_definingUnit'); 264 logger.enter('resolve: $_definingUnit');
1073 try { 265 try {
1074 AstNode rootNode = _findResolutionRoot(node); 266 Declaration executable = _findResolutionRoot(body);
1075 _prepareResolutionContext(rootNode); 267 _prepareResolutionContext(executable);
1076 // update elements 268 // update elements
1077 _updateCache(); 269 _updateCache();
1078 _updateElementNameOffsets(); 270 _updateElementNameOffsets();
1079 _buildElements(rootNode); 271 _buildElements(executable, body);
1080 if (!_canBeIncrementallyResolved(rootNode)) {
1081 return false;
1082 }
1083 // resolve 272 // resolve
1084 _resolveReferences(rootNode); 273 _resolveReferences(executable);
1085 _computeConstants(rootNode); 274 _computeConstants(executable);
1086 _resolveErrors = errorListener.getErrorsForSource(_source); 275 _resolveErrors = errorListener.getErrorsForSource(_source);
1087 // verify 276 // verify
1088 _verify(rootNode); 277 _verify(executable);
1089 _context.invalidateLibraryHints(_librarySource); 278 _context.invalidateLibraryHints(_librarySource);
1090 // update entry errors 279 // update entry errors
1091 _updateEntry(); 280 _updateEntry();
1092 // OK 281 // OK
1093 return true; 282 return true;
1094 } finally { 283 } finally {
1095 logger.exit(); 284 logger.exit();
1096 } 285 }
1097 } 286 }
1098 287
1099 void _buildElements(AstNode node) { 288 void _buildElements(Declaration executable, AstNode node) {
1100 LoggingTimer timer = logger.startTimer(); 289 LoggingTimer timer = logger.startTimer();
1101 try { 290 try {
1102 ElementHolder holder = new ElementHolder(); 291 ElementHolder holder = new ElementHolder();
1103 ElementBuilder builder = new ElementBuilder(holder, _definingUnit); 292 ElementBuilder builder = new ElementBuilder(holder, _definingUnit);
1104 if (_resolutionContext.enclosingClassDeclaration != null) { 293 builder.initForFunctionBodyIncrementalResolution();
1105 builder.visitClassDeclarationIncrementally(
1106 _resolutionContext.enclosingClassDeclaration);
1107 }
1108 node.accept(builder); 294 node.accept(builder);
295 // Move local elements into the ExecutableElementImpl.
296 ExecutableElementImpl executableElement =
297 executable.element as ExecutableElementImpl;
298 executableElement.localVariables = holder.localVariables;
299 executableElement.functions = holder.functions;
300 executableElement.labels = holder.labels;
301 holder.validate();
1109 } finally { 302 } finally {
1110 timer.stop('build elements'); 303 timer.stop('build elements');
1111 } 304 }
1112 } 305 }
1113 306
1114 /** 307 /**
1115 * Return `true` if [node] does not have element model changes, or these
1116 * changes can be incrementally propagated.
1117 */
1118 bool _canBeIncrementallyResolved(AstNode node) {
1119 // If we are replacing the whole declaration, this means that its signature
1120 // is changed. It might be an API change, or not.
1121 //
1122 // If, for example, a required parameter is changed, it is not an API
1123 // change, but we want to find the existing corresponding Element in the
1124 // enclosing one, set it for the node and update as needed.
1125 //
1126 // If, for example, the name of a method is changed, it is an API change,
1127 // we need to know the old Element and the new Element. Again, we need to
1128 // check the whole enclosing Element.
1129 if (node is Declaration) {
1130 node = node.parent;
1131 }
1132 Element element = _getElement(node);
1133 DeclarationMatcher matcher = new DeclarationMatcher();
1134 DeclarationMatchKind matchKind = matcher.matches(node, element);
1135 if (matchKind == DeclarationMatchKind.MATCH) {
1136 return true;
1137 }
1138 // mismatch that cannot be incrementally fixed
1139 return false;
1140 }
1141
1142 /**
1143 * Return `true` if the given node can be resolved independently of any other
1144 * nodes.
1145 *
1146 * *Note*: This method needs to be kept in sync with
1147 * [ScopeBuilder.ContextBuilder].
1148 *
1149 * [node] - the node being tested.
1150 */
1151 bool _canBeResolved(AstNode node) =>
1152 node is ClassDeclaration ||
1153 node is ClassTypeAlias ||
1154 node is CompilationUnit ||
1155 node is ConstructorDeclaration ||
1156 node is FunctionDeclaration ||
1157 node is FunctionTypeAlias ||
1158 node is MethodDeclaration ||
1159 node is TopLevelVariableDeclaration;
1160
1161 /**
1162 * Compute a value for all of the constants in the given [node]. 308 * Compute a value for all of the constants in the given [node].
1163 */ 309 */
1164 void _computeConstants(AstNode node) { 310 void _computeConstants(AstNode node) {
1165 // compute values 311 // compute values
1166 { 312 {
1167 CompilationUnit unit = node.getAncestor((n) => n is CompilationUnit); 313 CompilationUnit unit = node.getAncestor((n) => n is CompilationUnit);
1168 ConstantValueComputer computer = new ConstantValueComputer(_context, 314 ConstantValueComputer computer = new ConstantValueComputer(_context,
1169 _typeProvider, _context.declaredVariables, null, _typeSystem); 315 _typeProvider, _context.declaredVariables, null, _typeSystem);
1170 computer.add(unit, _source, _librarySource); 316 computer.add(unit, _source, _librarySource);
1171 computer.computeValues(); 317 computer.computeValues();
1172 } 318 }
1173 // validate 319 // validate
1174 { 320 {
1175 ErrorReporter errorReporter = new ErrorReporter(errorListener, _source); 321 ErrorReporter errorReporter = new ErrorReporter(errorListener, _source);
1176 ConstantVerifier constantVerifier = new ConstantVerifier(errorReporter, 322 ConstantVerifier constantVerifier = new ConstantVerifier(errorReporter,
1177 _definingLibrary, _typeProvider, _context.declaredVariables); 323 _definingLibrary, _typeProvider, _context.declaredVariables);
1178 node.accept(constantVerifier); 324 node.accept(constantVerifier);
1179 } 325 }
1180 } 326 }
1181 327
1182 /** 328 /**
1183 * Starting at [node], find the smallest AST node that can be resolved 329 * Starting at [node], find the smallest AST node that can be resolved
1184 * independently of any other nodes. Return the node that was found. 330 * independently of any other nodes. Return the node that was found.
1185 * 331 *
1186 * [node] - the node at which the search is to begin 332 * [node] - the node at which the search is to begin
1187 * 333 *
1188 * Throws [AnalysisException] if there is no such node. 334 * Throws [AnalysisException] if there is no such node.
1189 */ 335 */
1190 AstNode _findResolutionRoot(AstNode node) { 336 Declaration _findResolutionRoot(AstNode node) {
1191 while (node != null) { 337 while (node != null) {
1192 if (_canBeResolved(node)) { 338 if (node is ConstructorDeclaration ||
339 node is FunctionDeclaration ||
340 node is MethodDeclaration) {
1193 return node; 341 return node;
1194 } 342 }
1195 node = node.parent; 343 node = node.parent;
1196 } 344 }
1197 throw new AnalysisException("Cannot resolve node: no resolvable node"); 345 throw new AnalysisException("Cannot resolve node: no resolvable node");
1198 } 346 }
1199 347
1200 /**
1201 * Return the element defined by [node], or `null` if the node does not
1202 * define an element.
1203 */
1204 Element _getElement(AstNode node) {
1205 if (node is Declaration) {
1206 return node.element;
1207 } else if (node is CompilationUnit) {
1208 return node.element;
1209 }
1210 return null;
1211 }
1212
1213 void _prepareResolutionContext(AstNode node) { 348 void _prepareResolutionContext(AstNode node) {
1214 if (_resolutionContext == null) { 349 if (_resolutionContext == null) {
1215 _resolutionContext = 350 _resolutionContext =
1216 ResolutionContextBuilder.contextFor(node, errorListener); 351 ResolutionContextBuilder.contextFor(node, errorListener);
1217 } 352 }
1218 } 353 }
1219 354
1220 _resolveReferences(AstNode node) { 355 _resolveReferences(AstNode node) {
1221 LoggingTimer timer = logger.startTimer(); 356 LoggingTimer timer = logger.startTimer();
1222 try { 357 try {
(...skipping 302 matching lines...) Expand 10 before | Expand all | Expand 10 after
1525 logger.log( 660 logger.log(
1526 'Failure: class declarations mismatch $oldLength vs. $newLen gth'); 661 'Failure: class declarations mismatch $oldLength vs. $newLen gth');
1527 return false; 662 return false;
1528 } 663 }
1529 } else if (oldParent is FunctionDeclaration && 664 } else if (oldParent is FunctionDeclaration &&
1530 newParent is FunctionDeclaration || 665 newParent is FunctionDeclaration ||
1531 oldParent is ConstructorDeclaration && 666 oldParent is ConstructorDeclaration &&
1532 newParent is ConstructorDeclaration || 667 newParent is ConstructorDeclaration ||
1533 oldParent is MethodDeclaration && 668 oldParent is MethodDeclaration &&
1534 newParent is MethodDeclaration) { 669 newParent is MethodDeclaration) {
1535 Element oldElement = (oldParent as Declaration).element; 670 if (oldParents.length == i || newParents.length == i) {
1536 if (new DeclarationMatcher().matches(newParent, oldElement) ==
1537 DeclarationMatchKind.MATCH) {
1538 oldNode = oldParent;
1539 newNode = newParent;
1540 found = true;
1541 } else {
1542 return false; 671 return false;
1543 } 672 }
1544 } else if (oldParent is FunctionBody && newParent is FunctionBody) { 673 } else if (oldParent is FunctionBody && newParent is FunctionBody) {
1545 if (oldParent is BlockFunctionBody && 674 if (oldParent is BlockFunctionBody &&
1546 newParent is BlockFunctionBody) { 675 newParent is BlockFunctionBody) {
1547 oldNode = oldParent; 676 oldNode = oldParent;
1548 newNode = newParent; 677 newNode = newParent;
1549 found = true; 678 found = true;
1550 break; 679 break;
1551 } 680 }
(...skipping 513 matching lines...) Expand 10 before | Expand all | Expand 10 after
2065 ResolutionContext context = new ResolutionContext(); 1194 ResolutionContext context = new ResolutionContext();
2066 context.scope = scope; 1195 context.scope = scope;
2067 context.enclosingUnit = builder._enclosingUnit; 1196 context.enclosingUnit = builder._enclosingUnit;
2068 context.enclosingClassDeclaration = builder._enclosingClassDeclaration; 1197 context.enclosingClassDeclaration = builder._enclosingClassDeclaration;
2069 context.enclosingClass = builder._enclosingClass; 1198 context.enclosingClass = builder._enclosingClass;
2070 return context; 1199 return context;
2071 } 1200 }
2072 } 1201 }
2073 1202
2074 /** 1203 /**
2075 * Instances of the class [_DeclarationMismatchException] represent an exception
2076 * that is thrown when the element model defined by a given AST structure does
2077 * not match an existing element model.
2078 */
2079 class _DeclarationMismatchException {}
2080
2081 /**
2082 * Adjusts the location of each Element that moved. 1204 * Adjusts the location of each Element that moved.
2083 * 1205 *
2084 * Since `==` and `hashCode` of a local variable or function Element are based 1206 * Since `==` and `hashCode` of a local variable or function Element are based
2085 * on the element name offsets, we also need to remove these elements from the 1207 * on the element name offsets, we also need to remove these elements from the
2086 * cache to avoid a memory leak. TODO(scheglov) fix and remove this 1208 * cache to avoid a memory leak. TODO(scheglov) fix and remove this
2087 */ 1209 */
2088 class _ElementOffsetUpdater extends GeneralizingElementVisitor { 1210 class _ElementOffsetUpdater extends GeneralizingElementVisitor {
2089 final int updateOffset; 1211 final int updateOffset;
2090 final int updateDelta; 1212 final int updateDelta;
2091 final AnalysisCache cache; 1213 final AnalysisCache cache;
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
2166 } 1288 }
2167 // next 1289 // next
2168 if (token.type == TokenType.EOF) { 1290 if (token.type == TokenType.EOF) {
2169 break; 1291 break;
2170 } 1292 }
2171 token = token.next; 1293 token = token.next;
2172 } 1294 }
2173 } 1295 }
2174 } 1296 }
2175 1297
2176 class _ElementsGatherer extends GeneralizingElementVisitor {
2177 final DeclarationMatcher matcher;
2178
2179 _ElementsGatherer(this.matcher);
2180
2181 void addElements(List<Element> elements) {
2182 for (Element element in elements) {
2183 if (!element.isSynthetic) {
2184 _addElement(element);
2185 }
2186 }
2187 }
2188
2189 @override
2190 visitElement(Element element) {
2191 _addElement(element);
2192 super.visitElement(element);
2193 }
2194
2195 @override
2196 visitExecutableElement(ExecutableElement element) {
2197 _addElement(element);
2198 }
2199
2200 @override
2201 visitParameterElement(ParameterElement element) {}
2202
2203 @override
2204 visitPropertyAccessorElement(PropertyAccessorElement element) {
2205 if (!element.isSynthetic) {
2206 _addElement(element);
2207 }
2208 // Don't visit children (such as synthetic setter parameters).
2209 }
2210
2211 @override
2212 visitPropertyInducingElement(PropertyInducingElement element) {
2213 if (!element.isSynthetic) {
2214 _addElement(element);
2215 }
2216 // Don't visit children (such as property accessors).
2217 }
2218
2219 @override
2220 visitTypeParameterElement(TypeParameterElement element) {}
2221
2222 void _addElement(Element element) {
2223 if (element != null) {
2224 matcher._allElements.add(element);
2225 matcher._removedElements.add(element);
2226 }
2227 }
2228 }
2229
2230 /** 1298 /**
2231 * Describes how two [Token]s are different. 1299 * Describes how two [Token]s are different.
2232 */ 1300 */
2233 class _TokenDifferenceKind { 1301 class _TokenDifferenceKind {
2234 static const COMMENT = const _TokenDifferenceKind('COMMENT'); 1302 static const COMMENT = const _TokenDifferenceKind('COMMENT');
2235 static const COMMENT_DOC = const _TokenDifferenceKind('COMMENT_DOC'); 1303 static const COMMENT_DOC = const _TokenDifferenceKind('COMMENT_DOC');
2236 static const CONTENT = const _TokenDifferenceKind('CONTENT'); 1304 static const CONTENT = const _TokenDifferenceKind('CONTENT');
2237 static const OFFSET = const _TokenDifferenceKind('OFFSET'); 1305 static const OFFSET = const _TokenDifferenceKind('OFFSET');
2238 1306
2239 final String name; 1307 final String name;
2240 1308
2241 const _TokenDifferenceKind(this.name); 1309 const _TokenDifferenceKind(this.name);
2242 1310
2243 @override 1311 @override
2244 String toString() => name; 1312 String toString() => name;
2245 } 1313 }
2246 1314
2247 class _TokenPair { 1315 class _TokenPair {
2248 final _TokenDifferenceKind kind; 1316 final _TokenDifferenceKind kind;
2249 final Token oldToken; 1317 final Token oldToken;
2250 final Token newToken; 1318 final Token newToken;
2251 _TokenPair(this.kind, this.oldToken, this.newToken); 1319 _TokenPair(this.kind, this.oldToken, this.newToken);
2252 } 1320 }
OLDNEW
« no previous file with comments | « pkg/analyzer/lib/src/dart/element/builder.dart ('k') | pkg/analyzer/test/generated/incremental_resolver_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698