Skip to content

Commit e7a109c

Browse files
scheglovCommit Queue
authored andcommitted
Completion. Issue 53964. Recovery after parsing almost PropertyAccess before 'await'.
Bug: #53964 Change-Id: Ia583243fefd190bb14d857f8547c88e74524d33f Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/357520 Commit-Queue: Konstantin Shcheglov <[email protected]> Reviewed-by: Brian Wilkerson <[email protected]>
1 parent 6270a46 commit e7a109c

File tree

4 files changed

+196
-0
lines changed

4 files changed

+196
-0
lines changed

pkg/analysis_server/test/services/completion/dart/location/property_access_expression_test.dart

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,44 @@ suggestions
5555
''');
5656
}
5757

58+
Future<void> test_afterIdentifier_beforeAwait() async {
59+
await computeSuggestions('''
60+
void f(A a) async {
61+
a.^
62+
await a.foo();
63+
}
64+
65+
class A {
66+
void m01() {}
67+
}
68+
''');
69+
assertResponse(r'''
70+
suggestions
71+
m01
72+
kind: methodInvocation
73+
''');
74+
}
75+
76+
Future<void> test_afterIdentifier_beforeAwait_partial() async {
77+
await computeSuggestions('''
78+
void f(A a) async {
79+
a.m0^
80+
await 0;
81+
}
82+
83+
class A {
84+
void m01() {}
85+
}
86+
''');
87+
assertResponse(r'''
88+
replacement
89+
left: 2
90+
suggestions
91+
m01
92+
kind: methodInvocation
93+
''');
94+
}
95+
5896
Future<void> test_afterIdentifier_beforeIdentifier_partial() async {
5997
newFile('$testPackageLibPath/a.dart', r'''
6098
void v01() {}

pkg/analyzer/lib/src/fasta/ast_builder.dart

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3548,6 +3548,61 @@ class AstBuilder extends StackListener {
35483548
var comment = _findComment(metadata, variables[0].beginToken);
35493549
// var comment = _findComment(metadata,
35503550
// variables[0].beginToken ?? type?.beginToken ?? modifiers.beginToken);
3551+
3552+
// https://github.com/dart-lang/sdk/issues/53964
3553+
if (semicolon != null && semicolon.isSynthetic) {
3554+
if (variables.singleOrNull case var variable?) {
3555+
if (type is NamedTypeImpl) {
3556+
var importPrefix = type.importPrefix;
3557+
if (importPrefix != null) {
3558+
// x.^
3559+
// await y.foo();
3560+
{
3561+
var awaitToken = type.name2;
3562+
if (awaitToken.type == Keyword.AWAIT) {
3563+
push(
3564+
ExpressionStatementImpl(
3565+
expression: PrefixedIdentifierImpl(
3566+
prefix: SimpleIdentifierImpl(importPrefix.name),
3567+
period: importPrefix.period,
3568+
identifier: SimpleIdentifierImpl(
3569+
parser.rewriter.insertSyntheticIdentifier(
3570+
importPrefix.period,
3571+
),
3572+
),
3573+
),
3574+
semicolon: semicolon,
3575+
),
3576+
);
3577+
parser.rewriter.insertToken(semicolon, awaitToken);
3578+
parser.rewriter.insertToken(awaitToken, variable.name);
3579+
return;
3580+
}
3581+
}
3582+
// x.foo^
3583+
// await y.bar();
3584+
{
3585+
var awaitToken = variable.name;
3586+
if (awaitToken.type == Keyword.AWAIT) {
3587+
push(
3588+
ExpressionStatementImpl(
3589+
expression: PrefixedIdentifierImpl(
3590+
prefix: SimpleIdentifierImpl(importPrefix.name),
3591+
period: importPrefix.period,
3592+
identifier: SimpleIdentifierImpl(type.name2),
3593+
),
3594+
semicolon: semicolon,
3595+
),
3596+
);
3597+
parser.rewriter.insertToken(semicolon, awaitToken);
3598+
return;
3599+
}
3600+
}
3601+
}
3602+
}
3603+
}
3604+
}
3605+
35513606
push(
35523607
VariableDeclarationStatementImpl(
35533608
variableList: VariableDeclarationListImpl(

pkg/analyzer/test/src/dart/parser/test_all.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import 'extension_type_test.dart' as extension_type;
1010
import 'mixin_test.dart' as mixin_;
1111
import 'top_level_function_test.dart' as top_level_function;
1212
import 'top_level_variable_test.dart' as top_level_variable;
13+
import 'variable_declaration_statement_test.dart'
14+
as variable_declaration_statement;
1315

1416
/// Utility for manually running all tests.
1517
main() {
@@ -20,5 +22,6 @@ main() {
2022
mixin_.main();
2123
top_level_function.main();
2224
top_level_variable.main();
25+
variable_declaration_statement.main();
2326
}, name: 'parser');
2427
}
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
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 'package:analyzer/src/dart/error/syntactic_errors.dart';
6+
import 'package:test_reflective_loader/test_reflective_loader.dart';
7+
8+
import '../../diagnostics/parser_diagnostics.dart';
9+
10+
main() {
11+
defineReflectiveSuite(() {
12+
defineReflectiveTests(VariableDeclarationStatementParserTest);
13+
});
14+
}
15+
16+
@reflectiveTest
17+
class VariableDeclarationStatementParserTest extends ParserDiagnosticsTest {
18+
test_recovery_propertyAccess_beforeAwait_hasIdentifier() {
19+
final parseResult = parseStringWithErrors(r'''
20+
void f(x) async {
21+
x.foo
22+
await x.bar();
23+
}
24+
''');
25+
parseResult.assertErrors([
26+
error(ParserErrorCode.ASYNC_KEYWORD_USED_AS_IDENTIFIER, 28, 5),
27+
error(ParserErrorCode.EXPECTED_TOKEN, 28, 5),
28+
]);
29+
30+
final node = parseResult.findNode.singleBlock;
31+
assertParsedNodeText(node, r'''
32+
Block
33+
leftBracket: {
34+
statements
35+
ExpressionStatement
36+
expression: PrefixedIdentifier
37+
prefix: SimpleIdentifier
38+
token: x
39+
period: .
40+
identifier: SimpleIdentifier
41+
token: foo
42+
semicolon: ; <synthetic>
43+
ExpressionStatement
44+
expression: AwaitExpression
45+
awaitKeyword: await
46+
expression: MethodInvocation
47+
target: SimpleIdentifier
48+
token: x
49+
operator: .
50+
methodName: SimpleIdentifier
51+
token: bar
52+
argumentList: ArgumentList
53+
leftParenthesis: (
54+
rightParenthesis: )
55+
semicolon: ;
56+
rightBracket: }
57+
''');
58+
}
59+
60+
test_recovery_propertyAccess_beforeAwait_noIdentifier() {
61+
final parseResult = parseStringWithErrors(r'''
62+
void f(x) async {
63+
x.
64+
await x.foo();
65+
}
66+
''');
67+
parseResult.assertErrors([
68+
error(ParserErrorCode.EXPECTED_TOKEN, 31, 1),
69+
]);
70+
71+
final node = parseResult.findNode.singleBlock;
72+
assertParsedNodeText(node, r'''
73+
Block
74+
leftBracket: {
75+
statements
76+
ExpressionStatement
77+
expression: PrefixedIdentifier
78+
prefix: SimpleIdentifier
79+
token: x
80+
period: .
81+
identifier: SimpleIdentifier
82+
token: <empty> <synthetic>
83+
semicolon: ; <synthetic>
84+
ExpressionStatement
85+
expression: AwaitExpression
86+
awaitKeyword: await
87+
expression: MethodInvocation
88+
target: SimpleIdentifier
89+
token: x
90+
operator: .
91+
methodName: SimpleIdentifier
92+
token: foo
93+
argumentList: ArgumentList
94+
leftParenthesis: (
95+
rightParenthesis: )
96+
semicolon: ;
97+
rightBracket: }
98+
''');
99+
}
100+
}

0 commit comments

Comments
 (0)