File: Microsoft.CodeQuality.Analyzers\Maintainability\AvoidDeadConditionalCode_ValueContentAnalysis.cs
Web Access
Project: ..\..\..\src\Microsoft.CodeAnalysis.NetAnalyzers\tests\Microsoft.CodeAnalysis.NetAnalyzers.UnitTests\Microsoft.CodeAnalysis.NetAnalyzers.UnitTests.csproj (Microsoft.CodeAnalysis.NetAnalyzers.UnitTests)
// Copyright (c) Microsoft.  All Rights Reserved.  Licensed under the MIT license.  See License.txt in the project root for license information.
 
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Testing;
using Test.Utilities;
using Xunit;
using CSharpLanguageVersion = Microsoft.CodeAnalysis.CSharp.LanguageVersion;
using VerifyCS = Test.Utilities.CSharpCodeFixVerifier<
    Microsoft.CodeQuality.CSharp.Analyzers.Maintainability.CSharpAvoidDeadConditionalCode,
    Microsoft.CodeAnalysis.Testing.EmptyCodeFixProvider>;
 
namespace Microsoft.CodeQuality.Analyzers.Maintainability.UnitTests
{
    [Trait(Traits.DataflowAnalysis, Traits.Dataflow.PredicateAnalysis)]
    public partial class AvoidDeadConditionalCodeTests
    {
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.ValueContentAnalysis)]
        [Fact]
        public async Task SimpleStringCompare_NoDiagnosticAsync()
        {
            await VerifyCSharpAnalyzerAsync(@"
class Test
{
    void M1(string param)
    {
        if (param == """")
        {
        }
 
        if ("""" == param)
        {
        }
    }
}
");
 
            await VerifyBasicAnalyzerAsync(@"
Module Test
    Sub M1(param As String)
        If param = """" Then
        End If
 
        If """" = param Then
        End If
    End Sub
End Module");
        }
 
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.ValueContentAnalysis)]
        [Fact]
        public async Task SimpleValueCompare_NoDiagnosticAsync()
        {
            await VerifyCSharpAnalyzerAsync(@"
class Test
{
    void M1(int param)
    {
        if (param == 0)
        {
        }
 
        if (0 == param)
        {
        }
    }
}
");
 
            await VerifyBasicAnalyzerAsync(@"
Module Test
    Sub M1(param As Integer)
        If param = 0 Then
        End If
 
        If 0 = param Then
        End If
    End Sub
End Module");
        }
 
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.ValueContentAnalysis)]
        [Fact]
        public async Task ValueCompareWithAdd_DiagnosticAsync()
        {
            await VerifyCSharpAnalyzerAsync(@"
class Test
{
    void M1(int param, int param2, int param3)
    {
        param2 = 2;
        if (param == 1 && (param3 == param + param2))
        {
            if (param3 == 3)
            {
            }
        }
    }
}
",
            // Test0.cs(9,17): warning CA1508: 'param3 == 3' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
            GetCSharpResultAt(9, 17, "param3 == 3", "true"));
 
            await VerifyBasicAnalyzerAsync(@"
Module Test
    Sub M1(param As Integer, param2 As Integer, param3 As Integer)
        param2 = 2
        If param = 1 AndAlso (param3 = param + param2) Then
            If param3 = 3 Then
            End If
        End If
    End Sub
End Module",
            // Test0.vb(6,16): warning CA1508: 'param3 = 3' is always 'True'. Remove or refactor the condition(s) to avoid dead code.
            GetBasicResultAt(6, 16, "param3 = 3", "True"));
        }
 
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.ValueContentAnalysis)]
        [Fact]
        public async Task ValueCompareWithSubtract_DiagnosticAsync()
        {
            await VerifyCSharpAnalyzerAsync(@"
class Test
{
    void M1(int param, int param2, int param3)
    {
        param2 = 2;
        if (param3 == 3 && (param3 - param2 == param))
        {
            if (param == 1)
            {
            }
        }
    }
}
",
            // Test0.cs(9,17): warning CA1508: 'param == 1' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
            GetCSharpResultAt(9, 17, "param == 1", "true"));
 
            await VerifyBasicAnalyzerAsync(@"
Module Test
    Sub M1(param As Integer, param2 As Integer, param3 As Integer)
        param2 = 2
        If param3 = 3 AndAlso (param3 - param2 = param) Then
            If param = 1 Then
            End If
        End If
    End Sub
End Module",
            // Test0.vb(6,16): warning CA1508: 'param = 1' is always 'True'. Remove or refactor the condition(s) to avoid dead code.
            GetBasicResultAt(6, 16, "param = 1", "True"));
        }
 
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.ValueContentAnalysis)]
        [Fact]
        public async Task SimpleStringCompare_AfterAssignment_DiagnosticAsync()
        {
            await VerifyCSharpAnalyzerAsync(@"
class Test
{
    void M1(string param)
    {
        param = """";
        if (param == """")
        {
        }
 
        if ("""" != param)
        {
        }
    }
}
",
            // Test0.cs(7,13): warning CA1508: 'param == ""' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
            GetCSharpResultAt(7, 13, @"param == """"", "true"),
            // Test0.cs(11,13): warning CA1508: '"" != param' is always 'false'. Remove or refactor the condition(s) to avoid dead code.
            GetCSharpResultAt(11, 13, @""""" != param", "false"));
 
            await VerifyBasicAnalyzerAsync(@"
Module Test
    Sub M1(param As String)
        param = """"
        If param = """" Then
        End If
 
        If """" <> param Then
        End If
    End Sub
End Module",
            // Test0.vb(5,12): warning CA1508: 'param = ""' is always 'True'. Remove or refactor the condition(s) to avoid dead code.
            GetBasicResultAt(5, 12, @"param = """"", "True"),
            // Test0.vb(8,12): warning CA1508: '"" <> param' is always 'False'. Remove or refactor the condition(s) to avoid dead code.
            GetBasicResultAt(8, 12, @""""" <> param", "False"));
        }
 
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.ValueContentAnalysis)]
        [Fact]
        public async Task SimpleValueCompare_AfterAssignment_DiagnosticAsync()
        {
            await VerifyCSharpAnalyzerAsync(@"
class Test
{
    void M1(int param)
    {
        param = 0;
        if (param == 0)
        {
        }
 
        if (0 != param)
        {
        }
    }
}
",
            // Test0.cs(7,13): warning CA1508: 'param == 0' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
            GetCSharpResultAt(7, 13, @"param == 0", "true"),
            // Test0.cs(11,13): warning CA1508: '0 != param' is always 'false'. Remove or refactor the condition(s) to avoid dead code.
            GetCSharpResultAt(11, 13, @"0 != param", "false"));
 
            await VerifyBasicAnalyzerAsync(@"
Module Test
    Sub M1(param As Integer)
        param = 0
        If param = 0 Then
        End If
 
        If 0 <> param Then
        End If
    End Sub
End Module",
            // Test0.vb(5,12): warning CA1508: 'param = 0' is always 'True'. Remove or refactor the condition(s) to avoid dead code.
            GetBasicResultAt(5, 12, @"param = 0", "True"),
            // Test0.vb(8,12): warning CA1508: '0 <> param' is always 'False'. Remove or refactor the condition(s) to avoid dead code.
            GetBasicResultAt(8, 12, @"0 <> param", "False"));
        }
 
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.ValueContentAnalysis)]
        [Fact]
        public async Task ElseIf_NestedIf_StringCompare_DiagnosticAsync()
        {
            await VerifyCSharpAnalyzerAsync(@"
class Test
{
    void M1(string param)
    {
        string str = """";
        if (param != """")
        {
        }
        else if (param == str)
        {
        }
 
        if ("""" == param)
        {
            if (param != str)
            {
            }
        }
    }
}
",
            // Test0.cs(10,18): warning CA1508: 'param == str' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
            GetCSharpResultAt(10, 18, "param == str", "true"),
            // Test0.cs(16,17): warning CA1508: 'param != str' is always 'false'. Remove or refactor the condition(s) to avoid dead code.
            GetCSharpResultAt(16, 17, "param != str", "false"));
 
            await VerifyBasicAnalyzerAsync(@"
Module Test
    Sub M1(param As String)
        Dim str = """"
        If param <> """" Then
        Else If param = str Then
        End If
 
        If """" = param Then
            If param <> str Then
            End If
        End If
    End Sub
End Module",
            // Test0.vb(6,17): warning CA1508: 'param = str' is always 'True'. Remove or refactor the condition(s) to avoid dead code.
            GetBasicResultAt(6, 17, "param = str", "True"),
            // Test0.vb(10,16): warning CA1508: 'param <> str' is always 'False'. Remove or refactor the condition(s) to avoid dead code.
            GetBasicResultAt(10, 16, "param <> str", "False"));
        }
 
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.ValueContentAnalysis)]
        [Fact]
        public async Task ConditionaAndOrStringCompare_DiagnosticAsync()
        {
            await VerifyCSharpAnalyzerAsync(@"
class Test
{
    void M1(string param)
    {
        string str = """";
        if (param != """" || param == str)
        {
        }
 
        if ("""" == param && param != str)
        {
        }
    }
}
",
            // Test0.cs(7,28): warning CA1508: 'param == str' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
            GetCSharpResultAt(7, 28, "param == str", "true"),
            // Test0.cs(11,28): warning CA1508: 'param != str' is always 'false'. Remove or refactor the condition(s) to avoid dead code.
            GetCSharpResultAt(11, 28, "param != str", "false"));
 
            await VerifyBasicAnalyzerAsync(@"
Module Test
    Sub M1(param As String)
        Dim str = """"
        If param <> """" OrElse param = str Then
        End If
 
        If """" = param AndAlso param <> str Then
        End If
    End Sub
End Module",
            // Test0.vb(5,31): warning CA1508: 'param = str' is always 'True'. Remove or refactor the condition(s) to avoid dead code.
            GetBasicResultAt(5, 31, "param = str", "True"),
            // Test0.vb(8,31): warning CA1508: 'param <> str' is always 'False'. Remove or refactor the condition(s) to avoid dead code.
            GetBasicResultAt(8, 31, "param <> str", "False"));
        }
 
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.ValueContentAnalysis)]
        [Fact]
        public async Task ElseIf_NestedIf_StringCompare_DifferentLiteral_DiagnosticAsync()
        {
            await VerifyCSharpAnalyzerAsync(@"
class Test
{
    void M1(string param)
    {
        string str = ""a"";
        if (param != """")
        {
        }
        else if (param == str)
        {
        }
 
        if ("""" == param)
        {
            if (param != str)
            {
            }
        }
    }
}
",
            // Test0.cs(10,18): warning CA1508: 'param == str' is always 'false'. Remove or refactor the condition(s) to avoid dead code.
            GetCSharpResultAt(10, 18, "param == str", "false"),
            // Test0.cs(16,17): warning CA1508: 'param != str' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
            GetCSharpResultAt(16, 17, "param != str", "true"));
 
            await VerifyBasicAnalyzerAsync(@"
Module Test
    Sub M1(param As String)
        Dim str = ""a""
        If param <> """" Then
        Else If param = str Then
        End If
 
        If """" = param Then
            If param <> str Then
            End If
        End If
    End Sub
End Module",
            // Test0.vb(6,17): warning CA1508: 'param = str' is always 'False'. Remove or refactor the condition(s) to avoid dead code.
            GetBasicResultAt(6, 17, "param = str", "False"),
            // Test0.vb(10,16): warning CA1508: 'param <> str' is always 'True'. Remove or refactor the condition(s) to avoid dead code.
            GetBasicResultAt(10, 16, "param <> str", "True"));
        }
 
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.ValueContentAnalysis)]
        [Fact]
        public async Task ElseIf_NestedIf_ValueCompare_DifferentLiteral_DiagnosticAsync()
        {
            await VerifyCSharpAnalyzerAsync(@"
class Test
{
    void M1(int param)
    {
        long str = 0;
        if (param != 1)
        {
        }
        else if (param == str)
        {
        }
 
        if (1 == param)
        {
            if (param != str)
            {
            }
        }
    }
}
",
            // Test0.cs(10,18): warning CA1508: 'param == str' is always 'false'. Remove or refactor the condition(s) to avoid dead code.
            GetCSharpResultAt(10, 18, "param == str", "false"),
            // Test0.cs(16,17): warning CA1508: 'param != str' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
            GetCSharpResultAt(16, 17, "param != str", "true"));
 
            await VerifyBasicAnalyzerAsync(@"
Module Test
    Sub M1(param As Integer)
        Dim str As Long = 0
        If param <> 1 Then
        Else If param = str Then
        End If
 
        If 1 = param Then
            If param <> str Then
            End If
        End If
    End Sub
End Module",
            // Test0.vb(6,17): warning CA1508: 'param = str' is always 'False'. Remove or refactor the condition(s) to avoid dead code.
            GetBasicResultAt(6, 17, "param = str", "False"),
            // Test0.vb(10,16): warning CA1508: 'param <> str' is always 'True'. Remove or refactor the condition(s) to avoid dead code.
            GetBasicResultAt(10, 16, "param <> str", "True"));
        }
 
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.ValueContentAnalysis)]
        [Fact]
        public async Task ElseIf_NestedIf_StringCompare_DifferentLiterals_NoDiagnosticAsync()
        {
            await VerifyCSharpAnalyzerAsync(@"
class Test
{
    void M1(string param, bool flag)
    {
        string str = flag ? ""a"" : """";
        if (param != """")
        {
        }
        else if (param == str)
        {
        }
 
        if ("""" == param)
        {
            if (param != str)
            {
            }
        }
    }
}
");
 
            await VerifyBasicAnalyzerAsync(@"
Module Test
    Sub M1(param As String, flag As Boolean)
        Dim str = If(flag, ""a"", """")
        If param <> """" Then
        Else If param = str Then
        End If
 
        If """" = param Then
            If param <> str Then
            End If
        End If
    End Sub
End Module");
        }
 
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.ValueContentAnalysis)]
        [Fact]
        public async Task ElseIf_NestedIf_ValueCompare_DifferentLiterals_NoDiagnosticAsync()
        {
            await VerifyCSharpAnalyzerAsync(@"
class Test
{
    void M1(ulong param, bool flag)
    {
        var str = (byte)(flag ? 0 : 1);
        if (param != 1)
        {
        }
        else if (param == str)
        {
        }
 
        if (1 == param)
        {
            if (param != str)
            {
            }
        }
    }
}
");
 
            await VerifyBasicAnalyzerAsync(@"
Module Test
    Sub M1(param As ULong, flag As Boolean)
        Dim str As Short = If(flag, 0, 1)
        If param <> 1 Then
        Else If param = str Then
        End If
 
        If 1 = param Then
            If param <> str Then
            End If
        End If
    End Sub
End Module");
        }
 
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.ValueContentAnalysis)]
        [Fact]
        public async Task StringCompare_WhileLoopAsync()
        {
            await VerifyCSharpAnalyzerAsync(@"
class Test
{
    void M(string param)
    {
        string str = """";
        while (param == str)
        {
            // param = str here
            if (param == str)
            {
            }
            if (param != str)
            {
            }
        }
 
        // param is unknown here
        if (str == param)
        {
        }
        if (str != param)
        {
        }
    }
}
",
            // Test0.cs(10,17): warning CA1508: 'param == str' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
            GetCSharpResultAt(10, 17, "param == str", "true"),
            // Test0.cs(13,17): warning CA1508: 'param != str' is always 'false'. Remove or refactor the condition(s) to avoid dead code.
            GetCSharpResultAt(13, 17, "param != str", "false"));
 
            await VerifyBasicAnalyzerAsync(@"
Module Test
    ' While loop
    Private Sub M1(ByVal param As String)
        Dim str As String = """"
        While param = str
            ' param == str here
            If param = str Then
            End If
            If param <> str Then
            End If
        End While
 
        ' param is unknown here
        If str = param Then
            End If
        If str <> param Then
        End If
    End Sub
End Module",
            // Test0.vb(8,16): warning CA1508: 'param = str' is always 'True'. Remove or refactor the condition(s) to avoid dead code.
            GetBasicResultAt(8, 16, "param = str", "True"),
            // Test0.vb(10,16): warning CA1508: 'param <> str' is always 'False'. Remove or refactor the condition(s) to avoid dead code.
            GetBasicResultAt(10, 16, "param <> str", "False"));
        }
 
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.ValueContentAnalysis)]
        [Fact]
        public async Task ValueCompare_WhileLoopAsync()
        {
            await VerifyCSharpAnalyzerAsync(@"
class Test
{
    void M(double param)
    {
        var str = (float)3.0;
        while (param == str)
        {
            // param = str here
            if (param == str)
            {
            }
            if (param != str)
            {
            }
        }
 
        // param is unknown here
        if (str == param)
        {
        }
        if (str != param)
        {
        }
    }
}
",
            // Test0.cs(10,17): warning CA1508: 'param == str' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
            GetCSharpResultAt(10, 17, "param == str", "true"),
            // Test0.cs(13,17): warning CA1508: 'param != str' is always 'false'. Remove or refactor the condition(s) to avoid dead code.
            GetCSharpResultAt(13, 17, "param != str", "false"));
 
            await VerifyBasicAnalyzerAsync(@"
Module Test
    ' While loop
    Private Sub M1(ByVal param As Double)
        Dim str As Single = 3.0
        While param = str
            ' param == str here
            If param = str Then
            End If
            If param <> str Then
            End If
        End While
 
        ' param is unknown here
        If str = param Then
            End If
        If str <> param Then
        End If
    End Sub
End Module",
            // Test0.vb(8,16): warning CA1508: 'param = str' is always 'True'. Remove or refactor the condition(s) to avoid dead code.
            GetBasicResultAt(8, 16, "param = str", "True"),
            // Test0.vb(10,16): warning CA1508: 'param <> str' is always 'False'. Remove or refactor the condition(s) to avoid dead code.
            GetBasicResultAt(10, 16, "param <> str", "False"));
        }
 
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.ValueContentAnalysis)]
        [Fact]
        public async Task StringCompare_DoWhileLoopAsync()
        {
            await VerifyCSharpAnalyzerAsync(@"
class Test
{
    void M(string param)
    {
        string str = """";
        do
        {
            // param is unknown here
            if (str == param)
            {
            }
            if (str != param)
            {
            }
        }
        while (param != str);
 
        // param = str here
        if (param == str)
        {
        }
        if (param != str)
        {
        }
    }
}
",
            // Test0.cs(20,13): warning CA1508: 'param == str' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
            GetCSharpResultAt(20, 13, "param == str", "true"),
            // Test0.cs(23,13): warning CA1508: 'param != str' is always 'false'. Remove or refactor the condition(s) to avoid dead code.
            GetCSharpResultAt(23, 13, "param != str", "false"));
 
            await VerifyBasicAnalyzerAsync(@"
Module Test
    ' Do-While top loop
    Private Sub M(ByVal param As String)
        Dim str As String = """"
        Do While param <> str
            ' param is unknown here
            If str = param Then
                End If
            If str <> param Then
            End If
        Loop
 
        ' param == str here
        If param = str Then
        End If
        If param <> str Then
        End If
    End Sub
 
    ' Do-While bottom loop
    Private Sub M2(ByVal param2 As String)
        Dim str As String = """"
        Do
            ' param2 is unknown here
            If str = param2 Then
                End If
            If str <> param2 Then
            End If
        Loop While param2 <> str
 
        ' param2 == str here
        If param2 = str Then
        End If
        If param2 <> str Then
        End If
    End Sub
End Module",
            // Test0.vb(15,12): warning CA1508: 'param = str' is always 'True'. Remove or refactor the condition(s) to avoid dead code.
            GetBasicResultAt(15, 12, "param = str", "True"),
            // Test0.vb(17,12): warning CA1508: 'param <> str' is always 'False'. Remove or refactor the condition(s) to avoid dead code.
            GetBasicResultAt(17, 12, "param <> str", "False"),
            // Test0.vb(33,12): warning CA1508: 'param2 = str' is always 'True'. Remove or refactor the condition(s) to avoid dead code.
            GetBasicResultAt(33, 12, "param2 = str", "True"),
            // Test0.vb(35,12): warning CA1508: 'param2 <> str' is always 'False'. Remove or refactor the condition(s) to avoid dead code.
            GetBasicResultAt(35, 12, "param2 <> str", "False"));
        }
 
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.ValueContentAnalysis)]
        [Fact]
        public async Task StringCompare_DoUntilLoopAsync()
        {
            await VerifyBasicAnalyzerAsync(@"
Module Test
    ' Do-Until top loop
    Private Sub M(ByVal param As String)
        Dim str As String = """"
        Do Until param <> str
            ' param == str here
            If param = str Then
            End If
            If param <> str Then
            End If
        Loop
 
        ' param is unknown here
        If str = param Then
            End If
        If str <> param Then
        End If
    End Sub
 
    ' Do-Until bottom loop
    Private Sub M2(ByVal param2 As String)
        Dim str As String = """"
        Do
            ' param2 is unknown here
            If str = param2 Then
                End If
            If str <> param2 Then
            End If
        Loop Until param2 = str
 
        ' param2 == str here
        If param2 = str Then
        End If
        If param2 <> str Then
        End If
    End Sub
End Module",
            // Test0.vb(8,16): warning CA1508: 'param = str' is always 'True'. Remove or refactor the condition(s) to avoid dead code.
            GetBasicResultAt(8, 16, "param = str", "True"),
            // Test0.vb(10,16): warning CA1508: 'param <> str' is always 'False'. Remove or refactor the condition(s) to avoid dead code.
            GetBasicResultAt(10, 16, "param <> str", "False"),
            // Test0.vb(33,12): warning CA1508: 'param2 = str' is always 'True'. Remove or refactor the condition(s) to avoid dead code.
            GetBasicResultAt(33, 12, "param2 = str", "True"),
            // Test0.vb(35,12): warning CA1508: 'param2 <> str' is always 'False'. Remove or refactor the condition(s) to avoid dead code.
            GetBasicResultAt(35, 12, "param2 <> str", "False"));
        }
 
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.ValueContentAnalysis)]
        [Fact]
        public async Task StringCompare_ForLoopAsync()
        {
            await VerifyCSharpAnalyzerAsync(@"
class Test
{
    void M(string param, string param2)
    {
        string str = """";
        for (param = str; param2 != str;)
        {
            // param = str here
            if (param == str)
            {
            }
            if (param != str)
            {
            }
 
            // param2 != str here, but we don't track not-contained values so no diagnostic.
            if (param2 == str)
            {
            }
            if (param2 != str)
            {
            }
        }
 
        // param2 == str here
        if (str == param2)
        {
        }
        if (str != param2)
        {
        }
 
        // param == str here
        if (str == param)
        {
        }
        if (str != param)
        {
        }
    }
}
",
            // Test0.cs(10,17): warning CA1508: 'param == str' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
            GetCSharpResultAt(10, 17, "param == str", "true"),
            // Test0.cs(13,17): warning CA1508: 'param != str' is always 'false'. Remove or refactor the condition(s) to avoid dead code.
            GetCSharpResultAt(13, 17, "param != str", "false"),
            // Test0.cs(27,13): warning CA1508: 'str == param2' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
            GetCSharpResultAt(27, 13, "str == param2", "true"),
            // Test0.cs(30,13): warning CA1508: 'str != param2' is always 'false'. Remove or refactor the condition(s) to avoid dead code.
            GetCSharpResultAt(30, 13, "str != param2", "false"),
            // Test0.cs(35,13): warning CA1508: 'str == param' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
            GetCSharpResultAt(35, 13, "str == param", "true"),
            // Test0.cs(38,13): warning CA1508: 'str != param' is always 'false'. Remove or refactor the condition(s) to avoid dead code.
            GetCSharpResultAt(38, 13, "str != param", "false"));
        }
 
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.ValueContentAnalysis)]
        [Fact]
        public async Task IntegralValueCompare_ForLoopAsync()
        {
            await VerifyCSharpAnalyzerAsync(@"
class Test
{
    void M(int param, uint param2)
    {
        int str = 1;
        for (param = str; param2 != str;)
        {
            // param = str here
            if (param == str)
            {
            }
            if (param != str)
            {
            }
 
            // param2 != str here, but we don't track not-contained values so no diagnostic.
            if (param2 == str)
            {
            }
            if (param2 != str)
            {
            }
        }
        
        // param2 == str here
        if (str == param2)
        {
        }
        if (str != param2)
        {
        }
        
        // param == str here
        if (str == param)
        {
        }
        if (str != param)
        {
        }
    }
}
",
            // Test0.cs(10,17): warning CA1508: 'param == str' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
            GetCSharpResultAt(10, 17, "param == str", "true"),
            // Test0.cs(13,17): warning CA1508: 'param != str' is always 'false'. Remove or refactor the condition(s) to avoid dead code.
            GetCSharpResultAt(13, 17, "param != str", "false"),
            // Test0.cs(27,13): warning CA1508: 'str == param2' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
            GetCSharpResultAt(27, 13, "str == param2", "true"),
            // Test0.cs(30,13): warning CA1508: 'str != param2' is always 'false'. Remove or refactor the condition(s) to avoid dead code.
            GetCSharpResultAt(30, 13, "str != param2", "false"),
            // Test0.cs(35,13): warning CA1508: 'str == param' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
            GetCSharpResultAt(35, 13, "str == param", "true"),
            // Test0.cs(38,13): warning CA1508: 'str != param' is always 'false'. Remove or refactor the condition(s) to avoid dead code.
            GetCSharpResultAt(38, 13, "str != param", "false"));
        }
 
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.ValueContentAnalysis)]
        [Fact]
        public async Task IntegralValueCompare_ForLoop_02Async()
        {
            await VerifyCSharpAnalyzerAsync(@"
class Test
{
    void M(int param, string param2, string param3)
    {
        for (int i = 0; i < param; i++)
        {
            var x = i == 0 ? param2 : param3;
        }
    }
}
");
        }
 
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.ValueContentAnalysis)]
        [Fact]
        public async Task EnumValueCompare_ForEachLoopAsync()
        {
            await VerifyCSharpAnalyzerAsync(@"
enum Kind
{
    Kind1 = 1,
    Kind2 = 2
}
 
class Test
{
    private Kind MyKind { get; }
    private Test[] _tests;
 
    void M(int[] array)
    {
        foreach (var x in array)
        {
            var test = GetTest(x);
            if (test.MyKind != Kind.Kind2)
            {
                continue;
            }
 
            M2(test);
        }
    }
 
    Test GetTest(int x) => _tests[x];
    void M2(Test test) { }
}
");
        }
 
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.ValueContentAnalysis)]
        [Fact]
        public async Task EnumValueCompare_ForEachLoop_02Async()
        {
            await VerifyCSharpAnalyzerAsync(@"
enum Kind
{
    Kind1 = 1,
    Kind2 = 2
}
 
class Test
{
    private Kind MyKind { get; }
    private Test[] _tests;
 
    void M(int[] array)
    {
        var kind = Kind.Kind2;
        foreach (var x in array)
        {
            var test = GetTest(x);
            if (test.MyKind != kind)
            {
                continue;
            }
 
            M2(test);
            kind = GetKind(test);
        }
    }
 
    Test GetTest(int x) => _tests[x];
    Kind GetKind(Test t) => t.MyKind;
    void M2(Test test) { }
}
");
        }
 
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.ValueContentAnalysis)]
        [Fact]
        public async Task EnumValueCompare_ForEachLoop_03Async()
        {
            await VerifyCSharpAnalyzerAsync(@"
enum Kind
{
    Kind1 = 1,
    Kind2 = 2
}
 
class Test
{
    private Kind MyKind { get; }
    private Test[] _tests;
 
    void M(int[] array)
    {
        var kind = Kind.Kind2;
        foreach (var x in array)
        {
            var test = GetTest(x);
            var testKind = test.MyKind;
            if (testKind == kind &&
                testKind != Kind.Kind2) // Redundant check as 'kind' is always 'Kind.Kind2'
            {
                continue;
            }
 
            M2(test);
        }
    }
 
    Test GetTest(int x) => _tests[x];
    void M2(Test test) { }
}
",
            // Test0.cs(21,17): warning CA1508: 'Kind.Kind2 != Kind.Kind2' is always 'false'. Remove or refactor the condition(s) to avoid dead code.
            GetCSharpResultAt(21, 17, "testKind != Kind.Kind2", "false"));
        }
 
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.ValueContentAnalysis)]
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.CopyAnalysis)]
        [Fact]
        public async Task StringCompare_CopyAnalysisAsync()
        {
            await VerifyCSharpAnalyzerAsync(@"
class Test
{
    void M1(string param, string param2)
    {
        string str = ""a"";
        if (param == str && param2 == str && param == param2)
        {
        }
 
        param = param2;
        if (param != str || param2 != str)
        {
        }
    }
}
",
            // Test0.cs(7,46): warning CA1508: 'param == param2' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
            GetCSharpResultAt(7, 46, "param == param2", "true"),
            // Test0.cs(12,29): warning CA1508: 'param2 != str' is always 'false'. Remove or refactor the condition(s) to avoid dead code.
            GetCSharpResultAt(12, 29, "param2 != str", "false"));
 
            await VerifyBasicAnalyzerAsync(@"
Module Test
    Sub M1(param As String, param2 As String)
        Dim str = ""a""
        If param = str AndAlso param2 = str AndAlso param = param2 Then
        End If
 
        param = param2
        If param <> str OrElse param2 <> str Then
        End If
    End Sub
End Module",
            // Test0.vb(5,53): warning CA1508: 'param = param2' is always 'True'. Remove or refactor the condition(s) to avoid dead code.
            GetBasicResultAt(5, 53, "param = param2", "True"),
            // Test0.vb(9,32): warning CA1508: 'param2 <> str' is always 'False'. Remove or refactor the condition(s) to avoid dead code.
            GetBasicResultAt(9, 32, "param2 <> str", "False"));
        }
 
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.ValueContentAnalysis)]
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.CopyAnalysis)]
        [Fact]
        public async Task ValueCompare_CopyAnalysisAsync()
        {
            await VerifyCSharpAnalyzerAsync(@"
class Test
{
    void M1(int param, int param2)
    {
        int str = 0;
        if (param == str && param2 == str && param == param2)
        {
        }
 
        param = param2;
        if (param != str || param2 != str)
        {
        }
    }
}
",
            // Test0.cs(7,46): warning CA1508: 'param == param2' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
            GetCSharpResultAt(7, 46, "param == param2", "true"),
            // Test0.cs(12,29): warning CA1508: 'param2 != str' is always 'false'. Remove or refactor the condition(s) to avoid dead code.
            GetCSharpResultAt(12, 29, "param2 != str", "false"));
 
            await VerifyBasicAnalyzerAsync(@"
Module Test
    Sub M1(param As Integer, param2 As Integer)
        Dim str As Integer = 1
        If param = str AndAlso param2 = str AndAlso param = param2 Then
        End If
 
        param = param2
        If param <> str OrElse param2 <> str Then
        End If
    End Sub
End Module",
            // Test0.vb(5,53): warning CA1508: 'param = param2' is always 'True'. Remove or refactor the condition(s) to avoid dead code.
            GetBasicResultAt(5, 53, "param = param2", "True"),
            // Test0.vb(9,32): warning CA1508: 'param2 <> str' is always 'False'. Remove or refactor the condition(s) to avoid dead code.
            GetBasicResultAt(9, 32, "param2 <> str", "False"));
        }
 
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.ValueContentAnalysis)]
        [Fact]
        public async Task StringCompare_WithNonLiteral_ConditionalOr_NoDiagnosticAsync()
        {
            await VerifyCSharpAnalyzerAsync(@"
class Test
{
    void M1(string param, string param2, bool flag)
    {
        string str = """";
        string str2 = flag ? ""a"" : ""b"";
        string strMayBeConst = param2;
 
        if (param == str || param == str2)
        {
        }
 
        if (str2 != param || param == strMayBeConst)
        {
        }
 
        if (param == strMayBeConst || str2 != param)
        {
        }
    }
}
");
 
            await VerifyBasicAnalyzerAsync(@"
Module Test
    Sub M1(param As String, param2 As String, flag As Boolean)
        Dim str = """"
        Dim str2 = If(flag, ""a"", ""b"")
        Dim strMayBeConst = param2
 
        If param = str OrElse param = str2 Then
        End If
 
        If str2 <> param OrElse param = strMayBeConst Then
        End If
 
        If param = strMayBeConst OrElse str2 <> param Then
        End If
    End Sub
End Module");
        }
 
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.ValueContentAnalysis)]
        [Fact]
        public async Task ValueCompare_WithNonLiteral_ConditionalOr_NoDiagnosticAsync()
        {
            await VerifyCSharpAnalyzerAsync(@"
class Test
{
    void M1(uint param, uint param2, bool flag)
    {
        long str = 1;
        ulong str2 = flag ? 2UL : 3UL;
        ulong strMayBeConst = param2;
 
        if (param == str || param == str2)
        {
        }
 
        if (str2 != param || param == strMayBeConst)
        {
        }
 
        if (param == strMayBeConst || str2 != param)
        {
        }
    }
}
");
 
            await VerifyBasicAnalyzerAsync(@"
Module Test
    Sub M1(param As UInteger, param2 As UInteger, flag As Boolean)
        Dim str As Long = 1
        Dim str2 As ULong = DirectCast(If(flag, 2UL, 3UL), ULong)
        Dim strMayBeConst As Ulong = param2
 
        If param = str OrElse param = str2 Then
        End If
 
        If str2 <> param OrElse param = strMayBeConst Then
        End If
 
        If param = strMayBeConst OrElse str2 <> param Then
        End If
    End Sub
End Module");
        }
 
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.ValueContentAnalysis)]
        [Fact]
        public async Task StringCompare_WithNonLiteral_ConditionalAnd_NoDiagnosticAsync()
        {
            await VerifyCSharpAnalyzerAsync(@"
class Test
{
    void M1(string param, string param2, bool flag)
    {
        string str = """";
        string str2 = flag ? ""a"" : ""b"";
        string strMayBeConst = param2;
 
        if (param == str && param2 == str2)
        {
        }
 
        if (param == strMayBeConst && str2 == param)
        {
        }
 
        if (param != str && param != str2)
        {
        }
 
        if (param != str && param2 != str2)
        {
        }
 
        if (str2 != param && param == strMayBeConst)
        {
        }
    }
}
");
 
            await VerifyBasicAnalyzerAsync(@"
Module Test
    Sub M1(param As String, param2 As String, flag As Boolean)
        Dim str = """"
        Dim str2 = If(flag, ""a"", ""b"")
        Dim strMayBeConst = param2
 
        If param = str AndAlso param2 = str2 Then
        End If
 
        If param = strMayBeConst AndAlso str2 = param Then
        End If
 
        If str2 <> param AndAlso param <> str Then
        End If
 
        If str2 <> param AndAlso param2 <> str Then
        End If
 
        If str2 <> param AndAlso param = strMayBeConst Then
        End If
    End Sub
End Module");
        }
 
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.ValueContentAnalysis)]
        [Fact]
        public async Task ValueCompare_WithNonLiteral_ConditionalAnd_NoDiagnosticAsync()
        {
            await VerifyCSharpAnalyzerAsync(@"
class Test
{
    void M1(int param, int param2, bool flag)
    {
        int str = 1;
        int str2 = flag ? 2 : 3;
        int strMayBeConst = param2;
 
        if (param == str && param2 == str2)
        {
        }
 
        if (param == strMayBeConst && str2 == param)
        {
        }
 
        if (param != str && param != str2)
        {
        }
 
        if (param != str && param2 != str2)
        {
        }
 
        if (str2 != param && param == strMayBeConst)
        {
        }
    }
}
");
 
            await VerifyBasicAnalyzerAsync(@"
Module Test
    Sub M1(param As Integer, param2 As Integer, flag As Boolean)
        Dim str As Integer = 1
        Dim str2 As Integer = If(flag, 2, 3)
        Dim strMayBeConst As Integer = param2
 
        If param = str AndAlso param2 = str2 Then
        End If
 
        If param = strMayBeConst AndAlso str2 = param Then
        End If
 
        If str2 <> param AndAlso param <> str Then
        End If
        
        If str2 <> param AndAlso param2 <> str Then
        End If
        
        If str2 <> param AndAlso param = strMayBeConst Then
        End If
    End Sub
End Module");
        }
 
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.ValueContentAnalysis)]
        [Fact]
        public async Task StringCompare_ConditionalAndOrNegation_NoDiagnosticAsync()
        {
            await VerifyCSharpAnalyzerAsync(@"
class Test
{
    void M1(string param, bool flag, string param2)
    {
        string strConst = """";
        string strConst2 = flag ? ""a"" : """";
        string strMayBeNonConst = flag ? ""c"" : param2;
 
        if (param == strConst || !(strConst2 != param) && param != strMayBeNonConst)
        {
        }
 
        if (!(strConst2 == param && !(param != strConst)) || param == strMayBeNonConst)
        {
        }
 
        if (param != strConst && !(strConst2 != param || param != strMayBeNonConst))
        {
        }
    }
}
");
 
            await VerifyBasicAnalyzerAsync(@"
Module Test
    Sub M1(param As String, param2 As String, flag As Boolean)
        Dim strConst As String = """"
        Dim strConst2 As String = If(flag, ""a"", """")
        Dim strMayBeNonConst As String = If(flag, ""c"", param2)
 
        If param = strConst OrElse Not(strConst2 <> param) AndAlso param <> strMayBeNonConst Then
        End If
 
        If Not(strConst2 = param AndAlso Not (param <> strConst)) OrElse param <> strMayBeNonConst Then
        End If
 
        If param <> strConst AndAlso Not(strConst2 <> param OrElse param <> strMayBeNonConst) Then
        End If
    End Sub
End Module");
        }
 
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.ValueContentAnalysis)]
        [Fact]
        public async Task StringCompare_ConditionalAndOrNegation_DiagnosticAsync()
        {
            await VerifyCSharpAnalyzerAsync(@"
class Test
{
    void M1(string param, bool flag, string param2, string param3)
    {
        string strConst = """";
        string strConst2 = flag ? ""a"" : """";
        string strMayBeNonConst = flag ? ""c"" : param2;
 
        // First and last conditions are opposites, so infeasible.
        if (param == strConst && !(strConst2 != param || param != strConst))
        {
        }
 
        // First and last conditions are identical.
        if (param == strConst && !(strConst2 != param || param == strConst)){
        }
 
        // Comparing with maybe const, no diagnostic
        if (param3 == strConst && !(strConst2 == param3 || param3 == strMayBeNonConst))
        {
        }
 
        // We don't track not-equals values, no diagnostic
        if (param3 != strConst && !(strConst2 != param3 || param3 != strConst))
        {
        }
    }
}
",
            // Test0.cs(11,58): warning CA1508: 'param != strConst' is always 'false'. Remove or refactor the condition(s) to avoid dead code.
            GetCSharpResultAt(11, 58, "param != strConst", "false"),
            // Test0.cs(16,58): warning CA1508: 'param == strConst' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
            GetCSharpResultAt(16, 58, "param == strConst", "true"));
 
            await VerifyBasicAnalyzerAsync(@"
Module Test
    Sub M1(param As String, param2 As String, flag As Boolean, param3 As String)
        Dim strConst As String = """"
        Dim strConst2 As String = If(flag, ""a"", """")
        Dim strMayBeNonConst As String = If(flag, ""c"", param2)
 
        ' First and last conditions are opposites, so infeasible.
        If param = strConst AndAlso Not(strConst2 <> param OrElse param <> strConst) Then
        End If
 
        ' First and last conditions are identical.
        If param = strConst AndAlso Not(strConst2 <> param OrElse param = strConst) Then
        End If
 
        ' Comparing with maybe const, no diagnostic
        If param3 = strConst AndAlso Not(strConst2 = param3 OrElse param3 = strMayBeNonConst) Then
        End If
 
        ' We don't track not-equals values, no diagnostic
        If param3 <> strConst AndAlso Not(strConst2 <> param3 OrElse param3 <> strConst) Then
        End If
    End Sub
End Module",
            // Test0.vb(9,67): warning CA1508: 'param <> strConst' is always 'False'. Remove or refactor the condition(s) to avoid dead code.
            GetBasicResultAt(9, 67, "param <> strConst", "False"),
            // Test0.vb(13,67): warning CA1508: 'param = strConst' is always 'True'. Remove or refactor the condition(s) to avoid dead code.
            GetBasicResultAt(13, 67, "param = strConst", "True"));
        }
 
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.ValueContentAnalysis)]
        [Fact]
        public async Task StringCompare_ContractCheck_NoDiagnosticAsync()
        {
            await VerifyCSharpAnalyzerAsync(@"
class Test
{
    void M1(string param)
    {
        System.Diagnostics.Contracts.Contract.Requires(param != """");
    }
 
    void M2(string param, string param2)
    {
        param2 = """";
        System.Diagnostics.Contracts.Contract.Requires(param == """" || param2 != param);
    }
 
    void M3(string param, string param2, string param3)
    {
        System.Diagnostics.Contracts.Contract.Requires(param == param2 && !(param2 != """") || param2 == param3);
    }
}
");
 
            await VerifyBasicAnalyzerAsync(@"
Module Test
    Private Sub M1(ByVal param As String)
        System.Diagnostics.Contracts.Contract.Requires(param <> """")
    End Sub
 
    Private Sub M2(ByVal param As String, ByVal param2 As String)
        param2 = """"
        System.Diagnostics.Contracts.Contract.Requires(param = """" OrElse param2 <> param)
    End Sub
 
    Private Sub M3(ByVal param As String, ByVal param2 As String, param3 As String)
        System.Diagnostics.Contracts.Contract.Requires(param = param2 AndAlso Not(param2 <> """") OrElse param2 = param3)
    End Sub
End Module");
        }
 
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.ValueContentAnalysis)]
        [Fact]
        public async Task StringCompare_ContractCheck_DiagnosticAsync()
        {
            await VerifyCSharpAnalyzerAsync(@"
class Test
{
    void M(string param)
    {
        var str = """";
        param = """";
        System.Diagnostics.Contracts.Contract.Requires(param == str);
    }
}
",
            // Test0.cs(8,56): warning CA1508: 'param == str' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
            GetCSharpResultAt(8, 56, "param == str", "true"));
 
            await VerifyBasicAnalyzerAsync(@"
Module Test
    Private Sub M(ByVal param As String)
        Dim str = """"
        param = """"
        System.Diagnostics.Contracts.Contract.Requires(param <> str)
    End Sub
End Module",
            // Test0.vb(6,56): warning CA1508: 'param <> str' is always 'False'. Remove or refactor the condition(s) to avoid dead code.
            GetBasicResultAt(6, 56, "param <> str", "False"));
        }
 
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.ValueContentAnalysis)]
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.CopyAnalysis)]
        [Fact, WorkItem(1650, "https://github.com/dotnet/roslyn-analyzers/issues/1650")]
        public async Task StringCompare_InsideConstructorInitializer_DiagnosticAsync()
        {
            await VerifyCSharpAnalyzerAsync(@"
class C
{
    public bool Flag;
}
 
class Base
{
    protected Base(bool b) { }
}
 
class Test : Base
{
    public Test(string s1, string s2, string s3)
        : base(s1 == s2 && s2 == s3 ? (s1 == s3) : false)
    {
        var x = s1 == s3;
    }
}
",
            // Test0.cs(15,40): warning CA1508: 's1 == s3' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
            GetCSharpResultAt(15, 40, "s1 == s3", "true"));
        }
 
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.ValueContentAnalysis)]
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.CopyAnalysis)]
        [Fact, WorkItem(1650, "https://github.com/dotnet/roslyn-analyzers/issues/1650")]
        public async Task StringCompare_InsideFieldInitializer_DiagnosticAsync()
        {
            await VerifyCSharpAnalyzerAsync(@"
class C
{
    public bool Flag;
}
 
class Test
{
    private static string s1, s2, s3;
    private bool b = s1 == s2 && s2 == s3 ? (s1 == s3) : false;
}
",
            // Test0.cs(10,46): warning CA1508: 's1 == s3' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
            GetCSharpResultAt(10, 46, "s1 == s3", "true"));
        }
 
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.ValueContentAnalysis)]
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.CopyAnalysis)]
        [Fact, WorkItem(1650, "https://github.com/dotnet/roslyn-analyzers/issues/1650")]
        public async Task StringCompare_InsidePropertyInitializer_ExpressionBody_DiagnosticAsync()
        {
            await VerifyCSharpAnalyzerAsync(@"
class C
{
    public bool Flag;
}
 
class Test
{
    private static string s1, s2, s3, s4, s5, s6;
    private bool B1 => s1 == s2 && s2 == s3 ? (s1 == s3) : false;
    private bool B2 { get; } = s4 == s5 && s5 == s6 ? (s4 == s6) : false;
}
",
            // Test0.cs(10,48): warning CA1508: 's1 == s3' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
            GetCSharpResultAt(10, 48, "s1 == s3", "true"),
            // Test0.cs(11,56): warning CA1508: 's4 == s6' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
            GetCSharpResultAt(11, 56, "s4 == s6", "true"));
        }
 
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.CopyAnalysis)]
        [Fact]
        public async Task ValueCompare_IsConstantPattern_DiagnosticAsync()
        {
            await VerifyCSharpAnalyzerAsync(@"
class C
{
}
 
class D: C
{
}
 
class Test
{
    void M1_IsConstantPattern_AlwaysTrue(int c1)
    {
        c1 = 5;
        if (c1 is 5)
        {
            return;
        }
    }
 
    void M1_IsConstantPattern_AlwaysFalse(int c2)
    {
        c2 = 10;
        if (c2 is 5)
        {
            return;
        }
    }
 
    void M1_IsConstantPattern_Conversion_AlwaysTrue(short c3)
    {
        c3 = (short)5;
        if (c3 is 5)
        {
            return;
        }
    }
}
",
            // Test0.cs(15,13): warning CA1508: 'c1 is 5' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
            GetCSharpResultAt(15, 13, "c1 is 5", "true"),
            // Test0.cs(24,13): warning CA1508: 'c2 is 5' is always 'false'. Remove or refactor the condition(s) to avoid dead code.
            GetCSharpResultAt(24, 13, "c2 is 5", "false"),
            // Test0.cs(33,13): warning CA1508: 'c3 is 5' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
            GetCSharpResultAt(33, 13, "c3 is 5", "true"));
 
            // VB does not support patterns.
        }
 
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.CopyAnalysis)]
        [Fact]
        public async Task ValueCompare_IsConstantPattern_NoDiagnosticAsync()
        {
            await VerifyCSharpAnalyzerAsync(@"
class C
{
}
 
class D: C
{
}
 
class Test
{
    void M1_IsConstantPattern(int c1)
    {
        if (c1 is 5)
        {
            return;
        }
    }
 
    void M1_IsConstantPattern_02(int c2, bool flag)
    {
        if (flag)
        {
            c2 = 5;
        }
 
        if (c2 is 5)
        {
            return;
        }
    }
}
");
 
            // VB does not support patterns.
        }
 
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.CopyAnalysis)]
        [Fact]
        public async Task ValueCompare_GotoLoopAsync()
        {
            // Ensure we bound the number of value content literals
            // and avoid infinite analysis iterations.
            await VerifyCSharpAnalyzerAsync(@"
class C
{
    internal static uint ComputeStringHash(string text)
    {
        uint hashCode = 0;
        if (text != null)
        {
            hashCode = unchecked((uint)2166136261);
 
            int i = 0;
            goto start;
 
again:
            hashCode = unchecked((text[i] ^ hashCode) * 16777619);
            i = i + 1;
 
start:
            if (i < text.Length)
                goto again;
        }
        return hashCode;
    }
}");
        }
 
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.CopyAnalysis)]
        [Fact]
        public async Task ValueCompare_MayBeLiteralAssignedInLoopAsync()
        {
            await VerifyCSharpAnalyzerAsync(@"
using System.Diagnostics;
 
class C
{
    public int Int { get; }
    public C[] ArrayOfC { get; }
    void M(int x)
    {
        int lastOffset = -1;
        foreach (var c in ArrayOfC)
        {
            int offset = c.Int;
            if (offset >= 0)
            {
                if (lastOffset != offset)
                {
                    Debug.Assert(lastOffset < offset);
                    Debug.Assert((lastOffset >= 0) || (offset == 0));
                    lastOffset = offset;
                }
                else
                {
                    System.Console.Write(offset);
                }
            }
        }
    }
}");
        }
 
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.CopyAnalysis)]
        [Fact]
        public async Task ValueCompare_YieldBreakInTryFinallyAsync()
        {
            await VerifyCSharpAnalyzerAsync(@"
using System.Collections.Generic;
 
class C
{
    private static IEnumerable<IList<T>> M<T>(List<IEnumerator<T>> enumerators)
    {
        try
        {
            while (true)
            {
                for (int i = 0; i < enumerators.Count; i++)
                {
                    var e = enumerators[i];
                    if (!e.MoveNext())
                    {
                        yield break;
                    }
                }
            }
        }
        finally
        {
            foreach (var enumerator in enumerators)
            {
                enumerator.Dispose();
            }
        }
    }
}");
        }
 
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.CopyAnalysis)]
        [Fact]
        public async Task ValueCompare_NullableBoolAsync()
        {
            await VerifyCSharpAnalyzerAsync(@"
class C
{
    private object Field;
    public void M(C c)
    {
        bool? status = c.Field?.Equals(c);
    }
}");
        }
 
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.CopyAnalysis)]
        [Fact]
        public async Task ValueCompare_DefaultExpressionAsync()
        {
            await VerifyCSharpAnalyzerAsync(@"
struct S
{
}
 
class C
{
    public void M(S s)
    {
        if (object.Equals(s, default(S)))
        {
        }
    }
}");
        }
 
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.CopyAnalysis)]
        [Fact]
        public async Task ValueCompare_Boxing_DiagnosticAsync()
        {
            await VerifyCSharpAnalyzerAsync(@"
class C
{
    public void M(int i)
    {
        object o = i;       // Implicit boxing.
        if ((int)o == i)    // Always true.
        {
        }
        
        object o2 = (object)i;    // Explicit boxing with direct cast.
        if ((int)o2 == i)         // Always true.
        {
        }
 
        object o3 = i as object;    // Explicit boxing with try cast.
        if ((int)o3 == i)           // Always true.
        {
        }
 
        if (o == (object)i)    // Always false, but our current implementation is conservative and does not flag it.
        {
        }
    }
}",
    // Test0.cs(7,13): warning CA1508: '(int)o == i' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
    GetCSharpResultAt(7, 13, "(int)o == i", "true"),
    // Test0.cs(12,13): warning CA1508: '(int)o2 == i' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
    GetCSharpResultAt(12, 13, "(int)o2 == i", "true"),
    // Test0.cs(17,13): warning CA1508: '(int)o3 == i' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
    GetCSharpResultAt(17, 13, "(int)o3 == i", "true"));
        }
 
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.CopyAnalysis)]
        [Fact]
        public async Task ValueCompare_Boxing_NoDiagnosticAsync()
        {
            await VerifyCSharpAnalyzerAsync(@"
class C
{
    public void M(int i, int i2, int i3, int i4)
    {
        object o = i;       // Implicit boxing.
        i = 1;
        if ((int)o == i)    // May or may not be true.
        {
        }
        if (o is 1)         // May or may not be true.
        {
        }
        
        object o2 = (object)i2;    // Explicit boxing with direct cast.
        i2 = 2;
        if ((int)o2 == i2)         // May or may not be true.
        {
        }
        if (o2 is 2)               // May or may not be true.
        {
        }
 
        object o3 = i3;       // Implicit boxing.
        o3 = 3;
        if ((int)o3 == i3)    // May or may not be true.
        {
        }
        if (i3 == 3)           // May or may not be true.
        {
        }
 
        object o4 = (object)i4;    // Explicit boxing with direct cast.
        o4 = 4;
        if ((int)o4 == i4)         // May or may not be true.
        {
        }
        if (i4 == 4)               // May or may not be true.
        {
        }
    }
}");
        }
 
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.CopyAnalysis)]
        [Fact]
        public async Task ValueCompare_Unboxing_DiagnosticAsync()
        {
            await VerifyCSharpAnalyzerAsync(@"
class C
{
    public void M(object o, object o2, object o3)
    {
        var i = (int)o;         // Explicit unboxing with direct cast.
        if ((int)o == i)        // Always true.
        {
        }
 
        if (o == (object)i)     // Always false, but our current implementation is conservative and does not flag it.
        {
        }
 
        var i2 = o2 as int?;    // Explicit unboxing with try cast involving nullable types.
        if ((int)o2 == i2)      // Always true, but our current implementation is conservative and does not flag it.
        {
        }
 
        if (o2 == (object)i2)   // Always false, but our current implementation is conservative and does not flag it.
        {
        }
    }
}",
            // Test0.cs(7,13): warning CA1508: '(int)o == i' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
            GetCSharpResultAt(7, 13, "(int)o == i", "true"));
        }
 
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.CopyAnalysis)]
        [Fact]
        public async Task ValueCompare_Unboxing_NoDiagnosticAsync()
        {
            await VerifyCSharpAnalyzerAsync(@"
class C
{
    public void M(object o, object o2, object o3, object o4)
    {
        var i = (int)o;         // Explicit unboxing with direct cast.
        i = 1;
        if ((int)o == i)        // May or may not be true.
        {
        }
 
        var i2 = (int)o2;         // Explicit unboxing with direct cast.
        o2 = 2;
        if ((int)o2 == i2)        // May or may not be true.
        {
        }
 
        var i3 = o3 as int?;    // Explicit unboxing with try cast involving nullable types.
        i3 = 3;
        if ((int)o3 == i3)      // May or may not be true.
        {
        }
 
        var i4 = o4 as int?;    // Explicit unboxing with try cast involving nullable types.
        o4 = 4;
        if ((int)o4 == i4)      // May or may not be true.
        {
        }
    }
}");
        }
 
        [Fact, WorkItem(1571, "https://github.com/dotnet/roslyn-analyzers/issues/1571")]
        public async Task ValueCompare_AssignedToTuple_NotDisposed_SpecialCases_DiagnosticAsync()
        {
            // NOTE: We do not support predicate analysis for tuple binary operator comparison yet.
            await new VerifyCS.Test
            {
                TestState =
                {
                    Sources =
                    {
                        @"
using System;
 
class A
{
    public A(int i) { }
}
 
public class Test
{
    // Tuple binary compare with nested tuple.    
    ((A, int), (A, int)) M1()
    {
        A a = new A(1);
        A a2 = new A(2);
        ((A, int), (A, int)) b = ((a2, 0), (a2, 0));
        var b2 = ((a2, 0), (a2, 0));
        if (b == b2)    // This should get flagged as always 'true' once we implement predicate analysis for ITupleBinaryOperation
        {
        }
 
        return b;
    }
 
    // Declaration expression target
    A M2()
    {
        A a = new A(3);
        var ((a2, x), y) = ((a, 0), 1);
        if (a2 == a)
        {
        }
 
        return null;
    }
 
    // Declaration expression target with discards
    A M3()
    {
        A a = new A(4);
        var ((a2, _), _) = ((a, 0), 1);
        if (a2 == null)
        {
        }
 
        return null;
    }
 
    // Declaration expressions in target
    A M4()
    {
        A a = new A(5);
        ((var a2, var x), var y) = ((a, 0), 1);
        if (a == a2 || x == 0 || y == 1)
        {
        }
 
        return null;
    }
 
    // Discards in target
    A M5()
    {
        A a = new A(6);
        ((var a2, _), _) = ((a, 0), 1);
        if (null == a2)
        {
        }
 
        return null;
    }
 
    // Tuple binary compare
    (A, A) M6()
    {
        A a = new A(7);
        A a2 = new A(8);
        var c = (a2, a2);
        var c2 = (a2, a2);
        if (c == c2)        // This should get flagged as always 'true' once we implement predicate analysis for ITupleBinaryOperation
        {
        }
 
        var c3 = (a2, a);
        if (c == c3)        // This should get flagged as always 'false' once we implement predicate analysis for ITupleBinaryOperation
        {
        }
 
        var c4 = (a, a);
        if (c == c4)        // This should get flagged as always 'false' once we implement predicate analysis for ITupleBinaryOperation
        {
        }
 
        return c;
    }
}
"
                    },
                    AnalyzerConfigFiles = { ("/.editorconfig", @"root = true
 
[*]
dotnet_code_quality.copy_analysis = true") },
                    ExpectedDiagnostics =
                    {
                        // Test0.cs(30,13): warning CA1508: 'a2 == a' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
                        GetCSharpResultAt(30, 13, "a2 == a", "true"),
                        // Test0.cs(42,13): warning CA1508: 'a2 == null' is always 'false'. Remove or refactor the condition(s) to avoid dead code.
                        GetCSharpResultAt(42, 13, "a2 == null", "false"),
                        // Test0.cs(54,13): warning CA1508: 'a == a2' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
                        GetCSharpResultAt(54, 13, "a == a2", "true"),
                        // Test0.cs(54,24): warning CA1508: 'x == 0' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
                        GetCSharpResultAt(54, 24, "x == 0", "true"),
                        // Test0.cs(54,34): warning CA1508: 'y == 1' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
                        GetCSharpResultAt(54, 34, "y == 1", "true"),
                        // Test0.cs(66,13): warning CA1508: 'null == a2' is always 'false'. Remove or refactor the condition(s) to avoid dead code.
                        GetCSharpResultAt(66, 13, "null == a2", "false"),
                    }
                },
                LanguageVersion = CSharpLanguageVersion.CSharp7_3
            }.RunAsync();
        }
 
        [Fact, WorkItem(1571, "https://github.com/dotnet/roslyn-analyzers/issues/1571")]
        public async Task ValueCompare_AddedToTupleLiteral_SpecialCases_DiagnosticAsync()
        {
            await new VerifyCS.Test
            {
                TestState =
                {
                    Sources =
                    {
                        @"
using System;
 
class A
{
    public A(int i) { }
}
 
public class Test
{
    // Tuple literal assignment cases.
    void M1()
    {
        A a = new A(1);
        var x = ((a, 0), 1);
        if (x.Item1.Item1 == a || x.Item1.a == a || x.Item2 == 1)
        {
        }
    }
 
    void M2()
    {
        A a = new A(2);
        A a2 = new A(3);
        var x = (a, a2);
        if (x.a == a || x.Item2 == a2)
        {
        }
    }
 
    void M3(out (A a, A a2) arg)
    {
        A a = new A(4);
        A a2 = new A(5);
        arg = (a, a2);
        arg = default((A, A));  // We don't yet analyze default tuple expression, so below redundant conditionals are not flagged.
        if (arg.Item1 == a || arg.a2 == a2)
        {
        }
    }
 
    void M4(out (A a, A a2) arg)
    {
        A a = new A(6);
        A a2 = new A(7);
        var a3 = (a, a2);
        arg = a3;
        arg = (null, null);
        if (arg.a == a || arg.Item2 == a2)
        {
        }
    }
}
"
                    },
                    AnalyzerConfigFiles = { ("/.editorconfig", @"root = true
 
[*]
dotnet_code_quality.copy_analysis = true") },
                    ExpectedDiagnostics =
                    {
                        // Test0.cs(16,13): warning CA1508: 'x.Item1.Item1 == a' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
                        GetCSharpResultAt(16, 13, "x.Item1.Item1 == a", "true"),
                        // Test0.cs(16,35): warning CA1508: 'x.Item1.a == a' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
                        GetCSharpResultAt(16, 35, "x.Item1.a == a", "true"),
                        // Test0.cs(16,53): warning CA1508: 'x.Item2 == 1' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
                        GetCSharpResultAt(16, 53, "x.Item2 == 1", "true"),
                        // Test0.cs(26,13): warning CA1508: 'x.a == a' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
                        GetCSharpResultAt(26, 13, "x.a == a", "true"),
                        // Test0.cs(26,25): warning CA1508: 'x.Item2 == a2' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
                        GetCSharpResultAt(26, 25, "x.Item2 == a2", "true"),
                        // Test0.cs(49,13): warning CA1508: 'arg.a == a' is always 'false'. Remove or refactor the condition(s) to avoid dead code.
                        GetCSharpResultAt(49, 13, "arg.a == a", "false"),
                        // Test0.cs(49,27): warning CA1508: 'arg.Item2 == a2' is always 'false'. Remove or refactor the condition(s) to avoid dead code.
                        GetCSharpResultAt(49, 27, "arg.Item2 == a2", "false"),
                    }
                },
                LanguageVersion = CSharpLanguageVersion.CSharp7_3
            }.RunAsync();
        }
 
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.ValueContentAnalysis)]
        [Fact]
        public async Task MethodWithNonConstantReturn_DefaultSwitchCaseInsideLoopAsync()
        {
            await VerifyCSharpAnalyzerAsync(@"
class Operation
{
    public OperationKind Kind { get; }
    public Operation Parent { get; }
}
 
enum OperationKind
{
    Kind1,
    Kind2,
    Kind3
}
 
class Test
{
    bool M(Operation operation)
    {
        return IsRootOfCondition() == true;
 
        bool IsRootOfCondition()
        {
            var current = operation.Parent;
            while (current != null)
            {
                if (current.Kind == OperationKind.Kind1)
                {
                    return false;
                }
 
                current = current.Parent;
            }
 
            return current == null;
        }
    }
}
");
        }
 
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.ValueContentAnalysis)]
        [Fact]
        public async Task LogicalOrWrappedInsideParenthesisAndUnaryAsync()
        {
            await VerifyBasicAnalyzerAsync(@"
Class Test
    Public Sub M(x1 As Boolean, x2 As Boolean, t As Test)
        Dim y = Not (x1 Or x2)
        t?.M2()
    End Sub
 
    Private Sub M2()
    End Sub
End Class
");
        }
 
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.ValueContentAnalysis)]
        [Fact]
        public async Task DoWhileLoopWithSwitchAsync()
        {
            await VerifyBasicAnalyzerAsync(@"
Imports System
Imports System.Runtime.CompilerServices
 
Friend Module TypeSymbolExtensions
    <Extension()>
    Public Function VisitType(type As TypeSymbol, predicate As Func(Of TypeSymbol, Boolean)) As TypeSymbol
        Dim current As TypeSymbol = type
 
        Do
            Select Case current.TypeKind
                Case TypeKind.Class
            End Select
 
            If predicate(current) Then
                Return current
            End If
 
            Select Case current.TypeKind
                Case TypeKind.Array
                    current = DirectCast(current, ArrayTypeSymbol).ElementType
                    Continue Do
            End Select
        Loop
    End Function
End Module
 
Class TypeSymbol
    Public ReadOnly Property TypeKind As TypeKind
End Class
 
Class ArrayTypeSymbol
    Inherits TypeSymbol
    Public ReadOnly Property ElementType As TypeSymbol
End Class
 
Enum TypeKind
    [Class]
    Array
End Enum
");
        }
 
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.ValueContentAnalysis)]
        [Fact]
        public async Task ConditionalAccessInConditionalAndOperandAsync()
        {
            await VerifyBasicAnalyzerAsync(@"
Class Test
    Public ReadOnly Property Flag As Boolean
    Public Sub M(t As Test, flag As Boolean)
        If t?.Flag AndAlso flag Then
        End If
    End Sub
End Class
");
        }
 
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.ValueContentAnalysis)]
        [Fact]
        public async Task LoopWithMethodInvocationInConditionalAsync()
        {
            await VerifyBasicAnalyzerAsync(@"
Imports System
 
Class Test
    Public Function GetNextDirective(predicate As Func(Of SyntaxNode, Boolean), token As SyntaxToken, d As SyntaxNode) As SyntaxNode
        Do While (token.Kind <> SyntaxKind.None)
            If predicate(d) Then
                Return d
            End If
        Loop
        Return Nothing
    End Function
End Class
 
Class SyntaxNode
End Class
 
Structure SyntaxToken
    Public Property Kind As SyntaxKind
End Structure
 
Enum SyntaxKind
    None
    Kind1
End Enum
");
        }
 
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.ValueContentAnalysis)]
        [Fact]
        public async Task LoopWithGotoTargetBeforeLoopAsync()
        {
            await VerifyCSharpAnalyzerAsync(@"
class A
{
    public static A M(int? x, A[] listOfA, A a)
    {
    RETRY:
        if (a == null)
        {
            return null;
        }
 
        foreach (var element in listOfA)
        {
            if (x != 1)
            {
                goto RETRY;
            }
        }
 
        return a;
    }
 
    private Kind Kind { get; }
}
 
enum Kind
{
    Kind1,
    Kind2
}");
        }
 
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.ValueContentAnalysis)]
        [Fact]
        public async Task ConditionalAccess_OperationNoneAsync()
        {
            await VerifyBasicAnalyzerAsync(@"
Imports System
Imports System.Xml.Linq
 
Class Test
    Public Sub M(arg As XElement)
        Dim x = If(arg.@name, """")
    End Sub
End Class
");
        }
 
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.ValueContentAnalysis)]
        [Fact]
        public async Task Assignment_OperationNoneAsync()
        {
            await VerifyBasicAnalyzerAsync(@"
Imports System
Imports System.Xml.Linq
 
Class Test
    Public Sub M(arg As XElement, arg2 As XElement)
        Dim x = If(arg, arg2)
        Dim a = arg.@name
        arg.@name = """"
    End Sub
End Class
");
        }
 
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.ValueContentAnalysis)]
        [Fact]
        public async Task ConditionalExpression_OperationNoneAsync()
        {
            await VerifyBasicAnalyzerAsync(@"
Imports System
Imports System.Linq
 
Class Test
    Public Function M(ifNode As SingleLineIfStatementSyntax) As Boolean
        Return TypeOf ifNode.Parent IsNot SingleLineLambdaExpressionSyntax AndAlso
                Not ifNode.Statements.Any(Function(n) n.IsKind(SyntaxKind.Kind1)) AndAlso
                Not If(ifNode.ElseClause?.Statements.Any(Function(n) n.IsKind(SyntaxKind.Kind1)), False)
    End Function
End Class
 
Class SingleLineIfStatementSyntax
    Inherits SyntaxNode
    Public ReadOnly Property Statements As SyntaxNode()
    Public ReadOnly Property ElseClause As SingleLineIfStatementSyntax
End Class
 
Class SingleLineLambdaExpressionSyntax
    Inherits SyntaxNode
End Class
 
Class SyntaxNode
    Public ReadOnly Property Parent As SyntaxNode
    Public Function IsKind(kind As SyntaxKind) As Boolean
        Return True
    End Function
End Class
 
Enum SyntaxKind
    None
    Kind1
    Kind2
End Enum
");
        }
 
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.ValueContentAnalysis)]
        [Fact]
        public async Task PointsToAnalysisForLoopOnStructFieldsAsync()
        {
            await VerifyCSharpAnalyzerAsync(@"
using System.IO;
 
namespace ClassLibrary14
{
    public class Class2
    {
        struct S
        {
            public string f1;
            public string f2;
            public bool f3;
            public bool f4;
            public bool f5;
            public bool f6;
        };
 
        public void M(Class2 c)
        {
            c?.M(null);
            S[] filesToReplace = new[]
            {
                new S { f1=""file1"", f2=@""string1"",f3=true, f4=true, f5=false, f6=true},
                new S { f1=""file2"",f2=@""string2"", f3=true, f4=true, f5=false, f6=true},
                new S { f1=""file3"", f2=@""string2"",f3=false, f4=false, f5=false, f6=true},
                new S { f1=""file4"", f2=@""string2"", f3=false, f4=false, f5=true, f6=true},
                new S { f1=""file5"", f2=@""string2"", f3=false, f4=false, f5=true, f6=false}
            };
 
            foreach (S fileDetails in filesToReplace)
            {
                bool fileIsUpToDate = false;
                var x1 = fileDetails.f1;
                var destinationDir = fileDetails.f2;
                var x3 = Path.Combine(destinationDir, fileDetails.f1);
                var x4 = fileDetails.f1;
 
                foreach (var residual in Directory.GetFiles(destinationDir, fileDetails.f1 + "".delete.*""))
                {
                }
            }
        }
    }
}
");
        }
 
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.ValueContentAnalysis)]
        [Fact]
        public async Task ValueContentAnalysisWithLocalFunctionInvocationsInStaticMethodsAsync()
        {
            var editorconfig = "dotnet_code_quality.interprocedural_analysis_kind = ContextSensitive";
 
            await new VerifyCS.Test
            {
                TestState =
                {
                    Sources =
                    {
                        @"
using System;
 
public static class C
{
    public static float NextSingle(this Random random, float minValue, float maxValue)
    {
        float AdjustValue(float value) => Single.IsNegativeInfinity(value) ? Single.MinValue : (Single.IsPositiveInfinity(value) ? Single.MaxValue : value);
 
        return (float)random.NextDouble(AdjustValue(minValue), AdjustValue(maxValue));
    }
 
    public static double NextDouble(this Random random, double minValue, double maxValue)
    {
        return minValue;
    }
}
"
                    },
                    AnalyzerConfigFiles = { ("/.editorconfig", $@"root = true
 
[*]
{editorconfig}
") }
                }
            }.RunAsync();
        }
 
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.ValueContentAnalysis)]
        [Fact]
        public async Task PredicateAnalysisWithCastAsync()
        {
            await VerifyCSharpAnalyzerAsync(@"
using System;
 
public static class C
{
    private static int _f;
    public static bool M1(int x, int y)
    {
        y = x > 0 ?  x : 0;
        return !(bool)GetObject(y);
    }
 
    private static object GetObject(int o)
    {
        return (object)(o > _f);
    }
}
");
        }
 
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.ValueContentAnalysis)]
        [Fact, WorkItem(2246, "https://github.com/dotnet/roslyn-analyzers/issues/2246")]
        public async Task NestedPredicateAnalysisWithDifferentStringsAsync()
        {
            await VerifyCSharpAnalyzerAsync(@"
using System;
 
public static class C
{
    private static bool Test(string A, string B, string C, string D)
    {
        bool result = false;
 
        if (string.Compare(A, B, StringComparison.OrdinalIgnoreCase) == 0)
        {
            if (string.Compare(C, D, StringComparison.OrdinalIgnoreCase) == 0)
            {
                result = true;
            }
        }
 
        return result;
    }
}
");
        }
 
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.ValueContentAnalysis)]
        [Fact]
        [WorkItem(2681, "https://github.com/dotnet/roslyn-analyzers/issues/2681")]
        public async Task InterlockedOperations_NoDiagnosticAsync()
        {
            // Ensure that Interlocked increment/decrement/add operations
            // are not treated as absolute writes as it likely involves multiple threads
            // invoking the method and that can lead to false positives.
            await VerifyCSharpAnalyzerAsync(@"
class Test
{
    private int a;
    void M1()
    {
        a = 0;
        System.Threading.Interlocked.Increment(ref a);
        if (a == 1)
        {
        }
 
        a = 1;
        System.Threading.Interlocked.Decrement(ref a);
        if (a == 0)
        {
        }
 
        a = 2;
        System.Threading.Interlocked.Add(ref a, 1);
        if (a == 3)
        {
        }
    }
}");
 
            await VerifyBasicAnalyzerAsync(@"
Module Test
    Sub M1()
        Dim a As Integer = 0
        System.Threading.Interlocked.Increment(a)
        If a = 1 Then
        End If
 
        a = 1
        System.Threading.Interlocked.Decrement(a)
        If a = 0 Then
        End If
 
        a = 2
        System.Threading.Interlocked.Add(a, 1)
        If a = 3 Then
        End If
    End Sub
End Module");
        }
 
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.ValueContentAnalysis)]
        [Fact]
        public async Task ValueContentAnalysis_MergeForUnreachableCodeAsync()
        {
            var editorconfig = "dotnet_code_quality.interprocedural_analysis_kind = ContextSensitive";
 
            await new VerifyCS.Test
            {
                TestState =
                {
                    Sources =
                    {
                        @"
using System;
 
public class C
{
    public void Load(C c1, C c2)
    {
        var x = c1 ?? c2;
        this.Load(null);
    }
 
    public void Load(Uri productFileUrl, Uri originalLocation = null)
    {
        if (productFileUrl == null)
        {
            throw new ArgumentNullException();
        }
 
        Uri feedLocationUri = originalLocation ?? productFileUrl;
 
        _ = feedLocationUri.LocalPath;
    }
}
"
                    },
                    AnalyzerConfigFiles = { ("/.editorconfig", $@"root = true
 
[*]
{editorconfig}
") }
                }
            }.RunAsync();
        }
 
        [Theory]
        [InlineData("struct", "struct")]
        [InlineData("struct", "class")]
        [InlineData("class", "struct")]
        [InlineData("class", "class")]
        public async Task DataflowAcrossBranchesAsync(string typeTest, string typeA)
        {
            var test = new VerifyCS.Test
            {
                TestCode = $@"
using System;
 
namespace TestNamespace
{{
    public {typeA} A
    {{
        public int IntProperty {{ get; set; }}
    }}
 
    public {typeTest} Test
    {{
        public A A;
 
        public void Something(int param)
        {{
            Test t = new Test();
            t.A = new A();
            t.A.IntProperty = param;
            A a = new A();
            a.IntProperty = param;
            A a1 = new A();
            a1.IntProperty = param;
            A a2 = new A();
            a2.IntProperty = param;
            if (param >= 0)
            {{
                a1.IntProperty = 1;
                t.A = a1;                    // t.A now contains/points to a1
                a = a2;
            }}
            else
            {{
                a2.IntProperty = 1;
                t.A = a2;                    // t.A now contains/points to a2   
                a = a1;
            }}
        
            if (t.A.IntProperty == 1)        // t.A now contains/points either a1 or a2, both of which have .IntProperty = """"
                                             // However, we conservatively don't report it when 'A' is a class
            {{
            }}
 
            if (a.IntProperty == 1)          // a points to a1 or a2, and a.IntProperty = param for both cases.
            {{
            }}
        }}
    }}
}}"
            };
 
            if (typeA != "class")
            {
                test.ExpectedDiagnostics.Add(
                    // Test0.cs(33,17): warning CA1508: 't.A.IntProperty == 1' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
                    GetCSharpResultAt(39, 17, "t.A.IntProperty == 1", "true"));
            }
 
            await test.RunAsync();
        }
 
        [Fact, WorkItem(4056, "https://github.com/dotnet/roslyn-analyzers/issues/4056")]
        public async Task TestNegationPatternAsync()
        {
            await new VerifyCS.Test
            {
                TestState =
                {
                    Sources =
                    {
                        @"
public class Test
{
    bool M(int input, object t)
    {
        var x = t?.ToString();
        if (input is not 10)
        {
            return input == 10;
        }
 
        if (t is not null)
        {
            return t != null;
        }
 
        return true;
    }
}
"
                    }
                },
                LanguageVersion = CSharpLanguageVersion.CSharp9,
                ExpectedDiagnostics =
                {
                    // Test0.cs(14,20): warning CA1508: 't != null' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
                    GetCSharpResultAt(14, 20, "t != null", "true")
                }
            }.RunAsync();
        }
 
        [Fact, WorkItem(4056, "https://github.com/dotnet/roslyn-analyzers/issues/4056")]
        public async Task TestNegationPattern_SwitchCaseAsync()
        {
            await new VerifyCS.Test
            {
                TestState =
                {
                    Sources =
                    {
                        @"
public class Test
{
    bool M(int input, object t)
    {
        var x = t?.ToString();
 
        bool result;
        switch (input)
        {
            case not 10:
                result = false;
                break;
            default:
                result = true;
                break;
        }
 
        switch (t)
        {
            case not null:
                result = t != null;
                break;
            default:
                result = t == null;
                break;
        }
 
        return result;
    }
}
"
                    }
                },
                LanguageVersion = CSharpLanguageVersion.CSharp9,
                ExpectedDiagnostics =
                {
                    // Test0.cs(22,26): warning CA1508: 't != null' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
                    GetCSharpResultAt(22, 26, "t != null", "true"),
                    // Test0.cs(25,26): warning CA1508: 't == null' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
                    GetCSharpResultAt(25, 26, "t == null", "true")
                }
            }.RunAsync();
        }
 
        [Fact, WorkItem(4062, "https://github.com/dotnet/roslyn-analyzers/issues/4062")]
        public async Task TestNegationPattern_ExplicitConversionInFlowCapture_SwitchCaseAsync()
        {
            await new VerifyCS.Test
            {
                TestState =
                {
                    Sources =
                    {
                        @"
public class Test
{
    void M(int input, object t)
    {
        var x = t?.ToString();
 
        bool result;
        switch ((bool)t)
        {
            case not true:
                result = (bool)t == false;  // Consider: this should report a diagnostic
                break;
        }
    }
}
"
                    }
                },
                LanguageVersion = CSharpLanguageVersion.CSharp9
            }.RunAsync();
        }
 
        [Fact, WorkItem(4062, "https://github.com/dotnet/roslyn-analyzers/issues/4062")]
        public async Task Test_ExplicitConversionInFlowCapture_ConditionalExpressionAsync()
        {
            await VerifyCSharpAnalyzerAsync(@"
public class Test
{
    private object M(string str)
    {
        int? intVal = int.TryParse(str, out var outInt) ? outInt : (int?)null;
        return (intVal.HasValue ? (object)intVal.Value : (object)str);
    }
}
");
        }
 
        [Fact, WorkItem(4062, "https://github.com/dotnet/roslyn-analyzers/issues/4062")]
        public async Task Test_ExplicitConversionInFlowCapture_ConditionalExpression_02Async()
        {
            await VerifyCSharpAnalyzerAsync(@"
public class Test
{
    private object M(Test t, int? intVal)
    {
        return (intVal.HasValue ? (object)intVal.Value : (object)t);
    }
}
");
        }
 
        [Fact, WorkItem(4056, "https://github.com/dotnet/roslyn-analyzers/issues/4056")]
        public async Task TestRelationalPatternAsync()
        {
            await new VerifyCS.Test
            {
                TestState =
                {
                    Sources =
                    {
                        @"
public class Test
{
    bool M(int input, object t)
    {
        var x = t?.ToString();
 
        if (t is 10)
        {
            return (int)t == 10;
        }
 
        if (t is > 10)
        {
            return (int)t > 10;
        }
 
        return true;
    }
}
"
                    }
                },
                LanguageVersion = CSharpLanguageVersion.CSharp9,
                ExpectedDiagnostics =
                {
                    // Test0.cs(10,20): warning CA1508: '(int)t == 10' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
                    GetCSharpResultAt(10, 20, "(int)t == 10", "true")
                }
            }.RunAsync();
        }
 
        [Fact, WorkItem(4056, "https://github.com/dotnet/roslyn-analyzers/issues/4056")]
        public async Task TestRelationalPattern_SwitchCaseAsync()
        {
            await new VerifyCS.Test
            {
                TestState =
                {
                    Sources =
                    {
                        @"
public class Test
{
    bool M(int input, object t)
    {
        var x = t?.ToString();
 
        bool result;
        switch (input)
        {
            case > 10:
                result = false;
                break;
            default:
                result = true;
                break;
        }
 
        return result;
    }
}
"
                    }
                },
                LanguageVersion = CSharpLanguageVersion.CSharp9
            }.RunAsync();
        }
 
        [Fact, WorkItem(4056, "https://github.com/dotnet/roslyn-analyzers/issues/4056")]
        public async Task TestNegationAndRelationalPatternAsync()
        {
            await new VerifyCS.Test
            {
                TestState =
                {
                    Sources =
                    {
                        @"
public class Test
{
    bool M(int input, object t)
    {
        var x = t?.ToString();
 
        if (input is not > 10)
        {
            return input > 10;  // No range analysis to flag this as dead code.
        }
 
        return true;
    }
}
"
                    }
                },
                LanguageVersion = CSharpLanguageVersion.CSharp9
            }.RunAsync();
        }
 
        [Fact, WorkItem(4056, "https://github.com/dotnet/roslyn-analyzers/issues/4056")]
        public async Task TestNegationAndRelationalPattern_SwitchCaseAsync()
        {
            await new VerifyCS.Test
            {
                TestState =
                {
                    Sources =
                    {
                        @"
public class Test
{
    bool M(int input, object t)
    {
        var x = t?.ToString();
 
        bool result;
        switch (input)
        {
            case not > 10:
                result = false;
                break;
            default:
                result = true;
                break;
        }
 
        return result;
    }
}
"
                    }
                },
                LanguageVersion = CSharpLanguageVersion.CSharp9
            }.RunAsync();
        }
 
        [Fact, WorkItem(4056, "https://github.com/dotnet/roslyn-analyzers/issues/4056")]
        public async Task TestBinaryPatternAsync()
        {
            await new VerifyCS.Test
            {
                TestState =
                {
                    Sources =
                    {
                        @"
public class Test
{
    bool M(int input, object t)
    {
        var x = t?.ToString();
 
        if (t is Test or not null)
        {
            return t != null;   // In future, we might flag this as always 'true'.
        }
 
        return true;
    }
}
"
                    }
                },
                LanguageVersion = CSharpLanguageVersion.CSharp9
            }.RunAsync();
        }
 
#if NETCOREAPP
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.ValueContentAnalysis)]
        [Fact, WorkItem(4387, "https://github.com/dotnet/roslyn-analyzers/issues/4387")]
        public async Task RangeAndIndexOperation_NoDiagnosticAsync()
        {
            await new VerifyCS.Test
            {
                TestCode = @"
internal class Class1
{
    private static bool TryParseUnit(string unit)
    {
        char last = unit[^1];
        if (last != 'b')
            return false;
 
        string subUnit = unit[1..];
        if (subUnit != ""b"")
            return false;
 
        return true;
    }
}
",
                LanguageVersion = CodeAnalysis.CSharp.LanguageVersion.CSharp8,
            }.RunAsync();
        }
#endif
 
        [Fact, WorkItem(5789, "https://github.com/dotnet/roslyn-analyzers/issues/5789")]
        public async Task TestVarPattern()
        {
            var source = @"
public class C
{
    public void M(object o)
    {
        if (o is var o2 && o2 != null)
        {
        }
    }
}
";
            await VerifyCS.VerifyCodeFixAsync(source, source);
        }
 
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.ValueContentAnalysis)]
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.CopyAnalysis)]
        [Fact, WorkItem(6453, "https://github.com/dotnet/roslyn-analyzers/issues/6453")]
        public async Task IndexedValueCompare_NoDiagnosticAsync()
        {
            await VerifyCSharpAnalyzerAsync(@"
using System.Collections.Generic;
 
sealed class Data
{
    public int Value { get; }
    public Data(int value)
    {
        Value = value;
    }
}
 
static class Test
{
    static void Filter(List<Data> list, int j)
    {
        for (int i = 0; i < list.Count - 1; i++)
        {
            if (list[i + 1].Value != 0) continue;
            if (list[i].Value == 0) continue; // <-------- CA1508 False positive
            list.RemoveAt(i);
        }
    }
}
");
        }
 
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.ValueContentAnalysis)]
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.CopyAnalysis)]
        [Fact, WorkItem(6532, "https://github.com/dotnet/roslyn-analyzers/issues/6532")]
        public Task TestTernaryOperator_NoDiagnosticAsync()
        {
            return VerifyCSharpAnalyzerAsync(@"
using System.Collections.Generic;
 
class Test
{
    void M()
    {
        var i = 0;
        i += M2() ? 1 : 0;
        _ = i != 0;
    }
 
    bool M2() => true;
}");
        }
 
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.ValueContentAnalysis)]
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.CopyAnalysis)]
        [Fact, WorkItem(6532, "https://github.com/dotnet/roslyn-analyzers/issues/6532")]
        public Task TestTernaryOperator2_NoDiagnosticAsync()
        {
            return VerifyCSharpAnalyzerAsync(@"
using System.Collections.Generic;
 
class Test
{
    void M()
    {
        var i = 1;
        i += M2() ? 1 : 0;
        _ = i != 2;
    }
 
    bool M2() => true;
}");
        }
 
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.ValueContentAnalysis)]
        [Fact, WorkItem(6164, "https://github.com/dotnet/roslyn-analyzers/issues/6164")]
        public async Task DefaultNullableStringValue_NoDiagnosticAsync()
        {
            await new VerifyCS.Test
            {
                TestCode = @"
#nullable enable
 
using System;
 
class C
{
    public static void Bar(ConsoleColor c)
    {
        string? color = default;
        if (c == ConsoleColor.Green)
            color = ""green"";
 
        if (color != null)
        {
        }
    }
}",
                LanguageVersion = CodeAnalysis.CSharp.LanguageVersion.CSharp8
            }.RunAsync();
        }
 
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.ValueContentAnalysis)]
        [Fact, WorkItem(6483, "https://github.com/dotnet/roslyn-analyzers/issues/6483")]
        public async Task IsPatternExpression_Unboxing_NoDiagnosticsAsync()
        {
            await new VerifyCS.Test
            {
                TestCode = @"
class C
{
    public void Run(object value)
    {
        if (value is null)
        {
            return;
        }
 
        var x = value is double num1;
        if (x)
        {
            return;
        }
 
        if (!(value is int num2))
        {
            return;
        }
    }
}",
            }.RunAsync();
        }
 
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.ValueContentAnalysis)]
        [Fact, WorkItem(5160, "https://github.com/dotnet/roslyn-analyzers/issues/5160")]
        public async Task CatchBlock_WithinForLoop_NoDiagnosticsAsync()
        {
            await new VerifyCS.Test
            {
                TestCode = @"
using System;
 
class C
{
    void M1()
    {
        const int attempts = 5;
 
        for (int i = 0; i < attempts; i++)
        {
            try
            {
                Console.WriteLine($""Hello world: {i}"");
 
                if (i == attempts - 1) // Last iteration.
                {
                    throw new InvalidOperationException(""Oops, something went wrong!"");
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($""Exception caught: {ex.Message}"");
 
                if (i == attempts - 1)
                {
                    Console.WriteLine(""This should never happen, according to CA1508."");
                }
            }
        }
    }
 
    void M2()
    {
        for (int i = 0; i <= 5; i++)
        {
            try
            {
                MayThrowException(i);
                if (i == 0)
                {
                    throw new Exception();
                }
            }
            catch (Exception)
            {
                if (i == 1)
                {
                    Console.WriteLine();
                }
            }
        }
    }
 
    private void MayThrowException(int i)
    {
        if (i % 2 == 1)
        {
            throw new Exception();
        }
    }
}",
                LanguageVersion = CodeAnalysis.CSharp.LanguageVersion.CSharp8,
            }.RunAsync();
        }
 
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.ValueContentAnalysis)]
        [Fact, WorkItem(6983, "https://github.com/dotnet/roslyn-analyzers/issues/6983")]
        public Task DebugAssert_NoDiagnostic()
        {
            const string code = """
                                using System.Diagnostics;
                                
                                public static class MyClass
                                {
                                    internal const int MyConstant = 16;
                                
                                    public static void MyMethod()
                                    {
                                        Debug.Assert(MyConstant == 16);
                                    }
                                }
                                """;
            return VerifyCS.VerifyAnalyzerAsync(code);
        }
 
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.ValueContentAnalysis)]
        [Fact, WorkItem(6983, "https://github.com/dotnet/roslyn-analyzers/issues/6983")]
        public Task DebugAssertWithMessage_NoDiagnostic()
        {
            const string code = """
                                using System.Diagnostics;
                                
                                public static class MyClass
                                {
                                    internal const int MyConstant = 16;
                                
                                    public static void MyMethod()
                                    {
                                        Debug.Assert(MyConstant == 16, "MyConstant is not 16");
                                    }
                                }
                                """;
            return VerifyCS.VerifyAnalyzerAsync(code);
        }
 
        [Trait(Traits.DataflowAnalysis, Traits.Dataflow.ValueContentAnalysis)]
        [Fact, WorkItem(6983, "https://github.com/dotnet/roslyn-analyzers/issues/6983")]
        public Task AsMethodArgument_Diagnostic()
        {
            const string code = """
                                using System.Diagnostics;
 
                                public static class MyClass
                                {
                                    internal const int MyConstant = 16;
                                
                                    public static void MyMethod()
                                    {
                                        Test({|#0:MyConstant == 16|});
                                    }
                                    
                                    private static void Test(bool b) => throw null;
                                }
                                """;
            return new VerifyCS.Test
            {
                TestCode = code,
                ExpectedDiagnostics = { new DiagnosticResult(AvoidDeadConditionalCode.AlwaysTrueFalseOrNullRule).WithLocation(0).WithArguments("MyConstant == 16", "true") }
            }.RunAsync();
        }
    }
}