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

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

Issue 814533005: Incrementally resolve users of a changed method. (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 97 matching lines...) Expand 10 before | Expand all | Expand 10 after
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
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
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
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
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
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
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
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
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
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
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
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698