[analysis_server] Fix stack overflow when generating minimal edits for LSP range formatting

Fixes https://github.com/dart-lang/sdk/issues/47702.

Change-Id: I221427cb78eb6346fe6c78bf09c41bb22c78e8d2
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/220324
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Brian Wilkerson <brianwilkerson@google.com>
This commit is contained in:
Danny Tuppeny 2021-11-16 15:35:42 +00:00 committed by commit-bot@chromium.org
parent 798f2ff442
commit b74e8e5cec
2 changed files with 26 additions and 2 deletions

View file

@ -180,7 +180,10 @@ ErrorOr<List<TextEdit>> _generateMinimalEdits(
// To handle this, if both unformatted/formatted contain at least one
// newline, split this change into two around the last newline so that the
// final part (likely leading whitespace) can be included without
// including the whole change.
// including the whole change. This cannot be done if the newline is at
// the end of the source whitespace though, as this would create a split
// where the first part is the same and the second part is empty,
// resulting in an infinite loop/stack overflow.
//
// Without this, functionality like VS Code's "format modified lines"
// (which uses Git status to know which lines are edited) may appear to
@ -188,7 +191,8 @@ ErrorOr<List<TextEdit>> _generateMinimalEdits(
if (unformattedStart < rangeStart.result &&
unformattedEnd > rangeStart.result &&
unformattedWhitespace.contains('\n') &&
formattedWhitespace.contains('\n')) {
formattedWhitespace.contains('\n') &&
!unformattedWhitespace.endsWith('\n')) {
// Find the offsets of the character after the last newlines.
final unformattedOffset = unformattedWhitespace.lastIndexOf('\n') + 1;
final formattedOffset = formattedWhitespace.lastIndexOf('\n') + 1;

View file

@ -289,6 +289,26 @@ main3 ()
print('test');
}
''';
await initialize();
await openFile(mainFileUri, withoutMarkers(contents));
await expectRangeFormattedContents(mainFileUri, contents, expected);
}
Future<void> test_formatRange_trailingNewline_47702() async {
// Check we complete when a formatted block ends with a newline.
// https://github.com/dart-lang/sdk/issues/47702
const contents = '''
int a;
[[
int b;
]]
''';
final expected = '''
int a;
int b;
''';
await initialize();
await openFile(mainFileUri, withoutMarkers(contents));