未验证 提交 2a58f734 编写于 作者: N Neal Gafter 提交者: GitHub

When there is an error in an interpolated string, take the next quote as a close quote (#44899)

Fixes #44789
上级 896ac93c
......@@ -372,6 +372,12 @@ private void ScanInterpolatedStringLiteralContents(ArrayBuilder<Interpolation> i
switch (lexer.TextWindow.PeekChar())
{
case '"' when RecoveringFromRunawayLexing():
// When recovering from mismatched delimiters, we consume the next
// quote character as the close quote for the interpolated string. In
// practice this gets us out of trouble in scenarios we've encountered.
// See, for example, https://github.com/dotnet/roslyn/issues/44789
return;
case '"':
if (isVerbatim && lexer.TextWindow.PeekChar(1) == '"')
{
......@@ -588,13 +594,19 @@ private void ScanInterpolatedStringLiteralHoleBalancedText(char endingChar, bool
}
goto default;
case '"' when RecoveringFromRunawayLexing():
// When recovering from mismatched delimiters, we consume the next
// quote character as the close quote for the interpolated string. In
// practice this gets us out of trouble in scenarios we've encountered.
// See, for example, https://github.com/dotnet/roslyn/issues/44789
return;
case '"':
case '\'':
// handle string or character literal inside an expression hole.
ScanInterpolatedStringLiteralNestedString();
continue;
case '@':
if (lexer.TextWindow.PeekChar(1) == '"')
if (lexer.TextWindow.PeekChar(1) == '"' && !RecoveringFromRunawayLexing())
{
// check for verbatim string inside an expression hole.
ScanInterpolatedStringLiteralNestedVerbatimString();
......@@ -655,6 +667,12 @@ private void ScanInterpolatedStringLiteralHoleBalancedText(char endingChar, bool
}
}
/// <summary>
/// The lexer can run away consuming the rest of the input when delimiters are mismatched.
/// This is a test for when we are attempting to recover from that situation.
/// </summary>
private bool RecoveringFromRunawayLexing() => this.error != null;
private void ScanInterpolatedStringLiteralNestedComment()
{
Debug.Assert(lexer.TextWindow.PeekChar() == '/');
......
......@@ -151,14 +151,8 @@ public static void Main(string[] args)
// too many diagnostics perhaps, but it starts the right way.
CreateCompilationWithMscorlib45(source).VerifyDiagnostics(
// (5,71): error CS8077: A single-line comment may not be used in an interpolated string.
// Console.WriteLine("Jenny don\'t change your number \{ 8675309 // ");
Diagnostic(ErrorCode.ERR_SingleLineCommentInExpressionHole, "//").WithLocation(5, 71),
// (5,77): error CS1026: ) expected
// Console.WriteLine("Jenny don\'t change your number \{ 8675309 // ");
Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(5, 77),
// (5,77): error CS1002: ; expected
// Console.WriteLine("Jenny don\'t change your number \{ 8675309 // ");
Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(5, 77)
// Console.WriteLine($"Jenny don\'t change your number { 8675309 // ");
Diagnostic(ErrorCode.ERR_SingleLineCommentInExpressionHole, "//").WithLocation(5, 71)
);
}
......
......@@ -5236,5 +5236,118 @@ public void ArrayCreation_ElementAccess()
}
EOF();
}
[Fact, WorkItem(44789, "https://github.com/dotnet/roslyn/issues/44789")]
public void MismatchedInterpolatedStringContents_01()
{
var text =
@"class A
{
void M()
{
if (b)
{
A B = new C($@""{D(.E}"");
N.O("""", P.Q);
R.S(T);
U.V(W.X, Y.Z);
}
}
string M() => """";
}";
var tree = ParseTree(text, TestOptions.Regular);
// Note that the parser eventually syncs back up and stops producing diagnostics.
tree.GetDiagnostics().Verify(
// (7,31): error CS1001: Identifier expected
// A B = new C($@"{D(.E}");
Diagnostic(ErrorCode.ERR_IdentifierExpected, ".").WithLocation(7, 31),
// (7,33): error CS1003: Syntax error, ')' expected
// A B = new C($@"{D(.E}");
Diagnostic(ErrorCode.ERR_SyntaxError, "}").WithArguments(")").WithLocation(7, 33),
// (7,33): error CS1003: Syntax error, ',' expected
// A B = new C($@"{D(.E}");
Diagnostic(ErrorCode.ERR_SyntaxError, "}").WithArguments(",", "}").WithLocation(7, 33),
// (7,34): error CS1026: ) expected
// A B = new C($@"{D(.E}");
Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(7, 34)
);
}
[Fact, WorkItem(44789, "https://github.com/dotnet/roslyn/issues/44789")]
public void MismatchedInterpolatedStringContents_02()
{
var text =
@"class A
{
void M()
{
if (b)
{
A B = new C($@""{D(.E}\F\G{H}_{I.J.K(""L"")}.M"");
N.O("""", P.Q);
R.S(T);
U.V(W.X, Y.Z);
}
}
string M() => """";
}";
var tree = ParseTree(text, TestOptions.Regular);
// Note that the parser eventually syncs back up and stops producing diagnostics.
tree.GetDiagnostics().Verify(
// (7,31): error CS1001: Identifier expected
// A B = new C($@"{D(.E}\F\G{H}_{I.J.K("L")}.M");
Diagnostic(ErrorCode.ERR_IdentifierExpected, ".").WithLocation(7, 31),
// (7,33): error CS1003: Syntax error, ')' expected
// A B = new C($@"{D(.E}\F\G{H}_{I.J.K("L")}.M");
Diagnostic(ErrorCode.ERR_SyntaxError, "}").WithArguments(")").WithLocation(7, 33),
// (7,33): error CS1003: Syntax error, ',' expected
// A B = new C($@"{D(.E}\F\G{H}_{I.J.K("L")}.M");
Diagnostic(ErrorCode.ERR_SyntaxError, "}").WithArguments(",", "}").WithLocation(7, 33),
// (7,34): error CS1056: Unexpected character '\'
// A B = new C($@"{D(.E}\F\G{H}_{I.J.K("L")}.M");
Diagnostic(ErrorCode.ERR_UnexpectedCharacter, "").WithArguments("\\").WithLocation(7, 34),
// (7,35): error CS1003: Syntax error, ',' expected
// A B = new C($@"{D(.E}\F\G{H}_{I.J.K("L")}.M");
Diagnostic(ErrorCode.ERR_SyntaxError, "F").WithArguments(",", "").WithLocation(7, 35),
// (7,36): error CS1056: Unexpected character '\'
// A B = new C($@"{D(.E}\F\G{H}_{I.J.K("L")}.M");
Diagnostic(ErrorCode.ERR_UnexpectedCharacter, "").WithArguments("\\").WithLocation(7, 36),
// (7,37): error CS1003: Syntax error, ',' expected
// A B = new C($@"{D(.E}\F\G{H}_{I.J.K("L")}.M");
Diagnostic(ErrorCode.ERR_SyntaxError, "G").WithArguments(",", "").WithLocation(7, 37),
// (7,38): error CS1003: Syntax error, ',' expected
// A B = new C($@"{D(.E}\F\G{H}_{I.J.K("L")}.M");
Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments(",", "{").WithLocation(7, 38),
// (7,39): error CS1003: Syntax error, ',' expected
// A B = new C($@"{D(.E}\F\G{H}_{I.J.K("L")}.M");
Diagnostic(ErrorCode.ERR_SyntaxError, "H").WithArguments(",", "").WithLocation(7, 39),
// (7,40): error CS1003: Syntax error, ',' expected
// A B = new C($@"{D(.E}\F\G{H}_{I.J.K("L")}.M");
Diagnostic(ErrorCode.ERR_SyntaxError, "}").WithArguments(",", "}").WithLocation(7, 40),
// (7,41): error CS1003: Syntax error, ',' expected
// A B = new C($@"{D(.E}\F\G{H}_{I.J.K("L")}.M");
Diagnostic(ErrorCode.ERR_SyntaxError, "_").WithArguments(",", "").WithLocation(7, 41),
// (7,42): error CS1003: Syntax error, ',' expected
// A B = new C($@"{D(.E}\F\G{H}_{I.J.K("L")}.M");
Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments(",", "{").WithLocation(7, 42),
// (7,43): error CS1003: Syntax error, ',' expected
// A B = new C($@"{D(.E}\F\G{H}_{I.J.K("L")}.M");
Diagnostic(ErrorCode.ERR_SyntaxError, "I").WithArguments(",", "").WithLocation(7, 43),
// (7,49): error CS1026: ) expected
// A B = new C($@"{D(.E}\F\G{H}_{I.J.K("L")}.M");
Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(7, 49),
// (7,49): error CS1026: ) expected
// A B = new C($@"{D(.E}\F\G{H}_{I.J.K("L")}.M");
Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(7, 49),
// (7,50): error CS1003: Syntax error, ',' expected
// A B = new C($@"{D(.E}\F\G{H}_{I.J.K("L")}.M");
Diagnostic(ErrorCode.ERR_SyntaxError, "L").WithArguments(",", "").WithLocation(7, 50),
// (7,51): error CS1003: Syntax error, ',' expected
// A B = new C($@"{D(.E}\F\G{H}_{I.J.K("L")}.M");
Diagnostic(ErrorCode.ERR_SyntaxError, @""")}.M""").WithArguments(",", "").WithLocation(7, 51)
);
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册