Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions src/Compilers/CSharp/Portable/Parser/LanguageParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11967,6 +11967,21 @@ ExpressionSyntax parsePrimaryExpressionWithoutPostfix(Precedence precedence)
{
expr = this.AddError(expr, ErrorCode.ERR_ExpressionExpected);
}
else if (
SyntaxFacts.IsBinaryExpression(tk) ||
SyntaxFacts.IsAssignmentExpressionOperatorToken(tk))
{
// We got into the expression parsing path because we saw an error operator (see the
// default case in IsPossibleExpression), knowing we'd create a missing expr which would
// then allow the binary/assignment expr parsing to proceed. In this case, we want to
// report the invalid expr, but place it next to the operator, not whatever might have
// come arbitrarily far before us.
return WithAdditionalDiagnostics(expr, MakeError(
offset: this.CurrentToken.GetLeadingTriviaWidth(),
width: this.CurrentToken.Width,
ErrorCode.ERR_InvalidExprTerm,
SyntaxFacts.GetText(tk)));
}
else
{
expr = this.AddError(expr, ErrorCode.ERR_InvalidExprTerm, SyntaxFacts.GetText(tk));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2738,19 +2738,18 @@ class C
}";
var compilation = CreateCompilation(source, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp9));
compilation.VerifyDiagnostics(
// (5,6): error CS1525: Invalid expression term '|'
// {
Diagnostic(ErrorCode.ERR_InvalidExprTerm, "").WithArguments("|").WithLocation(5, 6),
// (6,18): error CS1525: Invalid expression term '||'
// (6,9): error CS1525: Invalid expression term '|'
// | 3 => 3,
Diagnostic(ErrorCode.ERR_InvalidExprTerm, "").WithArguments("||").WithLocation(6, 18),
Diagnostic(ErrorCode.ERR_InvalidExprTerm, "|").WithArguments("|").WithLocation(6, 9),
// (7,9): error CS1525: Invalid expression term '||'
// || 4 => 4,
Diagnostic(ErrorCode.ERR_InvalidExprTerm, "||").WithArguments("||").WithLocation(7, 9),
// (8,11): error CS0211: Cannot take the address of the given expression
// & 5 => 5,
Diagnostic(ErrorCode.ERR_InvalidAddrOp, "5").WithLocation(8, 11),
// (8,18): error CS1525: Invalid expression term '&&'
// & 5 => 5,
Diagnostic(ErrorCode.ERR_InvalidExprTerm, "").WithArguments("&&").WithLocation(8, 18)
);
// (9,9): error CS1525: Invalid expression term '&&'
// && 6 => 6,
Diagnostic(ErrorCode.ERR_InvalidExprTerm, "&&").WithArguments("&&").WithLocation(9, 9));
}

[Fact]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -239,10 +239,10 @@ static void M()
Children(0)
";
var expectedDiagnostics = new DiagnosticDescription[] {
// file.cs(5,6): error CS1525: Invalid expression term '??='
// {
Diagnostic(ErrorCode.ERR_InvalidExprTerm, "").WithArguments("??=").WithLocation(5, 6),
// file.cs(6,33): error CS1525: Invalid expression term ';'
// (6,19): error CS1525: Invalid expression term '??='
// /*<bind>*/??=/*</bind>*/;
Diagnostic(ErrorCode.ERR_InvalidExprTerm, "??=").WithArguments("??=").WithLocation(6, 19),
// (6,33): error CS1525: Invalid expression term ';'
// /*<bind>*/??=/*</bind>*/;
Diagnostic(ErrorCode.ERR_InvalidExprTerm, ";").WithArguments(";").WithLocation(6, 33)
};
Expand Down
208 changes: 208 additions & 0 deletions src/Compilers/CSharp/Test/Syntax/Parsing/ExpressionParsingTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8674,5 +8674,213 @@ public void TestParenthesizedDefaultInIsExpression()
}
EOF();
}

[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/58298")]
public void OperatorErrorLocation1()
{
UsingTree("""
void M()
{
<<;
}
""",
// (3,5): error CS1525: Invalid expression term '<<'
// <<;
Diagnostic(ErrorCode.ERR_InvalidExprTerm, "<<").WithArguments("<<").WithLocation(3, 5),
// (3,7): error CS1525: Invalid expression term ';'
// <<;
Diagnostic(ErrorCode.ERR_InvalidExprTerm, ";").WithArguments(";").WithLocation(3, 7));

N(SyntaxKind.CompilationUnit);
{
N(SyntaxKind.GlobalStatement);
{
N(SyntaxKind.LocalFunctionStatement);
{
N(SyntaxKind.PredefinedType);
{
N(SyntaxKind.VoidKeyword);
}
N(SyntaxKind.IdentifierToken, "M");
N(SyntaxKind.ParameterList);
{
N(SyntaxKind.OpenParenToken);
N(SyntaxKind.CloseParenToken);
}
N(SyntaxKind.Block);
{
N(SyntaxKind.OpenBraceToken);
N(SyntaxKind.ExpressionStatement);
{
N(SyntaxKind.LeftShiftExpression);
{
M(SyntaxKind.IdentifierName);
{
M(SyntaxKind.IdentifierToken);
}
N(SyntaxKind.LessThanLessThanToken);
M(SyntaxKind.IdentifierName);
{
M(SyntaxKind.IdentifierToken);
}
}
N(SyntaxKind.SemicolonToken);
}
N(SyntaxKind.CloseBraceToken);
}
}
}
N(SyntaxKind.EndOfFileToken);
}
EOF();
}

[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/31774")]
public void OperatorErrorLocation2()
{
UsingTree("""
void M()
{
// comment
/ Console.ReadKey();
}
""",
// (4,5): error CS1525: Invalid expression term '/'
// / Console.ReadKey();
Diagnostic(ErrorCode.ERR_InvalidExprTerm, "/").WithArguments("/").WithLocation(4, 5));

N(SyntaxKind.CompilationUnit);
{
N(SyntaxKind.GlobalStatement);
{
N(SyntaxKind.LocalFunctionStatement);
{
N(SyntaxKind.PredefinedType);
{
N(SyntaxKind.VoidKeyword);
}
N(SyntaxKind.IdentifierToken, "M");
N(SyntaxKind.ParameterList);
{
N(SyntaxKind.OpenParenToken);
N(SyntaxKind.CloseParenToken);
}
N(SyntaxKind.Block);
{
N(SyntaxKind.OpenBraceToken);
N(SyntaxKind.ExpressionStatement);
{
N(SyntaxKind.DivideExpression);
{
M(SyntaxKind.IdentifierName);
{
M(SyntaxKind.IdentifierToken);
}
N(SyntaxKind.SlashToken);
N(SyntaxKind.InvocationExpression);
{
N(SyntaxKind.SimpleMemberAccessExpression);
{
N(SyntaxKind.IdentifierName);
{
N(SyntaxKind.IdentifierToken, "Console");
}
N(SyntaxKind.DotToken);
N(SyntaxKind.IdentifierName);
{
N(SyntaxKind.IdentifierToken, "ReadKey");
}
}
N(SyntaxKind.ArgumentList);
{
N(SyntaxKind.OpenParenToken);
N(SyntaxKind.CloseParenToken);
}
}
}
N(SyntaxKind.SemicolonToken);
}
N(SyntaxKind.CloseBraceToken);
}
}
}
N(SyntaxKind.EndOfFileToken);
}
EOF();
}

[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/31774")]
public void OperatorErrorLocation3()
{
UsingTree("""
void M()
{
// comment
= Console.ReadKey();
}
""",
// (4,5): error CS1525: Invalid expression term '='
// = Console.ReadKey();
Diagnostic(ErrorCode.ERR_InvalidExprTerm, "=").WithArguments("=").WithLocation(4, 5));

N(SyntaxKind.CompilationUnit);
{
N(SyntaxKind.GlobalStatement);
{
N(SyntaxKind.LocalFunctionStatement);
{
N(SyntaxKind.PredefinedType);
{
N(SyntaxKind.VoidKeyword);
}
N(SyntaxKind.IdentifierToken, "M");
N(SyntaxKind.ParameterList);
{
N(SyntaxKind.OpenParenToken);
N(SyntaxKind.CloseParenToken);
}
N(SyntaxKind.Block);
{
N(SyntaxKind.OpenBraceToken);
N(SyntaxKind.ExpressionStatement);
{
N(SyntaxKind.SimpleAssignmentExpression);
{
M(SyntaxKind.IdentifierName);
{
M(SyntaxKind.IdentifierToken);
}
N(SyntaxKind.EqualsToken);
N(SyntaxKind.InvocationExpression);
{
N(SyntaxKind.SimpleMemberAccessExpression);
{
N(SyntaxKind.IdentifierName);
{
N(SyntaxKind.IdentifierToken, "Console");
}
N(SyntaxKind.DotToken);
N(SyntaxKind.IdentifierName);
{
N(SyntaxKind.IdentifierToken, "ReadKey");
}
}
N(SyntaxKind.ArgumentList);
{
N(SyntaxKind.OpenParenToken);
N(SyntaxKind.CloseParenToken);
}
}
}
N(SyntaxKind.SemicolonToken);
}
N(SyntaxKind.CloseBraceToken);
}
}
}
N(SyntaxKind.EndOfFileToken);
}
EOF();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1933,17 +1933,17 @@ void M()

var result = await service.AnalyzeChangeAsync(
document, [new TextChange(new TextSpan(listIndex, 1), """
<<<<<<<
<<<<<<< goo
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this test wanted to make merge-conflict-markers. but by leaving off the trailing text just ended up with lots of operator tokens, all of which had error locations get updated by the parsing change.

Goo
=======
======= bar
Bar
>>>>>>>
>>>>>>> baz
""")], CancellationToken.None);

Assert.True(result.Succeeded);

var diagnosticAnalysis = result.DiagnosticAnalyses.Single(d => d.Kind == DiagnosticKind.CompilerSyntax);
Assert.Equal(1, diagnosticAnalysis.IdToCount["CS8300"]);
Assert.Equal(3, diagnosticAnalysis.IdToCount["CS8300"]);

Assert.Equal(1, result.CodeFixAnalysis.DiagnosticIdToCount["CS8300"]);
Assert.Equal("CSharp.ConflictMarkerResolution.CSharpResolveConflictMarkerCodeFixProvider", result.CodeFixAnalysis.DiagnosticIdToProviderName["CS8300"].Single());
Expand All @@ -1967,8 +1967,8 @@ void M()
Assert.Equal("TestProposalId", properties["vs.ide.vbcs.copilot.analyzechange.proposalid"]);

Assert.Equal(44, properties["vs.ide.vbcs.copilot.analyzechange.olddocumentlength"]);
Assert.Equal(78, properties["vs.ide.vbcs.copilot.analyzechange.newdocumentlength"]);
Assert.Equal(34, properties["vs.ide.vbcs.copilot.analyzechange.textchangedelta"]);
Assert.Equal(90, properties["vs.ide.vbcs.copilot.analyzechange.newdocumentlength"]);
Assert.Equal(46, properties["vs.ide.vbcs.copilot.analyzechange.textchangedelta"]);

Assert.Equal(1, properties["vs.ide.vbcs.copilot.analyzechange.projectdocumentcount"]);
Assert.Equal(0, properties["vs.ide.vbcs.copilot.analyzechange.projectsourcegenerateddocumentcount"]);
Expand All @@ -1985,16 +1985,16 @@ void M()
Assert.Equal("", properties["vs.ide.vbcs.copilot.analyzechange.diagnosticanalysis_analyzersemantic_severitytocount"]);

// CS1002_1 means we got one CS1002 diagnostic. Whereas CS1525_3 means we got 3 CS1525 diagnostics.
Assert.Equal("CS1002_1,CS1513_1,CS1525_3,CS8300_1", properties["vs.ide.vbcs.copilot.analyzechange.diagnosticanalysis_compilersyntax_idtocount"]);
Assert.Equal("Compiler_6", properties["vs.ide.vbcs.copilot.analyzechange.diagnosticanalysis_compilersyntax_categorytocount"]);
Assert.Equal("Error_6", properties["vs.ide.vbcs.copilot.analyzechange.diagnosticanalysis_compilersyntax_severitytocount"]);
Assert.Equal("CS1002_1,CS8300_3", properties["vs.ide.vbcs.copilot.analyzechange.diagnosticanalysis_compilersyntax_idtocount"]);
Assert.Equal("Compiler_4", properties["vs.ide.vbcs.copilot.analyzechange.diagnosticanalysis_compilersyntax_categorytocount"]);
Assert.Equal("Error_4", properties["vs.ide.vbcs.copilot.analyzechange.diagnosticanalysis_compilersyntax_severitytocount"]);

Assert.Equal("CS0103_1", properties["vs.ide.vbcs.copilot.analyzechange.diagnosticanalysis_compilersemantic_idtocount"]);
Assert.Equal("Compiler_1", properties["vs.ide.vbcs.copilot.analyzechange.diagnosticanalysis_compilersemantic_categorytocount"]);
Assert.Equal("Error_1", properties["vs.ide.vbcs.copilot.analyzechange.diagnosticanalysis_compilersemantic_severitytocount"]);

Assert.Equal("CS0103_1,CS8300_1", properties["vs.ide.vbcs.copilot.analyzechange.codefixanalysis_diagnosticidtocount"]);
Assert.Equal("CS0103_CSharp.GenerateVariable.CSharpGenerateVariableCodeFixProvider,CS8300_CSharp.ConflictMarkerResolution.CSharpResolveConflictMarkerCodeFixProvider",
Assert.Equal("CS0103_2,CS8300_1", properties["vs.ide.vbcs.copilot.analyzechange.codefixanalysis_diagnosticidtocount"]);
Assert.Equal("CS0103_CSharp.GenerateVariable.CSharpGenerateVariableCodeFixProvider:CSharp.SpellCheck.CSharpSpellCheckCodeFixProvider,CS8300_CSharp.ConflictMarkerResolution.CSharpResolveConflictMarkerCodeFixProvider",
properties["vs.ide.vbcs.copilot.analyzechange.codefixanalysis_diagnosticidtoprovidername"]);
}

Expand Down
Loading