Skip to content

Commit

Permalink
Recover better from illegally named constructors (issue 28807)
Browse files Browse the repository at this point in the history
R=scheglov@google.com

Review-Url: https://codereview.chromium.org/2700343003 .
  • Loading branch information
bwilkerson committed Feb 18, 2017
1 parent 131b0e6 commit f64bad8
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 4 deletions.
5 changes: 5 additions & 0 deletions pkg/analyzer/lib/src/dart/error/syntactic_errors.dart
Expand Up @@ -450,6 +450,11 @@ class ParserErrorCode extends ErrorCode {
"Comment references should contain a possibly prefixed identifier and "
"can start with 'new', but shouldn't contain anything else.");

static const ParserErrorCode INVALID_CONSTRUCTOR_NAME = const ParserErrorCode(
'INVALID_CONSTRUCTOR_NAME',
"The keyword '{0}' cannot be used to name a constructor.",
"Try giving the constructor a different name.");

static const ParserErrorCode INVALID_HEX_ESCAPE = const ParserErrorCode(
'INVALID_HEX_ESCAPE',
"An escape sequence starting with '\\x' must be followed by 2 hexidecimal digits.");
Expand Down
21 changes: 17 additions & 4 deletions pkg/analyzer/lib/src/generated/parser.dart
Expand Up @@ -1379,16 +1379,20 @@ class Parser {
}
return null;
} else if (_tokenMatches(next, TokenType.PERIOD) &&
_tokenMatchesIdentifier(_peekAt(2)) &&
_tokenMatchesIdentifierOrKeyword(_peekAt(2)) &&
_tokenMatches(_peekAt(3), TokenType.OPEN_PAREN)) {
if (!_tokenMatchesIdentifier(_peekAt(2))) {
_reportErrorForToken(ParserErrorCode.INVALID_CONSTRUCTOR_NAME,
_peekAt(2), [_peekAt(2).lexeme]);
}
return _parseConstructor(
commentAndMetadata,
modifiers.externalKeyword,
_validateModifiersForConstructor(modifiers),
modifiers.factoryKeyword,
parseSimpleIdentifier(),
getAndAdvance(),
parseSimpleIdentifier(isDeclaration: true),
parseSimpleIdentifier(allowKeyword: true, isDeclaration: true),
parseFormalParameterList());
} else if (_tokenMatches(next, TokenType.OPEN_PAREN)) {
TypeName returnType = _parseOptionalTypeNameComment();
Expand Down Expand Up @@ -4682,8 +4686,10 @@ class Parser {
* identifier ::=
* IDENTIFIER
*/
SimpleIdentifier parseSimpleIdentifier({bool isDeclaration: false}) {
if (_matchesIdentifier()) {
SimpleIdentifier parseSimpleIdentifier(
{bool allowKeyword: false, bool isDeclaration: false}) {
if (_matchesIdentifier() ||
(allowKeyword && _tokenMatchesIdentifierOrKeyword(_currentToken))) {
return _parseSimpleIdentifierUnchecked(isDeclaration: isDeclaration);
}
_reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER);
Expand Down Expand Up @@ -7961,6 +7967,13 @@ class Parser {
_tokenMatches(token, TokenType.IDENTIFIER) ||
_tokenMatchesPseudoKeyword(token);

/**
* Return `true` if the given [token] is either an identifier or a keyword.
*/
bool _tokenMatchesIdentifierOrKeyword(Token token) =>
_tokenMatches(token, TokenType.IDENTIFIER) ||
_tokenMatches(token, TokenType.KEYWORD);

/**
* Return `true` if the given [token] matches the given [keyword].
*/
Expand Down
7 changes: 7 additions & 0 deletions pkg/analyzer/test/generated/parser_test.dart
Expand Up @@ -1670,6 +1670,13 @@ class Foo {
listener.assertErrorsWithCodes([ParserErrorCode.INVALID_COMMENT_REFERENCE]);
}

void test_invalidConstructorName_with() {
createParser("C.with();");
ClassMember member = parser.parseClassMember('C');
expectNotNullIfNoErrors(member);
listener.assertErrorsWithCodes([ParserErrorCode.INVALID_CONSTRUCTOR_NAME]);
}

void test_invalidHexEscape_invalidDigit() {
createParser("'\\x0 a'");
StringLiteral literal = parser.parseStringLiteral();
Expand Down

0 comments on commit f64bad8

Please sign in to comment.