diff --git a/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs b/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs index 830d75daae40f..007aab4bc1859 100644 --- a/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs +++ b/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs @@ -1040,6 +1040,7 @@ private AttributeSyntax ParseAttribute() SyntaxKind.CloseParenToken, static @this => @this.IsPossibleAttributeArgument(), static @this => @this.ParseAttributeArgument(), + immediatelyAbort, skipBadAttributeArgumentTokens, allowTrailingSeparator: false, requireOneElement: false, @@ -1058,6 +1059,23 @@ static PostSkipAction skipBadAttributeArgumentTokens( static (p, closeKind) => p.CurrentToken.Kind == closeKind, expectedKind, closeKind); } + + static bool immediatelyAbort(AttributeArgumentSyntax argument) + { + // We can be very thrown off by incomplete strings in an attribute argument (especially as the lexer + // will restart on the next line with the contents of the string then being interpreted as more + // arguments). Bail out in this case to prevent going off the rails. + if (argument.expression is LiteralExpressionSyntax { Kind: SyntaxKind.StringLiteralExpression, Token: var literalToken } && + literalToken.GetDiagnostics().Contains(d => d.Code == (int)ErrorCode.ERR_NewlineInConst)) + { + return true; + } + + if (argument.expression is InterpolatedStringExpressionSyntax { StringStartToken.Kind: SyntaxKind.InterpolatedStringStartToken, StringEndToken.IsMissing: true }) + return true; + + return false; + } } private bool IsPossibleAttributeArgument() @@ -13321,6 +13339,8 @@ private bool IsInQuery private delegate PostSkipAction SkipBadTokens( LanguageParser parser, ref SyntaxToken openToken, SeparatedSyntaxListBuilder builder, SyntaxKind expectedKind, SyntaxKind closeTokenKind) where TNode : GreenNode; +#nullable enable + /// /// Parses a comma separated list of nodes. /// @@ -13357,6 +13377,29 @@ private SeparatedSyntaxList ParseCommaSeparatedSyntaxList( bool allowTrailingSeparator, bool requireOneElement, bool allowSemicolonAsSeparator) where TNode : GreenNode + { + return ParseCommaSeparatedSyntaxList( + ref openToken, + closeTokenKind, + isPossibleElement, + parseElement, + immediatelyAbort: null, + skipBadTokens, + allowTrailingSeparator, + requireOneElement, + allowSemicolonAsSeparator); + } + + private SeparatedSyntaxList ParseCommaSeparatedSyntaxList( + ref SyntaxToken openToken, + SyntaxKind closeTokenKind, + Func isPossibleElement, + Func parseElement, + Func? immediatelyAbort, + SkipBadTokens skipBadTokens, + bool allowTrailingSeparator, + bool requireOneElement, + bool allowSemicolonAsSeparator) where TNode : GreenNode { // If we ever want this function to parse out separated lists with a different separator, we can // parameterize this method on this value. @@ -13369,7 +13412,8 @@ private SeparatedSyntaxList ParseCommaSeparatedSyntaxList( if (requireOneElement || shouldParseSeparatorOrElement()) { // first argument - nodes.Add(parseElement(this)); + var node = parseElement(this); + nodes.Add(node); // now that we've gotten one element, we don't require any more. requireOneElement = false; @@ -13377,7 +13421,8 @@ private SeparatedSyntaxList ParseCommaSeparatedSyntaxList( // Ensure that if parsing separators/elements doesn't move us forward, that we always bail out from // parsing this list. int lastTokenPosition = -1; - while (IsMakingProgress(ref lastTokenPosition)) + + while (immediatelyAbort?.Invoke(node) != true && IsMakingProgress(ref lastTokenPosition)) { if (this.CurrentToken.Kind == closeTokenKind) break; @@ -13402,7 +13447,8 @@ private SeparatedSyntaxList ParseCommaSeparatedSyntaxList( } } - nodes.Add(parseElement(this)); + node = parseElement(this); + nodes.Add(node); continue; } @@ -13441,6 +13487,8 @@ bool shouldParseSeparatorOrElement() } } +#nullable disable + private DisposableResetPoint GetDisposableResetPoint(bool resetOnDispose) => new DisposableResetPoint(this, resetOnDispose, GetResetPoint()); diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/CollectionExpressionParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/CollectionExpressionParsingTests.cs index 75cde7ce70fbc..5eed36571065c 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/CollectionExpressionParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/CollectionExpressionParsingTests.cs @@ -17128,4 +17128,988 @@ public void CollectionExpressionParsingSlotCounts([CombinatorialRange(1, 20)] in N(SyntaxKind.CloseBracketToken); EOF(); } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/72557")] + public void TestIncompleteString1() + { + UsingTree(""" + public enum BundleType + { + [A("B", "C"), Description("Goo + bar baz")] + A, + [A("B", "C"), Description("Goo + bar baz")] + B, + } + """, + // (3,31): error CS1010: Newline in constant + // [A("B", "C"), Description("Goo + Diagnostic(ErrorCode.ERR_NewlineInConst, "").WithLocation(3, 31), + // (3,35): error CS1026: ) expected + // [A("B", "C"), Description("Goo + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(3, 35), + // (3,35): error CS1003: Syntax error, ',' expected + // [A("B", "C"), Description("Goo + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(",").WithLocation(3, 35), + // (4,9): error CS1003: Syntax error, ',' expected + // bar baz")] + Diagnostic(ErrorCode.ERR_SyntaxError, "baz").WithArguments(",").WithLocation(4, 9), + // (4,12): error CS1010: Newline in constant + // bar baz")] + Diagnostic(ErrorCode.ERR_NewlineInConst, "").WithLocation(4, 12), + // (4,15): error CS1003: Syntax error, ',' expected + // bar baz")] + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(",").WithLocation(4, 15), + // (5,7): error CS1003: Syntax error, ']' expected + // A, + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("]").WithLocation(5, 7), + // (6,31): error CS1010: Newline in constant + // [A("B", "C"), Description("Goo + Diagnostic(ErrorCode.ERR_NewlineInConst, "").WithLocation(6, 31), + // (6,35): error CS1026: ) expected + // [A("B", "C"), Description("Goo + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(6, 35), + // (6,35): error CS1003: Syntax error, ',' expected + // [A("B", "C"), Description("Goo + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(",").WithLocation(6, 35), + // (7,9): error CS1003: Syntax error, ',' expected + // bar baz")] + Diagnostic(ErrorCode.ERR_SyntaxError, "baz").WithArguments(",").WithLocation(7, 9), + // (7,12): error CS1010: Newline in constant + // bar baz")] + Diagnostic(ErrorCode.ERR_NewlineInConst, "").WithLocation(7, 12), + // (7,15): error CS1003: Syntax error, ',' expected + // bar baz")] + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(",").WithLocation(7, 15), + // (8,7): error CS1003: Syntax error, ']' expected + // B, + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("]").WithLocation(8, 7), + // (8,7): error CS1001: Identifier expected + // B, + Diagnostic(ErrorCode.ERR_IdentifierExpected, "").WithLocation(8, 7)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.EnumDeclaration); + { + N(SyntaxKind.PublicKeyword); + N(SyntaxKind.EnumKeyword); + N(SyntaxKind.IdentifierToken, "BundleType"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.EnumMemberDeclaration); + { + N(SyntaxKind.AttributeList); + { + N(SyntaxKind.OpenBracketToken); + N(SyntaxKind.Attribute); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "A"); + } + N(SyntaxKind.AttributeArgumentList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.AttributeArgument); + { + N(SyntaxKind.StringLiteralExpression); + { + N(SyntaxKind.StringLiteralToken, "\"B\""); + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.AttributeArgument); + { + N(SyntaxKind.StringLiteralExpression); + { + N(SyntaxKind.StringLiteralToken, "\"C\""); + } + } + N(SyntaxKind.CloseParenToken); + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.Attribute); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Description"); + } + N(SyntaxKind.AttributeArgumentList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.AttributeArgument); + { + N(SyntaxKind.StringLiteralExpression); + { + N(SyntaxKind.StringLiteralToken, "\"Goo"); + } + } + M(SyntaxKind.CloseParenToken); + } + } + M(SyntaxKind.CommaToken); + N(SyntaxKind.Attribute); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "bar"); + } + } + M(SyntaxKind.CommaToken); + N(SyntaxKind.Attribute); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "baz"); + } + } + M(SyntaxKind.CommaToken); + N(SyntaxKind.Attribute); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "A"); + } + } + N(SyntaxKind.CommaToken); + M(SyntaxKind.CloseBracketToken); + } + N(SyntaxKind.AttributeList); + { + N(SyntaxKind.OpenBracketToken); + N(SyntaxKind.Attribute); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "A"); + } + N(SyntaxKind.AttributeArgumentList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.AttributeArgument); + { + N(SyntaxKind.StringLiteralExpression); + { + N(SyntaxKind.StringLiteralToken, "\"B\""); + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.AttributeArgument); + { + N(SyntaxKind.StringLiteralExpression); + { + N(SyntaxKind.StringLiteralToken, "\"C\""); + } + } + N(SyntaxKind.CloseParenToken); + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.Attribute); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Description"); + } + N(SyntaxKind.AttributeArgumentList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.AttributeArgument); + { + N(SyntaxKind.StringLiteralExpression); + { + N(SyntaxKind.StringLiteralToken, "\"Goo"); + } + } + M(SyntaxKind.CloseParenToken); + } + } + M(SyntaxKind.CommaToken); + N(SyntaxKind.Attribute); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "bar"); + } + } + M(SyntaxKind.CommaToken); + N(SyntaxKind.Attribute); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "baz"); + } + } + M(SyntaxKind.CommaToken); + N(SyntaxKind.Attribute); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "B"); + } + } + N(SyntaxKind.CommaToken); + M(SyntaxKind.CloseBracketToken); + } + M(SyntaxKind.IdentifierToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/72557")] + public void TestIncompleteString2() + { + UsingTree(""" + public enum BundleType + { + [A("B", "C"), Description("X", "Goo + bar baz")] + A, + [A("B", "C"), Description("X", "Goo + bar baz")] + B, + } + """, + // (3,36): error CS1010: Newline in constant + // [A("B", "C"), Description("X", "Goo + Diagnostic(ErrorCode.ERR_NewlineInConst, "").WithLocation(3, 36), + // (3,40): error CS1026: ) expected + // [A("B", "C"), Description("X", "Goo + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(3, 40), + // (3,40): error CS1003: Syntax error, ',' expected + // [A("B", "C"), Description("X", "Goo + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(",").WithLocation(3, 40), + // (4,9): error CS1003: Syntax error, ',' expected + // bar baz")] + Diagnostic(ErrorCode.ERR_SyntaxError, "baz").WithArguments(",").WithLocation(4, 9), + // (4,12): error CS1010: Newline in constant + // bar baz")] + Diagnostic(ErrorCode.ERR_NewlineInConst, "").WithLocation(4, 12), + // (4,15): error CS1003: Syntax error, ',' expected + // bar baz")] + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(",").WithLocation(4, 15), + // (5,7): error CS1003: Syntax error, ']' expected + // A, + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("]").WithLocation(5, 7), + // (6,36): error CS1010: Newline in constant + // [A("B", "C"), Description("X", "Goo + Diagnostic(ErrorCode.ERR_NewlineInConst, "").WithLocation(6, 36), + // (6,40): error CS1026: ) expected + // [A("B", "C"), Description("X", "Goo + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(6, 40), + // (6,40): error CS1003: Syntax error, ',' expected + // [A("B", "C"), Description("X", "Goo + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(",").WithLocation(6, 40), + // (7,9): error CS1003: Syntax error, ',' expected + // bar baz")] + Diagnostic(ErrorCode.ERR_SyntaxError, "baz").WithArguments(",").WithLocation(7, 9), + // (7,12): error CS1010: Newline in constant + // bar baz")] + Diagnostic(ErrorCode.ERR_NewlineInConst, "").WithLocation(7, 12), + // (7,15): error CS1003: Syntax error, ',' expected + // bar baz")] + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(",").WithLocation(7, 15), + // (8,7): error CS1003: Syntax error, ']' expected + // B, + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("]").WithLocation(8, 7), + // (8,7): error CS1001: Identifier expected + // B, + Diagnostic(ErrorCode.ERR_IdentifierExpected, "").WithLocation(8, 7)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.EnumDeclaration); + { + N(SyntaxKind.PublicKeyword); + N(SyntaxKind.EnumKeyword); + N(SyntaxKind.IdentifierToken, "BundleType"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.EnumMemberDeclaration); + { + N(SyntaxKind.AttributeList); + { + N(SyntaxKind.OpenBracketToken); + N(SyntaxKind.Attribute); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "A"); + } + N(SyntaxKind.AttributeArgumentList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.AttributeArgument); + { + N(SyntaxKind.StringLiteralExpression); + { + N(SyntaxKind.StringLiteralToken, "\"B\""); + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.AttributeArgument); + { + N(SyntaxKind.StringLiteralExpression); + { + N(SyntaxKind.StringLiteralToken, "\"C\""); + } + } + N(SyntaxKind.CloseParenToken); + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.Attribute); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Description"); + } + N(SyntaxKind.AttributeArgumentList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.AttributeArgument); + { + N(SyntaxKind.StringLiteralExpression); + { + N(SyntaxKind.StringLiteralToken, "\"X\""); + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.AttributeArgument); + { + N(SyntaxKind.StringLiteralExpression); + { + N(SyntaxKind.StringLiteralToken, "\"Goo"); + } + } + M(SyntaxKind.CloseParenToken); + } + } + M(SyntaxKind.CommaToken); + N(SyntaxKind.Attribute); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "bar"); + } + } + M(SyntaxKind.CommaToken); + N(SyntaxKind.Attribute); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "baz"); + } + } + M(SyntaxKind.CommaToken); + N(SyntaxKind.Attribute); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "A"); + } + } + N(SyntaxKind.CommaToken); + M(SyntaxKind.CloseBracketToken); + } + N(SyntaxKind.AttributeList); + { + N(SyntaxKind.OpenBracketToken); + N(SyntaxKind.Attribute); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "A"); + } + N(SyntaxKind.AttributeArgumentList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.AttributeArgument); + { + N(SyntaxKind.StringLiteralExpression); + { + N(SyntaxKind.StringLiteralToken, "\"B\""); + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.AttributeArgument); + { + N(SyntaxKind.StringLiteralExpression); + { + N(SyntaxKind.StringLiteralToken, "\"C\""); + } + } + N(SyntaxKind.CloseParenToken); + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.Attribute); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Description"); + } + N(SyntaxKind.AttributeArgumentList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.AttributeArgument); + { + N(SyntaxKind.StringLiteralExpression); + { + N(SyntaxKind.StringLiteralToken, "\"X\""); + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.AttributeArgument); + { + N(SyntaxKind.StringLiteralExpression); + { + N(SyntaxKind.StringLiteralToken, "\"Goo"); + } + } + M(SyntaxKind.CloseParenToken); + } + } + M(SyntaxKind.CommaToken); + N(SyntaxKind.Attribute); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "bar"); + } + } + M(SyntaxKind.CommaToken); + N(SyntaxKind.Attribute); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "baz"); + } + } + M(SyntaxKind.CommaToken); + N(SyntaxKind.Attribute); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "B"); + } + } + N(SyntaxKind.CommaToken); + M(SyntaxKind.CloseBracketToken); + } + M(SyntaxKind.IdentifierToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/72557")] + public void TestIncompleteString3() + { + UsingTree(""" + public enum BundleType + { + [A("B", "C"), Description($"Goo + bar baz")] + A, + [A("B", "C"), Description($"Goo + bar baz")] + B, + } + """, + // (3,35): error CS1039: Unterminated string literal + // [A("B", "C"), Description($"Goo + Diagnostic(ErrorCode.ERR_UnterminatedStringLit, "o").WithLocation(3, 35), + // (3,36): error CS1026: ) expected + // [A("B", "C"), Description($"Goo + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(3, 36), + // (3,36): error CS1003: Syntax error, ',' expected + // [A("B", "C"), Description($"Goo + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(",").WithLocation(3, 36), + // (4,9): error CS1003: Syntax error, ',' expected + // bar baz")] + Diagnostic(ErrorCode.ERR_SyntaxError, "baz").WithArguments(",").WithLocation(4, 9), + // (4,12): error CS1010: Newline in constant + // bar baz")] + Diagnostic(ErrorCode.ERR_NewlineInConst, "").WithLocation(4, 12), + // (4,15): error CS1003: Syntax error, ',' expected + // bar baz")] + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(",").WithLocation(4, 15), + // (5,7): error CS1003: Syntax error, ']' expected + // A, + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("]").WithLocation(5, 7), + // (6,35): error CS1039: Unterminated string literal + // [A("B", "C"), Description($"Goo + Diagnostic(ErrorCode.ERR_UnterminatedStringLit, "o").WithLocation(6, 35), + // (6,36): error CS1026: ) expected + // [A("B", "C"), Description($"Goo + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(6, 36), + // (6,36): error CS1003: Syntax error, ',' expected + // [A("B", "C"), Description($"Goo + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(",").WithLocation(6, 36), + // (7,9): error CS1003: Syntax error, ',' expected + // bar baz")] + Diagnostic(ErrorCode.ERR_SyntaxError, "baz").WithArguments(",").WithLocation(7, 9), + // (7,12): error CS1010: Newline in constant + // bar baz")] + Diagnostic(ErrorCode.ERR_NewlineInConst, "").WithLocation(7, 12), + // (7,15): error CS1003: Syntax error, ',' expected + // bar baz")] + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(",").WithLocation(7, 15), + // (8,7): error CS1003: Syntax error, ']' expected + // B, + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("]").WithLocation(8, 7), + // (8,7): error CS1001: Identifier expected + // B, + Diagnostic(ErrorCode.ERR_IdentifierExpected, "").WithLocation(8, 7)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.EnumDeclaration); + { + N(SyntaxKind.PublicKeyword); + N(SyntaxKind.EnumKeyword); + N(SyntaxKind.IdentifierToken, "BundleType"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.EnumMemberDeclaration); + { + N(SyntaxKind.AttributeList); + { + N(SyntaxKind.OpenBracketToken); + N(SyntaxKind.Attribute); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "A"); + } + N(SyntaxKind.AttributeArgumentList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.AttributeArgument); + { + N(SyntaxKind.StringLiteralExpression); + { + N(SyntaxKind.StringLiteralToken, "\"B\""); + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.AttributeArgument); + { + N(SyntaxKind.StringLiteralExpression); + { + N(SyntaxKind.StringLiteralToken, "\"C\""); + } + } + N(SyntaxKind.CloseParenToken); + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.Attribute); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Description"); + } + N(SyntaxKind.AttributeArgumentList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.AttributeArgument); + { + N(SyntaxKind.InterpolatedStringExpression); + { + N(SyntaxKind.InterpolatedStringStartToken); + N(SyntaxKind.InterpolatedStringText); + { + N(SyntaxKind.InterpolatedStringTextToken); + } + M(SyntaxKind.InterpolatedStringEndToken); + } + } + M(SyntaxKind.CloseParenToken); + } + } + M(SyntaxKind.CommaToken); + N(SyntaxKind.Attribute); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "bar"); + } + } + M(SyntaxKind.CommaToken); + N(SyntaxKind.Attribute); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "baz"); + } + } + M(SyntaxKind.CommaToken); + N(SyntaxKind.Attribute); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "A"); + } + } + N(SyntaxKind.CommaToken); + M(SyntaxKind.CloseBracketToken); + } + N(SyntaxKind.AttributeList); + { + N(SyntaxKind.OpenBracketToken); + N(SyntaxKind.Attribute); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "A"); + } + N(SyntaxKind.AttributeArgumentList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.AttributeArgument); + { + N(SyntaxKind.StringLiteralExpression); + { + N(SyntaxKind.StringLiteralToken, "\"B\""); + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.AttributeArgument); + { + N(SyntaxKind.StringLiteralExpression); + { + N(SyntaxKind.StringLiteralToken, "\"C\""); + } + } + N(SyntaxKind.CloseParenToken); + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.Attribute); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Description"); + } + N(SyntaxKind.AttributeArgumentList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.AttributeArgument); + { + N(SyntaxKind.InterpolatedStringExpression); + { + N(SyntaxKind.InterpolatedStringStartToken); + N(SyntaxKind.InterpolatedStringText); + { + N(SyntaxKind.InterpolatedStringTextToken); + } + M(SyntaxKind.InterpolatedStringEndToken); + } + } + M(SyntaxKind.CloseParenToken); + } + } + M(SyntaxKind.CommaToken); + N(SyntaxKind.Attribute); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "bar"); + } + } + M(SyntaxKind.CommaToken); + N(SyntaxKind.Attribute); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "baz"); + } + } + M(SyntaxKind.CommaToken); + N(SyntaxKind.Attribute); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "B"); + } + } + N(SyntaxKind.CommaToken); + M(SyntaxKind.CloseBracketToken); + } + M(SyntaxKind.IdentifierToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/72557")] + public void TestIncompleteString4() + { + UsingTree(""" + public enum BundleType + { + [A("B", "C"), Description("X", $"Goo + bar baz")] + A, + [A("B", "C"), Description("X", $"Goo + bar baz")] + B, + } + """, + // (3,40): error CS1039: Unterminated string literal + // [A("B", "C"), Description("X", $"Goo + Diagnostic(ErrorCode.ERR_UnterminatedStringLit, "o").WithLocation(3, 40), + // (3,41): error CS1026: ) expected + // [A("B", "C"), Description("X", $"Goo + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(3, 41), + // (3,41): error CS1003: Syntax error, ',' expected + // [A("B", "C"), Description("X", $"Goo + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(",").WithLocation(3, 41), + // (4,9): error CS1003: Syntax error, ',' expected + // bar baz")] + Diagnostic(ErrorCode.ERR_SyntaxError, "baz").WithArguments(",").WithLocation(4, 9), + // (4,12): error CS1010: Newline in constant + // bar baz")] + Diagnostic(ErrorCode.ERR_NewlineInConst, "").WithLocation(4, 12), + // (4,15): error CS1003: Syntax error, ',' expected + // bar baz")] + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(",").WithLocation(4, 15), + // (5,7): error CS1003: Syntax error, ']' expected + // A, + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("]").WithLocation(5, 7), + // (6,40): error CS1039: Unterminated string literal + // [A("B", "C"), Description("X", $"Goo + Diagnostic(ErrorCode.ERR_UnterminatedStringLit, "o").WithLocation(6, 40), + // (6,41): error CS1026: ) expected + // [A("B", "C"), Description("X", $"Goo + Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(6, 41), + // (6,41): error CS1003: Syntax error, ',' expected + // [A("B", "C"), Description("X", $"Goo + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(",").WithLocation(6, 41), + // (7,9): error CS1003: Syntax error, ',' expected + // bar baz")] + Diagnostic(ErrorCode.ERR_SyntaxError, "baz").WithArguments(",").WithLocation(7, 9), + // (7,12): error CS1010: Newline in constant + // bar baz")] + Diagnostic(ErrorCode.ERR_NewlineInConst, "").WithLocation(7, 12), + // (7,15): error CS1003: Syntax error, ',' expected + // bar baz")] + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(",").WithLocation(7, 15), + // (8,7): error CS1003: Syntax error, ']' expected + // B, + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("]").WithLocation(8, 7), + // (8,7): error CS1001: Identifier expected + // B, + Diagnostic(ErrorCode.ERR_IdentifierExpected, "").WithLocation(8, 7)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.EnumDeclaration); + { + N(SyntaxKind.PublicKeyword); + N(SyntaxKind.EnumKeyword); + N(SyntaxKind.IdentifierToken, "BundleType"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.EnumMemberDeclaration); + { + N(SyntaxKind.AttributeList); + { + N(SyntaxKind.OpenBracketToken); + N(SyntaxKind.Attribute); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "A"); + } + N(SyntaxKind.AttributeArgumentList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.AttributeArgument); + { + N(SyntaxKind.StringLiteralExpression); + { + N(SyntaxKind.StringLiteralToken, "\"B\""); + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.AttributeArgument); + { + N(SyntaxKind.StringLiteralExpression); + { + N(SyntaxKind.StringLiteralToken, "\"C\""); + } + } + N(SyntaxKind.CloseParenToken); + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.Attribute); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Description"); + } + N(SyntaxKind.AttributeArgumentList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.AttributeArgument); + { + N(SyntaxKind.StringLiteralExpression); + { + N(SyntaxKind.StringLiteralToken, "\"X\""); + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.AttributeArgument); + { + N(SyntaxKind.InterpolatedStringExpression); + { + N(SyntaxKind.InterpolatedStringStartToken); + N(SyntaxKind.InterpolatedStringText); + { + N(SyntaxKind.InterpolatedStringTextToken); + } + M(SyntaxKind.InterpolatedStringEndToken); + } + } + M(SyntaxKind.CloseParenToken); + } + } + M(SyntaxKind.CommaToken); + N(SyntaxKind.Attribute); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "bar"); + } + } + M(SyntaxKind.CommaToken); + N(SyntaxKind.Attribute); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "baz"); + } + } + M(SyntaxKind.CommaToken); + N(SyntaxKind.Attribute); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "A"); + } + } + N(SyntaxKind.CommaToken); + M(SyntaxKind.CloseBracketToken); + } + N(SyntaxKind.AttributeList); + { + N(SyntaxKind.OpenBracketToken); + N(SyntaxKind.Attribute); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "A"); + } + N(SyntaxKind.AttributeArgumentList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.AttributeArgument); + { + N(SyntaxKind.StringLiteralExpression); + { + N(SyntaxKind.StringLiteralToken, "\"B\""); + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.AttributeArgument); + { + N(SyntaxKind.StringLiteralExpression); + { + N(SyntaxKind.StringLiteralToken, "\"C\""); + } + } + N(SyntaxKind.CloseParenToken); + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.Attribute); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Description"); + } + N(SyntaxKind.AttributeArgumentList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.AttributeArgument); + { + N(SyntaxKind.StringLiteralExpression); + { + N(SyntaxKind.StringLiteralToken, "\"X\""); + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.AttributeArgument); + { + N(SyntaxKind.InterpolatedStringExpression); + { + N(SyntaxKind.InterpolatedStringStartToken); + N(SyntaxKind.InterpolatedStringText); + { + N(SyntaxKind.InterpolatedStringTextToken); + } + M(SyntaxKind.InterpolatedStringEndToken); + } + } + M(SyntaxKind.CloseParenToken); + } + } + M(SyntaxKind.CommaToken); + N(SyntaxKind.Attribute); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "bar"); + } + } + M(SyntaxKind.CommaToken); + N(SyntaxKind.Attribute); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "baz"); + } + } + M(SyntaxKind.CommaToken); + N(SyntaxKind.Attribute); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "B"); + } + } + N(SyntaxKind.CommaToken); + M(SyntaxKind.CloseBracketToken); + } + M(SyntaxKind.IdentifierToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } }