Skip to content

Commit cad93d5

Browse files
authored
Fix parsing bug in invalid using statements (#36428)
1 parent 62c9a74 commit cad93d5

File tree

3 files changed

+67
-2
lines changed

3 files changed

+67
-2
lines changed

src/Compilers/CSharp/Portable/Parser/LanguageParser.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8278,6 +8278,7 @@ private StatementSyntax ParseLocalDeclarationStatement(SyntaxToken awaitKeywordO
82788278
{
82798279
usingKeyword = CheckFeatureAvailability(usingKeyword, MessageID.IDS_FeatureUsingDeclarations);
82808280
}
8281+
bool canParseAsLocalFunction = usingKeyword == default;
82818282

82828283
var mods = _pool.Allocate();
82838284
this.ParseDeclarationModifiers(mods);
@@ -8288,7 +8289,7 @@ private StatementSyntax ParseLocalDeclarationStatement(SyntaxToken awaitKeywordO
82888289
TypeSyntax type;
82898290
LocalFunctionStatementSyntax localFunction;
82908291
this.ParseLocalDeclaration(variables,
8291-
allowLocalFunctions: usingKeyword == default,
8292+
allowLocalFunctions: canParseAsLocalFunction,
82928293
mods: mods.ToList(),
82938294
type: out type,
82948295
localFunction: out localFunction);
@@ -8301,7 +8302,8 @@ private StatementSyntax ParseLocalDeclarationStatement(SyntaxToken awaitKeywordO
83018302

83028303
// If we find an accessibility modifier but no local function it's likely
83038304
// the user forgot a closing brace. Let's back out of statement parsing.
8304-
if (mods.Count > 0 &&
8305+
if (canParseAsLocalFunction &&
8306+
mods.Count > 0 &&
83058307
IsAccessibilityModifier(((SyntaxToken)mods[0]).ContextualKind))
83068308
{
83078309
return null;

src/Compilers/CSharp/Test/Semantic/Semantics/UsingDeclarationTests.cs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
44
using Microsoft.CodeAnalysis.CSharp.UnitTests;
5+
using Roslyn.Test.Utilities;
56
using Xunit;
67

78
namespace Microsoft.CodeAnalysis.CSharp.Semantic.UnitTests.Semantics
@@ -769,5 +770,29 @@ static void Main()
769770
Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "using S3 S3 = new S3();").WithArguments("S3.Dispose()").WithLocation(40, 9)
770771
);
771772
}
773+
774+
[Fact]
775+
[WorkItem(36413, "https://github.com/dotnet/roslyn/issues/36413")]
776+
public void UsingDeclarationsWithInvalidModifiers()
777+
{
778+
var source = @"
779+
using System;
780+
class C
781+
{
782+
static void Main()
783+
{
784+
using public readonly var x = (IDisposable)null;
785+
}
786+
}
787+
";
788+
CreateCompilation(source, parseOptions: TestOptions.RegularPreview).VerifyDiagnostics(
789+
// (7,15): error CS0106: The modifier 'public' is not valid for this item
790+
// using public readonly var x = (IDisposable)null;
791+
Diagnostic(ErrorCode.ERR_BadMemberFlag, "public").WithArguments("public").WithLocation(7, 15),
792+
// (7,22): error CS0106: The modifier 'readonly' is not valid for this item
793+
// using public readonly var x = (IDisposable)null;
794+
Diagnostic(ErrorCode.ERR_BadMemberFlag, "readonly").WithArguments("readonly").WithLocation(7, 22)
795+
);
796+
}
772797
}
773798
}

src/Compilers/CSharp/Test/Syntax/Parsing/StatementParsingTests.cs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2508,6 +2508,44 @@ public void TestUsingVarWithVarDeclaration()
25082508
Assert.Equal("b", us.Declaration.Variables[0].Initializer.Value.ToString());
25092509
}
25102510

2511+
[Fact]
2512+
[WorkItem(36413, "https://github.com/dotnet/roslyn/issues/36413")]
2513+
public void TestUsingVarWithInvalidDeclaration()
2514+
{
2515+
var text = "using public readonly var a = b;";
2516+
var statement = this.ParseStatement(text, options: TestOptions.Regular8);
2517+
2518+
Assert.NotNull(statement);
2519+
Assert.Equal(SyntaxKind.LocalDeclarationStatement, statement.Kind());
2520+
Assert.Equal(text, statement.ToString());
2521+
Assert.Equal(2, statement.Errors().Length);
2522+
Assert.Equal((int)ErrorCode.ERR_BadMemberFlag, statement.Errors()[0].Code);
2523+
Assert.Equal("public", statement.Errors()[0].Arguments[0]);
2524+
Assert.Equal((int)ErrorCode.ERR_BadMemberFlag, statement.Errors()[1].Code);
2525+
Assert.Equal("readonly", statement.Errors()[1].Arguments[0]);
2526+
2527+
var us = (LocalDeclarationStatementSyntax)statement;
2528+
Assert.NotNull(us.UsingKeyword);
2529+
Assert.Equal(SyntaxKind.UsingKeyword, us.UsingKeyword.Kind());
2530+
2531+
Assert.NotNull(us.Declaration);
2532+
Assert.NotNull(us.Declaration.Type);
2533+
Assert.Equal("var", us.Declaration.Type.ToString());
2534+
Assert.Equal(SyntaxKind.IdentifierName, us.Declaration.Type.Kind());
2535+
Assert.Equal(SyntaxKind.IdentifierToken, ((IdentifierNameSyntax)us.Declaration.Type).Identifier.Kind());
2536+
Assert.Equal(2, us.Modifiers.Count);
2537+
Assert.Equal("public", us.Modifiers[0].ToString());
2538+
Assert.Equal("readonly", us.Modifiers[1].ToString());
2539+
Assert.Equal(1, us.Declaration.Variables.Count);
2540+
Assert.NotNull(us.Declaration.Variables[0].Identifier);
2541+
Assert.Equal("a", us.Declaration.Variables[0].Identifier.ToString());
2542+
Assert.Null(us.Declaration.Variables[0].ArgumentList);
2543+
Assert.NotNull(us.Declaration.Variables[0].Initializer);
2544+
Assert.NotNull(us.Declaration.Variables[0].Initializer.EqualsToken);
2545+
Assert.NotNull(us.Declaration.Variables[0].Initializer.Value);
2546+
Assert.Equal("b", us.Declaration.Variables[0].Initializer.Value.ToString());
2547+
}
2548+
25112549
[Fact]
25122550
public void TestUsingVarWithVarDeclarationTree()
25132551
{

0 commit comments

Comments
 (0)