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

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

Issue 778153003: Consider adding/editing a method as a resolvable mismatch. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years 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 | Annotate | Revision Log
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 engine.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 'ast.dart'; 10 import 'ast.dart';
(...skipping 10 matching lines...) Expand all
21 import 'utilities_dart.dart'; 21 import 'utilities_dart.dart';
22 22
23 23
24 /** 24 /**
25 * If `true`, an attempt to resolve API-changing modifications is made. 25 * If `true`, an attempt to resolve API-changing modifications is made.
26 */ 26 */
27 bool _resolveApiChanges = false; 27 bool _resolveApiChanges = false;
28 28
29 29
30 /** 30 /**
31 * This method is used to enable/disable API-changing modifications resolution.
32 */
33 void set test_resolveApiChanges(bool value) {
34 _resolveApiChanges = value;
35 }
36
37
38 /**
31 * Instances of the class [DeclarationMatcher] determine whether the element 39 * Instances of the class [DeclarationMatcher] determine whether the element
32 * model defined by a given AST structure matches an existing element model. 40 * model defined by a given AST structure matches an existing element model.
33 */ 41 */
34 class DeclarationMatcher extends RecursiveAstVisitor { 42 class DeclarationMatcher extends RecursiveAstVisitor {
35 /** 43 /**
36 * The libary containing the AST nodes being visited. 44 * The libary containing the AST nodes being visited.
37 */ 45 */
38 LibraryElement _enclosingLibrary; 46 LibraryElement _enclosingLibrary;
39 47
40 /** 48 /**
41 * The compilation unit containing the AST nodes being visited. 49 * The compilation unit containing the AST nodes being visited.
42 */ 50 */
43 CompilationUnitElement _enclosingUnit; 51 CompilationUnitElement _enclosingUnit;
44 52
45 /** 53 /**
46 * The function type alias containing the AST nodes being visited, or `null` i f we are not 54 * The function type alias containing the AST nodes being visited, or `null` i f we are not
47 * in the scope of a function type alias. 55 * in the scope of a function type alias.
48 */ 56 */
49 FunctionTypeAliasElement _enclosingAlias; 57 FunctionTypeAliasElement _enclosingAlias;
50 58
51 /** 59 /**
52 * The class containing the AST nodes being visited, or `null` if we are not 60 * The class containing the AST nodes being visited, or `null` if we are not
53 * in the scope of a class. 61 * in the scope of a class.
54 */ 62 */
55 ClassElement _enclosingClass; 63 ClassElementImpl _enclosingClass;
56 64
57 /** 65 /**
58 * The parameter containing the AST nodes being visited, or `null` if we are n ot in the 66 * The parameter containing the AST nodes being visited, or `null` if we are n ot in the
59 * scope of a parameter. 67 * scope of a parameter.
60 */ 68 */
61 ParameterElement _enclosingParameter; 69 ParameterElement _enclosingParameter;
62 70
63 FieldDeclaration _enclosingFieldNode = null; 71 FieldDeclaration _enclosingFieldNode = null;
64 bool _inTopLevelVariableDeclaration = false; 72 bool _inTopLevelVariableDeclaration = false;
65 73
66 /** 74 /**
67 * Is `true` if the current class declaration has a constructor. 75 * Is `true` if the current class declaration has a constructor.
68 */ 76 */
69 bool _hasConstructor = false; 77 bool _hasConstructor = false;
70 78
71 /** 79 /**
72 * A set containing all of the elements in the element model that were defined by the old AST node 80 * A set containing all of the elements in the element model that were defined by the old AST node
73 * corresponding to the AST node being visited. 81 * corresponding to the AST node being visited.
74 */ 82 */
75 HashSet<Element> _allElements = new HashSet<Element>(); 83 HashSet<Element> _allElements = new HashSet<Element>();
76 84
77 /** 85 /**
78 * A set containing all of the elements in the element model that were defined by the old AST node 86 * A set containing all of the elements were defined in the old element model,
79 * corresponding to the AST node being visited that have not already been matc hed to nodes in the 87 * but are not defined in the new element model.
80 * AST structure being visited.
81 */ 88 */
82 HashSet<Element> _unmatchedElements = new HashSet<Element>(); 89 HashSet<Element> _removedElements = new HashSet<Element>();
83 90
84 /** 91 /**
85 * Return `true` if the declarations within the given AST structure define an element model 92 * A set containing all of the elements are defined in the new element model,
86 * that is equivalent to the corresponding elements rooted at the given elemen t. 93 * but were not defined in the old element model.
87 *
88 * @param node the AST structure being compared to the element model
89 * @param element the root of the element model being compared to the AST stru cture
90 * @return `true` if the AST structure defines the same elements as those in t he given
91 * element model
92 */ 94 */
93 bool matches(AstNode node, Element element) { 95 HashSet<Element> _addedElements = new HashSet<Element>();
96
97 /**
98 * Determines how elements model corresponding to the given [node] differs
99 * from the [element].
100 */
101 DeclarationMatchKind matches(AstNode node, Element element) {
94 logger.enter('match $element @ ${element.nameOffset}'); 102 logger.enter('match $element @ ${element.nameOffset}');
95 try { 103 try {
96 _captureEnclosingElements(element); 104 _captureEnclosingElements(element);
97 _gatherElements(element); 105 _gatherElements(element);
98 node.accept(this); 106 node.accept(this);
99 } on _DeclarationMismatchException catch (exception) { 107 } on _DeclarationMismatchException catch (exception) {
100 return false; 108 return DeclarationMatchKind.MISMATCH;
101 } finally { 109 } finally {
102 logger.exit(); 110 logger.exit();
103 } 111 }
104 return _unmatchedElements.isEmpty; 112 // no API changes
113 if (_removedElements.isEmpty && _addedElements.isEmpty) {
114 return DeclarationMatchKind.MATCH;
115 }
116 // simple API change
117 if (_removedElements.length <= 1 && _addedElements.length == 1) {
118 return DeclarationMatchKind.MISMATCH_OK;
119 }
120 // something more complex
121 return DeclarationMatchKind.MISMATCH;
105 } 122 }
106 123
107 @override 124 @override
108 visitBlockFunctionBody(BlockFunctionBody node) { 125 visitBlockFunctionBody(BlockFunctionBody node) {
109 // ignore bodies 126 // ignore bodies
110 } 127 }
111 128
112 @override 129 @override
113 visitClassDeclaration(ClassDeclaration node) { 130 visitClassDeclaration(ClassDeclaration node) {
114 String name = node.name.name; 131 String name = node.name.name;
(...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after
304 } 321 }
305 // prepare element 322 // prepare element
306 Token property = node.propertyKeyword; 323 Token property = node.propertyKeyword;
307 ExecutableElementImpl element; 324 ExecutableElementImpl element;
308 if (property == null) { 325 if (property == null) {
309 element = _findElement(_enclosingClass.methods, name); 326 element = _findElement(_enclosingClass.methods, name);
310 } else { 327 } else {
311 element = _findElement(_enclosingClass.accessors, name); 328 element = _findElement(_enclosingClass.accessors, name);
312 } 329 }
313 // process element 330 // process element
314 _processElement(element);
315 _assertEquals(node.isStatic, element.isStatic);
316 _assertSameType(node.returnType, element.returnType);
317 _assertCompatibleParameters(node.parameters, element.parameters);
318 // matches, update the existing element
319 ExecutableElement newElement = node.element; 331 ExecutableElement newElement = node.element;
320 node.name.staticElement = element; 332 try {
321 _setLocalElements(element, newElement); 333 _assertNotNull(element);
322 _setParameterElements(node.parameters, element.parameters); 334 _assertEquals(node.isStatic, element.isStatic);
335 _assertSameType(node.returnType, element.returnType);
336 _assertCompatibleParameters(node.parameters, element.parameters);
337 _removedElements.remove(element);
338 // matches, update the existing element
339 node.name.staticElement = element;
340 _setLocalElements(element, newElement);
341 _setParameterElements(node.parameters, element.parameters);
342 } on _DeclarationMismatchException catch (e) {
343 _addedElements.add(newElement);
344 // remove old element
345 if (element is MethodElement) {
346 _enclosingClass.methods.remove(element);
347 } else if (element is PropertyAccessorElement) {
348 _enclosingClass.accessors.remove(element);
349 }
350 // add new element
351 if (newElement is MethodElement) {
352 List<MethodElement> methods = _enclosingClass.methods;
353 methods.add(newElement);
354 _enclosingClass.methods = methods;
355 } else {
356 List<PropertyAccessorElement> accessors = _enclosingClass.accessors;
357 accessors.add(newElement);
358 _enclosingClass.accessors = accessors;
359 }
360 }
323 } 361 }
324 362
325 @override 363 @override
326 visitPartDirective(PartDirective node) { 364 visitPartDirective(PartDirective node) {
327 String uri = _getStringValue(node.uri); 365 String uri = _getStringValue(node.uri);
328 if (uri != null) { 366 if (uri != null) {
329 CompilationUnitElement element = 367 CompilationUnitElement element =
330 _findUriReferencedElement(_enclosingLibrary.parts, uri); 368 _findUriReferencedElement(_enclosingLibrary.parts, uri);
331 _processElement(element); 369 _processElement(element);
332 } 370 }
(...skipping 248 matching lines...) Expand 10 before | Expand all | Expand 10 after
581 gatherer.addElements(_enclosingLibrary.exports); 619 gatherer.addElements(_enclosingLibrary.exports);
582 gatherer.addElements(_enclosingLibrary.parts); 620 gatherer.addElements(_enclosingLibrary.parts);
583 } 621 }
584 } 622 }
585 623
586 void _processElement(Element element) { 624 void _processElement(Element element) {
587 _assertNotNull(element); 625 _assertNotNull(element);
588 if (!_allElements.contains(element)) { 626 if (!_allElements.contains(element)) {
589 throw new _DeclarationMismatchException(); 627 throw new _DeclarationMismatchException();
590 } 628 }
591 _unmatchedElements.remove(element); 629 _removedElements.remove(element);
592 } 630 }
593 631
594 /** 632 /**
595 * Return the [Element] in [elements] with the given [name]. 633 * Return the [Element] in [elements] with the given [name].
596 */ 634 */
597 static Element _findElement(List<Element> elements, String name) { 635 static Element _findElement(List<Element> elements, String name) {
598 for (Element element in elements) { 636 for (Element element in elements) {
599 if (element.name == name) { 637 if (element.name == name) {
600 return element; 638 return element;
601 } 639 }
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
645 node.identifier.staticElement = element; 683 node.identifier.staticElement = element;
646 (element as ElementImpl).name = newElement.name; 684 (element as ElementImpl).name = newElement.name;
647 (element as ElementImpl).nameOffset = newElement.nameOffset; 685 (element as ElementImpl).nameOffset = newElement.nameOffset;
648 } 686 }
649 } 687 }
650 } 688 }
651 } 689 }
652 690
653 691
654 /** 692 /**
693 * Describes how declarations match an existing elements model.
694 */
695 class DeclarationMatchKind {
696 /**
697 * Complete match, no API changes.
698 */
699 static const MATCH = const DeclarationMatchKind('MATCH');
700
701 /**
702 * Has API changes that we might be able to resolve incrementally.
703 */
704 static const MISMATCH_OK = const DeclarationMatchKind('MISMATCH_OK');
705
706 /**
707 * Has API changes that we cannot resolve incrementally.
708 */
709 static const MISMATCH = const DeclarationMatchKind('MISMATCH');
710
711 final String name;
712
713 const DeclarationMatchKind(this.name);
714
715 @override
716 String toString() => name;
717 }
718
719
720 /**
655 * Instances of the class [IncrementalResolver] resolve the smallest portion of 721 * Instances of the class [IncrementalResolver] resolve the smallest portion of
656 * an AST structure that we currently know how to resolve. 722 * an AST structure that we currently know how to resolve.
657 */ 723 */
658 class IncrementalResolver { 724 class IncrementalResolver {
659 /** 725 /**
660 * The object used to access the types from the core library. 726 * The object used to access the types from the core library.
661 */ 727 */
662 final TypeProvider _typeProvider; 728 final TypeProvider _typeProvider;
663 729
664 /** 730 /**
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after
794 // check the whole enclosing Element. 860 // check the whole enclosing Element.
795 if (node is Declaration) { 861 if (node is Declaration) {
796 node = node.parent; 862 node = node.parent;
797 } 863 }
798 Element element = _getElement(node); 864 Element element = _getElement(node);
799 if (element == null) { 865 if (element == null) {
800 throw new AnalysisException( 866 throw new AnalysisException(
801 "Cannot resolve node: a ${node.runtimeType} does not define an element "); 867 "Cannot resolve node: a ${node.runtimeType} does not define an element ");
802 } 868 }
803 DeclarationMatcher matcher = new DeclarationMatcher(); 869 DeclarationMatcher matcher = new DeclarationMatcher();
804 return !matcher.matches(node, element); 870 return matcher.matches(node, element) != DeclarationMatchKind.MATCH;
805 } 871 }
806 872
807 /** 873 /**
808 * Starting at [node], find the smallest AST node that can be resolved 874 * Starting at [node], find the smallest AST node that can be resolved
809 * independently of any other nodes. Return the node that was found. 875 * independently of any other nodes. Return the node that was found.
810 * 876 *
811 * [node] - the node at which the search is to begin 877 * [node] - the node at which the search is to begin
812 * 878 *
813 * Throws [AnalysisException] if there is no such node. 879 * Throws [AnalysisException] if there is no such node.
814 */ 880 */
(...skipping 771 matching lines...) Expand 10 before | Expand all | Expand 10 after
1586 // Don't visit children (such as property accessors). 1652 // Don't visit children (such as property accessors).
1587 } 1653 }
1588 1654
1589 @override 1655 @override
1590 visitTypeParameterElement(TypeParameterElement element) { 1656 visitTypeParameterElement(TypeParameterElement element) {
1591 } 1657 }
1592 1658
1593 void _addElement(Element element) { 1659 void _addElement(Element element) {
1594 if (element != null) { 1660 if (element != null) {
1595 matcher._allElements.add(element); 1661 matcher._allElements.add(element);
1596 matcher._unmatchedElements.add(element); 1662 matcher._removedElements.add(element);
1597 } 1663 }
1598 } 1664 }
1599 } 1665 }
1600 1666
1601 1667
1602 /** 1668 /**
1603 * Describes how two [Token]s are different. 1669 * Describes how two [Token]s are different.
1604 */ 1670 */
1605 class _TokenDifferenceKind { 1671 class _TokenDifferenceKind {
1606 static const COMMENT = const _TokenDifferenceKind('COMMENT'); 1672 static const COMMENT = const _TokenDifferenceKind('COMMENT');
1607 static const COMMENT_DOC = const _TokenDifferenceKind('COMMENT_DOC'); 1673 static const COMMENT_DOC = const _TokenDifferenceKind('COMMENT_DOC');
1608 static const CONTENT = const _TokenDifferenceKind('CONTENT'); 1674 static const CONTENT = const _TokenDifferenceKind('CONTENT');
1609 static const OFFSET = const _TokenDifferenceKind('OFFSET'); 1675 static const OFFSET = const _TokenDifferenceKind('OFFSET');
1610 1676
1611 final String name; 1677 final String name;
1612 1678
1613 const _TokenDifferenceKind(this.name); 1679 const _TokenDifferenceKind(this.name);
1614 1680
1615 @override 1681 @override
1616 String toString() => name; 1682 String toString() => name;
1617 } 1683 }
1618 1684
1619 1685
1620 class _TokenPair { 1686 class _TokenPair {
1621 final _TokenDifferenceKind kind; 1687 final _TokenDifferenceKind kind;
1622 final Token oldToken; 1688 final Token oldToken;
1623 final Token newToken; 1689 final Token newToken;
1624 _TokenPair(this.kind, this.oldToken, this.newToken); 1690 _TokenPair(this.kind, this.oldToken, this.newToken);
1625 } 1691 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698