|
// 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 VerifyCS = Test.Utilities.CSharpCodeFixVerifier<
Microsoft.CodeQuality.CSharp.Analyzers.Maintainability.CSharpAvoidDeadConditionalCode,
Microsoft.CodeAnalysis.Testing.EmptyCodeFixProvider>;
using VerifyVB = Test.Utilities.VisualBasicCodeFixVerifier<
Microsoft.CodeQuality.VisualBasic.Analyzers.Maintainability.BasicAvoidDeadConditionalCode,
Microsoft.CodeAnalysis.Testing.EmptyCodeFixProvider>;
namespace Microsoft.CodeQuality.Analyzers.Maintainability.UnitTests
{
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.PredicateAnalysis)]
public partial class AvoidDeadConditionalCodeTests
{
private static DiagnosticResult GetCSharpResultAt(int line, int column, string condition, string reason)
#pragma warning disable RS0030 // Do not use banned APIs
=> VerifyCS.Diagnostic(AvoidDeadConditionalCode.AlwaysTrueFalseOrNullRule)
.WithLocation(line, column)
#pragma warning restore RS0030 // Do not use banned APIs
.WithArguments(condition, reason);
private static DiagnosticResult GetBasicResultAt(int line, int column, string condition, string reason)
#pragma warning disable RS0030 // Do not use banned APIs
=> VerifyVB.Diagnostic(AvoidDeadConditionalCode.AlwaysTrueFalseOrNullRule)
.WithLocation(line, column)
#pragma warning restore RS0030 // Do not use banned APIs
.WithArguments(condition, reason);
private static DiagnosticResult GetCSharpNeverNullResultAt(int line, int column, string condition, string reason)
#pragma warning disable RS0030 // Do not use banned APIs
=> VerifyCS.Diagnostic(AvoidDeadConditionalCode.NeverNullRule)
.WithLocation(line, column)
#pragma warning restore RS0030 // Do not use banned APIs
.WithArguments(condition, reason);
private static DiagnosticResult GetBasicNeverNullResultAt(int line, int column, string condition, string reason)
#pragma warning disable RS0030 // Do not use banned APIs
=> VerifyVB.Diagnostic(AvoidDeadConditionalCode.NeverNullRule)
.WithLocation(line, column)
#pragma warning restore RS0030 // Do not use banned APIs
.WithArguments(condition, reason);
private static async Task VerifyCSharpAnalyzerAsync(string source, params DiagnosticResult[] expected)
{
var csharpTest = new VerifyCS.Test
{
TestState =
{
Sources = { source },
AnalyzerConfigFiles = { ("/.editorconfig", @"root = true
[*]
dotnet_code_quality.copy_analysis = true") },
}
};
csharpTest.ExpectedDiagnostics.AddRange(expected);
await csharpTest.RunAsync();
}
private static async Task VerifyBasicAnalyzerAsync(string source, params DiagnosticResult[] expected)
{
var vbTest = new VerifyVB.Test
{
TestState =
{
Sources = { source },
AnalyzerConfigFiles = { ("/.editorconfig", @"root = true
[*]
dotnet_code_quality.copy_analysis = true") },
}
};
vbTest.ExpectedDiagnostics.AddRange(expected);
await vbTest.RunAsync();
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Fact]
public async Task SimpleNullCompare_NoDiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
class Test
{
void M1(string param)
{
if (param == null)
{
}
if (null == param)
{
}
}
}
");
await VerifyBasicAnalyzerAsync(@"
Module Test
Sub M1(param As String)
If param Is Nothing Then
End If
If Nothing Is param Then
End If
End Sub
End Module");
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Fact]
public async Task SimpleNullCompare_AfterAssignment_DiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
class Test
{
void M1(string param)
{
param = null;
if (param == null)
{
}
if (null != param)
{
}
}
}
",
// Test0.cs(7,13): warning CA1508: 'param == null' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(7, 13, @"param == null", "true"),
// Test0.cs(11,13): warning CA1508: 'null != param' is always 'false'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(11, 13, @"null != param", "false"));
await VerifyBasicAnalyzerAsync(@"
Module Test
Sub M1(param As String)
param = Nothing
If param Is Nothing Then
End If
If Nothing IsNot param Then
End If
End Sub
End Module",
// Test0.vb(5,12): warning CA1508: 'param Is Nothing' is always 'True'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(5, 12, "param Is Nothing", "True"),
// Test0.vb(8,12): warning CA1508: 'Nothing IsNot param' is always 'False'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(8, 12, "Nothing IsNot param", "False"));
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Fact]
public async Task ElseIf_NestedIf_NullCompare_IsNullValue_DiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
class C
{
}
class Test
{
void M1(C param, C param2)
{
C cNull = null;
C cNotNull = new C();
C cMayBeNull = param2;
if (param != cNull)
{
}
else if (param == cNotNull)
{
}
else if (param == cMayBeNull)
{
if (param != cNotNull)
{
}
}
if (cNull == param)
{
if (param != cNull)
{
}
if (param != cNotNull)
{
}
if (param != cMayBeNull)
{
}
if (param == cNull)
{
}
if (param == cNotNull)
{
}
if (param == cMayBeNull)
{
}
}
}
}
",
// Test0.cs(17,18): warning CA1508: 'param == cNotNull' is always 'false'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(17, 18, "param == cNotNull", "false"),
// Test0.cs(22,17): warning CA1508: 'param != cNotNull' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(22, 17, "param != cNotNull", "true"),
// Test0.cs(29,17): warning CA1508: 'param != cNull' is always 'false'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(29, 17, "param != cNull", "false"),
// Test0.cs(33,17): warning CA1508: 'param != cNotNull' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(33, 17, "param != cNotNull", "true"),
// Test0.cs(41,17): warning CA1508: 'param == cNull' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(41, 17, "param == cNull", "true"),
// Test0.cs(45,17): warning CA1508: 'param == cNotNull' is always 'false'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(45, 17, "param == cNotNull", "false"));
await VerifyBasicAnalyzerAsync(@"
Class C
End Class
Module Test
Sub M(param As C, param2 As C)
Dim cNull As C = Nothing
Dim cNotNull As C = New C()
Dim cMayBeNull As C = param2
If param IsNot cNull Then
ElseIf param Is cNotNull Then
ElseIf param Is cMayBeNull Then
If param IsNot cNotNull Then
End If
End If
If cNull Is param Then
If param IsNot cNull Then
End If
If param IsNot cNotNull Then
End If
If param IsNot cMayBeNull Then
End If
If param Is cNull Then
End If
If param Is cNotNull Then
End If
If param Is cMayBeNull Then
End If
End If
End Sub
End Module",
// Test0.vb(12,16): warning CA1508: 'param Is cNotNull' is always 'False'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(12, 16, "param Is cNotNull", "False"),
// Test0.vb(14,16): warning CA1508: 'param IsNot cNotNull' is always 'True'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(14, 16, "param IsNot cNotNull", "True"),
// Test0.vb(19,16): warning CA1508: 'param IsNot cNull' is always 'False'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(19, 16, "param IsNot cNull", "False"),
// Test0.vb(22,16): warning CA1508: 'param IsNot cNotNull' is always 'True'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(22, 16, "param IsNot cNotNull", "True"),
// Test0.vb(28,16): warning CA1508: 'param Is cNull' is always 'True'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(28, 16, "param Is cNull", "True"),
// Test0.vb(31,16): warning CA1508: 'param Is cNotNull' is always 'False'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(31, 16, "param Is cNotNull", "False"));
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Fact]
public async Task ElseIf_NestedIf_NullCompare_IsNotNullValue_DiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
class C
{
}
class Test
{
void M1(C param, C param2)
{
C cNull = null;
C cNotNull = new C();
C cMayBeNull = param2;
if (param != cNotNull)
{
}
else if (param == cNull)
{
}
else if (param == cMayBeNull)
{
if (param != cNull)
{
}
}
if (cNotNull == param)
{
if (param != cNull)
{
}
if (param != cNotNull)
{
}
if (param != cMayBeNull)
{
}
if (param == cNull)
{
}
if (param == cNotNull)
{
}
if (param == cMayBeNull)
{
}
}
}
}
",
// Test0.cs(17,18): warning CA1508: 'param == cNull' is always 'false'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(17, 18, "param == cNull", "false"),
// Test0.cs(22,17): warning CA1508: 'param != cNull' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(22, 17, "param != cNull", "true"),
// Test0.cs(29,17): warning CA1508: 'param != cNull' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(29, 17, "param != cNull", "true"),
// Test0.cs(33,17): warning CA1508: 'param != cNotNull' is always 'false'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(33, 17, "param != cNotNull", "false"),
// Test0.cs(41,17): warning CA1508: 'param == cNull' is always 'false'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(41, 17, "param == cNull", "false"),
// Test0.cs(45,17): warning CA1508: 'param == cNotNull' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(45, 17, "param == cNotNull", "true"));
await VerifyBasicAnalyzerAsync(@"
Class C
End Class
Module Test
Sub M(param As C, param2 As C)
Dim cNull As C = Nothing
Dim cNotNull As C = New C()
Dim cMayBeNull As C = param2
If param IsNot cNotNull Then
ElseIf param Is cNotNull Then
ElseIf param Is cMayBeNull Then
If param IsNot cNotNull Then
End If
End If
If cNotNull Is param Then
If param IsNot cNull Then
End If
If param IsNot cNotNull Then
End If
If param IsNot cMayBeNull Then
End If
If param Is cNull Then
End If
If param Is cNotNull Then
End If
If param Is cMayBeNull Then
End If
End If
End Sub
End Module",
// Test0.vb(12,16): warning CA1508: 'param Is cNotNull' is always 'True'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(12, 16, "param Is cNotNull", "True"),
// Test0.vb(14,16): warning CA1508: 'param IsNot cNotNull' is always 'False'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(14, 16, "param IsNot cNotNull", "False"),
// Test0.vb(19,16): warning CA1508: 'param IsNot cNull' is always 'True'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(19, 16, "param IsNot cNull", "True"),
// Test0.vb(22,16): warning CA1508: 'param IsNot cNotNull' is always 'False'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(22, 16, "param IsNot cNotNull", "False"),
// Test0.vb(28,16): warning CA1508: 'param Is cNull' is always 'False'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(28, 16, "param Is cNull", "False"),
// Test0.vb(31,16): warning CA1508: 'param Is cNotNull' is always 'True'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(31, 16, "param Is cNotNull", "True"));
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Fact]
public async Task ElseIf_NestedIf_NullCompare_IsNotNotNullValue_NoDiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
class C
{
}
class Test
{
void M1(C param, C param2)
{
C cNull = null;
C cNotNull = new C();
C cMayBeNull = param2;
if (param == cNotNull) // We do not track not-equal values so comparisons with cNotNull below are not flagged.
{
}
else if (param == cNull)
{
}
else if (param == cMayBeNull)
{
if (param != cNotNull)
{
}
}
if (cNotNull != param) // We do not track not-equal values so comparisons with cNotNull below are not flagged.
{
if (param != cNull)
{
}
if (param != cNotNull)
{
}
if (param != cMayBeNull)
{
}
if (param == cNull)
{
}
if (param == cNotNull)
{
}
if (param == cMayBeNull)
{
}
}
}
}
");
await VerifyBasicAnalyzerAsync(@"
Class C
End Class
Module Test
Sub M(param As C, param2 As C)
Dim cNull As C = Nothing
Dim cNotNull As C = New C()
Dim cMayBeNull As C = param2
If param Is cNotNull Then ' We do not track not-equal values so comparisons with cNotNull below are not flagged.
ElseIf param Is cNotNull Then
ElseIf param Is cMayBeNull Then
If param IsNot cNotNull Then
End If
End If
If cNotNull IsNot param Then ' We do not track not-equal values so comparisons with cNotNull below are not flagged.
If param IsNot cNull Then
End If
If param IsNot cNotNull Then
End If
If param IsNot cMayBeNull Then
End If
If param Is cNull Then
End If
If param Is cNotNull Then
End If
If param Is cMayBeNull Then
End If
End If
End Sub
End Module");
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Fact]
public async Task ElseIf_NestedIf_NullCompare_IsMayBeNullValue_NoDiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
class C
{
}
class Test
{
void M1(C param, C param2)
{
C cNull = null;
C cNotNull = new C();
C cMayBeNull = param2;
if (param == cMayBeNull) // We do not track maybe values so comparisons with cMayBeNull below are not flagged.
{
}
else if (param == cNull)
{
}
else if (param == cMayBeNull)
{
if (param != cNotNull)
{
}
}
if (cMayBeNull != param) // We do not track maybe values so comparisons with cMayBeNull below are not flagged.
{
if (param != cNull)
{
}
if (param != cNotNull)
{
}
if (param != cMayBeNull)
{
}
if (param == cNull)
{
}
if (param == cNotNull)
{
}
if (param == cMayBeNull)
{
}
}
}
}
");
await VerifyBasicAnalyzerAsync(@"
Class C
End Class
Module Test
Sub M(param As C, param2 As C)
Dim cNull As C = Nothing
Dim cNotNull As C = New C()
Dim cMayBeNull As C = param2
If param Is cMayBeNull Then ' We do not track maybe values so comparisons with cNotNull below are not flagged.
ElseIf param Is cNotNull Then
ElseIf param Is cMayBeNull Then
If param IsNot cNotNull Then
End If
End If
If cMayBeNull IsNot param Then ' We do not track maybe values so comparisons with cNotNull below are not flagged.
If param IsNot cNull Then
End If
If param IsNot cNotNull Then
End If
If param IsNot cMayBeNull Then
End If
If param Is cNull Then
End If
If param Is cNotNull Then
End If
If param Is cMayBeNull Then
End If
End If
End Sub
End Module");
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Fact]
public async Task NullCompare_WhileLoopAsync()
{
await VerifyCSharpAnalyzerAsync(@"
class Test
{
void M(string param)
{
string str = null;
while (param == str)
{
// param = null here
if (param == str)
{
}
if (param != str)
{
}
}
// param is not-null 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(19, 13): warning CA1508: 'str == param' is always 'false'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(19, 13, "str == param", "false"),
// Test0.cs(22,13): warning CA1508: 'str != param' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(22, 13, "str != param", "true"));
await VerifyBasicAnalyzerAsync(@"
Module Test
' While loop
Private Sub M1(ByVal param As String)
Dim str As String = Nothing
While param = str
' param == null here
If param = str Then
End If
If param <> str Then
End If
End While
' param is non-null 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"),
// Test0.vb(15,12): warning CA1508: 'str = param' is always 'False'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(15, 12, "str = param", "False"),
// Test0.vb(17,12): warning CA1508: 'str <> param' is always 'True'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(17, 12, "str <> param", "True"));
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Fact]
public async Task NullCompare_WhileLoop_02Async()
{
await VerifyCSharpAnalyzerAsync(@"
class Test
{
void M(string param, string param2)
{
if (param != null)
{
while (param != null)
{
param = param2;
}
}
}
}
");
await VerifyBasicAnalyzerAsync(@"
Module Test
' While loop
Private Sub M1(param As String, param2 As String)
If param IsNot Nothing Then
While param IsNot Nothing
param = param2
End While
End If
End Sub
End Module");
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Fact]
public async Task NullCompare_WhileLoop_03Async()
{
await VerifyCSharpAnalyzerAsync(@"
class C
{
public C ContainingC => new C();
}
class Test
{
void M(C param)
{
if (param == null || param.ContainingC == null)
{
return;
}
while (param != null)
{
param = param.ContainingC;
}
}
}
");
await VerifyBasicAnalyzerAsync(@"
Class C
Public ReadOnly Property ContainingC As C
End Class
Module Test
Private Sub M1(param As C)
If param Is Nothing OrElse param.ContainingC Is Nothing Then
Return
End If
While param IsNot Nothing
param = param.ContainingC
End While
End Sub
End Module");
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Fact]
public async Task NullCompare_WhileLoop_04Async()
{
await VerifyCSharpAnalyzerAsync(@"
class C
{
}
class Test
{
private Test Next { get; }
private C[] CInstances { get; }
void M(bool flag)
{
var current = this;
while (current != null)
{
foreach (var x in current.CInstances)
{
if (flag) return;
}
current = current.Next;
}
}
}
");
await VerifyBasicAnalyzerAsync(@"
Class C
End Class
Class Test
Private Property [Next] As Test
Private Property CInstances As C()
Private Sub M(ByVal flag As Boolean)
Dim current = Me
While current IsNot Nothing
For Each x In current.CInstances
If flag Then Return
Next
current = current.[Next]
End While
End Sub
End Class
");
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Fact]
public async Task NullCompare_WhileLoop_05Async()
{
await VerifyCSharpAnalyzerAsync(@"
class Test
{
void M(C[] args)
{
C local = null;
int i = 0;
while (i < args.Length)
{
// local may or may not be null here.
if (local == null)
{
local = new C();
}
i++;
}
// local may or may not be null here.
if (local != null)
{
return;
}
}
}
class C
{
}
");
await VerifyBasicAnalyzerAsync(@"
Module Test
Sub M1(args As C())
Dim local As C = Nothing
Dim i As Integer = 0
While i < args.Length
' local may or may not be null here.
If local Is Nothing Then
local = New C()
End If
i = i + 1
End While
' local may or may not be null here.
If local IsNot Nothing Then
Return
End If
End Sub
End Module
Class C
End Class
");
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Fact]
public async Task NullCompare_WhileLoop_WithBreakAsync()
{
await VerifyCSharpAnalyzerAsync(@"
class Test
{
void M(string param, string param2, bool flag)
{
string str = null;
while (param == str)
{
// param = null here
if (param == str)
{
}
if (flag)
{
param = param2;
break;
}
// param = null here
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(21,17): warning CA1508: 'param != str' is always 'false'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(21, 17, "param != str", "false"));
await VerifyBasicAnalyzerAsync(@"
Module Test
' While loop
Private Sub M1(param As String, param2 As String, flag As Boolean)
Dim str As String = Nothing
While param = str
' param == null here
If param = str Then
End If
If flag Then
param = param2
Exit While
End If
' param == null here
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(15,16): warning CA1508: 'param <> str' is always 'False'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(15, 16, "param <> str", "False"));
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Fact]
public async Task NullCompare_WhileLoop_WithContinueAsync()
{
await VerifyCSharpAnalyzerAsync(@"
class Test
{
void M(string param, string param2, string param3, bool flag)
{
string str = null;
param3 = str;
while (param == str)
{
// param = null here.
if (param == str)
{
}
// param3 is unknown here due to continue statement in the loop.
if (param3 == str)
{
}
if (flag)
{
param3 = param2;
continue;
}
// param = null here.
if (param != str)
{
}
// param3 is unknown here due to continue statement in the loop.
if (param3 != str)
{
}
}
// param = null here
if (str == param)
{
}
if (str != param)
{
}
}
}
",
// Test0.cs(11,17): warning CA1508: 'param == str' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(11, 17, "param == str", "true"),
// Test0.cs(27,17): warning CA1508: 'param != str' is always 'false'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(27, 17, "param != str", "false"),
// 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"),
// Test0.cs(41,13): warning CA1508: 'str != param' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(41, 13, "str != param", "true"));
await VerifyBasicAnalyzerAsync(@"
Module Test
' While loop
Private Sub M1(param As String, param2 As String, param3 As String, flag As Boolean)
Dim str As String = Nothing
param3 = str
While param = str
' param == null here
If param = str Then
End If
' param3 is unknown here due to continue statement in the loop.
If param3 = str Then
End If
If flag Then
param3 = param2
Continue While
End If
' param == null here
If param <> str Then
End If
' param3 is unknown here due to continue statement in the loop.
If param3 <> str Then
End If
End While
' param = null here
If str = param Then
End If
If str <> param Then
End If
End Sub
End Module",
// Test0.vb(9,16): warning CA1508: 'param = str' is always 'True'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(9, 16, "param = str", "True"),
// Test0.vb(19,16): warning CA1508: 'param <> str' is always 'False'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(19, 16, "param <> str", "False"),
// Test0.vb(27,12): warning CA1508: 'str = param' is always 'False'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(27, 12, "str = param", "False"),
// Test0.vb(29,12): warning CA1508: 'str <> param' is always 'True'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(29, 12, "str <> param", "True"));
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Fact]
public async Task NullCompare_DoWhileLoopAsync()
{
await VerifyCSharpAnalyzerAsync(@"
class C
{
}
class Test
{
void M(C param)
{
C cNotNull = new C();
do
{
// param is unknown here
if (cNotNull == param)
{
}
if (cNotNull != param)
{
}
}
while (param != cNotNull);
// param = cNotNull here
if (param == cNotNull)
{
}
if (param != cNotNull)
{
}
}
}
",
// Test0.cs(24,13): warning CA1508: 'param == cNotNull' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(24, 13, "param == cNotNull", "true"),
// Test0.cs(27,13): warning CA1508: 'param != cNotNull' is always 'false'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(27, 13, "param != cNotNull", "false"));
await VerifyBasicAnalyzerAsync(@"
Class C
End Class
Module Test
' Do-While top loop
Private Sub M(ByVal param As String)
Dim cNotNull As New C()
Do While param IsNot cNotNull
' param is unknown here
If cNotNull Is param Then
End If
If cNotNull IsNot param Then
End If
Loop
' param == cNotNull here
If param Is cNotNull Then
End If
If param IsNot cNotNull Then
End If
End Sub
' Do-While bottom loop
Private Sub M2(ByVal param2 As String)
Dim cNotNull As New C()
Do
' param2 is unknown here
If cNotNull Is param2 Then
End If
If cNotNull IsNot param2 Then
End If
Loop While param2 IsNot cNotNull
' param2 == cNotNull here
If param2 Is cNotNull Then
End If
If param2 IsNot cNotNull Then
End If
End Sub
End Module",
// Test0.vb(18,12): warning CA1508: 'param Is cNotNull' is always 'True'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(18, 12, "param Is cNotNull", "True"),
// Test0.vb(20,12): warning CA1508: 'param IsNot str' is always 'False'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(20, 12, "param IsNot cNotNull", "False"),
// Test0.vb(36,12): warning CA1508: 'param2 Is str' is always 'True'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(36, 12, "param2 Is cNotNull", "True"),
// Test0.vb(38,12): warning CA1508: 'param2 IsNot str' is always 'False'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(38, 12, "param2 IsNot cNotNull", "False"));
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Fact]
public async Task NullCompare_DoWhileLoop_02Async()
{
await VerifyCSharpAnalyzerAsync(@"
class C
{
public C ContainingC => new C();
}
class Test
{
void M(C param)
{
if (param.ContainingC == null)
{
return;
}
do
{
param = param.ContainingC;
}
while (param != null);
}
}
");
await VerifyBasicAnalyzerAsync(@"
Class C
Public ReadOnly Property ContainingC As C
End Class
Module Test
Private Sub M1(param As C)
If param.ContainingC Is Nothing Then
Return
End If
Do
param = param.ContainingC
Loop While param IsNot Nothing
End Sub
End Module");
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Fact]
public async Task NullCompare_DoWhileLoop_WithBreakAsync()
{
await VerifyCSharpAnalyzerAsync(@"
class C
{
}
class Test
{
void M(C param, C param2, bool flag)
{
C cNotNull = new C();
do
{
// param is unknown here
if (cNotNull == param)
{
}
if (flag)
{
param = param2;
break;
}
if (cNotNull != param)
{
}
}
while (param != cNotNull);
// param is unknown here
if (param == cNotNull)
{
}
if (param != cNotNull)
{
}
}
}
");
await VerifyBasicAnalyzerAsync(@"
Class C
End Class
Module Test
' Do-While top loop
Private Sub M(param As String, param2 As String, flag As Boolean)
Dim cNotNull As New C()
Do While param IsNot cNotNull
' param is unknown here
If cNotNull Is param Then
End If
If flag Then
param = param2
Exit Do
End If
If cNotNull IsNot param Then
End If
Loop
' param is unknown here due to Exit While
If param Is cNotNull Then
End If
If param IsNot cNotNull Then
End If
End Sub
' Do-While bottom loop
Private Sub M2(param As String, param2 As String, flag As Boolean)
Dim cNotNull As New C()
Do
' param2 is unknown here
If cNotNull Is param2 Then
End If
If flag Then
param2 = param
Exit Do
End If
If cNotNull IsNot param2 Then
End If
Loop While param2 IsNot cNotNull
' param2 is unknown here due to Exit While
If param2 Is cNotNull Then
End If
If param2 IsNot cNotNull Then
End If
End Sub
End Module");
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Fact]
public async Task NullCompare_DoWhileLoop_WithContinueAsync()
{
await VerifyCSharpAnalyzerAsync(@"
class C
{
}
class Test
{
void M(C param, C param2, C param3, bool flag)
{
C cNull = null;
param3 = null;
do
{
// param is unknown here from first loop iteration.
if (cNull == param)
{
}
// param3 is unknown here due to continue statement.
if (cNull == param3)
{
}
if (flag)
{
param3 = param2;
continue;
}
// param is unknown here from first loop iteration.
if (cNull != param)
{
}
// param is unknown here due to continue statement.
if (cNull != param)
{
}
}
while (param != cNull);
// param = cNull here
if (param == cNull)
{
}
if (param != cNull)
{
}
// param3 is unknwon here
if (param3 == cNull)
{
}
if (param3 != cNull)
{
}
}
}
",
// Test0.cs(39,13): warning CA1508: 'param == cNull' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(39, 13, "param == cNull", "true"),
// Test0.cs(42,13): warning CA1508: 'param != cNull' is always 'false'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(42, 13, "param != cNull", "false"));
await VerifyBasicAnalyzerAsync(@"
Class C
End Class
Module Test
' Do-While top loop
Private Sub M(param As C, param2 As C, param3 As C, flag As Boolean)
Dim cNull As C = Nothing
param3 = Nothing
Do While param IsNot cNull
' param is non-null here
If cNull Is param Then
End If
' param3 is unknown here due to continue statement in the loop.
If cNull Is param3 Then
End If
If flag Then
param3 = param2
Continue Do
End If
' param is non-null here
If cNull IsNot param Then
End If
' param3 is unknown here due to continue statement in the loop.
If cNull IsNot param3 Then
End If
Loop
' param = cNull here
If param Is cNull Then
End If
If param IsNot cNull Then
End If
' param3 is unknown here due.
If param3 Is cNull Then
End If
If param3 IsNot cNull Then
End If
End Sub
' Do-While bottom loop
Private Sub M2(param As C, param2 As C, param4 As C, flag As Boolean)
Dim cNull As C = Nothing
param4 = Nothing
Do
' param2 is unknown here from first loop iteration
If cNull Is param2 Then
End If
' param4 is unknown here due to continue statement in the loop
If cNull Is param4 Then
End If
If flag Then
param4 = param
Continue Do
End If
' param2 is unknown here from first loop iteration
If cNull IsNot param2 Then
End If
' param4 is unknown here due to continue statement in the loop
If cNull IsNot param4 Then
End If
Loop While param2 IsNot cNull
' param2 = cNull here
If param2 Is cNull Then
End If
If param2 IsNot cNull Then
End If
' param4 is unknown here
If param4 Is cNull Then
End If
If param4 IsNot cNull Then
End If
End Sub
End Module",
// Test0.vb(12,16): warning CA1508: 'cNull Is param' is always 'False'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(12, 16, "cNull Is param", "False"),
// Test0.vb(22,16): warning CA1508: 'cNull IsNot param' is always 'True'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(22, 16, "cNull IsNot param", "True"),
// Test0.vb(30,12): warning CA1508: 'param Is cNull' is always 'True'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(30, 12, "param Is cNull", "True"),
// Test0.vb(32,12): warning CA1508: 'param IsNot cNull' is always 'False'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(32, 12, "param IsNot cNull", "False"),
// Test0.vb(66,12): warning CA1508: 'param2 Is cNull' is always 'True'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(66, 12, "param2 Is cNull", "True"),
// Test0.vb(68,12): warning CA1508: 'param2 IsNot cNull' is always 'False'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(68, 12, "param2 IsNot cNull", "False"));
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Fact]
public async Task NullCompare_DoUntilLoopAsync()
{
await VerifyBasicAnalyzerAsync(@"
Module Test
' Do-Until top loop
Private Sub M(ByVal param As String)
Dim str As String = Nothing
Do Until param <> str
' param == str here
If param = str Then
End If
If param <> str Then
End If
Loop
' param is non-null 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 = Nothing
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(15,12): warning CA1508: 'str = param' is always 'False'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(15, 12, "str = param", "False"),
// Test0.vb(17,12): warning CA1508: 'str <> param' is always 'True'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(17, 12, "str <> param", "True"),
// 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.NullAnalysis)]
[Fact]
public async Task NullCompare_ForLoopAsync()
{
await VerifyCSharpAnalyzerAsync(@"
class Test
{
void M(C param, C param2)
{
C cNotNull = new C();
for (param = cNotNull; param2 != cNotNull;)
{
// param = cNotNull here
if (param == cNotNull)
{
}
if (param != cNotNull)
{
}
// param2 != cNotNull here, but we don't track not-contained values so no diagnostic.
if (param2 == cNotNull)
{
}
if (param2 != cNotNull)
{
}
}
// param2 == cNotNull here
if (cNotNull == param2)
{
}
if (cNotNull != param2)
{
}
// param == cNotNull here
if (cNotNull == param)
{
}
if (cNotNull != param)
{
}
}
}
class C
{
}
",
// Test0.cs(10,17): warning CA1508: 'param == cNotNull' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(10, 17, "param == cNotNull", "true"),
// Test0.cs(13,17): warning CA1508: 'param != cNotNull' is always 'false'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(13, 17, "param != cNotNull", "false"),
// Test0.cs(27,13): warning CA1508: 'cNotNull == param2' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(27, 13, "cNotNull == param2", "true"),
// Test0.cs(30,13): warning CA1508: 'cNotNull != param2' is always 'false'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(30, 13, "cNotNull != param2", "false"),
// Test0.cs(35,13): warning CA1508: 'cNotNull == param' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(35, 13, "cNotNull == param", "true"),
// Test0.cs(38,13): warning CA1508: 'cNotNull != param' is always 'false'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(38, 13, "cNotNull != param", "false"));
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Fact]
public async Task NullCompare_ForLoop_02Async()
{
await VerifyCSharpAnalyzerAsync(@"
class Test
{
void M(C[] args)
{
foreach (var arg in args)
{
if (arg == null)
{
return;
}
}
}
}
class C
{
}
");
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Fact]
public async Task NullCompare_ForLoop_03Async()
{
await VerifyCSharpAnalyzerAsync(@"
class Test
{
void M(C[] args)
{
C local = null;
for (int i = 0; i < args.Length; i++)
{
// local may or may not be null here.
if (local == null)
{
local = new C();
}
}
// local may or may not be null here.
if (local != null)
{
return;
}
}
}
class C
{
}
");
await VerifyBasicAnalyzerAsync(@"
Module Test
Sub M1(args As C())
Dim local As C = Nothing
For i As Integer = 0 To args.Length
' local may or may not be null here.
If local Is Nothing Then
local = New C()
End If
Next
' local may or may not be null here.
If local IsNot Nothing Then
Return
End If
End Sub
End Module
Class C
End Class
");
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Fact]
public async Task NullCompare_ForLoop_WithBreakAsync()
{
await VerifyCSharpAnalyzerAsync(@"
class Test
{
void M(string param, string param2, bool flag)
{
string str;
for (str = null; param == str;)
{
// param = null here
if (param == str)
{
}
if (flag)
{
param = param2;
break;
}
// param = null here
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(21,17): warning CA1508: 'param != str' is always 'false'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(21, 17, "param != str", "false"));
await VerifyBasicAnalyzerAsync(@"
Module Test
' For loop
Private Sub M1(param As String, param2 As String, flag As Boolean)
Dim str As String = Nothing
For i As Integer = 0 To 10
param = str
' param == null here
If param = str Then
End If
If flag Then
param = param2
Exit For
End If
' param == null here
If param <> str Then
End If
Next
' param is unknown here
If str = param Then
End If
If str <> param Then
End If
End Sub
End Module",
// Test0.vb(9,16): warning CA1508: 'param = str' is always 'True'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(9, 16, "param = str", "True"),
// Test0.vb(16,16): warning CA1508: 'param <> str' is always 'False'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(16, 16, "param <> str", "False"));
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Fact]
public async Task NullCompare_ForLoop_WithContinueAsync()
{
await VerifyCSharpAnalyzerAsync(@"
class Test
{
void M(string param, string param2, string param3, bool flag)
{
string str;
param3 = null;
for (str = null; param == str;)
{
// param = null here.
if (param == str)
{
}
// param3 is unknown here due to continue statement in the loop.
if (param3 == str)
{
}
if (flag)
{
param3 = param2;
continue;
}
// param = null here.
if (param != str)
{
}
// param3 is unknown here due to continue statement in the loop.
if (param3 != str)
{
}
}
// param = null here
if (str == param)
{
}
if (str != param)
{
}
}
}
",
// Test0.cs(11,17): warning CA1508: 'param == str' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(11, 17, "param == str", "true"),
// Test0.cs(27,17): warning CA1508: 'param != str' is always 'false'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(27, 17, "param != str", "false"),
// 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"),
// Test0.cs(41,13): warning CA1508: 'str != param' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(41, 13, "str != param", "true"));
await VerifyBasicAnalyzerAsync(@"
Module Test
Private Sub M1(param As String, param2 As String, param3 As String, flag As Boolean)
Dim str As String = Nothing
param3 = Nothing
For i As Integer = 0 To 10
param = str
' param == null here
If param = str Then
End If
' param3 is unknown here due to continue statement in the loop.
If param3 = str Then
End If
If flag Then
param3 = param2
Continue For
End If
' param == null here
If param <> str Then
End If
' param3 is unknown here due to continue statement in the loop.
If param3 <> str Then
End If
Next
' param is unknown here
If str = param Then
End If
If str <> param Then
End If
End Sub
End Module",
// Test0.vb(9,16): warning CA1508: 'param = str' is always 'True'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(9, 16, "param = str", "True"),
// Test0.vb(19,16): warning CA1508: 'param <> str' is always 'False'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(19, 16, "param <> str", "False"));
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Fact]
public async Task ValueCompare_ForLoopAsync()
{
await VerifyCSharpAnalyzerAsync(@"
class Test
{
void M(string[] args, int j)
{
int i;
for (i = j; i < args.Length; i++)
{
}
if (i == j)
{
return;
}
}
}
");
await VerifyBasicAnalyzerAsync(@"
Module Test
Sub M1(args As C(), j As Integer)
Dim i As Integer
For i = j To args.Length
Next
If i = j Then
Return
End If
End Sub
End Module
Class C
End Class
");
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Fact]
public async Task NullCompare_ForEachLoopAsync()
{
await VerifyCSharpAnalyzerAsync(@"
class Test
{
void M(C[] args)
{
C local = null;
foreach (var c in args)
{
// local may or may not be null here.
if (local == null)
{
local = new C();
}
}
// local may or may not be null here.
if (local != null)
{
return;
}
}
}
class C
{
}
");
await VerifyBasicAnalyzerAsync(@"
Module Test
Sub M1(args As C())
Dim local As C = Nothing
For Each c in args
' local may or may not be null here.
If local Is Nothing Then
local = New C()
End If
Next
' local may or may not be null here.
If local IsNot Nothing Then
Return
End If
End Sub
End Module
Class C
End Class
");
}
[Fact]
public async Task NullCompare_ForEachLoop_WithBreakAsync()
{
await VerifyCSharpAnalyzerAsync(@"
class Test
{
void M(string param, string param2, bool flag)
{
string str = null;
param = str;
foreach (var ch in param2)
{
// param = null here
if (param == str)
{
}
if (flag)
{
param = param2;
break;
}
// param = null here
if (param != str)
{
}
}
// param is unknown here
if (str == param)
{
}
if (str != param)
{
}
}
}
",
// Test0.cs(11,17): warning CA1508: 'param == str' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(11, 17, "param == str", "true"),
// Test0.cs(22,17): warning CA1508: 'param != str' is always 'false'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(22, 17, "param != str", "false"));
await VerifyBasicAnalyzerAsync(@"
Module Test
' While loop
Private Sub M1(param As String, param2 As String, flag As Boolean)
Dim str As String = Nothing
param = str
For Each ch As Char in param2
' param == null here
If param = str Then
End If
If flag Then
param = param2
Exit For
End If
' param == null here
If param <> str Then
End If
Next
' param is unknown here
If str = param Then
End If
If str <> param Then
End If
End Sub
End Module",
// Test0.vb(9,16): warning CA1508: 'param = str' is always 'True'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(9, 16, "param = str", "True"),
// Test0.vb(16,16): warning CA1508: 'param <> str' is always 'False'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(16, 16, "param <> str", "False"));
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Fact]
public async Task NullCompare_ForEachLoop_WithContinueAsync()
{
await VerifyCSharpAnalyzerAsync(@"
class Test
{
void M(string param, string param2, string param3, bool flag)
{
string str = null;
param3 = null;
param = str;
foreach (var ch in param2)
{
// param = null here.
if (param == str)
{
}
// param3 is unknown here due to continue statement in the loop.
if (param3 == str)
{
}
if (flag)
{
param3 = param2;
continue;
}
// param = null here.
if (param != str)
{
}
// param3 is unknown here due to continue statement in the loop.
if (param3 != str)
{
}
}
// param = null here
if (str == param)
{
}
if (str != param)
{
}
// param3 is unkown here
if (str == param3)
{
}
if (str != param3)
{
}
}
}
",
// Test0.cs(12,17): warning CA1508: 'param == str' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(12, 17, "param == str", "true"),
// Test0.cs(28,17): warning CA1508: 'param != str' is always 'false'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(28, 17, "param != str", "false"),
// Test0.cs(39,13): warning CA1508: 'str == param' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(39, 13, "str == param", "true"),
// Test0.cs(42,13): warning CA1508: 'str != param' is always 'false'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(42, 13, "str != param", "false"));
await VerifyBasicAnalyzerAsync(@"
Module Test
Private Sub M1(param As String, param2 As String, param3 As String, flag As Boolean)
Dim str As String = Nothing
param3 = Nothing
param = str
For Each ch As Char in param2
' param == null here
If param = str Then
End If
' param3 is unknown here due to continue statement in the loop.
If param3 = str Then
End If
If flag Then
param3 = param2
Continue For
End If
' param == null here
If param <> str Then
End If
' param3 is unknown here due to continue statement in the loop.
If param3 <> str Then
End If
Next
' param = null here
If str = param Then
End If
If str <> param Then
End If
' param3 is unknown here
If str = param3 Then
End If
If str <> param3 Then
End If
End Sub
End Module",
// Test0.vb(9,16): warning CA1508: 'param = str' is always 'True'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(9, 16, "param = str", "True"),
// Test0.vb(19,16): warning CA1508: 'param <> str' is always 'False'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(19, 16, "param <> str", "False"),
// Test0.vb(27,12): warning CA1508: 'str = param' is always 'True'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(27, 12, "str = param", "True"),
// Test0.vb(29,12): warning CA1508: 'str <> param' is always 'False'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(29, 12, "str <> param", "False"));
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Fact]
public async Task NullCompare_SwitchStatement_01_NoDiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
class Test
{
void M1(C param, int i)
{
switch (i)
{
case 0:
param = new C();
break;
case 1:
param = null;
break;
default:
return;
}
if (param != null)
{
}
}
}
class C
{
}
");
await VerifyBasicAnalyzerAsync(@"
Class Test
Private Sub M(param As C, i As Integer)
Select Case i
Case 0
param = New C()
Case 1
param = Nothing
Case Else
Return
End Select
If param IsNot Nothing Then
End If
End Sub
End Class
Class C
End Class
");
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Fact]
public async Task NullCompare_SwitchStatement_02_NoDiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
class Test
{
void M(C param, int i)
{
switch (i)
{
case 0:
param = new C();
break;
case 1:
return;
default:
param = null;
break;
}
if (param != null)
{
}
}
}
class C
{
}
");
await VerifyBasicAnalyzerAsync(@"
Class Test
Private Sub M(param As C, i As Integer)
Select Case i
Case 0
param = New C()
Case 1
Return
Case Else
param = Nothing
End Select
If param IsNot Nothing Then
End If
End Sub
End Class
Class C
End Class
");
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Fact]
public async Task NullCompare_SwitchStatement_03_NoDiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
class Test
{
void M(C param, int i)
{
switch (i)
{
case 0:
param = new C();
return;
case 1:
return;
default:
param = new C();
return;
}
if (param != null)
{
}
}
}
class C
{
}
");
await VerifyBasicAnalyzerAsync(@"
Class Test
Private Sub M(param As C, i As Integer)
Select Case i
Case 0
param = New C()
Return
Case 1
Return
Case Else
param = Nothing
Return
End Select
If param IsNot Nothing Then
End If
End Sub
End Class
Class C
End Class
");
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Fact]
public async Task NullCompare_SwitchStatement_01_DiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
class Test
{
void M(C param, int i)
{
switch (i)
{
case 0:
param = new C();
break;
case 1:
param = new C();
break;
default:
return;
}
if (param != null)
{
}
}
}
class C
{
}
",
// Test0.cs(20,13): warning CA1508: 'param != null' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(20, 13, "param != null", "true"));
await VerifyBasicAnalyzerAsync(@"
Class Test
Private Sub M(param As C, i As Integer)
Select Case i
Case 0
param = New C()
Case 1
param = New C()
Case Else
Return
End Select
If param IsNot Nothing Then
End If
End Sub
End Class
Class C
End Class
",
// Test0.vb(13,12): warning CA1508: 'param IsNot Nothing' is always 'True'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(13, 12, "param IsNot Nothing", "True"));
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Fact]
public async Task NullCompare_SwitchStatement_02_DiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
class Test
{
void M(C param, int i)
{
switch (i)
{
default:
param = null;
break;
case 1:
return;
case 0:
param = null;
break;
}
if (param != null)
{
}
}
}
class C
{
}
",
// Test0.cs(20,13): warning CA1508: 'param != null' is always 'false'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(20, 13, "param != null", "false"));
await VerifyBasicAnalyzerAsync(@"
Class Test
Private Sub M(param As C, i As Integer)
Select Case i
Case 1
Return
Case 0
param = Nothing
Case Else
param = Nothing
End Select
If param IsNot Nothing Then
End If
End Sub
End Class
Class C
End Class
",
// Test0.vb(13,12): warning CA1508: 'param IsNot Nothing' is always 'False'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(13, 12, "param IsNot Nothing", "False"));
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.CopyAnalysis)]
[Fact]
public async Task NullCompare_CopyAnalysisAsync()
{
await VerifyCSharpAnalyzerAsync(@"
class Test
{
void M1(C param, C param2)
{
C cNotNull = new C();
if (param == cNotNull && param2 == cNotNull && param == param2)
{
}
param = param2;
if (param != cNotNull || param2 != cNotNull)
{
}
}
}
class C
{
}
",
// Test0.cs(7,56): warning CA1508: 'param == param2' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(7, 56, "param == param2", "true"),
// Test0.cs(12,34): warning CA1508: 'param2 != cNotNull' is always 'false'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(12, 34, "param2 != cNotNull", "false"));
await VerifyBasicAnalyzerAsync(@"
Module Test
Sub M1(param As C, param2 As C)
Dim cNotNull As New C()
If param Is cNotNull AndAlso param2 Is cNotNull AndAlso param Is param2 Then
End If
param = param2
If param IsNot cNotNull OrElse param2 IsNot cNotNull Then
End If
End Sub
End Module
Class C
End Class
",
// Test0.vb(5,65): warning CA1508: 'param Is param2' is always 'True'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(5, 65, "param Is param2", "True"),
// Test0.vb(9,40): warning CA1508: 'param2 IsNot cNotNull' is always 'False'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(9, 40, "param2 IsNot cNotNull", "False"));
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Fact]
public async Task NullCompare_ConditionalOr_NoDiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
class Test
{
void M1(string param, string param2)
{
string strNotNull = """";
string strNull = null;
string strMayBeNull = param2;
if (param == strNotNull || param == strNull)
{
}
if (strNull != param || param == strMayBeNull)
{
}
if (param == strMayBeNull || strNull != param)
{
}
}
}
");
await VerifyBasicAnalyzerAsync(@"
Module Test
Sub M1(param As String, param2 As String)
Dim strNotNull = """"
Dim strNull = Nothing
Dim strMayBeNull = param2
If param = strNotNull OrElse param = strNull Then
End If
If strNull <> param OrElse param = strMayBeNull Then
End If
If param = strMayBeNull OrElse strNull <> param Then
End If
End Sub
End Module");
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Fact]
public async Task NullCompare_ConditionalOr_DiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
class Test
{
void M1(string param, string param2)
{
string strNotNull = """";
string strNull = null;
string strMayBeNull = param2;
if (strNull != param || param == strNotNull)
{
}
if (param != strNotNull || strNull != param)
{
}
}
}
",
// Test0.cs(10,33): warning CA1508: 'param == strNotNull' is always 'false'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(10, 33, "param == strNotNull", "false"),
// Test0.cs(14,36): warning CA1508: 'strNull != param' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(14, 36, "strNull != param", "true"));
await VerifyBasicAnalyzerAsync(@"
Module Test
Sub M1(param As String, param2 As String)
Dim strNotNull = """"
Dim strNull = Nothing
Dim strMayBeNull = param2
If strNull <> param OrElse param = strNotNull Then
End If
If param <> strNotNull OrElse strNull <> param Then
End If
End Sub
End Module",
// Test0.vb(8,36): warning CA1508: 'param = strNotNull' is always 'False'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(8, 36, "param = strNotNull", "False"),
// Test0.vb(11,39): warning CA1508: 'strNull <> param' is always 'True'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(11, 39, "strNull <> param", "True"));
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Fact]
public async Task NullCompare_ConditionalAnd_NoDiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
class Test
{
void M1(string param, string param2)
{
string strNotNull = """";
string strNull = null;
string strMayBeNull = param2;
if (param == strNotNull && param2 == strNull)
{
}
if (param == strMayBeNull && strNull == param)
{
}
if (param != strNotNull && param != strNull)
{
}
if (param != strNotNull && param2 != strNull)
{
}
if (strNull != param && param == strMayBeNull)
{
}
if (param2 == strNull && param != strNotNull && param == param2)
{
}
if (strNull != param && param == strNotNull)
{
}
}
}
");
await VerifyBasicAnalyzerAsync(@"
Module Test
Sub M1(param As String, param2 As String, flag As Boolean)
Dim strNotNull = """"
Dim strNull = Nothing
Dim strMayBeNull = param2
If param = strNotNull AndAlso param2 = strNull Then
End If
If param = strMayBeNull AndAlso strNull = param Then
End If
If strNull <> param AndAlso param <> strNotNull Then
End If
If strNull <> param AndAlso param2 <> strNotNull Then
End If
If strNull <> param AndAlso param = strMayBeNull Then
End If
If param2 = strNull AndAlso param <> strNotNull AndAlso param = param2 Then
End If
If strNull <> param AndAlso param = strNotNull Then
End If
End Sub
End Module");
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Fact]
public async Task NullCompare_ConditionalAnd_DiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
class Test
{
void M1(string param, string param2)
{
string strNotNull = """";
string strNull = null;
string strMayBeNull = param2;
if (param == strNotNull && param != strNull)
{
}
if (strNull != param || (param == strMayBeNull && strNull != param))
{
}
}
}
",
// Test0.cs(10,36): warning CA1508: 'param != strNull' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(10, 36, "param != strNull", "true"),
// Test0.cs(14,59): warning CA1508: 'strNull != param' is always 'false'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(14, 59, "strNull != param", "false"));
await VerifyBasicAnalyzerAsync(@"
Module Test
Sub M1(param As String, param2 As String)
Dim strNotNull = """"
Dim strNull = Nothing
Dim strMayBeNull = param2
If param = strNotNull AndAlso param <> strNull Then
End If
If strNull <> param OrElse (param = strMayBeNull AndAlso strNull <> param) Then
System.Console.Write("""")
End If
End Sub
End Module",
// Test0.vb(8,39): warning CA1508: 'param <> strNull' is always 'True'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(8, 39, "param <> strNull", "True"),
// Test0.vb(11,66): warning CA1508: 'strNull <> param' is always 'False'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(11, 66, "strNull <> param", "False"));
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Fact]
public async Task ConditionaAndOrNullCompare_DiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
class Test
{
void M1(string param)
{
string str = """";
if (param != null || param == str)
{
}
if (null == param && param != str)
{
}
}
}
",
// Test0.cs(7,30): warning CA1508: 'param == str' is always 'false'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(7, 30, "param == str", "false"),
// Test0.cs(11,30): warning CA1508: 'param != str' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(11, 30, "param != str", "true"));
await VerifyBasicAnalyzerAsync(@"
Module Test
Sub M1(param As String)
Dim str = """"
If param <> Nothing OrElse param = str Then
End If
If Nothing = param AndAlso param <> str Then
End If
End Sub
End Module",
// Test0.vb(5,36): warning CA1508: 'param = str' is always 'False'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(5, 36, "param = str", "False"),
// Test0.vb(8,36): warning CA1508: 'param <> str' is always 'True'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(8, 36, "param <> str", "True"));
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Fact]
public async Task NullCompare_ContractCheck_NoDiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
class C
{
}
class Test
{
void M1(C param)
{
System.Diagnostics.Contracts.Contract.Requires(param != null);
}
void M2(C param, C param2, C param3)
{
System.Diagnostics.Contracts.Contract.Requires(param == param2 && !(param2 != null) || param2 == param3);
}
}
");
await VerifyBasicAnalyzerAsync(@"
Class C
End Class
Module Test
Private Sub M1(param As C)
System.Diagnostics.Contracts.Contract.Requires(param IsNot Nothing)
End Sub
Private Sub M2(param As C, param2 As C, param3 As C)
System.Diagnostics.Contracts.Contract.Requires(param Is param2 AndAlso Not(param2 IsNot Nothing) OrElse param2 Is param3)
End Sub
End Module");
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Fact]
public async Task NullCompare_ContractCheck_DiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
class C
{
}
class Test
{
void M1(C param)
{
C c = null;
param = null;
System.Diagnostics.Contracts.Contract.Requires(param == c);
}
void M2(C param)
{
C c = null;
param = null;
System.Diagnostics.Contracts.Contract.Requires(param != c);
}
void M3(C param)
{
var c = new C();
param = param ?? c;
System.Diagnostics.Contracts.Contract.Requires(param == null);
}
void M4(C param)
{
var c = new C();
param = param ?? c;
System.Diagnostics.Contracts.Contract.Requires(param != null);
}
}
",
// Test0.cs(12,56): warning CA1508: 'param == c' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(12, 56, "param == c", "true"),
// Test0.cs(19,56): warning CA1508: 'param != c' is always 'false'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(19, 56, "param != c", "false"),
// Test0.cs(26,56): warning CA1508: 'param == null' is always 'false'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(26, 56, "param == null", "false"),
// Test0.cs(33,56): warning CA1508: 'param != null' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(33, 56, "param != null", "true"));
await VerifyBasicAnalyzerAsync(@"
Class C
End Class
Module Test
Private Sub M1(param As C)
Dim c As C = Nothing
param = Nothing
System.Diagnostics.Contracts.Contract.Requires(param Is c)
End Sub
Private Sub M2(param As C)
Dim c As C = Nothing
param = Nothing
System.Diagnostics.Contracts.Contract.Requires(param IsNot c)
End Sub
Private Sub M3(param As C)
Dim c As C = New C()
param = If (param, c)
System.Diagnostics.Contracts.Contract.Requires(param Is Nothing)
End Sub
Private Sub M4(param As C)
Dim c As C = New C()
param = If (param, c)
System.Diagnostics.Contracts.Contract.Requires(param IsNot Nothing)
End Sub
End Module",
// Test0.vb(9,56): warning CA1508: 'param Is c' is always 'True'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(9, 56, "param Is c", "True"),
// Test0.vb(15,56): warning CA1508: 'param IsNot c' is always 'False'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(15, 56, "param IsNot c", "False"),
// Test0.vb(21,56): warning CA1508: 'param Is Nothing' is always 'False'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(21, 56, "param Is Nothing", "False"),
// Test0.vb(27,56): warning CA1508: 'param IsNot Nothing' is always 'True'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(27, 56, "param IsNot Nothing", "True"));
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Fact]
public async Task NullCompare_InAssignment_DiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
class C
{
}
class Test
{
void M1(C param)
{
C c = null;
param = null;
bool flag = param == c;
}
}
",
// Test0.cs(12,21): warning CA1508: 'param == c' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(12, 21, "param == c", "true"));
await VerifyBasicAnalyzerAsync(@"
Class C
End Class
Module Test
Private Sub M1(param As C)
Dim c As C = Nothing
param = Nothing
Dim flag As Boolean = param Is c
End Sub
End Module",
// Test0.vb(9,31): warning CA1508: 'param Is c' is always 'True'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(9, 31, "param Is c", "True"));
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Fact]
public async Task NullCompare_Nested_NoDiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
class C
{
}
class Test
{
void M1(C param)
{
if (param == null)
{
param = M2();
if (param == null)
{
}
}
}
C M2() => new C();
}
");
await VerifyBasicAnalyzerAsync(@"
Class C
End Class
Module Test
Private Sub M1(param As C)
If param Is Nothing Then
param = M2()
If param Is Nothing Then
End If
End If
End Sub
Private Function M2() As C
Return New C()
End Function
End Module");
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Fact]
public async Task NullCoalesce_NoDiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
class C
{
}
class Test
{
void M1(C param, bool flag)
{
param = param ?? new C();
C c = flag ? null : new C();
c = c ?? new C();
}
}
");
await VerifyBasicAnalyzerAsync(@"
Class C
End Class
Module Test
Private Sub M1(param As C, flag As Boolean)
param = If (param, New C())
Dim c As C = If (flag, Nothing, New C())
c = If (c, New C())
End Sub
End Module");
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Fact]
public async Task NullCoalesce_DiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
class C
{
}
class Test
{
void M1(C param)
{
C c = null;
param = c ?? new C();
}
void M2(C param)
{
C c = new C();
param = c ?? new C();
}
void M3(C param)
{
var local = param ?? throw new System.ArgumentNullException(nameof(param));
local = local ?? new C();
}
}
",
// Test0.cs(11,17): warning CA1508: 'c' is always 'null'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(11, 17, "c", "null"),
// Test0.cs(17,17): warning CA1508: 'c' is never 'null'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpNeverNullResultAt(17, 17, "c", "null"),
// Test0.cs(23,17): warning CA1508: 'local' is never 'null'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpNeverNullResultAt(23, 17, "local", "null"));
await VerifyBasicAnalyzerAsync(@"
Class C
End Class
Module Test
Private Sub M1(param As C)
Dim c As C = Nothing
param = If (c, New C())
End Sub
Private Sub M2(param As C)
Dim c As C = New C()
param = If (c, New C())
End Sub
End Module",
// Test0.vb(8,21): warning CA1508: 'c' is always 'Nothing'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(8, 21, "c", "Nothing"),
// Test0.vb(13,21): warning CA1508: 'c' is never 'Nothing'. Remove or refactor the condition(s) to avoid dead code.
GetBasicNeverNullResultAt(13, 21, "c", "Nothing"));
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Fact]
public async Task NullCoalesce_NullableValueType_NoDiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
class C
{
public int X;
}
class Test
{
void M1(C param)
{
var x = param?.X ?? 0;
}
}
");
await VerifyBasicAnalyzerAsync(@"
Class C
Public X As Integer
End Class
Module Test
Private Sub M1(param As C)
Dim x = If(param?.X, 0)
End Sub
End Module");
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Fact]
public async Task NullCoalesce_NullableValueType_DiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
class Test
{
void M1(int? x)
{
x = null;
if (x == null)
{
return;
}
}
}
",
// Test0.cs(7,13): warning CA1508: 'x == null' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(7, 13, "x == null", "true"));
await VerifyBasicAnalyzerAsync(@"
Module Test
Private Sub M1(x As Integer?)
x = Nothing
If x Is Nothing Then
End If
End Sub
End Module",
// Test0.vb(5,12): warning CA1508: 'x Is Nothing' is always 'True'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(5, 12, "x Is Nothing", "True"));
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Fact]
public async Task ConditionalAccess_NoDiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
class C
{
public int X;
}
class Test
{
void M1(C param, bool flag)
{
var x = param?.X;
C c = flag ? null : new C();
x = c?.X;
}
}
");
await VerifyBasicAnalyzerAsync(@"
Class C
Public X As Integer
End Class
Module Test
Private Sub M1(param As C, flag As Boolean)
Dim x = param?.X
Dim c As C = If (flag, Nothing, New C())
x = c?.X
End Sub
End Module");
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Fact]
public async Task ConditionalAccess_DiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
class C
{
public int X;
}
class Test
{
void M1(C param)
{
param = null;
var x = param?.X;
}
void M2(C param)
{
param = new C();
var x = param?.X;
}
void M3(C param)
{
var local = param ?? throw new System.ArgumentNullException(nameof(param));
var x = local?.X;
}
}
",
// Test0.cs(12,17): warning CA1508: 'param' is always 'null'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(12, 17, "param", "null"),
// Test0.cs(18,17): warning CA1508: 'param' is never 'null'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpNeverNullResultAt(18, 17, "param", "null"),
// Test0.cs(24,17): warning CA1508: 'local' is never 'null'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpNeverNullResultAt(24, 17, "local", "null"));
await VerifyBasicAnalyzerAsync(@"
Class C
Public X As Integer
End Class
Module Test
Private Sub M1(param As C)
param = Nothing
Dim x = param?.X
End Sub
Private Sub M2(param As C)
param = New C()
Dim x = param?.X
End Sub
End Module",
// Test0.vb(9,17): warning CA1508: 'param' is always 'Nothing'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(9, 17, "param", "Nothing"),
// Test0.vb(14,17): warning CA1508: 'param' is never 'Nothing'. Remove or refactor the condition(s) to avoid dead code.
GetBasicNeverNullResultAt(14, 17, "param", "Nothing"));
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Fact]
public async Task ConditionalAccessNullCoalesce_Field_NoDiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
class C
{
public int X;
}
class Test
{
public C _c;
void M1()
{
var x = _c?.X;
var y = _c ?? new C();
}
}
");
await VerifyBasicAnalyzerAsync(@"
Class C
Public X As Integer
End Class
Class Test
Public _c As C
Private Sub M1()
Dim x = _c?.X
Dim x2 = If(_c, new C())
End Sub
End Class");
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.CopyAnalysis)]
[Fact]
public async Task NullCheck_AfterTryCast_NoDiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
class C
{
}
class D: C
{
}
class Test
{
void M1(C c)
{
if (c == null)
{
return;
}
var d = c as D;
if (d == null)
{
return;
}
if (c is D)
{
return;
}
}
}
");
await VerifyBasicAnalyzerAsync(@"
Class C
End Class
Class D
Inherits C
End Class
Class Test
Private Sub M1(c As C)
If c Is Nothing Then
Return
End If
Dim d = TryCast(c, D)
If d Is Nothing Then
Return
End If
If TypeOf(c) Is D Then
Return
End If
End Sub
End Class");
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.CopyAnalysis)]
[Fact]
public async Task NullCheck_AfterTryCast_02_NoDiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
class C
{
}
class D: C
{
}
class Test
{
void M1(C c, bool flag)
{
if (flag)
{
c = new D();
}
else
{
c = new C();
}
var d = c as D;
if (d == null)
{
return;
}
if (d == c)
{
return;
}
}
void M2(C c, bool flag)
{
if (flag)
{
c = new D();
}
else
{
c = null;
}
var d = c as D;
if (d == null)
{
return;
}
if (d == c)
{
return;
}
}
}
");
await VerifyBasicAnalyzerAsync(@"
Class C
End Class
Class D
Inherits C
End Class
Class Test
Private Sub M1(c As C, flag As Boolean)
If flag Then
c = New D()
Else
c = New C()
End If
Dim d = TryCast(c, D)
If d Is Nothing Then
Return
End If
If d Is c Then
Return
End If
End Sub
Private Sub M2(c As C, flag As Boolean)
If flag Then
c = New D()
Else
c = Nothing
End If
Dim d = TryCast(c, D)
If d Is Nothing Then
Return
End If
If d Is c Then
Return
End If
End Sub
End Class");
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.CopyAnalysis)]
[Fact, WorkItem(4411, "https://github.com/dotnet/roslyn-analyzers/issues/4411")]
public async Task NullCheck_AfterTryCast_03_NoDiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
class A
{
void M(object o)
{
if (o is A a)
{
_ = (a as B)?.ToString();
}
}
}
class B : A
{
}
");
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.CopyAnalysis)]
[Fact, WorkItem(4383, "https://github.com/dotnet/roslyn-analyzers/issues/4383")]
public async Task NullCheck_AfterTryCast_04_NoDiagnosticAsync()
{
await new VerifyCS.Test
{
TestCode = @"
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
internal static class Class1
{
public static ReadOnlyDictionary<TKey, ReadOnlyCollection<TValue>> AsReadOnlyItems<TKey, TValue>(this IDictionary<TKey, IList<TValue>> self, IEqualityComparer<TKey> keyComparer = null)
{
_ = self ?? throw new ArgumentNullException(nameof(self));
keyComparer ??= (self as Dictionary<TKey, TValue>)?.Comparer;
var copy = new Dictionary<TKey, ReadOnlyCollection<TValue>>(self.Count, keyComparer);
foreach (var kvp in self)
{
if (kvp.Value is null)
{
copy.Add(kvp.Key, null);
continue;
}
var readOnlyValue = kvp.Value as ReadOnlyCollection<TValue> ?? new ReadOnlyCollection<TValue>(kvp.Value);
copy.Add(kvp.Key, readOnlyValue);
}
return new ReadOnlyDictionary<TKey, ReadOnlyCollection<TValue>>(copy);
}
}",
LanguageVersion = CodeAnalysis.CSharp.LanguageVersion.CSharp8,
}.RunAsync();
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.CopyAnalysis)]
[Fact]
public async Task NullCheck_AfterTryCast_DiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
class C
{
}
class D: C
{
}
class Test
{
void M1(C c)
{
c = new D();
var d = c as D;
if (d == null)
{
return;
}
}
void M2(C c)
{
c = new D();
var d = c as D;
if (d == c)
{
return;
}
}
}
",
// Test0.cs(16,13): warning CA1508: 'd == null' is always 'false'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(16, 13, "d == null", "false"),
// Test0.cs(26,13): warning CA1508: 'd == c' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(26, 13, "d == c", "true"));
await VerifyBasicAnalyzerAsync(@"
Class C
End Class
Class D
Inherits C
End Class
Class Test
Private Sub M1(c As C)
c = New D()
Dim d = TryCast(c, D)
If d Is Nothing Then
Return
End If
End Sub
Private Sub M2(c As C)
c = New D()
Dim d = TryCast(c, D)
If d Is c Then
Return
End If
End Sub
End Class",
// Test0.vb(13,12): warning CA1508: 'd Is Nothing' is always 'False'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(13, 12, "d Is Nothing", "False"),
// Test0.vb(21,12): warning CA1508: 'd Is c' is always 'True'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(21, 12, "d Is c", "True"));
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.CopyAnalysis)]
[Fact]
public async Task NullCheck_AfterTryCast_02_DiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
class C
{
}
class D: C
{
}
class E_DerivesFromD: D
{
}
class F_DerivesFromC: C
{
}
class G_DerivesFromF: F_DerivesFromC
{
}
class Test
{
void M1(C c, bool flag)
{
if (flag)
{
c = new D();
}
else
{
c = new E_DerivesFromD();
}
var d = c as D;
if (d == null)
{
return;
}
}
void M2(C c, bool flag)
{
if (flag)
{
c = new D();
}
else
{
c = new E_DerivesFromD();
}
var d = c as D;
if (d != c)
{
return;
}
}
void M3(C c, bool flag)
{
if (flag)
{
c = new F_DerivesFromC();
}
else
{
c = new G_DerivesFromF();
}
var d = c as D;
if (d == null)
{
return;
}
}
void M4(C c, bool flag)
{
if (flag)
{
c = new F_DerivesFromC();
}
else
{
c = new G_DerivesFromF();
}
var d = c as D;
if (d != c)
{
return;
}
}
}
",
// Test0.cs(36,13): warning CA1508: 'd == null' is always 'false'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(36, 13, "d == null", "false"),
// Test0.cs(54,13): warning CA1508: 'd != c' is always 'false'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(54, 13, "d != c", "false"),
// Test0.cs(72,13): warning CA1508: 'd == null' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(72, 13, "d == null", "true"),
// Test0.cs(90,13): warning CA1508: 'd != c' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(90, 13, "d != c", "true"));
await VerifyBasicAnalyzerAsync(@"
Class C
End Class
Class D
Inherits C
End Class
Class E_DerivesFromD
Inherits D
End Class
Class F_DerivesFromC
Inherits C
End Class
Class G_DerivesFromF
Inherits F_DerivesFromC
End Class
Class Test
Private Sub M1(c As C, flag As Boolean)
If flag Then
c = New D()
Else
c = New E_DerivesFromD()
End If
Dim d = TryCast(c, D)
If d Is Nothing Then
Return
End If
End Sub
Private Sub M2(c As C, flag As Boolean)
If flag Then
c = New D()
Else
c = New E_DerivesFromD()
End If
Dim d = TryCast(c, D)
If d IsNot c Then
Return
End If
End Sub
Private Sub M3(c As C, flag As Boolean)
If flag Then
c = New F_DerivesFromC()
Else
c = New G_DerivesFromF()
End If
Dim d = TryCast(c, D)
If d Is Nothing Then
Return
End If
End Sub
Private Sub M4(c As C, flag As Boolean)
If flag Then
c = New F_DerivesFromC()
Else
c = New G_DerivesFromF()
End If
Dim d = TryCast(c, D)
If d IsNot c Then
Return
End If
End Sub
End Class",
// Test0.vb(35,12): warning CA1508: 'd Is Nothing' is always 'False'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(35, 12, "d Is Nothing", "False"),
// Test0.vb(48,12): warning CA1508: 'd IsNot c' is always 'False'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(48, 12, "d IsNot c", "False"),
// Test0.vb(61,12): warning CA1508: 'd Is Nothing' is always 'True'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(61, 12, "d Is Nothing", "True"),
// Test0.vb(74,12): warning CA1508: 'd IsNot c' is always 'True'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(74, 12, "d IsNot c", "True"));
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.CopyAnalysis)]
[Fact]
public async Task NullCheck_AfterTryCast_IsPattern_DiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
class C
{
}
class D: C
{
}
class Test
{
void M1_IsDeclarationPattern_AlwaysTrue(C c1)
{
c1 = new D();
if (c1 is D d1)
{
return;
}
}
void M1_IsDeclarationPattern_AlwaysFalse(C c2)
{
c2 = null;
if (c2 is D d2)
{
return;
}
}
void M1_IsConstantPattern_AlwaysTrue(C c3)
{
c3 = new C();
var d3 = c3 as D; // Our analysis is currently conservative here.
if (d3 is null)
{
return;
}
}
void M1_IsConstantPattern_AlwaysFalse(C c4)
{
c4 = new D();
var d4 = c4 as D;
if (d4 is null)
{
return;
}
}
void M2_IsDeclarationPattern_AlwaysTrue(C c5)
{
c5 = new D();
var d5 = c5 as D;
if (d5 is C c5_2)
{
return;
}
}
}
",
// Test0.cs(15,13): warning CA1508: 'c1 is D d1' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(15, 13, "c1 is D d1", "true"),
// Test0.cs(24,13): warning CA1508: 'c2 is D d2' is always 'false'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(24, 13, "c2 is D d2", "false"),
// Test0.cs(44,13): warning CA1508: 'd4 is null' is always 'false'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(44, 13, "d4 is null", "false"),
// Test0.cs(54,13): warning CA1508: 'd5 is C c5_2' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(54, 13, "d5 is C c5_2", "true"));
// VB does not support patterns.
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.CopyAnalysis)]
[Fact]
public async Task DeclarationPattern_DiscardSymbol_DiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
class C
{
}
class D: C
{
}
class Test
{
bool M1(C c1)
{
switch (c1)
{
case D _:
return true;
case C c2:
return c1 == c2;
default:
return true;
}
}
}
",
// Test0.cs(20,24): warning CA1508: 'c1 == c2' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(20, 24, "c1 == c2", "true"));
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.CopyAnalysis)]
[Fact]
public async Task NullCheck_AfterTryCast_IsPattern_NoDiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
class C
{
}
class D: C
{
}
class Test
{
void M1_IsDeclarationPattern(C c1, bool flag)
{
c1 = new D();
if (flag)
{
c1 = new C();
}
if (c1 is D d1)
{
return;
}
}
void M1_IsConstantPattern(C c2, bool flag)
{
c2 = new D();
if (flag)
{
c2 = new C();
}
var d2 = c2 as D;
if (d2 is null)
{
return;
}
}
}
");
// VB does not support patterns.
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.CopyAnalysis)]
[Fact]
public async Task NullCheck_AfterTryCast_Interfaces_NoDiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
interface I
{
}
interface I2 : I
{
}
class C : I
{
}
class Test
{
void M1(object o)
{
if (o == null)
{
return;
}
var i = o as I;
if (i == null)
{
return;
}
var i2 = i as I2;
if (i2 == null)
{
return;
}
var c = i as C;
if (c == null)
{
return;
}
}
}
");
await VerifyBasicAnalyzerAsync(@"
Interface I
End Interface
Interface I2
Inherits I
End Interface
Class C
Implements I
End Class
Class Test
Private Sub M1(o As Object)
If o Is Nothing Then
Return
End If
Dim i = TryCast(o, I)
If i Is Nothing Then
Return
End If
Dim i2 = TryCast(i, I2)
If i2 Is Nothing Then
Return
End If
Dim c = TryCast(i, C)
If c Is Nothing Then
Return
End If
End Sub
End Class");
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.CopyAnalysis)]
[Fact]
public async Task NullCheck_AfterTryCast_Interfaces_DiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
interface I
{
}
interface I2 : I
{
}
class C : I
{
}
class Test
{
void M1(C c, I2 i2)
{
if (c == null || i2 == null)
{
return;
}
var i = c as I;
if (i == null)
{
return;
}
i = i2 as I;
if (i == null)
{
return;
}
}
}
",
// Test0.cs(24,13): warning CA1508: 'i == null' is always 'false'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(24, 13, "i == null", "false"),
// Test0.cs(30,13): warning CA1508: 'i == null' is always 'false'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(30, 13, "i == null", "false"));
await VerifyBasicAnalyzerAsync(@"
Interface I
End Interface
Interface I2
Inherits I
End Interface
Class C
Implements I
End Class
Class Test
Private Sub M1(c As C, i2 As I2)
If c Is Nothing OrElse i2 Is Nothing Then
Return
End If
Dim i = TryCast(c, I)
If i Is Nothing Then
Return
End If
i = TryCast(i2, I)
If i Is Nothing Then
Return
End If
End Sub
End Class",
// Test0.vb(20,12): warning CA1508: 'i Is Nothing' is always 'False'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(20, 12, "i Is Nothing", "False"),
// Test0.vb(25,12): warning CA1508: 'i Is Nothing' is always 'False'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(25, 12, "i Is Nothing", "False"));
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.CopyAnalysis)]
[Fact]
public async Task NullCheck_AfterTryCast_TypeParameter_NoDiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
class C
{
}
class D : C
{
}
class Test<T>
where T : C
{
void M1(C c)
{
if (c == null)
{
return;
}
var t = c as T;
if (t == null)
{
return;
}
}
void M2(T t)
{
if (t == null)
{
return;
}
var d = t as D;
if (d == null)
{
return;
}
}
}
");
await VerifyBasicAnalyzerAsync(@"
Class C
End Class
Class D
Inherits C
End Class
Class Test(Of T As C)
Private Sub M1(c As C)
If c Is Nothing Then
Return
End If
Dim t = TryCast(c, T)
If t Is Nothing Then
Return
End If
End Sub
Private Sub M2(t As T)
If t Is Nothing Then
Return
End If
Dim d = TryCast(t, D)
If d Is Nothing Then
Return
End If
End Sub
End Class");
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.CopyAnalysis)]
[Fact]
public async Task NullCheck_AfterTryCast_TypeParameter_DiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
class C
{
}
class D : C
{
}
class Test<T>
where T : C
{
void M1(T t)
{
if (t == null)
{
return;
}
var c = t as C;
if (c == null)
{
return;
}
}
}
",
// Test0.cs(21,13): warning CA1508: 'c == null' is always 'false'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(21, 13, "c == null", "false"));
await VerifyBasicAnalyzerAsync(@"
Class C
End Class
Class D
Inherits C
End Class
Class Test(Of T As C)
Private Sub M1(t As T)
If t Is Nothing Then
Return
End If
Dim c = TryCast(t, C)
If c Is Nothing Then
Return
End If
End Sub
End Class",
// Test0.vb(16,12): warning CA1508: 'c Is Nothing' is always 'False'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(16, 12, "c Is Nothing", "False"));
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.CopyAnalysis)]
[Fact]
public async Task NullCheck_AfterDirectCast_NoDiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
class C
{
}
class D: C
{
}
class Test
{
void M1(C c, bool flag)
{
if (flag)
{
c = new D();
}
else
{
c = null;
}
var d = (D)c;
if (d == null)
{
return;
}
}
}
");
await VerifyBasicAnalyzerAsync(@"
Class C
End Class
Class D
Inherits C
End Class
Class Test
Private Sub M1(c As C, flag As Boolean)
If flag Then
c = New D()
Else
c = Nothing
End If
Dim d = TryCast(c, D)
If d Is Nothing Then
Return
End If
End Sub
End Class");
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.CopyAnalysis)]
[Fact]
public async Task NullCheck_AfterDirectCast_NarrowingConversion_NoDiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
class Test
{
void M1(int value)
{
if ((sbyte)value == value)
{
}
}
}
");
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.CopyAnalysis)]
[Fact, WorkItem(4415, "https://github.com/dotnet/roslyn-analyzers/issues/4415")]
public async Task NullCheck_AfterDirectCast_NullableValueType_NoDiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
using System;
internal class Class1
{
public static void M(object obj)
{
var d = (DateTime?)obj;
if (d != null)
{
}
}
}
");
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.CopyAnalysis)]
[Fact]
public async Task NullCheck_AfterDirectCast_DiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
class C
{
}
class D: C
{
}
class Test
{
void M1(C c)
{
if (c == null)
{
return;
}
var d = (D)c;
if (d == null)
{
return;
}
}
}
",
// Test0.cs(20,13): warning CA1508: 'd == null' is always 'false'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(20, 13, "d == null", "false"));
await VerifyBasicAnalyzerAsync(@"
Class C
End Class
Class D
Inherits C
End Class
Class Test
Private Sub M1(c As C)
If c Is Nothing Then
Return
End If
Dim d = DirectCast(c, D)
If d Is Nothing Then
Return
End If
End Sub
End Class",
// Test0.vb(16,12): warning CA1508: 'd Is Nothing' is always 'False'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(16, 12, "d Is Nothing", "False"));
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.CopyAnalysis)]
[Fact]
public async Task NullCheck_AfterDirectCast_02_DiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
class C
{
}
class D: C
{
}
class Test
{
void M1(C c)
{
if (c == null)
{
return;
}
var d = (D)c;
if (d == c)
{
return;
}
}
}
",
// Test0.cs(20,13): warning CA1508: 'd == c' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(20, 13, "d == c", "true"));
await VerifyBasicAnalyzerAsync(@"
Class C
End Class
Class D
Inherits C
End Class
Class Test
Private Sub M1(c As C)
If c Is Nothing Then
Return
End If
Dim d = DirectCast(c, D)
If d Is c Then
Return
End If
End Sub
End Class",
// Test0.vb(16,12): warning CA1508: 'd Is c' is always 'True'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(16, 12, "d Is c", "True"));
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.CopyAnalysis)]
[Fact]
public async Task NullCheck_AfterDirectCast_03_DiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
class C
{
}
class D: C
{
}
class Test
{
void M1(C c, bool flag)
{
if (flag)
{
c = new D();
}
else
{
c = new C();
}
var d = (D)c;
if (d == null)
{
return;
}
if (d == c)
{
return;
}
}
void M2(C c, bool flag)
{
if (flag)
{
c = new D();
}
else
{
c = null;
}
var d = (D)c;
if (d == null)
{
return;
}
if (d == c)
{
return;
}
}
}
",
// Test0.cs(24,13): warning CA1508: 'd == null' is always 'false'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(24, 13, "d == null", "false"),
// Test0.cs(29,13): warning CA1508: 'd == c' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(29, 13, "d == c", "true"),
// Test0.cs(52,13): warning CA1508: 'd == c' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(52, 13, "d == c", "true"));
await VerifyBasicAnalyzerAsync(@"
Class C
End Class
Class D
Inherits C
End Class
Class Test
Private Sub M1(c As C, flag As Boolean)
If flag Then
c = New D()
Else
c = New C()
End If
Dim d = DirectCast(c, D)
If d Is Nothing Then
Return
End If
If d Is c Then
Return
End If
End Sub
Private Sub M2(c As C, flag As Boolean)
If flag Then
c = New D()
Else
c = Nothing
End If
Dim d = DirectCast(c, D)
If d Is Nothing Then
Return
End If
If d Is c Then
Return
End If
End Sub
End Class",
// Test0.vb(18,12): warning CA1508: 'd Is Nothing' is always 'False'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(18, 12, "d Is Nothing", "False"),
// Test0.vb(22,12): warning CA1508: 'd Is c' is always 'True'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(22, 12, "d Is c", "True"),
// Test0.vb(39,12): warning CA1508: 'd Is c' is always 'True'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(39, 12, "d Is c", "True"));
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.CopyAnalysis)]
[Fact]
public async Task NullCheck_AfterDirectCast_04_DiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
class C
{
}
class D: C
{
}
class Test
{
void M1(C c)
{
c = new D();
var local = c;
var d = (D)c;
if (d == local)
{
return;
}
}
}
",
// Test0.cs(17,13): warning CA1508: 'd == local' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(17, 13, "d == local", "true"));
await VerifyBasicAnalyzerAsync(@"
Class C
End Class
Class D
Inherits C
End Class
Class Test
Private Sub M1(c As C)
c = New D()
Dim local = c
Dim d = DirectCast(c, D)
If d Is local Then
Return
End If
End Sub
End Class",
// Test0.vb(14,12): warning CA1508: 'd Is local' is always 'True'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(14, 12, "d Is local", "True"));
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.CopyAnalysis)]
[Fact]
public async Task NullCheck_AfterDirectCast_05_DiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
class C
{
}
class D: C
{
}
class E_DerivesFromC : C
{
}
class Test
{
void M1(C c)
{
c = new E_DerivesFromC();
var local = c;
var d = (D)c;
if (d == local)
{
return;
}
}
}
",
// Test0.cs(21,13): warning CA1508: 'd == local' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(21, 13, "d == local", "true"));
await VerifyBasicAnalyzerAsync(@"
Class C
End Class
Class D
Inherits C
End Class
Class E_DerivesFromC
Inherits C
End Class
Class Test
Private Sub M1(c As C)
c = New E_DerivesFromC()
Dim local = c
Dim d = DirectCast(c, D)
If d Is local Then
Return
End If
End Sub
End Class",
// Test0.vb(18,12): warning CA1508: 'd Is local' is always 'True'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(18, 12, "d Is local", "True"));
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.CopyAnalysis)]
[Fact]
public async Task NullCheck_AfterDirectCast_Interfaces_NoDiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
interface I
{
}
interface I2 : I
{
}
class C : I
{
}
class Test
{
void M1(object o)
{
var i = (I)o;
if (i == null)
{
return;
}
}
void M2(I i)
{
var i2 = (I2)i;
if (i2 == null)
{
return;
}
}
void M3(I i)
{
var c = (C)i;
if (c == null)
{
return;
}
}
}
");
await VerifyBasicAnalyzerAsync(@"
Interface I
End Interface
Interface I2
Inherits I
End Interface
Class C
Implements I
End Class
Class Test
Private Sub M1(o As Object)
Dim i = DirectCast(o, I)
If i Is Nothing Then
Return
End If
End Sub
Private Sub M2(i As I)
Dim i2 = DirectCast(i, I2)
If i2 Is Nothing Then
Return
End If
End Sub
Private Sub M3(i As I)
Dim c = DirectCast(i, C)
If c Is Nothing Then
Return
End If
End Sub
End Class");
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.CopyAnalysis)]
[Fact]
public async Task NullCheck_AfterDirectCast_Interfaces_DiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
interface I
{
}
interface I2 : I
{
}
class C : I
{
}
class Test
{
void M1(C c, I2 i2)
{
if (c == null || i2 == null)
{
return;
}
var i = (I)c;
if (i == null)
{
return;
}
i = (I)i2;
if (i == null)
{
return;
}
}
}
",
// Test0.cs(24,13): warning CA1508: 'i == null' is always 'false'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(24, 13, "i == null", "false"),
// Test0.cs(30,13): warning CA1508: 'i == null' is always 'false'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(30, 13, "i == null", "false"));
await VerifyBasicAnalyzerAsync(@"
Interface I
End Interface
Interface I2
Inherits I
End Interface
Class C
Implements I
End Class
Class Test
Private Sub M1(c As C, i2 As I2)
If c Is Nothing OrElse i2 Is Nothing Then
Return
End If
Dim i = DirectCast(c, I)
If i Is Nothing Then
Return
End If
i = DirectCast(i2, I)
If i Is Nothing Then
Return
End If
End Sub
End Class",
// Test0.vb(20,12): warning CA1508: 'i Is Nothing' is always 'False'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(20, 12, "i Is Nothing", "False"),
// Test0.vb(25,12): warning CA1508: 'i Is Nothing' is always 'False'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(25, 12, "i Is Nothing", "False"));
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.CopyAnalysis)]
[Fact]
public async Task NullCheck_AfterDirectCast_Interfaces_02_DiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
interface I
{
}
interface I2 : I
{
}
class C : I
{
}
class Test
{
void M1(object o)
{
if (o == null)
{
return;
}
var i = (I)o;
if (i == null)
{
return;
}
var i2 = (I2)i;
if (i2 == null)
{
return;
}
var c = (C)i;
if (c == null)
{
return;
}
}
}
",
// Test0.cs(24,13): warning CA1508: 'i == null' is always 'false'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(24, 13, "i == null", "false"),
// Test0.cs(30,13): warning CA1508: 'i2 == null' is always 'false'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(30, 13, "i2 == null", "false"),
// Test0.cs(36,13): warning CA1508: 'c == null' is always 'false'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(36, 13, "c == null", "false"));
await VerifyBasicAnalyzerAsync(@"
Interface I
End Interface
Interface I2
Inherits I
End Interface
Class C
Implements I
End Class
Class Test
Private Sub M1(o As Object)
If o Is Nothing Then
Return
End If
Dim i = DirectCast(o, I)
If i Is Nothing Then
Return
End If
Dim i2 = DirectCast(i, I2)
If i2 Is Nothing Then
Return
End If
Dim c = DirectCast(i, C)
If c Is Nothing Then
Return
End If
End Sub
End Class",
// Test0.vb(20,12): warning CA1508: 'i Is Nothing' is always 'False'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(20, 12, "i Is Nothing", "False"),
// Test0.vb(25,12): warning CA1508: 'i2 Is Nothing' is always 'False'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(25, 12, "i2 Is Nothing", "False"),
// Test0.vb(30,12): warning CA1508: 'c Is Nothing' is always 'False'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(30, 12, "c Is Nothing", "False"));
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.CopyAnalysis)]
[Fact]
public async Task NullCheck_AfterDirectCast_TypeParameter_NoDiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
class C
{
}
class D : C
{
}
class Test<T>
where T : C
{
void M1(T t)
{
if (t == null)
{
return;
}
var d = {|CS0030:(D)t|}; // Compiler error CS0030: Cannot convert type 'T' to 'D'
if (d == null)
{
return;
}
}
}
");
await VerifyBasicAnalyzerAsync(@"
Class C
End Class
Class D
Inherits C
End Class
Class Test(Of T As C)
Private Sub M1(t As T)
If t Is Nothing Then
Return
End If
Dim d = DirectCast({|BC30311:t|}, D) ' Compiler error BC30311: Value of type 'T' cannot be converted to 'D'
If d Is Nothing Then
Return
End If
End Sub
End Class");
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.CopyAnalysis)]
[Fact]
public async Task NullCheck_AfterDirectCast_TypeParameter_DiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
class C
{
}
class D : C
{
}
class Test<T>
where T : C
{
void M1(C c)
{
if (c == null)
{
return;
}
var t = (T)c;
if (t == null)
{
return;
}
}
void M2(T t)
{
if (t == null)
{
return;
}
var c = (C)t;
if (c == null)
{
return;
}
}
}
",
// Test0.cs(21,13): warning CA1508: 't == null' is always 'false'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(21, 13, "t == null", "false"),
// Test0.cs(35,13): warning CA1508: 'c == null' is always 'false'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(35, 13, "c == null", "false"));
await VerifyBasicAnalyzerAsync(@"
Class C
End Class
Class D
Inherits C
End Class
Class Test(Of T As C)
Private Sub M1(c As C)
If c Is Nothing Then
Return
End If
Dim t = DirectCast(c, T)
If t Is Nothing Then
Return
End If
End Sub
Private Sub M2(t As T)
If t Is Nothing Then
Return
End If
Dim c = DirectCast(t, C)
If c Is Nothing Then
Return
End If
End Sub
End Class",
// Test0.vb(16,12): warning CA1508: 't Is Nothing' is always 'False'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(16, 12, "t Is Nothing", "False"),
// Test0.vb(27,12): warning CA1508: 'c Is Nothing' is always 'False'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(27, 12, "c Is Nothing", "False"));
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.CopyAnalysis)]
[Fact]
public async Task NullCheck_ThrowExpressionWithoutArgument_NoDiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
class C
{
}
class Test
{
void M1(C c)
{
try
{
}
catch (System.Exception ex)
{
if (c == null)
{
throw;
}
}
}
}
");
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.CopyAnalysis)]
[Fact]
public async Task NullCheck_AssignedInCatch_NoDiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
class C
{
}
class Test
{
void M1()
{
object o = null;
try
{
}
catch (System.Exception ex)
{
o = ex;
}
catch
{
o = null;
}
if (o != null)
{
return;
}
}
}
");
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.CopyAnalysis)]
[Fact]
public async Task NullCheck_OutArgument_NoDiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
class C
{
public void Cleanup() { }
}
class Test
{
bool M1()
{
C c = null;
try
{
if (M2(out c))
{
return true;
}
}
finally
{
c?.Cleanup();
}
return false;
}
bool M2(out C c)
{
c = new C();
return true;
}
}
");
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.CopyAnalysis)]
[Fact]
public async Task NullCheck_RefArgument_NoDiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
class Test
{
void M1(int count)
{
int initialCount = count;
M2(ref count);
if (initialCount == count)
{
}
}
int M2(ref int count)
{
count++;
return 0;
}
}
");
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.CopyAnalysis)]
[Fact]
public async Task NullCheck_LogicalOr_NoDiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
class Test
{
void M1(int x, int y)
{
var z = x;
z |= y;
if (z == x)
{
}
}
}
");
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.CopyAnalysis)]
[Fact]
public async Task NullCheck_DeconstructionAssignment_NoDiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
class C
{
}
class Test
{
void M1(int x, int y)
{
C c = null;
(c, x) = M2();
if (c != null)
{
}
}
(C, int) M2() => (new C(), 0);
}
");
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.CopyAnalysis)]
[Fact]
public async Task NullCheck_DeconstructionAssignment_InLambda_NoDiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
class C
{
}
class Test
{
void M1(int x, int y)
{
C c = null;
System.Action a = () => (c, x) = M2();
a();
if (c != null)
{
}
}
(C, int) M2() => (new C(), 0);
}
");
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.CopyAnalysis)]
[Fact(Skip = "https://github.com/dotnet/roslyn-analyzers/issues/1647")]
public async Task NullCheck_DeconstructionAssignment_InLambdaPassedAsArgument_NoDiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
class C
{
}
class Test
{
void M1(int x, int y)
{
C c = null;
System.Action a = () => (c, x) = M2();
Invoke(a);
if (c != null)
{
}
}
(C, int) M2() => (new C(), 0);
void Invoke(System.Action a) => a();
}
");
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.CopyAnalysis)]
[Fact]
public async Task NullCheck_AwaitExpression_NoDiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
using System.Threading.Tasks;
class Test
{
Task<Test> M() => null;
async Task M2()
{
Test t = await M();
if (t == null)
{
return;
}
}
}
");
await VerifyBasicAnalyzerAsync(@"
Imports System.Threading.Tasks
Class Test
Private Function M() As Task(Of Test)
Return Nothing
End Function
Private Async Function M2() As Task
Dim t As Test = Await M()
If t Is Nothing Then
Return
End If
End Function
End Class
");
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.CopyAnalysis)]
[Fact]
public async Task NullCheck_CollectionAddAndCount_NoDiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
using System.Collections.Generic;
class Test
{
void M(List<int> map)
{
System.Action a = () => {};
a();
var initialCount = map.Count;
map.Add(0);
if (map.Count == initialCount)
{
return;
}
}
}
class C
{
}
");
await VerifyBasicAnalyzerAsync(@"
Imports System.Collections.Immutable
Class Test
Private Sub M(map As ImmutableDictionary(Of C, Integer).Builder, arr As C())
Dim initialCount = map.Count
For Each element in arr
map.Add(element, 0)
Next
If map.Count = initialCount Then
Return
End If
End Sub
End Class
Class C
End Class
");
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Fact]
public async Task NullCheck_BothSidesOfEquals_NoDiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
class Test
{
void M(Test a, Test b)
{
// If a is not-null, ensure b is not null.
// If a is null, b may or may not be null.
if ((a != null && b != null) == (a != null))
{
return;
}
if ((a != null) == (a != null && b != null))
{
return;
}
}
}
");
await VerifyBasicAnalyzerAsync(@"
Class Test
Private Sub M(a As Test, b As Test)
' If a is not-null, ensure b is not null.
' If a is null, b may or may not be null.
If (a IsNot Nothing AndAlso b IsNot Nothing) = (a IsNot Nothing) Then
Return
End If
If (a IsNot Nothing) = (a IsNot Nothing AndAlso b IsNot Nothing) Then
Return
End If
End Sub
End Class
");
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Fact]
public async Task ConditionalAccessCheck_InsideLocalFunction_NoDiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
class Test
{
public bool Flag;
bool? M(Test t)
{
bool? MyFunc() { return t?.Flag; }
return MyFunc();
}
}
");
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Fact]
public async Task ConditionalAccessCheck_InsideLocalFunction_02_NoDiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
class Test
{
public bool Flag;
bool? M(Test t)
{
return MyFunc();
bool? MyFunc() { return t?.Flag; }
}
}
");
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Fact]
public async Task ConditionalAccessCheck_InsideInitializer_NoDiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
class C
{
public bool Flag;
}
class Base
{
protected Base(bool b) { }
}
class Test : Base
{
public Test(C c)
: base(c?.Flag == true)
{
var x = c?.Flag == true;
}
}
");
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Fact, WorkItem(1650, "https://github.com/dotnet/roslyn-analyzers/issues/1650")]
public async Task ConditionalAccessCheck_InsideConstructorInitializer_DiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
class C
{
public bool Flag;
}
class Base
{
protected Base(bool b) { }
}
class Test : Base
{
public Test(C c)
: base(c != null ? (c?.Flag == true) : false)
{
var x = c != null;
}
}
",
// Test0.cs(15,29): warning CA1508: 'c' is never 'null'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpNeverNullResultAt(15, 29, "c", "null"));
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Fact, WorkItem(1650, "https://github.com/dotnet/roslyn-analyzers/issues/1650")]
public async Task ConditionalAccessCheck_InsideFieldInitializer_DiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
class C
{
public bool Flag;
}
class Test
{
private static C c;
private bool b = c != null ? (c?.Flag == true) : false;
}
",
// Test0.cs(10,35): warning CA1508: 'c' is never 'null'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpNeverNullResultAt(10, 35, "c", "null"));
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Fact, WorkItem(1650, "https://github.com/dotnet/roslyn-analyzers/issues/1650")]
public async Task ConditionalAccessCheck_InsidePropertyInitializer_ExpressionBody_DiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
class C
{
public bool Flag;
}
class Test
{
private static C c1, c2;
private bool B1 => c1 != null ? (c1?.Flag == true) : false;
private bool B2 { get; } = c2 != null ? (c2?.Flag == true) : false;
}
",
// Test0.cs(10,38): warning CA1508: 'c1' is never 'null'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpNeverNullResultAt(10, 38, "c1", "null"),
// Test0.cs(11,46): warning CA1508: 'c2' is never 'null'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpNeverNullResultAt(11, 46, "c2", "null"));
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Fact]
public async Task InsideLockStatement_FieldCheck_NoDiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
class C
{
}
class Test
{
private C _c;
private readonly object _gate = new object();
void EnsureC()
{
if (_c == null)
{
lock (_gate)
{
if (_c == null)
{
_c = new C();
}
}
}
}
}
");
await VerifyBasicAnalyzerAsync(@"
Class C
End Class
Class Test
Private _c As C
Private ReadOnly _gate As New Object
Private Sub EnsureC()
If _c Is Nothing Then
SyncLock _gate
If _c Is Nothing Then
_c = New C()
End If
End SyncLock
End If
End Sub
End Class");
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.CopyAnalysis)]
[Fact]
public async Task TestCompilerGeneratedNullCheckNotFlaggedAsync()
{
await VerifyCSharpAnalyzerAsync(@"
using System;
public class C : IDisposable
{
public void Dispose() { }
public void M(C c)
{
if (c == null)
{
return;
}
// Compiler implicitly generates a null-check for assigned variable here.
// We should not flag compiler generate operations as redundant.
using (c = new C())
{
}
}
}");
}
#if NETCOREAPP
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.CopyAnalysis)]
[Fact, WorkItem(4327, "https://github.com/dotnet/roslyn-analyzers/issues/4327")]
public async Task TestCompilerGeneratedNullCheckNotFlagged_02Async()
{
await new VerifyCS.Test
{
TestCode = @"
using System.Collections.Generic;
using System.Threading.Tasks;
class Class1
{
static async IAsyncEnumerable<int> M(IAsyncEnumerable<int> iae)
{
await foreach (int i in iae.ConfigureAwait(false))
{
if (i > 0)
yield return i;
}
}
}",
LanguageVersion = CodeAnalysis.CSharp.LanguageVersion.CSharp8,
}.RunAsync();
}
#endif
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.CopyAnalysis)]
[Fact, WorkItem(4382, "https://github.com/dotnet/roslyn-analyzers/issues/4382")]
public async Task TestCompilerGeneratedNullCheckNotFlagged_03Async()
{
await VerifyCSharpAnalyzerAsync(@"
using System;
class C
{
void F(IDisposable x)
{
if (x != null)
{
using (x) { }
}
}
}");
}
[Fact]
public async Task StaticObjectReferenceEquals_DiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
public class C
{
public int X;
}
public class Test
{
public void M1(C c)
{
if (ReferenceEquals(c, null))
{
return;
}
if (c != null)
{
}
}
public void M2(C c, C c2)
{
if (!ReferenceEquals(c, c2))
{
return;
}
if (c != c2)
{
}
}
public void M3(C c, C c2)
{
if (c != c2)
{
return;
}
if (!ReferenceEquals(c, c2))
{
}
}
}",
// Test0.cs(16,13): warning CA1508: 'c != null' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(16, 13, "c != null", "true"),
// Test0.cs(28,13): warning CA1508: 'c != c2' is always 'false'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(28, 13, "c != c2", "false"),
// Test0.cs(40,14): warning CA1508: 'ReferenceEquals(c, c2)' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(40, 14, "ReferenceEquals(c, c2)", "true"));
await VerifyBasicAnalyzerAsync(@"
Public Class C
Public X As Integer
End Class
Public Class Test
Public Sub M1(c As C)
If ReferenceEquals(c, Nothing) Then
Return
End If
If c IsNot Nothing Then
End If
End Sub
Public Sub M2(c As C, c2 As C)
If Not ReferenceEquals(c, c2) Then
Return
End If
If c IsNot c2 Then
End If
End Sub
Public Sub M3(c As C, c2 As C)
If c IsNot c2 Then
Return
End If
If Not ReferenceEquals(c, c2) Then
End If
End Sub
End Class",
// Test0.vb(12,12): warning CA1508: 'c IsNot Nothing' is always 'True'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(12, 12, "c IsNot Nothing", "True"),
// Test0.vb(21,12): warning CA1508: 'c IsNot c2' is always 'False'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(21, 12, "c IsNot c2", "False"),
// Test0.vb(30,16): warning CA1508: 'ReferenceEquals(c, c2)' is always 'True'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(30, 16, "ReferenceEquals(c, c2)", "True"));
}
[Fact]
public async Task StaticObjectEquals_NoObjectEqualsOverride_DiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
public class C
{
public int X;
}
public class Test
{
public void M1(C c)
{
if (object.Equals(c, null))
{
return;
}
if (c != null)
{
}
}
public void M2(C c, C c2)
{
if (!object.Equals(c, c2))
{
return;
}
if (c != c2)
{
}
}
public void M3(C c, C c2)
{
if (c != c2)
{
return;
}
if (!object.Equals(c, c2))
{
}
}
}",
// Test0.cs(16,13): warning CA1508: 'c != null' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(16, 13, "c != null", "true"),
// Test0.cs(28,13): warning CA1508: 'c != c2' is always 'false'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(28, 13, "c != c2", "false"),
// Test0.cs(40,14): warning CA1508: 'object.Equals(c, c2)' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(40, 14, "object.Equals(c, c2)", "true"));
await VerifyBasicAnalyzerAsync(@"
Public Class C
Public X As Integer
End Class
Public Class Test
Public Sub M1(c As C)
If object.Equals(c, Nothing) Then
Return
End If
If c IsNot Nothing Then
End If
End Sub
Public Sub M2(c As C, c2 As C)
If Not object.Equals(c, c2) Then
Return
End If
If c IsNot c2 Then
End If
End Sub
Public Sub M3(c As C, c2 As C)
If c IsNot c2 Then
Return
End If
If Not object.Equals(c, c2) Then
End If
End Sub
End Class",
// Test0.vb(12,12): warning CA1508: 'c IsNot Nothing' is always 'True'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(12, 12, "c IsNot Nothing", "True"),
// Test0.vb(21,12): warning CA1508: 'c IsNot c2' is always 'False'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(21, 12, "c IsNot c2", "False"),
// Test0.vb(30,16): warning CA1508: 'object.Equals(c, c2)' is always 'True'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(30, 16, "object.Equals(c, c2)", "True"));
}
[Fact]
public async Task StaticObjectEquals_ObjectEqualsOverride_DiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
public class C
{
public int X;
public override bool Equals(object other) => true;
}
public class Test
{
public void M1(C c)
{
if (object.Equals(c, null))
{
return;
}
if (c != null)
{
}
}
public void M2(C c, C c2)
{
if (!object.Equals(c, c2))
{
return;
}
if (c != c2) // No diagnostic reported here as 'object.Equals(c, c2)' does not guarantee reference equality due to Equals override in C.
{
}
}
public void M3(C c, C c2)
{
if (c != c2)
{
return;
}
if (!object.Equals(c, c2))
{
}
}
}",
// Test0.cs(18,13): warning CA1508: 'c != null' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(18, 13, "c != null", "true"),
// Test0.cs(42,14): warning CA1508: 'object.Equals(c, c2)' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(42, 14, "object.Equals(c, c2)", "true"));
await VerifyBasicAnalyzerAsync(@"
Public Class C
Public X As Integer
Public Overrides Function Equals(other As Object) As Boolean
Return True
End Function
End Class
Public Class Test
Public Sub M1(c As C)
If object.Equals(c, Nothing) Then
Return
End If
If c IsNot Nothing Then
End If
End Sub
Public Sub M2(c As C, c2 As C)
If Not object.Equals(c, c2) Then
Return
End If
If c IsNot c2 Then ' No diagnostic reported here as 'object.Equals(c, c2)' does not guarantee reference equality due to Equals override in C.
End If
End Sub
Public Sub M3(c As C, c2 As C)
If c IsNot c2 Then
Return
End If
If Not object.Equals(c, c2) Then
End If
End Sub
End Class",
// Test0.vb(16,12): warning CA1508: 'c IsNot Nothing' is always 'True'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(16, 12, "c IsNot Nothing", "True"),
// Test0.vb(34,16): warning CA1508: 'object.Equals(c, c2)' is always 'True'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(34, 16, "object.Equals(c, c2)", "True"));
}
[Fact]
public async Task ObjectEquals_NoObjectEqualsOverride_DiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
public class C
{
public int X;
}
public class Test
{
public void M1(C c, C c2)
{
if (c == null || !c.Equals(c2))
{
return;
}
if (c2 != null)
{
}
}
public void M2(C c, C c2)
{
if (!c.Equals(c2))
{
return;
}
if (c != c2)
{
}
}
public void M3(C c, C c2)
{
if (c != c2)
{
return;
}
if (!c.Equals(c2))
{
}
}
}",
// Test0.cs(16,13): warning CA1508: 'c2 != null' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(16, 13, "c2 != null", "true"),
// Test0.cs(28,13): warning CA1508: 'c != c2' is always 'false'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(28, 13, "c != c2", "false"),
// Test0.cs(40,14): warning CA1508: 'c.Equals(c2)' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(40, 14, "c.Equals(c2)", "true"));
await VerifyBasicAnalyzerAsync(@"
Public Class C
Public X As Integer
End Class
Public Class Test
Public Sub M1(c As C, c2 As C)
If c Is Nothing OrElse Not c.Equals(c2) Then
Return
End If
If c2 IsNot Nothing Then
End If
End Sub
Public Sub M2(c As C, c2 As C)
If Not c.Equals(c2) Then
Return
End If
If c IsNot c2 Then
End If
End Sub
Public Sub M3(c As C, c2 As C)
If c IsNot c2 Then
Return
End If
If Not c.Equals(c2) Then
End If
End Sub
End Class",
// Test0.vb(12,12): warning CA1508: 'c2 IsNot Nothing' is always 'True'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(12, 12, "c2 IsNot Nothing", "True"),
// Test0.vb(21,12): warning CA1508: 'c IsNot c2' is always 'False'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(21, 12, "c IsNot c2", "False"),
// Test0.vb(30,16): warning CA1508: 'c.Equals(c2)' is always 'True'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(30, 16, "c.Equals(c2)", "True"));
}
[Fact]
public async Task ObjectEquals_ObjectEqualsOverride_DiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
public class C
{
public int X;
public override bool Equals(object other) => true;
}
public class Test
{
public void M1(C c, C c2)
{
if (c == null || !c.Equals(c2))
{
return;
}
if (c2 != null)
{
}
}
public void M2(C c, C c2)
{
if (!c.Equals(c2))
{
return;
}
if (c != c2) // No diagnostic reported here as 'c.Equals(c2)' only guarantees value equality.
{
}
}
public void M3(C c, C c2)
{
if (c != c2)
{
return;
}
if (!c.Equals(c2))
{
}
}
}",
// Test0.cs(18,13): warning CA1508: 'c2 != null' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(18, 13, "c2 != null", "true"),
// Test0.cs(42,14): warning CA1508: 'c.Equals(c2)' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(42, 14, "c.Equals(c2)", "true"));
await VerifyBasicAnalyzerAsync(@"
Public Class C
Public X As Integer
Public Overrides Function Equals(other As Object) As Boolean
Return True
End Function
End Class
Public Class Test
Public Sub M1(c As C, c2 As C)
If c Is Nothing OrElse Not c.Equals(c2) Then
Return
End If
If c2 IsNot Nothing Then
End If
End Sub
Public Sub M2(c As C, c2 As C)
If Not c.Equals(c2) Then
Return
End If
If c IsNot c2 Then ' No diagnostic reported here as 'c.Equals(c2)' only guarantees value equality.
End If
End Sub
Public Sub M3(c As C, c2 As C)
If c IsNot c2 Then
Return
End If
If Not c.Equals(c2) Then
End If
End Sub
End Class",
// Test0.vb(16,12): warning CA1508: 'c2 IsNot Nothing' is always 'True'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(16, 12, "c2 IsNot Nothing", "True"),
// Test0.vb(34,16): warning CA1508: 'c.Equals(c2)' is always 'True'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(34, 16, "c.Equals(c2)", "True"));
}
[Fact]
public async Task IEquatableEquals_ExplicitImplementation_DiagnosticAsync()
{
// Explicit implementation of Equals means c1.Equals(c2) performs
// reference equality using object.Equals(object) overload.
await VerifyCSharpAnalyzerAsync(@"
using System;
public class C : IEquatable<C>
{
public int X;
bool IEquatable<C>.Equals(C other) => true;
}
public class Test
{
public void M1(C c, C c2)
{
if (c == null || !c.Equals(c2))
{
return;
}
if (c2 != null)
{
}
}
public void M2(C c, C c2)
{
if (!c.Equals(c2))
{
return;
}
if (c != c2)
{
}
}
public void M3(C c, C c2)
{
if (c != c2)
{
return;
}
if (!c.Equals(c2))
{
}
}
}
",
// Test0.cs(20,13): warning CA1508: 'c2 != null' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(20, 13, "c2 != null", "true"),
// Test0.cs(32,13): warning CA1508: 'c != c2' is always 'false'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(32, 13, "c != c2", "false"),
// Test0.cs(44,14): warning CA1508: 'c.Equals(c2)' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(44, 14, "c.Equals(c2)", "true"));
await VerifyBasicAnalyzerAsync(@"
Imports System
Public Class C
Implements IEquatable(Of C)
Public X As Integer
Private Function Equals(other As C) As Boolean Implements IEquatable(Of C).Equals
Return True
End Function
End Class
Public Class Test
Public Sub M1(c As C, c2 As C)
If c Is Nothing OrElse Not c.Equals(c2) Then
Return
End If
If c2 IsNot Nothing Then
End If
End Sub
Public Sub M2(c As C, c2 As C)
If Not c.Equals(c2) Then
Return
End If
If c IsNot c2 Then
End If
End Sub
Public Sub M3(c As C, c2 As C)
If c IsNot c2 Then
Return
End If
If Not c.Equals(c2) Then
End If
End Sub
End Class",
// Test0.vb(19,12): warning CA1508: 'c2 IsNot Nothing' is always 'True'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(19, 12, "c2 IsNot Nothing", "True"),
// Test0.vb(28,12): warning CA1508: 'c IsNot c2' is always 'False'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(28, 12, "c IsNot c2", "False"),
// Test0.vb(37,16): warning CA1508: 'c.Equals(c2)' is always 'True'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(37, 16, "c.Equals(c2)", "True"));
}
[Fact]
public async Task IEquatableEquals_ImplicitImplementation_DiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
using System;
public class C : IEquatable<C>
{
public int X;
public bool Equals(C other) => true;
}
public class Test
{
public void M1(C c, C c2)
{
if (c == null || !c.Equals(c2))
{
return;
}
if (c2 != null)
{
}
}
public void M2(C c, C c2)
{
if (!c.Equals(c2))
{
return;
}
if (c != c2) // No diagnostic reported here as 'c.Equals(c2)' only guarantees value equality.
{
}
}
public void M3(C c, C c2)
{
if (c != c2)
{
return;
}
if (!c.Equals(c2))
{
}
}
}
",
// Test0.cs(20,13): warning CA1508: 'c2 != null' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(20, 13, "c2 != null", "true"),
// Test0.cs(44,14): warning CA1508: 'c.Equals(c2)' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(44, 14, "c.Equals(c2)", "true"));
}
[Fact]
public async Task IEquatableEquals_Override_DiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
using System;
public abstract class MyEquatable<T> : IEquatable<T>
{
public abstract bool Equals(T other);
}
public class C : MyEquatable<C>
{
public int X;
public override bool Equals(C other) => true;
}
public class Test
{
public void M1(C c, C c2)
{
if (c == null || !c.Equals(c2))
{
return;
}
if (c2 != null)
{
}
}
public void M2(C c, C c2)
{
if (!c.Equals(c2))
{
return;
}
if (c != c2) // No diagnostic reported here as 'c.Equals(c2)' only guarantees value equality.
{
}
}
public void M3(C c, C c2)
{
if (c != c2)
{
return;
}
if (!c.Equals(c2))
{
}
}
}
",
// Test0.cs(24,13): warning CA1508: 'c2 != null' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(24, 13, "c2 != null", "true"),
// Test0.cs(48,14): warning CA1508: 'c.Equals(c2)' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(48, 14, "c.Equals(c2)", "true"));
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Fact]
public async Task MultidimensionalArray_NoDiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
class Test
{
void M()
{
var x = new int[,] { { 1, 2 }, { 2, 3 } };
if (x == null)
{
}
}
}
",
// Test0.cs(7,13): warning CA1508: 'x == null' is always 'false'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(7, 13, "x == null", "false"));
await VerifyBasicAnalyzerAsync(@"
Class Test
Private Sub M()
Dim x = New Integer(,) { { 1, 2 }, { 2, 3 } }
If x Is Nothing Then
End If
End Sub
End Class
",
// Test0.vb(5,12): warning CA1508: 'x Is Nothing' is always 'False'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(5, 12, "x Is Nothing", "False"));
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.CopyAnalysis)]
[Fact]
public async Task NullCheck_LambdaResult_DiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
class Test
{
void M1()
{
string x = null;
System.Func<string, bool> isNonNull = s => s != null;
if (isNonNull(x))
{
return;
}
}
}
",
// Test0.cs(9,13): warning CA1508: 'isNonNull(x)' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(9, 13, "isNonNull(x)", "true"));
await VerifyBasicAnalyzerAsync(@"
Class Test
Private Sub M1()
Dim x As String = Nothing
Dim isNonNull As System.Func(Of String, Boolean) = Function(s) s IsNot Nothing
If isNonNull(x) Then
Return
End If
End Sub
End Class
",
// Test0.vb(7,12): warning CA1508: 'isNonNull(x)' is always 'True'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(7, 12, "isNonNull(x)", "True"));
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.CopyAnalysis)]
[Fact]
public async Task NullCheck_LambdaResult_EditorConfig_NoInterproceduralLambdaAnalysis_NoDiagnosticAsync()
{
const string editorConfigText = "dotnet_code_quality.max_interprocedural_lambda_or_local_function_call_chain = 0";
await new VerifyCS.Test
{
TestState =
{
Sources =
{
@"
class Test
{
void M1()
{
string x = null;
System.Func<string, bool> isNonNull = s => s != null;
if (isNonNull(x))
{
return;
}
}
}
"
},
AnalyzerConfigFiles = { ("/.editorconfig", $@"root = true
[*]
{editorConfigText}
") }
}
}.RunAsync();
await new VerifyVB.Test
{
TestState =
{
Sources =
{
@"
Class Test
Private Sub M1()
Dim x As String = Nothing
Dim isNonNull As System.Func(Of String, Boolean) = Function(s) s IsNot Nothing
If isNonNull(x) Then
Return
End If
End Sub
End Class
"
},
AnalyzerConfigFiles = { ("/.editorconfig", $@"root = true
[*]
{editorConfigText}
") }
}
}.RunAsync();
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.CopyAnalysis)]
[Fact]
public async Task NullCheck_LambdaResult_NoDiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
class Test
{
void M1()
{
System.Action<string> myLambda = (string x) =>
{
System.Func<string, bool> isNonNull = s => s != null;
if (isNonNull(x))
{
return;
}
};
myLambda(null);
}
}
");
await VerifyBasicAnalyzerAsync(@"
Class Test
Private Sub M1()
Dim myLambda As System.Action(Of String) = Sub(x As String)
Dim isNonNull As System.Func(Of String, Boolean) = Function(s) s IsNot Nothing
If isNonNull(x) Then
Return
End If
End Sub
myLambda(Nothing)
End Sub
End Class");
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.CopyAnalysis)]
[Fact]
public async Task NullCheck_LambdaResult_NoDiagnostic_02Async()
{
await VerifyCSharpAnalyzerAsync(@"
class Test
{
void M1()
{
System.Action<string> myLambda = (string x) =>
{
System.Func<string, bool> isNonNull = s => s != null;
if (isNonNull(x))
{
return;
}
};
myLambda(null);
myLambda("""");
}
}
");
await VerifyBasicAnalyzerAsync(@"
Class Test
Private Sub M1()
Dim myLambda As System.Action(Of String) = Sub(x As String)
Dim isNonNull As System.Func(Of String, Boolean) = Function(s) s IsNot Nothing
If isNonNull(x) Then
Return
End If
End Sub
myLambda(Nothing)
myLambda("""")
End Sub
End Class");
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.CopyAnalysis)]
[Fact]
public async Task NullCheck_LambdaResult_NoDiagnostic_03Async()
{
// We do not analyze lambdas/local functions independent of the calling context
// Hence no diagnostic reported for dead code in lambda here.
await VerifyCSharpAnalyzerAsync(@"
class Test
{
void M1()
{
System.Action myLambda = () =>
{
System.Func<string, bool> isNonNull = s => s != null;
if (isNonNull(null))
{
return;
}
};
myLambda();
}
}
");
await VerifyBasicAnalyzerAsync(@"
Class Test
Private Sub M1()
Dim myLambda As System.Action = Sub()
Dim isNonNull As System.Func(Of String, Boolean) = Function(s) s IsNot Nothing
If isNonNull(Nothing) Then
Return
End If
End Sub
myLambda()
End Sub
End Class");
}
[Fact, WorkItem(1855, "https://github.com/dotnet/roslyn-analyzers/issues/1855")]
public async Task PointsToAbstractValue_MakeMayBeNull_AssertsKindNotEqualKnownKnownLValueCapturesAsync()
{
await VerifyCSharpAnalyzerAsync(@"
using System;
using System.Collections.Generic;
using System.Linq;
namespace Blah
{
public class SomeSetting
{
private string[] _modules;
private readonly IDictionary<string, string> _values;
public SomeSetting()
{
_values = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
Modules = new string[0];
}
public SomeSetting(SomeSetting settings)
{
_values = new Dictionary<string, string>(settings._values, StringComparer.OrdinalIgnoreCase);
Modules = settings.Modules;
}
public string this[string key]
{
get
{
string retVal;
return _values.TryGetValue(key, out retVal) ? retVal : null;
}
set { _values[key] = value; }
}
/// <summary>
/// List of available modules for this setting
/// </summary>
public string[] Modules
{
get
{
return _modules ?? (Modules = (_values[""Modules""] ?? """").Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries))
.Select(t => t.Trim())
.ToArray();
}
set
{
_modules = value;
this[""Modules""] = string.Join("";"", value);
}
}
}
}");
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.CopyAnalysis)]
[Fact]
public async Task NullCompare_Unboxing_InstanceEntityAssertAsync()
{
await VerifyCSharpAnalyzerAsync(@"
struct S
{
public C C { get; }
}
class C
{
private object _field;
public void M(C c)
{
var x = (_field as C) ?? ((S)_field).C;
}
}");
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Fact]
public async Task NullCompare_PointsToFlowCaptureAssertAsync()
{
await VerifyCSharpAnalyzerAsync(@"
class C
{
private C _field;
public void M(int[] array, int x)
{
C c = null;
C c2 = null;
C c3 = null;
LocalFunction2();
LocalFunction3();
void LocalFunction()
{
c = c ?? GetC();
c.M2();
}
void LocalFunction2()
{
LocalFunction();
c2 = c2 ?? GetC();
c2.M2();
}
void LocalFunction3()
{
LocalFunction();
c3 = c3 ?? GetC();
c3.M2();
}
}
C GetC() => _field;
void M2() { }
}");
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Fact]
public async Task NestedLambdaAndLocalFunctionsWithCapturesAsync()
{
await VerifyCSharpAnalyzerAsync(@"
using System;
class C
{
public void M(C p, C p1, C p2)
{
C l1 = p1;
LocalFunction();
return;
void LocalFunction()
{
C l2 = p2;
M2(s => s != null && p != null && l1 != null && l2 != null);
}
}
void M2(Func<C, bool> f) { }
}");
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.CopyAnalysis)]
[Fact]
public async Task CopyAnalysisAssert_IndexerArrayAccessWithCastAsync()
{
await VerifyCSharpAnalyzerAsync(@"
public struct S
{
public object Value { get; }
}
public class C
{
public void M(S[] arguments)
{
for (int i = 0; i < arguments.Length; i++)
{
if (arguments[i].Value != null)
{
var value = (string)arguments[i].Value;
var value2 = (S)arguments[i + 1].Value;
}
}
}
}");
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.PointsToAnalysis)]
[Fact, WorkItem(6616, "https://github.com/dotnet/roslyn-analyzers/issues/6616")]
public async Task IndexedArrayAccessWithConstantsAndNonConstants_NoDiagnosticsAsync()
{
await new VerifyCS.Test
{
TestCode = @"
#nullable enable
using System;
namespace Test
{
public static class Test
{
public static void Method1()
{
// default
var objPlayers = new object?[] { null };
for (var idx = 0; idx < 1; idx++)
{
objPlayers[idx] = $""{idx}"";
}
// validate
if (objPlayers[0] is null) // CA1508: Always true (should probably be unknown)
{
}
}
public static void Method2(object?[] objPlayers, int idx)
{
objPlayers[0] = null;
objPlayers[idx] = 0;
if (objPlayers[0] is null) // CA1508: Always true (should probably be unknown)
{
}
}
}
}",
LanguageVersion = CodeAnalysis.CSharp.LanguageVersion.CSharp8,
}.RunAsync();
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.PointsToAnalysis)]
[Fact, WorkItem(6616, "https://github.com/dotnet/roslyn-analyzers/issues/6616")]
public async Task IndexedArrayAccessWithConstantsAndNonConstants_DiagnosticsAsync()
{
await new VerifyCS.Test
{
TestCode = @"
#nullable enable
using System;
namespace Test
{
public static class Test
{
public static void Method1(object?[][] objPlayers, int idx)
{
objPlayers[0][0] = null;
for (idx = 0; idx < 1; idx++)
{
objPlayers[1][idx] = 0;
}
if (objPlayers[0][0] is null) // CA1508: Always true
{
}
}
public static void Method2(object?[][] objPlayers, int idx)
{
objPlayers[0][0] = null;
objPlayers[1][idx] = 0;
if (objPlayers[0][0] is null) // CA1508: Always true
{
}
}
}
}",
LanguageVersion = CodeAnalysis.CSharp.LanguageVersion.CSharp8,
ExpectedDiagnostics =
{
// /0/Test0.cs(19,17): warning CA1508: 'objPlayers[0][0] is null' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(19, 17, "objPlayers[0][0] is null", "true"),
// /0/Test0.cs(28,17): warning CA1508: 'objPlayers[0][0] is null' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(28, 17, "objPlayers[0][0] is null", "true"),
},
}.RunAsync();
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Fact]
public async Task ArrayInitializerNotParentedByArrayCreationAsync()
{
await VerifyBasicAnalyzerAsync(@"
Class C
Public Sub F(p As Object)
Dim a = {|BC30451:M|}
Dim b = If(p, new C())
End Sub
End Class
");
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Theory]
[InlineData("")]
[InlineData("dotnet_code_quality.excluded_symbol_names = M1")]
[InlineData("dotnet_code_quality.CA1508.excluded_symbol_names = M1")]
[InlineData("dotnet_code_quality.dataflow.excluded_symbol_names = M1")]
[InlineData("dotnet_code_quality.CA1508.excluded_symbol_names = M*")]
public async Task EditorConfigConfiguration_ExcludedSymbolNamesWithValueOptionAsync(string editorConfigText)
{
var csharpTest = new VerifyCS.Test
{
TestState =
{
Sources =
{
@"
class Test
{
void M1(string param)
{
param = null;
if (param == null)
{
}
}
}
"
},
AnalyzerConfigFiles = { ("/.editorconfig", $@"root = true
[*]
{editorConfigText}
") },
}
};
if (editorConfigText.Length == 0)
{
csharpTest.ExpectedDiagnostics.Add(
// Test0.cs(7,13): warning CA1508: 'param == null' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(7, 13, @"param == null", "true")
);
}
await csharpTest.RunAsync();
var vbTest = new VerifyVB.Test
{
TestState =
{
Sources =
{
@"
Module Test
Sub M1(param As String)
param = Nothing
If param Is Nothing Then
End If
End Sub
End Module"
},
AnalyzerConfigFiles = { ("/.editorconfig", $@"root = true
[*]
{editorConfigText}
") },
}
};
if (editorConfigText.Length == 0)
{
vbTest.ExpectedDiagnostics.Add(
// Test0.vb(5,12): warning CA1508: 'param Is Nothing' is always 'True'. Remove or refactor the condition(s) to avoid dead code.
GetBasicResultAt(5, 12, "param Is Nothing", "True")
);
}
await vbTest.RunAsync();
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Fact]
[WorkItem(3063, "https://github.com/dotnet/roslyn-analyzers/issues/3063")]
[WorkItem(2985, "https://github.com/dotnet/roslyn-analyzers/issues/2985")]
public async Task UsingBlock_NoDiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
using System;
using System.IO;
public class Class1
{
public static void M1(string values)
{
if (values == null) { }
using (var sw = new StringWriter()) { }
}
public static void M2(byte[] data)
{
using (var ms = new MemoryStream(data))
{
Console.WriteLine(ms);
}
}
}
");
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Fact]
public async Task UsingStatement_NoDiagnosticAsync()
{
await new VerifyCS.Test
{
TestCode = @"
using System;
using System.IO;
public class Class1
{
public void M1(string path)
{
if (!File.Exists(path))
return;
using var fileStream = new FileStream(path, FileMode.Open, FileAccess.Read);
DoSomething(fileStream);
}
private static void DoSomething(Stream stream) { }
}
",
LanguageVersion = CodeAnalysis.CSharp.LanguageVersion.CSharp8,
}.RunAsync();
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Theory, WorkItem(3685, "https://github.com/dotnet/roslyn-analyzers/issues/3685")]
[InlineData("IsNullOrWhiteSpace")]
[InlineData("IsNullOrEmpty")]
public async Task StringNullCheckApisAsync(string apiName)
{
await new VerifyCS.Test
{
TestCode = $@"
using System;
using System.IO;
public class Class1
{{
public void M1(object value)
{{
if (value is string stringValue)
{{
if (string.{apiName}(stringValue))
{{
}}
}}
}}
}}
",
LanguageVersion = CodeAnalysis.CSharp.LanguageVersion.CSharp8,
}.RunAsync();
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Fact]
[WorkItem(3845, "https://github.com/dotnet/roslyn-analyzers/issues/3845")]
public async Task ParamArrayNullCheckIsNotFlaggedAsync()
{
await VerifyCS.VerifyAnalyzerAsync(@"
public class C
{
public void M(params int[] p)
{
if (p == null)
{
}
}
}");
await VerifyVB.VerifyAnalyzerAsync(@"
Public Class C
Public Sub M(ParamArray p As Integer())
If p is Nothing Then
End If
End Sub
End Class
");
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Fact]
[WorkItem(4509, "https://github.com/dotnet/roslyn-analyzers/issues/4509")]
public async Task GenericFieldNullCheckIsNotFlaggedAsync()
{
await VerifyCS.VerifyAnalyzerAsync(@"
public class MyClass<T>
{
private T m_myValue;
public void M()
{
var x = this.m_myValue?.ToString();
}
}");
await VerifyVB.VerifyAnalyzerAsync(@"
Public Class [MyClass](Of T)
Private m_myValue As T
Public Sub M()
Dim x = Me.m_myValue?.ToString()
End Sub
End Class
");
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Fact]
[WorkItem(4548, "https://github.com/dotnet/roslyn-analyzers/issues/4548")]
public async Task ActivatorCreateInstanceNullCheckIsNotFlaggedAsync()
{
await VerifyCS.VerifyAnalyzerAsync(@"
using System;
public class C
{
public void M()
{
var value = Activator.CreateInstance(typeof(int?));
if (value is null)
{
}
}
}");
await VerifyVB.VerifyAnalyzerAsync(@"
Imports System
Public Class C
Public Sub M()
Dim value = Activator.CreateInstance(GetType(Integer?))
If value Is Nothing Then
End If
End Sub
End Class
");
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Fact]
[WorkItem(4548, "https://github.com/dotnet/roslyn-analyzers/issues/4548")]
public async Task FactoryMethodWithNullableReturnIsNotFlaggedAsync()
{
await new VerifyCS.Test
{
TestCode = @"
using System;
#nullable enable
public class C
{
public void M(bool flag)
{
var value = CreateC(flag);
if (value is null)
{
}
}
public static C? CreateC(bool flag)
{
return flag ? new C() : null;
}
}",
LanguageVersion = CodeAnalysis.CSharp.LanguageVersion.CSharp8,
}.RunAsync();
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.PointsToAnalysis)]
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.CopyAnalysis)]
[Fact, WorkItem(6453, "https://github.com/dotnet/roslyn-analyzers/issues/6453")]
public async Task IndexedNullCompare_NoDiagnosticAsync()
{
await VerifyCSharpAnalyzerAsync(@"
using System.Collections.Generic;
sealed class Data
{
public object Value { get; }
public Data(object 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 != null) continue;
if (list[i].Value == null) continue; // <-------- CA1508 False positive
list.RemoveAt(i);
}
}
}
");
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.PointsToAnalysis)]
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.CopyAnalysis)]
[Fact, WorkItem(6695, "https://github.com/dotnet/roslyn-analyzers/issues/6695")]
public async Task NullCoalesceAndNullConditional_NoDiagnosticAsync()
{
await new VerifyCS.Test
{
TestCode = @"
#nullable enable
using System;
using System.Collections.Generic;
using System.Linq;
class C
{
private void Method(IEnumerable<int>? items = null)
{
var itemsToTest = items as IReadOnlyList<int> ??
items?.ToList();
}
private void Method2(IEnumerable<int>? items2 = null)
{
var itemsToTest = items2 as IReadOnlyList<int> ??
items2?.ToList() ??
(IReadOnlyList<int>)Array.Empty<int>();
}
private void Method3(IEnumerable<int>? items3 = null)
{
var itemsToTest = (IReadOnlyList<int>?)items3 ??
items3?.ToList();
}
}",
LanguageVersion = CodeAnalysis.CSharp.LanguageVersion.CSharp8,
}.RunAsync();
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.PointsToAnalysis)]
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.CopyAnalysis)]
[Fact, WorkItem(6695, "https://github.com/dotnet/roslyn-analyzers/issues/6695")]
public async Task NullCoalesceAndNullConditional_DiagnosticAsync()
{
await new VerifyCS.Test
{
TestCode = @"
#nullable enable
using System;
using System.Collections.Generic;
using System.Linq;
class C
{
private void Method(IReadOnlyList<int>? items = null)
{
var itemsToTest = items as IEnumerable<int> ??
items?.ToList();
}
private void Method2(IReadOnlyList<int>? items2 = null)
{
var itemsToTest = items2 as IEnumerable<int> ??
items2?.ToList() ??
(IReadOnlyList<int>)Array.Empty<int>();
}
private void Method3(IReadOnlyList<int>? items3 = null)
{
var itemsToTest = (IEnumerable<int>?)items3 ??
items3?.ToList();
}
}",
LanguageVersion = CodeAnalysis.CSharp.LanguageVersion.CSharp8,
ExpectedDiagnostics =
{
// /0/Test0.cs(13,27): warning CA1508: 'items' is always 'null'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(13, 27, "items", "null"),
// /0/Test0.cs(19,12): warning CA1508: 'items2' is always 'null'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(19, 12, "items2", "null"),
// /0/Test0.cs(19,12): warning CA1508: 'items2?.ToList()' is always 'null'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(19, 12, "items2?.ToList()", "null"),
// /0/Test0.cs(26,27): warning CA1508: 'items3' is always 'null'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(26, 27, "items3", "null")
},
}.RunAsync();
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.PointsToAnalysis)]
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.CopyAnalysis)]
[Fact, WorkItem(6520, "https://github.com/dotnet/roslyn-analyzers/issues/6520")]
public async Task CompareTwoUnrelatedEnumVariables_NoDiagnosticsAsync()
{
await new VerifyCS.Test
{
TestCode = @"
public class Parser
{
private static ParsedPredicate ParsePredicate(ParsedPredicate predicate, PredicateOperand identifier, PredicateOperand literal)
{
if (predicate.Left.TypePrimitive == PredicateTypePrimitive.F1)
{
identifier = predicate.Left;
literal = predicate.Right;
}
else
{
identifier = predicate.Right;
literal = predicate.Left;
}
if (identifier.TypePrimitive != PredicateTypePrimitive.F1)
{
return predicate;
}
if (literal.TypePrimitive == PredicateTypePrimitive.F2)
{
}
return predicate;
}
}
public class PredicateOperand
{
public PredicateTypePrimitive TypePrimitive { get; set; }
}
public enum PredicateTypePrimitive
{
F1,
F2,
}
public class ParsedPredicate
{
public PredicateOperand Left { get; }
public PredicateOperand Right { get; }
}",
LanguageVersion = CodeAnalysis.CSharp.LanguageVersion.CSharp8,
}.RunAsync();
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.PointsToAnalysis)]
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.CopyAnalysis)]
[Fact, WorkItem(6520, "https://github.com/dotnet/roslyn-analyzers/issues/6520")]
public async Task CompareTwoRelatedEnumVariables_DiagnosticsAsync()
{
await new VerifyCS.Test
{
TestCode = @"
public class Parser
{
private static ParsedPredicate ParsePredicate(ParsedPredicate predicate, PredicateOperand identifier, PredicateOperand literal)
{
if (predicate.Left.TypePrimitive == PredicateTypePrimitive.F1)
{
identifier = predicate.Left;
literal = predicate.Right;
}
else
{
identifier = predicate.Right;
literal = predicate.Left;
}
if (identifier.TypePrimitive != PredicateTypePrimitive.F1)
{
return predicate;
}
if (identifier.TypePrimitive == PredicateTypePrimitive.F2)
{
}
return predicate;
}
}
public class PredicateOperand
{
public PredicateTypePrimitive TypePrimitive { get; set; }
}
public enum PredicateTypePrimitive
{
F1,
F2,
}
public class ParsedPredicate
{
public PredicateOperand Left { get; }
public PredicateOperand Right { get; }
}",
LanguageVersion = CodeAnalysis.CSharp.LanguageVersion.CSharp8,
ExpectedDiagnostics =
{
// /0/Test0.cs(22,13): warning CA1508: 'identifier.TypePrimitive == PredicateTypePrimitive.F2' is always 'false'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(22, 13, "identifier.TypePrimitive == PredicateTypePrimitive.F2", "false")
}
}.RunAsync();
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.PointsToAnalysis)]
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Fact, WorkItem(6435, "https://github.com/dotnet/roslyn-analyzers/issues/6435")]
public async Task UserDefinedConversion_NoDiagnosticsAsync()
{
await new VerifyCS.Test
{
TestCode = @"
#nullable enable
internal struct S
{
public bool Flag;
public static explicit operator byte[]?(S s)
{
if (s.Flag)
return null;
return new byte[10];
}
}
internal static class C
{
public static bool M(S s)
{
byte[]? a = (byte[]?)s;
bool b = a == null; // incorrect CA1508; this b could be true or false
return b;
}
}",
LanguageVersion = CodeAnalysis.CSharp.LanguageVersion.CSharp8,
}.RunAsync();
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.PointsToAnalysis)]
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Fact, WorkItem(6249, "https://github.com/dotnet/roslyn-analyzers/issues/6249")]
public async Task TupleElementExchange_NoDiagnosticsAsync()
{
await new VerifyCS.Test
{
TestCode = @"
using System.Collections.Generic;
using System.Diagnostics;
class Test
{
public static List<T> Test1<T>(IEnumerable<T> source)
{
var current = new Queue<T>(source);
var next = new Queue<T>();
var result = new List<T>(current.Count);
while (true)
{
while (current.TryDequeue(out var item))
{
next.Enqueue(item);
}
// swap with tuple
(next, current) = (current, next);
Debug.Assert(next.Count == 0);
// the following line is marked by CA1508
if (current.Count == 0)
return result;
}
}
}",
LanguageVersion = CodeAnalysis.CSharp.LanguageVersion.CSharp8,
}.RunAsync();
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.PointsToAnalysis)]
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Fact, WorkItem(6048, "https://github.com/dotnet/roslyn-analyzers/issues/6048")]
public async Task RethrowInCatchClause_NoDiagnosticsAsync()
{
await new VerifyCS.Test
{
TestCode = @"
using System;
class Test
{
public static void M()
{
try
{
throw new Random().NextDouble() > 0.5 ? new Exception() : new ArgumentException();
}
catch (Exception e)
{
if (e is ArgumentException ae) // can be both true or false depending on the Exception thrown from the try-block, yet is flagged with CA1508
Console.Out.WriteLine(""ArgumentException"");
throw;
}
}
public static void M2()
{
try
{
throw new Exception();
}
catch (Exception e)
{
if (e is ArgumentException ae)
{
}
throw;
}
}
}",
}.RunAsync();
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.PointsToAnalysis)]
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Fact, WorkItem(5929, "https://github.com/dotnet/roslyn-analyzers/issues/5929")]
public async Task IsPatternExpression_SwitchExpressionArmWithWhenClause_NoDiagnosticsAsync()
{
await new VerifyCS.Test
{
TestCode = @"
using System;
class C1
{
static bool Predicate(string s, bool flag) => flag;
static void WarningTest(string input, bool flag)
{
var result = input switch
{
null => ""null"",
string s when Predicate(s, flag) => ""Predicate"", // CA1508 false positive with any 'when' clause
_ => ""default""
};
Console.WriteLine(result);
}
}",
LanguageVersion = CodeAnalysis.CSharp.LanguageVersion.CSharp8,
}.RunAsync();
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.PointsToAnalysis)]
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Fact, WorkItem(5720, "https://github.com/dotnet/roslyn-analyzers/issues/5720")]
public async Task AsExpression_WithNullCoalescingOperator_NoDiagnosticsAsync()
{
await new VerifyCS.Test
{
TestCode = @"
class A
{
public object FieldA;
}
class B : A
{
public object FieldB;
}
class C
{
void M(A a)
{
var x = a.FieldA as C ?? (a.FieldA as B)?.FieldA; // CA1508 false positive on 'a.FieldA as B'
}
}",
LanguageVersion = CodeAnalysis.CSharp.LanguageVersion.CSharp8,
}.RunAsync();
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.PointsToAnalysis)]
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Theory, CombinatorialData, WorkItem(5684, "https://github.com/dotnet/roslyn-analyzers/issues/5684")]
public async Task EscapedLambdaWithMethodCall_AssignsCapturedVariable_NoDiagnosticsAsync(bool enableInterproceduralAnalysis)
{
var interproceduralValue = enableInterproceduralAnalysis ? "ContextSensitive" : "None";
var editorConfigText = $"dotnet_code_quality.interprocedural_analysis_kind = {interproceduralValue}";
var test = new VerifyCS.Test
{
TestState =
{
Sources =
{
@"
#nullable enable
using System;
internal class C
{
static void M1(Action a)
{
a();
}
static void M2()
{
Exception? exception = null;
M1(() =>
{
exception = new Exception();
});
if (exception != null)
{
}
}
}"
},
AnalyzerConfigFiles = { ("/.editorconfig", $@"root = true
[*]
{editorConfigText}
"),
},
},
LanguageVersion = CodeAnalysis.CSharp.LanguageVersion.CSharp8
};
if (enableInterproceduralAnalysis)
{
test.ExpectedDiagnostics.Add(
// /0/Test0.cs(22,13): warning CA1508: 'exception != null' is always 'true'. Remove or refactor the condition(s) to avoid dead code.
GetCSharpResultAt(22, 13, "exception != null", "true"));
}
await test.RunAsync();
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.PointsToAnalysis)]
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Theory, CombinatorialData, WorkItem(5684, "https://github.com/dotnet/roslyn-analyzers/issues/5684")]
public async Task EscapedLambdaInTaskRun_AssignsCapturedVariable_NoDiagnosticsAsync(bool enableInterproceduralAnalysis)
{
var interproceduralValue = enableInterproceduralAnalysis ? "ContextSensitive" : "None";
var editorConfigText = $"dotnet_code_quality.interprocedural_analysis_kind = {interproceduralValue}";
var test = new VerifyCS.Test
{
TestState =
{
Sources =
{
@"
#nullable enable
using System;
using System.Threading.Tasks;
internal class C
{
static async Task M()
{
Exception? exception = null;
await Task.Run(() =>
{
exception = new Exception();
}).ConfigureAwait(false);
if (exception != null)
{
}
}
}"
},
AnalyzerConfigFiles = { ("/.editorconfig", $@"root = true
[*]
{editorConfigText}
"),
},
},
LanguageVersion = CodeAnalysis.CSharp.LanguageVersion.CSharp8
};
// NOTE: Even with interprocedural analysis enabled, we do not have flow analysis logic
// to perform interprocedural analysis for a delegate passed to Task.Run.
// Hence the results are identical with interprocedural analysis enabled and disabled.
await test.RunAsync();
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.PointsToAnalysis)]
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Fact, WorkItem(5199, "https://github.com/dotnet/roslyn-analyzers/issues/5199")]
public async Task InvocationToExceptionThrowingMethod_InsideTryBlock_NoDiagnosticsAsync()
{
await new VerifyCS.Test
{
TestCode = @"
#nullable enable
using System;
class C
{
public SerialPort? OpenPort2(string portName)
{
SerialPort? tempPort = null;
SerialPort? port = null;
try
{
tempPort = new SerialPort(portName);
tempPort.Open();
SomeMethod();
port = tempPort;
tempPort = null;
}
finally
{
if (tempPort != null) // BOOM
{
tempPort.Close();
}
}
return port;
}
private void SomeMethod()
{
throw new NotImplementedException();
}
}
internal class SerialPort
{
private string portName;
public SerialPort(string portName)
{
this.portName = portName;
}
internal void Close()
{
throw new NotImplementedException();
}
internal void Open()
{
throw new NotImplementedException();
}
}",
LanguageVersion = CodeAnalysis.CSharp.LanguageVersion.CSharp8,
}.RunAsync();
}
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.PointsToAnalysis)]
[Trait(Traits.DataflowAnalysis, Traits.Dataflow.NullAnalysis)]
[Fact, WorkItem(4984, "https://github.com/dotnet/roslyn-analyzers/issues/4984")]
public async Task NullCoalescingOperatorInsideCatchBlock_WithinLoop_NoDiagnosticsAsync()
{
await new VerifyCS.Test
{
TestCode = @"
namespace Ca1508FalsePositive
{
using System;
using System.Collections.Generic;
class Program
{
private static object AutoDetectAndConnect(string host)
{
List<Exception> exceptions = null;
foreach (string registeredScheduler in s_schedulers)
{
try
{
object conn = Connect(registeredScheduler, host);
if (conn != null)
return conn;
}
catch (Exception ex)
{
// warning CA1508: 'exceptions' is always 'null'. Remove or refactor the condition(s) to avoid dead code.
(exceptions ??= new List<Exception>()).Add(ex);
}
}
// Commenting out this code block will ""resolve"" CA1508 above
if (exceptions == null)
{
throw new NotSupportedException(host);
}
throw new AggregateException(exceptions);
static object Connect(string a, string b) => throw new NotImplementedException($""{a}{b}"");
}
static List<string> s_schedulers = new List<string>();
static void Register(string scheduler) => s_schedulers.Add(scheduler);
static void Main(string[] args)
{
Register(""abc"");
Register(""def"");
try
{
var conn = AutoDetectAndConnect(args.Length > 0 ? args[0] : args.GetHashCode().ToString());
Console.WriteLine(conn);
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
}
}",
LanguageVersion = CodeAnalysis.CSharp.LanguageVersion.CSharp8,
}.RunAsync();
}
}
}
|