File: MetaAnalyzers\PreferIsKindAnalyzerTests.cs
Web Access
Project: src\src\RoslynAnalyzers\Microsoft.CodeAnalysis.Analyzers\UnitTests\Microsoft.CodeAnalysis.Analyzers.UnitTests.csproj (Microsoft.CodeAnalysis.Analyzers.UnitTests)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
using System;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Testing;
using Test.Utilities;
using Xunit;
using VerifyCS = Test.Utilities.CSharpCodeFixVerifier<
    Microsoft.CodeAnalysis.Analyzers.MetaAnalyzers.PreferIsKindAnalyzer,
    Microsoft.CodeAnalysis.CSharp.Analyzers.MetaAnalyzers.Fixers.CSharpPreferIsKindFix>;
using VerifyVB = Test.Utilities.VisualBasicCodeFixVerifier<
    Microsoft.CodeAnalysis.Analyzers.MetaAnalyzers.PreferIsKindAnalyzer,
    Microsoft.CodeAnalysis.VisualBasic.Analyzers.MetaAnalyzers.CodeFixes.BasicPreferIsKindFix>;
 
namespace Microsoft.CodeAnalysis.Analyzers.UnitTests.MetaAnalyzers
{
    public class PreferIsKindAnalyzerTests
    {
        [Theory]
        [InlineData("==")]
        [InlineData("!=")]
        public async Task TestSimpleReturn_CSAsync(string @operator)
        {
            var source =
$@"using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
 
class C
{{
    bool Method(SyntaxNode node)
    {{
        return [|node.Kind()|] {@operator} SyntaxKind.None;
    }}
}}
";
 
            var prefix = @operator switch
            {
                "==" => "",
                "!=" => "!",
                _ => throw new InvalidOperationException(),
            };
 
            var fixedSource =
$@"using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
 
class C
{{
    bool Method(SyntaxNode node)
    {{
        return {prefix}node.IsKind(SyntaxKind.None);
    }}
}}
";
 
            await VerifyCS.VerifyCodeFixAsync(source, fixedSource);
        }
 
        [Theory]
        [InlineData("=")]
        [InlineData("<>")]
        public async Task TestSimpleReturn_VBAsync(string @operator)
        {
            var source =
$@"Imports Microsoft.CodeAnalysis
Imports Microsoft.CodeAnalysis.VisualBasic
 
Class C
    Function Method(node As SyntaxNode) As Boolean
        Return [|node.Kind()|] {@operator} SyntaxKind.None
    End Function
End Class
";
 
            var prefix = @operator switch
            {
                "=" => "",
                "<>" => "Not ",
                _ => throw new InvalidOperationException(),
            };
 
            var fixedSource =
$@"Imports Microsoft.CodeAnalysis
Imports Microsoft.CodeAnalysis.VisualBasic
 
Class C
    Function Method(node As SyntaxNode) As Boolean
        Return {prefix}node.IsKind(SyntaxKind.None)
    End Function
End Class
";
 
            await VerifyVB.VerifyCodeFixAsync(source, fixedSource);
        }
 
        [Fact]
        public async Task TestCompoundExpression_CSAsync()
        {
            var source =
@"using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
 
class C
{
    bool Method(SyntaxNode node)
    {
        return [|node.Kind()|] != SyntaxKind.None && [|node.Kind()|] != SyntaxKind.TrueKeyword;
    }
}
";
            var fixedSource =
@"using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
 
class C
{
    bool Method(SyntaxNode node)
    {
        return !node.IsKind(SyntaxKind.None) && !node.IsKind(SyntaxKind.TrueKeyword);
    }
}
";
 
            await VerifyCS.VerifyCodeFixAsync(source, fixedSource);
        }
 
        [Fact]
        public async Task TestCompoundExpression_VBAsync()
        {
            var source =
@"Imports Microsoft.CodeAnalysis
Imports Microsoft.CodeAnalysis.VisualBasic
 
Class C
    Function Method(node As SyntaxNode) As Boolean
        Return [|node.Kind()|] <> SyntaxKind.None AndAlso [|node.Kind()|] <> SyntaxKind.TrueKeyword
    End Function
End Class
";
            var fixedSource =
@"Imports Microsoft.CodeAnalysis
Imports Microsoft.CodeAnalysis.VisualBasic
 
Class C
    Function Method(node As SyntaxNode) As Boolean
        Return Not node.IsKind(SyntaxKind.None) AndAlso Not node.IsKind(SyntaxKind.TrueKeyword)
    End Function
End Class
";
 
            await VerifyVB.VerifyCodeFixAsync(source, fixedSource);
        }
 
        [Theory]
        [InlineData("==")]
        [InlineData("!=")]
        public async Task TestCompoundExpression2_CSAsync(string @operator)
        {
            var source =
$@"using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
 
class C
{{
    bool Method(SyntaxNode node)
    {{
        return [|node.Kind()|] {@operator} SyntaxKind.None &&
            [|node.Kind()|] {@operator} SyntaxKind.TrueKeyword;
    }}
}}
";
 
            var prefix = @operator switch
            {
                "==" => "",
                "!=" => "!",
                _ => throw new InvalidOperationException(),
            };
 
            var fixedSource =
$@"using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
 
class C
{{
    bool Method(SyntaxNode node)
    {{
        return {prefix}node.IsKind(SyntaxKind.None) &&
            {prefix}node.IsKind(SyntaxKind.TrueKeyword);
    }}
}}
";
 
            await VerifyCS.VerifyCodeFixAsync(source, fixedSource);
        }
 
        [Theory]
        [InlineData("=")]
        [InlineData("<>")]
        public async Task TestCompoundExpression2_VBAsync(string @operator)
        {
            var source =
$@"Imports Microsoft.CodeAnalysis
Imports Microsoft.CodeAnalysis.VisualBasic
 
Class C
    Function Method(node As SyntaxNode) As Boolean
        Return [|node.Kind()|] {@operator} SyntaxKind.None AndAlso
            [|node.Kind()|] {@operator} SyntaxKind.TrueKeyword
    End Function
End Class
";
 
            var prefix = @operator switch
            {
                "=" => "",
                "<>" => "Not ",
                _ => throw new InvalidOperationException(),
            };
 
            var fixedSource =
$@"Imports Microsoft.CodeAnalysis
Imports Microsoft.CodeAnalysis.VisualBasic
 
Class C
    Function Method(node As SyntaxNode) As Boolean
        Return {prefix}node.IsKind(SyntaxKind.None) AndAlso
            {prefix}node.IsKind(SyntaxKind.TrueKeyword)
    End Function
End Class
";
 
            await VerifyVB.VerifyCodeFixAsync(source, fixedSource);
        }
 
        [Theory]
        [InlineData("==")]
        [InlineData("!=")]
        public async Task TestCalledAsStaticMethod_CSAsync(string @operator)
        {
            var source =
$@"using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
 
class C
{{
    bool Method(SyntaxNode node)
    {{
        return [|Microsoft.CodeAnalysis.CSharp.CSharpExtensions.Kind(node)|] {@operator} SyntaxKind.None;
    }}
}}
";
 
            var prefix = @operator switch
            {
                "==" => "",
                "!=" => "!",
                _ => throw new InvalidOperationException(),
            };
 
            var fixedSource =
$@"using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
 
class C
{{
    bool Method(SyntaxNode node)
    {{
        return {prefix}Microsoft.CodeAnalysis.CSharp.CSharpExtensions.{{|#0:IsKind|}}(node, SyntaxKind.None);
    }}
}}
";
 
            await new VerifyCS.Test
            {
                TestCode = source,
                FixedState =
                {
                    Sources = { fixedSource },
                    ExpectedDiagnostics =
                    {
                        // /0/Test0.cs(8,63): error CS0117: 'CSharpExtensions' does not contain a definition for 'IsKind'
                        DiagnosticResult.CompilerError("CS0117").WithLocation(0).WithArguments("Microsoft.CodeAnalysis.CSharp.CSharpExtensions", "IsKind"),
                    },
                },
            }.RunAsync();
        }
 
        [Theory]
        [InlineData("=")]
        [InlineData("<>")]
        public async Task TestCalledAsStaticMethod_VBAsync(string @operator)
        {
            var source =
$@"Imports Microsoft.CodeAnalysis
Imports Microsoft.CodeAnalysis.VisualBasic
 
Class C
    Function Method(node As SyntaxNode) As Boolean
        Return [|Microsoft.CodeAnalysis.VisualBasic.VisualBasicExtensions.Kind(node)|] {@operator} SyntaxKind.None
    End Function
End Class
";
 
            var prefix = @operator switch
            {
                "=" => "",
                "<>" => "Not ",
                _ => throw new InvalidOperationException(),
            };
 
            var fixedSource =
$@"Imports Microsoft.CodeAnalysis
Imports Microsoft.CodeAnalysis.VisualBasic
 
Class C
    Function Method(node As SyntaxNode) As Boolean
        Return {prefix}{{|#0:Microsoft.CodeAnalysis.VisualBasic.VisualBasicExtensions.IsKind|}}(node, SyntaxKind.None)
    End Function
End Class
";
 
            await new VerifyVB.Test
            {
                TestCode = source,
                FixedState =
                {
                    Sources = { fixedSource },
                    ExpectedDiagnostics =
                    {
                        // /0/Test0.vb(6) : error BC30456: 'IsKind' is not a member of 'VisualBasicExtensions'.
                        DiagnosticResult.CompilerError("BC30456").WithLocation(0).WithArguments("IsKind", "Microsoft.CodeAnalysis.VisualBasic.VisualBasicExtensions"),
                    },
                },
            }.RunAsync();
        }
 
        [Theory]
        [InlineData("=")]
        [InlineData("<>")]
        public async Task TestVBWithoutParensAsync(string @operator)
        {
            var source =
$@"Imports Microsoft.CodeAnalysis
Imports Microsoft.CodeAnalysis.VisualBasic
 
Class C
    Function Method(node As SyntaxNode) As Boolean
        Return [|node.Kind|] {@operator} SyntaxKind.None
    End Function
End Class
";
 
            var prefix = @operator switch
            {
                "=" => "",
                "<>" => "Not ",
                _ => throw new InvalidOperationException(),
            };
 
            var fixedSource =
$@"Imports Microsoft.CodeAnalysis
Imports Microsoft.CodeAnalysis.VisualBasic
 
Class C
    Function Method(node As SyntaxNode) As Boolean
        Return {prefix}node.IsKind(SyntaxKind.None)
    End Function
End Class
";
 
            await VerifyVB.VerifyCodeFixAsync(source, fixedSource);
        }
 
        [Fact]
        public async Task TestSwitchStatement_CSAsync()
        {
            var source =
@"using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
 
class C
{
    void Method(SyntaxNode node)
    {
        switch (node.Kind())
        {
            case SyntaxKind.NewKeyword:
                break;
 
            case SyntaxKind.None:
                break;
        }
    }
}
";
 
            await VerifyCS.VerifyCodeFixAsync(source, source);
        }
 
        [Fact]
        public async Task TestSwitchStatement_VBAsync()
        {
            var source =
@"Imports Microsoft.CodeAnalysis
Imports Microsoft.CodeAnalysis.VisualBasic
 
Class C
    Sub Method(node As SyntaxNode)
        Select Case node.Kind()
            Case SyntaxKind.NewKeyword
                Return
            Case Else
                Return
        End Select
    End Sub
End Class
";
 
            await VerifyVB.VerifyCodeFixAsync(source, source);
        }
 
        [Fact]
        [WorkItem(4946, "https://github.com/dotnet/roslyn-analyzers/issues/4946")]
        public async Task TestSingleNullConditionalAccess_CSAsync()
        {
            var source =
@"using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
 
class C
{
    bool Method(SyntaxNode node)
    {
        return [|node?.Kind()|] == SyntaxKind.None;
    }
}
";
 
            var fixedSource =
@"using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
 
class C
{
    bool Method(SyntaxNode node)
    {
        return node.IsKind(SyntaxKind.None);
    }
}
";
 
            await VerifyCS.VerifyCodeFixAsync(source, fixedSource);
        }
 
        [Fact]
        [WorkItem(4946, "https://github.com/dotnet/roslyn-analyzers/issues/4946")]
        public async Task TestSingleNullConditionalAccess_VBAsync()
        {
            var source =
@"Imports Microsoft.CodeAnalysis
Imports Microsoft.CodeAnalysis.VisualBasic
 
Class C
    Function Method(node As SyntaxNode) As Boolean
        Return [|node?.Kind()|] = SyntaxKind.None
    End Function
End Class
";
            var fixedSource =
@"Imports Microsoft.CodeAnalysis
Imports Microsoft.CodeAnalysis.VisualBasic
 
Class C
    Function Method(node As SyntaxNode) As Boolean
        Return node.IsKind(SyntaxKind.None)
    End Function
End Class
";
            await VerifyVB.VerifyCodeFixAsync(source, fixedSource);
        }
 
        [Fact]
        [WorkItem(4946, "https://github.com/dotnet/roslyn-analyzers/issues/4946")]
        public async Task TestSingleNullConditionalAccess_SyntaxToken_CSAsync()
        {
            var source =
@"using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
 
class C
{
    bool Method(SyntaxToken? token)
    {
        return token?.Kind() == SyntaxKind.None;
    }
}
";
 
            await VerifyCS.VerifyCodeFixAsync(source, source);
        }
 
        [Fact]
        [WorkItem(4946, "https://github.com/dotnet/roslyn-analyzers/issues/4946")]
        public async Task TestSingleNullConditionalAccess_SyntaxToken_VBAsync()
        {
            var source =
@"Imports Microsoft.CodeAnalysis
Imports Microsoft.CodeAnalysis.VisualBasic
 
Class C
    Function Method(token As SyntaxToken?) As Boolean
        Return token?.Kind() = SyntaxKind.None
    End Function
End Class
";
            await VerifyVB.VerifyCodeFixAsync(source, source);
        }
    }
}