Sonar-dotnet: Symbolic execution engine should not throw on TypePattern and RelationalPattern (introduced in .Net 5)

Created on 2 Mar 2021  路  3Comments  路  Source: SonarSource/sonar-dotnet

Description

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

Repro steps

#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();
    }
}

Known workarounds

Change:
case ClassTwo<int>:
to
case ClassTwo<int> _:
or
case ClassTwo<int> foo:

Related information

  • C# 9
  • Visual Studio 2019 - 16.8.3
  • dotnet 5.0
  • occurs in SonarAnalyzer.CSharp 8.17.0.26580 and 8.19.0.28253
  • Win 10
C# C#9 CFG Bug

Most helpful comment

This also happens with relational patterns like
var i = 9;
switch (i) {
case > 0:
.
.
.
}

All 3 comments

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;
}
Was this page helpful?
0 / 5 - 0 ratings