Index: pkg/analyzer/lib/src/generated/parser.dart |
diff --git a/pkg/analyzer/lib/src/generated/parser.dart b/pkg/analyzer/lib/src/generated/parser.dart |
index 4c93ace3bf6dd2f15da19980c72056f0d75fca01..ba8e00c82fd12ae0e5ef911e9b2ef9b306d102b5 100644 |
--- a/pkg/analyzer/lib/src/generated/parser.dart |
+++ b/pkg/analyzer/lib/src/generated/parser.dart |
@@ -308,7 +308,11 @@ class IncrementalParseDispatcher implements ASTVisitor<ASTNode> { |
} else if (identical(_oldNode, node.implementsClause)) { |
return _parser.parseImplementsClause(); |
} else if (node.members.contains(_oldNode)) { |
- return _parser.parseClassMember(node.name.name); |
+ ClassMember member = _parser.parseClassMember(node.name.name); |
+ if (member == null) { |
+ throw new InsufficientContextException(); |
+ } |
+ return member; |
} |
return notAChild(node); |
} |
@@ -1692,6 +1696,14 @@ class Parser { |
return parseOperator(commentAndMetadata, modifiers.externalKeyword, null); |
} |
reportError14(ParserErrorCode.EXPECTED_CLASS_MEMBER, _currentToken, []); |
+ if (commentAndMetadata.comment != null || !commentAndMetadata.metadata.isEmpty) { |
+ // |
+ // We appear to have found an incomplete declaration at the end of the class. At this point |
+ // it consists of a metadata, which we don't want to loose, so we'll treat it as a method |
+ // declaration with a missing name, parameters and empty body. |
+ // |
+ return new MethodDeclaration(commentAndMetadata.comment, commentAndMetadata.metadata, null, null, null, null, null, createSyntheticIdentifier(), new FormalParameterList(null, new List<FormalParameter>(), null, null, null), new EmptyFunctionBody(createSyntheticToken2(TokenType.SEMICOLON))); |
+ } |
return null; |
} else if (matches4(peek(), TokenType.PERIOD) && matchesIdentifier2(peek2(2)) && matches4(peek2(3), TokenType.OPEN_PAREN)) { |
return parseConstructor(commentAndMetadata, modifiers.externalKeyword, validateModifiersForConstructor(modifiers), modifiers.factoryKeyword, parseSimpleIdentifier(), andAdvance, parseSimpleIdentifier(), parseFormalParameterList()); |
@@ -2772,6 +2784,21 @@ class Parser { |
} |
/** |
+ * If [currentToken] is a semicolon, returns it; otherwise reports error and creates a |
+ * synthetic one. |
+ * |
+ * TODO(scheglov) consider pushing this into [expect] |
+ */ |
+ Token expectSemicolon() { |
+ if (matches5(TokenType.SEMICOLON)) { |
+ return andAdvance; |
+ } else { |
+ reportError14(ParserErrorCode.EXPECTED_TOKEN, _currentToken.previous, [";"]); |
+ return createSyntheticToken2(TokenType.SEMICOLON); |
+ } |
+ } |
+ |
+ /** |
* Search the given list of ranges for a range that contains the given index. Return the range |
* that was found, or `null` if none of the ranges contain the index. |
* |
@@ -3833,7 +3860,8 @@ class Parser { |
CommentReference parseCommentReference(String referenceSource, int sourceOffset) { |
// TODO(brianwilkerson) The errors are not getting the right offset/length and are being duplicated. |
if (referenceSource.length == 0) { |
- return null; |
+ Token syntheticToken = new SyntheticStringToken(TokenType.IDENTIFIER, "", sourceOffset); |
+ return new CommentReference(null, new SimpleIdentifier(syntheticToken)); |
} |
try { |
BooleanErrorListener listener = new BooleanErrorListener(); |
@@ -3900,19 +3928,32 @@ class Parser { |
while (leftIndex >= 0 && leftIndex + 1 < length) { |
List<int> range = findRange(codeBlockRanges, leftIndex); |
if (range == null) { |
+ int nameOffset = token.offset + leftIndex + 1; |
int rightIndex = JavaString.indexOf(comment, ']', leftIndex); |
if (rightIndex >= 0) { |
int firstChar = comment.codeUnitAt(leftIndex + 1); |
if (firstChar != 0x27 && firstChar != 0x22) { |
if (isLinkText(comment, rightIndex)) { |
} else { |
- CommentReference reference = parseCommentReference(comment.substring(leftIndex + 1, rightIndex), token.offset + leftIndex + 1); |
+ CommentReference reference = parseCommentReference(comment.substring(leftIndex + 1, rightIndex), nameOffset); |
if (reference != null) { |
references.add(reference); |
} |
} |
} |
} else { |
+ // terminating ']' is not typed yet |
+ int charAfterLeft = comment.codeUnitAt(leftIndex + 1); |
+ if (Character.isLetterOrDigit(charAfterLeft)) { |
+ int nameEnd = StringUtilities.indexOfFirstNotLetterDigit(comment, leftIndex + 1); |
+ String name = comment.substring(leftIndex + 1, nameEnd); |
+ Token nameToken = new StringToken(TokenType.IDENTIFIER, name, nameOffset); |
+ references.add(new CommentReference(null, new SimpleIdentifier(nameToken))); |
+ } else { |
+ Token nameToken = new SyntheticStringToken(TokenType.IDENTIFIER, "", nameOffset); |
+ references.add(new CommentReference(null, new SimpleIdentifier(nameToken))); |
+ } |
+ // next character |
rightIndex = leftIndex + 1; |
} |
leftIndex = JavaString.indexOf(comment, '[', rightIndex); |
@@ -4322,7 +4363,7 @@ class Parser { |
Token exportKeyword = expect(Keyword.EXPORT); |
StringLiteral libraryUri = parseStringLiteral(); |
List<Combinator> combinators = parseCombinators(); |
- Token semicolon = expect2(TokenType.SEMICOLON); |
+ Token semicolon = expectSemicolon(); |
return new ExportDirective(commentAndMetadata.comment, commentAndMetadata.metadata, exportKeyword, libraryUri, combinators, semicolon); |
} |
@@ -4815,7 +4856,7 @@ class Parser { |
prefix = parseSimpleIdentifier(); |
} |
List<Combinator> combinators = parseCombinators(); |
- Token semicolon = expect2(TokenType.SEMICOLON); |
+ Token semicolon = expectSemicolon(); |
return new ImportDirective(commentAndMetadata.comment, commentAndMetadata.metadata, importKeyword, libraryUri, asToken, prefix, combinators, semicolon); |
} |
@@ -5472,9 +5513,7 @@ class Parser { |
if (!_currentToken.type.isIncrementOperator) { |
return operand; |
} |
- if (operand is Literal || operand is FunctionExpressionInvocation) { |
- reportError13(ParserErrorCode.MISSING_ASSIGNABLE_SELECTOR, []); |
- } |
+ ensureAssignable(operand); |
Token operator = andAdvance; |
return new PostfixExpression(operand, operator); |
} |
@@ -6952,7 +6991,7 @@ class Parser { |
*/ |
Token validateModifiersForConstructor(Modifiers modifiers) { |
if (modifiers.abstractKeyword != null) { |
- reportError13(ParserErrorCode.ABSTRACT_CLASS_MEMBER, []); |
+ reportError14(ParserErrorCode.ABSTRACT_CLASS_MEMBER, modifiers.abstractKeyword, []); |
} |
if (modifiers.finalKeyword != null) { |
reportError14(ParserErrorCode.FINAL_CONSTRUCTOR, modifiers.finalKeyword, []); |