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

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

Issue 2214943002: Fix incremental resolution when inserting/removing empty lines before comments. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 4 years, 4 months 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
« no previous file with comments | « no previous file | pkg/analyzer/test/generated/incremental_resolver_test.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 analyzer.src.generated.incremental_resolver; 5 library analyzer.src.generated.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/dart/ast/ast.dart'; 10 import 'package:analyzer/dart/ast/ast.dart';
(...skipping 551 matching lines...) Expand 10 before | Expand all | Expand 10 after
562 _findLastDifferentToken(_oldUnit.endToken, newUnit.endToken); 562 _findLastDifferentToken(_oldUnit.endToken, newUnit.endToken);
563 if (firstPair != null && lastPair != null) { 563 if (firstPair != null && lastPair != null) {
564 int firstOffsetOld = firstPair.oldToken.offset; 564 int firstOffsetOld = firstPair.oldToken.offset;
565 int firstOffsetNew = firstPair.newToken.offset; 565 int firstOffsetNew = firstPair.newToken.offset;
566 int lastOffsetOld = lastPair.oldToken.end; 566 int lastOffsetOld = lastPair.oldToken.end;
567 int lastOffsetNew = lastPair.newToken.end; 567 int lastOffsetNew = lastPair.newToken.end;
568 int beginOffsetOld = math.min(firstOffsetOld, lastOffsetOld); 568 int beginOffsetOld = math.min(firstOffsetOld, lastOffsetOld);
569 int endOffsetOld = math.max(firstOffsetOld, lastOffsetOld); 569 int endOffsetOld = math.max(firstOffsetOld, lastOffsetOld);
570 int beginOffsetNew = math.min(firstOffsetNew, lastOffsetNew); 570 int beginOffsetNew = math.min(firstOffsetNew, lastOffsetNew);
571 int endOffsetNew = math.max(firstOffsetNew, lastOffsetNew); 571 int endOffsetNew = math.max(firstOffsetNew, lastOffsetNew);
572 // check for a whitespace only change 572 // A pure whitespace change.
573 if (identical(lastPair.oldToken, firstPair.oldToken) && 573 if (identical(firstPair.oldToken, lastPair.oldToken) &&
574 identical(lastPair.newToken, firstPair.newToken)) { 574 identical(firstPair.newToken, lastPair.newToken) &&
575 firstPair.kind == _TokenDifferenceKind.OFFSET) {
575 _updateOffset = beginOffsetOld - 1; 576 _updateOffset = beginOffsetOld - 1;
576 _updateEndOld = endOffsetOld; 577 _updateEndOld = endOffsetOld;
577 _updateEndNew = endOffsetNew; 578 _updateEndNew = endOffsetNew;
578 _updateDelta = newUnit.length - _oldUnit.length; 579 _updateDelta = newUnit.length - _oldUnit.length;
579 // A Dart documentation comment change. 580 logger.log('Whitespace change.');
580 if (firstPair.kind == _TokenDifferenceKind.COMMENT_DOC) { 581 _shiftTokens(firstPair.oldToken, true);
581 bool success = _resolveCommentDoc(newUnit, firstPair); 582 IncrementalResolver incrementalResolver = new IncrementalResolver(
583 _cache,
584 _sourceEntry,
585 _unitEntry,
586 _unitElement,
587 _updateOffset,
588 _updateEndOld,
589 _updateEndNew);
590 incrementalResolver._updateCache();
591 incrementalResolver._updateElementNameOffsets();
592 incrementalResolver._shiftEntryErrors();
593 _updateEntry();
594 logger.log('Success.');
595 return true;
596 }
597 // A Dart documentation comment change.
598 {
599 Token firstOldToken = firstPair.oldToken;
600 Token firstNewToken = firstPair.newToken;
601 Token lastOldToken = lastPair.oldToken;
602 Token lastNewToken = lastPair.newToken;
603 if (firstOldToken is DocumentationCommentToken &&
604 firstNewToken is DocumentationCommentToken &&
605 lastOldToken is DocumentationCommentToken &&
606 lastNewToken is DocumentationCommentToken &&
607 identical(firstOldToken.parent, lastOldToken.parent) &&
608 identical(firstNewToken.parent, lastNewToken.parent)) {
609 _updateOffset = beginOffsetOld;
610 _updateEndOld = firstOldToken.parent.offset;
611 _updateEndNew = firstNewToken.parent.offset;
612 _updateDelta = newUnit.length - _oldUnit.length;
613 bool success =
614 _resolveCommentDoc(newUnit, firstOldToken, firstNewToken);
582 logger.log('Documentation comment resolved: $success'); 615 logger.log('Documentation comment resolved: $success');
583 return success; 616 return success;
584 } 617 }
585 // A pure whitespace change.
586 if (firstPair.kind == _TokenDifferenceKind.OFFSET) {
587 logger.log('Whitespace change.');
588 _shiftTokens(firstPair.oldToken);
589 {
590 IncrementalResolver incrementalResolver = new IncrementalResolver(
591 _cache,
592 _sourceEntry,
593 _unitEntry,
594 _unitElement,
595 _updateOffset,
596 _updateEndOld,
597 _updateEndNew);
598 incrementalResolver._updateCache();
599 incrementalResolver._updateElementNameOffsets();
600 incrementalResolver._shiftEntryErrors();
601 }
602 _updateEntry();
603 logger.log('Success.');
604 return true;
605 }
606 // fall-through, end-of-line comment
607 } 618 }
608 // Find nodes covering the "old" and "new" token ranges. 619 // Find nodes covering the "old" and "new" token ranges.
609 AstNode oldNode = 620 AstNode oldNode =
610 _findNodeCovering(_oldUnit, beginOffsetOld, endOffsetOld - 1); 621 _findNodeCovering(_oldUnit, beginOffsetOld, endOffsetOld - 1);
611 AstNode newNode = 622 AstNode newNode =
612 _findNodeCovering(newUnit, beginOffsetNew, endOffsetNew - 1); 623 _findNodeCovering(newUnit, beginOffsetNew, endOffsetNew - 1);
613 logger.log(() => 'oldNode: $oldNode'); 624 logger.log(() => 'oldNode: $oldNode');
614 logger.log(() => 'newNode: $newNode'); 625 logger.log(() => 'newNode: $newNode');
615 // Try to find the smallest common node, a FunctionBody currently. 626 // Try to find the smallest common node, a FunctionBody currently.
616 { 627 {
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
670 } else { 681 } else {
671 logger.log('Failure: old and new parent mismatch' 682 logger.log('Failure: old and new parent mismatch'
672 ' ${oldParent.runtimeType} vs. ${newParent.runtimeType}'); 683 ' ${oldParent.runtimeType} vs. ${newParent.runtimeType}');
673 return false; 684 return false;
674 } 685 }
675 } 686 }
676 if (!found) { 687 if (!found) {
677 logger.log('Failure: no enclosing function body or executable.'); 688 logger.log('Failure: no enclosing function body or executable.');
678 return false; 689 return false;
679 } 690 }
680 // fail if a comment change outside the bodies
681 if (firstPair.kind == _TokenDifferenceKind.COMMENT) {
682 if (beginOffsetOld <= oldNode.offset ||
683 beginOffsetNew <= newNode.offset) {
684 logger.log('Failure: comment outside a function body.');
685 return false;
686 }
687 }
688 } 691 }
689 logger.log(() => 'oldNode: $oldNode'); 692 logger.log(() => 'oldNode: $oldNode');
690 logger.log(() => 'newNode: $newNode'); 693 logger.log(() => 'newNode: $newNode');
691 // prepare update range 694 // prepare update range
692 _updateOffset = oldNode.offset; 695 _updateOffset = oldNode.offset;
693 _updateEndOld = oldNode.end; 696 _updateEndOld = oldNode.end;
694 _updateEndNew = newNode.end; 697 _updateEndNew = newNode.end;
695 _updateDelta = _updateEndNew - _updateEndOld; 698 _updateDelta = _updateEndNew - _updateEndOld;
696 // replace node 699 // replace node
697 NodeReplacer.replace(oldNode, newNode); 700 NodeReplacer.replace(oldNode, newNode);
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
749 return unit; 752 return unit;
750 } finally { 753 } finally {
751 timer.stop('parse'); 754 timer.stop('parse');
752 } 755 }
753 } 756 }
754 757
755 /** 758 /**
756 * Attempts to resolve a documentation comment change. 759 * Attempts to resolve a documentation comment change.
757 * Returns `true` if success. 760 * Returns `true` if success.
758 */ 761 */
759 bool _resolveCommentDoc(CompilationUnit newUnit, _TokenPair firstPair) { 762 bool _resolveCommentDoc(
760 Token oldToken = firstPair.oldToken; 763 CompilationUnit newUnit, CommentToken oldToken, CommentToken newToken) {
761 Token newToken = firstPair.newToken; 764 if (oldToken == null || newToken == null) {
762 CommentToken oldComments = oldToken.precedingComments;
763 CommentToken newComments = newToken.precedingComments;
764 if (oldComments == null || newComments == null) {
765 return false; 765 return false;
766 } 766 }
767 // find nodes 767 // find nodes
768 int offset = oldComments.offset; 768 int offset = oldToken.offset;
769 logger.log('offset: $offset'); 769 logger.log('offset: $offset');
770 AstNode oldNode = _findNodeCovering(_oldUnit, offset, offset); 770 AstNode oldNode = _findNodeCovering(_oldUnit, offset, offset);
771 AstNode newNode = _findNodeCovering(newUnit, offset, offset); 771 AstNode newNode = _findNodeCovering(newUnit, offset, offset);
772 if (oldNode is! Comment || newNode is! Comment) { 772 if (oldNode is! Comment || newNode is! Comment) {
773 return false; 773 return false;
774 } 774 }
775 Comment oldComment = oldNode; 775 Comment oldComment = oldNode;
776 Comment newComment = newNode; 776 Comment newComment = newNode;
777 logger.log('oldComment.beginToken: ${oldComment.beginToken}'); 777 logger.log('oldComment.beginToken: ${oldComment.beginToken}');
778 logger.log('newComment.beginToken: ${newComment.beginToken}'); 778 logger.log('newComment.beginToken: ${newComment.beginToken}');
779 _updateOffset = oldToken.offset - 1;
780 // update token references 779 // update token references
781 _shiftTokens(firstPair.oldToken); 780 _shiftTokens(oldToken.parent);
782 _setPrecedingComments(oldToken, newComment.tokens.first); 781 _setPrecedingComments(oldToken.parent, newComment.tokens.first);
783 // replace node 782 // replace node
784 NodeReplacer.replace(oldComment, newComment); 783 NodeReplacer.replace(oldComment, newComment);
785 // update elements 784 // update elements
786 IncrementalResolver incrementalResolver = new IncrementalResolver( 785 IncrementalResolver incrementalResolver = new IncrementalResolver(
787 _cache, 786 _cache,
788 _sourceEntry, 787 _sourceEntry,
789 _unitEntry, 788 _unitEntry,
790 _unitElement, 789 _unitElement,
791 _updateOffset, 790 _updateOffset,
792 _updateEndOld, 791 _updateEndOld,
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
841 } else if (token is StringTokenWithComment) { 840 } else if (token is StringTokenWithComment) {
842 token.precedingComments = comment; 841 token.precedingComments = comment;
843 } else if (token is TokenWithComment) { 842 } else if (token is TokenWithComment) {
844 token.precedingComments = comment; 843 token.precedingComments = comment;
845 } else { 844 } else {
846 Type parentType = token?.runtimeType; 845 Type parentType = token?.runtimeType;
847 throw new AnalysisException('Uknown parent token type: $parentType'); 846 throw new AnalysisException('Uknown parent token type: $parentType');
848 } 847 }
849 } 848 }
850 849
851 void _shiftTokens(Token token) { 850 void _shiftTokens(Token token, [bool goUpComment = false]) {
852 while (token != null) { 851 while (token != null) {
852 if (goUpComment && token is CommentToken) {
853 token = (token as CommentToken).parent;
854 }
853 if (token.offset > _updateOffset) { 855 if (token.offset > _updateOffset) {
854 token.offset += _updateDelta; 856 token.offset += _updateDelta;
855 } 857 }
856 // comments 858 // comments
857 _shiftTokens(token.precedingComments); 859 _shiftTokens(token.precedingComments);
858 if (token is DocumentationCommentToken) { 860 if (token is DocumentationCommentToken) {
859 for (Token reference in token.references) { 861 for (Token reference in token.references) {
860 _shiftTokens(reference); 862 _shiftTokens(reference);
861 } 863 }
862 } 864 }
(...skipping 23 matching lines...) Expand all
886 */ 888 */
887 static bool _areCurlyBracketsBalanced(Token token) { 889 static bool _areCurlyBracketsBalanced(Token token) {
888 int numOpen = _getTokenCount(token, TokenType.OPEN_CURLY_BRACKET); 890 int numOpen = _getTokenCount(token, TokenType.OPEN_CURLY_BRACKET);
889 int numOpen2 = 891 int numOpen2 =
890 _getTokenCount(token, TokenType.STRING_INTERPOLATION_EXPRESSION); 892 _getTokenCount(token, TokenType.STRING_INTERPOLATION_EXPRESSION);
891 int numClosed = _getTokenCount(token, TokenType.CLOSE_CURLY_BRACKET); 893 int numClosed = _getTokenCount(token, TokenType.CLOSE_CURLY_BRACKET);
892 return numOpen + numOpen2 == numClosed; 894 return numOpen + numOpen2 == numClosed;
893 } 895 }
894 896
895 static _TokenDifferenceKind _compareToken( 897 static _TokenDifferenceKind _compareToken(
896 Token oldToken, Token newToken, int delta, bool forComment) { 898 Token oldToken, Token newToken, int delta) {
897 while (true) { 899 if (oldToken == null && newToken == null) {
898 if (oldToken == null && newToken == null) { 900 return null;
899 return null; 901 }
900 } 902 if (oldToken == null || newToken == null) {
901 if (oldToken == null || newToken == null) { 903 return _TokenDifferenceKind.CONTENT;
902 return _TokenDifferenceKind.CONTENT; 904 }
903 } 905 if (oldToken.type != newToken.type) {
904 if (oldToken.type != newToken.type) { 906 return _TokenDifferenceKind.CONTENT;
905 return _TokenDifferenceKind.CONTENT; 907 }
906 } 908 if (oldToken.lexeme != newToken.lexeme) {
907 if (oldToken.lexeme != newToken.lexeme) { 909 return _TokenDifferenceKind.CONTENT;
908 return _TokenDifferenceKind.CONTENT; 910 }
909 } 911 if (newToken.offset - oldToken.offset != delta) {
910 if (newToken.offset - oldToken.offset != delta) { 912 return _TokenDifferenceKind.OFFSET;
911 return _TokenDifferenceKind.OFFSET;
912 }
913 // continue if comment tokens are being checked
914 if (!forComment) {
915 break;
916 }
917 oldToken = oldToken.next;
918 newToken = newToken.next;
919 } 913 }
920 return null; 914 return null;
921 } 915 }
922 916
923 static _TokenPair _findFirstDifferentToken(Token oldToken, Token newToken) { 917 static _TokenPair _findFirstDifferentToken(Token oldToken, Token newToken) {
924 while (oldToken.type != TokenType.EOF || newToken.type != TokenType.EOF) { 918 while (oldToken.type != TokenType.EOF || newToken.type != TokenType.EOF) {
925 if (oldToken.type == TokenType.EOF || newToken.type == TokenType.EOF) { 919 if (oldToken.type == TokenType.EOF || newToken.type == TokenType.EOF) {
926 return new _TokenPair(_TokenDifferenceKind.CONTENT, oldToken, newToken); 920 return new _TokenPair(_TokenDifferenceKind.CONTENT, oldToken, newToken);
927 } 921 }
928 // compare comments 922 // compare comments
929 { 923 {
930 Token oldComment = oldToken.precedingComments; 924 Token oldComment = oldToken.precedingComments;
931 Token newComment = newToken.precedingComments; 925 Token newComment = newToken.precedingComments;
932 if (_compareToken(oldComment, newComment, 0, true) != null) { 926 while (true) {
933 _TokenDifferenceKind diffKind = _TokenDifferenceKind.COMMENT; 927 _TokenDifferenceKind diffKind =
934 if (oldComment is DocumentationCommentToken && 928 _compareToken(oldComment, newComment, 0);
935 newComment is DocumentationCommentToken) { 929 if (diffKind != null) {
936 diffKind = _TokenDifferenceKind.COMMENT_DOC; 930 return new _TokenPair(
931 diffKind, oldComment ?? oldToken, newComment ?? newToken);
937 } 932 }
938 return new _TokenPair(diffKind, oldToken, newToken); 933 if (oldComment == null && newComment == null) {
934 break;
935 }
936 oldComment = oldComment.next;
937 newComment = newComment.next;
939 } 938 }
940 } 939 }
941 // compare tokens 940 // compare tokens
942 _TokenDifferenceKind diffKind = 941 _TokenDifferenceKind diffKind = _compareToken(oldToken, newToken, 0);
943 _compareToken(oldToken, newToken, 0, false);
944 if (diffKind != null) { 942 if (diffKind != null) {
945 return new _TokenPair(diffKind, oldToken, newToken); 943 return new _TokenPair(diffKind, oldToken, newToken);
946 } 944 }
947 // next tokens 945 // next tokens
948 oldToken = oldToken.next; 946 oldToken = oldToken.next;
949 newToken = newToken.next; 947 newToken = newToken.next;
950 } 948 }
951 // no difference 949 // no difference
952 return null; 950 return null;
953 } 951 }
954 952
955 static _TokenPair _findLastDifferentToken(Token oldToken, Token newToken) { 953 static _TokenPair _findLastDifferentToken(Token oldToken, Token newToken) {
956 int delta = newToken.offset - oldToken.offset; 954 int delta = newToken.offset - oldToken.offset;
955 Token prevOldToken;
956 Token prevNewToken;
957 while (oldToken.previous != oldToken && newToken.previous != newToken) { 957 while (oldToken.previous != oldToken && newToken.previous != newToken) {
958 // compare tokens 958 // compare tokens
959 _TokenDifferenceKind diffKind = 959 _TokenDifferenceKind diffKind = _compareToken(oldToken, newToken, delta);
960 _compareToken(oldToken, newToken, delta, false);
961 if (diffKind != null) { 960 if (diffKind != null) {
962 return new _TokenPair(diffKind, oldToken.next, newToken.next); 961 return new _TokenPair(diffKind, prevOldToken, prevNewToken);
963 } 962 }
963 prevOldToken = oldToken;
964 prevNewToken = newToken;
964 // compare comments 965 // compare comments
965 { 966 {
966 Token oldComment = oldToken.precedingComments; 967 Token oldComment = oldToken.precedingComments;
967 Token newComment = newToken.precedingComments; 968 Token newComment = newToken.precedingComments;
968 if (_compareToken(oldComment, newComment, delta, true) != null) { 969 while (oldComment?.next != null) {
969 _TokenDifferenceKind diffKind = _TokenDifferenceKind.COMMENT; 970 oldComment = oldComment.next;
970 if (oldComment is DocumentationCommentToken && 971 }
971 newComment is DocumentationCommentToken) { 972 while (newComment?.next != null) {
972 diffKind = _TokenDifferenceKind.COMMENT_DOC; 973 newComment = newComment.next;
974 }
975 while (true) {
976 _TokenDifferenceKind diffKind =
977 _compareToken(oldComment, newComment, delta);
978 if (diffKind != null) {
979 return new _TokenPair(
980 diffKind, oldComment ?? oldToken, newComment ?? newToken);
973 } 981 }
974 return new _TokenPair(diffKind, oldToken, newToken); 982 if (oldComment == null && newComment == null) {
983 break;
984 }
985 prevOldToken = oldComment;
986 prevNewToken = newComment;
987 oldComment = oldComment.previous;
988 newComment = newComment.previous;
975 } 989 }
976 } 990 }
977 // next tokens 991 // next tokens
978 oldToken = oldToken.previous; 992 oldToken = oldToken.previous;
979 newToken = newToken.previous; 993 newToken = newToken.previous;
980 } 994 }
981 return null; 995 return null;
982 } 996 }
983 997
984 static AstNode _findNodeCovering(AstNode root, int offset, int end) { 998 static AstNode _findNodeCovering(AstNode root, int offset, int end) {
(...skipping 298 matching lines...) Expand 10 before | Expand all | Expand 10 after
1283 } 1297 }
1284 token = token.next; 1298 token = token.next;
1285 } 1299 }
1286 } 1300 }
1287 } 1301 }
1288 1302
1289 /** 1303 /**
1290 * Describes how two [Token]s are different. 1304 * Describes how two [Token]s are different.
1291 */ 1305 */
1292 class _TokenDifferenceKind { 1306 class _TokenDifferenceKind {
1293 static const COMMENT = const _TokenDifferenceKind('COMMENT');
1294 static const COMMENT_DOC = const _TokenDifferenceKind('COMMENT_DOC');
1295 static const CONTENT = const _TokenDifferenceKind('CONTENT'); 1307 static const CONTENT = const _TokenDifferenceKind('CONTENT');
1296 static const OFFSET = const _TokenDifferenceKind('OFFSET'); 1308 static const OFFSET = const _TokenDifferenceKind('OFFSET');
1297 1309
1298 final String name; 1310 final String name;
1299 1311
1300 const _TokenDifferenceKind(this.name); 1312 const _TokenDifferenceKind(this.name);
1301 1313
1302 @override 1314 @override
1303 String toString() => name; 1315 String toString() => name;
1304 } 1316 }
1305 1317
1306 class _TokenPair { 1318 class _TokenPair {
1307 final _TokenDifferenceKind kind; 1319 final _TokenDifferenceKind kind;
1308 final Token oldToken; 1320 final Token oldToken;
1309 final Token newToken; 1321 final Token newToken;
1310 _TokenPair(this.kind, this.oldToken, this.newToken); 1322 _TokenPair(this.kind, this.oldToken, this.newToken);
1311 } 1323 }
OLDNEW
« no previous file with comments | « no previous file | pkg/analyzer/test/generated/incremental_resolver_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698