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

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

Issue 758383003: Incremental resolution of updated DartDoc comments. (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 'package:analyzer/src/generated/error_verifier.dart'; 10 import 'package:analyzer/src/generated/error_verifier.dart';
(...skipping 601 matching lines...) Expand 10 before | Expand all | Expand 10 after
612 * Instances of the class [IncrementalResolver] resolve the smallest portion of 612 * Instances of the class [IncrementalResolver] resolve the smallest portion of
613 * an AST structure that we currently know how to resolve. 613 * an AST structure that we currently know how to resolve.
614 */ 614 */
615 class IncrementalResolver { 615 class IncrementalResolver {
616 /** 616 /**
617 * The object used to access the types from the core library. 617 * The object used to access the types from the core library.
618 */ 618 */
619 final TypeProvider _typeProvider; 619 final TypeProvider _typeProvider;
620 620
621 /** 621 /**
622 * The element for the library containing the compilation unit being resolved.
623 */
624 final LibraryElement _definingLibrary;
625
626 /**
627 * The element of the compilation unit being resolved. 622 * The element of the compilation unit being resolved.
628 */ 623 */
629 final CompilationUnitElement _definingUnit; 624 final CompilationUnitElement _definingUnit;
630 625
631 /** 626 /**
627 * The element for the library containing the compilation unit being resolved.
628 */
629 LibraryElement _definingLibrary;
630
631 /**
632 * The source representing the compilation unit being visited. 632 * The source representing the compilation unit being visited.
633 */ 633 */
634 final Source _source; 634 Source _source;
635 635
636 /** 636 /**
637 * The offset of the changed contents. 637 * The offset of the changed contents.
638 */ 638 */
639 final int _updateOffset; 639 final int _updateOffset;
640 640
641 /** 641 /**
642 * The number of characters in the original contents that were replaced. 642 * The number of characters in the original contents that were replaced.
643 */ 643 */
644 final int _updateOldLength; 644 final int _updateOldLength;
645 645
646 /** 646 /**
647 * The number of characters in the replacement text. 647 * The number of characters in the replacement text.
648 */ 648 */
649 final int _updateNewLength; 649 final int _updateNewLength;
650 650
651 ResolutionContext _resolutionContext; 651 ResolutionContext _resolutionContext;
652 652
653 List<AnalysisError> _resolveErrors = AnalysisError.NO_ERRORS; 653 List<AnalysisError> _resolveErrors = AnalysisError.NO_ERRORS;
654 List<AnalysisError> _verifyErrors = AnalysisError.NO_ERRORS; 654 List<AnalysisError> _verifyErrors = AnalysisError.NO_ERRORS;
655 List<AnalysisError> _hints = AnalysisError.NO_ERRORS; 655 List<AnalysisError> _hints = AnalysisError.NO_ERRORS;
656 656
657 /** 657 /**
658 * Initialize a newly created incremental resolver to resolve a node in the 658 * Initialize a newly created incremental resolver to resolve a node in the
659 * given source in the given library. 659 * given source in the given library.
660 */ 660 */
661 IncrementalResolver(this._typeProvider, this._definingLibrary, 661 IncrementalResolver(this._typeProvider, this._definingUnit,
662 this._definingUnit, this._source, this._updateOffset, this._updateOldLengt h, 662 this._updateOffset, this._updateOldLength, this._updateNewLength) {
663 this._updateNewLength); 663 _definingLibrary = _definingUnit.library;
664 _source = _definingUnit.source;
665 }
664 666
665 /** 667 /**
666 * Resolve [node], reporting any errors or warnings to the given listener. 668 * Resolve [node], reporting any errors or warnings to the given listener.
667 * 669 *
668 * [node] - the root of the AST structure to be resolved. 670 * [node] - the root of the AST structure to be resolved.
669 */ 671 */
670 void resolve(AstNode node) { 672 void resolve(AstNode node) {
671 AstNode rootNode = _findResolutionRoot(node); 673 AstNode rootNode = _findResolutionRoot(node);
672 // update elements 674 // update elements
673 _updateElementNameOffsets( 675 _updateElementNameOffsets(
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after
802 ResolverVisitor visitor = new ResolverVisitor.con3( 804 ResolverVisitor visitor = new ResolverVisitor.con3(
803 _definingLibrary, 805 _definingLibrary,
804 _source, 806 _source,
805 _typeProvider, 807 _typeProvider,
806 _resolutionContext.scope, 808 _resolutionContext.scope,
807 errorListener); 809 errorListener);
808 if (_resolutionContext.enclosingClassDeclaration != null) { 810 if (_resolutionContext.enclosingClassDeclaration != null) {
809 visitor.visitClassDeclarationIncrementally( 811 visitor.visitClassDeclarationIncrementally(
810 _resolutionContext.enclosingClassDeclaration); 812 _resolutionContext.enclosingClassDeclaration);
811 } 813 }
814 if (node is Comment) {
815 visitor.resolveOnlyCommentInFunctionBody = true;
816 node = node.parent;
817 }
818 visitor.initForIncrementalResolution();
812 node.accept(visitor); 819 node.accept(visitor);
813 } 820 }
814 // remember errors 821 // remember errors
815 _resolveErrors = errorListener.getErrorsForSource(_source); 822 _resolveErrors = errorListener.getErrorsForSource(_source);
816 } 823 }
817 824
818 void _updateElements(AstNode node) { 825 void _updateElements(AstNode node) {
819 // build elements in node 826 // build elements in node
820 ElementHolder holder; 827 ElementHolder holder;
821 _ElementsRestorer elementsRestorer = new _ElementsRestorer(node); 828 _ElementsRestorer elementsRestorer = new _ElementsRestorer(node);
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after
925 int beginOffsetOld = math.min(firstOffsetOld, lastOffsetOld); 932 int beginOffsetOld = math.min(firstOffsetOld, lastOffsetOld);
926 int endOffsetOld = math.max(firstOffsetOld, lastOffsetOld); 933 int endOffsetOld = math.max(firstOffsetOld, lastOffsetOld);
927 int beginOffsetNew = math.min(firstOffsetNew, lastOffsetNew); 934 int beginOffsetNew = math.min(firstOffsetNew, lastOffsetNew);
928 int endOffsetNew = math.max(firstOffsetNew, lastOffsetNew); 935 int endOffsetNew = math.max(firstOffsetNew, lastOffsetNew);
929 // check for a whitespace only change 936 // check for a whitespace only change
930 if (identical(lastPair.oldToken, firstPair.oldToken) && 937 if (identical(lastPair.oldToken, firstPair.oldToken) &&
931 identical(lastPair.newToken, firstPair.newToken)) { 938 identical(lastPair.newToken, firstPair.newToken)) {
932 _updateOffset = beginOffsetOld - 1; 939 _updateOffset = beginOffsetOld - 1;
933 _updateEndOld = endOffsetOld; 940 _updateEndOld = endOffsetOld;
934 _updateDelta = newUnit.length - oldUnit.length; 941 _updateDelta = newUnit.length - oldUnit.length;
942 if (firstPair.atComment && lastPair.atComment) {
943 _resolveComment(oldUnit, newUnit, firstPair);
944 }
935 _shiftTokens(firstPair.oldToken, _updateDelta); 945 _shiftTokens(firstPair.oldToken, _updateDelta);
936 IncrementalResolver._updateElementNameOffsets( 946 IncrementalResolver._updateElementNameOffsets(
937 oldUnit.element, 947 oldUnit.element,
938 _updateOffset, 948 _updateOffset,
939 _updateDelta); 949 _updateDelta);
940 _updateEntry(); 950 _updateEntry();
941 return true; 951 return true;
942 } 952 }
943 // print('beginOffsetOld: $beginOffsetOld endOffsetOld: $endOffsetOld');
944 // print('beginOffsetNew: $beginOffsetNew endOffsetNew: $endOffsetNew');
945 // Find nodes covering the "old" and "new" token ranges. 953 // Find nodes covering the "old" and "new" token ranges.
946 AstNode oldNode = 954 AstNode oldNode =
947 _findNodeCovering(oldUnit, beginOffsetOld, endOffsetOld); 955 _findNodeCovering(oldUnit, beginOffsetOld, endOffsetOld);
948 AstNode newNode = 956 AstNode newNode =
949 _findNodeCovering(newUnit, beginOffsetNew, endOffsetNew); 957 _findNodeCovering(newUnit, beginOffsetNew, endOffsetNew);
950 // print('oldNode: $oldNode'); 958 // print('oldNode: $oldNode');
951 // print('newNode: $newNode'); 959 // print('newNode: $newNode');
952 // Try to find the smallest common node, a FunctionBody currently. 960 // Try to find the smallest common node, a FunctionBody currently.
953 { 961 {
954 List<AstNode> oldParents = _getParents(oldNode); 962 List<AstNode> oldParents = _getParents(oldNode);
(...skipping 26 matching lines...) Expand all
981 // print('newNode: $newNode'); 989 // print('newNode: $newNode');
982 // prepare update range 990 // prepare update range
983 _updateOffset = oldNode.offset; 991 _updateOffset = oldNode.offset;
984 _updateEndOld = oldNode.end; 992 _updateEndOld = oldNode.end;
985 _updateEndNew = newNode.end; 993 _updateEndNew = newNode.end;
986 _updateDelta = _updateEndNew - _updateEndOld; 994 _updateDelta = _updateEndNew - _updateEndOld;
987 // replace node 995 // replace node
988 NodeReplacer.replace(oldNode, newNode); 996 NodeReplacer.replace(oldNode, newNode);
989 // update token references 997 // update token references
990 { 998 {
991 Token oldBeginToken = oldNode.beginToken; 999 Token oldBeginToken = _getBeginTokenNotComment(oldNode);
1000 Token newBeginToken = _getBeginTokenNotComment(newNode);
992 if (oldBeginToken.previous.type == TokenType.EOF) { 1001 if (oldBeginToken.previous.type == TokenType.EOF) {
993 oldUnit.beginToken = newNode.beginToken; 1002 oldUnit.beginToken = newBeginToken;
994 } else { 1003 } else {
995 oldBeginToken.previous.setNext(newNode.beginToken); 1004 oldBeginToken.previous.setNext(newBeginToken);
996 } 1005 }
997 newNode.endToken.setNext(oldNode.endToken.next); 1006 newNode.endToken.setNext(oldNode.endToken.next);
998 _shiftTokens(oldNode.endToken.next, _updateDelta); 1007 _shiftTokens(oldNode.endToken.next, _updateDelta);
999 } 1008 }
1000 // perform incremental resolution 1009 // perform incremental resolution
1001 CompilationUnitElement oldUnitElement = oldUnit.element; 1010 CompilationUnitElement oldUnitElement = oldUnit.element;
1002 IncrementalResolver incrementalResolver = new IncrementalResolver( 1011 IncrementalResolver incrementalResolver = new IncrementalResolver(
1003 _typeProvider, 1012 _typeProvider,
1004 oldUnitElement.library,
1005 oldUnitElement, 1013 oldUnitElement,
1006 oldUnitElement.source,
1007 _updateOffset, 1014 _updateOffset,
1008 oldNode.length, 1015 oldNode.length,
1009 newNode.length); 1016 newNode.length);
1010 incrementalResolver.resolve(newNode); 1017 incrementalResolver.resolve(newNode);
1011 _newResolveErrors = incrementalResolver._resolveErrors; 1018 _newResolveErrors = incrementalResolver._resolveErrors;
1012 _newVerifyErrors = incrementalResolver._verifyErrors; 1019 _newVerifyErrors = incrementalResolver._verifyErrors;
1013 _newHints = incrementalResolver._hints; 1020 _newHints = incrementalResolver._hints;
1014 _updateEntry(); 1021 _updateEntry();
1015 // print('Successfully incrementally resolved.'); 1022 // print('Successfully incrementally resolved.');
1016 return true; 1023 return true;
1017 } 1024 }
1018 } catch (e) { 1025 } catch (e) {
1019 // TODO(scheglov) find a way to log these exceptions 1026 // TODO(scheglov) find a way to log these exceptions
1020 // print(e); 1027 // print(e);
1021 // print(st); 1028 // print(st);
1022 } 1029 }
1023 return false; 1030 return false;
1024 } 1031 }
1025 1032
1026 CompilationUnit _parseUnit(String code) { 1033 CompilationUnit _parseUnit(String code) {
1027 Token token = _scan(code); 1034 Token token = _scan(code);
1028 RecordingErrorListener errorListener = new RecordingErrorListener(); 1035 RecordingErrorListener errorListener = new RecordingErrorListener();
1029 Parser parser = new Parser(_unitSource, errorListener); 1036 Parser parser = new Parser(_unitSource, errorListener);
1030 CompilationUnit unit = parser.parseCompilationUnit(token); 1037 CompilationUnit unit = parser.parseCompilationUnit(token);
1031 _newParseErrors = errorListener.errors; 1038 _newParseErrors = errorListener.errors;
1032 return unit; 1039 return unit;
1033 } 1040 }
1034 1041
1042 void _resolveComment(CompilationUnit oldUnit, CompilationUnit newUnit,
1043 _TokenPair firstPair) {
1044 Token oldToken = firstPair.oldToken;
1045 int offset = oldToken.precedingComments.offset;
1046 Comment oldComment = _findNodeCovering(oldUnit, offset, offset);
1047 Comment newComment = _findNodeCovering(newUnit, offset, offset);
1048 _updateOffset = offset + 1;
1049 // replace node
1050 NodeReplacer.replace(oldComment, newComment);
1051 // update token references
1052 _setPrecedingComments(oldToken, newComment.tokens.first);
1053 // resolve references in the comment
1054 CompilationUnitElement oldUnitElement = oldUnit.element;
1055 IncrementalResolver incrementalResolver =
1056 new IncrementalResolver(_typeProvider, oldUnitElement, _updateOffset, 0, 0);
1057 incrementalResolver._resolveReferences(newComment);
1058 }
1059
1035 Token _scan(String code) { 1060 Token _scan(String code) {
1036 RecordingErrorListener errorListener = new RecordingErrorListener(); 1061 RecordingErrorListener errorListener = new RecordingErrorListener();
1037 CharSequenceReader reader = new CharSequenceReader(code); 1062 CharSequenceReader reader = new CharSequenceReader(code);
1038 Scanner scanner = new Scanner(_unitSource, reader, errorListener); 1063 Scanner scanner = new Scanner(_unitSource, reader, errorListener);
1039 Token token = scanner.tokenize(); 1064 Token token = scanner.tokenize();
1040 _newScanErrors = errorListener.errors; 1065 _newScanErrors = errorListener.errors;
1041 return token; 1066 return token;
1042 } 1067 }
1043 1068
1069 void _shiftTokens(Token token, int delta) {
1070 while (token != null) {
1071 if (token.offset > _updateOffset) {
1072 token.offset += delta;
1073 }
1074 _shiftTokens(token.precedingComments, delta);
1075 if (token.type == TokenType.EOF) {
1076 break;
1077 }
1078 token = token.next;
1079 }
1080 }
1081
1044 void _updateEntry() { 1082 void _updateEntry() {
1045 _entry.setValue(DartEntry.SCAN_ERRORS, _newScanErrors); 1083 _entry.setValue(DartEntry.SCAN_ERRORS, _newScanErrors);
1046 _entry.setValue(DartEntry.PARSE_ERRORS, _newParseErrors); 1084 _entry.setValue(DartEntry.PARSE_ERRORS, _newParseErrors);
1047 { 1085 {
1048 List<AnalysisError> oldErrors = 1086 List<AnalysisError> oldErrors =
1049 _entry.getValueInLibrary(DartEntry.RESOLUTION_ERRORS, _librarySource); 1087 _entry.getValueInLibrary(DartEntry.RESOLUTION_ERRORS, _librarySource);
1050 List<AnalysisError> errors = _updateErrors(oldErrors, _newResolveErrors); 1088 List<AnalysisError> errors = _updateErrors(oldErrors, _newResolveErrors);
1051 _entry.setValueInLibrary( 1089 _entry.setValueInLibrary(
1052 DartEntry.RESOLUTION_ERRORS, 1090 DartEntry.RESOLUTION_ERRORS,
1053 _librarySource, 1091 _librarySource,
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
1102 return false; 1140 return false;
1103 } 1141 }
1104 return oldToken.lexeme == newToken.lexeme; 1142 return oldToken.lexeme == newToken.lexeme;
1105 } 1143 }
1106 1144
1107 static _TokenPair _findFirstDifferentToken(Token oldToken, Token newToken) { 1145 static _TokenPair _findFirstDifferentToken(Token oldToken, Token newToken) {
1108 // print('first ------------'); 1146 // print('first ------------');
1109 while (oldToken.type != TokenType.EOF && newToken.type != TokenType.EOF) { 1147 while (oldToken.type != TokenType.EOF && newToken.type != TokenType.EOF) {
1110 // print('old: $oldToken @ ${oldToken.offset}'); 1148 // print('old: $oldToken @ ${oldToken.offset}');
1111 // print('new: $newToken @ ${newToken.offset}'); 1149 // print('new: $newToken @ ${newToken.offset}');
1150 {
1151 Token oldComment = oldToken.precedingComments;
1152 Token newComment = newToken.precedingComments;
1153 if (oldComment != null && newComment != null) {
1154 if (!_equalToken(oldComment, newComment, 0)) {
1155 return new _TokenPair(oldToken, newToken, true);
1156 }
1157 }
1158 }
1112 if (!_equalToken(oldToken, newToken, 0)) { 1159 if (!_equalToken(oldToken, newToken, 0)) {
1113 return new _TokenPair(oldToken, newToken); 1160 return new _TokenPair(oldToken, newToken);
1114 } 1161 }
1115 oldToken = oldToken.next; 1162 oldToken = oldToken.next;
1116 newToken = newToken.next; 1163 newToken = newToken.next;
1117 } 1164 }
1118 return null; 1165 return null;
1119 } 1166 }
1120 1167
1121 static _TokenPair _findLastDifferentToken(Token oldToken, Token newToken) { 1168 static _TokenPair _findLastDifferentToken(Token oldToken, Token newToken) {
1122 // print('last ------------'); 1169 // print('last ------------');
1123 int delta = newToken.offset - oldToken.offset; 1170 int delta = newToken.offset - oldToken.offset;
1124 while (oldToken.previous != oldToken && newToken.previous != newToken) { 1171 while (oldToken.previous != oldToken && newToken.previous != newToken) {
1125 // print('old: $oldToken @ ${oldToken.offset}'); 1172 // print('old: $oldToken @ ${oldToken.offset}');
1126 // print('new: $newToken @ ${newToken.offset}'); 1173 // print('new: $newToken @ ${newToken.offset}');
1127 if (!_equalToken(oldToken, newToken, delta)) { 1174 if (!_equalToken(oldToken, newToken, delta)) {
1128 return new _TokenPair(oldToken.next, newToken.next); 1175 return new _TokenPair(oldToken.next, newToken.next);
1129 } 1176 }
1177 {
1178 Token oldComment = oldToken.precedingComments;
1179 Token newComment = newToken.precedingComments;
1180 if (oldComment != null && newComment != null) {
1181 if (!_equalToken(oldComment, newComment, delta)) {
1182 return new _TokenPair(oldToken, newToken, true);
1183 }
1184 }
1185 }
1130 oldToken = oldToken.previous; 1186 oldToken = oldToken.previous;
1131 newToken = newToken.previous; 1187 newToken = newToken.previous;
1132 } 1188 }
1133 return null; 1189 return null;
1134 } 1190 }
1135 1191
1136 static AstNode _findNodeCovering(AstNode root, int offset, int end) { 1192 static AstNode _findNodeCovering(AstNode root, int offset, int end) {
1137 NodeLocator nodeLocator = new NodeLocator.con2(offset, end); 1193 NodeLocator nodeLocator = new NodeLocator.con2(offset, end);
1138 return nodeLocator.searchWithin(root); 1194 return nodeLocator.searchWithin(root);
1139 } 1195 }
1140 1196
1197 static Token _getBeginTokenNotComment(AstNode node) {
1198 Token oldBeginToken = node.beginToken;
1199 if (oldBeginToken is CommentToken) {
1200 oldBeginToken = (oldBeginToken as CommentToken).parent;
1201 }
1202 return oldBeginToken;
1203 }
1204
1205
1141 static List<AstNode> _getParents(AstNode node) { 1206 static List<AstNode> _getParents(AstNode node) {
1142 List<AstNode> parents = <AstNode>[]; 1207 List<AstNode> parents = <AstNode>[];
1143 while (node != null) { 1208 while (node != null) {
1144 parents.insert(0, node); 1209 parents.insert(0, node);
1145 node = node.parent; 1210 node = node.parent;
1146 } 1211 }
1147 return parents; 1212 return parents;
1148 } 1213 }
1149 1214
1150 static void _shiftTokens(Token token, int delta) { 1215 /**
1151 while (true) { 1216 * Set the given [comment] as a "precedingComments" for [parent].
1152 token.offset += delta; 1217 */
1153 if (token.type == TokenType.EOF) { 1218 static void _setPrecedingComments(Token parent, CommentToken comment) {
1154 break; 1219 if (parent is BeginTokenWithComment) {
1155 } 1220 parent.precedingComments = comment;
1156 token = token.next; 1221 } else if (parent is KeywordTokenWithComment) {
1222 parent.precedingComments = comment;
1223 } else if (parent is StringTokenWithComment) {
1224 parent.precedingComments = comment;
1225 } else if (parent is TokenWithComment) {
1226 parent.precedingComments = comment;
1227 } else {
1228 Type parentType = parent != null ? parent.runtimeType : null;
1229 throw new AnalysisException('Uknown parent token type: $parentType');
1157 } 1230 }
1158 } 1231 }
1159 } 1232 }
1160 1233
1161 1234
1162 /** 1235 /**
1163 * The context to resolve an [AstNode] in. 1236 * The context to resolve an [AstNode] in.
1164 */ 1237 */
1165 class ResolutionContext { 1238 class ResolutionContext {
1166 ClassDeclaration enclosingClassDeclaration; 1239 ClassDeclaration enclosingClassDeclaration;
(...skipping 286 matching lines...) Expand 10 before | Expand all | Expand 10 after
1453 @override 1526 @override
1454 visitSimpleIdentifier(SimpleIdentifier node) { 1527 visitSimpleIdentifier(SimpleIdentifier node) {
1455 _elements[node] = node.staticElement; 1528 _elements[node] = node.staticElement;
1456 } 1529 }
1457 } 1530 }
1458 1531
1459 1532
1460 class _TokenPair { 1533 class _TokenPair {
1461 final Token oldToken; 1534 final Token oldToken;
1462 final Token newToken; 1535 final Token newToken;
1463 _TokenPair(this.oldToken, this.newToken); 1536 final bool atComment;
1537 _TokenPair(this.oldToken, this.newToken, [this.atComment = false]);
1464 } 1538 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698