Skip to content

Commit 4e4c823

Browse files
authored
Correct incomplete record parsing (#51610)
1 parent 81db970 commit 4e4c823

File tree

4 files changed

+69
-2
lines changed

4 files changed

+69
-2
lines changed

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2218,8 +2218,6 @@ private MemberDeclarationSyntax ParseMemberDeclarationOrStatementCore(SyntaxKind
22182218
token = this.AddError(token, ErrorCode.ERR_MemberNeedsType);
22192219
var voidType = _syntaxFactory.PredefinedType(token);
22202220

2221-
var identifier = this.EatToken();
2222-
22232221
if (!IsScript)
22242222
{
22252223
if (tryParseLocalDeclarationStatementFromStartPoint<LocalFunctionStatementSyntax>(attributes, ref afterAttributesPoint, out result))
@@ -2229,6 +2227,7 @@ private MemberDeclarationSyntax ParseMemberDeclarationOrStatementCore(SyntaxKind
22292227
}
22302228
else
22312229
{
2230+
var identifier = this.EatToken();
22322231
return this.ParseMethodDeclaration(attributes, modifiers, voidType, explicitInterfaceOpt: null, identifier: identifier, typeParameterList: null);
22332232
}
22342233
}

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

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28371,5 +28371,27 @@ public static class IsExternalInit
2837128371
</member>
2837228372
", constructor.GetDocumentationCommentXml());
2837328373
}
28374+
28375+
[Fact, WorkItem(51590, "https://github.com/dotnet/roslyn/issues/51590")]
28376+
public void SealedIncomplete()
28377+
{
28378+
var source = @"
28379+
public sealed record(";
28380+
var comp = CreateCompilation(source);
28381+
comp.VerifyDiagnostics(
28382+
// (2,21): error CS1001: Identifier expected
28383+
// public sealed record(
28384+
Diagnostic(ErrorCode.ERR_IdentifierExpected, "(").WithLocation(2, 21),
28385+
// (2,22): error CS1026: ) expected
28386+
// public sealed record(
28387+
Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(2, 22),
28388+
// (2,22): error CS1514: { expected
28389+
// public sealed record(
28390+
Diagnostic(ErrorCode.ERR_LbraceExpected, "").WithLocation(2, 22),
28391+
// (2,22): error CS1513: } expected
28392+
// public sealed record(
28393+
Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(2, 22)
28394+
);
28395+
}
2837428396
}
2837528397
}

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

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,13 @@
33
// See the LICENSE file in the project root for more information.
44

55
using System.Collections.Generic;
6+
using System.Collections.Immutable;
67
using System.Diagnostics;
78
using System.Linq;
9+
using System.Text;
810
using Microsoft.CodeAnalysis.CSharp.Syntax;
911
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
12+
using Microsoft.CodeAnalysis.PooledObjects;
1013
using Microsoft.CodeAnalysis.Test.Utilities;
1114
using Xunit;
1215
using Xunit.Abstractions;
@@ -319,5 +322,42 @@ private void Done(bool dump)
319322
_output.WriteLine("EOF();");
320323
}
321324
}
325+
326+
protected static void ParseIncompleteSyntax(string text)
327+
{
328+
var tokens = getLexedTokens(text);
329+
330+
var stringBuilder = new StringBuilder();
331+
for (int skip = 0; skip < tokens.Length; skip++)
332+
{
333+
stringBuilder.Clear();
334+
335+
for (int i = 0; i < tokens.Length; i++)
336+
{
337+
if (i == skip)
338+
{
339+
continue;
340+
}
341+
stringBuilder.Append(tokens[i].Text);
342+
stringBuilder.Append(' ');
343+
344+
// Verify that we can parse and round-trip
345+
_ = SyntaxFactory.ParseSyntaxTree(stringBuilder.ToString(), TestOptions.RegularPreview);
346+
}
347+
}
348+
349+
static ImmutableArray<Syntax.InternalSyntax.SyntaxToken> getLexedTokens(string text)
350+
{
351+
var lexer = new Syntax.InternalSyntax.Lexer(Text.SourceText.From(text), CSharpParseOptions.Default);
352+
var tokensBuilder = ArrayBuilder<Syntax.InternalSyntax.SyntaxToken>.GetInstance();
353+
354+
while (lexer.Lex(Syntax.InternalSyntax.LexerMode.Syntax) is var token && token.Kind != SyntaxKind.EndOfFileToken)
355+
{
356+
tokensBuilder.Add(token);
357+
}
358+
359+
return tokensBuilder.ToImmutableAndFree();
360+
}
361+
}
322362
}
323363
}

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2608,5 +2608,11 @@ public void Base_05()
26082608
}
26092609
EOF();
26102610
}
2611+
2612+
[Fact, WorkItem(51590, "https://github.com/dotnet/roslyn/issues/51590")]
2613+
public void ParseIncompleteRecordSyntax()
2614+
{
2615+
ParseIncompleteSyntax("public sealed record C() { }");
2616+
}
26112617
}
26122618
}

0 commit comments

Comments
 (0)