| 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 'package:analyzer/src/generated/error_verifier.dart'; | |
| 11 import 'package:analyzer/src/generated/utilities_dart.dart'; | |
| 12 | |
| 13 import 'ast.dart'; | 10 import 'ast.dart'; |
| 14 import 'element.dart'; | 11 import 'element.dart'; |
| 15 import 'engine.dart'; | 12 import 'engine.dart'; |
| 16 import 'error.dart'; | 13 import 'error.dart'; |
| 14 import 'error_verifier.dart'; |
| 15 import 'incremental_logger.dart' show logger; |
| 17 import 'java_engine.dart'; | 16 import 'java_engine.dart'; |
| 18 import 'parser.dart'; | 17 import 'parser.dart'; |
| 19 import 'resolver.dart'; | 18 import 'resolver.dart'; |
| 20 import 'scanner.dart'; | 19 import 'scanner.dart'; |
| 21 import 'source.dart'; | 20 import 'source.dart'; |
| 21 import 'utilities_dart.dart'; |
| 22 | 22 |
| 23 | 23 |
| 24 /** | 24 /** |
| 25 * Instances of the class [DeclarationMatcher] determine whether the element | 25 * Instances of the class [DeclarationMatcher] determine whether the element |
| 26 * model defined by a given AST structure matches an existing element model. | 26 * model defined by a given AST structure matches an existing element model. |
| 27 */ | 27 */ |
| 28 class DeclarationMatcher extends RecursiveAstVisitor { | 28 class DeclarationMatcher extends RecursiveAstVisitor { |
| 29 /** | 29 /** |
| 30 * The libary containing the AST nodes being visited. | 30 * The libary containing the AST nodes being visited. |
| 31 */ | 31 */ |
| (...skipping 881 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 913 | 913 |
| 914 PoorMansIncrementalResolver(this._typeProvider, this._unitSource, | 914 PoorMansIncrementalResolver(this._typeProvider, this._unitSource, |
| 915 this._librarySource, this._entry); | 915 this._librarySource, this._entry); |
| 916 | 916 |
| 917 /** | 917 /** |
| 918 * Attempts to update [oldUnit] to the state corresponding to [newCode]. | 918 * Attempts to update [oldUnit] to the state corresponding to [newCode]. |
| 919 * Returns `true` if success, or `false` otherwise. | 919 * Returns `true` if success, or `false` otherwise. |
| 920 * The [oldUnit] might be damaged. | 920 * The [oldUnit] might be damaged. |
| 921 */ | 921 */ |
| 922 bool resolve(CompilationUnit oldUnit, String newCode) { | 922 bool resolve(CompilationUnit oldUnit, String newCode) { |
| 923 logger.enter('resolve $_unitSource'); |
| 924 logger.log(oldUnit != null ? 'has oldUnit' : 'oldUnit is null'); |
| 923 try { | 925 try { |
| 924 CompilationUnit newUnit = _parseUnit(newCode); | 926 CompilationUnit newUnit = _parseUnit(newCode); |
| 925 _TokenPair firstPair = | 927 _TokenPair firstPair = |
| 926 _findFirstDifferentToken(oldUnit.beginToken, newUnit.beginToken); | 928 _findFirstDifferentToken(oldUnit.beginToken, newUnit.beginToken); |
| 927 _TokenPair lastPair = | 929 _TokenPair lastPair = |
| 928 _findLastDifferentToken(oldUnit.endToken, newUnit.endToken); | 930 _findLastDifferentToken(oldUnit.endToken, newUnit.endToken); |
| 929 if (firstPair != null && lastPair != null) { | 931 if (firstPair != null && lastPair != null) { |
| 930 int firstOffsetOld = firstPair.oldToken.offset; | 932 int firstOffsetOld = firstPair.oldToken.offset; |
| 931 int firstOffsetNew = firstPair.newToken.offset; | 933 int firstOffsetNew = firstPair.newToken.offset; |
| 932 int lastOffsetOld = lastPair.oldToken.end; | 934 int lastOffsetOld = lastPair.oldToken.end; |
| 933 int lastOffsetNew = lastPair.newToken.end; | 935 int lastOffsetNew = lastPair.newToken.end; |
| 934 int beginOffsetOld = math.min(firstOffsetOld, lastOffsetOld); | 936 int beginOffsetOld = math.min(firstOffsetOld, lastOffsetOld); |
| 935 int endOffsetOld = math.max(firstOffsetOld, lastOffsetOld); | 937 int endOffsetOld = math.max(firstOffsetOld, lastOffsetOld); |
| 936 int beginOffsetNew = math.min(firstOffsetNew, lastOffsetNew); | 938 int beginOffsetNew = math.min(firstOffsetNew, lastOffsetNew); |
| 937 int endOffsetNew = math.max(firstOffsetNew, lastOffsetNew); | 939 int endOffsetNew = math.max(firstOffsetNew, lastOffsetNew); |
| 938 // check for a whitespace only change | 940 // check for a whitespace only change |
| 939 if (identical(lastPair.oldToken, firstPair.oldToken) && | 941 if (identical(lastPair.oldToken, firstPair.oldToken) && |
| 940 identical(lastPair.newToken, firstPair.newToken)) { | 942 identical(lastPair.newToken, firstPair.newToken)) { |
| 941 _updateOffset = beginOffsetOld - 1; | 943 _updateOffset = beginOffsetOld - 1; |
| 942 _updateEndOld = endOffsetOld; | 944 _updateEndOld = endOffsetOld; |
| 943 _updateDelta = newUnit.length - oldUnit.length; | 945 _updateDelta = newUnit.length - oldUnit.length; |
| 944 if (firstPair.atComment && lastPair.atComment) { | 946 if (firstPair.atComment && lastPair.atComment) { |
| 947 logger.log('Comment change.'); |
| 945 _resolveComment(oldUnit, newUnit, firstPair); | 948 _resolveComment(oldUnit, newUnit, firstPair); |
| 946 } else { | 949 } else { |
| 950 logger.log('Whitespace change.'); |
| 947 _shiftTokens(firstPair.oldToken); | 951 _shiftTokens(firstPair.oldToken); |
| 948 IncrementalResolver._updateElementNameOffsets( | 952 IncrementalResolver._updateElementNameOffsets( |
| 949 oldUnit.element, | 953 oldUnit.element, |
| 950 _updateOffset, | 954 _updateOffset, |
| 951 _updateDelta); | 955 _updateDelta); |
| 952 _updateEntry(); | 956 _updateEntry(); |
| 953 } | 957 } |
| 958 logger.log('Success.'); |
| 954 return true; | 959 return true; |
| 955 } | 960 } |
| 956 // Find nodes covering the "old" and "new" token ranges. | 961 // Find nodes covering the "old" and "new" token ranges. |
| 957 AstNode oldNode = | 962 AstNode oldNode = |
| 958 _findNodeCovering(oldUnit, beginOffsetOld, endOffsetOld); | 963 _findNodeCovering(oldUnit, beginOffsetOld, endOffsetOld); |
| 959 AstNode newNode = | 964 AstNode newNode = |
| 960 _findNodeCovering(newUnit, beginOffsetNew, endOffsetNew); | 965 _findNodeCovering(newUnit, beginOffsetNew, endOffsetNew); |
| 961 // print('oldNode: $oldNode'); | 966 logger.log('oldNode: $oldNode'); |
| 962 // print('newNode: $newNode'); | 967 logger.log('newNode: $newNode'); |
| 963 // Try to find the smallest common node, a FunctionBody currently. | 968 // Try to find the smallest common node, a FunctionBody currently. |
| 964 { | 969 { |
| 965 List<AstNode> oldParents = _getParents(oldNode); | 970 List<AstNode> oldParents = _getParents(oldNode); |
| 966 List<AstNode> newParents = _getParents(newNode); | 971 List<AstNode> newParents = _getParents(newNode); |
| 967 int length = math.min(oldParents.length, newParents.length); | 972 int length = math.min(oldParents.length, newParents.length); |
| 968 bool found = false; | 973 bool found = false; |
| 969 for (int i = 0; i < length; i++) { | 974 for (int i = 0; i < length; i++) { |
| 970 AstNode oldParent = oldParents[i]; | 975 AstNode oldParent = oldParents[i]; |
| 971 AstNode newParent = newParents[i]; | 976 AstNode newParent = newParents[i]; |
| 972 if (oldParent is FunctionDeclaration && | 977 if (oldParent is FunctionDeclaration && |
| 973 newParent is FunctionDeclaration || | 978 newParent is FunctionDeclaration || |
| 974 oldParent is MethodDeclaration && newParent is MethodDeclaration
|| | 979 oldParent is MethodDeclaration && newParent is MethodDeclaration
|| |
| 975 oldParent is ConstructorDeclaration && newParent is ConstructorD
eclaration) { | 980 oldParent is ConstructorDeclaration && newParent is ConstructorD
eclaration) { |
| 976 oldNode = oldParent; | 981 oldNode = oldParent; |
| 977 newNode = newParent; | 982 newNode = newParent; |
| 978 found = true; | 983 found = true; |
| 979 } | 984 } |
| 980 if (oldParent is FunctionBody && newParent is FunctionBody) { | 985 if (oldParent is FunctionBody && newParent is FunctionBody) { |
| 981 oldNode = oldParent; | 986 oldNode = oldParent; |
| 982 newNode = newParent; | 987 newNode = newParent; |
| 983 found = true; | 988 found = true; |
| 984 break; | 989 break; |
| 985 } | 990 } |
| 986 } | 991 } |
| 987 if (!found) { | 992 if (!found) { |
| 993 logger.log('Failure: no enclosing function body or executable.'); |
| 988 return false; | 994 return false; |
| 989 } | 995 } |
| 990 } | 996 } |
| 991 // print('oldNode: $oldNode'); | 997 logger.log('oldNode: $oldNode'); |
| 992 // print('newNode: $newNode'); | 998 logger.log('newNode: $newNode'); |
| 993 // prepare update range | 999 // prepare update range |
| 994 _updateOffset = oldNode.offset; | 1000 _updateOffset = oldNode.offset; |
| 995 _updateEndOld = oldNode.end; | 1001 _updateEndOld = oldNode.end; |
| 996 _updateEndNew = newNode.end; | 1002 _updateEndNew = newNode.end; |
| 997 _updateDelta = _updateEndNew - _updateEndOld; | 1003 _updateDelta = _updateEndNew - _updateEndOld; |
| 998 // replace node | 1004 // replace node |
| 999 NodeReplacer.replace(oldNode, newNode); | 1005 NodeReplacer.replace(oldNode, newNode); |
| 1000 // update token references | 1006 // update token references |
| 1001 { | 1007 { |
| 1002 Token oldBeginToken = _getBeginTokenNotComment(oldNode); | 1008 Token oldBeginToken = _getBeginTokenNotComment(oldNode); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 1015 _typeProvider, | 1021 _typeProvider, |
| 1016 oldUnitElement, | 1022 oldUnitElement, |
| 1017 _updateOffset, | 1023 _updateOffset, |
| 1018 oldNode.length, | 1024 oldNode.length, |
| 1019 newNode.length); | 1025 newNode.length); |
| 1020 incrementalResolver.resolve(newNode); | 1026 incrementalResolver.resolve(newNode); |
| 1021 _newResolveErrors = incrementalResolver._resolveErrors; | 1027 _newResolveErrors = incrementalResolver._resolveErrors; |
| 1022 _newVerifyErrors = incrementalResolver._verifyErrors; | 1028 _newVerifyErrors = incrementalResolver._verifyErrors; |
| 1023 _newHints = incrementalResolver._hints; | 1029 _newHints = incrementalResolver._hints; |
| 1024 _updateEntry(); | 1030 _updateEntry(); |
| 1025 // print('Successfully incrementally resolved.'); | 1031 logger.log('Success.'); |
| 1026 return true; | 1032 return true; |
| 1027 } | 1033 } |
| 1028 } catch (e) { | 1034 } catch (e, st) { |
| 1029 // TODO(scheglov) find a way to log these exceptions | 1035 logger.log(e); |
| 1030 // print(e); | 1036 logger.log(st); |
| 1031 // print(st); | 1037 logger.log('Failure: exception.'); |
| 1038 } finally { |
| 1039 logger.exit(); |
| 1032 } | 1040 } |
| 1033 return false; | 1041 return false; |
| 1034 } | 1042 } |
| 1035 | 1043 |
| 1036 CompilationUnit _parseUnit(String code) { | 1044 CompilationUnit _parseUnit(String code) { |
| 1037 Token token = _scan(code); | 1045 Token token = _scan(code); |
| 1038 RecordingErrorListener errorListener = new RecordingErrorListener(); | 1046 RecordingErrorListener errorListener = new RecordingErrorListener(); |
| 1039 Parser parser = new Parser(_unitSource, errorListener); | 1047 Parser parser = new Parser(_unitSource, errorListener); |
| 1040 CompilationUnit unit = parser.parseCompilationUnit(token); | 1048 CompilationUnit unit = parser.parseCompilationUnit(token); |
| 1041 _newParseErrors = errorListener.errors; | 1049 _newParseErrors = errorListener.errors; |
| 1042 return unit; | 1050 return unit; |
| 1043 } | 1051 } |
| 1044 | 1052 |
| 1045 void _resolveComment(CompilationUnit oldUnit, CompilationUnit newUnit, | 1053 void _resolveComment(CompilationUnit oldUnit, CompilationUnit newUnit, |
| 1046 _TokenPair firstPair) { | 1054 _TokenPair firstPair) { |
| 1047 Token oldToken = firstPair.oldToken; | 1055 Token oldToken = firstPair.oldToken; |
| 1048 int offset = oldToken.precedingComments.offset; | 1056 CommentToken precedingComments = oldToken.precedingComments; |
| 1057 int offset = precedingComments.offset; |
| 1058 logger.log('offset: $offset'); |
| 1049 Comment oldComment = _findNodeCovering(oldUnit, offset, offset); | 1059 Comment oldComment = _findNodeCovering(oldUnit, offset, offset); |
| 1050 Comment newComment = _findNodeCovering(newUnit, offset, offset); | 1060 Comment newComment = _findNodeCovering(newUnit, offset, offset); |
| 1061 logger.log('oldComment.beginToken: ${oldComment.beginToken}'); |
| 1062 logger.log('newComment.beginToken: ${newComment.beginToken}'); |
| 1051 _updateOffset = oldToken.offset - 1; | 1063 _updateOffset = oldToken.offset - 1; |
| 1052 // update token references | 1064 // update token references |
| 1053 _shiftTokens(firstPair.oldToken); | 1065 _shiftTokens(firstPair.oldToken); |
| 1054 _setPrecedingComments(oldToken, newComment.tokens.first); | 1066 _setPrecedingComments(oldToken, newComment.tokens.first); |
| 1055 // replace node | 1067 // replace node |
| 1056 NodeReplacer.replace(oldComment, newComment); | 1068 NodeReplacer.replace(oldComment, newComment); |
| 1057 // update elements | 1069 // update elements |
| 1058 IncrementalResolver._updateElementNameOffsets( | 1070 IncrementalResolver._updateElementNameOffsets( |
| 1059 oldUnit.element, | 1071 oldUnit.element, |
| 1060 _updateOffset, | 1072 _updateOffset, |
| (...skipping 485 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1546 } | 1558 } |
| 1547 } | 1559 } |
| 1548 | 1560 |
| 1549 | 1561 |
| 1550 class _TokenPair { | 1562 class _TokenPair { |
| 1551 final Token oldToken; | 1563 final Token oldToken; |
| 1552 final Token newToken; | 1564 final Token newToken; |
| 1553 final bool atComment; | 1565 final bool atComment; |
| 1554 _TokenPair(this.oldToken, this.newToken, [this.atComment = false]); | 1566 _TokenPair(this.oldToken, this.newToken, [this.atComment = false]); |
| 1555 } | 1567 } |
| OLD | NEW |