When not specifying a discard operator during a case for a switch with a generic type, sonar analyzer throws a SymbolicExecutionRunner
Severity Code Description Project Path File Line Suppression State
Error AD0001 Analyzer 'SonarAnalyzer.Rules.SymbolicExecution.SymbolicExecutionRunner' threw an exception of type 'SonarAnalyzer.SymbolicExecution.SymbolicExecutionException' with message 'Error processing method: Evaluate ## Method file: MyPath\SonarExample.cs ## Method line: 17,8 ## Inner exception: System.NotSupportedException: TypePattern ## at SonarAnalyzer.SymbolicExecution.CSharpExplodedGraph.VisitInstruction(ExplodedGraphNode node) ## at SonarAnalyzer.SymbolicExecution.AbstractExplodedGraph.Walk() ## at SonarAnalyzer.Rules.SymbolicExecution.SymbolicExecutionRunner.Analyze(CSharpExplodedGraph explodedGraph, SyntaxNodeAnalysisContext context) ## at SonarAnalyzer.Extensions.SonarAnalysisContextExtensions.Analyze(CSharpSyntaxNode declarationBody, ISymbol symbol, Action`2 runAnalysis, SyntaxNodeAnalysisContext context) ## '. MyProject MyPath MyPath\CSC 1 Active
#nullable enable
using System;
using System.Threading.Tasks;
namespace SonarAnalyzerFailure
{
public class SonarExample
{
private IOtherClass otherClass;
public SonarExample(IOtherClass otherClass)
{
this.otherClass = otherClass;
}
public async Task<int> Evaluate()
{
var result = await this.otherClass.DoSomething();
switch (result)
{
case ClassOne<int> error: // this is fine
// some code
break;
case ClassTwo<int>: // this throws a SymbolicExecutionException
// some code
break;
case ClassThree<int> _: // this is fine
// some code
break;
default:
throw new NotImplementedException(nameof(ISomeClass<int>));
}
return 42;
}
}
public interface ISomeClass<out T>
where T : notnull
{
}
public sealed class ClassOne<T> :
ISomeClass<T>
where T : notnull
{
}
public sealed class ClassTwo<T> :
ISomeClass<T>
where T : notnull
{
}
public sealed class ClassThree<T> :
ISomeClass<T>
where T : notnull
{
}
public interface IOtherClass
{
Task<ISomeClass<int>> DoSomething();
}
}
Change:
case ClassTwo<int>:
to
case ClassTwo<int> _:
or
case ClassTwo<int> foo:
This also happens with relational patterns like
var i = 9;
switch (i) {
case > 0:
.
.
.
}
Hi @KraftyKanuck.
This problem appears due to the fact that we don't yet support the TypePattern introduced in .Net 5 (https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-9.0/patterns3).
As a result the analysis for snippets like:
switch (values)
{
case IEnumerable<int>: // TypePattern is not supported
break;
}
is not yet supported.
We will do a first step this sprint to not throw but proper support will be added later this year.
Same problem appears for RelationalPattern (https://github.com/dotnet/csharplang/issues/812) too.
switch (i)
{
case > 0:
break;
}
Most helpful comment
This also happens with relational patterns like
var i = 9;
switch (i) {
case > 0:
.
.
.
}