diff --git a/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs b/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs
index 6550d229bb5c4..1de27e706b6de 100644
--- a/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs
+++ b/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs
@@ -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));
diff --git a/src/Compilers/CSharp/Test/Emit3/Semantics/PatternMatchingTests3.cs b/src/Compilers/CSharp/Test/Emit3/Semantics/PatternMatchingTests3.cs
index 48f0d4a5838e0..0771f9922d3c0 100644
--- a/src/Compilers/CSharp/Test/Emit3/Semantics/PatternMatchingTests3.cs
+++ b/src/Compilers/CSharp/Test/Emit3/Semantics/PatternMatchingTests3.cs
@@ -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]
diff --git a/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_ICoalesceAssignmentOperation.cs b/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_ICoalesceAssignmentOperation.cs
index 90e70ad9449b3..a144c67e01fa9 100644
--- a/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_ICoalesceAssignmentOperation.cs
+++ b/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_ICoalesceAssignmentOperation.cs
@@ -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 '??='
+ // /**/??=/**/;
+ Diagnostic(ErrorCode.ERR_InvalidExprTerm, "??=").WithArguments("??=").WithLocation(6, 19),
+ // (6,33): error CS1525: Invalid expression term ';'
// /**/??=/**/;
Diagnostic(ErrorCode.ERR_InvalidExprTerm, ";").WithArguments(";").WithLocation(6, 33)
};
diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/ExpressionParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/ExpressionParsingTests.cs
index be8bac428f07b..019487e219537 100644
--- a/src/Compilers/CSharp/Test/Syntax/Parsing/ExpressionParsingTests.cs
+++ b/src/Compilers/CSharp/Test/Syntax/Parsing/ExpressionParsingTests.cs
@@ -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();
+ }
}
}
diff --git a/src/VisualStudio/Core/Test.Next/Services/ServiceHubServicesTests.cs b/src/VisualStudio/Core/Test.Next/Services/ServiceHubServicesTests.cs
index d6212e9bb63a4..65dd675cd3f83 100644
--- a/src/VisualStudio/Core/Test.Next/Services/ServiceHubServicesTests.cs
+++ b/src/VisualStudio/Core/Test.Next/Services/ServiceHubServicesTests.cs
@@ -1933,17 +1933,17 @@ void M()
var result = await service.AnalyzeChangeAsync(
document, [new TextChange(new TextSpan(listIndex, 1), """
- <<<<<<<
+ <<<<<<< goo
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());
@@ -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"]);
@@ -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"]);
}