Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 108 } on _DeclarationMismatchException catch (exception) { | 108 } on _DeclarationMismatchException catch (exception) { |
| 109 return DeclarationMatchKind.MISMATCH; | 109 return DeclarationMatchKind.MISMATCH; |
| 110 } finally { | 110 } finally { |
| 111 logger.exit(); | 111 logger.exit(); |
| 112 } | 112 } |
| 113 // no API changes | 113 // no API changes |
| 114 if (_removedElements.isEmpty && _addedElements.isEmpty) { | 114 if (_removedElements.isEmpty && _addedElements.isEmpty) { |
| 115 return DeclarationMatchKind.MATCH; | 115 return DeclarationMatchKind.MATCH; |
| 116 } | 116 } |
| 117 // simple API change | 117 // simple API change |
| 118 logger.log('_removedElements: $_removedElements'); | |
| 119 logger.log('_addedElements: $_addedElements'); | |
| 120 _removedElements.forEach(_removeElement); | |
| 118 if (_removedElements.length <= 1 && _addedElements.length == 1) { | 121 if (_removedElements.length <= 1 && _addedElements.length == 1) { |
| 119 return DeclarationMatchKind.MISMATCH_OK; | 122 return DeclarationMatchKind.MISMATCH_OK; |
| 120 } | 123 } |
| 121 // something more complex | 124 // something more complex |
| 122 logger.log('_removedElements: $_removedElements'); | |
| 123 logger.log('_addedElements: $_addedElements'); | |
| 124 return DeclarationMatchKind.MISMATCH; | 125 return DeclarationMatchKind.MISMATCH; |
| 125 } | 126 } |
| 126 | 127 |
| 127 @override | 128 @override |
| 128 visitBlockFunctionBody(BlockFunctionBody node) { | 129 visitBlockFunctionBody(BlockFunctionBody node) { |
| 129 // ignore bodies | 130 // ignore bodies |
| 130 } | 131 } |
| 131 | 132 |
| 132 @override | 133 @override |
| 133 visitClassDeclaration(ClassDeclaration node) { | 134 visitClassDeclaration(ClassDeclaration node) { |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 181 _hasConstructor = true; | 182 _hasConstructor = true; |
| 182 SimpleIdentifier constructorName = node.name; | 183 SimpleIdentifier constructorName = node.name; |
| 183 ConstructorElementImpl element = constructorName == null ? | 184 ConstructorElementImpl element = constructorName == null ? |
| 184 _enclosingClass.unnamedConstructor : | 185 _enclosingClass.unnamedConstructor : |
| 185 _enclosingClass.getNamedConstructor(constructorName.name); | 186 _enclosingClass.getNamedConstructor(constructorName.name); |
| 186 _processElement(element); | 187 _processElement(element); |
| 187 _assertCompatibleParameters(node.parameters, element.parameters); | 188 _assertCompatibleParameters(node.parameters, element.parameters); |
| 188 // TODO(scheglov) debug null Location | 189 // TODO(scheglov) debug null Location |
| 189 if (element != null) { | 190 if (element != null) { |
| 190 if (element.context == null || element.source == null) { | 191 if (element.context == null || element.source == null) { |
| 191 logger.log('Bad constructor element $element for $node in ${node.parent} '); | 192 logger.log( |
| 193 'Bad constructor element $element for $node in ${node.parent}'); | |
| 192 } | 194 } |
| 193 } | 195 } |
| 194 // matches, update the existing element | 196 // matches, update the existing element |
| 195 ExecutableElement newElement = node.element; | 197 ExecutableElement newElement = node.element; |
| 196 node.element = element; | 198 node.element = element; |
| 197 _setLocalElements(element, newElement); | 199 _setLocalElements(element, newElement); |
| 198 } | 200 } |
| 199 | 201 |
| 200 @override | 202 @override |
| 201 visitEnumConstantDeclaration(EnumConstantDeclaration node) { | 203 visitEnumConstantDeclaration(EnumConstantDeclaration node) { |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 338 _assertNotNull(element); | 340 _assertNotNull(element); |
| 339 _assertEquals(node.isStatic, element.isStatic); | 341 _assertEquals(node.isStatic, element.isStatic); |
| 340 _assertSameType(node.returnType, element.returnType); | 342 _assertSameType(node.returnType, element.returnType); |
| 341 _assertCompatibleParameters(node.parameters, element.parameters); | 343 _assertCompatibleParameters(node.parameters, element.parameters); |
| 342 _removedElements.remove(element); | 344 _removedElements.remove(element); |
| 343 // matches, update the existing element | 345 // matches, update the existing element |
| 344 node.name.staticElement = element; | 346 node.name.staticElement = element; |
| 345 _setLocalElements(element, newElement); | 347 _setLocalElements(element, newElement); |
| 346 } on _DeclarationMismatchException catch (e) { | 348 } on _DeclarationMismatchException catch (e) { |
| 347 _addedElements.add(newElement); | 349 _addedElements.add(newElement); |
| 348 // remove old element | 350 _removeElement(element); |
| 349 if (element is MethodElement) { | |
| 350 _enclosingClass.methods.remove(element); | |
| 351 } else if (element is PropertyAccessorElement) { | |
| 352 _enclosingClass.accessors.remove(element); | |
| 353 } | |
| 354 // add new element | 351 // add new element |
| 355 if (newElement is MethodElement) { | 352 if (newElement is MethodElement) { |
| 356 List<MethodElement> methods = _enclosingClass.methods; | 353 List<MethodElement> methods = _enclosingClass.methods; |
| 357 methods.add(newElement); | 354 methods.add(newElement); |
| 358 _enclosingClass.methods = methods; | 355 _enclosingClass.methods = methods; |
| 359 } else { | 356 } else { |
| 360 List<PropertyAccessorElement> accessors = _enclosingClass.accessors; | 357 List<PropertyAccessorElement> accessors = _enclosingClass.accessors; |
| 361 accessors.add(newElement); | 358 accessors.add(newElement); |
| 362 _enclosingClass.accessors = accessors; | 359 _enclosingClass.accessors = accessors; |
| 363 } | 360 } |
| (...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 626 } | 623 } |
| 627 | 624 |
| 628 void _processElement(Element element) { | 625 void _processElement(Element element) { |
| 629 _assertNotNull(element); | 626 _assertNotNull(element); |
| 630 if (!_allElements.contains(element)) { | 627 if (!_allElements.contains(element)) { |
| 631 throw new _DeclarationMismatchException(); | 628 throw new _DeclarationMismatchException(); |
| 632 } | 629 } |
| 633 _removedElements.remove(element); | 630 _removedElements.remove(element); |
| 634 } | 631 } |
| 635 | 632 |
| 633 void _removeElement(Element element) { | |
| 634 if (element != null) { | |
| 635 Element enclosingElement = element.enclosingElement; | |
| 636 if (element is MethodElement) { | |
| 637 ClassElement classElement = enclosingElement; | |
| 638 classElement.methods.removeWhere((e) => identical(e, element)); | |
|
Brian Wilkerson
2014/12/19 15:03:29
Do we really need to iterate over all of the eleme
scheglov
2014/12/19 17:43:04
No, we don't.
But we cannot use just List.remove()
| |
| 639 } else if (element is PropertyAccessorElement) { | |
| 640 if (enclosingElement is ClassElement) { | |
| 641 enclosingElement.accessors.removeWhere((e) => identical(e, element)); | |
| 642 } | |
| 643 if (enclosingElement is CompilationUnitElement) { | |
| 644 enclosingElement.accessors.removeWhere((e) => identical(e, element)); | |
| 645 } | |
| 646 } | |
| 647 } | |
| 648 } | |
| 649 | |
| 636 /** | 650 /** |
| 637 * Return the [Element] in [elements] with the given [name]. | 651 * Return the [Element] in [elements] with the given [name]. |
| 638 */ | 652 */ |
| 639 static Element _findElement(List<Element> elements, String name) { | 653 static Element _findElement(List<Element> elements, String name) { |
| 640 for (Element element in elements) { | 654 for (Element element in elements) { |
| 641 if (element.name == name) { | 655 if (element.name == name) { |
| 642 return element; | 656 return element; |
| 643 } | 657 } |
| 644 } | 658 } |
| 645 return null; | 659 return null; |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 707 String toString() => name; | 721 String toString() => name; |
| 708 } | 722 } |
| 709 | 723 |
| 710 | 724 |
| 711 /** | 725 /** |
| 712 * Instances of the class [IncrementalResolver] resolve the smallest portion of | 726 * Instances of the class [IncrementalResolver] resolve the smallest portion of |
| 713 * an AST structure that we currently know how to resolve. | 727 * an AST structure that we currently know how to resolve. |
| 714 */ | 728 */ |
| 715 class IncrementalResolver { | 729 class IncrementalResolver { |
| 716 /** | 730 /** |
| 717 * The object used to access the types from the core library. | |
| 718 */ | |
| 719 final TypeProvider _typeProvider; | |
| 720 | |
| 721 /** | |
| 722 * The element of the compilation unit being resolved. | 731 * The element of the compilation unit being resolved. |
| 723 */ | 732 */ |
| 724 final CompilationUnitElement _definingUnit; | 733 final CompilationUnitElement _definingUnit; |
| 725 | 734 |
| 726 /** | 735 /** |
| 736 * The context the compilation unit being resolved in. | |
| 737 */ | |
| 738 AnalysisContextImpl _context; | |
| 739 | |
| 740 /** | |
| 741 * The object used to access the types from the core library. | |
| 742 */ | |
| 743 TypeProvider _typeProvider; | |
| 744 | |
| 745 /** | |
| 727 * The element for the library containing the compilation unit being resolved. | 746 * The element for the library containing the compilation unit being resolved. |
| 728 */ | 747 */ |
| 729 LibraryElement _definingLibrary; | 748 LibraryElement _definingLibrary; |
| 730 | 749 |
| 731 /** | 750 /** |
| 751 * The [DartEntry] corresponding to the source being resolved. | |
| 752 */ | |
| 753 DartEntry entry; | |
| 754 | |
| 755 /** | |
| 732 * The source representing the compilation unit being visited. | 756 * The source representing the compilation unit being visited. |
| 733 */ | 757 */ |
| 734 Source _source; | 758 Source _source; |
| 735 | 759 |
| 736 /** | 760 /** |
| 737 * The offset of the changed contents. | 761 * The offset of the changed contents. |
| 738 */ | 762 */ |
| 739 final int _updateOffset; | 763 final int _updateOffset; |
| 740 | 764 |
| 741 /** | 765 /** |
| 742 * The number of characters in the original contents that were replaced. | 766 * The end of the changed contents in the old unit. |
| 743 */ | 767 */ |
| 744 final int _updateOldLength; | 768 final int _updateEndOld; |
| 745 | 769 |
| 746 /** | 770 /** |
| 747 * The number of characters in the replacement text. | 771 * The end of the changed contents in the new unit. |
| 748 */ | 772 */ |
| 749 final int _updateNewLength; | 773 final int _updateEndNew; |
| 774 | |
| 775 int _updateDelta; | |
| 750 | 776 |
| 751 RecordingErrorListener errorListener = new RecordingErrorListener(); | 777 RecordingErrorListener errorListener = new RecordingErrorListener(); |
| 752 ResolutionContext _resolutionContext; | 778 ResolutionContext _resolutionContext; |
| 753 | 779 |
| 754 List<AnalysisError> _resolveErrors = AnalysisError.NO_ERRORS; | 780 List<AnalysisError> _resolveErrors = AnalysisError.NO_ERRORS; |
| 755 List<AnalysisError> _verifyErrors = AnalysisError.NO_ERRORS; | 781 List<AnalysisError> _verifyErrors = AnalysisError.NO_ERRORS; |
| 756 List<AnalysisError> _hints = AnalysisError.NO_ERRORS; | 782 List<AnalysisError> _hints = AnalysisError.NO_ERRORS; |
| 757 | 783 |
| 758 /** | 784 /** |
| 759 * The elements that should be resolved because of API changes. | 785 * The elements that should be resolved because of API changes. |
| 760 */ | 786 */ |
| 761 HashSet<Element> _resolutionQueue = new HashSet<Element>(); | 787 HashSet<Element> _resolutionQueue = new HashSet<Element>(); |
| 762 | 788 |
| 763 /** | 789 /** |
| 764 * Initialize a newly created incremental resolver to resolve a node in the | 790 * Initialize a newly created incremental resolver to resolve a node in the |
| 765 * given source in the given library. | 791 * given source in the given library. |
| 766 */ | 792 */ |
| 767 IncrementalResolver(this._typeProvider, this._definingUnit, | 793 IncrementalResolver(this._definingUnit, this._updateOffset, |
| 768 this._updateOffset, this._updateOldLength, this._updateNewLength) { | 794 this._updateEndOld, this._updateEndNew) { |
| 795 _updateDelta = _updateEndNew - _updateEndOld; | |
| 769 _definingLibrary = _definingUnit.library; | 796 _definingLibrary = _definingUnit.library; |
| 770 _source = _definingUnit.source; | 797 _source = _definingUnit.source; |
| 798 _context = _definingUnit.context; | |
| 799 _typeProvider = _context.typeProvider; | |
| 800 entry = _context.getReadableSourceEntryOrNull(_source); | |
| 771 } | 801 } |
| 772 | 802 |
| 773 /** | 803 /** |
| 774 * Resolve [node], reporting any errors or warnings to the given listener. | 804 * Resolve [node], reporting any errors or warnings to the given listener. |
| 775 * | 805 * |
| 776 * [node] - the root of the AST structure to be resolved. | 806 * [node] - the root of the AST structure to be resolved. |
| 777 * | 807 * |
| 778 * Returns `true` if resolution was successful. | 808 * Returns `true` if resolution was successful. |
| 779 */ | 809 */ |
| 780 bool resolve(AstNode node) { | 810 bool resolve(AstNode node) { |
| 781 logger.enter('resolve: $_definingUnit'); | 811 logger.enter('resolve: $_definingUnit'); |
| 782 try { | 812 try { |
| 783 logger.log(() => 'node: $node'); | |
| 784 AstNode rootNode = _findResolutionRoot(node); | 813 AstNode rootNode = _findResolutionRoot(node); |
| 785 logger.log(() => 'rootNode: $rootNode'); | |
| 786 _prepareResolutionContext(rootNode); | 814 _prepareResolutionContext(rootNode); |
| 787 // update elements | 815 // update elements |
| 788 _updateElementNameOffsets( | 816 _updateElementNameOffsets(); |
| 789 _definingUnit, | |
| 790 _updateOffset, | |
| 791 _updateNewLength - _updateOldLength); | |
| 792 _buildElements(rootNode); | 817 _buildElements(rootNode); |
| 793 if (!_canBeIncrementallyResolved(rootNode)) { | 818 if (!_canBeIncrementallyResolved(rootNode)) { |
| 794 return false; | 819 return false; |
| 795 } | 820 } |
| 796 // resolve | 821 // resolve |
| 797 _resolveReferences(rootNode); | 822 _resolveReferences(rootNode); |
| 798 // verify | 823 // verify |
| 799 _verify(rootNode); | 824 _verify(rootNode); |
| 800 _generateHints(rootNode); | 825 _generateHints(rootNode); |
| 826 // update entry errors | |
| 827 _updateEntry(); | |
| 801 // resolve queue in response of API changes | 828 // resolve queue in response of API changes |
| 802 _resolveQueue(); | 829 _resolveQueue(); |
| 803 // OK | 830 // OK |
| 804 return true; | 831 return true; |
| 805 } finally { | 832 } finally { |
| 806 logger.exit(); | 833 logger.exit(); |
| 807 } | 834 } |
| 808 } | 835 } |
| 809 | 836 |
| 810 void _buildElements(AstNode node) { | 837 void _buildElements(AstNode node) { |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 867 bool _canBeResolved(AstNode node) => | 894 bool _canBeResolved(AstNode node) => |
| 868 node is ClassDeclaration || | 895 node is ClassDeclaration || |
| 869 node is ClassTypeAlias || | 896 node is ClassTypeAlias || |
| 870 node is CompilationUnit || | 897 node is CompilationUnit || |
| 871 node is ConstructorDeclaration || | 898 node is ConstructorDeclaration || |
| 872 node is FunctionDeclaration || | 899 node is FunctionDeclaration || |
| 873 node is FunctionTypeAlias || | 900 node is FunctionTypeAlias || |
| 874 node is MethodDeclaration; | 901 node is MethodDeclaration; |
| 875 | 902 |
| 876 void _fillResolutionQueue(DeclarationMatcher matcher) { | 903 void _fillResolutionQueue(DeclarationMatcher matcher) { |
| 877 for (Element removedElement in matcher._removedElements) { | 904 HashSet<Element> removedElements = matcher._removedElements; |
| 905 logger.log('${removedElements.length} elements removed'); | |
| 906 for (Element removedElement in removedElements) { | |
| 878 AnalysisContextImpl context = removedElement.context; | 907 AnalysisContextImpl context = removedElement.context; |
| 879 IntSet users = removedElement.users; | 908 IntSet users = removedElement.users; |
| 880 while (!users.isEmpty) { | 909 while (!users.isEmpty) { |
| 881 int id = users.remove(); | 910 int id = users.remove(); |
| 882 Element removedElementUser = context.findElementById(id); | 911 Element removedElementUser = context.findElementById(id); |
| 883 _resolutionQueue.add(removedElementUser); | 912 _resolutionQueue.add(removedElementUser); |
| 884 } | 913 } |
| 885 } | 914 } |
| 886 // TODO(scheglov) a method change might also require its class, and | 915 // TODO(scheglov) a method change might also require its class, and |
| 887 // subclasses resolution | 916 // subclasses resolution |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 941 } | 970 } |
| 942 | 971 |
| 943 /** | 972 /** |
| 944 * Resolves elements [_resolutionQueue]. | 973 * Resolves elements [_resolutionQueue]. |
| 945 * | 974 * |
| 946 * TODO(scheglov) work in progress | 975 * TODO(scheglov) work in progress |
| 947 * | 976 * |
| 948 * TODO(scheglov) revisit later. Each task duration should be kept short. | 977 * TODO(scheglov) revisit later. Each task duration should be kept short. |
| 949 */ | 978 */ |
| 950 void _resolveQueue() { | 979 void _resolveQueue() { |
| 980 logger.log('${_resolutionQueue.length} elements in the resolution queue'); | |
| 951 for (Element element in _resolutionQueue) { | 981 for (Element element in _resolutionQueue) { |
| 952 // TODO(scheglov) in general, we should not call Element.node, it | 982 // TODO(scheglov) in general, we should not call Element.node, it |
| 953 // might perform complete unit resolution. | 983 // might perform complete unit resolution. |
| 954 AstNode node = element.node; | 984 logger.enter('resolve $element'); |
| 955 CompilationUnitElement unit = | 985 try { |
| 956 element.getAncestor((e) => e is CompilationUnitElement); | 986 AstNode node = element.node; |
| 957 IncrementalResolver resolver = | 987 CompilationUnitElement unit = |
| 958 new IncrementalResolver(_typeProvider, unit, 0, 0, 0); | 988 element.getAncestor((e) => e is CompilationUnitElement); |
| 959 resolver._resolveReferences(node); | 989 IncrementalResolver resolver = |
| 990 new IncrementalResolver(unit, node.offset, node.end, node.end); | |
| 991 resolver._resolveReferences(node); | |
| 992 resolver._verify(node); | |
| 993 resolver._generateHints(node); | |
| 994 resolver._updateEntry(); | |
| 995 } finally { | |
| 996 logger.exit(); | |
| 997 } | |
| 960 } | 998 } |
| 961 } | 999 } |
| 962 | 1000 |
| 963 _resolveReferences(AstNode node) { | 1001 _resolveReferences(AstNode node) { |
| 964 LoggingTimer timer = logger.startTimer(); | 1002 LoggingTimer timer = logger.startTimer(); |
| 965 try { | 1003 try { |
| 966 _prepareResolutionContext(node); | 1004 _prepareResolutionContext(node); |
| 967 Scope scope = _resolutionContext.scope; | 1005 Scope scope = _resolutionContext.scope; |
| 968 // resolve types | 1006 // resolve types |
| 969 { | 1007 { |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1004 visitor.initForIncrementalResolution(); | 1042 visitor.initForIncrementalResolution(); |
| 1005 node.accept(visitor); | 1043 node.accept(visitor); |
| 1006 } | 1044 } |
| 1007 // remember errors | 1045 // remember errors |
| 1008 _resolveErrors = errorListener.getErrorsForSource(_source); | 1046 _resolveErrors = errorListener.getErrorsForSource(_source); |
| 1009 } finally { | 1047 } finally { |
| 1010 timer.stop('resolve references'); | 1048 timer.stop('resolve references'); |
| 1011 } | 1049 } |
| 1012 } | 1050 } |
| 1013 | 1051 |
| 1052 void _shiftEntryErrors() { | |
| 1053 Source librarySource = _definingLibrary.source; | |
| 1054 { | |
| 1055 List<AnalysisError> errors = | |
| 1056 entry.getValueInLibrary(DartEntry.RESOLUTION_ERRORS, librarySource); | |
|
Brian Wilkerson
2014/12/19 15:03:29
FWIW the error access could also be moved into _sh
scheglov
2014/12/19 17:43:04
Done.
| |
| 1057 _shiftErrors(errors); | |
| 1058 } | |
| 1059 { | |
| 1060 List<AnalysisError> errors = | |
| 1061 entry.getValueInLibrary(DartEntry.VERIFICATION_ERRORS, librarySource); | |
| 1062 _shiftErrors(errors); | |
| 1063 } | |
| 1064 { | |
| 1065 List<AnalysisError> errors = | |
| 1066 entry.getValueInLibrary(DartEntry.HINTS, librarySource); | |
| 1067 _shiftErrors(errors); | |
| 1068 } | |
| 1069 } | |
| 1070 | |
| 1071 void _shiftErrors(List<AnalysisError> errors) { | |
| 1072 for (AnalysisError error in errors) { | |
| 1073 int errorOffset = error.offset; | |
| 1074 if (errorOffset > _updateOffset) { | |
| 1075 error.offset += _updateDelta; | |
| 1076 } | |
| 1077 } | |
| 1078 } | |
| 1079 | |
| 1080 void _updateElementNameOffsets() { | |
| 1081 LoggingTimer timer = logger.startTimer(); | |
| 1082 try { | |
| 1083 _definingUnit.accept( | |
| 1084 new _ElementNameOffsetUpdater(_updateOffset, _updateDelta)); | |
| 1085 } finally { | |
| 1086 timer.stop('update element offsets'); | |
| 1087 } | |
| 1088 } | |
| 1089 | |
| 1090 void _updateEntry() { | |
| 1091 Source librarySource = _definingLibrary.source; | |
| 1092 { | |
| 1093 List<AnalysisError> oldErrors = | |
| 1094 entry.getValueInLibrary(DartEntry.RESOLUTION_ERRORS, librarySource); | |
| 1095 List<AnalysisError> errors = _updateErrors(oldErrors, _resolveErrors); | |
| 1096 entry.setValueInLibrary( | |
| 1097 DartEntry.RESOLUTION_ERRORS, | |
| 1098 librarySource, | |
| 1099 errors); | |
| 1100 } | |
| 1101 { | |
| 1102 List<AnalysisError> oldErrors = | |
| 1103 entry.getValueInLibrary(DartEntry.VERIFICATION_ERRORS, librarySource); | |
| 1104 List<AnalysisError> errors = _updateErrors(oldErrors, _verifyErrors); | |
| 1105 entry.setValueInLibrary( | |
| 1106 DartEntry.VERIFICATION_ERRORS, | |
| 1107 librarySource, | |
| 1108 errors); | |
| 1109 } | |
| 1110 entry.setValueInLibrary(DartEntry.HINTS, librarySource, _hints); | |
| 1111 } | |
| 1112 | |
| 1113 List<AnalysisError> _updateErrors(List<AnalysisError> oldErrors, | |
| 1114 List<AnalysisError> newErrors) { | |
| 1115 List<AnalysisError> errors = new List<AnalysisError>(); | |
| 1116 // add updated old errors | |
| 1117 for (AnalysisError error in oldErrors) { | |
| 1118 int errorOffset = error.offset; | |
| 1119 if (errorOffset < _updateOffset) { | |
| 1120 errors.add(error); | |
| 1121 } else if (errorOffset > _updateEndOld) { | |
| 1122 error.offset += _updateDelta; | |
| 1123 errors.add(error); | |
| 1124 } | |
| 1125 } | |
| 1126 // add new errors | |
| 1127 for (AnalysisError error in newErrors) { | |
| 1128 int errorOffset = error.offset; | |
| 1129 if (errorOffset > _updateOffset && errorOffset < _updateEndNew) { | |
| 1130 errors.add(error); | |
| 1131 } | |
| 1132 } | |
| 1133 // done | |
| 1134 return errors; | |
| 1135 } | |
| 1136 | |
| 1014 void _verify(AstNode node) { | 1137 void _verify(AstNode node) { |
| 1015 LoggingTimer timer = logger.startTimer(); | 1138 LoggingTimer timer = logger.startTimer(); |
| 1016 try { | 1139 try { |
| 1017 RecordingErrorListener errorListener = new RecordingErrorListener(); | 1140 RecordingErrorListener errorListener = new RecordingErrorListener(); |
| 1018 ErrorReporter errorReporter = new ErrorReporter(errorListener, _source); | 1141 ErrorReporter errorReporter = new ErrorReporter(errorListener, _source); |
| 1019 ErrorVerifier errorVerifier = new ErrorVerifier( | 1142 ErrorVerifier errorVerifier = new ErrorVerifier( |
| 1020 errorReporter, | 1143 errorReporter, |
| 1021 _definingLibrary, | 1144 _definingLibrary, |
| 1022 _typeProvider, | 1145 _typeProvider, |
| 1023 new InheritanceManager(_definingLibrary)); | 1146 new InheritanceManager(_definingLibrary)); |
| 1024 if (_resolutionContext.enclosingClassDeclaration != null) { | 1147 if (_resolutionContext.enclosingClassDeclaration != null) { |
| 1025 errorVerifier.visitClassDeclarationIncrementally( | 1148 errorVerifier.visitClassDeclarationIncrementally( |
| 1026 _resolutionContext.enclosingClassDeclaration); | 1149 _resolutionContext.enclosingClassDeclaration); |
| 1027 } | 1150 } |
| 1028 node.accept(errorVerifier); | 1151 node.accept(errorVerifier); |
| 1029 _verifyErrors = errorListener.getErrorsForSource(_source); | 1152 _verifyErrors = errorListener.getErrorsForSource(_source); |
| 1030 } finally { | 1153 } finally { |
| 1031 timer.stop('verify'); | 1154 timer.stop('verify'); |
| 1032 } | 1155 } |
| 1033 } | 1156 } |
| 1034 | |
| 1035 static void _updateElementNameOffsets(Element root, int offset, int delta) { | |
| 1036 LoggingTimer timer = logger.startTimer(); | |
| 1037 try { | |
| 1038 root.accept(new _ElementNameOffsetUpdater(offset, delta)); | |
| 1039 } finally { | |
| 1040 timer.stop('update element offsets'); | |
| 1041 } | |
| 1042 } | |
| 1043 } | 1157 } |
| 1044 | 1158 |
| 1045 | 1159 |
| 1046 class PoorMansIncrementalResolver { | 1160 class PoorMansIncrementalResolver { |
| 1047 final TypeProvider _typeProvider; | 1161 final TypeProvider _typeProvider; |
| 1048 final Source _unitSource; | 1162 final Source _unitSource; |
| 1049 final Source _librarySource; | |
| 1050 final DartEntry _entry; | 1163 final DartEntry _entry; |
| 1164 CompilationUnitElement _unitElement; | |
| 1051 | 1165 |
| 1052 int _updateOffset; | 1166 int _updateOffset; |
| 1053 int _updateDelta; | 1167 int _updateDelta; |
| 1054 int _updateEndOld; | 1168 int _updateEndOld; |
| 1055 int _updateEndNew; | 1169 int _updateEndNew; |
| 1056 | 1170 |
| 1057 List<AnalysisError> _newScanErrors = <AnalysisError>[]; | 1171 List<AnalysisError> _newScanErrors = <AnalysisError>[]; |
| 1058 List<AnalysisError> _newParseErrors = <AnalysisError>[]; | 1172 List<AnalysisError> _newParseErrors = <AnalysisError>[]; |
| 1059 List<AnalysisError> _newResolveErrors = <AnalysisError>[]; | |
| 1060 List<AnalysisError> _newVerifyErrors = <AnalysisError>[]; | |
| 1061 List<AnalysisError> _newHints = <AnalysisError>[]; | |
| 1062 | 1173 |
| 1063 PoorMansIncrementalResolver(this._typeProvider, this._unitSource, | 1174 PoorMansIncrementalResolver(this._typeProvider, this._unitSource, this._entry, |
| 1064 this._librarySource, this._entry, bool resolveApiChanges) { | 1175 bool resolveApiChanges) { |
| 1065 _resolveApiChanges = resolveApiChanges; | 1176 _resolveApiChanges = resolveApiChanges; |
| 1066 } | 1177 } |
| 1067 | 1178 |
| 1068 /** | 1179 /** |
| 1069 * Attempts to update [oldUnit] to the state corresponding to [newCode]. | 1180 * Attempts to update [oldUnit] to the state corresponding to [newCode]. |
| 1070 * Returns `true` if success, or `false` otherwise. | 1181 * Returns `true` if success, or `false` otherwise. |
| 1071 * The [oldUnit] might be damaged. | 1182 * The [oldUnit] might be damaged. |
| 1072 */ | 1183 */ |
| 1073 bool resolve(CompilationUnit oldUnit, String newCode) { | 1184 bool resolve(CompilationUnit oldUnit, String newCode) { |
| 1074 logger.enter('diff/resolve $_unitSource'); | 1185 logger.enter('diff/resolve $_unitSource'); |
| 1075 logger.log(oldUnit != null ? 'has oldUnit' : 'oldUnit is null'); | 1186 logger.log(oldUnit != null ? 'has oldUnit' : 'oldUnit is null'); |
| 1076 try { | 1187 try { |
| 1188 _unitElement = oldUnit.element; | |
| 1077 CompilationUnit newUnit = _parseUnit(newCode); | 1189 CompilationUnit newUnit = _parseUnit(newCode); |
| 1078 _TokenPair firstPair = | 1190 _TokenPair firstPair = |
| 1079 _findFirstDifferentToken(oldUnit.beginToken, newUnit.beginToken); | 1191 _findFirstDifferentToken(oldUnit.beginToken, newUnit.beginToken); |
| 1080 _TokenPair lastPair = | 1192 _TokenPair lastPair = |
| 1081 _findLastDifferentToken(oldUnit.endToken, newUnit.endToken); | 1193 _findLastDifferentToken(oldUnit.endToken, newUnit.endToken); |
| 1082 if (firstPair != null && lastPair != null) { | 1194 if (firstPair != null && lastPair != null) { |
| 1083 int firstOffsetOld = firstPair.oldToken.offset; | 1195 int firstOffsetOld = firstPair.oldToken.offset; |
| 1084 int firstOffsetNew = firstPair.newToken.offset; | 1196 int firstOffsetNew = firstPair.newToken.offset; |
| 1085 int lastOffsetOld = lastPair.oldToken.end; | 1197 int lastOffsetOld = lastPair.oldToken.end; |
| 1086 int lastOffsetNew = lastPair.newToken.end; | 1198 int lastOffsetNew = lastPair.newToken.end; |
| 1087 int beginOffsetOld = math.min(firstOffsetOld, lastOffsetOld); | 1199 int beginOffsetOld = math.min(firstOffsetOld, lastOffsetOld); |
| 1088 int endOffsetOld = math.max(firstOffsetOld, lastOffsetOld); | 1200 int endOffsetOld = math.max(firstOffsetOld, lastOffsetOld); |
| 1089 int beginOffsetNew = math.min(firstOffsetNew, lastOffsetNew); | 1201 int beginOffsetNew = math.min(firstOffsetNew, lastOffsetNew); |
| 1090 int endOffsetNew = math.max(firstOffsetNew, lastOffsetNew); | 1202 int endOffsetNew = math.max(firstOffsetNew, lastOffsetNew); |
| 1091 // check for a whitespace only change | 1203 // check for a whitespace only change |
| 1092 if (identical(lastPair.oldToken, firstPair.oldToken) && | 1204 if (identical(lastPair.oldToken, firstPair.oldToken) && |
| 1093 identical(lastPair.newToken, firstPair.newToken)) { | 1205 identical(lastPair.newToken, firstPair.newToken)) { |
| 1094 _updateOffset = beginOffsetOld - 1; | 1206 _updateOffset = beginOffsetOld - 1; |
| 1095 _updateEndOld = endOffsetOld; | 1207 _updateEndOld = endOffsetOld; |
| 1208 _updateEndNew = endOffsetNew; | |
| 1096 _updateDelta = newUnit.length - oldUnit.length; | 1209 _updateDelta = newUnit.length - oldUnit.length; |
| 1097 // A Dart documentation comment change. | 1210 // A Dart documentation comment change. |
| 1098 if (firstPair.kind == _TokenDifferenceKind.COMMENT_DOC) { | 1211 if (firstPair.kind == _TokenDifferenceKind.COMMENT_DOC) { |
| 1099 _resolveComment(oldUnit, newUnit, firstPair); | 1212 _resolveComment(oldUnit, newUnit, firstPair); |
| 1100 logger.log('Success.'); | 1213 logger.log('Success.'); |
| 1101 return true; | 1214 return true; |
| 1102 } | 1215 } |
| 1103 // A pure whitespace change. | 1216 // A pure whitespace change. |
| 1104 if (firstPair.kind == _TokenDifferenceKind.OFFSET) { | 1217 if (firstPair.kind == _TokenDifferenceKind.OFFSET) { |
| 1105 logger.log('Whitespace change.'); | 1218 logger.log('Whitespace change.'); |
| 1106 _shiftTokens(firstPair.oldToken); | 1219 _shiftTokens(firstPair.oldToken); |
| 1107 IncrementalResolver._updateElementNameOffsets( | 1220 { |
| 1108 oldUnit.element, | 1221 IncrementalResolver incrementalResolver = new IncrementalResolver( |
| 1109 _updateOffset, | 1222 _unitElement, |
| 1110 _updateDelta); | 1223 _updateOffset, |
| 1224 _updateEndOld, | |
| 1225 _updateEndNew); | |
| 1226 incrementalResolver._updateElementNameOffsets(); | |
| 1227 incrementalResolver._shiftEntryErrors(); | |
| 1228 } | |
| 1111 _updateEntry(); | 1229 _updateEntry(); |
| 1112 logger.log('Success.'); | 1230 logger.log('Success.'); |
| 1113 return true; | 1231 return true; |
| 1114 } | 1232 } |
| 1115 // fall-through, end-of-line comment | 1233 // fall-through, end-of-line comment |
| 1116 } | 1234 } |
| 1117 // Find nodes covering the "old" and "new" token ranges. | 1235 // Find nodes covering the "old" and "new" token ranges. |
| 1118 AstNode oldNode = | 1236 AstNode oldNode = |
| 1119 _findNodeCovering(oldUnit, beginOffsetOld, endOffsetOld); | 1237 _findNodeCovering(oldUnit, beginOffsetOld, endOffsetOld); |
| 1120 AstNode newNode = | 1238 AstNode newNode = |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1165 Token newBeginToken = _getBeginTokenNotComment(newNode); | 1283 Token newBeginToken = _getBeginTokenNotComment(newNode); |
| 1166 if (oldBeginToken.previous.type == TokenType.EOF) { | 1284 if (oldBeginToken.previous.type == TokenType.EOF) { |
| 1167 oldUnit.beginToken = newBeginToken; | 1285 oldUnit.beginToken = newBeginToken; |
| 1168 } else { | 1286 } else { |
| 1169 oldBeginToken.previous.setNext(newBeginToken); | 1287 oldBeginToken.previous.setNext(newBeginToken); |
| 1170 } | 1288 } |
| 1171 newNode.endToken.setNext(oldNode.endToken.next); | 1289 newNode.endToken.setNext(oldNode.endToken.next); |
| 1172 _shiftTokens(oldNode.endToken.next); | 1290 _shiftTokens(oldNode.endToken.next); |
| 1173 } | 1291 } |
| 1174 // perform incremental resolution | 1292 // perform incremental resolution |
| 1175 CompilationUnitElement oldUnitElement = oldUnit.element; | |
| 1176 IncrementalResolver incrementalResolver = new IncrementalResolver( | 1293 IncrementalResolver incrementalResolver = new IncrementalResolver( |
| 1177 _typeProvider, | 1294 _unitElement, |
| 1178 oldUnitElement, | |
| 1179 _updateOffset, | 1295 _updateOffset, |
| 1180 oldNode.length, | 1296 oldNode.length, |
| 1181 newNode.length); | 1297 newNode.length); |
| 1182 bool success = incrementalResolver.resolve(newNode); | 1298 bool success = incrementalResolver.resolve(newNode); |
| 1183 // check if success | 1299 // check if success |
| 1184 if (!success) { | 1300 if (!success) { |
| 1185 logger.log('Failure: element model changed.'); | 1301 logger.log('Failure: element model changed.'); |
| 1186 return false; | 1302 return false; |
| 1187 } | 1303 } |
| 1188 // update DartEntry | 1304 // update DartEntry |
| 1189 _newResolveErrors = incrementalResolver._resolveErrors; | |
| 1190 _newVerifyErrors = incrementalResolver._verifyErrors; | |
| 1191 _newHints = incrementalResolver._hints; | |
| 1192 _updateEntry(); | 1305 _updateEntry(); |
| 1193 logger.log('Success.'); | 1306 logger.log('Success.'); |
| 1194 return true; | 1307 return true; |
| 1195 } | 1308 } |
| 1196 } catch (e, st) { | 1309 } catch (e, st) { |
| 1197 logger.log(e); | 1310 logger.log(e); |
| 1198 logger.log(st); | 1311 logger.log(st); |
| 1199 logger.log('Failure: exception.'); | 1312 logger.log('Failure: exception.'); |
| 1200 } finally { | 1313 } finally { |
| 1201 logger.exit(); | 1314 logger.exit(); |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 1227 Comment newComment = _findNodeCovering(newUnit, offset, offset); | 1340 Comment newComment = _findNodeCovering(newUnit, offset, offset); |
| 1228 logger.log('oldComment.beginToken: ${oldComment.beginToken}'); | 1341 logger.log('oldComment.beginToken: ${oldComment.beginToken}'); |
| 1229 logger.log('newComment.beginToken: ${newComment.beginToken}'); | 1342 logger.log('newComment.beginToken: ${newComment.beginToken}'); |
| 1230 _updateOffset = oldToken.offset - 1; | 1343 _updateOffset = oldToken.offset - 1; |
| 1231 // update token references | 1344 // update token references |
| 1232 _shiftTokens(firstPair.oldToken); | 1345 _shiftTokens(firstPair.oldToken); |
| 1233 _setPrecedingComments(oldToken, newComment.tokens.first); | 1346 _setPrecedingComments(oldToken, newComment.tokens.first); |
| 1234 // replace node | 1347 // replace node |
| 1235 NodeReplacer.replace(oldComment, newComment); | 1348 NodeReplacer.replace(oldComment, newComment); |
| 1236 // update elements | 1349 // update elements |
| 1237 IncrementalResolver._updateElementNameOffsets( | 1350 IncrementalResolver incrementalResolver = new IncrementalResolver( |
| 1238 oldUnit.element, | 1351 _unitElement, |
| 1239 _updateOffset, | 1352 _updateOffset, |
| 1240 _updateDelta); | 1353 _updateEndOld, |
| 1354 _updateEndNew); | |
| 1355 incrementalResolver._updateElementNameOffsets(); | |
| 1241 _updateEntry(); | 1356 _updateEntry(); |
| 1242 // resolve references in the comment | 1357 // resolve references in the comment |
| 1243 CompilationUnitElement oldUnitElement = oldUnit.element; | |
| 1244 IncrementalResolver incrementalResolver = | |
| 1245 new IncrementalResolver(_typeProvider, oldUnitElement, _updateOffset, 0, 0); | |
| 1246 incrementalResolver._resolveReferences(newComment); | 1358 incrementalResolver._resolveReferences(newComment); |
| 1247 } | 1359 } |
| 1248 | 1360 |
| 1249 Token _scan(String code) { | 1361 Token _scan(String code) { |
| 1250 RecordingErrorListener errorListener = new RecordingErrorListener(); | 1362 RecordingErrorListener errorListener = new RecordingErrorListener(); |
| 1251 CharSequenceReader reader = new CharSequenceReader(code); | 1363 CharSequenceReader reader = new CharSequenceReader(code); |
| 1252 Scanner scanner = new Scanner(_unitSource, reader, errorListener); | 1364 Scanner scanner = new Scanner(_unitSource, reader, errorListener); |
| 1253 Token token = scanner.tokenize(); | 1365 Token token = scanner.tokenize(); |
| 1254 _newScanErrors = errorListener.errors; | 1366 _newScanErrors = errorListener.errors; |
| 1255 return token; | 1367 return token; |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 1271 if (token.type == TokenType.EOF) { | 1383 if (token.type == TokenType.EOF) { |
| 1272 break; | 1384 break; |
| 1273 } | 1385 } |
| 1274 token = token.next; | 1386 token = token.next; |
| 1275 } | 1387 } |
| 1276 } | 1388 } |
| 1277 | 1389 |
| 1278 void _updateEntry() { | 1390 void _updateEntry() { |
| 1279 _entry.setValue(DartEntry.SCAN_ERRORS, _newScanErrors); | 1391 _entry.setValue(DartEntry.SCAN_ERRORS, _newScanErrors); |
| 1280 _entry.setValue(DartEntry.PARSE_ERRORS, _newParseErrors); | 1392 _entry.setValue(DartEntry.PARSE_ERRORS, _newParseErrors); |
| 1281 { | |
| 1282 List<AnalysisError> oldErrors = | |
| 1283 _entry.getValueInLibrary(DartEntry.RESOLUTION_ERRORS, _librarySource); | |
| 1284 List<AnalysisError> errors = _updateErrors(oldErrors, _newResolveErrors); | |
| 1285 _entry.setValueInLibrary( | |
| 1286 DartEntry.RESOLUTION_ERRORS, | |
| 1287 _librarySource, | |
| 1288 errors); | |
| 1289 } | |
| 1290 { | |
| 1291 List<AnalysisError> oldErrors = | |
| 1292 _entry.getValueInLibrary(DartEntry.VERIFICATION_ERRORS, _librarySource ); | |
| 1293 List<AnalysisError> errors = _updateErrors(oldErrors, _newVerifyErrors); | |
| 1294 _entry.setValueInLibrary( | |
| 1295 DartEntry.VERIFICATION_ERRORS, | |
| 1296 _librarySource, | |
| 1297 errors); | |
| 1298 } | |
| 1299 _entry.setValueInLibrary(DartEntry.HINTS, _librarySource, _newHints); | |
| 1300 } | |
| 1301 | |
| 1302 List<AnalysisError> _updateErrors(List<AnalysisError> oldErrors, | |
| 1303 List<AnalysisError> newErrors) { | |
| 1304 List<AnalysisError> errors = new List<AnalysisError>(); | |
| 1305 // add updated old errors | |
| 1306 for (AnalysisError error in oldErrors) { | |
| 1307 int errorOffset = error.offset; | |
| 1308 if (errorOffset < _updateOffset) { | |
| 1309 errors.add(error); | |
| 1310 } else if (errorOffset > _updateEndOld) { | |
| 1311 error.offset += _updateDelta; | |
| 1312 errors.add(error); | |
| 1313 } | |
| 1314 } | |
| 1315 // add new errors | |
| 1316 for (AnalysisError error in newErrors) { | |
| 1317 int errorOffset = error.offset; | |
| 1318 if (errorOffset > _updateOffset && errorOffset < _updateEndNew) { | |
| 1319 errors.add(error); | |
| 1320 } | |
| 1321 } | |
| 1322 // done | |
| 1323 return errors; | |
| 1324 } | 1393 } |
| 1325 | 1394 |
| 1326 static _TokenDifferenceKind _compareToken(Token oldToken, Token newToken, | 1395 static _TokenDifferenceKind _compareToken(Token oldToken, Token newToken, |
| 1327 int delta) { | 1396 int delta) { |
| 1328 if (oldToken == null && newToken == null) { | 1397 if (oldToken == null && newToken == null) { |
| 1329 return null; | 1398 return null; |
| 1330 } | 1399 } |
| 1331 if (oldToken == null || newToken == null) { | 1400 if (oldToken == null || newToken == null) { |
| 1332 return _TokenDifferenceKind.CONTENT; | 1401 return _TokenDifferenceKind.CONTENT; |
| 1333 } | 1402 } |
| (...skipping 385 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1719 String toString() => name; | 1788 String toString() => name; |
| 1720 } | 1789 } |
| 1721 | 1790 |
| 1722 | 1791 |
| 1723 class _TokenPair { | 1792 class _TokenPair { |
| 1724 final _TokenDifferenceKind kind; | 1793 final _TokenDifferenceKind kind; |
| 1725 final Token oldToken; | 1794 final Token oldToken; |
| 1726 final Token newToken; | 1795 final Token newToken; |
| 1727 _TokenPair(this.kind, this.oldToken, this.newToken); | 1796 _TokenPair(this.kind, this.oldToken, this.newToken); |
| 1728 } | 1797 } |
| OLD | NEW |