Skip to content

Commit 04dfa8a

Browse files
jensjohaCommit Queue
authored andcommitted
[CFE] Textual outline shouldn't crash on import recovery
Fixes #57051 Change-Id: Ifff69b5987da0a184edea78fd744e343b2005a94 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/399680 Reviewed-by: Johnni Winther <[email protected]> Commit-Queue: Jens Johansen <[email protected]>
1 parent baa49c6 commit 04dfa8a

13 files changed

+119
-7
lines changed

pkg/front_end/lib/src/util/textual_outline.dart

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -402,6 +402,12 @@ class _UnknownChunk extends _TokenChunk {
402402
_UnknownChunk(Token startToken, Token endToken) : super(startToken, endToken);
403403
}
404404

405+
// Coverage-ignore(suite): Not run.
406+
class _RecoveredImportChunk extends _TokenChunk {
407+
_RecoveredImportChunk(Token startToken, Token endToken)
408+
: super(startToken, endToken);
409+
}
410+
405411
class _UnknownTokenBuilder {
406412
Token? start;
407413
Token? interimEnd;
@@ -838,6 +844,7 @@ class TextualOutlineListener extends Listener {
838844
}
839845

840846
Token? firstShowOrHide;
847+
Token? rememberedImportKeyword;
841848
List<_NamespaceCombinator>? _combinators;
842849
List<String>? _combinatorNames;
843850

@@ -887,9 +894,26 @@ class TextualOutlineListener extends Listener {
887894
if (semicolon != null) {
888895
importExportsStartToChunk[importKeyword] = new _ImportChunk(
889896
importKeyword, semicolon, firstShowOrHide, _combinators);
897+
_combinators = null;
898+
firstShowOrHide = null;
899+
} else {
900+
// Coverage-ignore-block(suite): Not run.
901+
rememberedImportKeyword = importKeyword;
902+
}
903+
}
904+
905+
@override
906+
// Coverage-ignore(suite): Not run.
907+
void handleRecoverImport(Token? semicolon) {
908+
gotError = true;
909+
if (semicolon != null) {
910+
if (rememberedImportKeyword != null) {
911+
unsortableElementStartToChunk[rememberedImportKeyword!] =
912+
new _RecoveredImportChunk(rememberedImportKeyword!, semicolon);
913+
}
914+
_combinators = null;
915+
firstShowOrHide = null;
890916
}
891-
_combinators = null;
892-
firstShowOrHide = null;
893917
}
894918

895919
@override

pkg/front_end/test/testing/suite.dart

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1746,10 +1746,24 @@ class FuzzAstVisitorSorter extends IgnoreSomeForCompatibilityAstVisitor {
17461746
node.exportKeyword, node.semicolon);
17471747
}
17481748

1749+
ImportEnd? _importEndNode;
1750+
17491751
@override
17501752
void visitImportEnd(ImportEnd node) {
1751-
handleData(FuzzOriginalType.Import, FuzzSorterState.importExportSortable,
1752-
node.importKeyword, node.semicolon!);
1753+
if (node.semicolon != null) {
1754+
handleData(FuzzOriginalType.Import, FuzzSorterState.importExportSortable,
1755+
node.importKeyword, node.semicolon!);
1756+
} else {
1757+
_importEndNode = node;
1758+
}
1759+
}
1760+
1761+
@override
1762+
void visitRecoverImportHandle(RecoverImportHandle node) {
1763+
if (node.semicolon != null && _importEndNode != null) {
1764+
handleData(FuzzOriginalType.Import, FuzzSorterState.importExportSortable,
1765+
_importEndNode!.importKeyword, node.semicolon!);
1766+
}
17531767
}
17541768

17551769
@override

pkg/front_end/test/textual_outline_test.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -521,7 +521,7 @@ export "a3.dart" show foo;
521521
import "a1.dart" show foo;""") {
522522
throw "Unexpected result: $result";
523523
}
524-
expectUnknownChunk(infoForTesting);
524+
expectNoUnknownChunk(infoForTesting);
525525

526526
// Enums.
527527
infoForTesting = new TextualOutlineInfoForTesting();
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import "syntax_lib.dart" as 28;
2+
3+
digits;
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
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.
4+
5+
import "bad_import_2.dart" show a; // OK
6+
import "bad_import_2.dart" show a as b show c; // Error
7+
import "bad_import_2.dart" as b; // OK
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
library;
2+
//
3+
// Problems in library:
4+
//
5+
// pkg/front_end/testcases/general/bad_import_2.dart:6:35: Error: The prefix ('as' clause) should come before any show/hide combinators.
6+
// Try moving the prefix before the combinators.
7+
// import "bad_import_2.dart" show a as b show c; // Error
8+
// ^^
9+
//
10+
import self as self;
11+
12+
import "org-dartlang-testcase:///bad_import_2.dart" show a;
13+
import "org-dartlang-testcase:///bad_import_2.dart" show a;
14+
import "org-dartlang-testcase:///bad_import_2.dart" as b;
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
library;
2+
//
3+
// Problems in library:
4+
//
5+
// pkg/front_end/testcases/general/bad_import_2.dart:6:35: Error: The prefix ('as' clause) should come before any show/hide combinators.
6+
// Try moving the prefix before the combinators.
7+
// import "bad_import_2.dart" show a as b show c; // Error
8+
// ^^
9+
//
10+
import self as self;
11+
12+
import "org-dartlang-testcase:///bad_import_2.dart" show a;
13+
import "org-dartlang-testcase:///bad_import_2.dart" show a;
14+
import "org-dartlang-testcase:///bad_import_2.dart" as b;
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
library;
2+
//
3+
// Problems in library:
4+
//
5+
// pkg/front_end/testcases/general/bad_import_2.dart:6:35: Error: The prefix ('as' clause) should come before any show/hide combinators.
6+
// Try moving the prefix before the combinators.
7+
// import "bad_import_2.dart" show a as b show c; // Error
8+
// ^^
9+
//
10+
import self as self;
11+
12+
import "org-dartlang-testcase:///bad_import_2.dart" show a;
13+
import "org-dartlang-testcase:///bad_import_2.dart" show a;
14+
import "org-dartlang-testcase:///bad_import_2.dart" as b;
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
library;
2+
//
3+
// Problems in library:
4+
//
5+
// pkg/front_end/testcases/general/bad_import_2.dart:6:35: Error: The prefix ('as' clause) should come before any show/hide combinators.
6+
// Try moving the prefix before the combinators.
7+
// import "bad_import_2.dart" show a as b show c; // Error
8+
// ^^
9+
//
10+
import self as self;
11+
12+
import "org-dartlang-testcase:///bad_import_2.dart" show a;
13+
import "org-dartlang-testcase:///bad_import_2.dart" show a;
14+
import "org-dartlang-testcase:///bad_import_2.dart" as b;
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import "bad_import_2.dart" show a;
2+
3+
import "bad_import_2.dart" show a as b show c;
4+
5+
import "bad_import_2.dart" as b;

0 commit comments

Comments
 (0)