提交 f081705e 编写于 作者: A Andy Gocke 提交者: GitHub

Fix infinite loop in parsing local functions (#13010)

The original intent of #12056 was to improve parsing recovery in the
cast of a leading accessibility modifier on a local function. However, I
mistakenly allowed for recovery for an accessibility modifier *anywhere*
in the modifier list of the local function.

This is a mistake because it significantly complicates parsing back-out.
While it's easy to recognize that the local function parsing failed and
skip any leading accessibility modifiers, it's significantly more
complicated to find and skip all accessibility modifiers anywhere in a
sequence of modifiers.

This PR changes the parsing backout to only consider accessibility
modifiers at the start of statements. Any other case will be treated
like other bad modifiers in local functions -- they will be marked as
errors in the declaration list. Fixes #12947.
上级 3cd09376
......@@ -8312,17 +8312,18 @@ private StatementSyntax ParseLocalDeclarationStatement()
return localFunction;
}
// If we find an accessibility modifier but no local function it's likely
// the user forgot a closing brace. Let's back out of statement parsing.
if (mods.Count > 0 &&
IsAccessibilityModifier(((SyntaxToken)mods[0]).ContextualKind))
{
return null;
}
for (int i = 0; i < mods.Count; i++)
{
var mod = (SyntaxToken)mods[i];
// If we find an accessibility modifier but no local function it's likely
// the user forgot a closing brace. Let's back out of statement parsing.
if (IsAccessibilityModifier(mod.ContextualKind))
{
return null;
}
if (IsAdditionalLocalFunctionModifier(mod.ContextualKind))
{
mods[i] = this.AddError(mod, ErrorCode.ERR_BadMemberFlag, mod.Text);
......
......@@ -13,6 +13,57 @@ public class LocalFunctionParsingTests : ParsingTests
{
internal static readonly CSharpParseOptions LocalFuncOptions = TestOptions.Regular.WithLocalFunctionsFeature();
[Fact]
public void NeverEndingTest()
{
var file = ParseFile(@"public class C {
public void M() {
async public virtual M() {}
unsafe public M() {}
async override M() {}
unsafe private async override M() {}
async virtual override sealed M() {}
}
}");
file.SyntaxTree.GetDiagnostics().Verify(
// (3,9): error CS0106: The modifier 'async' is not valid for this item
// async public virtual M() {}
Diagnostic(ErrorCode.ERR_BadMemberFlag, "async").WithArguments("async").WithLocation(3, 9),
// (3,15): error CS0106: The modifier 'public' is not valid for this item
// async public virtual M() {}
Diagnostic(ErrorCode.ERR_BadMemberFlag, "public").WithArguments("public").WithLocation(3, 15),
// (3,22): error CS1031: Type expected
// async public virtual M() {}
Diagnostic(ErrorCode.ERR_TypeExpected, "virtual").WithLocation(3, 22),
// (3,22): error CS1001: Identifier expected
// async public virtual M() {}
Diagnostic(ErrorCode.ERR_IdentifierExpected, "virtual").WithLocation(3, 22),
// (3,22): error CS1002: ; expected
// async public virtual M() {}
Diagnostic(ErrorCode.ERR_SemicolonExpected, "virtual").WithLocation(3, 22),
// (3,22): error CS1513: } expected
// async public virtual M() {}
Diagnostic(ErrorCode.ERR_RbraceExpected, "virtual").WithLocation(3, 22),
// (3,30): error CS1520: Method must have a return type
// async public virtual M() {}
Diagnostic(ErrorCode.ERR_MemberNeedsType, "M").WithLocation(3, 30),
// (4,23): error CS1520: Method must have a return type
// unsafe public M() {}
Diagnostic(ErrorCode.ERR_MemberNeedsType, "M").WithLocation(4, 23),
// (5,24): error CS1520: Method must have a return type
// async override M() {}
Diagnostic(ErrorCode.ERR_MemberNeedsType, "M").WithLocation(5, 24),
// (6,39): error CS1520: Method must have a return type
// unsafe private async override M() {}
Diagnostic(ErrorCode.ERR_MemberNeedsType, "M").WithLocation(6, 39),
// (7,39): error CS1520: Method must have a return type
// async virtual override sealed M() {}
Diagnostic(ErrorCode.ERR_MemberNeedsType, "M").WithLocation(7, 39),
// (9,1): error CS1022: Type or namespace definition, or end-of-file expected
// }
Diagnostic(ErrorCode.ERR_EOFExpected, "}").WithLocation(9, 1));
}
[Fact]
public void DiagnosticsWithoutExperimental()
{
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册