Completion. Issue 53964. Recovery after parsing almost PropertyAccess before 'await'.

Bug: https://github.com/dart-lang/sdk/issues/53964
Change-Id: Ia583243fefd190bb14d857f8547c88e74524d33f
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/357520
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
This commit is contained in:
Konstantin Shcheglov 2024-03-14 18:30:10 +00:00 committed by Commit Queue
parent 6270a46469
commit e7a109c875
4 changed files with 196 additions and 0 deletions

View file

@ -55,6 +55,44 @@ suggestions
''');
}
Future<void> test_afterIdentifier_beforeAwait() async {
await computeSuggestions('''
void f(A a) async {
a.^
await a.foo();
}
class A {
void m01() {}
}
''');
assertResponse(r'''
suggestions
m01
kind: methodInvocation
''');
}
Future<void> test_afterIdentifier_beforeAwait_partial() async {
await computeSuggestions('''
void f(A a) async {
a.m0^
await 0;
}
class A {
void m01() {}
}
''');
assertResponse(r'''
replacement
left: 2
suggestions
m01
kind: methodInvocation
''');
}
Future<void> test_afterIdentifier_beforeIdentifier_partial() async {
newFile('$testPackageLibPath/a.dart', r'''
void v01() {}

View file

@ -3548,6 +3548,61 @@ class AstBuilder extends StackListener {
var comment = _findComment(metadata, variables[0].beginToken);
// var comment = _findComment(metadata,
// variables[0].beginToken ?? type?.beginToken ?? modifiers.beginToken);
// https://github.com/dart-lang/sdk/issues/53964
if (semicolon != null && semicolon.isSynthetic) {
if (variables.singleOrNull case var variable?) {
if (type is NamedTypeImpl) {
var importPrefix = type.importPrefix;
if (importPrefix != null) {
// x.^
// await y.foo();
{
var awaitToken = type.name2;
if (awaitToken.type == Keyword.AWAIT) {
push(
ExpressionStatementImpl(
expression: PrefixedIdentifierImpl(
prefix: SimpleIdentifierImpl(importPrefix.name),
period: importPrefix.period,
identifier: SimpleIdentifierImpl(
parser.rewriter.insertSyntheticIdentifier(
importPrefix.period,
),
),
),
semicolon: semicolon,
),
);
parser.rewriter.insertToken(semicolon, awaitToken);
parser.rewriter.insertToken(awaitToken, variable.name);
return;
}
}
// x.foo^
// await y.bar();
{
var awaitToken = variable.name;
if (awaitToken.type == Keyword.AWAIT) {
push(
ExpressionStatementImpl(
expression: PrefixedIdentifierImpl(
prefix: SimpleIdentifierImpl(importPrefix.name),
period: importPrefix.period,
identifier: SimpleIdentifierImpl(type.name2),
),
semicolon: semicolon,
),
);
parser.rewriter.insertToken(semicolon, awaitToken);
return;
}
}
}
}
}
}
push(
VariableDeclarationStatementImpl(
variableList: VariableDeclarationListImpl(

View file

@ -10,6 +10,8 @@ import 'extension_type_test.dart' as extension_type;
import 'mixin_test.dart' as mixin_;
import 'top_level_function_test.dart' as top_level_function;
import 'top_level_variable_test.dart' as top_level_variable;
import 'variable_declaration_statement_test.dart'
as variable_declaration_statement;
/// Utility for manually running all tests.
main() {
@ -20,5 +22,6 @@ main() {
mixin_.main();
top_level_function.main();
top_level_variable.main();
variable_declaration_statement.main();
}, name: 'parser');
}

View file

@ -0,0 +1,100 @@
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'package:analyzer/src/dart/error/syntactic_errors.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import '../../diagnostics/parser_diagnostics.dart';
main() {
defineReflectiveSuite(() {
defineReflectiveTests(VariableDeclarationStatementParserTest);
});
}
@reflectiveTest
class VariableDeclarationStatementParserTest extends ParserDiagnosticsTest {
test_recovery_propertyAccess_beforeAwait_hasIdentifier() {
final parseResult = parseStringWithErrors(r'''
void f(x) async {
x.foo
await x.bar();
}
''');
parseResult.assertErrors([
error(ParserErrorCode.ASYNC_KEYWORD_USED_AS_IDENTIFIER, 28, 5),
error(ParserErrorCode.EXPECTED_TOKEN, 28, 5),
]);
final node = parseResult.findNode.singleBlock;
assertParsedNodeText(node, r'''
Block
leftBracket: {
statements
ExpressionStatement
expression: PrefixedIdentifier
prefix: SimpleIdentifier
token: x
period: .
identifier: SimpleIdentifier
token: foo
semicolon: ; <synthetic>
ExpressionStatement
expression: AwaitExpression
awaitKeyword: await
expression: MethodInvocation
target: SimpleIdentifier
token: x
operator: .
methodName: SimpleIdentifier
token: bar
argumentList: ArgumentList
leftParenthesis: (
rightParenthesis: )
semicolon: ;
rightBracket: }
''');
}
test_recovery_propertyAccess_beforeAwait_noIdentifier() {
final parseResult = parseStringWithErrors(r'''
void f(x) async {
x.
await x.foo();
}
''');
parseResult.assertErrors([
error(ParserErrorCode.EXPECTED_TOKEN, 31, 1),
]);
final node = parseResult.findNode.singleBlock;
assertParsedNodeText(node, r'''
Block
leftBracket: {
statements
ExpressionStatement
expression: PrefixedIdentifier
prefix: SimpleIdentifier
token: x
period: .
identifier: SimpleIdentifier
token: <empty> <synthetic>
semicolon: ; <synthetic>
ExpressionStatement
expression: AwaitExpression
awaitKeyword: await
expression: MethodInvocation
target: SimpleIdentifier
token: x
operator: .
methodName: SimpleIdentifier
token: foo
argumentList: ArgumentList
leftParenthesis: (
rightParenthesis: )
semicolon: ;
rightBracket: }
''');
}
}