[parser] More 'typing' parser tests (with missing end-braces)
Fixes issue when "good" braces are on the same line but the (e.g.) `if`
is on another line.
Change-Id: I3e78a4c557f596eb62b51546927ee0076c8b1a82
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/417163
Commit-Queue: Jens Johansen <jensj@google.com>
Reviewed-by: Johnni Winther <johnniwinther@google.com>
diff --git a/pkg/_fe_analyzer_shared/lib/src/scanner/abstract_scanner.dart b/pkg/_fe_analyzer_shared/lib/src/scanner/abstract_scanner.dart
index 2cefe49..151ee55 100644
--- a/pkg/_fe_analyzer_shared/lib/src/scanner/abstract_scanner.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/scanner/abstract_scanner.dart
@@ -356,6 +356,22 @@
appendToken(new KeywordToken(keyword, tokenStart, comments));
}
+ int _getLineOf(Token token) {
+ if (lineStarts.isEmpty) return -1;
+ final int offset = token.offset;
+ int low = 0, high = lineStarts.length - 1;
+ while (low < high) {
+ int mid = high - ((high - low) >> 1); // Get middle, rounding up.
+ int pivot = lineStarts[mid];
+ if (pivot <= offset) {
+ low = mid;
+ } else {
+ high = mid - 1;
+ }
+ }
+ return low;
+ }
+
/// Find the indentation of the logical line of [token].
///
/// By logical take this as an example:
@@ -415,18 +431,7 @@
}
// Now find the line of [token].
- final int offset = token.offset;
- int low = 0, high = lineStarts.length - 1;
- while (low < high) {
- int mid = high - ((high - low) >> 1); // Get middle, rounding up.
- int pivot = lineStarts[mid];
- if (pivot <= offset) {
- low = mid;
- } else {
- high = mid - 1;
- }
- }
- final int lineIndex = low;
+ final int lineIndex = _getLineOf(token);
if (lineIndex == 0) {
// On first line.
return tokens.next?.charOffset ?? -1;
@@ -463,10 +468,12 @@
Token? lastMismatch;
while (next != null && !next.isEof) {
if (next.isA(TokenType.OPEN_CURLY_BRACKET)) {
- int indentOfNext = _spacesAtStartOfLogicalLineOf(next);
- if (indentOfNext >= 0 &&
- indentOfNext != _spacesAtStartOfLogicalLineOf(next.endGroup!)) {
- lastMismatch = next;
+ if (_getLineOf(next) != _getLineOf(next.endGroup!)) {
+ int indentOfNext = _spacesAtStartOfLogicalLineOf(next);
+ if (indentOfNext >= 0 &&
+ indentOfNext != _spacesAtStartOfLogicalLineOf(next.endGroup!)) {
+ lastMismatch = next;
+ }
}
}
next = next.next;
diff --git a/pkg/front_end/parser_testcases/error_recovery/with_outline/typing_14.dart b/pkg/front_end/parser_testcases/error_recovery/with_outline/typing_14.dart
new file mode 100644
index 0000000..7d5c768
--- /dev/null
+++ b/pkg/front_end/parser_testcases/error_recovery/with_outline/typing_14.dart
@@ -0,0 +1,25 @@
+// Without specific missing-brace recovery, we'll end up with:
+// * Class Foo, member Foo.foo_method1, Foo.toplevel_method1, Foo.toplevel_method2
+// With specific missing-brace recovery, we'll end up with the correct:
+// * Class Foo, members Foo.foo_method1, Foo.foo_method2
+// * Top-level members toplevel_method1, toplevel_method2
+
+class Foo {
+ void foo_method1(dynamic input) {
+ if (1 + 1 == 2) {
+ foo_method2({1, 2, 3 /* missing: }*/)
+ // missing: }
+ }
+
+ void foo_method2(dynamic whatever) {
+ // bla
+ }
+}
+
+void toplevel_method1() {
+ // bla
+}
+
+void toplevel_method2() {
+ // bla
+}
diff --git a/pkg/front_end/parser_testcases/error_recovery/with_outline/typing_14.dart.expect b/pkg/front_end/parser_testcases/error_recovery/with_outline/typing_14.dart.expect
new file mode 100644
index 0000000..ac17730
--- /dev/null
+++ b/pkg/front_end/parser_testcases/error_recovery/with_outline/typing_14.dart.expect
@@ -0,0 +1,137 @@
+Problems reported:
+
+parser/error_recovery/with_outline/typing_14:10:43: Expected ';' after this.
+ foo_method2({1, 2, 3 /* missing: }*/)
+ ^
+
+parser/error_recovery/with_outline/typing_14:10:19: Can't find '}' to match '{'.
+ foo_method2({1, 2, 3 /* missing: }*/)
+ ^
+
+parser/error_recovery/with_outline/typing_14:9:21: Can't find '}' to match '{'.
+ if (1 + 1 == 2) {
+ ^
+
+beginCompilationUnit(class)
+ beginMetadataStar(class)
+ endMetadataStar(0)
+ beginClassOrMixinOrNamedMixinApplicationPrelude(class)
+ handleIdentifier(Foo, classOrMixinDeclaration)
+ handleNoTypeVariables({)
+ beginClassDeclaration(class, null, null, null, null, null, null, null, null, Foo)
+ handleNoType(Foo)
+ handleClassExtends(null, 1)
+ handleClassNoWithClause()
+ handleImplements(null, 0)
+ handleClassHeader(class, class, null)
+ beginClassOrMixinOrExtensionBody(DeclarationKind.Class, {)
+ beginMetadataStar(void)
+ endMetadataStar(0)
+ beginMember()
+ beginMethod(DeclarationKind.Class, null, null, null, null, null, null, foo_method1, Foo)
+ handleVoidKeyword(void)
+ handleIdentifier(foo_method1, methodDeclaration)
+ handleNoTypeVariables(()
+ beginFormalParameters((, MemberKind.NonStaticMethod)
+ beginMetadataStar(dynamic)
+ endMetadataStar(0)
+ beginFormalParameter(dynamic, MemberKind.NonStaticMethod, null, null, null)
+ handleIdentifier(dynamic, typeReference)
+ handleNoTypeArguments(input)
+ handleType(dynamic, null)
+ handleIdentifier(input, formalParameterDeclaration)
+ handleFormalParameterWithoutValue())
+ endFormalParameter(null, null, null, input, null, null, FormalParameterKind.requiredPositional, MemberKind.NonStaticMethod)
+ endFormalParameters(1, (, ), MemberKind.NonStaticMethod)
+ handleNoInitializers()
+ handleAsyncModifier(null, null)
+ beginBlockFunctionBody({)
+ beginIfStatement(if)
+ handleLiteralInt(1)
+ beginBinaryExpression(+)
+ handleLiteralInt(1)
+ endBinaryExpression(+, 1)
+ beginBinaryExpression(==)
+ handleLiteralInt(2)
+ endBinaryExpression(==, 2)
+ handleParenthesizedCondition((, null, null)
+ beginThenStatement({)
+ beginBlock({, BlockKind(statement))
+ handleIdentifier(foo_method2, expression)
+ handleNoTypeArguments(()
+ beginArguments(()
+ handleNoTypeArguments({)
+ handleLiteralInt(1)
+ handleLiteralInt(2)
+ handleLiteralInt(3)
+ handleLiteralSetOrMap(3, {, null, }, true)
+ endArguments(1, (, ))
+ handleSend(foo_method2, ))
+ handleRecoverableError(Message[ExpectedAfterButGot, Expected ';' after this., null, {string: ;}], ), ))
+ handleExpressionStatement(foo_method2, ;)
+ endBlock(1, {, }, BlockKind(statement))
+ endThenStatement({, })
+ endIfStatement(if, null, })
+ endBlockFunctionBody(1, {, })
+ endClassMethod(null, void, (, null, })
+ endMember()
+ beginMetadataStar(void)
+ endMetadataStar(0)
+ beginMember()
+ beginMethod(DeclarationKind.Class, null, null, null, null, null, null, foo_method2, Foo)
+ handleVoidKeyword(void)
+ handleIdentifier(foo_method2, methodDeclaration)
+ handleNoTypeVariables(()
+ beginFormalParameters((, MemberKind.NonStaticMethod)
+ beginMetadataStar(dynamic)
+ endMetadataStar(0)
+ beginFormalParameter(dynamic, MemberKind.NonStaticMethod, null, null, null)
+ handleIdentifier(dynamic, typeReference)
+ handleNoTypeArguments(whatever)
+ handleType(dynamic, null)
+ handleIdentifier(whatever, formalParameterDeclaration)
+ handleFormalParameterWithoutValue())
+ endFormalParameter(null, null, null, whatever, null, null, FormalParameterKind.requiredPositional, MemberKind.NonStaticMethod)
+ endFormalParameters(1, (, ), MemberKind.NonStaticMethod)
+ handleNoInitializers()
+ handleAsyncModifier(null, null)
+ beginBlockFunctionBody({)
+ endBlockFunctionBody(0, {, })
+ endClassMethod(null, void, (, null, })
+ endMember()
+ endClassOrMixinOrExtensionBody(DeclarationKind.Class, 2, {, })
+ endClassDeclaration(class, })
+ endTopLevelDeclaration(})
+ beginMetadataStar(void)
+ endMetadataStar(0)
+ beginTopLevelMember(void)
+ beginTopLevelMethod(}, null, null)
+ handleVoidKeyword(void)
+ handleIdentifier(toplevel_method1, topLevelFunctionDeclaration)
+ handleNoTypeVariables(()
+ beginFormalParameters((, MemberKind.TopLevelMethod)
+ endFormalParameters(0, (, ), MemberKind.TopLevelMethod)
+ handleAsyncModifier(null, null)
+ beginBlockFunctionBody({)
+ endBlockFunctionBody(0, {, })
+ endTopLevelMethod(void, null, })
+ endTopLevelDeclaration(})
+ beginMetadataStar(void)
+ endMetadataStar(0)
+ beginTopLevelMember(void)
+ beginTopLevelMethod(}, null, null)
+ handleVoidKeyword(void)
+ handleIdentifier(toplevel_method2, topLevelFunctionDeclaration)
+ handleNoTypeVariables(()
+ beginFormalParameters((, MemberKind.TopLevelMethod)
+ endFormalParameters(0, (, ), MemberKind.TopLevelMethod)
+ handleAsyncModifier(null, null)
+ beginBlockFunctionBody({)
+ endBlockFunctionBody(0, {, })
+ endTopLevelMethod(void, null, })
+ endTopLevelDeclaration(})
+ handleErrorToken(UnmatchedToken({))
+ handleRecoverableError(Message[UnmatchedToken, Can't find '}' to match '{'., null, {string: }, lexeme: {}], UnmatchedToken({), UnmatchedToken({))
+ handleErrorToken(UnmatchedToken({))
+ handleRecoverableError(Message[UnmatchedToken, Can't find '}' to match '{'., null, {string: }, lexeme: {}], UnmatchedToken({), UnmatchedToken({))
+endCompilationUnit(3, )
diff --git a/pkg/front_end/parser_testcases/error_recovery/with_outline/typing_14.dart.intertwined.expect b/pkg/front_end/parser_testcases/error_recovery/with_outline/typing_14.dart.intertwined.expect
new file mode 100644
index 0000000..ab558dd
--- /dev/null
+++ b/pkg/front_end/parser_testcases/error_recovery/with_outline/typing_14.dart.intertwined.expect
@@ -0,0 +1,269 @@
+parseUnit(UnmatchedToken({))
+ skipErrorTokens(UnmatchedToken({))
+ listener: beginCompilationUnit(class)
+ syntheticPreviousToken(class)
+ parseTopLevelDeclarationImpl(UnmatchedToken({), DirectiveContext(DirectiveState.Unknown))
+ parseMetadataStar(UnmatchedToken({))
+ listener: beginMetadataStar(class)
+ listener: endMetadataStar(0)
+ parseTopLevelKeywordDeclaration(class, UnmatchedToken({), class, null, null, null, null, DirectiveContext(DirectiveState.Unknown))
+ parseClassOrNamedMixinApplication(class, null, null, null, null, null, null, null, null, class)
+ listener: beginClassOrMixinOrNamedMixinApplicationPrelude(class)
+ ensureIdentifier(class, classOrMixinDeclaration)
+ listener: handleIdentifier(Foo, classOrMixinDeclaration)
+ listener: handleNoTypeVariables({)
+ listener: beginClassDeclaration(class, null, null, null, null, null, null, null, null, Foo)
+ parseClass(Foo, class, class, Foo)
+ parseClassHeaderOpt(Foo, class, class)
+ parseClassExtendsOpt(Foo, DeclarationHeaderKind.Class)
+ listener: handleNoType(Foo)
+ listener: handleClassExtends(null, 1)
+ parseClassWithClauseOpt(Foo)
+ listener: handleClassNoWithClause()
+ parseClassOrMixinOrEnumImplementsOpt(Foo)
+ listener: handleImplements(null, 0)
+ listener: handleClassHeader(class, class, null)
+ parseClassOrMixinOrExtensionBody(Foo, DeclarationKind.Class, Foo)
+ listener: beginClassOrMixinOrExtensionBody(DeclarationKind.Class, {)
+ notEofOrValue(}, void)
+ parseClassOrMixinOrExtensionOrEnumMemberImpl({, DeclarationKind.Class, Foo)
+ parseMetadataStar({)
+ listener: beginMetadataStar(void)
+ listener: endMetadataStar(0)
+ listener: beginMember()
+ parseMethod({, null, null, null, null, null, null, null, {, VoidType(), null, foo_method1, DeclarationKind.Class, Foo, false)
+ listener: beginMethod(DeclarationKind.Class, null, null, null, null, null, null, foo_method1, Foo)
+ listener: handleVoidKeyword(void)
+ ensureIdentifierPotentiallyRecovered(void, methodDeclaration, false)
+ listener: handleIdentifier(foo_method1, methodDeclaration)
+ parseQualifiedRestOpt(foo_method1, methodDeclarationContinuation)
+ parseMethodTypeVar(foo_method1)
+ listener: handleNoTypeVariables(()
+ parseGetterOrFormalParameters(foo_method1, foo_method1, false, MemberKind.NonStaticMethod)
+ parseFormalParameters(foo_method1, MemberKind.NonStaticMethod)
+ parseFormalParametersRest((, MemberKind.NonStaticMethod)
+ listener: beginFormalParameters((, MemberKind.NonStaticMethod)
+ parseFormalParameter((, FormalParameterKind.requiredPositional, MemberKind.NonStaticMethod)
+ parseMetadataStar(()
+ listener: beginMetadataStar(dynamic)
+ listener: endMetadataStar(0)
+ listener: beginFormalParameter(dynamic, MemberKind.NonStaticMethod, null, null, null)
+ listener: handleIdentifier(dynamic, typeReference)
+ listener: handleNoTypeArguments(input)
+ listener: handleType(dynamic, null)
+ ensureIdentifier(dynamic, formalParameterDeclaration)
+ listener: handleIdentifier(input, formalParameterDeclaration)
+ listener: handleFormalParameterWithoutValue())
+ listener: endFormalParameter(null, null, null, input, null, null, FormalParameterKind.requiredPositional, MemberKind.NonStaticMethod)
+ listener: endFormalParameters(1, (, ), MemberKind.NonStaticMethod)
+ parseInitializersOpt())
+ listener: handleNoInitializers()
+ parseAsyncModifierOpt())
+ listener: handleAsyncModifier(null, null)
+ inPlainSync()
+ inPlainSync()
+ parseFunctionBody(), false, true)
+ listener: beginBlockFunctionBody({)
+ notEofOrValue(}, if)
+ parseStatement({)
+ parseStatementX({)
+ parseIfStatement({)
+ listener: beginIfStatement(if)
+ ensureParenthesizedCondition(if, allowCase: false)
+ parseExpressionInParenthesisRest((, allowCase: false)
+ parseExpression(()
+ parsePrecedenceExpression((, 1, true, ConstantPatternContext.none)
+ parseUnaryExpression((, true, ConstantPatternContext.none)
+ parsePrimary((, expression, ConstantPatternContext.none)
+ parseLiteralInt(()
+ listener: handleLiteralInt(1)
+ listener: beginBinaryExpression(+)
+ parsePrecedenceExpression(+, 14, true, ConstantPatternContext.none)
+ parseUnaryExpression(+, true, ConstantPatternContext.none)
+ parsePrimary(+, expression, ConstantPatternContext.none)
+ parseLiteralInt(+)
+ listener: handleLiteralInt(1)
+ listener: endBinaryExpression(+, 1)
+ listener: beginBinaryExpression(==)
+ parsePrecedenceExpression(==, 8, true, ConstantPatternContext.none)
+ parseUnaryExpression(==, true, ConstantPatternContext.none)
+ parsePrimary(==, expression, ConstantPatternContext.none)
+ parseLiteralInt(==)
+ listener: handleLiteralInt(2)
+ listener: endBinaryExpression(==, 2)
+ ensureCloseParen(2, ()
+ listener: handleParenthesizedCondition((, null, null)
+ listener: beginThenStatement({)
+ parseStatement())
+ parseStatementX())
+ parseBlock(), BlockKind(statement))
+ ensureBlock(), BlockKind(statement))
+ listener: beginBlock({, BlockKind(statement))
+ notEofOrValue(}, foo_method2)
+ parseStatement({)
+ parseStatementX({)
+ parseExpressionStatementOrDeclarationAfterModifiers({, {, null, null, null, null)
+ looksLikeLocalFunction(foo_method2)
+ parseExpressionStatement({)
+ parseExpression({)
+ parsePrecedenceExpression({, 1, true, ConstantPatternContext.none)
+ parseUnaryExpression({, true, ConstantPatternContext.none)
+ parsePrimary({, expression, ConstantPatternContext.none)
+ parseSendOrFunctionLiteral({, expression, ConstantPatternContext.none)
+ looksLikeFunctionBody(})
+ parseSend({, expression, ConstantPatternContext.none)
+ isNextIdentifier({)
+ ensureIdentifier({, expression)
+ listener: handleIdentifier(foo_method2, expression)
+ listener: handleNoTypeArguments(()
+ parseArgumentsOpt(foo_method2)
+ parseArguments(foo_method2)
+ parseArgumentsRest(()
+ listener: beginArguments(()
+ parseExpression(()
+ parsePrecedenceExpression((, 1, true, ConstantPatternContext.none)
+ parseUnaryExpression((, true, ConstantPatternContext.none)
+ parsePrimary((, expression, ConstantPatternContext.none)
+ listener: handleNoTypeArguments({)
+ parseLiteralSetOrMapSuffix((, null)
+ parseExpression({)
+ parsePrecedenceExpression({, 1, true, ConstantPatternContext.none)
+ parseUnaryExpression({, true, ConstantPatternContext.none)
+ parsePrimary({, expression, ConstantPatternContext.none)
+ parseLiteralInt({)
+ listener: handleLiteralInt(1)
+ parseExpression(,)
+ parsePrecedenceExpression(,, 1, true, ConstantPatternContext.none)
+ parseUnaryExpression(,, true, ConstantPatternContext.none)
+ parsePrimary(,, expression, ConstantPatternContext.none)
+ parseLiteralInt(,)
+ listener: handleLiteralInt(2)
+ parseExpression(,)
+ parsePrecedenceExpression(,, 1, true, ConstantPatternContext.none)
+ parseUnaryExpression(,, true, ConstantPatternContext.none)
+ parsePrimary(,, expression, ConstantPatternContext.none)
+ parseLiteralInt(,)
+ listener: handleLiteralInt(3)
+ listener: handleLiteralSetOrMap(3, {, null, }, true)
+ listener: endArguments(1, (, ))
+ listener: handleSend(foo_method2, ))
+ ensureSemicolon())
+ reportRecoverableError(), Message[ExpectedAfterButGot, Expected ';' after this., null, {string: ;}])
+ listener: handleRecoverableError(Message[ExpectedAfterButGot, Expected ';' after this., null, {string: ;}], ), ))
+ rewriter()
+ listener: handleExpressionStatement(foo_method2, ;)
+ notEofOrValue(}, })
+ listener: endBlock(1, {, }, BlockKind(statement))
+ listener: endThenStatement({, })
+ listener: endIfStatement(if, null, })
+ notEofOrValue(}, })
+ listener: endBlockFunctionBody(1, {, })
+ listener: endClassMethod(null, void, (, null, })
+ listener: endMember()
+ notEofOrValue(}, void)
+ parseClassOrMixinOrExtensionOrEnumMemberImpl(}, DeclarationKind.Class, Foo)
+ parseMetadataStar(})
+ listener: beginMetadataStar(void)
+ listener: endMetadataStar(0)
+ listener: beginMember()
+ parseMethod(}, null, null, null, null, null, null, null, }, VoidType(), null, foo_method2, DeclarationKind.Class, Foo, false)
+ listener: beginMethod(DeclarationKind.Class, null, null, null, null, null, null, foo_method2, Foo)
+ listener: handleVoidKeyword(void)
+ ensureIdentifierPotentiallyRecovered(void, methodDeclaration, false)
+ listener: handleIdentifier(foo_method2, methodDeclaration)
+ parseQualifiedRestOpt(foo_method2, methodDeclarationContinuation)
+ parseMethodTypeVar(foo_method2)
+ listener: handleNoTypeVariables(()
+ parseGetterOrFormalParameters(foo_method2, foo_method2, false, MemberKind.NonStaticMethod)
+ parseFormalParameters(foo_method2, MemberKind.NonStaticMethod)
+ parseFormalParametersRest((, MemberKind.NonStaticMethod)
+ listener: beginFormalParameters((, MemberKind.NonStaticMethod)
+ parseFormalParameter((, FormalParameterKind.requiredPositional, MemberKind.NonStaticMethod)
+ parseMetadataStar(()
+ listener: beginMetadataStar(dynamic)
+ listener: endMetadataStar(0)
+ listener: beginFormalParameter(dynamic, MemberKind.NonStaticMethod, null, null, null)
+ listener: handleIdentifier(dynamic, typeReference)
+ listener: handleNoTypeArguments(whatever)
+ listener: handleType(dynamic, null)
+ ensureIdentifier(dynamic, formalParameterDeclaration)
+ listener: handleIdentifier(whatever, formalParameterDeclaration)
+ listener: handleFormalParameterWithoutValue())
+ listener: endFormalParameter(null, null, null, whatever, null, null, FormalParameterKind.requiredPositional, MemberKind.NonStaticMethod)
+ listener: endFormalParameters(1, (, ), MemberKind.NonStaticMethod)
+ parseInitializersOpt())
+ listener: handleNoInitializers()
+ parseAsyncModifierOpt())
+ listener: handleAsyncModifier(null, null)
+ inPlainSync()
+ inPlainSync()
+ parseFunctionBody(), false, true)
+ listener: beginBlockFunctionBody({)
+ notEofOrValue(}, })
+ listener: endBlockFunctionBody(0, {, })
+ listener: endClassMethod(null, void, (, null, })
+ listener: endMember()
+ notEofOrValue(}, })
+ listener: endClassOrMixinOrExtensionBody(DeclarationKind.Class, 2, {, })
+ listener: endClassDeclaration(class, })
+ listener: endTopLevelDeclaration(})
+ parseTopLevelDeclarationImpl(}, DirectiveContext(DirectiveState.Declarations))
+ parseMetadataStar(})
+ listener: beginMetadataStar(void)
+ listener: endMetadataStar(0)
+ parseTopLevelMemberImpl(})
+ listener: beginTopLevelMember(void)
+ parseTopLevelMethod(}, null, null, }, VoidType(), null, toplevel_method1, false)
+ listener: beginTopLevelMethod(}, null, null)
+ listener: handleVoidKeyword(void)
+ ensureIdentifierPotentiallyRecovered(void, topLevelFunctionDeclaration, false)
+ listener: handleIdentifier(toplevel_method1, topLevelFunctionDeclaration)
+ parseMethodTypeVar(toplevel_method1)
+ listener: handleNoTypeVariables(()
+ parseGetterOrFormalParameters(toplevel_method1, toplevel_method1, false, MemberKind.TopLevelMethod)
+ parseFormalParameters(toplevel_method1, MemberKind.TopLevelMethod)
+ parseFormalParametersRest((, MemberKind.TopLevelMethod)
+ listener: beginFormalParameters((, MemberKind.TopLevelMethod)
+ listener: endFormalParameters(0, (, ), MemberKind.TopLevelMethod)
+ parseAsyncModifierOpt())
+ listener: handleAsyncModifier(null, null)
+ inPlainSync()
+ parseFunctionBody(), false, false)
+ listener: beginBlockFunctionBody({)
+ notEofOrValue(}, })
+ listener: endBlockFunctionBody(0, {, })
+ listener: endTopLevelMethod(void, null, })
+ listener: endTopLevelDeclaration(})
+ parseTopLevelDeclarationImpl(}, DirectiveContext(DirectiveState.Declarations))
+ parseMetadataStar(})
+ listener: beginMetadataStar(void)
+ listener: endMetadataStar(0)
+ parseTopLevelMemberImpl(})
+ listener: beginTopLevelMember(void)
+ parseTopLevelMethod(}, null, null, }, VoidType(), null, toplevel_method2, false)
+ listener: beginTopLevelMethod(}, null, null)
+ listener: handleVoidKeyword(void)
+ ensureIdentifierPotentiallyRecovered(void, topLevelFunctionDeclaration, false)
+ listener: handleIdentifier(toplevel_method2, topLevelFunctionDeclaration)
+ parseMethodTypeVar(toplevel_method2)
+ listener: handleNoTypeVariables(()
+ parseGetterOrFormalParameters(toplevel_method2, toplevel_method2, false, MemberKind.TopLevelMethod)
+ parseFormalParameters(toplevel_method2, MemberKind.TopLevelMethod)
+ parseFormalParametersRest((, MemberKind.TopLevelMethod)
+ listener: beginFormalParameters((, MemberKind.TopLevelMethod)
+ listener: endFormalParameters(0, (, ), MemberKind.TopLevelMethod)
+ parseAsyncModifierOpt())
+ listener: handleAsyncModifier(null, null)
+ inPlainSync()
+ parseFunctionBody(), false, false)
+ listener: beginBlockFunctionBody({)
+ notEofOrValue(}, })
+ listener: endBlockFunctionBody(0, {, })
+ listener: endTopLevelMethod(void, null, })
+ listener: endTopLevelDeclaration(})
+ reportAllErrorTokens(UnmatchedToken({))
+ listener: handleErrorToken(UnmatchedToken({))
+ listener: handleRecoverableError(Message[UnmatchedToken, Can't find '}' to match '{'., null, {string: }, lexeme: {}], UnmatchedToken({), UnmatchedToken({))
+ listener: handleErrorToken(UnmatchedToken({))
+ listener: handleRecoverableError(Message[UnmatchedToken, Can't find '}' to match '{'., null, {string: }, lexeme: {}], UnmatchedToken({), UnmatchedToken({))
+ listener: endCompilationUnit(3, )
diff --git a/pkg/front_end/parser_testcases/error_recovery/with_outline/typing_14.dart.outline.expect b/pkg/front_end/parser_testcases/error_recovery/with_outline/typing_14.dart.outline.expect
new file mode 100644
index 0000000..96af17b
--- /dev/null
+++ b/pkg/front_end/parser_testcases/error_recovery/with_outline/typing_14.dart.outline.expect
@@ -0,0 +1,5 @@
+Class: Foo
+Class method: Foo.foo_method1
+Class method: Foo.foo_method2
+Top-level method: toplevel_method1
+Top-level method: toplevel_method2
diff --git a/pkg/front_end/parser_testcases/error_recovery/with_outline/typing_14.dart.parser.expect b/pkg/front_end/parser_testcases/error_recovery/with_outline/typing_14.dart.parser.expect
new file mode 100644
index 0000000..8bd759f
--- /dev/null
+++ b/pkg/front_end/parser_testcases/error_recovery/with_outline/typing_14.dart.parser.expect
@@ -0,0 +1,43 @@
+NOTICE: Stream was rewritten by parser!
+
+class Foo {
+void foo_method1(dynamic input) {
+if (1 + 1 == 2) {
+foo_method2({1, 2, 3 })
+
+;}}
+
+void foo_method2(dynamic whatever) {
+
+}
+}
+
+void toplevel_method1() {
+
+}
+
+void toplevel_method2() {
+
+}
+
+
+[UnmatchedToken][UnmatchedToken]class[KeywordToken] Foo[StringToken] {[BeginToken]
+void[KeywordToken] foo_method1[StringToken]([BeginToken]dynamic[KeywordToken] input[StringToken])[SimpleToken] {[BeginToken]
+if[KeywordToken] ([BeginToken]1[StringToken] +[SimpleToken] 1[StringToken] ==[SimpleToken] 2[StringToken])[SimpleToken] {[BeginToken]
+foo_method2[StringToken]([BeginToken]{[BeginToken]1[StringToken],[SimpleToken] 2[StringToken],[SimpleToken] 3[StringToken] }[SyntheticToken])[SimpleToken]
+
+;[SyntheticToken]}[SyntheticToken]}[SimpleToken]
+
+void[KeywordToken] foo_method2[StringToken]([BeginToken]dynamic[KeywordToken] whatever[StringToken])[SimpleToken] {[BeginToken]
+
+}[SimpleToken]
+}[SimpleToken]
+
+void[KeywordToken] toplevel_method1[StringToken]([BeginToken])[SimpleToken] {[BeginToken]
+
+}[SimpleToken]
+
+void[KeywordToken] toplevel_method2[StringToken]([BeginToken])[SimpleToken] {[BeginToken]
+
+}[SimpleToken]
+[SimpleToken]
diff --git a/pkg/front_end/parser_testcases/error_recovery/with_outline/typing_14.dart.scanner.expect b/pkg/front_end/parser_testcases/error_recovery/with_outline/typing_14.dart.scanner.expect
new file mode 100644
index 0000000..3d0432b
--- /dev/null
+++ b/pkg/front_end/parser_testcases/error_recovery/with_outline/typing_14.dart.scanner.expect
@@ -0,0 +1,41 @@
+class Foo {
+void foo_method1(dynamic input) {
+if (1 + 1 == 2) {
+foo_method2({1, 2, 3 })
+
+}}
+
+void foo_method2(dynamic whatever) {
+
+}
+}
+
+void toplevel_method1() {
+
+}
+
+void toplevel_method2() {
+
+}
+
+
+[UnmatchedToken][UnmatchedToken]class[KeywordToken] Foo[StringToken] {[BeginToken]
+void[KeywordToken] foo_method1[StringToken]([BeginToken]dynamic[KeywordToken] input[StringToken])[SimpleToken] {[BeginToken]
+if[KeywordToken] ([BeginToken]1[StringToken] +[SimpleToken] 1[StringToken] ==[SimpleToken] 2[StringToken])[SimpleToken] {[BeginToken]
+foo_method2[StringToken]([BeginToken]{[BeginToken]1[StringToken],[SimpleToken] 2[StringToken],[SimpleToken] 3[StringToken] }[SyntheticToken])[SimpleToken]
+
+}[SyntheticToken]}[SimpleToken]
+
+void[KeywordToken] foo_method2[StringToken]([BeginToken]dynamic[KeywordToken] whatever[StringToken])[SimpleToken] {[BeginToken]
+
+}[SimpleToken]
+}[SimpleToken]
+
+void[KeywordToken] toplevel_method1[StringToken]([BeginToken])[SimpleToken] {[BeginToken]
+
+}[SimpleToken]
+
+void[KeywordToken] toplevel_method2[StringToken]([BeginToken])[SimpleToken] {[BeginToken]
+
+}[SimpleToken]
+[SimpleToken]
diff --git a/pkg/front_end/parser_testcases/error_recovery/with_outline/typing_15.dart b/pkg/front_end/parser_testcases/error_recovery/with_outline/typing_15.dart
new file mode 100644
index 0000000..e2ab30d
--- /dev/null
+++ b/pkg/front_end/parser_testcases/error_recovery/with_outline/typing_15.dart
@@ -0,0 +1,29 @@
+// Without specific missing-brace recovery, we'll end up with:
+// * Class Foo, member Foo.foo_method1, Foo.toplevel_method1, Foo.toplevel_method2
+// With specific missing-brace recovery, we'll end up with the correct:
+// * Class Foo, members Foo.foo_method1, Foo.foo_method2
+// * Top-level members toplevel_method1, toplevel_method2
+
+class Foo {
+ void foo_method1(dynamic input) {
+ if (1 + 1 == 2) {
+ // missing: }
+ }
+
+ void foo_method2() {
+ if (1 + 1 == 2 &&
+ 1 + 1 == 2 &&
+ 1 + 1 == 2 &&
+ 1 + 1 == 2 &&
+ 1 + 1 == 2 &&
+ 1 + 1 == 2) {} /* braces on the same line but "if" on another */
+ }
+}
+
+void toplevel_method1() {
+ // bla
+}
+
+void toplevel_method2() {
+ // bla
+}
diff --git a/pkg/front_end/parser_testcases/error_recovery/with_outline/typing_15.dart.expect b/pkg/front_end/parser_testcases/error_recovery/with_outline/typing_15.dart.expect
new file mode 100644
index 0000000..7792232
--- /dev/null
+++ b/pkg/front_end/parser_testcases/error_recovery/with_outline/typing_15.dart.expect
@@ -0,0 +1,165 @@
+Problems reported:
+
+parser/error_recovery/with_outline/typing_15:9:21: Can't find '}' to match '{'.
+ if (1 + 1 == 2) {
+ ^
+
+beginCompilationUnit(class)
+ beginMetadataStar(class)
+ endMetadataStar(0)
+ beginClassOrMixinOrNamedMixinApplicationPrelude(class)
+ handleIdentifier(Foo, classOrMixinDeclaration)
+ handleNoTypeVariables({)
+ beginClassDeclaration(class, null, null, null, null, null, null, null, null, Foo)
+ handleNoType(Foo)
+ handleClassExtends(null, 1)
+ handleClassNoWithClause()
+ handleImplements(null, 0)
+ handleClassHeader(class, class, null)
+ beginClassOrMixinOrExtensionBody(DeclarationKind.Class, {)
+ beginMetadataStar(void)
+ endMetadataStar(0)
+ beginMember()
+ beginMethod(DeclarationKind.Class, null, null, null, null, null, null, foo_method1, Foo)
+ handleVoidKeyword(void)
+ handleIdentifier(foo_method1, methodDeclaration)
+ handleNoTypeVariables(()
+ beginFormalParameters((, MemberKind.NonStaticMethod)
+ beginMetadataStar(dynamic)
+ endMetadataStar(0)
+ beginFormalParameter(dynamic, MemberKind.NonStaticMethod, null, null, null)
+ handleIdentifier(dynamic, typeReference)
+ handleNoTypeArguments(input)
+ handleType(dynamic, null)
+ handleIdentifier(input, formalParameterDeclaration)
+ handleFormalParameterWithoutValue())
+ endFormalParameter(null, null, null, input, null, null, FormalParameterKind.requiredPositional, MemberKind.NonStaticMethod)
+ endFormalParameters(1, (, ), MemberKind.NonStaticMethod)
+ handleNoInitializers()
+ handleAsyncModifier(null, null)
+ beginBlockFunctionBody({)
+ beginIfStatement(if)
+ handleLiteralInt(1)
+ beginBinaryExpression(+)
+ handleLiteralInt(1)
+ endBinaryExpression(+, 1)
+ beginBinaryExpression(==)
+ handleLiteralInt(2)
+ endBinaryExpression(==, 2)
+ handleParenthesizedCondition((, null, null)
+ beginThenStatement({)
+ beginBlock({, BlockKind(statement))
+ endBlock(0, {, }, BlockKind(statement))
+ endThenStatement({, })
+ endIfStatement(if, null, })
+ endBlockFunctionBody(1, {, })
+ endClassMethod(null, void, (, null, })
+ endMember()
+ beginMetadataStar(void)
+ endMetadataStar(0)
+ beginMember()
+ beginMethod(DeclarationKind.Class, null, null, null, null, null, null, foo_method2, Foo)
+ handleVoidKeyword(void)
+ handleIdentifier(foo_method2, methodDeclaration)
+ handleNoTypeVariables(()
+ beginFormalParameters((, MemberKind.NonStaticMethod)
+ endFormalParameters(0, (, ), MemberKind.NonStaticMethod)
+ handleNoInitializers()
+ handleAsyncModifier(null, null)
+ beginBlockFunctionBody({)
+ beginIfStatement(if)
+ handleLiteralInt(1)
+ beginBinaryExpression(+)
+ handleLiteralInt(1)
+ endBinaryExpression(+, 1)
+ beginBinaryExpression(==)
+ handleLiteralInt(2)
+ endBinaryExpression(==, 2)
+ beginBinaryExpression(&&)
+ handleLiteralInt(1)
+ beginBinaryExpression(+)
+ handleLiteralInt(1)
+ endBinaryExpression(+, 1)
+ beginBinaryExpression(==)
+ handleLiteralInt(2)
+ endBinaryExpression(==, 2)
+ endBinaryExpression(&&, 2)
+ beginBinaryExpression(&&)
+ handleLiteralInt(1)
+ beginBinaryExpression(+)
+ handleLiteralInt(1)
+ endBinaryExpression(+, 1)
+ beginBinaryExpression(==)
+ handleLiteralInt(2)
+ endBinaryExpression(==, 2)
+ endBinaryExpression(&&, 2)
+ beginBinaryExpression(&&)
+ handleLiteralInt(1)
+ beginBinaryExpression(+)
+ handleLiteralInt(1)
+ endBinaryExpression(+, 1)
+ beginBinaryExpression(==)
+ handleLiteralInt(2)
+ endBinaryExpression(==, 2)
+ endBinaryExpression(&&, 2)
+ beginBinaryExpression(&&)
+ handleLiteralInt(1)
+ beginBinaryExpression(+)
+ handleLiteralInt(1)
+ endBinaryExpression(+, 1)
+ beginBinaryExpression(==)
+ handleLiteralInt(2)
+ endBinaryExpression(==, 2)
+ endBinaryExpression(&&, 2)
+ beginBinaryExpression(&&)
+ handleLiteralInt(1)
+ beginBinaryExpression(+)
+ handleLiteralInt(1)
+ endBinaryExpression(+, 1)
+ beginBinaryExpression(==)
+ handleLiteralInt(2)
+ endBinaryExpression(==, 2)
+ endBinaryExpression(&&, 2)
+ handleParenthesizedCondition((, null, null)
+ beginThenStatement({)
+ beginBlock({, BlockKind(statement))
+ endBlock(0, {, }, BlockKind(statement))
+ endThenStatement({, })
+ endIfStatement(if, null, })
+ endBlockFunctionBody(1, {, })
+ endClassMethod(null, void, (, null, })
+ endMember()
+ endClassOrMixinOrExtensionBody(DeclarationKind.Class, 2, {, })
+ endClassDeclaration(class, })
+ endTopLevelDeclaration(})
+ beginMetadataStar(void)
+ endMetadataStar(0)
+ beginTopLevelMember(void)
+ beginTopLevelMethod(}, null, null)
+ handleVoidKeyword(void)
+ handleIdentifier(toplevel_method1, topLevelFunctionDeclaration)
+ handleNoTypeVariables(()
+ beginFormalParameters((, MemberKind.TopLevelMethod)
+ endFormalParameters(0, (, ), MemberKind.TopLevelMethod)
+ handleAsyncModifier(null, null)
+ beginBlockFunctionBody({)
+ endBlockFunctionBody(0, {, })
+ endTopLevelMethod(void, null, })
+ endTopLevelDeclaration(})
+ beginMetadataStar(void)
+ endMetadataStar(0)
+ beginTopLevelMember(void)
+ beginTopLevelMethod(}, null, null)
+ handleVoidKeyword(void)
+ handleIdentifier(toplevel_method2, topLevelFunctionDeclaration)
+ handleNoTypeVariables(()
+ beginFormalParameters((, MemberKind.TopLevelMethod)
+ endFormalParameters(0, (, ), MemberKind.TopLevelMethod)
+ handleAsyncModifier(null, null)
+ beginBlockFunctionBody({)
+ endBlockFunctionBody(0, {, })
+ endTopLevelMethod(void, null, })
+ endTopLevelDeclaration(})
+ handleErrorToken(UnmatchedToken({))
+ handleRecoverableError(Message[UnmatchedToken, Can't find '}' to match '{'., null, {string: }, lexeme: {}], UnmatchedToken({), UnmatchedToken({))
+endCompilationUnit(3, )
diff --git a/pkg/front_end/parser_testcases/error_recovery/with_outline/typing_15.dart.intertwined.expect b/pkg/front_end/parser_testcases/error_recovery/with_outline/typing_15.dart.intertwined.expect
new file mode 100644
index 0000000..6643676
--- /dev/null
+++ b/pkg/front_end/parser_testcases/error_recovery/with_outline/typing_15.dart.intertwined.expect
@@ -0,0 +1,346 @@
+parseUnit(UnmatchedToken({))
+ skipErrorTokens(UnmatchedToken({))
+ listener: beginCompilationUnit(class)
+ syntheticPreviousToken(class)
+ parseTopLevelDeclarationImpl(UnmatchedToken({), DirectiveContext(DirectiveState.Unknown))
+ parseMetadataStar(UnmatchedToken({))
+ listener: beginMetadataStar(class)
+ listener: endMetadataStar(0)
+ parseTopLevelKeywordDeclaration(class, UnmatchedToken({), class, null, null, null, null, DirectiveContext(DirectiveState.Unknown))
+ parseClassOrNamedMixinApplication(class, null, null, null, null, null, null, null, null, class)
+ listener: beginClassOrMixinOrNamedMixinApplicationPrelude(class)
+ ensureIdentifier(class, classOrMixinDeclaration)
+ listener: handleIdentifier(Foo, classOrMixinDeclaration)
+ listener: handleNoTypeVariables({)
+ listener: beginClassDeclaration(class, null, null, null, null, null, null, null, null, Foo)
+ parseClass(Foo, class, class, Foo)
+ parseClassHeaderOpt(Foo, class, class)
+ parseClassExtendsOpt(Foo, DeclarationHeaderKind.Class)
+ listener: handleNoType(Foo)
+ listener: handleClassExtends(null, 1)
+ parseClassWithClauseOpt(Foo)
+ listener: handleClassNoWithClause()
+ parseClassOrMixinOrEnumImplementsOpt(Foo)
+ listener: handleImplements(null, 0)
+ listener: handleClassHeader(class, class, null)
+ parseClassOrMixinOrExtensionBody(Foo, DeclarationKind.Class, Foo)
+ listener: beginClassOrMixinOrExtensionBody(DeclarationKind.Class, {)
+ notEofOrValue(}, void)
+ parseClassOrMixinOrExtensionOrEnumMemberImpl({, DeclarationKind.Class, Foo)
+ parseMetadataStar({)
+ listener: beginMetadataStar(void)
+ listener: endMetadataStar(0)
+ listener: beginMember()
+ parseMethod({, null, null, null, null, null, null, null, {, VoidType(), null, foo_method1, DeclarationKind.Class, Foo, false)
+ listener: beginMethod(DeclarationKind.Class, null, null, null, null, null, null, foo_method1, Foo)
+ listener: handleVoidKeyword(void)
+ ensureIdentifierPotentiallyRecovered(void, methodDeclaration, false)
+ listener: handleIdentifier(foo_method1, methodDeclaration)
+ parseQualifiedRestOpt(foo_method1, methodDeclarationContinuation)
+ parseMethodTypeVar(foo_method1)
+ listener: handleNoTypeVariables(()
+ parseGetterOrFormalParameters(foo_method1, foo_method1, false, MemberKind.NonStaticMethod)
+ parseFormalParameters(foo_method1, MemberKind.NonStaticMethod)
+ parseFormalParametersRest((, MemberKind.NonStaticMethod)
+ listener: beginFormalParameters((, MemberKind.NonStaticMethod)
+ parseFormalParameter((, FormalParameterKind.requiredPositional, MemberKind.NonStaticMethod)
+ parseMetadataStar(()
+ listener: beginMetadataStar(dynamic)
+ listener: endMetadataStar(0)
+ listener: beginFormalParameter(dynamic, MemberKind.NonStaticMethod, null, null, null)
+ listener: handleIdentifier(dynamic, typeReference)
+ listener: handleNoTypeArguments(input)
+ listener: handleType(dynamic, null)
+ ensureIdentifier(dynamic, formalParameterDeclaration)
+ listener: handleIdentifier(input, formalParameterDeclaration)
+ listener: handleFormalParameterWithoutValue())
+ listener: endFormalParameter(null, null, null, input, null, null, FormalParameterKind.requiredPositional, MemberKind.NonStaticMethod)
+ listener: endFormalParameters(1, (, ), MemberKind.NonStaticMethod)
+ parseInitializersOpt())
+ listener: handleNoInitializers()
+ parseAsyncModifierOpt())
+ listener: handleAsyncModifier(null, null)
+ inPlainSync()
+ inPlainSync()
+ parseFunctionBody(), false, true)
+ listener: beginBlockFunctionBody({)
+ notEofOrValue(}, if)
+ parseStatement({)
+ parseStatementX({)
+ parseIfStatement({)
+ listener: beginIfStatement(if)
+ ensureParenthesizedCondition(if, allowCase: false)
+ parseExpressionInParenthesisRest((, allowCase: false)
+ parseExpression(()
+ parsePrecedenceExpression((, 1, true, ConstantPatternContext.none)
+ parseUnaryExpression((, true, ConstantPatternContext.none)
+ parsePrimary((, expression, ConstantPatternContext.none)
+ parseLiteralInt(()
+ listener: handleLiteralInt(1)
+ listener: beginBinaryExpression(+)
+ parsePrecedenceExpression(+, 14, true, ConstantPatternContext.none)
+ parseUnaryExpression(+, true, ConstantPatternContext.none)
+ parsePrimary(+, expression, ConstantPatternContext.none)
+ parseLiteralInt(+)
+ listener: handleLiteralInt(1)
+ listener: endBinaryExpression(+, 1)
+ listener: beginBinaryExpression(==)
+ parsePrecedenceExpression(==, 8, true, ConstantPatternContext.none)
+ parseUnaryExpression(==, true, ConstantPatternContext.none)
+ parsePrimary(==, expression, ConstantPatternContext.none)
+ parseLiteralInt(==)
+ listener: handleLiteralInt(2)
+ listener: endBinaryExpression(==, 2)
+ ensureCloseParen(2, ()
+ listener: handleParenthesizedCondition((, null, null)
+ listener: beginThenStatement({)
+ parseStatement())
+ parseStatementX())
+ parseBlock(), BlockKind(statement))
+ ensureBlock(), BlockKind(statement))
+ listener: beginBlock({, BlockKind(statement))
+ notEofOrValue(}, })
+ listener: endBlock(0, {, }, BlockKind(statement))
+ listener: endThenStatement({, })
+ listener: endIfStatement(if, null, })
+ notEofOrValue(}, })
+ listener: endBlockFunctionBody(1, {, })
+ listener: endClassMethod(null, void, (, null, })
+ listener: endMember()
+ notEofOrValue(}, void)
+ parseClassOrMixinOrExtensionOrEnumMemberImpl(}, DeclarationKind.Class, Foo)
+ parseMetadataStar(})
+ listener: beginMetadataStar(void)
+ listener: endMetadataStar(0)
+ listener: beginMember()
+ parseMethod(}, null, null, null, null, null, null, null, }, VoidType(), null, foo_method2, DeclarationKind.Class, Foo, false)
+ listener: beginMethod(DeclarationKind.Class, null, null, null, null, null, null, foo_method2, Foo)
+ listener: handleVoidKeyword(void)
+ ensureIdentifierPotentiallyRecovered(void, methodDeclaration, false)
+ listener: handleIdentifier(foo_method2, methodDeclaration)
+ parseQualifiedRestOpt(foo_method2, methodDeclarationContinuation)
+ parseMethodTypeVar(foo_method2)
+ listener: handleNoTypeVariables(()
+ parseGetterOrFormalParameters(foo_method2, foo_method2, false, MemberKind.NonStaticMethod)
+ parseFormalParameters(foo_method2, MemberKind.NonStaticMethod)
+ parseFormalParametersRest((, MemberKind.NonStaticMethod)
+ listener: beginFormalParameters((, MemberKind.NonStaticMethod)
+ listener: endFormalParameters(0, (, ), MemberKind.NonStaticMethod)
+ parseInitializersOpt())
+ listener: handleNoInitializers()
+ parseAsyncModifierOpt())
+ listener: handleAsyncModifier(null, null)
+ inPlainSync()
+ inPlainSync()
+ parseFunctionBody(), false, true)
+ listener: beginBlockFunctionBody({)
+ notEofOrValue(}, if)
+ parseStatement({)
+ parseStatementX({)
+ parseIfStatement({)
+ listener: beginIfStatement(if)
+ ensureParenthesizedCondition(if, allowCase: false)
+ parseExpressionInParenthesisRest((, allowCase: false)
+ parseExpression(()
+ parsePrecedenceExpression((, 1, true, ConstantPatternContext.none)
+ parseUnaryExpression((, true, ConstantPatternContext.none)
+ parsePrimary((, expression, ConstantPatternContext.none)
+ parseLiteralInt(()
+ listener: handleLiteralInt(1)
+ listener: beginBinaryExpression(+)
+ parsePrecedenceExpression(+, 14, true, ConstantPatternContext.none)
+ parseUnaryExpression(+, true, ConstantPatternContext.none)
+ parsePrimary(+, expression, ConstantPatternContext.none)
+ parseLiteralInt(+)
+ listener: handleLiteralInt(1)
+ listener: endBinaryExpression(+, 1)
+ listener: beginBinaryExpression(==)
+ parsePrecedenceExpression(==, 8, true, ConstantPatternContext.none)
+ parseUnaryExpression(==, true, ConstantPatternContext.none)
+ parsePrimary(==, expression, ConstantPatternContext.none)
+ parseLiteralInt(==)
+ listener: handleLiteralInt(2)
+ listener: endBinaryExpression(==, 2)
+ listener: beginBinaryExpression(&&)
+ parsePrecedenceExpression(&&, 7, true, ConstantPatternContext.none)
+ parseUnaryExpression(&&, true, ConstantPatternContext.none)
+ parsePrimary(&&, expression, ConstantPatternContext.none)
+ parseLiteralInt(&&)
+ listener: handleLiteralInt(1)
+ listener: beginBinaryExpression(+)
+ parsePrecedenceExpression(+, 14, true, ConstantPatternContext.none)
+ parseUnaryExpression(+, true, ConstantPatternContext.none)
+ parsePrimary(+, expression, ConstantPatternContext.none)
+ parseLiteralInt(+)
+ listener: handleLiteralInt(1)
+ listener: endBinaryExpression(+, 1)
+ listener: beginBinaryExpression(==)
+ parsePrecedenceExpression(==, 8, true, ConstantPatternContext.none)
+ parseUnaryExpression(==, true, ConstantPatternContext.none)
+ parsePrimary(==, expression, ConstantPatternContext.none)
+ parseLiteralInt(==)
+ listener: handleLiteralInt(2)
+ listener: endBinaryExpression(==, 2)
+ listener: endBinaryExpression(&&, 2)
+ listener: beginBinaryExpression(&&)
+ parsePrecedenceExpression(&&, 7, true, ConstantPatternContext.none)
+ parseUnaryExpression(&&, true, ConstantPatternContext.none)
+ parsePrimary(&&, expression, ConstantPatternContext.none)
+ parseLiteralInt(&&)
+ listener: handleLiteralInt(1)
+ listener: beginBinaryExpression(+)
+ parsePrecedenceExpression(+, 14, true, ConstantPatternContext.none)
+ parseUnaryExpression(+, true, ConstantPatternContext.none)
+ parsePrimary(+, expression, ConstantPatternContext.none)
+ parseLiteralInt(+)
+ listener: handleLiteralInt(1)
+ listener: endBinaryExpression(+, 1)
+ listener: beginBinaryExpression(==)
+ parsePrecedenceExpression(==, 8, true, ConstantPatternContext.none)
+ parseUnaryExpression(==, true, ConstantPatternContext.none)
+ parsePrimary(==, expression, ConstantPatternContext.none)
+ parseLiteralInt(==)
+ listener: handleLiteralInt(2)
+ listener: endBinaryExpression(==, 2)
+ listener: endBinaryExpression(&&, 2)
+ listener: beginBinaryExpression(&&)
+ parsePrecedenceExpression(&&, 7, true, ConstantPatternContext.none)
+ parseUnaryExpression(&&, true, ConstantPatternContext.none)
+ parsePrimary(&&, expression, ConstantPatternContext.none)
+ parseLiteralInt(&&)
+ listener: handleLiteralInt(1)
+ listener: beginBinaryExpression(+)
+ parsePrecedenceExpression(+, 14, true, ConstantPatternContext.none)
+ parseUnaryExpression(+, true, ConstantPatternContext.none)
+ parsePrimary(+, expression, ConstantPatternContext.none)
+ parseLiteralInt(+)
+ listener: handleLiteralInt(1)
+ listener: endBinaryExpression(+, 1)
+ listener: beginBinaryExpression(==)
+ parsePrecedenceExpression(==, 8, true, ConstantPatternContext.none)
+ parseUnaryExpression(==, true, ConstantPatternContext.none)
+ parsePrimary(==, expression, ConstantPatternContext.none)
+ parseLiteralInt(==)
+ listener: handleLiteralInt(2)
+ listener: endBinaryExpression(==, 2)
+ listener: endBinaryExpression(&&, 2)
+ listener: beginBinaryExpression(&&)
+ parsePrecedenceExpression(&&, 7, true, ConstantPatternContext.none)
+ parseUnaryExpression(&&, true, ConstantPatternContext.none)
+ parsePrimary(&&, expression, ConstantPatternContext.none)
+ parseLiteralInt(&&)
+ listener: handleLiteralInt(1)
+ listener: beginBinaryExpression(+)
+ parsePrecedenceExpression(+, 14, true, ConstantPatternContext.none)
+ parseUnaryExpression(+, true, ConstantPatternContext.none)
+ parsePrimary(+, expression, ConstantPatternContext.none)
+ parseLiteralInt(+)
+ listener: handleLiteralInt(1)
+ listener: endBinaryExpression(+, 1)
+ listener: beginBinaryExpression(==)
+ parsePrecedenceExpression(==, 8, true, ConstantPatternContext.none)
+ parseUnaryExpression(==, true, ConstantPatternContext.none)
+ parsePrimary(==, expression, ConstantPatternContext.none)
+ parseLiteralInt(==)
+ listener: handleLiteralInt(2)
+ listener: endBinaryExpression(==, 2)
+ listener: endBinaryExpression(&&, 2)
+ listener: beginBinaryExpression(&&)
+ parsePrecedenceExpression(&&, 7, true, ConstantPatternContext.none)
+ parseUnaryExpression(&&, true, ConstantPatternContext.none)
+ parsePrimary(&&, expression, ConstantPatternContext.none)
+ parseLiteralInt(&&)
+ listener: handleLiteralInt(1)
+ listener: beginBinaryExpression(+)
+ parsePrecedenceExpression(+, 14, true, ConstantPatternContext.none)
+ parseUnaryExpression(+, true, ConstantPatternContext.none)
+ parsePrimary(+, expression, ConstantPatternContext.none)
+ parseLiteralInt(+)
+ listener: handleLiteralInt(1)
+ listener: endBinaryExpression(+, 1)
+ listener: beginBinaryExpression(==)
+ parsePrecedenceExpression(==, 8, true, ConstantPatternContext.none)
+ parseUnaryExpression(==, true, ConstantPatternContext.none)
+ parsePrimary(==, expression, ConstantPatternContext.none)
+ parseLiteralInt(==)
+ listener: handleLiteralInt(2)
+ listener: endBinaryExpression(==, 2)
+ listener: endBinaryExpression(&&, 2)
+ ensureCloseParen(2, ()
+ listener: handleParenthesizedCondition((, null, null)
+ listener: beginThenStatement({)
+ parseStatement())
+ parseStatementX())
+ parseBlock(), BlockKind(statement))
+ ensureBlock(), BlockKind(statement))
+ listener: beginBlock({, BlockKind(statement))
+ notEofOrValue(}, })
+ listener: endBlock(0, {, }, BlockKind(statement))
+ listener: endThenStatement({, })
+ listener: endIfStatement(if, null, })
+ notEofOrValue(}, })
+ listener: endBlockFunctionBody(1, {, })
+ listener: endClassMethod(null, void, (, null, })
+ listener: endMember()
+ notEofOrValue(}, })
+ listener: endClassOrMixinOrExtensionBody(DeclarationKind.Class, 2, {, })
+ listener: endClassDeclaration(class, })
+ listener: endTopLevelDeclaration(})
+ parseTopLevelDeclarationImpl(}, DirectiveContext(DirectiveState.Declarations))
+ parseMetadataStar(})
+ listener: beginMetadataStar(void)
+ listener: endMetadataStar(0)
+ parseTopLevelMemberImpl(})
+ listener: beginTopLevelMember(void)
+ parseTopLevelMethod(}, null, null, }, VoidType(), null, toplevel_method1, false)
+ listener: beginTopLevelMethod(}, null, null)
+ listener: handleVoidKeyword(void)
+ ensureIdentifierPotentiallyRecovered(void, topLevelFunctionDeclaration, false)
+ listener: handleIdentifier(toplevel_method1, topLevelFunctionDeclaration)
+ parseMethodTypeVar(toplevel_method1)
+ listener: handleNoTypeVariables(()
+ parseGetterOrFormalParameters(toplevel_method1, toplevel_method1, false, MemberKind.TopLevelMethod)
+ parseFormalParameters(toplevel_method1, MemberKind.TopLevelMethod)
+ parseFormalParametersRest((, MemberKind.TopLevelMethod)
+ listener: beginFormalParameters((, MemberKind.TopLevelMethod)
+ listener: endFormalParameters(0, (, ), MemberKind.TopLevelMethod)
+ parseAsyncModifierOpt())
+ listener: handleAsyncModifier(null, null)
+ inPlainSync()
+ parseFunctionBody(), false, false)
+ listener: beginBlockFunctionBody({)
+ notEofOrValue(}, })
+ listener: endBlockFunctionBody(0, {, })
+ listener: endTopLevelMethod(void, null, })
+ listener: endTopLevelDeclaration(})
+ parseTopLevelDeclarationImpl(}, DirectiveContext(DirectiveState.Declarations))
+ parseMetadataStar(})
+ listener: beginMetadataStar(void)
+ listener: endMetadataStar(0)
+ parseTopLevelMemberImpl(})
+ listener: beginTopLevelMember(void)
+ parseTopLevelMethod(}, null, null, }, VoidType(), null, toplevel_method2, false)
+ listener: beginTopLevelMethod(}, null, null)
+ listener: handleVoidKeyword(void)
+ ensureIdentifierPotentiallyRecovered(void, topLevelFunctionDeclaration, false)
+ listener: handleIdentifier(toplevel_method2, topLevelFunctionDeclaration)
+ parseMethodTypeVar(toplevel_method2)
+ listener: handleNoTypeVariables(()
+ parseGetterOrFormalParameters(toplevel_method2, toplevel_method2, false, MemberKind.TopLevelMethod)
+ parseFormalParameters(toplevel_method2, MemberKind.TopLevelMethod)
+ parseFormalParametersRest((, MemberKind.TopLevelMethod)
+ listener: beginFormalParameters((, MemberKind.TopLevelMethod)
+ listener: endFormalParameters(0, (, ), MemberKind.TopLevelMethod)
+ parseAsyncModifierOpt())
+ listener: handleAsyncModifier(null, null)
+ inPlainSync()
+ parseFunctionBody(), false, false)
+ listener: beginBlockFunctionBody({)
+ notEofOrValue(}, })
+ listener: endBlockFunctionBody(0, {, })
+ listener: endTopLevelMethod(void, null, })
+ listener: endTopLevelDeclaration(})
+ reportAllErrorTokens(UnmatchedToken({))
+ listener: handleErrorToken(UnmatchedToken({))
+ listener: handleRecoverableError(Message[UnmatchedToken, Can't find '}' to match '{'., null, {string: }, lexeme: {}], UnmatchedToken({), UnmatchedToken({))
+ listener: endCompilationUnit(3, )
diff --git a/pkg/front_end/parser_testcases/error_recovery/with_outline/typing_15.dart.outline.expect b/pkg/front_end/parser_testcases/error_recovery/with_outline/typing_15.dart.outline.expect
new file mode 100644
index 0000000..96af17b
--- /dev/null
+++ b/pkg/front_end/parser_testcases/error_recovery/with_outline/typing_15.dart.outline.expect
@@ -0,0 +1,5 @@
+Class: Foo
+Class method: Foo.foo_method1
+Class method: Foo.foo_method2
+Top-level method: toplevel_method1
+Top-level method: toplevel_method2
diff --git a/pkg/front_end/parser_testcases/error_recovery/with_outline/typing_15.dart.parser.expect b/pkg/front_end/parser_testcases/error_recovery/with_outline/typing_15.dart.parser.expect
new file mode 100644
index 0000000..303ff3b
--- /dev/null
+++ b/pkg/front_end/parser_testcases/error_recovery/with_outline/typing_15.dart.parser.expect
@@ -0,0 +1,49 @@
+class Foo {
+void foo_method1(dynamic input) {
+if (1 + 1 == 2) {
+
+}}
+
+void foo_method2() {
+if (1 + 1 == 2 &&
+1 + 1 == 2 &&
+1 + 1 == 2 &&
+1 + 1 == 2 &&
+1 + 1 == 2 &&
+1 + 1 == 2) {}
+}
+}
+
+void toplevel_method1() {
+
+}
+
+void toplevel_method2() {
+
+}
+
+
+[UnmatchedToken]class[KeywordToken] Foo[StringToken] {[BeginToken]
+void[KeywordToken] foo_method1[StringToken]([BeginToken]dynamic[KeywordToken] input[StringToken])[SimpleToken] {[BeginToken]
+if[KeywordToken] ([BeginToken]1[StringToken] +[SimpleToken] 1[StringToken] ==[SimpleToken] 2[StringToken])[SimpleToken] {[BeginToken]
+
+}[SyntheticToken]}[SimpleToken]
+
+void[KeywordToken] foo_method2[StringToken]([BeginToken])[SimpleToken] {[BeginToken]
+if[KeywordToken] ([BeginToken]1[StringToken] +[SimpleToken] 1[StringToken] ==[SimpleToken] 2[StringToken] &&[SimpleToken]
+1[StringToken] +[SimpleToken] 1[StringToken] ==[SimpleToken] 2[StringToken] &&[SimpleToken]
+1[StringToken] +[SimpleToken] 1[StringToken] ==[SimpleToken] 2[StringToken] &&[SimpleToken]
+1[StringToken] +[SimpleToken] 1[StringToken] ==[SimpleToken] 2[StringToken] &&[SimpleToken]
+1[StringToken] +[SimpleToken] 1[StringToken] ==[SimpleToken] 2[StringToken] &&[SimpleToken]
+1[StringToken] +[SimpleToken] 1[StringToken] ==[SimpleToken] 2[StringToken])[SimpleToken] {[BeginToken]}[SimpleToken]
+}[SimpleToken]
+}[SimpleToken]
+
+void[KeywordToken] toplevel_method1[StringToken]([BeginToken])[SimpleToken] {[BeginToken]
+
+}[SimpleToken]
+
+void[KeywordToken] toplevel_method2[StringToken]([BeginToken])[SimpleToken] {[BeginToken]
+
+}[SimpleToken]
+[SimpleToken]
diff --git a/pkg/front_end/parser_testcases/error_recovery/with_outline/typing_15.dart.scanner.expect b/pkg/front_end/parser_testcases/error_recovery/with_outline/typing_15.dart.scanner.expect
new file mode 100644
index 0000000..303ff3b
--- /dev/null
+++ b/pkg/front_end/parser_testcases/error_recovery/with_outline/typing_15.dart.scanner.expect
@@ -0,0 +1,49 @@
+class Foo {
+void foo_method1(dynamic input) {
+if (1 + 1 == 2) {
+
+}}
+
+void foo_method2() {
+if (1 + 1 == 2 &&
+1 + 1 == 2 &&
+1 + 1 == 2 &&
+1 + 1 == 2 &&
+1 + 1 == 2 &&
+1 + 1 == 2) {}
+}
+}
+
+void toplevel_method1() {
+
+}
+
+void toplevel_method2() {
+
+}
+
+
+[UnmatchedToken]class[KeywordToken] Foo[StringToken] {[BeginToken]
+void[KeywordToken] foo_method1[StringToken]([BeginToken]dynamic[KeywordToken] input[StringToken])[SimpleToken] {[BeginToken]
+if[KeywordToken] ([BeginToken]1[StringToken] +[SimpleToken] 1[StringToken] ==[SimpleToken] 2[StringToken])[SimpleToken] {[BeginToken]
+
+}[SyntheticToken]}[SimpleToken]
+
+void[KeywordToken] foo_method2[StringToken]([BeginToken])[SimpleToken] {[BeginToken]
+if[KeywordToken] ([BeginToken]1[StringToken] +[SimpleToken] 1[StringToken] ==[SimpleToken] 2[StringToken] &&[SimpleToken]
+1[StringToken] +[SimpleToken] 1[StringToken] ==[SimpleToken] 2[StringToken] &&[SimpleToken]
+1[StringToken] +[SimpleToken] 1[StringToken] ==[SimpleToken] 2[StringToken] &&[SimpleToken]
+1[StringToken] +[SimpleToken] 1[StringToken] ==[SimpleToken] 2[StringToken] &&[SimpleToken]
+1[StringToken] +[SimpleToken] 1[StringToken] ==[SimpleToken] 2[StringToken] &&[SimpleToken]
+1[StringToken] +[SimpleToken] 1[StringToken] ==[SimpleToken] 2[StringToken])[SimpleToken] {[BeginToken]}[SimpleToken]
+}[SimpleToken]
+}[SimpleToken]
+
+void[KeywordToken] toplevel_method1[StringToken]([BeginToken])[SimpleToken] {[BeginToken]
+
+}[SimpleToken]
+
+void[KeywordToken] toplevel_method2[StringToken]([BeginToken])[SimpleToken] {[BeginToken]
+
+}[SimpleToken]
+[SimpleToken]