mirror of
https://github.com/dart-lang/sdk
synced 2024-09-05 08:24:39 +00:00
Improve typedef identifier recovery
... and also address comment in https://dart-review.googlesource.com/c/sdk/+/53140 Change-Id: I915fe4433102bfcbdac95bb63416587b03b98680 Reviewed-on: https://dart-review.googlesource.com/53300 Reviewed-by: Brian Wilkerson <brianwilkerson@google.com> Commit-Queue: Dan Rubel <danrubel@google.com>
This commit is contained in:
parent
46a9ed0617
commit
e93b2ee250
|
@ -4117,11 +4117,11 @@ class Wrong<T> {
|
|||
parseCompilationUnit("typedef var Function(var arg);",
|
||||
errors: usingFastaParser
|
||||
? [
|
||||
expectedError(ParserErrorCode.EXPECTED_TYPE_NAME, 8, 3),
|
||||
expectedError(ParserErrorCode.VAR_AND_TYPE, 21, 3),
|
||||
expectedError(ParserErrorCode.MISSING_IDENTIFIER, 29, 1),
|
||||
expectedError(
|
||||
ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE, 0, 7),
|
||||
expectedError(ParserErrorCode.EXPECTED_TOKEN, 8, 3),
|
||||
expectedError(ParserErrorCode.VAR_RETURN_TYPE, 8, 3),
|
||||
expectedError(ParserErrorCode.MISSING_FUNCTION_BODY, 29, 1),
|
||||
ParserErrorCode.MISSING_TYPEDEF_PARAMETERS, 29, 1),
|
||||
]
|
||||
: [
|
||||
expectedError(ParserErrorCode.MISSING_IDENTIFIER, 8, 3),
|
||||
|
|
|
@ -77,7 +77,7 @@ class ImportDirectivesTest extends PartialCodeTest {
|
|||
],
|
||||
"import 'a.dart' if (b) '';"),
|
||||
new TestDescriptor(
|
||||
'ifCondition',
|
||||
'as',
|
||||
"import 'a.dart' as",
|
||||
[
|
||||
ParserErrorCode.MISSING_IDENTIFIER,
|
||||
|
|
|
@ -26,6 +26,7 @@ import 'return_statement_test.dart' as return_statement;
|
|||
import 'switch_statement_test.dart' as switch_statement;
|
||||
import 'top_level_variable_test.dart' as top_level_variable;
|
||||
import 'try_statement_test.dart' as try_statement;
|
||||
import 'typedef_test.dart' as typedef_declaration;
|
||||
import 'while_statement_test.dart' as while_statement;
|
||||
import 'yield_statement_test.dart' as yield_statement;
|
||||
|
||||
|
@ -53,6 +54,7 @@ main() {
|
|||
switch_statement.main();
|
||||
top_level_variable.main();
|
||||
try_statement.main();
|
||||
typedef_declaration.main();
|
||||
while_statement.main();
|
||||
yield_statement.main();
|
||||
});
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
// Copyright (c) 2017, 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 'partial_code_support.dart';
|
||||
|
||||
main() {
|
||||
new TypedefTest().buildAll();
|
||||
}
|
||||
|
||||
class TypedefTest extends PartialCodeTest {
|
||||
buildAll() {
|
||||
List<String> allExceptEof =
|
||||
PartialCodeTest.declarationSuffixes.map((t) => t.name).toList();
|
||||
buildTests(
|
||||
'typedef',
|
||||
[
|
||||
new TestDescriptor(
|
||||
'keyword',
|
||||
'typedef',
|
||||
[
|
||||
ParserErrorCode.MISSING_IDENTIFIER,
|
||||
ParserErrorCode.MISSING_TYPEDEF_PARAMETERS,
|
||||
ParserErrorCode.EXPECTED_TOKEN
|
||||
],
|
||||
"typedef _s_();",
|
||||
failing: [
|
||||
'functionVoid',
|
||||
'functionNonVoid',
|
||||
'var',
|
||||
'const',
|
||||
'final',
|
||||
'getter'
|
||||
]),
|
||||
new TestDescriptor(
|
||||
'keywordEquals',
|
||||
'typedef =',
|
||||
[
|
||||
ParserErrorCode.MISSING_IDENTIFIER,
|
||||
ParserErrorCode.EXPECTED_TYPE_NAME,
|
||||
ParserErrorCode.EXPECTED_TOKEN
|
||||
],
|
||||
"typedef _s_ = _s_;",
|
||||
failing: allExceptEof),
|
||||
],
|
||||
PartialCodeTest.declarationSuffixes);
|
||||
}
|
||||
}
|
|
@ -54,10 +54,7 @@ class IdentifierContext {
|
|||
isContinuation: true);
|
||||
|
||||
/// Identifier is the name being declared by a typedef declaration.
|
||||
static const typedefDeclaration = const IdentifierContext(
|
||||
'typedefDeclaration',
|
||||
inDeclaration: true,
|
||||
isBuiltInIdentifierAllowed: false);
|
||||
static const typedefDeclaration = const TypedefDeclarationIdentifierContext();
|
||||
|
||||
/// Identifier is a field initializer in a formal parameter list (i.e. it
|
||||
/// appears directly after `this.`).
|
||||
|
|
|
@ -346,6 +346,43 @@ class MethodDeclarationIdentifierContext extends IdentifierContext {
|
|||
}
|
||||
}
|
||||
|
||||
/// See [IdentifierContext].typedefDeclaration
|
||||
class TypedefDeclarationIdentifierContext extends IdentifierContext {
|
||||
const TypedefDeclarationIdentifierContext()
|
||||
: super('typedefDeclaration',
|
||||
inDeclaration: true, isBuiltInIdentifierAllowed: false);
|
||||
|
||||
@override
|
||||
Token ensureIdentifier(Token token, Parser parser) {
|
||||
Token identifier = token.next;
|
||||
assert(identifier.kind != IDENTIFIER_TOKEN);
|
||||
if (identifier.type.isPseudo) {
|
||||
return identifier;
|
||||
}
|
||||
|
||||
// Recovery
|
||||
const followingValues = const ['(', '<', '=', ';', 'var'];
|
||||
if (identifier.type.isBuiltIn &&
|
||||
isOneOfOrEof(identifier.next, followingValues)) {
|
||||
parser.reportRecoverableErrorWithToken(
|
||||
identifier, fasta.templateBuiltInIdentifierInDeclaration);
|
||||
} else if (looksLikeStartOfNextTopLevelDeclaration(identifier) ||
|
||||
isOneOfOrEof(identifier, followingValues)) {
|
||||
identifier = parser.insertSyntheticIdentifier(token, this,
|
||||
message: fasta.templateExpectedIdentifier.withArguments(identifier));
|
||||
} else {
|
||||
parser.reportRecoverableErrorWithToken(
|
||||
identifier, fasta.templateExpectedIdentifier);
|
||||
if (!identifier.isKeywordOrIdentifier) {
|
||||
// When in doubt, consume the token to ensure we make progress
|
||||
// but insert a synthetic identifier to satisfy listeners.
|
||||
identifier = insertSyntheticIdentifierAfter(identifier, parser);
|
||||
}
|
||||
}
|
||||
return identifier;
|
||||
}
|
||||
}
|
||||
|
||||
/// See [IdentifierContext].typeReference
|
||||
class TypeReferenceIdentifierContext extends IdentifierContext {
|
||||
const TypeReferenceIdentifierContext()
|
||||
|
|
|
@ -534,6 +534,12 @@ class Parser {
|
|||
directiveState?.checkDeclaration();
|
||||
if (next.isIdentifier || optional("void", next)) {
|
||||
return parseTypedef(previous);
|
||||
} else if (next.isTopLevelKeyword ||
|
||||
optional('var', next) ||
|
||||
optional('=', next) ||
|
||||
next.isEof) {
|
||||
// Recovery
|
||||
return parseTypedef(previous);
|
||||
} else {
|
||||
return parseTopLevelMemberImpl(previous);
|
||||
}
|
||||
|
@ -2019,8 +2025,6 @@ class Parser {
|
|||
followingValues = ['(', '{', '=>'];
|
||||
} else if (context == IdentifierContext.topLevelVariableDeclaration) {
|
||||
followingValues = [';', '=', ','];
|
||||
} else if (context == IdentifierContext.typedefDeclaration) {
|
||||
followingValues = ['(', '<', ';'];
|
||||
} else if (context == IdentifierContext.typeVariableDeclaration) {
|
||||
followingValues = ['<', '>', ';', '}'];
|
||||
} else {
|
||||
|
@ -2095,8 +2099,6 @@ class Parser {
|
|||
initialKeywords = topLevelKeywords();
|
||||
} else if (context == IdentifierContext.topLevelVariableDeclaration) {
|
||||
initialKeywords = topLevelKeywords();
|
||||
} else if (context == IdentifierContext.typedefDeclaration) {
|
||||
initialKeywords = topLevelKeywords();
|
||||
} else if (context == IdentifierContext.typeVariableDeclaration) {
|
||||
initialKeywords = topLevelKeywords()
|
||||
..addAll(classMemberKeywords())
|
||||
|
|
Loading…
Reference in a new issue