From cadd992eb623643b4e43ffe4e83ef217c07a84e9 Mon Sep 17 00:00:00 2001 From: Tim Pohlmann Date: Fri, 4 Aug 2023 13:58:16 +0200 Subject: [PATCH 01/20] Reworked secondary locations --- .../Roslyn/ConditionEvaluatesToConstant.cs | 17 +---- .../ConditionEvaluatesToConstantBase.cs | 67 ++++++++++--------- .../Roslyn/SymbolicRuleCheck.cs | 7 +- .../ConditionEvaluatesToConstant.CSharp8.cs | 15 +++-- .../Roslyn/ConditionEvaluatesToConstant.cs | 15 +++-- 5 files changed, 61 insertions(+), 60 deletions(-) diff --git a/analyzers/src/SonarAnalyzer.CSharp/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.cs b/analyzers/src/SonarAnalyzer.CSharp/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.cs index 9ccf666951c..b0ebbf868f6 100644 --- a/analyzers/src/SonarAnalyzer.CSharp/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.cs +++ b/analyzers/src/SonarAnalyzer.CSharp/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.cs @@ -59,18 +59,7 @@ public override void Visit(SyntaxNode node) } } - protected override bool IsLeftCoalesceExpression(SyntaxNode syntax) => - syntax.Parent is BinaryExpressionSyntax { } binary - && binary.OperatorToken.IsKind(SyntaxKind.QuestionQuestionToken) - && binary.Left == syntax; - - protected override bool IsConditionalAccessExpression(SyntaxNode syntax) => - syntax.Parent is ConditionalAccessExpressionSyntax conditional && conditional.Expression == syntax; - - protected override bool IsForLoopIncrementor(SyntaxNode syntax) => - syntax.Parent is ForStatementSyntax forStatement && forStatement.Incrementors.Contains(syntax); - - protected override bool IsUsing(SyntaxNode syntax) => - (syntax.IsKind(SyntaxKind.VariableDeclaration) && syntax.Parent.IsKind(SyntaxKind.UsingStatement)) - || (syntax is LocalDeclarationStatementSyntax local && local.UsingKeyword().IsKind(SyntaxKind.UsingKeyword)); + protected override bool IsInsideUsingDeclaration(SyntaxNode node) => + (node.IsKind(SyntaxKind.VariableDeclaration) && node.Parent.IsKind(SyntaxKind.UsingStatement)) + || (node is LocalDeclarationStatementSyntax local && local.UsingKeyword().IsKind(SyntaxKind.UsingKeyword)); } diff --git a/analyzers/src/SonarAnalyzer.Common/SymbolicExecution/Roslyn/RuleChecks/ConditionEvaluatesToConstantBase.cs b/analyzers/src/SonarAnalyzer.Common/SymbolicExecution/Roslyn/RuleChecks/ConditionEvaluatesToConstantBase.cs index df3b3f0918b..fd6b6220be3 100644 --- a/analyzers/src/SonarAnalyzer.Common/SymbolicExecution/Roslyn/RuleChecks/ConditionEvaluatesToConstantBase.cs +++ b/analyzers/src/SonarAnalyzer.Common/SymbolicExecution/Roslyn/RuleChecks/ConditionEvaluatesToConstantBase.cs @@ -38,12 +38,9 @@ public abstract class ConditionEvaluatesToConstantBase : SymbolicRuleCheck private readonly Dictionary trueOperations = new(); private readonly Dictionary falseOperations = new(); - private readonly HashSet reached = new(); + private readonly List reached = new(); - protected abstract bool IsLeftCoalesceExpression(SyntaxNode syntax); - protected abstract bool IsConditionalAccessExpression(SyntaxNode syntax); - protected abstract bool IsForLoopIncrementor(SyntaxNode syntax); - protected abstract bool IsUsing(SyntaxNode syntax); + protected abstract bool IsInsideUsingDeclaration(SyntaxNode node); public override ProgramState[] PreProcess(SymbolicContext context) { @@ -55,7 +52,7 @@ public override ProgramState ConditionEvaluated(SymbolicContext context) { var operation = context.Operation.Instance; if (operation.Kind is not OperationKindEx.Literal - && !operation.Syntax.Ancestors().Any(IsUsing) + && !operation.Syntax.Ancestors().Any(IsInsideUsingDeclaration) && operation.TrackedSymbol(context.State) is not IFieldSymbol { IsConst: true } && !IsDiscardPattern(operation)) { @@ -93,53 +90,54 @@ public override void ExecutionCompleted() private void ReportIssue(IOperation operation, BasicBlock block, bool conditionValue) { var issueMessage = operation.Kind == OperationKindEx.IsNull ? MessageNull : string.Format(MessageBool, conditionValue); - var secondaryLocations = SecondaryLocations(block, conditionValue); + var syntax = ToBranchValueCondition(operation.Syntax); + var secondaryLocations = SecondaryLocations(block, conditionValue, syntax); if (secondaryLocations.Any()) { - ReportIssue(Rule2583, operation, secondaryLocations, issueMessage, S2583MessageSuffix); + ReportIssue(Rule2583, syntax, secondaryLocations, issueMessage, S2583MessageSuffix); } else { - ReportIssue(Rule2589, operation, null, issueMessage, string.Empty); + ReportIssue(Rule2589, syntax, null, issueMessage, string.Empty); } } - private List SecondaryLocations(BasicBlock block, bool conditionValue) + private List SecondaryLocations(BasicBlock block, bool conditionValue, SyntaxNode conditionSyntax) { List locations = new(); - IOperation currentStart = null; - IOperation currentEnd = null; - var unreachable = UnreachableOperations(block, conditionValue).Where(x => !IsIgnoredLocation(x.Syntax)).ToHashSet(); - foreach (var operation in unreachable.Concat(reached).OrderBy(x => x.Syntax.SpanStart)) + var unreachable = UnreachableOperations(block, conditionValue).ToHashSet(); + var currentStart = conditionSyntax.Span.End; + var reachedNodes = reached.Select(x => x.Syntax).Where(x => x.SpanStart > conditionSyntax.Span.End).OrderBy(x => x.SpanStart); + + foreach (var reachedNode in reachedNodes) { - if (unreachable.Contains(operation)) - { - currentStart ??= operation; - currentEnd = operation; - } - else + if (AddLocation(reachedNode.SpanStart)) { - AddCurrent(); + currentStart = reachedNode.Span.End; } } - AddCurrent(); + AddLocation(int.MaxValue); return locations; - void AddCurrent() + bool AddLocation(int end) { - if (currentStart is not null) + var nodes = unreachable.Where(x => x.SpanStart > currentStart && x.Span.End < end); + if (nodes.Any()) { - locations.Add(currentStart.Syntax.CreateLocation(currentEnd.Syntax)); - currentStart = null; + var first = nodes.OrderBy(x => x.SpanStart).First(); + var last = nodes.OrderBy(x => x.Span.End).Last(); + locations.Add(first.CreateLocation(last)); + return true; } + return false; } } - private IEnumerable UnreachableOperations(BasicBlock block, bool conditionValue) + private IEnumerable UnreachableOperations(BasicBlock block, bool conditionValue) { if (block.SuccessorBlocks.Distinct().Count() != 2) { - return Enumerable.Empty(); + return Enumerable.Empty(); } HashSet reachable = new() { block }; HashSet unreachable = new(); @@ -147,7 +145,11 @@ private IEnumerable UnreachableOperations(BasicBlock block, bool con var conditionalIsRechable = (block.ConditionKind == ControlFlowConditionKind.WhenTrue) == conditionValue; Traverse(conditionalIsRechable ? block.ConditionalSuccessor : block.FallThroughSuccessor, reachable, new List()); Traverse(conditionalIsRechable ? block.FallThroughSuccessor : block.ConditionalSuccessor, unreachable, reachable); - return unreachable.SelectMany(x => x.OperationsAndBranchValue).Except(reached); + return unreachable + .SelectMany(x => x.OperationsAndBranchValue) + .Except(reached) + .SelectMany(x => x.DescendantsAndSelf().Select(x => x.Syntax)) + .ToList(); static void Traverse(ControlFlowBranch branch, HashSet result, ICollection excluded) { @@ -168,8 +170,7 @@ static void Traverse(ControlFlowBranch branch, HashSet result, IColl } } - private bool IsIgnoredLocation(SyntaxNode x) => - IsForLoopIncrementor(x) - || IsConditionalAccessExpression(x) - || IsLeftCoalesceExpression(x); + // For SwitchExpressionArms like `true => 5` we are only interested in the left part (`true`). + private static SyntaxNode ToBranchValueCondition(SyntaxNode syntax) => + syntax.IsKind(SyntaxKindEx.SwitchExpressionArm) ? ((SwitchExpressionArmSyntaxWrapper)syntax).Pattern : syntax; } diff --git a/analyzers/src/SonarAnalyzer.Common/SymbolicExecution/Roslyn/SymbolicRuleCheck.cs b/analyzers/src/SonarAnalyzer.Common/SymbolicExecution/Roslyn/SymbolicRuleCheck.cs index f13eb966204..b867c9bbcc5 100644 --- a/analyzers/src/SonarAnalyzer.Common/SymbolicExecution/Roslyn/SymbolicRuleCheck.cs +++ b/analyzers/src/SonarAnalyzer.Common/SymbolicExecution/Roslyn/SymbolicRuleCheck.cs @@ -62,9 +62,12 @@ protected void ReportIssue(IOperation operation, IEnumerable additiona ReportIssue(Rule, operation, additionalLocations, messageArgs); } - protected void ReportIssue(DiagnosticDescriptor rule, IOperation operation, IEnumerable additionalLocations, params object[] messageArgs) + protected void ReportIssue(DiagnosticDescriptor rule, IOperation operation, IEnumerable additionalLocations, params object[] messageArgs) => + ReportIssue(rule, operation.Syntax, additionalLocations, messageArgs); + + protected void ReportIssue(DiagnosticDescriptor rule, SyntaxNode syntax, IEnumerable additionalLocations, params object[] messageArgs) { - var location = operation.Syntax.GetLocation(); + var location = syntax.GetLocation(); if (reportedDiagnostics.Add(location)) { context.ReportIssue(Diagnostic.Create(rule, location, additionalLocations, messageArgs)); diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.CSharp8.cs b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.CSharp8.cs index 86d8a9b665c..b5cf878241b 100644 --- a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.CSharp8.cs +++ b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.CSharp8.cs @@ -23,10 +23,11 @@ public class CSharp8 int SwitchExpression() { var a = false; - return a switch // Secondary FP + return a switch { - true => 0, // Noncompliant: true branch is always false - // Secondary@-1 + true => 0, + // ^^^^ Noncompliant + // ^ Secondary@-1 false => 1 // Noncompliant: false branch is always true }; } @@ -234,8 +235,9 @@ void NullCoalesceAssignment_Useless(string a, string b, string c, string d) //Left operand: Values notNull, notEmpty and ret are known to be not-null ret = notNull; - ret ??= a; // Noncompliant - // Secondary@-1 + ret ??= a; + // ^^^ Noncompliant + // ^ Secondary@-1 ret = notNull; ret = "Lorem " + (ret ??= a) + " ipsum"; // Noncompliant @@ -255,7 +257,6 @@ void NullCoalesceAssignment_Useless(string a, string b, string c, string d) ret = null; ret = "Lorem " + (ret ??= a) + " ipsum"; // Noncompliant - // Secondary@-1 //Right operand: isNull is known to be null, therefore ?? is useless ret = a; @@ -460,7 +461,7 @@ void IfStatement() void LogicalAndExpression() { - bool a = true; + bool a = false; var b = a && true; // Noncompliant // Secondary@-1 } diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.cs b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.cs index 5f1b73b610f..57c96418abd 100644 --- a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.cs +++ b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.cs @@ -64,9 +64,10 @@ public void NotExecutedLoops(object o1, object o2, object o3) // ^^ for (int i = 0; c3; i++) // Noncompliant {{Change this condition so that it does not always evaluate to 'False'. Some code paths are unreachable.}} - // ^^ + // Secondary@-1 ^33#239 { - if (o3 != null) // Secondary + if (o3 != null) + // secondary location starts at incrementor and ends at the end of the above line break; } } @@ -176,6 +177,13 @@ public void Foo7(bool a, bool b) } } + public void Foo8(bool a, bool b) + { + a = true; + _ = a && b; + // ^ Noncompliant + } + void Pointer(int* a) // Error [CS0214] { if (a != null) // Error [CS0214] @@ -1917,7 +1925,7 @@ public static void NonCompliant6() S sObj = null; if (sObj?.str?.Length > 2) // ^^^^ Noncompliant - // ^^^^^^^ Secondary@-1 + // ^^^^^^^^^^^^ Secondary@-1 // ^^^^^^^^^^^^^^^^^^^^^ Noncompliant@-2 { Console.WriteLine("a"); // Secondary @@ -2792,7 +2800,6 @@ void NullCoalesce_Useless(string a, string b, string c, string d) ret = null ?? a; // Noncompliant ret = isNull ?? a; // Noncompliant ret = ((isNull)) ?? a; // Noncompliant - // Secondary@-1 FP ret = "Lorem " + (isNull ?? a) + " ipsum"; // Noncompliant //Right operand: isNull is known to be null, therefore ?? is useless From 0f4ff345fd14c3719631179dad27a71901aa7179 Mon Sep 17 00:00:00 2001 From: Tim Pohlmann Date: Fri, 28 Jul 2023 08:49:00 +0200 Subject: [PATCH 02/20] VB Rule --- .../SymbolicExecutionRunner.cs | 2 + .../Roslyn/ConditionEvaluatesToConstant.cs | 41 + .../ConditionEvaluatesToConstantTest.cs | 16 + .../ConditionEvaluatesToConstant.VB14.vb | 205 ++ .../Roslyn/ConditionEvaluatesToConstant.vb | 2034 +++++++++++++++++ 5 files changed, 2298 insertions(+) create mode 100644 analyzers/src/SonarAnalyzer.VisualBasic/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.cs create mode 100644 analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.VB14.vb create mode 100644 analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.vb diff --git a/analyzers/src/SonarAnalyzer.VisualBasic/Rules/SymbolicExecution/SymbolicExecutionRunner.cs b/analyzers/src/SonarAnalyzer.VisualBasic/Rules/SymbolicExecution/SymbolicExecutionRunner.cs index e15472796b0..79a696218c1 100644 --- a/analyzers/src/SonarAnalyzer.VisualBasic/Rules/SymbolicExecution/SymbolicExecutionRunner.cs +++ b/analyzers/src/SonarAnalyzer.VisualBasic/Rules/SymbolicExecution/SymbolicExecutionRunner.cs @@ -34,6 +34,8 @@ public SymbolicExecutionRunner() : base(AnalyzerConfiguration.AlwaysEnabled) { } .Add(HashesShouldHaveUnpredictableSalt.S2053, CreateFactory()) .Add(LocksReleasedAllPaths.S2222, CreateFactory()) .Add(NullPointerDereference.S2259, CreateFactory()) + .Add(ConditionEvaluatesToConstant.S2583, CreateFactory()) + .Add(ConditionEvaluatesToConstant.S2589, CreateFactory()) .Add(InitializationVectorShouldBeRandom.S3329, CreateFactory()) .Add(EmptyNullableValueAccess.S3655, CreateFactory()) .Add(PublicMethodArgumentsShouldBeCheckedForNull.S3900, CreateFactory()) diff --git a/analyzers/src/SonarAnalyzer.VisualBasic/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.cs b/analyzers/src/SonarAnalyzer.VisualBasic/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.cs new file mode 100644 index 00000000000..54c9fbd7b25 --- /dev/null +++ b/analyzers/src/SonarAnalyzer.VisualBasic/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.cs @@ -0,0 +1,41 @@ +/* + * SonarAnalyzer for .NET + * Copyright (C) 2015-2023 SonarSource SA + * mailto: contact AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +namespace SonarAnalyzer.SymbolicExecution.Roslyn.RuleChecks.VisualBasic; + +public class ConditionEvaluatesToConstant : ConditionEvaluatesToConstantBase +{ + public static readonly DiagnosticDescriptor S2583 = DescriptorFactory.Create(DiagnosticId2583, MessageFormat); + public static readonly DiagnosticDescriptor S2589 = DescriptorFactory.Create(DiagnosticId2589, MessageFormat); + protected override DiagnosticDescriptor Rule => null; + protected override DiagnosticDescriptor Rule2583 => S2583; + protected override DiagnosticDescriptor Rule2589 => S2589; + + public override bool ShouldExecute() => true; + protected override bool IsConditionalAccessExpression(SyntaxNode syntax) => + syntax.Parent is ConditionalAccessExpressionSyntax conditional && conditional.Expression == syntax; + + protected override bool IsForLoopIncrementor(SyntaxNode syntax) => false; // Is is possible to have a boolean in a for loop in vb.net? + protected override bool IsLeftCoalesceExpression(SyntaxNode syntax) => + syntax.Parent is BinaryConditionalExpressionSyntax { } binary + && binary.FirstExpression == syntax; + protected override bool IsUsing(SyntaxNode syntax) => + syntax.IsKind(SyntaxKind.VariableDeclarator) && syntax.Parent.IsKind(SyntaxKind.UsingStatement); +} diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/Rules/SymbolicExecution/ConditionEvaluatesToConstantTest.cs b/analyzers/tests/SonarAnalyzer.UnitTest/Rules/SymbolicExecution/ConditionEvaluatesToConstantTest.cs index c607bc69370..fe3f8a43516 100644 --- a/analyzers/tests/SonarAnalyzer.UnitTest/Rules/SymbolicExecution/ConditionEvaluatesToConstantTest.cs +++ b/analyzers/tests/SonarAnalyzer.UnitTest/Rules/SymbolicExecution/ConditionEvaluatesToConstantTest.cs @@ -21,7 +21,9 @@ using SonarAnalyzer.SymbolicExecution.Sonar.Analyzers; using ChecksCS = SonarAnalyzer.SymbolicExecution.Roslyn.RuleChecks.CSharp; +using ChecksVB = SonarAnalyzer.SymbolicExecution.Roslyn.RuleChecks.VisualBasic; using CS = SonarAnalyzer.Rules.CSharp; +using VB = SonarAnalyzer.Rules.VisualBasic; namespace SonarAnalyzer.UnitTest.Rules; @@ -38,6 +40,10 @@ public class ConditionEvaluatesToConstantTest .WithBasePath(@"SymbolicExecution\Roslyn") .WithOnlyDiagnostics(ChecksCS.ConditionEvaluatesToConstant.S2583, ChecksCS.ConditionEvaluatesToConstant.S2589); + private readonly VerifierBuilder roslynVB = new VerifierBuilder() + .WithBasePath(@"SymbolicExecution\Roslyn") + .WithOnlyDiagnostics(ChecksVB.ConditionEvaluatesToConstant.S2583, ChecksVB.ConditionEvaluatesToConstant.S2589); + [DataTestMethod] [DataRow(ProjectType.Product)] [DataRow(ProjectType.Test)] @@ -54,6 +60,16 @@ public void ConditionEvaluatesToConstant_Roslyn_CS(ProjectType projectType) => .AddReferences(NuGetMetadataReference.MicrosoftExtensionsPrimitives("3.1.7").Concat(TestHelper.ProjectTypeReference(projectType))) .Verify(); + [TestMethod] + public void ConditionEvaluatesToConstant_Roslyn_VB() => + roslynVB.AddPaths("ConditionEvaluatesToConstant.vb").Verify(); + + [TestMethod] + public void ConditionEvaluatesToConstant_Roslyn_VB14() => + roslynVB.AddPaths("ConditionEvaluatesToConstant.VB14.vb") + .WithOptions(ParseOptionsHelper.FromVisualBasic14) + .Verify(); + [TestMethod] public void ConditionEvaluatesToConstant_Sonar_CSharp7() => sonar.AddPaths("ConditionEvaluatesToConstant.CSharp7.cs") diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.VB14.vb b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.VB14.vb new file mode 100644 index 00000000000..d7d673f8474 --- /dev/null +++ b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.VB14.vb @@ -0,0 +1,205 @@ +Namespace Tests.Diagnostics + Public Class VB14 + + Private Sub ConditionalAccessNullPropagation(ByVal o As Object) + If o Is Nothing Then + If Equals(o?.ToString(), Nothing) Then ' Noncompliant + ' Secondary@-1 + ' Noncompliant@-2 + End If + If o?.GetHashCode() Is Nothing Then '' Noncompliant + ' Secondary@-1 + ' Noncompliant@-2 + End If + End If + End Sub + + Friend Enum MyEnum + One + Two + End Enum + + Friend Class MyClassWithEnum + Public myEnum As MyEnum + End Class + + Public Sub EnumMemberAccess() + Dim m = New MyClassWithEnum() + Console.WriteLine(m.myEnum) + m = Nothing + If m?.myEnum = MyEnum.One Then ' Noncompliant + ' Secondary@-1 + ' Noncompliant@-2 + End If + End Sub + + Friend Class FooContainer + Public Property Foo As Boolean + End Class + + Friend Class TestNullConditional + Private Sub First(ByVal fooContainer As FooContainer, ByVal bar As Boolean) + If fooContainer?.Foo = False OrElse bar Then + Console.WriteLine(If(bar, "1", "2")) + Else + Console.WriteLine(If(fooContainer IsNot Nothing, "3", "4")) + End If + End Sub + + Private Sub Second(ByVal fooContainer As FooContainer) + If fooContainer?.Foo <> True Then + Console.WriteLine("3") + If fooContainer IsNot Nothing Then + Console.WriteLine("4") + End If + End If + End Sub + + Public Class Result + Public Property Succeed As Boolean + + Public Shared Function Test() As Result + If Date.Now.Day = 17 Then ' swap value here to test both cases if needed + Return New Result() + End If + Return Nothing + End Function + End Class + + Public Shared Sub Compliant1() + Dim result = TestNullConditional.Result.Test() + + If result Is Nothing OrElse Not result.Succeed Then + Console.WriteLine("shorted") + If result IsNot Nothing Then + Console.WriteLine("other") + End If + End If + + If result?.Succeed <> True Then + Console.WriteLine("shorted") + If result IsNot Nothing Then + Console.WriteLine("other") + End If + End If + End Sub + + Public Shared Sub NonCompliant1() + Dim result As Result = Nothing + If result?.Succeed IsNot Nothing Then ' Noncompliant + ' Secondary@-1 + ' Noncompliant@-2 + Console.WriteLine("shorted") ' Secondary + If result IsNot Nothing Then + Console.WriteLine("other") + End If + End If + End Sub + + Public Shared Sub NonCompliant2() + Dim result As Result = New Result() + If result?.Succeed IsNot Nothing Then ' Noncompliant + ' Noncompliant@-1 + Console.WriteLine("shorted") + While result IsNot Nothing ' Noncompliant + Console.WriteLine("other") + End While + End If + End Sub + + Public Class A + Public Property booleanVal As Boolean + End Class + + Public Shared Sub Compliant2() + Dim aObj As A = Nothing + If If(aObj?.booleanVal, False) Then ' Noncompliant + ' Secondary@-1 + ' Noncompliant@-2 + Console.WriteLine("a") + End If + End Sub + + Public Shared Sub NonCompliant3() + Dim aObj As A = Nothing + If aObj?.booleanVal Is Nothing Then ' Noncompliant + ' Secondary@-1 + ' Noncompliant@-2 + Console.WriteLine("a") + End If + + If aObj?.booleanVal IsNot Nothing Then ' Noncompliant + ' Secondary@-1 + ' Noncompliant@-2 + Console.WriteLine("a") ' Secondary + End If + End Sub + + Public Shared Sub Compliant3(ByVal a As A) + + If a?.booleanVal = True Then + Console.WriteLine("Compliant") + Return + End If + + If a IsNot Nothing Then ' Compliant + End If + End Sub + + Public Shared Sub NonCompliant4(ByVal a As A) + + If a?.booleanVal Is Nothing Then + Console.WriteLine("Compliant") + Return + End If + + If a IsNot Nothing Then ' Noncompliant + End If + End Sub + + Public Shared Sub Compliant4(ByVal a As A) + If a?.booleanVal Is Nothing Then + Console.WriteLine("Compliant") + End If + + If a IsNot Nothing Then ' Compliant + End If + End Sub + + Public Shared Sub Compliant5(ByVal a As A) + While If(a?.booleanVal Is Nothing, True, False) ' Compliant + Console.WriteLine("Compliant") + End While + End Sub + + Public Shared Sub NonCompliant5() + Dim a As A = Nothing + While If(a?.booleanVal Is Nothing, True, False) ' Noncompliant + ' Secondary@-1 + ' Noncompliant@-2 + ' Secondary@-3 + Console.WriteLine("Compliant") + End While + End Sub + + Public Class S + Public str As String = Nothing + End Class + + Public Shared Sub Compliant6(ByVal sObj As S) + If sObj?.str?.Length > 2 Then + Console.WriteLine("a") + End If + End Sub + + Public Shared Sub NonCompliant6() + Dim sObj As S = Nothing + If sObj?.str?.Length > 2 Then ' Noncompliant + ' Secondary@-1 + ' Noncompliant@-2 + Console.WriteLine("a") ' Secondary + End If + End Sub + End Class + End Class +End Namespace diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.vb b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.vb new file mode 100644 index 00000000000..abdd7d8ea57 --- /dev/null +++ b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.vb @@ -0,0 +1,2034 @@ +Imports System +Imports System.Collections.Generic +Imports System.Diagnostics +Imports System.Threading.Tasks +Imports System.IO +Imports System.Linq +Imports Microsoft.Extensions.Primitives +Imports System.Runtime.InteropServices + +Namespace Tests.Diagnostics + Public Class ConditionEvaluatesToConstant + Private Const t As Boolean = True + Private Const f As Boolean = False + + Public Sub LoopsWithBreak(ByVal o1 As Object, ByVal o2 As Object, ByVal o3 As Object) + Dim c1, c2 As Boolean + c1 = c2 = True + While c1 ' Noncompliant + If o1 IsNot Nothing Then Exit While ' Secondary + End While + + Do + If o2 IsNot Nothing Then Exit Do + Loop While c2 ' Noncompliant + + End Sub + + Public Sub IfStatement() + Dim c1 = True + If c1 Then ' Noncompliant + Console.WriteLine("Always True") + End If + End Sub + + Private Sub UsingStatement() + Using writer As TextWriter = Nothing + If writer IsNot Nothing Then ' Noncompliant + Console.WriteLine("Hello world") ' Secondary + End If + End Using + End Sub + + Public Sub DoesNotRaiseForConst() + If t Then ' Compliant - no issue is raised for const fields. + Console.WriteLine("Do stuff") + End If + End Sub + + Public Sub NotExecutedLoops(ByVal o1 As Object, ByVal o2 As Object, ByVal o3 As Object) + Dim c1, c2, c3 As Boolean + c1 = c2 = c3 = False + + While c1 ' Noncompliant {{Change this condition so that it does not always evaluate to 'False'. Some code paths are unreachable.}} + If o1 IsNot Nothing Then Exit While ' Secondary + End While + + Do + If o2 IsNot Nothing Then Exit Do + + Loop While c2 ' Noncompliant {{Change this condition so that it does not always evaluate to 'False'.}} + ' ^^ + End Sub + + Public Sub BreakInLoop(ByVal o As Object) + Dim c = True + While c ' Noncompliant + If o IsNot Nothing Then Exit While + End While + End Sub + + Public Sub ReturnInLoop(ByVal o As Object) + Dim c = True + While c ' Noncompliant + If o IsNot Nothing Then Return + End While + End Sub + + Public Sub ThrowInLoop(ByVal o As Object) + Dim c = True + While c ' Noncompliant + If o IsNot Nothing Then Throw New Exception() + End While + End Sub + + Public Sub ConstField(ByVal a As Boolean, ByVal b As Boolean) + + Dim x = t OrElse a OrElse b ' Compliant t is const + + If t = True Then ' Noncompliant + Console.WriteLine("") + End If + + End Sub + + Public Sub Foo1(ByVal a As Boolean, ByVal b As Boolean) + Dim l = True + Dim x = l OrElse a OrElse b + ' ^ Noncompliant + ' ^^^^^^^^^^ Secondary@-1 + End Sub + + Public Sub Foo2(ByVal a As Boolean, ByVal b As Boolean) + Dim l = True + Dim x = l OrElse a OrElse b + ' ^ Noncompliant + ' ^^^^^^^^^^ Secondary@-1 + + End Sub + + Public Sub Foo3(ByVal a As Boolean, ByVal b As Boolean) + Dim l = True + Dim x = l OrElse a OrElse b + ' ^ Noncompliant + ' ^^^^^^^^^^ Secondary@-1 + End Sub + + Public Sub Foo4(ByVal a As Boolean, ByVal b As Boolean) + Dim l = True + Dim m = False + Dim x = m OrElse l OrElse a OrElse b + ' ^ Noncompliant + ' ^ Noncompliant@-1 + ' ^^^^^^^^^^ Secondary@-2 + + End Sub + + Public Sub Foo5(ByVal a As Boolean, ByVal b As Boolean) + Dim l = True + Dim m = False + Dim x = m AndAlso l OrElse a OrElse b + ' ^ Noncompliant + ' ^ Secondary@-1 + End Sub + + Public Sub Foo6(ByVal a As Boolean, ByVal b As Boolean) + Dim l = True + Dim x = If(l OrElse a, a, b) + ' ^ Noncompliant + ' ^ Secondary@-1 + ' ^ Secondary@-2 + End Sub + + Public Sub Foo7(ByVal a As Boolean, ByVal b As Boolean) + Dim l = True + If If(l OrElse a, a, b) OrElse b Then + ' ^ Noncompliant + ' ^ Secondary@-1 + ' ^ Secondary@-2 + End If + End Sub + + Private Sub TestNameof(ByVal s As String) + If Equals(Nothing, NameOf(Method1)) Then ' FN FIX + End If + End Sub + + Public Sub Method1() + Dim b = True + If b Then ' Noncompliant + Console.WriteLine() + Else + ' secondary location covers all unreachable code blocks: + Console.WriteLine(1) ' Secondary ?????? + While b + Console.WriteLine(2) + End While ' the secondary location ends at the end of the above line + End If + + Console.WriteLine() + End Sub + + Public Sub Method2() + Dim b = True + If b Then ' Noncompliant + Console.WriteLine() + End If + + If Not b Then ' Noncompliant + Console.WriteLine() ' Secondary + End If + + Console.WriteLine() + End Sub + + Public Sub Method2Literals() + If True Then ' Compliant + Console.WriteLine() + End If + + If False Then ' Compliant + Console.WriteLine() + End If + + Console.WriteLine() + End Sub + + Public Sub Method3() + Dim b As Boolean + TryGet(b) + If b Then + End If + End Sub + + Private Sub TryGet( ByRef b As Boolean) + b = False + End Sub + + Public Sub Method5(ByVal cond As Boolean) + While cond + Console.WriteLine() + End While + + Dim b = True + While b ' Noncompliant + Console.WriteLine() + End While + + Console.WriteLine() ' Secondary + End Sub + + Public Sub Method6(ByVal cond As Boolean) + Dim i = 10 + While i < 20 + i = i + 1 + End While + + Dim b = True + While b ' Noncompliant + Console.WriteLine() + End While + + Console.WriteLine() ' Secondary + End Sub + + Public Sub Method7() + While True ' Compliant + Console.WriteLine() + End While + + Console.WriteLine() + End Sub + + Public Sub Method8(n) + For Each item In New Integer()() {New Integer() {1, 2, 3}} + For Each i In item + Console.WriteLine() + Next + Next + End Sub + + Public Sub Method9_For(ByVal cond As Boolean) + While True ' Not reporting on this + + End While + End Sub + + Public Sub Method_Switch() + Dim i = 10 + Dim b = True + Select Case i + Case 1 ' Noncompliant + b = False ' Secondary + End Select + + If b Then ' Noncompliant + Else + End If + End Sub + + Public Sub Method_Switch_Learn(ByVal cond As Boolean) + Select Case cond + Case True + If cond Then ' Noncompliant + Console.WriteLine() + End If + End Select + End Sub + + Public Property Property1 As Boolean + Get + Dim a = New Action(Sub() + Dim b = True + If b Then ' Noncompliant + Console.WriteLine() + Else + Console.WriteLine() ' Secondary + End If + End Sub) + Return True + End Get + Set(ByVal value As Boolean) + value = True + If value Then ' Noncompliant + Console.WriteLine() + Else + Console.WriteLine() ' Secondary + End If + End Set + End Property + + Public Shared ReadOnly Property Prop As Boolean + Get + Return Prop + End Get + End Property + + Public Sub Method_Complex() + Dim guard1 = True + Dim guard2 = True + Dim guard3 = True + + While GetCondition() + If guard1 Then + guard1 = False + Else + If guard2 Then ' Noncompliant FP: loop is only analyzed twice + guard2 = False + Else + guard3 = False ' Secondary FP + End If + End If + End While + + If guard3 Then ' Noncompliant FP: loop is only analyzed twice + Console.WriteLine() + End If + End Sub + + Public Sub Method_Complex_2() + Dim x = False + Dim y = False + + While GetCondition() + While GetCondition() + If x Then + If y Then ' Noncompliant FP: loop is only analyzed twice + End If + End If + y = True + End While + x = True + End While + End Sub + Private Shared Function GetObject() As Object + Return Nothing + End Function + Public Sub M() + + Dim o1 = GetObject() + Dim o2 As Object = Nothing + + If o1 IsNot Nothing Then + If Not Equals(o1.ToString(), Nothing) Then + o2 = New Object() + End If + End If + + If o2 Is Nothing Then + End If + + End Sub + + Public Sub NullableStructs() + Dim i As Integer? = Nothing + + If i Is Nothing Then ' Noncompliant, always true + Console.WriteLine(i) + End If + + i = New Integer?() + If i Is Nothing Then ' Noncompliant + End If + + Dim ii = "" + If ii Is Nothing Then ' Noncompliant, always false + Console.WriteLine(ii) ' Secondary + End If + End Sub + + Private Shared Function GetCondition() As Boolean + Return True + End Function + + Public Sub Lambda(ByVal condition As Boolean) + + Dim fail = False + Dim a As Action = New Action(Sub() fail = condition) + a() + + If fail Then ' Noncompliant FP + End If + End Sub + + Public Sub Constraint(ByVal cond As Boolean) + Dim a = cond + Dim b = a + If a Then + If b Then ' FN: requires relation support + + End If + End If + End Sub + + Public Sub Stack(ByVal cond As Boolean) + Dim a = cond + Dim b = a + + If Not a Then + If b Then ' FN: requires relation support + End If + End If + + Dim fail = False + Dim ac As Action = New Action(Sub() fail = cond) + + ac() + + If Not fail Then ' Noncompliant FP + End If + End Sub + + Public Sub BooleanBinary(ByVal a As Boolean, ByVal b As Boolean) + If a And Not b Then + If a Then ' FN: engine doesn't learn BoolConstraints from binary operators + End If + If b Then ' FN: engine doesn't learn BoolConstraints from binary operators + End If + + End If + + If Not (a Or b) Then + If a Then ' FN: engine doesn't learn BoolConstraints from binary operators + End If + + End If + + If a Xor b Then + If Not a Xor Not b Then ' FN: engine doesn't learn BoolConstraints from binary operators + End If + End If + + a = False + If a And b Then ' Noncompliant + End If + + a = a Or True + If a Then ' Noncompliant + End If + + a = a Or True + If a Then ' Noncompliant + End If + + a = a Xor True + If a Then ' Noncompliant + End If + + a = a Xor True + If a Then ' Noncompliant + End If + End Sub + + Public Sub IsAsExpression(ByVal o As Object) + + If TypeOf o Is String Then + End If + + Dim oo As Object = TryCast(o, String) + If oo Is Nothing Then + End If + + o = Nothing + If TypeOf o Is Object Then ' Noncompliant + End If + + oo = TryCast(o, Object) + If oo Is Nothing Then ' Noncompliant + End If + End Sub + + Public Overloads Sub Equals(ByVal b As Boolean) + Dim a = True + If a = b Then + If b Then ' Noncompliant + End If + Else + If b Then ' Noncompliant + End If + End If + + If Not a = b Then + If b Then ' Noncompliant + End If + Else + If b Then ' Noncompliant + End If + End If + End Sub + + Public Sub NotEquals(ByVal b As Boolean) + Dim a = True + If a <> b Then + If b Then ' Noncompliant + End If + Else + If b Then ' Noncompliant + End If + End If + + If Not a <> b Then + If b Then ' Noncompliant + End If + Else + If b Then ' Noncompliant + End If + End If + End Sub + + Public Sub EqRelations(ByVal a As Boolean, ByVal b As Boolean) + If a = b Then + If b = a Then ' FN: requires relation support + End If + If b = Not a Then ' FN: requires relation support + End If + If Not b = Not Not a Then ' FN: requires relation support + End If + If Not a = b Then ' FN: requires relation support + End If + Else + If b <> a Then ' FN: requires relation support + End If + If b <> Not a Then ' FN: requires relation support + End If + If Not b <> Not Not a Then ' FN: requires relation support + End If + + End If + + If a <> b Then + If b = a Then ' FN: requires relation support + End If + Else + If b <> a Then ' FN: requires relation support + End If + End If + End Sub + + Private Shared Sub BackPropagation(ByVal a As Object, ByVal b As Object) + If a Is b AndAlso b Is Nothing Then + a.ToString() + End If + End Sub + + Public Sub RefEqualsImpliesValueEquals(ByVal a As Object, ByVal b As Object) + If Object.ReferenceEquals(a, b) Then + If Equals(a, b) Then ' FN + End If + If Equals(a, b) Then ' FN + End If + If a.Equals(b) Then ' FN + End If + End If + + If Me Is a Then + If Equals(a) Then ' FN + End If + If Equals(a) Then ' FN + End If + End If + End Sub + + Public Sub ValueEqualsDoesNotImplyRefEquals(ByVal a As Object, ByVal b As Object) + If Equals(a, b) Then ' 'a' could override Equals, so this is not a ref equality check + If a Is b Then + End If ' Compliant + End If + End Sub + + Public Sub ReferenceEqualsMethodCalls(ByVal a As Object, ByVal b As Object) + If Object.ReferenceEquals(a, b) Then + If a Is b Then + End If ' FN + End If + + If a Is b Then + If Object.ReferenceEquals(a, b) Then + End If ' FN + End If + End Sub + + Public Sub ReferenceEqualsMethodCallWithOpOverload(ByVal a As ConditionEvaluatesToConstant, ByVal b As ConditionEvaluatesToConstant) + If Object.ReferenceEquals(a, b) Then + If a Is b Then ' FN + End If + End If + + If a Is b Then + If Object.ReferenceEquals(a, b) Then ' Compliant, == is doing a value comparison above. FIX + End If + End If + End Sub + + Public Sub ReferenceEquals(ByVal a As Object, ByVal b As Object) + If Object.ReferenceEquals(a, b) Then + End If + + If Object.ReferenceEquals(a, a) Then + End If ' FN + + a = Nothing + If Object.ReferenceEquals(Nothing, a) Then ' Noncompliant + End If + If Object.ReferenceEquals(a, a) Then ' Noncompliant + End If + + If Object.ReferenceEquals(Nothing, New Object()) Then ' Noncompliant + End If + + ' Because of boxing: + Dim i = 10 + If Object.ReferenceEquals(i, i) Then ' FN + End If + + Dim ii As Integer? = Nothing + Dim jj As Integer? = Nothing + If Object.ReferenceEquals(ii, jj) Then ' Noncompliant + End If + + jj = 10 + If Object.ReferenceEquals(ii, jj) Then ' Noncompliant + End If + End Sub + + Public Sub ReferenceEqualsBool() + Dim a, b As Boolean + a = b = True + If Object.ReferenceEquals(a, b) Then ' FN + End If + End Sub + + Public Overrides Function Equals(ByVal obj As Object) As Boolean + Return MyBase.Equals(obj) + End Function + + Public Shared Operator =(ByVal a As ConditionEvaluatesToConstant, ByVal b As ConditionEvaluatesToConstant) As Boolean + Return False + End Operator + + Public Shared Operator <>(ByVal a As ConditionEvaluatesToConstant, ByVal b As ConditionEvaluatesToConstant) As Boolean + Return False + End Operator + + Public Sub StringEmpty(ByVal s1 As String) + Dim s As String = Nothing + If String.IsNullOrEmpty(s) Then ' Noncompliant + End If + If String.IsNullOrWhiteSpace(s) Then ' Noncompliant + End If + If Not Equals(String.IsInterned(s), Nothing) Then ' FN FIX + End If + s = "" + If String.IsNullOrEmpty(s) Then ' FN + End If + + If String.IsNullOrWhiteSpace(s) Then ' FN + End If + + If String.IsNullOrEmpty(s1) Then ' Compliant, we don't know anything about the argument + End If + + If String.IsNullOrWhiteSpace(s1) Then ' Compliant + End If + + If String.IsNullOrEmpty(s1) Then + If String.IsNullOrEmpty(s1) Then ' FN + End If + End If + End Sub + + Public Sub Comparisons(ByVal i As Integer, ByVal j As Integer) + If i < j Then + If j < i Then ' FN + End If + If j <= i Then ' FN + End If + If j = i Then ' FN + End If + If j <> i Then ' FN + End If + End If + End Sub + + Private Sub ValueEquals(ByVal i As Integer, ByVal j As Integer) + If i = j Then + If Equals(i, j) Then ' FN + End If + If i.Equals(j) Then ' FN + End If + End If + End Sub + + Private Sub DefaultExpression(ByVal o As Object) + If Nothing Is Nothing Then ' Noncompliant + End If + + Dim nullableInt As Integer? = Nothing + If nullableInt Is Nothing Then ' Noncompliant + End If + + If Nothing Is Nothing Then ' Noncompliant + End If + + If Nothing IsNot Nothing Then ' Noncompliant + End If + + If Nothing IsNot Nothing Then ' Noncompliant + End If + End Sub + + Private Sub Cast() + Dim i = 5 + Dim o = CObj(i) + If o Is Nothing Then ' Noncompliant + End If + + Dim x = CType(o, ConditionEvaluatesToConstant) ' This would throw and invalid cast exception + If x Is Nothing Then ' Noncompliant + End If + + End Sub + + Public Async Function NotNullAfterAccess(ByVal o As Object, ByVal arr As Integer(,), ByVal coll As IEnumerable(Of Integer), ByVal task As Task) As Task + Console.WriteLine(o.ToString()) + If o Is Nothing Then ' Noncompliant + End If + + + Console.WriteLine(arr(42, 42)) + If arr Is Nothing Then ' Noncompliant + End If + + + For Each item In coll + Next + If coll Is Nothing Then ' Noncompliant + End If + + + Await task + If task Is Nothing Then ' FN + End If + + End Function + + Public Sub EqualsTest32(ByVal o As Object) + Dim o2 = o + If o Is o2 Then ' FN + End If + If Object.ReferenceEquals(o, o2) Then ' FN + End If + If o.Equals(o2) Then ' FN + End If + If Equals(o2, o) Then ' FN + End If + + + Dim i = 1 + Dim j = i + If i = j Then ' Noncompliant + End If + + If i.Equals(j) Then ' FN + End If + + If Equals(i, j) Then ' FN + End If + End Sub + + Private Async Function Test_Await_Constraint(ByVal t As Task(Of String)) As Task + If t IsNot Nothing Then + Dim o = Await t + If Equals(o, Nothing) Then ' Compliant, might be null + End If + End If + End Function + + Public Sub Assert(ByVal condition As Boolean, ByVal o1 As Object) + Debug.Assert(condition) + + If condition Then ' Noncompliant + End If + + Trace.Assert(condition) ' Compliant + + If o1 IsNot Nothing Then + Debug.Assert(o1 Is Nothing, "Some message", "More details", 1, 2, 3) ' Compliant + End If + End Sub + + Public Sub Assert(ByVal o1 As Object) + Debug.Assert(o1 IsNot Nothing) + Debug.Assert(o1 Is Nothing) + End Sub + + Private Sub ComparisonTransitivity(ByVal a As Integer, ByVal b As Integer, ByVal c As Integer) + If a = b AndAlso b < c Then + If a >= c Then ' FN + End If + + End If + If a = b AndAlso b <= c Then + If a > c Then ' FN + End If + + End If + If a > b AndAlso b > c Then + If a <= c Then ' FN + End If + + End If + If a > b AndAlso b >= c Then + If a <= c Then ' FN + End If + + End If + If a >= b AndAlso b >= c Then + If a < c Then ' FN + End If + + End If + If a >= b AndAlso c <= b Then + If a < c Then ' FN + End If + + End If + If a >= b AndAlso c >= b Then + If a < c Then + End If + End If + End Sub + + Friend Class Comp + Public Shared Operator <(ByVal a As Comp, ByVal b As Comp) As Boolean + Return True + End Operator + Public Shared Operator >(ByVal a As Comp, ByVal b As Comp) As Boolean + Return True + End Operator + Public Shared Operator >=(ByVal a As Comp, ByVal b As Comp) As Boolean + Return True + End Operator + Public Shared Operator <=(ByVal a As Comp, ByVal b As Comp) As Boolean + Return True + End Operator + End Class + + Private Sub RefEqTransitivity(ByVal a As Comp, ByVal b As Comp, ByVal c As Comp) + If a Is b AndAlso b Is c Then + If a IsNot c Then ' FN + End If + End If + + If a.Equals(b) AndAlso b Is c Then + If a IsNot c Then + End If + If a Is c Then + End If + If a.Equals(c) Then ' FN + End If + If Not a.Equals(c) Then ' FN + End If + End If + + If a > b AndAlso b Is c Then + If a <= c Then ' FN + End If + End If + End Sub + + Private Sub ValueEqTransitivity(ByVal a As Comp, ByVal b As Comp, ByVal c As Comp) + If a Is b AndAlso b.Equals(c) Then + If a.Equals(c) Then ' FN + End If + End If + + If a.Equals(b) AndAlso b.Equals(c) Then + If a IsNot c Then + End If + If a Is c Then + End If + If a.Equals(c) Then ' FN + End If + If Not a.Equals(c) Then ' FN + End If + End If + + If a > b AndAlso b.Equals(c) Then + If a > c Then ' FN + End If + If a <= c Then ' FN + End If + End If + + If Not a.Equals(b) AndAlso b.Equals(c) Then + If a.Equals(c) Then ' FN + End If + If a Is c Then ' FN + End If + End If + + If a IsNot b AndAlso b.Equals(c) Then + If a.Equals(c) Then + End If + If a Is c Then + End If + End If + End Sub + + Private Sub NeqEqTransitivity(ByVal a As Object, ByVal b As Object, ByVal c As Object) + If a Is c AndAlso a IsNot b Then + If b Is c Then ' FN + End If + + If b.Equals(c) Then + End If + End If + + If a Is c AndAlso Not a.Equals(b) Then + If b Is c Then ' FN + End If + + If b.Equals(c) Then ' FN + End If ' FN + + End If + End Sub + + Public Sub LiftedOperator() + Dim i As Integer? = Nothing + Dim j As Integer? = 5 + + If i < j Then ' Noncompliant + End If + + If i <= j Then ' Noncompliant + End If + + If i > j Then ' Noncompliant + End If + + If i >= j Then ' Noncompliant + End If + + If i > 0 Then ' Noncompliant + End If + + If i >= 0 Then ' Noncompliant + End If + + If i < 0 Then ' Noncompliant + End If + + If i <= 0 Then ' Noncompliant + End If + + If j > Nothing Then ' Noncompliant + End If + + If j >= Nothing Then ' Noncompliant + End If + + If j < Nothing Then ' Noncompliant + End If + + If j <= Nothing Then ' Noncompliant + End If + End Sub + + Friend Class Singleton + Private Shared syncRoot As Object = New Object() + + Private Shared instanceField As Singleton + + Public Shared ReadOnly Property Instance As Singleton + Get + If instanceField Is Nothing Then + SyncLock syncRoot + If instanceField Is Nothing Then ' Noncompliant FP + instanceField = New Singleton() + End If + End SyncLock + End If + Return instanceField + End Get + End Property + End Class + + Friend Structure MyStructWithNoOperator + Public Shared Sub M(ByVal a As MyStructWithNoOperator) + If a Is Nothing Then ' Noncompliant, also a compiler error + ' Error@-1 [BC30020] + End If + End Sub + End Structure + + Public Class NullableCases + Private Sub Case1() + Dim b1 As Boolean? = True + If b1 = True Then ' Noncompliant + End If + End Sub + + Private Sub Case2(ByVal i As Boolean?) + If i Is Nothing Then + + End If + If i = True Then + + End If + If i = False Then + + End If + + i = Nothing + If i Is Nothing Then ' Noncompliant + + End If + If i = True Then ' Noncompliant + + End If + If i = False Then ' Noncompliant + + End If + + i = True + If i Is Nothing Then ' Noncompliant + + End If + If i = True Then ' Noncompliant + + End If + If i = False Then ' Noncompliant + + End If + + i = False + If i Is Nothing Then ' Noncompliant + + End If + If i = True Then ' Noncompliant + + End If + If i = False Then ' Noncompliant + + End If + + Dim b2 As Boolean? = True + If b2 = False Then ' Noncompliant + End If + + Dim b3 As Boolean? = True + If b3 Is Nothing Then ' Noncompliant + End If + + Dim b4 As Boolean? = Nothing + If b4 = True Then ' Noncompliant + End If + + Dim b5 As Boolean? = Nothing + If b5 = False Then ' Noncompliant + End If + + + Dim b6 As Boolean? = Nothing + If b6 Is Nothing Then ' Noncompliant + End If + Dim b7 As Boolean? = True + If b7 = True Then ' Noncompliant + End If + Dim b8 As Boolean? = False + If b8 = False Then ' Noncompliant + End If + + End Sub + + Private Sub Case3(ByVal b As Boolean?) + If b Is Nothing Then + If Nothing Is b Then ' Noncompliant + b.ToString() + End If + Else + If b IsNot Nothing Then ' Noncompliant + b.ToString() + End If + End If + End Sub + + Private Sub Case4(ByVal b As Boolean?) + If b = True Then + If True = b Then ' Noncompliant + b.ToString() + End If + End If + End Sub + + Private Sub Case5(ByVal b As Boolean?) + If b = True Then + ElseIf b = False Then + Else + End If + End Sub + + Private Sub Case6(ByVal b As Boolean?) + If b Is Nothing Then + ElseIf b = True Then + Else + End If + End Sub + + Private Sub Case7(ByVal b As Boolean?) + If b Is Nothing Then + If If(b, False) Then ' Noncompliant + + End If + End If + End Sub + + Private Sub Case8(ByVal b As Boolean?) + If b IsNot Nothing Then + If b.HasValue Then ' Noncompliant + End If + End If + End Sub + + Private Sub Case9(ByVal b As Boolean?) + If b = True Then + Dim x = b.Value + If x = True Then ' Noncompliant + End If + End If + End Sub + + Private Sub Case10(ByVal i As Integer?) + If i Is Nothing Then + If i.HasValue Then ' Noncompliant + End If + End If + End Sub + + ' https://github.com/SonarSource/sonar-dotnet/issues/4755 + Public Sub IfElseIfElseFlow_FromCast(ByVal value As Object) + Dim b = CType(value, Boolean?) + If b = True Then + Console.WriteLine("true") + ElseIf b = False Then ' Compliant + Console.WriteLine("false") + Else + Console.WriteLine("null") + End If + End Sub + + Public Sub IfElseIfElseFlow_DirectValue(ByVal b As Boolean?) + If b = True Then + Console.WriteLine("true") + ElseIf b = False Then + Console.WriteLine("false") + Else + Console.WriteLine("null") + End If + End Sub + + Public Sub IfElseIfElseFlow_KnownNull() + Dim b As Boolean? = Nothing + If b = True Then ' Noncompliant + Console.WriteLine("true") ' Secondary + ElseIf b = False Then ' Noncompliant + Console.WriteLine("false") ' Secondary + Else + Console.WriteLine("null") + End If + End Sub + End Class + + Public Class ConstantExpressionsAreExcluded + Const T As Boolean = True + Const F As Boolean = False + + Private Sub LocalConstants() + Const t = True + If t Then ' Noncompliant + Console.WriteLine() + End If + Const f = False + If f Then ' Noncompliant + Console.WriteLine() ' Secondary + End If + End Sub + Private Sub Constants() + If T Then ' Compliant it's a constant + Console.WriteLine() + End If + If F Then ' Compliant it's a constant + Console.WriteLine() + End If + End Sub + Private Sub WhileTrue() + While T ' Compliant it's a constant + Console.WriteLine() + End While + End Sub + Private Sub WhileFalse() + Do + Console.WriteLine() + Loop While F ' Compliant it's a constant + End Sub + Private Sub Condition() + Dim x = If(T, 1, 2) ' Compliant, T is constant + End Sub + End Class + + End Class + + Public Class GuardedTests + Public Sub Guarded(ByVal s1 As String) + Guard1(s1) + + If Equals(s1, Nothing) Then ' Noncompliant, always flse + ' this branch is never executed + Else + End If + End Sub + + Public Sub Guard1(Of T As Class)( + ByVal value As T) + End Sub + + + Public NotInheritable Class ValidatedNotNullAttribute + Inherits Attribute + End Class + End Class + + Public Class CatchFinally + Public Sub ObjectsShouldNotBeDisposedMoreThanOnce() + Dim stream As Stream = Nothing + Try + stream = File.Open("file", FileMode.Open) + Using reader = New StreamReader(stream) + ' read the file here + + ' StreamReader will dispose the stream automatically; set stream to null + ' to prevent it from disposing twice (the recommended pattern for S3966) + stream = Nothing + End Using + + Finally + If stream IsNot Nothing Then + stream.Dispose() + End If + End Try + End Sub + + Public Sub FalseNegatives() + ' We cannot detect the case in ObjectsShouldNotBeDisposedMoreThanOnce method above + ' and to avoid False Positives we do not report in catch or finally + Dim o As Object = Nothing + Try + Console.WriteLine("Could throw") + Catch + If o IsNot Nothing Then ' Noncompliant + End If + If o Is Nothing Then ' Noncompliant + End If + + Finally + If o IsNot Nothing Then ' Noncompliant + End If + If o Is Nothing Then ' Noncompliant + End If + End Try + End Sub + End Class + + Friend Class UsingStatement + Public Sub Method() + Dim isTrue = True + If isTrue Then ' Noncompliant + End If + Using reader = New StreamReader("") + If isTrue Then ' Noncompliant + End If + End Using + If isTrue Then ' Noncompliant + End If + End Sub + End Class + + Friend Class AsyncAwait + Private _foo1 As Object + Private Async Function Foo(ByVal t As Task) As Task + Dim o As Object = Nothing + _foo1 = o + Await t ' awaiting clears the constraints + If _foo1 IsNot Nothing Then ' Compliant S2583 + End If + If _foo1 Is Nothing Then ' Compliant S2589 + End If + If o IsNot Nothing Then ' Noncompliant + End If + If o Is Nothing Then ' Noncompliant + End If + End Function + End Class + + Public Class StaticMethods + Private _foo1 As Object + ' https://github.com/SonarSource/sonar-dotnet/issues/947 + Private Sub CallToMonitorWaitShouldResetFieldConstraints() + Dim o As Object = Nothing + _foo1 = o + Threading.Monitor.Wait(o) ' This is a multi-threaded application, the fields could change + If _foo1 IsNot Nothing Then ' Noncompliant FP + End If + If _foo1 Is Nothing Then ' Noncompliant FP + End If + If o IsNot Nothing Then ' Noncompliant + End If + If o Is Nothing Then ' Noncompliant + End If + End Sub + + Private Sub CallToStaticMethodsShouldResetFieldConstraints() + Dim o As Object = Nothing + _foo1 = o + Console.WriteLine() ' This particular method has no side effects + If _foo1 IsNot Nothing Then ' Noncompliant + End If + If _foo1 Is Nothing Then ' Noncompliant + End If + If o IsNot Nothing Then ' Noncompliant + End If + If o Is Nothing Then ' Noncompliant + End If + End Sub + End Class + + + Public Class TestNullCoalescing + Public Sub CompliantMethod(ByVal input As Boolean?) + If If(input, False) Then ' Compliant + Console.WriteLine("input is true") + Else + Console.WriteLine("input is false") + End If + End Sub + + Public Sub CompliantMethod1(ByVal input As Boolean?) + While If(input, False) ' Compliant + Console.WriteLine("input is true") + End While + End Sub + + Public Sub CompliantMethod2(ByVal input As Boolean?, ByVal input1 As Boolean) + While If(input, False) AndAlso input1 ' Compliant + Console.WriteLine("input is true") + End While + End Sub + + Public Sub CompliantMethod3(ByVal input As Boolean?, ByVal input1 As Boolean) + + If If(If(input, False), input1, False) Then ' Compliant + Console.WriteLine("input is true") + End If + End Sub + + Public Sub NonCompliantMethod() + Dim input As Boolean? = True + If If(input, False) Then ' Noncompliant + Console.WriteLine("input is true") + Else + Console.WriteLine("input is false") ' Secondary + End If + End Sub + + Public Sub NonCompliantMethod1() + Dim input As Boolean? = True + While If(input, False) ' Noncompliant + Console.WriteLine("input is true") + End While + End Sub + + Public Sub NonCompliantMethod2(ByVal input As Boolean?) + While If(input, False) OrElse True ' Compliant + Console.WriteLine("input is true") + End While + End Sub + + Public Sub NonCompliantMethod3(ByVal input As Boolean?, ByVal input1 As Boolean) + If If(If(input, False), False, False) Then ' Compliant + Console.WriteLine("input is true") + End If + End Sub + End Class + + Friend Class Program + Public Shared Function CompliantMethod4(ByVal parameter As String) As String + Dim useParameter = If(parameter, "non-empty") + If Equals(useParameter, Nothing) OrElse Equals(useParameter, "") Then Return "non-empty" ' Noncompliant + ' we don't know if this going to be excuted or not + + Return "empty" + End Function + + Public Shared Function Method1347(ByVal parameter As String) As String + Dim useParameter = If(parameter, "non-empty") + If Not String.IsNullOrEmpty(useParameter) Then + Return "non-empty" + Else + End If + Return "empty" + End Function + End Class + + Friend Class Repro2442 + Public Sub Method(ByVal unknown As Boolean) + Dim f = False + Dim t = True + If t Then ' Noncompliant + Else + + End If + + If f Then ' Noncompliant + Else + + End If + + If unknown OrElse t Then ' Noncompliant + Else + + End If + + If unknown AndAlso f Then ' Noncompliant + Else + + End If + + If unknown AndAlso t Then ' Noncompliant + Else + + End If + + If unknown OrElse f Then ' Noncompliant + Else + + End If + + If unknown AndAlso t Then ' Noncompliant + Else + + End If + End Sub + + ''' + ''' A certain combination of condition wrongly considers the else code as dead. + ''' + Private Shared Sub FalsePositive() + FalsePositive2_Sub(True, False, False) + FalsePositive2_Sub(True, False, True) + + FalsePositive2_Sub(True, True, True) + FalsePositive2_Sub(True, True, False) + + FalsePositive2_Sub(False, False, False) + FalsePositive2_Sub(False, False, True) + + FalsePositive2_Sub(False, True, True) + FalsePositive2_Sub(False, True, False) + + ' Outcome. + Console.WriteLine(If(_test1 AndAlso _test2 AndAlso _test3 AndAlso _test4, "Went through each test condition", "Missed at least one test condition")) + End Sub + + Private Shared _test1 As Boolean = False + Private Shared _test2 As Boolean = False + Private Shared _test3 As Boolean = False + Private Shared _test4 As Boolean = False + + Private Shared Sub FalsePositive2_Sub(ByVal testCondition1 As Boolean, ByVal testCondition2 As Boolean, ByVal testCondition3 As Boolean) + Dim condition1 = testCondition1 + Dim condition2 = testCondition2 + Dim condition3 = condition2 AndAlso testCondition3 + + If condition2 AndAlso condition3 AndAlso condition1 Then + _test1 = True + ElseIf Not condition2 AndAlso Not condition1 Then + _test2 = True + ElseIf condition2 AndAlso condition1 AndAlso Not condition3 Then ' Noncompliant + _test3 = True + Else + _test4 = True + End If + End Sub + End Class + + Public Class RefArgTest + Public Sub Method(ByRef s As String, ByVal x As Integer) + End Sub + Public Sub Method1(ByVal infixes As String) + If Not Equals(infixes, Nothing) Then + Method(infixes, infixes.Length) + If Equals(infixes, Nothing) Then ' Noncompliant FP: ref + Return + End If + End If + End Sub + + Public Sub Method2(ByVal infixes As String) + If Not Equals(infixes, Nothing) Then + Method(infixes, infixes.Length) + If Not Equals(infixes, Nothing) Then ' Noncompliant FP: ref + Return + End If + End If + End Sub + + Public Sub Method3(ByVal infixes As String) + If Equals(infixes, Nothing) Then + Method(infixes, infixes.Length) + If Equals(infixes, Nothing) Then ' Noncompliant FP: ref + Return + End If + End If + End Sub + + Public Sub Method4(ByVal infixes As String) + If Equals(infixes, Nothing) Then + Method(infixes, infixes.Length) + If Not Equals(infixes, Nothing) Then ' Noncompliant FP: ref + Return + End If + End If + End Sub + + End Class + + Friend Class ReproForEachFP + Private Shared Function Repro2348(ByVal list As List(Of Integer)) As Boolean + Dim containspositive = False + Dim containsnegative = False + + For Each value In list + If value > 0 Then + containspositive = True + ElseIf value < 0 Then + containsnegative = True + End If + Next + + Return containspositive AndAlso Not containsnegative ' Compliant + End Function + + Private Shared Sub Repro1187_1() + Dim do1 = False + Dim do2 = False + Dim items = New Integer() {1, 2, 3} + For Each item In items + Select Case item + Case 1 + do1 = True + Case 2 + do2 = True + End Select + Next + + If do1 AndAlso do2 Then ' Noncompliant: This repro is badly written. This is a TP. You can find the FP below. + Throw New InvalidOperationException() ' Secondary + End If + End Sub + + Private Shared Sub Repro1187_1_Fixed(ByVal items As Integer()) + Dim do1 = False + Dim do2 = False + For Each item In items + Select Case item + Case 1 + do1 = True + Case 2 + do2 = True + End Select + Next + + If do1 AndAlso do2 Then ' Noncompliant FP + Throw New InvalidOperationException() ' Secondary FP + End If + End Sub + + Private Shared Sub Repro1187_2(ByVal elementGroup As List(Of Integer)) + Dim startDoingSomething = False + Dim a = 0 + + For Each element In elementGroup + If Not startDoingSomething Then ' Compliant + If element > 3 Then + startDoingSomething = True + End If + Else + a += 1 + End If + Next + End Sub + + Private Shared Function Repro1160(ByVal files As String()) As Boolean + Dim anyPathRooted = False + Dim allPathsRooted = True + For Each file In files + If Path.IsPathRooted(file) Then + anyPathRooted = True + Else + allPathsRooted = False + End If + Next + If anyPathRooted AndAlso Not allPathsRooted Then ' Noncompliant FP + Throw New InvalidOperationException("Paths must be all rooted or all unrooted") ' Secondary FP + End If + Return allPathsRooted + End Function + + Private Shared Function ForEachLoop(ByVal items As Integer()) As Boolean + Dim bool1 = False + Dim bool2 = False + + For Each item In items + If item > 0 Then + bool1 = True + ElseIf item < 0 Then + bool2 = True + End If + Next + + If bool1 AndAlso bool2 Then ' Noncompliant FP + Throw New InvalidOperationException() ' Secondary FP + End If + + Return bool1 AndAlso Not bool2 ' Compliant + End Function + + Private Shared Function ForEachLoop2(ByVal items As Integer()) As Boolean + Dim bool1 = False + Dim bool2 = False + +BeforeLoop: + + For Each item1 In items + For Each item2 In items + For Each item3 In items + For Each item4 In items + If item1 > 0 Then + bool1 = True + ElseIf item2 < 0 Then + bool2 = True + End If + Next + Next + Next + Next + + If bool1 AndAlso bool2 Then ' Noncompliant FP FIX + GoTo BeforeLoop + End If + Return False + End Function + + Private Shared Function LoopIterationLimitation(ByVal items As Integer()) As Boolean + Dim bool1 = False + Dim bool2 = False + Dim bool3 = False + + For Each item1 In items + If bool2 Then ' Noncompliant - FP because symbolic execution stops at the third iteration of loop + bool3 = True ' Secondary FP + End If + If bool1 Then + bool2 = True + End If + If item1 > 1 Then + bool1 = True + End If + + Next + Return bool3 + End Function + End Class + + Public Class GeneratorFunctions + Private generate As Boolean + + Public Sub [Stop]() + generate = False + End Sub + + Public Iterator Function Repro_1295() As IEnumerable(Of Integer) + generate = True + While generate ' Noncompliant FP: 'generate' field can potentially be changed inside the loop where this generator is used + Yield 0 + End While + End Function + + Public Iterator Function FalseNegative() As IEnumerable(Of Integer) + Dim myVariable = True + While myVariable ' Noncompliant: myVariable will never change after initialization + Yield 0 + End While + End Function + End Class + + Public Class StringComparision + Public Sub Method(ByVal parameterString As String) + Dim emptyString1 = "" + Dim emptyString2 = "" + Dim nullString1 As String = Nothing + Dim nullString2 As String = Nothing + Dim fullStringa1 = "a" + Dim fullStringa2 = "a" + Dim fullStringb = "b" + Dim whiteSpaceString1 = " " + Dim whiteSpaceString2 = " " + Dim doubleWhiteSpaceString1 = " " + Dim doubleWhiteSpaceString2 = " " + + If Equals(emptyString1, emptyString2) Then ' FN + + End If + If Equals(nullString1, nullString2) Then ' Noncompliant + + End If + + If Equals(fullStringa1, fullStringa2) Then + + End If + + If Equals(fullStringa1, fullStringb) Then + + End If + + If Equals(parameterString, emptyString1) Then + + End If + + If Equals(parameterString, nullString1) Then + + End If + + If Equals(emptyString1, nullString1) Then ' Noncompliant + + End If + + If Equals(emptyString1, fullStringa1) Then ' FN + + End If + + If Equals(nullString1, fullStringa1) Then ' Noncompliant + + End If + + If Equals(fullStringa1, "") Then ' FN + + End If + + If Equals(fullStringa1, Nothing) Then ' Noncompliant + + End If + + If Equals(whiteSpaceString1, whiteSpaceString2) Then ' FN + + End If + + If Equals(whiteSpaceString1, " ") Then ' FN + + End If + + If Equals(whiteSpaceString1, emptyString1) Then ' FN + + End If + + If Equals(whiteSpaceString1, nullString1) Then ' Noncompliant + + End If + + If Equals(whiteSpaceString1, fullStringa1) Then ' FN + + End If + + If Equals(whiteSpaceString1, parameterString) Then + + End If + + If Equals(doubleWhiteSpaceString1, doubleWhiteSpaceString2) Then ' FN + + End If + + If Equals(doubleWhiteSpaceString1, emptyString1) Then ' FN + + End If + + If Equals(doubleWhiteSpaceString1, nullString1) Then ' Noncompliant + + End If + + If Equals(doubleWhiteSpaceString1, fullStringa1) Then ' FN + + End If + + If Equals(doubleWhiteSpaceString1, parameterString) Then + + End If + + End Sub + End Class + + Public Class NullOrEmpty + Public Sub Method1(ByVal s As String) + Dim s1 As String = Nothing + Dim s2 = "" + Dim s3 = "a" + If String.IsNullOrEmpty(s1) Then ' Noncompliant + End If + If String.IsNullOrEmpty(s2) Then ' FN + End If + + If String.IsNullOrEmpty(s) Then + End If + + If String.IsNullOrEmpty(s3) Then ' FN + End If + End Sub + + Public Sub Method2(ByVal s As String) + + If String.IsNullOrEmpty(s) Then + End If + + s = "" + If String.IsNullOrEmpty(s) Then ' FN + End If + + s = Nothing + If String.IsNullOrEmpty(s) Then ' Noncompliant + End If + + s = "a" + If String.IsNullOrEmpty(s) Then ' FN + End If + End Sub + + Public Sub Method3(ByVal s1 As String) + If String.IsNullOrEmpty(s1) Then + s1.ToString() + Else + If Equals(s1, Nothing) Then ' Noncompliant + s1.ToString() ' Secondary + End If + End If + + End Sub + + Public Sub Method4(ByVal s1 As String) + If Not String.IsNullOrEmpty(s1) Then + If Equals(s1, Nothing) Then ' Noncompliant + s1.ToString() ' Secondary + End If + Else + s1.ToString() + End If + + End Sub + + Public Sub Method5(ByVal s1 As String) + If Not String.IsNullOrEmpty(s1) Then + If Equals(s1, Nothing) Then ' Noncompliant + s1.ToString() ' Secondary + End If + Else + s1.ToString() + End If + + End Sub + + Public Sub Method6(ByVal s1 As String) + If String.IsNullOrEmpty(s1) OrElse Equals(s1, "a") Then + s1.ToString() + Else + If Equals(s1, Nothing) Then ' Noncompliant + s1.ToString() ' Secondary + End If + End If + + End Sub + + Public Sub Method7(ByVal s1 As String) + If String.IsNullOrEmpty(s1) AndAlso Equals(s1, "a") Then ' FN + s1.ToString() + Else + If Equals(s1, Nothing) Then + s1.ToString() + End If + End If + + End Sub + + + Public Function Method8(ByVal message As String) As String + If Equals(message, Nothing) Then + Throw New ArgumentNullException($"{NameOf(message)} shouldn't be null!") + End If + + If String.IsNullOrEmpty(message) Then + Throw New ArgumentNullException($"{NameOf(message)} shouldn't be empty!") + End If + + Return String.Empty + End Function + + Private Sub NullCoalesce_Useless(ByVal a As String, ByVal b As String, ByVal c As String, ByVal d As String) + Dim isNull As String = Nothing + Dim notNull = "" + Dim notEmpty = "value" + Dim ret As String + + ret = If(b, a) + ret = If(b, notNull) + ret = If(c, notEmpty) + ret = If(d, "N/A") + + 'Left operand: Values notNull and notEmpty are known to be not-null + ret = If(notNull, a) ' Noncompliant + ' Secondary@-1 + ret = If(notNull, a) ' Noncompliant + ' Secondary@-1 + ret = "Lorem " & If(notNull, a) & " ipsum" ' Noncompliant + ' Secondary@-1 + ret = If(notNull, "N/A") ' Noncompliant + ' Secondary@-1 + ret = If(notEmpty, "N/A") ' Noncompliant + ' Secondary@-1 + + 'Left operand: isNull is known to be null + ret = If(Nothing, a) ' Noncompliant + ret = If(isNull, a) ' NoncompliantP + ret = "Lorem " & If(isNull, a) & " ipsum" ' Noncompliant + + 'Right operand: isNull is known to be null, therefore ?? is useless + ret = If(a, Nothing) ' FN: NOOP + ret = If(a, isNull) ' FN: NOOP + ' ~~~~~~ + + 'Combo/Fatality + ret = If(notNull, isNull) + ' ^^^^^^^ Noncompliant {{Change this expression which always evaluates to the same result. Some code paths are unreachable.}} + ' ^^^^^^ Secondary@-1 + ret = If(isNull, Nothing) ' Noncompliant {{Change this expression which always evaluates to the same result.}} + ' ^^^^^^ + ret = If("Value", a) + ' ^^^^^^^ Noncompliant {{Change this expression which always evaluates to the same result. Some code paths are unreachable.}} + ' ^ Secondary@-1 + End Sub + + Private Function CoalesceCount(Of T)(ByVal arg As IList(Of T)) As Integer + arg = If(arg, New List(Of T)()) + Return arg.Count + End Function + + Public Class CoalesceProperty + Private messageField As Object + + Public ReadOnly Property Message As Object + Get + Return CSharpImpl.__Assign(messageField, If(messageField, New Object())) + End Get + End Property + + Private Class CSharpImpl + + Shared Function __Assign(Of T)(ByRef target As T, value As T) As T + target = value + Return value + End Function + End Class + End Class + End Class + + Public Class NullOrWhiteSpace + Public Sub Method1(ByVal s As String) + Dim s1 As String = Nothing + Dim s2 = "" + Dim s3 = If(s, "") + Dim s4 = " " + + If String.IsNullOrWhiteSpace(s1) Then ' Noncompliant + End If + + + If String.IsNullOrWhiteSpace(s2) Then ' FN + If Equals(s2, "a") Then ' FN + + End If + End If + + If String.IsNullOrWhiteSpace(s3) Then + + End If + + If String.IsNullOrWhiteSpace(s4) Then ' FN + + End If + + If Not String.IsNullOrWhiteSpace(s4) Then ' FN + + End If + + If Not String.IsNullOrWhiteSpace(s) Then + If Equals(s, "") Then ' FN + + End If + + If Equals(s, " ") Then ' FN + + End If + End If + + End Sub + End Class + +End Namespace From 31279fc25efc28f07eb3eddbca5cd7638d9cc8d1 Mon Sep 17 00:00:00 2001 From: mary-georgiou-sonarsource Date: Wed, 9 Aug 2023 11:21:18 +0200 Subject: [PATCH 03/20] Ignore this commit - rspec update so tests work - rspec is draft --- analyzers/rspec/vbnet/S2583.html | 56 +++++++++++++++++++ analyzers/rspec/vbnet/S2583.json | 33 +++++++++++ analyzers/rspec/vbnet/S2589.html | 59 ++++++++++++++++++++ analyzers/rspec/vbnet/S2589.json | 32 +++++++++++ analyzers/rspec/vbnet/Sonar_way_profile.json | 2 + 5 files changed, 182 insertions(+) create mode 100644 analyzers/rspec/vbnet/S2583.html create mode 100644 analyzers/rspec/vbnet/S2583.json create mode 100644 analyzers/rspec/vbnet/S2589.html create mode 100644 analyzers/rspec/vbnet/S2589.json diff --git a/analyzers/rspec/vbnet/S2583.html b/analyzers/rspec/vbnet/S2583.html new file mode 100644 index 00000000000..e3ac10fbce1 --- /dev/null +++ b/analyzers/rspec/vbnet/S2583.html @@ -0,0 +1,56 @@ +

Why is this an issue?

+

Conditional expressions which are always true or false can lead to unreachable code.

+

In the case below, the call of Dispose() never happens.

+
+var a = false;
+if (a)
+{
+    Dispose(); // Never reached
+}
+
+

Exceptions

+

This rule will not raise an issue in either of these cases:

+
    +
  • When the condition is a single const bool
    +const bool debug = false;
    +//...
    +if (debug)
    +{
    +  // Print something
    +}
    +
  • +
  • When the condition is the literal true or false.
  • +
+

In these cases, it is obvious the code is as intended.

+

How to fix it

+

The conditions should be reviewed to decide whether:

+
    +
  • to update the condition or
  • +
  • to remove the condition.
  • +
+

Code examples

+

Noncompliant code example

+
+' TODO
+
+

Compliant solution

+
+' TODO
+
+

Resources

+ +

Documentation

+ + diff --git a/analyzers/rspec/vbnet/S2583.json b/analyzers/rspec/vbnet/S2583.json new file mode 100644 index 00000000000..c0cf516a4cc --- /dev/null +++ b/analyzers/rspec/vbnet/S2583.json @@ -0,0 +1,33 @@ +{ + "title": "Conditionally executed code should be reachable", + "type": "BUG", + "code": { + "impacts": { + "RELIABILITY": "MEDIUM" + }, + "attribute": "LOGICAL" + }, + "status": "ready", + "remediation": { + "func": "Constant\/Issue", + "constantCost": "15min" + }, + "tags": [ + "cwe", + "unused", + "suspicious", + "pitfall" + ], + "defaultSeverity": "Major", + "ruleSpecification": "RSPEC-2583", + "sqKey": "S2583", + "scope": "All", + "securityStandards": { + "CWE": [ + 489, + 571, + 570 + ] + }, + "quickfix": "targeted" +} diff --git a/analyzers/rspec/vbnet/S2589.html b/analyzers/rspec/vbnet/S2589.html new file mode 100644 index 00000000000..20919778e85 --- /dev/null +++ b/analyzers/rspec/vbnet/S2589.html @@ -0,0 +1,59 @@ +

Why is this an issue?

+

An operand of a boolean expression that never changes the result of the expression might not match the programmer’s intent and can lead to +unexpected behavior and potential bugs.

+
+var a = true;
+if (a)
+{
+    DoSomething();
+}
+
+

This also applies to the null +coalescing operator when one of the operands always evaluates to null.

+
+string d = null;
+var v1 = d ?? "value";
+
+

Exceptions

+

This rule will not raise an issue in either of these cases:

+
    +
  • When the condition is a single const bool
    +const bool debug = false;
    +//...
    +if (debug)
    +{
    +  // Print something
    +}
    +
  • +
  • When the condition is the literal true or false.
  • +
+

In these cases, it is obvious the code is as intended.

+

How to fix it

+

The conditions should be reviewed to decide whether:

+
    +
  • to update the unnecessary operand
  • +
  • to remove the unnecessary operand
  • +
+

Code examples

+

Noncompliant code example

+
+' To be updated
+
+

Compliant solution

+
+' To be updated
+----
+
+

Resources

+

Documentation

+ + diff --git a/analyzers/rspec/vbnet/S2589.json b/analyzers/rspec/vbnet/S2589.json new file mode 100644 index 00000000000..3b655f4974f --- /dev/null +++ b/analyzers/rspec/vbnet/S2589.json @@ -0,0 +1,32 @@ +{ + "title": "Boolean expressions should not be gratuitous", + "type": "CODE_SMELL", + "code": { + "impacts": { + "MAINTAINABILITY": "MEDIUM" + }, + "attribute": "LOGICAL" + }, + "status": "ready", + "remediation": { + "func": "Constant\/Issue", + "constantCost": "10min" + }, + "tags": [ + "cwe", + "suspicious", + "redundant" + ], + "defaultSeverity": "Major", + "ruleSpecification": "RSPEC-2589", + "sqKey": "S2589", + "scope": "All", + "securityStandards": { + "CWE": [ + 489, + 571, + 570 + ] + }, + "quickfix": "unknown" +} diff --git a/analyzers/rspec/vbnet/Sonar_way_profile.json b/analyzers/rspec/vbnet/Sonar_way_profile.json index b31d79ea262..c8c73e8f87f 100644 --- a/analyzers/rspec/vbnet/Sonar_way_profile.json +++ b/analyzers/rspec/vbnet/Sonar_way_profile.json @@ -68,6 +68,8 @@ "S2387", "S2437", "S2551", + "S2583", + "S2589", "S2612", "S2692", "S2737", From 5d07f9b025dab7df438758f95745ecbac974aba8 Mon Sep 17 00:00:00 2001 From: mary-georgiou-sonarsource Date: Thu, 10 Aug 2023 09:32:26 +0200 Subject: [PATCH 04/20] Change class name in UTs to be clearer --- .../Roslyn/ConditionEvaluatesToConstant.CSharp9.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.CSharp9.cs b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.CSharp9.cs index 3f9e4b3c9ec..42cce4b0c0c 100644 --- a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.CSharp9.cs +++ b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.CSharp9.cs @@ -3,7 +3,7 @@ namespace Tests.Diagnostics { - public class CSharp8 + public class Patterns { void IsPattern() { From b7fa219a6e5cde1dc5d0da1a26bdbb5449ee5cf1 Mon Sep 17 00:00:00 2001 From: mary-georgiou-sonarsource Date: Thu, 10 Aug 2023 09:41:40 +0200 Subject: [PATCH 05/20] Fix after rebase --- .../Roslyn/ConditionEvaluatesToConstant.cs | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/analyzers/src/SonarAnalyzer.VisualBasic/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.cs b/analyzers/src/SonarAnalyzer.VisualBasic/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.cs index 54c9fbd7b25..96d6770827e 100644 --- a/analyzers/src/SonarAnalyzer.VisualBasic/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.cs +++ b/analyzers/src/SonarAnalyzer.VisualBasic/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.cs @@ -29,13 +29,6 @@ public class ConditionEvaluatesToConstant : ConditionEvaluatesToConstantBase protected override DiagnosticDescriptor Rule2589 => S2589; public override bool ShouldExecute() => true; - protected override bool IsConditionalAccessExpression(SyntaxNode syntax) => - syntax.Parent is ConditionalAccessExpressionSyntax conditional && conditional.Expression == syntax; - - protected override bool IsForLoopIncrementor(SyntaxNode syntax) => false; // Is is possible to have a boolean in a for loop in vb.net? - protected override bool IsLeftCoalesceExpression(SyntaxNode syntax) => - syntax.Parent is BinaryConditionalExpressionSyntax { } binary - && binary.FirstExpression == syntax; - protected override bool IsUsing(SyntaxNode syntax) => - syntax.IsKind(SyntaxKind.VariableDeclarator) && syntax.Parent.IsKind(SyntaxKind.UsingStatement); + protected override bool IsInsideUsingDeclaration(SyntaxNode node) => + node.IsKind(SyntaxKind.VariableDeclarator) && node.Parent.IsKind(SyntaxKind.UsingStatement); } From 29904d82ab7352226b46a335b4603c95017f64d4 Mon Sep 17 00:00:00 2001 From: mary-georgiou-sonarsource Date: Thu, 10 Aug 2023 10:32:26 +0200 Subject: [PATCH 06/20] mark UTs with issue location and remove repros already existing in C# uts --- .../ConditionEvaluatesToConstant.VB14.vb | 21 +- .../Roslyn/ConditionEvaluatesToConstant.vb | 252 ------------------ 2 files changed, 12 insertions(+), 261 deletions(-) diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.VB14.vb b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.VB14.vb index d7d673f8474..4f852e6a4ba 100644 --- a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.VB14.vb +++ b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.VB14.vb @@ -3,13 +3,15 @@ Private Sub ConditionalAccessNullPropagation(ByVal o As Object) If o Is Nothing Then - If Equals(o?.ToString(), Nothing) Then ' Noncompliant - ' Secondary@-1 - ' Noncompliant@-2 + If Equals(o?.ToString(), Nothing) Then + ' ^ Noncompliant + ' ^^^^^^^^^^^ Secondary@-1 + ' ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Noncompliant@-2 End If - If o?.GetHashCode() Is Nothing Then '' Noncompliant - ' Secondary@-1 - ' Noncompliant@-2 + If o?.GetHashCode() Is Nothing Then + ' ^ Noncompliant + ' ^^^^^^^^^^^^^^ Secondary@-1 + ' ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Noncompliant@-2 End If End If End Sub @@ -27,9 +29,10 @@ Dim m = New MyClassWithEnum() Console.WriteLine(m.myEnum) m = Nothing - If m?.myEnum = MyEnum.One Then ' Noncompliant - ' Secondary@-1 - ' Noncompliant@-2 + If m?.myEnum = MyEnum.One Then + ' ^ Noncompliant + ' ^^^^^^^ Secondary@-1 + ' ^^^^^^^^^^^^^^^^^^^^^^ Noncompliant@-2 End If End Sub diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.vb b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.vb index abdd7d8ea57..49bfeed6c9d 100644 --- a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.vb +++ b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.vb @@ -1421,88 +1421,6 @@ Namespace Tests.Diagnostics End Function End Class - Friend Class Repro2442 - Public Sub Method(ByVal unknown As Boolean) - Dim f = False - Dim t = True - If t Then ' Noncompliant - Else - - End If - - If f Then ' Noncompliant - Else - - End If - - If unknown OrElse t Then ' Noncompliant - Else - - End If - - If unknown AndAlso f Then ' Noncompliant - Else - - End If - - If unknown AndAlso t Then ' Noncompliant - Else - - End If - - If unknown OrElse f Then ' Noncompliant - Else - - End If - - If unknown AndAlso t Then ' Noncompliant - Else - - End If - End Sub - - ''' - ''' A certain combination of condition wrongly considers the else code as dead. - ''' - Private Shared Sub FalsePositive() - FalsePositive2_Sub(True, False, False) - FalsePositive2_Sub(True, False, True) - - FalsePositive2_Sub(True, True, True) - FalsePositive2_Sub(True, True, False) - - FalsePositive2_Sub(False, False, False) - FalsePositive2_Sub(False, False, True) - - FalsePositive2_Sub(False, True, True) - FalsePositive2_Sub(False, True, False) - - ' Outcome. - Console.WriteLine(If(_test1 AndAlso _test2 AndAlso _test3 AndAlso _test4, "Went through each test condition", "Missed at least one test condition")) - End Sub - - Private Shared _test1 As Boolean = False - Private Shared _test2 As Boolean = False - Private Shared _test3 As Boolean = False - Private Shared _test4 As Boolean = False - - Private Shared Sub FalsePositive2_Sub(ByVal testCondition1 As Boolean, ByVal testCondition2 As Boolean, ByVal testCondition3 As Boolean) - Dim condition1 = testCondition1 - Dim condition2 = testCondition2 - Dim condition3 = condition2 AndAlso testCondition3 - - If condition2 AndAlso condition3 AndAlso condition1 Then - _test1 = True - ElseIf Not condition2 AndAlso Not condition1 Then - _test2 = True - ElseIf condition2 AndAlso condition1 AndAlso Not condition3 Then ' Noncompliant - _test3 = True - Else - _test4 = True - End If - End Sub - End Class - Public Class RefArgTest Public Sub Method(ByRef s As String, ByVal x As Integer) End Sub @@ -1544,176 +1462,6 @@ Namespace Tests.Diagnostics End Class - Friend Class ReproForEachFP - Private Shared Function Repro2348(ByVal list As List(Of Integer)) As Boolean - Dim containspositive = False - Dim containsnegative = False - - For Each value In list - If value > 0 Then - containspositive = True - ElseIf value < 0 Then - containsnegative = True - End If - Next - - Return containspositive AndAlso Not containsnegative ' Compliant - End Function - - Private Shared Sub Repro1187_1() - Dim do1 = False - Dim do2 = False - Dim items = New Integer() {1, 2, 3} - For Each item In items - Select Case item - Case 1 - do1 = True - Case 2 - do2 = True - End Select - Next - - If do1 AndAlso do2 Then ' Noncompliant: This repro is badly written. This is a TP. You can find the FP below. - Throw New InvalidOperationException() ' Secondary - End If - End Sub - - Private Shared Sub Repro1187_1_Fixed(ByVal items As Integer()) - Dim do1 = False - Dim do2 = False - For Each item In items - Select Case item - Case 1 - do1 = True - Case 2 - do2 = True - End Select - Next - - If do1 AndAlso do2 Then ' Noncompliant FP - Throw New InvalidOperationException() ' Secondary FP - End If - End Sub - - Private Shared Sub Repro1187_2(ByVal elementGroup As List(Of Integer)) - Dim startDoingSomething = False - Dim a = 0 - - For Each element In elementGroup - If Not startDoingSomething Then ' Compliant - If element > 3 Then - startDoingSomething = True - End If - Else - a += 1 - End If - Next - End Sub - - Private Shared Function Repro1160(ByVal files As String()) As Boolean - Dim anyPathRooted = False - Dim allPathsRooted = True - For Each file In files - If Path.IsPathRooted(file) Then - anyPathRooted = True - Else - allPathsRooted = False - End If - Next - If anyPathRooted AndAlso Not allPathsRooted Then ' Noncompliant FP - Throw New InvalidOperationException("Paths must be all rooted or all unrooted") ' Secondary FP - End If - Return allPathsRooted - End Function - - Private Shared Function ForEachLoop(ByVal items As Integer()) As Boolean - Dim bool1 = False - Dim bool2 = False - - For Each item In items - If item > 0 Then - bool1 = True - ElseIf item < 0 Then - bool2 = True - End If - Next - - If bool1 AndAlso bool2 Then ' Noncompliant FP - Throw New InvalidOperationException() ' Secondary FP - End If - - Return bool1 AndAlso Not bool2 ' Compliant - End Function - - Private Shared Function ForEachLoop2(ByVal items As Integer()) As Boolean - Dim bool1 = False - Dim bool2 = False - -BeforeLoop: - - For Each item1 In items - For Each item2 In items - For Each item3 In items - For Each item4 In items - If item1 > 0 Then - bool1 = True - ElseIf item2 < 0 Then - bool2 = True - End If - Next - Next - Next - Next - - If bool1 AndAlso bool2 Then ' Noncompliant FP FIX - GoTo BeforeLoop - End If - Return False - End Function - - Private Shared Function LoopIterationLimitation(ByVal items As Integer()) As Boolean - Dim bool1 = False - Dim bool2 = False - Dim bool3 = False - - For Each item1 In items - If bool2 Then ' Noncompliant - FP because symbolic execution stops at the third iteration of loop - bool3 = True ' Secondary FP - End If - If bool1 Then - bool2 = True - End If - If item1 > 1 Then - bool1 = True - End If - - Next - Return bool3 - End Function - End Class - - Public Class GeneratorFunctions - Private generate As Boolean - - Public Sub [Stop]() - generate = False - End Sub - - Public Iterator Function Repro_1295() As IEnumerable(Of Integer) - generate = True - While generate ' Noncompliant FP: 'generate' field can potentially be changed inside the loop where this generator is used - Yield 0 - End While - End Function - - Public Iterator Function FalseNegative() As IEnumerable(Of Integer) - Dim myVariable = True - While myVariable ' Noncompliant: myVariable will never change after initialization - Yield 0 - End While - End Function - End Class - Public Class StringComparision Public Sub Method(ByVal parameterString As String) Dim emptyString1 = "" From ac8ca0d1fe96c74c67f2675e6f40bd72db56a7f5 Mon Sep 17 00:00:00 2001 From: mary-georgiou-sonarsource Date: Thu, 10 Aug 2023 11:42:42 +0200 Subject: [PATCH 07/20] Add shouldexecute, tests for shouldExecute + small fixes --- .../Roslyn/ConditionEvaluatesToConstant.cs | 36 +++++- .../ConditionEvaluatesToConstant.VB14.vb | 105 +++++++++++++++++- .../Roslyn/ConditionEvaluatesToConstant.vb | 19 +--- 3 files changed, 145 insertions(+), 15 deletions(-) diff --git a/analyzers/src/SonarAnalyzer.VisualBasic/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.cs b/analyzers/src/SonarAnalyzer.VisualBasic/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.cs index 96d6770827e..15823297bd0 100644 --- a/analyzers/src/SonarAnalyzer.VisualBasic/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.cs +++ b/analyzers/src/SonarAnalyzer.VisualBasic/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.cs @@ -18,6 +18,8 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +using StyleCop.Analyzers.Lightup; + namespace SonarAnalyzer.SymbolicExecution.Roslyn.RuleChecks.VisualBasic; public class ConditionEvaluatesToConstant : ConditionEvaluatesToConstantBase @@ -28,7 +30,39 @@ public class ConditionEvaluatesToConstant : ConditionEvaluatesToConstantBase protected override DiagnosticDescriptor Rule2583 => S2583; protected override DiagnosticDescriptor Rule2589 => S2589; - public override bool ShouldExecute() => true; + public override bool ShouldExecute() + { + var walker = new SyntaxKindWalker(); + walker.SafeVisit(Node); + return walker.ContainsCondition; + } + + private sealed class SyntaxKindWalker : SafeVisualBasicSyntaxWalker + { + public bool ContainsCondition { get; private set; } + public override void Visit(SyntaxNode node) + { + if (!ContainsCondition) + { + ContainsCondition = node.IsAnyKind( + SyntaxKind.AndAlsoExpression, + SyntaxKind.AndExpression, + SyntaxKind.BinaryConditionalExpression, + SyntaxKind.ConditionalAccessExpression, + SyntaxKind.DoWhileStatement, + SyntaxKind.DoUntilStatement, + SyntaxKind.SelectStatement, + SyntaxKind.SimpleDoStatement, + SyntaxKind.TernaryConditionalExpression, + SyntaxKind.IfStatement, + SyntaxKind.OrExpression, + SyntaxKind.OrElseExpression, + SyntaxKind.WhileStatement); + + base.Visit(node); + } + } + } protected override bool IsInsideUsingDeclaration(SyntaxNode node) => node.IsKind(SyntaxKind.VariableDeclarator) && node.Parent.IsKind(SyntaxKind.UsingStatement); } diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.VB14.vb b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.VB14.vb index 4f852e6a4ba..7a806c5c756 100644 --- a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.VB14.vb +++ b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.VB14.vb @@ -1,4 +1,6 @@ -Namespace Tests.Diagnostics +Imports System + +Namespace Tests.Diagnostics Public Class VB14 Private Sub ConditionalAccessNullPropagation(ByVal o As Object) @@ -205,4 +207,105 @@ End Sub End Class End Class + + Class ShouldExecute + + Public Sub AndAlsoExpression() + Dim c1 = True + If c1 AndAlso c1 Then ' Noncompliant + ' Noncompliant@-1 + Console.WriteLine("Always True") + End If + End Sub + + Public Sub AndExpression() + Dim c1 = True + If c1 And c1 Then ' Noncompliant + Console.WriteLine("Always True") + End If + End Sub + + Public Sub TernaryConditionalExpression() + Dim c1 = True + Dim x = If(c1, c1, c1) ' Noncompliant + ' Secondary@-1 + End Sub + + Public Shared Sub ConditionalAccessExpression() + Dim sObj = Nothing + Dim x = sObj?.str?.Length > 2 ' Noncompliant + ' Secondary@-1 + End Sub + + Public Sub DoLoopUntilStatement() + Dim c1 = false + Do + Console.WriteLine("") + Loop Until c1 ' Noncompliant + End Sub + + Public Sub DoLoopWhileStatement() + Dim c1 = True + Do + Console.WriteLine("") + Loop While c1 ' Noncompliant + End Sub + + Public Sub DoUntilStatement() + Dim c1 = False + Do Until c1 ' Noncompliant + Console.WriteLine("") + Loop + End Sub + + Public Sub DoWhileStatement() + Dim c1 = True + Do While c1 ' Noncompliant + Console.WriteLine("") + Loop + End Sub + + Public Sub IfStatement() + Dim c1 = True + If c1 ' Noncompliant + Console.WriteLine("") + End If + End Sub + + Public Sub OrAlsoExpression() + Dim c1 = True + If c1 OrElse False Then ' Noncompliant + ' Secondary@-1 + Console.WriteLine("Always True") + End If + End Sub + + Public Sub OrExpression() + Dim c1 = True + If c1 Or False Then ' Noncompliant + Console.WriteLine("Always True") + End If + End Sub + + Public Sub WhileStatement() + Dim c1 = True + While c1 ' Noncompliant + Console.WriteLine("") + End While + End Sub + + Public Sub SelectStatement() + Dim i = 10 + Dim b = True + Select Case i + Case 1 ' Noncompliant + b = False ' Secondary + End Select + End Sub + + End Class + End Namespace + + + diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.vb b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.vb index 49bfeed6c9d..de13a2ef348 100644 --- a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.vb +++ b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.vb @@ -254,7 +254,7 @@ Namespace Tests.Diagnostics End While End Sub - Public Sub Method_Switch() + Public Sub Method_Select() Dim i = 10 Dim b = True Select Case i @@ -267,7 +267,7 @@ Namespace Tests.Diagnostics End If End Sub - Public Sub Method_Switch_Learn(ByVal cond As Boolean) + Public Sub Method_Select_Learn(ByVal cond As Boolean) Select Case cond Case True If cond Then ' Noncompliant @@ -1427,7 +1427,7 @@ Namespace Tests.Diagnostics Public Sub Method1(ByVal infixes As String) If Not Equals(infixes, Nothing) Then Method(infixes, infixes.Length) - If Equals(infixes, Nothing) Then ' Noncompliant FP: ref + If Equals(infixes, Nothing) Then ' Noncompliant FP: ref Return End If End If @@ -1445,7 +1445,7 @@ Namespace Tests.Diagnostics Public Sub Method3(ByVal infixes As String) If Equals(infixes, Nothing) Then Method(infixes, infixes.Length) - If Equals(infixes, Nothing) Then ' Noncompliant FP: ref + If Equals(infixes, Nothing) Then ' Noncompliant FP: ref Return End If End If @@ -1515,7 +1515,7 @@ Namespace Tests.Diagnostics End If - If Equals(fullStringa1, Nothing) Then ' Noncompliant + If Equals(fullStringa1, Nothing) Then ' Noncompliant End If @@ -1723,17 +1723,10 @@ Namespace Tests.Diagnostics Public ReadOnly Property Message As Object Get - Return CSharpImpl.__Assign(messageField, If(messageField, New Object())) + Return If(messageField Is Nothing, New Object(), messageField) End Get End Property - Private Class CSharpImpl - - Shared Function __Assign(Of T)(ByRef target As T, value As T) As T - target = value - Return value - End Function - End Class End Class End Class From a88295c0d36ab0161e7c1a193e03adc1b59c024f Mon Sep 17 00:00:00 2001 From: mary-georgiou-sonarsource Date: Thu, 10 Aug 2023 14:08:31 +0200 Subject: [PATCH 08/20] Revert "Reworked secondary locations" This reverts commit 4137efaa629d837a0d36e609c45473d81a021e28. --- .../Roslyn/ConditionEvaluatesToConstant.cs | 17 ++++- .../ConditionEvaluatesToConstantBase.cs | 67 +++++++++---------- .../Roslyn/SymbolicRuleCheck.cs | 7 +- .../ConditionEvaluatesToConstant.CSharp8.cs | 15 ++--- .../Roslyn/ConditionEvaluatesToConstant.cs | 15 ++--- 5 files changed, 60 insertions(+), 61 deletions(-) diff --git a/analyzers/src/SonarAnalyzer.CSharp/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.cs b/analyzers/src/SonarAnalyzer.CSharp/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.cs index b0ebbf868f6..9ccf666951c 100644 --- a/analyzers/src/SonarAnalyzer.CSharp/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.cs +++ b/analyzers/src/SonarAnalyzer.CSharp/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.cs @@ -59,7 +59,18 @@ public override void Visit(SyntaxNode node) } } - protected override bool IsInsideUsingDeclaration(SyntaxNode node) => - (node.IsKind(SyntaxKind.VariableDeclaration) && node.Parent.IsKind(SyntaxKind.UsingStatement)) - || (node is LocalDeclarationStatementSyntax local && local.UsingKeyword().IsKind(SyntaxKind.UsingKeyword)); + protected override bool IsLeftCoalesceExpression(SyntaxNode syntax) => + syntax.Parent is BinaryExpressionSyntax { } binary + && binary.OperatorToken.IsKind(SyntaxKind.QuestionQuestionToken) + && binary.Left == syntax; + + protected override bool IsConditionalAccessExpression(SyntaxNode syntax) => + syntax.Parent is ConditionalAccessExpressionSyntax conditional && conditional.Expression == syntax; + + protected override bool IsForLoopIncrementor(SyntaxNode syntax) => + syntax.Parent is ForStatementSyntax forStatement && forStatement.Incrementors.Contains(syntax); + + protected override bool IsUsing(SyntaxNode syntax) => + (syntax.IsKind(SyntaxKind.VariableDeclaration) && syntax.Parent.IsKind(SyntaxKind.UsingStatement)) + || (syntax is LocalDeclarationStatementSyntax local && local.UsingKeyword().IsKind(SyntaxKind.UsingKeyword)); } diff --git a/analyzers/src/SonarAnalyzer.Common/SymbolicExecution/Roslyn/RuleChecks/ConditionEvaluatesToConstantBase.cs b/analyzers/src/SonarAnalyzer.Common/SymbolicExecution/Roslyn/RuleChecks/ConditionEvaluatesToConstantBase.cs index fd6b6220be3..df3b3f0918b 100644 --- a/analyzers/src/SonarAnalyzer.Common/SymbolicExecution/Roslyn/RuleChecks/ConditionEvaluatesToConstantBase.cs +++ b/analyzers/src/SonarAnalyzer.Common/SymbolicExecution/Roslyn/RuleChecks/ConditionEvaluatesToConstantBase.cs @@ -38,9 +38,12 @@ public abstract class ConditionEvaluatesToConstantBase : SymbolicRuleCheck private readonly Dictionary trueOperations = new(); private readonly Dictionary falseOperations = new(); - private readonly List reached = new(); + private readonly HashSet reached = new(); - protected abstract bool IsInsideUsingDeclaration(SyntaxNode node); + protected abstract bool IsLeftCoalesceExpression(SyntaxNode syntax); + protected abstract bool IsConditionalAccessExpression(SyntaxNode syntax); + protected abstract bool IsForLoopIncrementor(SyntaxNode syntax); + protected abstract bool IsUsing(SyntaxNode syntax); public override ProgramState[] PreProcess(SymbolicContext context) { @@ -52,7 +55,7 @@ public override ProgramState ConditionEvaluated(SymbolicContext context) { var operation = context.Operation.Instance; if (operation.Kind is not OperationKindEx.Literal - && !operation.Syntax.Ancestors().Any(IsInsideUsingDeclaration) + && !operation.Syntax.Ancestors().Any(IsUsing) && operation.TrackedSymbol(context.State) is not IFieldSymbol { IsConst: true } && !IsDiscardPattern(operation)) { @@ -90,54 +93,53 @@ public override void ExecutionCompleted() private void ReportIssue(IOperation operation, BasicBlock block, bool conditionValue) { var issueMessage = operation.Kind == OperationKindEx.IsNull ? MessageNull : string.Format(MessageBool, conditionValue); - var syntax = ToBranchValueCondition(operation.Syntax); - var secondaryLocations = SecondaryLocations(block, conditionValue, syntax); + var secondaryLocations = SecondaryLocations(block, conditionValue); if (secondaryLocations.Any()) { - ReportIssue(Rule2583, syntax, secondaryLocations, issueMessage, S2583MessageSuffix); + ReportIssue(Rule2583, operation, secondaryLocations, issueMessage, S2583MessageSuffix); } else { - ReportIssue(Rule2589, syntax, null, issueMessage, string.Empty); + ReportIssue(Rule2589, operation, null, issueMessage, string.Empty); } } - private List SecondaryLocations(BasicBlock block, bool conditionValue, SyntaxNode conditionSyntax) + private List SecondaryLocations(BasicBlock block, bool conditionValue) { List locations = new(); - var unreachable = UnreachableOperations(block, conditionValue).ToHashSet(); - var currentStart = conditionSyntax.Span.End; - var reachedNodes = reached.Select(x => x.Syntax).Where(x => x.SpanStart > conditionSyntax.Span.End).OrderBy(x => x.SpanStart); - - foreach (var reachedNode in reachedNodes) + IOperation currentStart = null; + IOperation currentEnd = null; + var unreachable = UnreachableOperations(block, conditionValue).Where(x => !IsIgnoredLocation(x.Syntax)).ToHashSet(); + foreach (var operation in unreachable.Concat(reached).OrderBy(x => x.Syntax.SpanStart)) { - if (AddLocation(reachedNode.SpanStart)) + if (unreachable.Contains(operation)) + { + currentStart ??= operation; + currentEnd = operation; + } + else { - currentStart = reachedNode.Span.End; + AddCurrent(); } } - AddLocation(int.MaxValue); + AddCurrent(); return locations; - bool AddLocation(int end) + void AddCurrent() { - var nodes = unreachable.Where(x => x.SpanStart > currentStart && x.Span.End < end); - if (nodes.Any()) + if (currentStart is not null) { - var first = nodes.OrderBy(x => x.SpanStart).First(); - var last = nodes.OrderBy(x => x.Span.End).Last(); - locations.Add(first.CreateLocation(last)); - return true; + locations.Add(currentStart.Syntax.CreateLocation(currentEnd.Syntax)); + currentStart = null; } - return false; } } - private IEnumerable UnreachableOperations(BasicBlock block, bool conditionValue) + private IEnumerable UnreachableOperations(BasicBlock block, bool conditionValue) { if (block.SuccessorBlocks.Distinct().Count() != 2) { - return Enumerable.Empty(); + return Enumerable.Empty(); } HashSet reachable = new() { block }; HashSet unreachable = new(); @@ -145,11 +147,7 @@ private IEnumerable UnreachableOperations(BasicBlock block, bool con var conditionalIsRechable = (block.ConditionKind == ControlFlowConditionKind.WhenTrue) == conditionValue; Traverse(conditionalIsRechable ? block.ConditionalSuccessor : block.FallThroughSuccessor, reachable, new List()); Traverse(conditionalIsRechable ? block.FallThroughSuccessor : block.ConditionalSuccessor, unreachable, reachable); - return unreachable - .SelectMany(x => x.OperationsAndBranchValue) - .Except(reached) - .SelectMany(x => x.DescendantsAndSelf().Select(x => x.Syntax)) - .ToList(); + return unreachable.SelectMany(x => x.OperationsAndBranchValue).Except(reached); static void Traverse(ControlFlowBranch branch, HashSet result, ICollection excluded) { @@ -170,7 +168,8 @@ static void Traverse(ControlFlowBranch branch, HashSet result, IColl } } - // For SwitchExpressionArms like `true => 5` we are only interested in the left part (`true`). - private static SyntaxNode ToBranchValueCondition(SyntaxNode syntax) => - syntax.IsKind(SyntaxKindEx.SwitchExpressionArm) ? ((SwitchExpressionArmSyntaxWrapper)syntax).Pattern : syntax; + private bool IsIgnoredLocation(SyntaxNode x) => + IsForLoopIncrementor(x) + || IsConditionalAccessExpression(x) + || IsLeftCoalesceExpression(x); } diff --git a/analyzers/src/SonarAnalyzer.Common/SymbolicExecution/Roslyn/SymbolicRuleCheck.cs b/analyzers/src/SonarAnalyzer.Common/SymbolicExecution/Roslyn/SymbolicRuleCheck.cs index b867c9bbcc5..f13eb966204 100644 --- a/analyzers/src/SonarAnalyzer.Common/SymbolicExecution/Roslyn/SymbolicRuleCheck.cs +++ b/analyzers/src/SonarAnalyzer.Common/SymbolicExecution/Roslyn/SymbolicRuleCheck.cs @@ -62,12 +62,9 @@ protected void ReportIssue(IOperation operation, IEnumerable additiona ReportIssue(Rule, operation, additionalLocations, messageArgs); } - protected void ReportIssue(DiagnosticDescriptor rule, IOperation operation, IEnumerable additionalLocations, params object[] messageArgs) => - ReportIssue(rule, operation.Syntax, additionalLocations, messageArgs); - - protected void ReportIssue(DiagnosticDescriptor rule, SyntaxNode syntax, IEnumerable additionalLocations, params object[] messageArgs) + protected void ReportIssue(DiagnosticDescriptor rule, IOperation operation, IEnumerable additionalLocations, params object[] messageArgs) { - var location = syntax.GetLocation(); + var location = operation.Syntax.GetLocation(); if (reportedDiagnostics.Add(location)) { context.ReportIssue(Diagnostic.Create(rule, location, additionalLocations, messageArgs)); diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.CSharp8.cs b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.CSharp8.cs index b5cf878241b..86d8a9b665c 100644 --- a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.CSharp8.cs +++ b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.CSharp8.cs @@ -23,11 +23,10 @@ public class CSharp8 int SwitchExpression() { var a = false; - return a switch + return a switch // Secondary FP { - true => 0, - // ^^^^ Noncompliant - // ^ Secondary@-1 + true => 0, // Noncompliant: true branch is always false + // Secondary@-1 false => 1 // Noncompliant: false branch is always true }; } @@ -235,9 +234,8 @@ void NullCoalesceAssignment_Useless(string a, string b, string c, string d) //Left operand: Values notNull, notEmpty and ret are known to be not-null ret = notNull; - ret ??= a; - // ^^^ Noncompliant - // ^ Secondary@-1 + ret ??= a; // Noncompliant + // Secondary@-1 ret = notNull; ret = "Lorem " + (ret ??= a) + " ipsum"; // Noncompliant @@ -257,6 +255,7 @@ void NullCoalesceAssignment_Useless(string a, string b, string c, string d) ret = null; ret = "Lorem " + (ret ??= a) + " ipsum"; // Noncompliant + // Secondary@-1 //Right operand: isNull is known to be null, therefore ?? is useless ret = a; @@ -461,7 +460,7 @@ void IfStatement() void LogicalAndExpression() { - bool a = false; + bool a = true; var b = a && true; // Noncompliant // Secondary@-1 } diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.cs b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.cs index 57c96418abd..5f1b73b610f 100644 --- a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.cs +++ b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.cs @@ -64,10 +64,9 @@ public void NotExecutedLoops(object o1, object o2, object o3) // ^^ for (int i = 0; c3; i++) // Noncompliant {{Change this condition so that it does not always evaluate to 'False'. Some code paths are unreachable.}} - // Secondary@-1 ^33#239 + // ^^ { - if (o3 != null) - // secondary location starts at incrementor and ends at the end of the above line + if (o3 != null) // Secondary break; } } @@ -177,13 +176,6 @@ public void Foo7(bool a, bool b) } } - public void Foo8(bool a, bool b) - { - a = true; - _ = a && b; - // ^ Noncompliant - } - void Pointer(int* a) // Error [CS0214] { if (a != null) // Error [CS0214] @@ -1925,7 +1917,7 @@ public static void NonCompliant6() S sObj = null; if (sObj?.str?.Length > 2) // ^^^^ Noncompliant - // ^^^^^^^^^^^^ Secondary@-1 + // ^^^^^^^ Secondary@-1 // ^^^^^^^^^^^^^^^^^^^^^ Noncompliant@-2 { Console.WriteLine("a"); // Secondary @@ -2800,6 +2792,7 @@ void NullCoalesce_Useless(string a, string b, string c, string d) ret = null ?? a; // Noncompliant ret = isNull ?? a; // Noncompliant ret = ((isNull)) ?? a; // Noncompliant + // Secondary@-1 FP ret = "Lorem " + (isNull ?? a) + " ipsum"; // Noncompliant //Right operand: isNull is known to be null, therefore ?? is useless From 1198475137b027a74081e6eae3c7f770a5e3fcc1 Mon Sep 17 00:00:00 2001 From: mary-georgiou-sonarsource Date: Thu, 10 Aug 2023 14:12:42 +0200 Subject: [PATCH 09/20] revert secondary locations changes --- .../Roslyn/ConditionEvaluatesToConstant.cs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/analyzers/src/SonarAnalyzer.VisualBasic/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.cs b/analyzers/src/SonarAnalyzer.VisualBasic/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.cs index 15823297bd0..71bd7bde289 100644 --- a/analyzers/src/SonarAnalyzer.VisualBasic/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.cs +++ b/analyzers/src/SonarAnalyzer.VisualBasic/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.cs @@ -63,6 +63,15 @@ public override void Visit(SyntaxNode node) } } } - protected override bool IsInsideUsingDeclaration(SyntaxNode node) => - node.IsKind(SyntaxKind.VariableDeclarator) && node.Parent.IsKind(SyntaxKind.UsingStatement); + protected override bool IsConditionalAccessExpression(SyntaxNode syntax) => + syntax.Parent is ConditionalAccessExpressionSyntax conditional && conditional.Expression == syntax; + + protected override bool IsForLoopIncrementor(SyntaxNode syntax) => false; // Is is possible to have a boolean in a for loop in vb.net? + + protected override bool IsLeftCoalesceExpression(SyntaxNode syntax) => + syntax.Parent is BinaryConditionalExpressionSyntax { } binary + && binary.FirstExpression == syntax; + + protected override bool IsUsing(SyntaxNode syntax) => + syntax.IsKind(SyntaxKind.VariableDeclarator) && syntax.Parent.IsKind(SyntaxKind.UsingStatement); } From 38574921659dc724c81f80a4ed74cbee6ccfab3b Mon Sep 17 00:00:00 2001 From: mary-georgiou-sonarsource Date: Thu, 10 Aug 2023 14:15:58 +0200 Subject: [PATCH 10/20] nitpicks --- .../Roslyn/ConditionEvaluatesToConstant.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/analyzers/src/SonarAnalyzer.VisualBasic/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.cs b/analyzers/src/SonarAnalyzer.VisualBasic/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.cs index 71bd7bde289..f98c7970963 100644 --- a/analyzers/src/SonarAnalyzer.VisualBasic/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.cs +++ b/analyzers/src/SonarAnalyzer.VisualBasic/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.cs @@ -51,10 +51,10 @@ public override void Visit(SyntaxNode node) SyntaxKind.ConditionalAccessExpression, SyntaxKind.DoWhileStatement, SyntaxKind.DoUntilStatement, + SyntaxKind.IfStatement, SyntaxKind.SelectStatement, SyntaxKind.SimpleDoStatement, SyntaxKind.TernaryConditionalExpression, - SyntaxKind.IfStatement, SyntaxKind.OrExpression, SyntaxKind.OrElseExpression, SyntaxKind.WhileStatement); @@ -66,7 +66,10 @@ public override void Visit(SyntaxNode node) protected override bool IsConditionalAccessExpression(SyntaxNode syntax) => syntax.Parent is ConditionalAccessExpressionSyntax conditional && conditional.Expression == syntax; - protected override bool IsForLoopIncrementor(SyntaxNode syntax) => false; // Is is possible to have a boolean in a for loop in vb.net? + // For loop in VB.NET does dont have conditions in for loops. + // see https://learn.microsoft.com/en-us/dotnet/visual-basic/language-reference/statements/for-each-next-statement and + // https://learn.microsoft.com/en-us/dotnet/visual-basic/language-reference/statements/for-next-statement + protected override bool IsForLoopIncrementor(SyntaxNode syntax) => false; protected override bool IsLeftCoalesceExpression(SyntaxNode syntax) => syntax.Parent is BinaryConditionalExpressionSyntax { } binary From 6195d0e71ed086b5cb10392fe0b0e8a1f53a2937 Mon Sep 17 00:00:00 2001 From: mary-georgiou-sonarsource Date: Thu, 10 Aug 2023 15:13:43 +0200 Subject: [PATCH 11/20] fix UTs --- .../PackagingTests/RuleTypeMappingVB.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/PackagingTests/RuleTypeMappingVB.cs b/analyzers/tests/SonarAnalyzer.UnitTest/PackagingTests/RuleTypeMappingVB.cs index 053882cb24d..f465745e4f8 100644 --- a/analyzers/tests/SonarAnalyzer.UnitTest/PackagingTests/RuleTypeMappingVB.cs +++ b/analyzers/tests/SonarAnalyzer.UnitTest/PackagingTests/RuleTypeMappingVB.cs @@ -2507,13 +2507,13 @@ internal static class RuleTypeMappingVB // ["S2580"], // ["S2581"], // ["S2582"], - // ["S2583"], + ["S2583"] = "BUG", // ["S2584"], // ["S2585"], // ["S2586"], // ["S2587"], // ["S2588"], - // ["S2589"], + ["S2589"] = "CODE_SMELL", // ["S2590"], // ["S2591"], // ["S2592"], From 1bc0abf82d82290d14147b0fcdd966a3d6bbae3a Mon Sep 17 00:00:00 2001 From: mary-georgiou-sonarsource Date: Thu, 10 Aug 2023 15:22:37 +0200 Subject: [PATCH 12/20] update ITs --- ...AB-AF12-4012-B945-284C2448DC81}-S2589.json | 17 ++ ...5E-C6AE-4D2D-A9DD-B6EFD19A4279}-S2583.json | 28 ++ ...5E-C6AE-4D2D-A9DD-B6EFD19A4279}-S2589.json | 95 +++++++ ...C2-EB9C-4090-B9A9-B703DF00CCEF}-S2589.json | 30 +++ ...61-E2C2-4982-9536-63AEF0A98AAA}-S2589.json | 17 ++ ...0E-DD76-4F4D-8250-8598140F828B}-S2583.json | 37 +++ ...0E-DD76-4F4D-8250-8598140F828B}-S2589.json | 43 +++ ...31-1F7B-4637-9B3A-806988DE50CF}-S2583.json | 244 ++++++++++++++++++ ...31-1F7B-4637-9B3A-806988DE50CF}-S2589.json | 43 +++ 9 files changed, 554 insertions(+) create mode 100644 analyzers/its/expected/Ember-MM/Ember Media Manager-{9B57D3AB-AF12-4012-B945-284C2448DC81}-S2589.json create mode 100644 analyzers/its/expected/Ember-MM/EmberAPI-{208AA35E-C6AE-4D2D-A9DD-B6EFD19A4279}-S2583.json create mode 100644 analyzers/its/expected/Ember-MM/EmberAPI-{208AA35E-C6AE-4D2D-A9DD-B6EFD19A4279}-S2589.json create mode 100644 analyzers/its/expected/Ember-MM/generic.EmberCore.MovieExporter-{B0BDF9C2-EB9C-4090-B9A9-B703DF00CCEF}-S2589.json create mode 100644 analyzers/its/expected/Ember-MM/generic.EmberCore.XBMC-{6FE33C61-E2C2-4982-9536-63AEF0A98AAA}-S2589.json create mode 100644 analyzers/its/expected/Ember-MM/scraper.EmberCore-{EF6A550E-DD76-4F4D-8250-8598140F828B}-S2583.json create mode 100644 analyzers/its/expected/Ember-MM/scraper.EmberCore-{EF6A550E-DD76-4F4D-8250-8598140F828B}-S2589.json create mode 100644 analyzers/its/expected/Ember-MM/scraper.EmberCore.XML-{E567C031-1F7B-4637-9B3A-806988DE50CF}-S2583.json create mode 100644 analyzers/its/expected/Ember-MM/scraper.EmberCore.XML-{E567C031-1F7B-4637-9B3A-806988DE50CF}-S2589.json diff --git a/analyzers/its/expected/Ember-MM/Ember Media Manager-{9B57D3AB-AF12-4012-B945-284C2448DC81}-S2589.json b/analyzers/its/expected/Ember-MM/Ember Media Manager-{9B57D3AB-AF12-4012-B945-284C2448DC81}-S2589.json new file mode 100644 index 00000000000..a774e83fffb --- /dev/null +++ b/analyzers/its/expected/Ember-MM/Ember Media Manager-{9B57D3AB-AF12-4012-B945-284C2448DC81}-S2589.json @@ -0,0 +1,17 @@ +{ +"issues": [ +{ +"id": "S2589", +"message": "Change this condition so that it does not always evaluate to 'True'.", +"location": { +"uri": "https://github.com/SonarSource/sonar-dotnet/blob/master/analyzers/its/sources/Ember-MM/Ember%20Media%20Manager/dlgSettings.vb#L105", +"region": { +"startLine": 105, +"startColumn": 12, +"endLine": 105, +"endColumn": 26 +} +} +} +] +} diff --git a/analyzers/its/expected/Ember-MM/EmberAPI-{208AA35E-C6AE-4D2D-A9DD-B6EFD19A4279}-S2583.json b/analyzers/its/expected/Ember-MM/EmberAPI-{208AA35E-C6AE-4D2D-A9DD-B6EFD19A4279}-S2583.json new file mode 100644 index 00000000000..9c21c355d2f --- /dev/null +++ b/analyzers/its/expected/Ember-MM/EmberAPI-{208AA35E-C6AE-4D2D-A9DD-B6EFD19A4279}-S2583.json @@ -0,0 +1,28 @@ +{ +"issues": [ +{ +"id": "S2583", +"message": "Change this condition so that it does not always evaluate to 'False'. Some code paths are unreachable.", +"location": [ +{ +"uri": "https://github.com/SonarSource/sonar-dotnet/blob/master/analyzers/its/sources/Ember-MM/EmberAPI/clsAPILocalization.vb#L242", +"region": { +"startLine": 242, +"startColumn": 32, +"endLine": 242, +"endColumn": 48 +} +}, +{ +"uri": "https://github.com/SonarSource/sonar-dotnet/blob/master/analyzers/its/sources/Ember-MM/EmberAPI/clsAPILocalization.vb#L245", +"region": { +"startLine": 245, +"startColumn": 29, +"endLine": 245, +"endColumn": 130 +} +} +] +} +] +} diff --git a/analyzers/its/expected/Ember-MM/EmberAPI-{208AA35E-C6AE-4D2D-A9DD-B6EFD19A4279}-S2589.json b/analyzers/its/expected/Ember-MM/EmberAPI-{208AA35E-C6AE-4D2D-A9DD-B6EFD19A4279}-S2589.json new file mode 100644 index 00000000000..2a6b873d11e --- /dev/null +++ b/analyzers/its/expected/Ember-MM/EmberAPI-{208AA35E-C6AE-4D2D-A9DD-B6EFD19A4279}-S2589.json @@ -0,0 +1,95 @@ +{ +"issues": [ +{ +"id": "S2589", +"message": "Change this condition so that it does not always evaluate to 'False'.", +"location": { +"uri": "https://github.com/SonarSource/sonar-dotnet/blob/master/analyzers/its/sources/Ember-MM/EmberAPI/clsAPIHTTP.vb#L275", +"region": { +"startLine": 275, +"startColumn": 66, +"endLine": 275, +"endColumn": 76 +} +} +}, +{ +"id": "S2589", +"message": "Change this condition so that it does not always evaluate to 'False'.", +"location": { +"uri": "https://github.com/SonarSource/sonar-dotnet/blob/master/analyzers/its/sources/Ember-MM/EmberAPI/clsAPIHTTP.vb#L308", +"region": { +"startLine": 308, +"startColumn": 20, +"endLine": 308, +"endColumn": 30 +} +} +}, +{ +"id": "S2589", +"message": "Change this condition so that it does not always evaluate to 'False'.", +"location": { +"uri": "https://github.com/SonarSource/sonar-dotnet/blob/master/analyzers/its/sources/Ember-MM/EmberAPI/clsAPIHTTP.vb#L311", +"region": { +"startLine": 311, +"startColumn": 24, +"endLine": 311, +"endColumn": 34 +} +} +}, +{ +"id": "S2589", +"message": "Change this condition so that it does not always evaluate to 'False'.", +"location": { +"uri": "https://github.com/SonarSource/sonar-dotnet/blob/master/analyzers/its/sources/Ember-MM/EmberAPI/clsAPIHTTP.vb#L314", +"region": { +"startLine": 314, +"startColumn": 28, +"endLine": 314, +"endColumn": 38 +} +} +}, +{ +"id": "S2589", +"message": "Change this condition so that it does not always evaluate to 'False'.", +"location": { +"uri": "https://github.com/SonarSource/sonar-dotnet/blob/master/analyzers/its/sources/Ember-MM/EmberAPI/clsAPINFO.vb#L461", +"region": { +"startLine": 461, +"startColumn": 32, +"endLine": 461, +"endColumn": 49 +} +} +}, +{ +"id": "S2589", +"message": "Change this condition so that it does not always evaluate to 'True'.", +"location": { +"uri": "https://github.com/SonarSource/sonar-dotnet/blob/master/analyzers/its/sources/Ember-MM/EmberAPI/clsAPINFO.vb#L706", +"region": { +"startLine": 706, +"startColumn": 24, +"endLine": 706, +"endColumn": 34 +} +} +}, +{ +"id": "S2589", +"message": "Change this condition so that it does not always evaluate to 'True'.", +"location": { +"uri": "https://github.com/SonarSource/sonar-dotnet/blob/master/analyzers/its/sources/Ember-MM/EmberAPI/clsAPINFO.vb#L978", +"region": { +"startLine": 978, +"startColumn": 20, +"endLine": 978, +"endColumn": 30 +} +} +} +] +} diff --git a/analyzers/its/expected/Ember-MM/generic.EmberCore.MovieExporter-{B0BDF9C2-EB9C-4090-B9A9-B703DF00CCEF}-S2589.json b/analyzers/its/expected/Ember-MM/generic.EmberCore.MovieExporter-{B0BDF9C2-EB9C-4090-B9A9-B703DF00CCEF}-S2589.json new file mode 100644 index 00000000000..d9469e1ef36 --- /dev/null +++ b/analyzers/its/expected/Ember-MM/generic.EmberCore.MovieExporter-{B0BDF9C2-EB9C-4090-B9A9-B703DF00CCEF}-S2589.json @@ -0,0 +1,30 @@ +{ +"issues": [ +{ +"id": "S2589", +"message": "Change this condition so that it does not always evaluate to 'False'.", +"location": { +"uri": "https://github.com/SonarSource/sonar-dotnet/blob/master/analyzers/its/sources/Ember-MM/Addons/generic.EmberCore.MovieExport/dlgExportMovies.vb#L367", +"region": { +"startLine": 367, +"startColumn": 24, +"endLine": 367, +"endColumn": 31 +} +} +}, +{ +"id": "S2589", +"message": "Change this condition so that it does not always evaluate to 'False'.", +"location": { +"uri": "https://github.com/SonarSource/sonar-dotnet/blob/master/analyzers/its/sources/Ember-MM/Addons/generic.EmberCore.MovieExport/dlgExportMovies.vb#L754", +"region": { +"startLine": 754, +"startColumn": 20, +"endLine": 754, +"endColumn": 39 +} +} +} +] +} diff --git a/analyzers/its/expected/Ember-MM/generic.EmberCore.XBMC-{6FE33C61-E2C2-4982-9536-63AEF0A98AAA}-S2589.json b/analyzers/its/expected/Ember-MM/generic.EmberCore.XBMC-{6FE33C61-E2C2-4982-9536-63AEF0A98AAA}-S2589.json new file mode 100644 index 00000000000..7b517d64098 --- /dev/null +++ b/analyzers/its/expected/Ember-MM/generic.EmberCore.XBMC-{6FE33C61-E2C2-4982-9536-63AEF0A98AAA}-S2589.json @@ -0,0 +1,17 @@ +{ +"issues": [ +{ +"id": "S2589", +"message": "Change this condition so that it does not always evaluate to 'True'.", +"location": { +"uri": "https://github.com/SonarSource/sonar-dotnet/blob/master/analyzers/its/sources/Ember-MM/Addons/generic.EmberCore.XBMC/Module.XBMCxCom.vb#L404", +"region": { +"startLine": 404, +"startColumn": 30, +"endLine": 404, +"endColumn": 40 +} +} +} +] +} diff --git a/analyzers/its/expected/Ember-MM/scraper.EmberCore-{EF6A550E-DD76-4F4D-8250-8598140F828B}-S2583.json b/analyzers/its/expected/Ember-MM/scraper.EmberCore-{EF6A550E-DD76-4F4D-8250-8598140F828B}-S2583.json new file mode 100644 index 00000000000..2a8e8ed6d74 --- /dev/null +++ b/analyzers/its/expected/Ember-MM/scraper.EmberCore-{EF6A550E-DD76-4F4D-8250-8598140F828B}-S2583.json @@ -0,0 +1,37 @@ +{ +"issues": [ +{ +"id": "S2583", +"message": "Change this condition so that it does not always evaluate to 'False'. Some code paths are unreachable.", +"location": [ +{ +"uri": "https://github.com/SonarSource/sonar-dotnet/blob/master/analyzers/its/sources/Ember-MM/Addons/scraper.EmberCore/TVScraper/dlgTVImageSelect.vb#L989", +"region": { +"startLine": 989, +"startColumn": 16, +"endLine": 989, +"endColumn": 31 +} +}, +{ +"uri": "https://github.com/SonarSource/sonar-dotnet/blob/master/analyzers/its/sources/Ember-MM/Addons/scraper.EmberCore/TVScraper/dlgTVImageSelect.vb#L989", +"region": { +"startLine": 989, +"startColumn": 43, +"endLine": 989, +"endColumn": 56 +} +}, +{ +"uri": "https://github.com/SonarSource/sonar-dotnet/blob/master/analyzers/its/sources/Ember-MM/Addons/scraper.EmberCore/TVScraper/dlgTVImageSelect.vb#L992", +"region": { +"startLine": 992, +"startColumn": 13, +"endLine": 992, +"endColumn": 58 +} +} +] +} +] +} diff --git a/analyzers/its/expected/Ember-MM/scraper.EmberCore-{EF6A550E-DD76-4F4D-8250-8598140F828B}-S2589.json b/analyzers/its/expected/Ember-MM/scraper.EmberCore-{EF6A550E-DD76-4F4D-8250-8598140F828B}-S2589.json new file mode 100644 index 00000000000..11353f2e979 --- /dev/null +++ b/analyzers/its/expected/Ember-MM/scraper.EmberCore-{EF6A550E-DD76-4F4D-8250-8598140F828B}-S2589.json @@ -0,0 +1,43 @@ +{ +"issues": [ +{ +"id": "S2589", +"message": "Change this condition so that it does not always evaluate to 'False'.", +"location": { +"uri": "https://github.com/SonarSource/sonar-dotnet/blob/master/analyzers/its/sources/Ember-MM/Addons/scraper.EmberCore/TVScraper/clsScrapeTVDB.vb#L674", +"region": { +"startLine": 674, +"startColumn": 44, +"endLine": 674, +"endColumn": 68 +} +} +}, +{ +"id": "S2589", +"message": "Change this condition so that it does not always evaluate to 'False'.", +"location": { +"uri": "https://github.com/SonarSource/sonar-dotnet/blob/master/analyzers/its/sources/Ember-MM/Addons/scraper.EmberCore/TVScraper/clsScrapeTVDB.vb#L694", +"region": { +"startLine": 694, +"startColumn": 40, +"endLine": 694, +"endColumn": 64 +} +} +}, +{ +"id": "S2589", +"message": "Change this condition so that it does not always evaluate to 'False'.", +"location": { +"uri": "https://github.com/SonarSource/sonar-dotnet/blob/master/analyzers/its/sources/Ember-MM/Addons/scraper.EmberCore/TVScraper/clsScrapeTVDB.vb#L715", +"region": { +"startLine": 715, +"startColumn": 48, +"endLine": 715, +"endColumn": 72 +} +} +} +] +} diff --git a/analyzers/its/expected/Ember-MM/scraper.EmberCore.XML-{E567C031-1F7B-4637-9B3A-806988DE50CF}-S2583.json b/analyzers/its/expected/Ember-MM/scraper.EmberCore.XML-{E567C031-1F7B-4637-9B3A-806988DE50CF}-S2583.json new file mode 100644 index 00000000000..bf9c75c30b8 --- /dev/null +++ b/analyzers/its/expected/Ember-MM/scraper.EmberCore.XML-{E567C031-1F7B-4637-9B3A-806988DE50CF}-S2583.json @@ -0,0 +1,244 @@ +{ +"issues": [ +{ +"id": "S2583", +"message": "Change this condition so that it does not always evaluate to 'True'. Some code paths are unreachable.", +"location": [ +{ +"uri": "https://github.com/SonarSource/sonar-dotnet/blob/master/analyzers/its/sources/Ember-MM/Addons/scraper.EmberCore.XML/frmXMLSettingsHolder.vb#L44", +"region": { +"startLine": 44, +"startColumn": 15, +"endLine": 44, +"endColumn": 28 +} +}, +{ +"uri": "https://github.com/SonarSource/sonar-dotnet/blob/master/analyzers/its/sources/Ember-MM/Addons/scraper.EmberCore.XML/frmXMLSettingsHolder.vb#L48-L51", +"region": { +"startLine": 48, +"startColumn": 9, +"endLine": 51, +"endColumn": 35 +} +} +] +}, +{ +"id": "S2583", +"message": "Change this condition so that it does not always evaluate to 'False'. Some code paths are unreachable.", +"location": [ +{ +"uri": "https://github.com/SonarSource/sonar-dotnet/blob/master/analyzers/its/sources/Ember-MM/Addons/scraper.EmberCore.XML/XMLScraper/MediaTags/AlbumTag.vb#L380", +"region": { +"startLine": 380, +"startColumn": 20, +"endLine": 380, +"endColumn": 33 +} +}, +{ +"uri": "https://github.com/SonarSource/sonar-dotnet/blob/master/analyzers/its/sources/Ember-MM/Addons/scraper.EmberCore.XML/XMLScraper/MediaTags/AlbumTag.vb#L381-L384", +"region": { +"startLine": 381, +"startColumn": 24, +"endLine": 384, +"endColumn": 33 +} +} +] +}, +{ +"id": "S2583", +"message": "Change this condition so that it does not always evaluate to 'False'. Some code paths are unreachable.", +"location": [ +{ +"uri": "https://github.com/SonarSource/sonar-dotnet/blob/master/analyzers/its/sources/Ember-MM/Addons/scraper.EmberCore.XML/XMLScraper/MediaTags/PersonInfo.vb#L221", +"region": { +"startLine": 221, +"startColumn": 20, +"endLine": 221, +"endColumn": 33 +} +}, +{ +"uri": "https://github.com/SonarSource/sonar-dotnet/blob/master/analyzers/its/sources/Ember-MM/Addons/scraper.EmberCore.XML/XMLScraper/MediaTags/PersonInfo.vb#L222-L225", +"region": { +"startLine": 222, +"startColumn": 24, +"endLine": 225, +"endColumn": 34 +} +} +] +}, +{ +"id": "S2583", +"message": "Change this condition so that it does not always evaluate to 'False'. Some code paths are unreachable.", +"location": [ +{ +"uri": "https://github.com/SonarSource/sonar-dotnet/blob/master/analyzers/its/sources/Ember-MM/Addons/scraper.EmberCore.XML/XMLScraper/ScraperLib/ScrapeResultsEntity.vb#L398", +"region": { +"startLine": 398, +"startColumn": 20, +"endLine": 398, +"endColumn": 33 +} +}, +{ +"uri": "https://github.com/SonarSource/sonar-dotnet/blob/master/analyzers/its/sources/Ember-MM/Addons/scraper.EmberCore.XML/XMLScraper/ScraperLib/ScrapeResultsEntity.vb#L399-L402", +"region": { +"startLine": 399, +"startColumn": 24, +"endLine": 402, +"endColumn": 33 +} +} +] +}, +{ +"id": "S2583", +"message": "Change this condition so that it does not always evaluate to 'False'. Some code paths are unreachable.", +"location": [ +{ +"uri": "https://github.com/SonarSource/sonar-dotnet/blob/master/analyzers/its/sources/Ember-MM/Addons/scraper.EmberCore.XML/XMLScraper/ScraperLib/ScrapeResultsEntity.vb#L414", +"region": { +"startLine": 414, +"startColumn": 20, +"endLine": 414, +"endColumn": 33 +} +}, +{ +"uri": "https://github.com/SonarSource/sonar-dotnet/blob/master/analyzers/its/sources/Ember-MM/Addons/scraper.EmberCore.XML/XMLScraper/ScraperLib/ScrapeResultsEntity.vb#L415-L418", +"region": { +"startLine": 415, +"startColumn": 24, +"endLine": 418, +"endColumn": 33 +} +} +] +}, +{ +"id": "S2583", +"message": "Change this condition so that it does not always evaluate to 'False'. Some code paths are unreachable.", +"location": [ +{ +"uri": "https://github.com/SonarSource/sonar-dotnet/blob/master/analyzers/its/sources/Ember-MM/Addons/scraper.EmberCore.XML/XMLScraper/ScraperLib/ScrapeResultsEntity.vb#L430", +"region": { +"startLine": 430, +"startColumn": 20, +"endLine": 430, +"endColumn": 33 +} +}, +{ +"uri": "https://github.com/SonarSource/sonar-dotnet/blob/master/analyzers/its/sources/Ember-MM/Addons/scraper.EmberCore.XML/XMLScraper/ScraperLib/ScrapeResultsEntity.vb#L431-L434", +"region": { +"startLine": 431, +"startColumn": 24, +"endLine": 434, +"endColumn": 33 +} +} +] +}, +{ +"id": "S2583", +"message": "Change this condition so that it does not always evaluate to 'False'. Some code paths are unreachable.", +"location": [ +{ +"uri": "https://github.com/SonarSource/sonar-dotnet/blob/master/analyzers/its/sources/Ember-MM/Addons/scraper.EmberCore.XML/XMLScraper/ScraperLib/ScrapeResultsEntity.vb#L446", +"region": { +"startLine": 446, +"startColumn": 20, +"endLine": 446, +"endColumn": 33 +} +}, +{ +"uri": "https://github.com/SonarSource/sonar-dotnet/blob/master/analyzers/its/sources/Ember-MM/Addons/scraper.EmberCore.XML/XMLScraper/ScraperLib/ScrapeResultsEntity.vb#L447-L450", +"region": { +"startLine": 447, +"startColumn": 24, +"endLine": 450, +"endColumn": 33 +} +} +] +}, +{ +"id": "S2583", +"message": "Change this condition so that it does not always evaluate to 'False'. Some code paths are unreachable.", +"location": [ +{ +"uri": "https://github.com/SonarSource/sonar-dotnet/blob/master/analyzers/its/sources/Ember-MM/Addons/scraper.EmberCore.XML/XMLScraper/ScraperLib/ScrapeResultsEntity.vb#L462", +"region": { +"startLine": 462, +"startColumn": 20, +"endLine": 462, +"endColumn": 33 +} +}, +{ +"uri": "https://github.com/SonarSource/sonar-dotnet/blob/master/analyzers/its/sources/Ember-MM/Addons/scraper.EmberCore.XML/XMLScraper/ScraperLib/ScrapeResultsEntity.vb#L463-L466", +"region": { +"startLine": 463, +"startColumn": 24, +"endLine": 466, +"endColumn": 33 +} +} +] +}, +{ +"id": "S2583", +"message": "Change this condition so that it does not always evaluate to 'False'. Some code paths are unreachable.", +"location": [ +{ +"uri": "https://github.com/SonarSource/sonar-dotnet/blob/master/analyzers/its/sources/Ember-MM/Addons/scraper.EmberCore.XML/XMLScraper/ScraperLib/ScraperEvaluation.vb#L101", +"region": { +"startLine": 101, +"startColumn": 20, +"endLine": 101, +"endColumn": 33 +} +}, +{ +"uri": "https://github.com/SonarSource/sonar-dotnet/blob/master/analyzers/its/sources/Ember-MM/Addons/scraper.EmberCore.XML/XMLScraper/ScraperLib/ScraperEvaluation.vb#L102-L105", +"region": { +"startLine": 102, +"startColumn": 24, +"endLine": 105, +"endColumn": 33 +} +} +] +}, +{ +"id": "S2583", +"message": "Change this condition so that it does not always evaluate to 'False'. Some code paths are unreachable.", +"location": [ +{ +"uri": "https://github.com/SonarSource/sonar-dotnet/blob/master/analyzers/its/sources/Ember-MM/Addons/scraper.EmberCore.XML/XMLScraper/ScraperXML/ScraperInfo.vb#L190", +"region": { +"startLine": 190, +"startColumn": 20, +"endLine": 190, +"endColumn": 33 +} +}, +{ +"uri": "https://github.com/SonarSource/sonar-dotnet/blob/master/analyzers/its/sources/Ember-MM/Addons/scraper.EmberCore.XML/XMLScraper/ScraperXML/ScraperInfo.vb#L191-L194", +"region": { +"startLine": 191, +"startColumn": 24, +"endLine": 194, +"endColumn": 33 +} +} +] +} +] +} diff --git a/analyzers/its/expected/Ember-MM/scraper.EmberCore.XML-{E567C031-1F7B-4637-9B3A-806988DE50CF}-S2589.json b/analyzers/its/expected/Ember-MM/scraper.EmberCore.XML-{E567C031-1F7B-4637-9B3A-806988DE50CF}-S2589.json new file mode 100644 index 00000000000..afdb05225cb --- /dev/null +++ b/analyzers/its/expected/Ember-MM/scraper.EmberCore.XML-{E567C031-1F7B-4637-9B3A-806988DE50CF}-S2589.json @@ -0,0 +1,43 @@ +{ +"issues": [ +{ +"id": "S2589", +"message": "Change this condition so that it does not always evaluate to 'False'.", +"location": { +"uri": "https://github.com/SonarSource/sonar-dotnet/blob/master/analyzers/its/sources/Ember-MM/Addons/scraper.EmberCore.XML/XMLScraper/ScraperLib/ScrapeResultsEntity.vb#L344", +"region": { +"startLine": 344, +"startColumn": 24, +"endLine": 344, +"endColumn": 40 +} +} +}, +{ +"id": "S2589", +"message": "Change this condition so that it does not always evaluate to 'False'.", +"location": { +"uri": "https://github.com/SonarSource/sonar-dotnet/blob/master/analyzers/its/sources/Ember-MM/Addons/scraper.EmberCore.XML/XMLScraper/ScraperLib/ScrapeResultsEntity.vb#L348", +"region": { +"startLine": 348, +"startColumn": 24, +"endLine": 348, +"endColumn": 37 +} +} +}, +{ +"id": "S2589", +"message": "Change this condition so that it does not always evaluate to 'False'.", +"location": { +"uri": "https://github.com/SonarSource/sonar-dotnet/blob/master/analyzers/its/sources/Ember-MM/Addons/scraper.EmberCore.XML/XMLScraper/ScraperLib/ScrapeResultsEntity.vb#L372", +"region": { +"startLine": 372, +"startColumn": 24, +"endLine": 372, +"endColumn": 41 +} +} +} +] +} From 0b67aa5e468e3b770a4d870b2184a93aab25635f Mon Sep 17 00:00:00 2001 From: mary-georgiou-sonarsource Date: Thu, 10 Aug 2023 17:06:40 +0200 Subject: [PATCH 13/20] remove usused using --- .../SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/analyzers/src/SonarAnalyzer.VisualBasic/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.cs b/analyzers/src/SonarAnalyzer.VisualBasic/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.cs index f98c7970963..9614c8ff0f6 100644 --- a/analyzers/src/SonarAnalyzer.VisualBasic/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.cs +++ b/analyzers/src/SonarAnalyzer.VisualBasic/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.cs @@ -18,8 +18,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -using StyleCop.Analyzers.Lightup; - namespace SonarAnalyzer.SymbolicExecution.Roslyn.RuleChecks.VisualBasic; public class ConditionEvaluatesToConstant : ConditionEvaluatesToConstantBase From a749c8e19aaf98de8b560b1d4e1470e555963968 Mon Sep 17 00:00:00 2001 From: mary-georgiou-sonarsource Date: Thu, 10 Aug 2023 17:58:08 +0200 Subject: [PATCH 14/20] Apply issue locations --- .../Roslyn/ConditionEvaluatesToConstant.cs | 2 - .../ConditionEvaluatesToConstant.VB14.vb | 92 +++++++++---------- .../Roslyn/ConditionEvaluatesToConstant.cs | 8 +- .../Roslyn/ConditionEvaluatesToConstant.vb | 21 +---- 4 files changed, 49 insertions(+), 74 deletions(-) diff --git a/analyzers/src/SonarAnalyzer.VisualBasic/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.cs b/analyzers/src/SonarAnalyzer.VisualBasic/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.cs index 9614c8ff0f6..1e9dae0e0c8 100644 --- a/analyzers/src/SonarAnalyzer.VisualBasic/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.cs +++ b/analyzers/src/SonarAnalyzer.VisualBasic/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.cs @@ -44,7 +44,6 @@ public override void Visit(SyntaxNode node) { ContainsCondition = node.IsAnyKind( SyntaxKind.AndAlsoExpression, - SyntaxKind.AndExpression, SyntaxKind.BinaryConditionalExpression, SyntaxKind.ConditionalAccessExpression, SyntaxKind.DoWhileStatement, @@ -53,7 +52,6 @@ public override void Visit(SyntaxNode node) SyntaxKind.SelectStatement, SyntaxKind.SimpleDoStatement, SyntaxKind.TernaryConditionalExpression, - SyntaxKind.OrExpression, SyntaxKind.OrElseExpression, SyntaxKind.WhileStatement); diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.VB14.vb b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.VB14.vb index 7a806c5c756..a331328af6a 100644 --- a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.VB14.vb +++ b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.VB14.vb @@ -63,16 +63,16 @@ Namespace Tests.Diagnostics Public Class Result Public Property Succeed As Boolean - Public Shared Function Test() As Result - If Date.Now.Day = 17 Then ' swap value here to test both cases if needed + Public Shared Function Test(ByVal cond As Boolean) As Result + If cond Then Return New Result() End If Return Nothing End Function End Class - Public Shared Sub Compliant1() - Dim result = TestNullConditional.Result.Test() + Public Shared Sub Compliant1(ByVal cond As Boolean) + Dim result = TestNullConditional.Result.Test(cond) If result Is Nothing OrElse Not result.Succeed Then Console.WriteLine("shorted") @@ -91,10 +91,11 @@ Namespace Tests.Diagnostics Public Shared Sub NonCompliant1() Dim result As Result = Nothing - If result?.Succeed IsNot Nothing Then ' Noncompliant - ' Secondary@-1 - ' Noncompliant@-2 - Console.WriteLine("shorted") ' Secondary + If result?.Succeed IsNot Nothing Then + ' ^^^^^^ Noncompliant + ' ^^^^^^^^ Secondary@-1 + ' ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Noncompliant@-2 + Console.WriteLine("shorted") ' Secondary If result IsNot Nothing Then Console.WriteLine("other") End If @@ -103,10 +104,11 @@ Namespace Tests.Diagnostics Public Shared Sub NonCompliant2() Dim result As Result = New Result() - If result?.Succeed IsNot Nothing Then ' Noncompliant - ' Noncompliant@-1 + If result?.Succeed IsNot Nothing Then + ' ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Noncompliant + ' ^^^^^^ Noncompliant@-1 Console.WriteLine("shorted") - While result IsNot Nothing ' Noncompliant + While result IsNot Nothing ' Noncompliant Console.WriteLine("other") End While End If @@ -118,24 +120,27 @@ Namespace Tests.Diagnostics Public Shared Sub Compliant2() Dim aObj As A = Nothing - If If(aObj?.booleanVal, False) Then ' Noncompliant - ' Secondary@-1 - ' Noncompliant@-2 + If If(aObj?.booleanVal, False) Then + ' ^^^^ Noncompliant + ' ^^^^^^^^^^^ Secondary@-1 + ' ^^^^^^^^^^^^^^^^ Noncompliant@-2 Console.WriteLine("a") End If End Sub Public Shared Sub NonCompliant3() Dim aObj As A = Nothing - If aObj?.booleanVal Is Nothing Then ' Noncompliant - ' Secondary@-1 - ' Noncompliant@-2 + If aObj?.booleanVal Is Nothing Then + ' ^^^^ Noncompliant + ' ^^^^^^^^^^^ Secondary@-1 + ' ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Noncompliant@-2 Console.WriteLine("a") End If - If aObj?.booleanVal IsNot Nothing Then ' Noncompliant - ' Secondary@-1 - ' Noncompliant@-2 + If aObj?.booleanVal IsNot Nothing Then + ' ^^^^ Noncompliant + ' ^^^^^^^^^^^ Secondary@-1 + ' ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Noncompliant@-2 Console.WriteLine("a") ' Secondary End If End Sub @@ -179,10 +184,11 @@ Namespace Tests.Diagnostics Public Shared Sub NonCompliant5() Dim a As A = Nothing - While If(a?.booleanVal Is Nothing, True, False) ' Noncompliant - ' Secondary@-1 - ' Noncompliant@-2 - ' Secondary@-3 + While If(a?.booleanVal Is Nothing, True, False) + ' ^ Noncompliant + ' ^^^^^^^^^^^ Secondary@-1 + ' ^^^^^^^^^^^^^^^^^^^^^^^^ Noncompliant@-2 + ' ^^^^^ Secondary@-3 Console.WriteLine("Compliant") End While End Sub @@ -199,9 +205,10 @@ Namespace Tests.Diagnostics Public Shared Sub NonCompliant6() Dim sObj As S = Nothing - If sObj?.str?.Length > 2 Then ' Noncompliant - ' Secondary@-1 - ' Noncompliant@-2 + If sObj?.str?.Length > 2 Then + ' ^^^^ Noncompliant + ' ^^^^^^^ Secondary@-1 + ' ^^^^^^^^^^^^^^^^^^^^^ Noncompliant@-2 Console.WriteLine("a") ' Secondary End If End Sub @@ -212,17 +219,8 @@ Namespace Tests.Diagnostics Public Sub AndAlsoExpression() Dim c1 = True - If c1 AndAlso c1 Then ' Noncompliant - ' Noncompliant@-1 - Console.WriteLine("Always True") - End If - End Sub - - Public Sub AndExpression() - Dim c1 = True - If c1 And c1 Then ' Noncompliant - Console.WriteLine("Always True") - End If + Dim a = c1 AndAlso c1 ' Noncompliant + ' Secondary@-1 End Sub Public Sub TernaryConditionalExpression() @@ -233,8 +231,9 @@ Namespace Tests.Diagnostics Public Shared Sub ConditionalAccessExpression() Dim sObj = Nothing - Dim x = sObj?.str?.Length > 2 ' Noncompliant - ' Secondary@-1 + Dim x = sObj?.str?.Length > 2 + ' ^^^^ Noncompliant + ' ^^^^^^^ Secondary@-1 End Sub Public Sub DoLoopUntilStatement() @@ -274,17 +273,8 @@ Namespace Tests.Diagnostics Public Sub OrAlsoExpression() Dim c1 = True - If c1 OrElse False Then ' Noncompliant - ' Secondary@-1 - Console.WriteLine("Always True") - End If - End Sub - - Public Sub OrExpression() - Dim c1 = True - If c1 Or False Then ' Noncompliant - Console.WriteLine("Always True") - End If + Dim a = c1 OrElse False ' Noncompliant + ' Secondary@-1 End Sub Public Sub WhileStatement() diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.cs b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.cs index 5f1b73b610f..e1e556f1290 100644 --- a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.cs +++ b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.cs @@ -1739,9 +1739,9 @@ public class Result { public bool Succeed { get; set; } - public static Result Test() + public static Result Test(bool cond) { - if (DateTime.Now.Day == 17) // swap value here to test both cases if needed + if (cond) { return new Result(); } @@ -1749,9 +1749,9 @@ public static Result Test() } } - public static void Compliant1() + public static void Compliant1(bool cond) { - var result = Result.Test(); + var result = Result.Test(cond); if (result == null || !result.Succeed) { diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.vb b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.vb index de13a2ef348..1a1164fa923 100644 --- a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.vb +++ b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.vb @@ -160,7 +160,7 @@ Namespace Tests.Diagnostics Console.WriteLine() Else ' secondary location covers all unreachable code blocks: - Console.WriteLine(1) ' Secondary ?????? + Console.WriteLine(1) ' Secondary ^17#108 While b Console.WriteLine(2) End While ' the secondary location ends at the end of the above line @@ -205,7 +205,7 @@ Namespace Tests.Diagnostics b = False End Sub - Public Sub Method5(ByVal cond As Boolean) + Public Sub Method3(ByVal cond As Boolean) While cond Console.WriteLine() End While @@ -218,7 +218,7 @@ Namespace Tests.Diagnostics Console.WriteLine() ' Secondary End Sub - Public Sub Method6(ByVal cond As Boolean) + Public Sub Method4(ByVal cond As Boolean) Dim i = 10 While i < 20 i = i + 1 @@ -232,7 +232,7 @@ Namespace Tests.Diagnostics Console.WriteLine() ' Secondary End Sub - Public Sub Method7() + Public Sub Method5() While True ' Compliant Console.WriteLine() End While @@ -240,19 +240,6 @@ Namespace Tests.Diagnostics Console.WriteLine() End Sub - Public Sub Method8(n) - For Each item In New Integer()() {New Integer() {1, 2, 3}} - For Each i In item - Console.WriteLine() - Next - Next - End Sub - - Public Sub Method9_For(ByVal cond As Boolean) - While True ' Not reporting on this - - End While - End Sub Public Sub Method_Select() Dim i = 10 From 45da0ec3de3997557dcc7890363f6baa29a9d14f Mon Sep 17 00:00:00 2001 From: mary-georgiou-sonarsource Date: Thu, 10 Aug 2023 18:09:26 +0200 Subject: [PATCH 15/20] Update compound assignment UTs in both vb and c# --- .../Roslyn/ConditionEvaluatesToConstant.cs | 13 +++++++++++-- .../Roslyn/ConditionEvaluatesToConstant.vb | 11 +++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.cs b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.cs index e1e556f1290..114b8227a7b 100644 --- a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.cs +++ b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.cs @@ -579,8 +579,17 @@ public void BooleanBinary(bool a, bool b) a ^= true; if (a) { } // FN: engine doesn't learn BoolConstraints from binary operators - a ^= true; - if (a) { } // FN: engine doesn't learn BoolConstraints from binary operators + a = a & true; + if (a) // FN + { } + + a = a | true; + if (a) // Noncompliant + { } + + a = a^ true; + if (a) // Noncompliant + { } } public void IsAsExpression(object o) diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.vb b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.vb index 1a1164fa923..eb73896ea91 100644 --- a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.vb +++ b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.vb @@ -447,6 +447,17 @@ Namespace Tests.Diagnostics End If End Sub + Public Sub CompoundAssignment(ByVal a As Boolean, ByVal b As Boolean) + ' https://learn.microsoft.com/en-us/dotnet/visual-basic/language-reference/operators/assignment-operators + a &=True + If a Then ' FN + End If + + a ^=True + If a Then ' FN + End If + End Sub + Public Sub IsAsExpression(ByVal o As Object) If TypeOf o Is String Then From 296bbb21876df780449e9aba6964e6900b9e3378 Mon Sep 17 00:00:00 2001 From: mary-georgiou-sonarsource Date: Thu, 10 Aug 2023 18:19:05 +0200 Subject: [PATCH 16/20] Formatting etc --- .../Roslyn/ConditionEvaluatesToConstant.cs | 6 +-- .../Roslyn/ConditionEvaluatesToConstant.vb | 44 +++++++++---------- 2 files changed, 23 insertions(+), 27 deletions(-) diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.cs b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.cs index 114b8227a7b..ffb8f7cbc4f 100644 --- a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.cs +++ b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.cs @@ -1637,8 +1637,6 @@ public void Rethrow(bool condition) public void FalseNegatives() { - // We cannot detect the case in ObjectsShouldNotBeDisposedMoreThanOnce method above - // and to avoid False Positives we do not report in catch or finally object o = null; try { @@ -1679,8 +1677,8 @@ async Task Foo(Task t) object o = null; _foo1 = o; await t; // awaiting clears the constraints - if (_foo1 != null) { } // Compliant S2583 - if (_foo1 == null) { } // Compliant S2589 + if (_foo1 != null) { } // FN + if (_foo1 == null) { } // FN if (o != null) { } // Noncompliant if (o == null) { } // Noncompliant } diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.vb b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.vb index eb73896ea91..de4c59282ac 100644 --- a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.vb +++ b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.vb @@ -654,7 +654,7 @@ Namespace Tests.Diagnostics End If If String.IsNullOrWhiteSpace(s) Then ' Noncompliant End If - If Not Equals(String.IsInterned(s), Nothing) Then ' FN FIX + If Not Equals(String.IsInterned(s), Nothing) Then End If s = "" If String.IsNullOrEmpty(s) Then ' FN @@ -996,7 +996,7 @@ Namespace Tests.Diagnostics Friend Structure MyStructWithNoOperator Public Shared Sub M(ByVal a As MyStructWithNoOperator) If a Is Nothing Then ' Noncompliant, also a compiler error - ' Error@-1 [BC30020] + ' Error@-1 [BC30020] End If End Sub End Structure @@ -1190,7 +1190,7 @@ Namespace Tests.Diagnostics End If Const f = False If f Then ' Noncompliant - Console.WriteLine() ' Secondary + Console.WriteLine() ' Secondary End If End Sub Private Sub Constants() @@ -1259,8 +1259,6 @@ Namespace Tests.Diagnostics End Sub Public Sub FalseNegatives() - ' We cannot detect the case in ObjectsShouldNotBeDisposedMoreThanOnce method above - ' and to avoid False Positives we do not report in catch or finally Dim o As Object = Nothing Try Console.WriteLine("Could throw") @@ -1299,9 +1297,9 @@ Namespace Tests.Diagnostics Dim o As Object = Nothing _foo1 = o Await t ' awaiting clears the constraints - If _foo1 IsNot Nothing Then ' Compliant S2583 + If _foo1 IsNot Nothing Then ' FN End If - If _foo1 Is Nothing Then ' Compliant S2589 + If _foo1 Is Nothing Then ' FN End If If o IsNot Nothing Then ' Noncompliant End If @@ -1604,7 +1602,7 @@ Namespace Tests.Diagnostics s1.ToString() Else If Equals(s1, Nothing) Then ' Noncompliant - s1.ToString() ' Secondary + s1.ToString() ' Secondary End If End If @@ -1613,7 +1611,7 @@ Namespace Tests.Diagnostics Public Sub Method4(ByVal s1 As String) If Not String.IsNullOrEmpty(s1) Then If Equals(s1, Nothing) Then ' Noncompliant - s1.ToString() ' Secondary + s1.ToString() ' Secondary End If Else s1.ToString() @@ -1624,7 +1622,7 @@ Namespace Tests.Diagnostics Public Sub Method5(ByVal s1 As String) If Not String.IsNullOrEmpty(s1) Then If Equals(s1, Nothing) Then ' Noncompliant - s1.ToString() ' Secondary + s1.ToString() ' Secondary End If Else s1.ToString() @@ -1637,7 +1635,7 @@ Namespace Tests.Diagnostics s1.ToString() Else If Equals(s1, Nothing) Then ' Noncompliant - s1.ToString() ' Secondary + s1.ToString() ' Secondary End If End If @@ -1680,19 +1678,19 @@ Namespace Tests.Diagnostics 'Left operand: Values notNull and notEmpty are known to be not-null ret = If(notNull, a) ' Noncompliant - ' Secondary@-1 + ' Secondary@-1 ret = If(notNull, a) ' Noncompliant - ' Secondary@-1 + ' Secondary@-1 ret = "Lorem " & If(notNull, a) & " ipsum" ' Noncompliant - ' Secondary@-1 + ' Secondary@-1 ret = If(notNull, "N/A") ' Noncompliant - ' Secondary@-1 + ' Secondary@-1 ret = If(notEmpty, "N/A") ' Noncompliant - ' Secondary@-1 + ' Secondary@-1 'Left operand: isNull is known to be null ret = If(Nothing, a) ' Noncompliant - ret = If(isNull, a) ' NoncompliantP + ret = If(isNull, a) ' Noncompliant ret = "Lorem " & If(isNull, a) & " ipsum" ' Noncompliant 'Right operand: isNull is known to be null, therefore ?? is useless @@ -1739,8 +1737,8 @@ Namespace Tests.Diagnostics End If - If String.IsNullOrWhiteSpace(s2) Then ' FN - If Equals(s2, "a") Then ' FN + If String.IsNullOrWhiteSpace(s2) Then ' FN + If Equals(s2, "a") Then ' FN End If End If @@ -1749,20 +1747,20 @@ Namespace Tests.Diagnostics End If - If String.IsNullOrWhiteSpace(s4) Then ' FN + If String.IsNullOrWhiteSpace(s4) Then ' FN End If - If Not String.IsNullOrWhiteSpace(s4) Then ' FN + If Not String.IsNullOrWhiteSpace(s4) Then ' FN End If If Not String.IsNullOrWhiteSpace(s) Then - If Equals(s, "") Then ' FN + If Equals(s, "") Then ' FN End If - If Equals(s, " ") Then ' FN + If Equals(s, " ") Then ' FN End If End If From a91a60dcd27414f245f835dfb3f1df45bcbba952 Mon Sep 17 00:00:00 2001 From: mary-georgiou-sonarsource Date: Fri, 11 Aug 2023 07:32:49 +0200 Subject: [PATCH 17/20] nitpicks --- .../ConditionEvaluatesToConstant.VB14.vb | 10 +- .../Roslyn/ConditionEvaluatesToConstant.vb | 217 +++++++++--------- 2 files changed, 108 insertions(+), 119 deletions(-) diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.VB14.vb b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.VB14.vb index a331328af6a..5a378e46fd7 100644 --- a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.VB14.vb +++ b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.VB14.vb @@ -95,7 +95,7 @@ Namespace Tests.Diagnostics ' ^^^^^^ Noncompliant ' ^^^^^^^^ Secondary@-1 ' ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Noncompliant@-2 - Console.WriteLine("shorted") ' Secondary + Console.WriteLine("shorted") ' Secondary If result IsNot Nothing Then Console.WriteLine("other") End If @@ -108,7 +108,7 @@ Namespace Tests.Diagnostics ' ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Noncompliant ' ^^^^^^ Noncompliant@-1 Console.WriteLine("shorted") - While result IsNot Nothing ' Noncompliant + While result IsNot Nothing ' Noncompliant Console.WriteLine("other") End While End If @@ -141,7 +141,7 @@ Namespace Tests.Diagnostics ' ^^^^ Noncompliant ' ^^^^^^^^^^^ Secondary@-1 ' ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Noncompliant@-2 - Console.WriteLine("a") ' Secondary + Console.WriteLine("a") ' Secondary End If End Sub @@ -209,7 +209,7 @@ Namespace Tests.Diagnostics ' ^^^^ Noncompliant ' ^^^^^^^ Secondary@-1 ' ^^^^^^^^^^^^^^^^^^^^^ Noncompliant@-2 - Console.WriteLine("a") ' Secondary + Console.WriteLine("a") ' Secondary End If End Sub End Class @@ -266,7 +266,7 @@ Namespace Tests.Diagnostics Public Sub IfStatement() Dim c1 = True - If c1 ' Noncompliant + If c1 ' Noncompliant Console.WriteLine("") End If End Sub diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.vb b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.vb index de4c59282ac..0f2f4db1bf0 100644 --- a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.vb +++ b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.vb @@ -57,7 +57,7 @@ Namespace Tests.Diagnostics Do If o2 IsNot Nothing Then Exit Do - Loop While c2 ' Noncompliant {{Change this condition so that it does not always evaluate to 'False'.}} + Loop While c2 ' Noncompliant {{Change this condition so that it does not always evaluate to 'False'.}} ' ^^ End Sub @@ -86,7 +86,7 @@ Namespace Tests.Diagnostics Dim x = t OrElse a OrElse b ' Compliant t is const - If t = True Then ' Noncompliant + If t = True Then ' Noncompliant Console.WriteLine("") End If @@ -102,7 +102,7 @@ Namespace Tests.Diagnostics Public Sub Foo2(ByVal a As Boolean, ByVal b As Boolean) Dim l = True Dim x = l OrElse a OrElse b - ' ^ Noncompliant + ' ^ Noncompliant ' ^^^^^^^^^^ Secondary@-1 End Sub @@ -270,7 +270,7 @@ Namespace Tests.Diagnostics If b Then ' Noncompliant Console.WriteLine() Else - Console.WriteLine() ' Secondary + Console.WriteLine() ' Secondary End If End Sub) Return True @@ -393,7 +393,7 @@ Namespace Tests.Diagnostics Dim b = a If Not a Then - If b Then ' FN: requires relation support + If b Then ' FN: requires relation support End If End If @@ -416,7 +416,7 @@ Namespace Tests.Diagnostics End If If Not (a Or b) Then - If a Then ' FN: engine doesn't learn BoolConstraints from binary operators + If a Then ' FN: engine doesn't learn BoolConstraints from binary operators End If End If @@ -516,18 +516,18 @@ Namespace Tests.Diagnostics Public Sub EqRelations(ByVal a As Boolean, ByVal b As Boolean) If a = b Then - If b = a Then ' FN: requires relation support + If b = a Then ' FN: requires relation support End If - If b = Not a Then ' FN: requires relation support + If b = Not a Then ' FN: requires relation support End If - If Not b = Not Not a Then ' FN: requires relation support + If Not b = Not Not a Then ' FN: requires relation support End If - If Not a = b Then ' FN: requires relation support + If Not a = b Then ' FN: requires relation support End If Else - If b <> a Then ' FN: requires relation support + If b <> a Then ' FN: requires relation support End If - If b <> Not a Then ' FN: requires relation support + If b <> Not a Then ' FN: requires relation support End If If Not b <> Not Not a Then ' FN: requires relation support End If @@ -535,7 +535,7 @@ Namespace Tests.Diagnostics End If If a <> b Then - If b = a Then ' FN: requires relation support + If b = a Then ' FN: requires relation support End If Else If b <> a Then ' FN: requires relation support @@ -555,14 +555,14 @@ Namespace Tests.Diagnostics End If If Equals(a, b) Then ' FN End If - If a.Equals(b) Then ' FN + If a.Equals(b) Then ' FN End If End If If Me Is a Then If Equals(a) Then ' FN End If - If Equals(a) Then ' FN + If Equals(a) Then ' FN End If End If End Sub @@ -606,9 +606,9 @@ Namespace Tests.Diagnostics End If ' FN a = Nothing - If Object.ReferenceEquals(Nothing, a) Then ' Noncompliant + If Object.ReferenceEquals(Nothing, a) Then ' Noncompliant End If - If Object.ReferenceEquals(a, a) Then ' Noncompliant + If Object.ReferenceEquals(a, a) Then ' Noncompliant End If If Object.ReferenceEquals(Nothing, New Object()) Then ' Noncompliant @@ -650,27 +650,27 @@ Namespace Tests.Diagnostics Public Sub StringEmpty(ByVal s1 As String) Dim s As String = Nothing - If String.IsNullOrEmpty(s) Then ' Noncompliant + If String.IsNullOrEmpty(s) Then ' Noncompliant End If If String.IsNullOrWhiteSpace(s) Then ' Noncompliant End If If Not Equals(String.IsInterned(s), Nothing) Then End If s = "" - If String.IsNullOrEmpty(s) Then ' FN + If String.IsNullOrEmpty(s) Then ' FN End If If String.IsNullOrWhiteSpace(s) Then ' FN End If - If String.IsNullOrEmpty(s1) Then ' Compliant, we don't know anything about the argument + If String.IsNullOrEmpty(s1) Then ' Compliant, we don't know anything about the argument End If If String.IsNullOrWhiteSpace(s1) Then ' Compliant End If If String.IsNullOrEmpty(s1) Then - If String.IsNullOrEmpty(s1) Then ' FN + If String.IsNullOrEmpty(s1) Then ' FN End If End If End Sub @@ -681,7 +681,7 @@ Namespace Tests.Diagnostics End If If j <= i Then ' FN End If - If j = i Then ' FN + If j = i Then ' FN End If If j <> i Then ' FN End If @@ -692,26 +692,26 @@ Namespace Tests.Diagnostics If i = j Then If Equals(i, j) Then ' FN End If - If i.Equals(j) Then ' FN + If i.Equals(j) Then ' FN End If End If End Sub Private Sub DefaultExpression(ByVal o As Object) - If Nothing Is Nothing Then ' Noncompliant + If Nothing Is Nothing Then ' Noncompliant End If Dim nullableInt As Integer? = Nothing If nullableInt Is Nothing Then ' Noncompliant End If - If Nothing Is Nothing Then ' Noncompliant + If Nothing Is Nothing Then ' Noncompliant End If - If Nothing IsNot Nothing Then ' Noncompliant + If Nothing IsNot Nothing Then ' Noncompliant End If - If Nothing IsNot Nothing Then ' Noncompliant + If Nothing IsNot Nothing Then ' Noncompliant End If End Sub @@ -767,7 +767,7 @@ Namespace Tests.Diagnostics If i = j Then ' Noncompliant End If - If i.Equals(j) Then ' FN + If i.Equals(j) Then ' FN End If If Equals(i, j) Then ' FN @@ -785,7 +785,7 @@ Namespace Tests.Diagnostics Public Sub Assert(ByVal condition As Boolean, ByVal o1 As Object) Debug.Assert(condition) - If condition Then ' Noncompliant + If condition Then ' Noncompliant End If Trace.Assert(condition) ' Compliant @@ -807,7 +807,7 @@ Namespace Tests.Diagnostics End If If a = b AndAlso b <= c Then - If a > c Then ' FN + If a > c Then ' FN End If End If @@ -822,12 +822,12 @@ Namespace Tests.Diagnostics End If If a >= b AndAlso b >= c Then - If a < c Then ' FN + If a < c Then ' FN End If End If If a >= b AndAlso c <= b Then - If a < c Then ' FN + If a < c Then ' FN End If End If @@ -854,7 +854,7 @@ Namespace Tests.Diagnostics Private Sub RefEqTransitivity(ByVal a As Comp, ByVal b As Comp, ByVal c As Comp) If a Is b AndAlso b Is c Then - If a IsNot c Then ' FN + If a IsNot c Then ' FN End If End If @@ -863,21 +863,21 @@ Namespace Tests.Diagnostics End If If a Is c Then End If - If a.Equals(c) Then ' FN + If a.Equals(c) Then ' FN End If If Not a.Equals(c) Then ' FN End If End If If a > b AndAlso b Is c Then - If a <= c Then ' FN + If a <= c Then ' FN End If End If End Sub Private Sub ValueEqTransitivity(ByVal a As Comp, ByVal b As Comp, ByVal c As Comp) If a Is b AndAlso b.Equals(c) Then - If a.Equals(c) Then ' FN + If a.Equals(c) Then ' FN End If End If @@ -886,14 +886,14 @@ Namespace Tests.Diagnostics End If If a Is c Then End If - If a.Equals(c) Then ' FN + If a.Equals(c) Then ' FN End If If Not a.Equals(c) Then ' FN End If End If If a > b AndAlso b.Equals(c) Then - If a > c Then ' FN + If a > c Then ' FN End If If a <= c Then ' FN End If @@ -902,7 +902,7 @@ Namespace Tests.Diagnostics If Not a.Equals(b) AndAlso b.Equals(c) Then If a.Equals(c) Then ' FN End If - If a Is c Then ' FN + If a Is c Then ' FN End If End If @@ -928,7 +928,7 @@ Namespace Tests.Diagnostics End If If b.Equals(c) Then ' FN - End If ' FN + End If End If End Sub @@ -937,28 +937,28 @@ Namespace Tests.Diagnostics Dim i As Integer? = Nothing Dim j As Integer? = 5 - If i < j Then ' Noncompliant + If i < j Then ' Noncompliant End If - If i <= j Then ' Noncompliant + If i <= j Then ' Noncompliant End If - If i > j Then ' Noncompliant + If i > j Then ' Noncompliant End If - If i >= j Then ' Noncompliant + If i >= j Then ' Noncompliant End If - If i > 0 Then ' Noncompliant + If i > 0 Then ' Noncompliant End If - If i >= 0 Then ' Noncompliant + If i >= 0 Then ' Noncompliant End If - If i < 0 Then ' Noncompliant + If i < 0 Then ' Noncompliant End If - If i <= 0 Then ' Noncompliant + If i <= 0 Then ' Noncompliant End If If j > Nothing Then ' Noncompliant @@ -1004,7 +1004,7 @@ Namespace Tests.Diagnostics Public Class NullableCases Private Sub Case1() Dim b1 As Boolean? = True - If b1 = True Then ' Noncompliant + If b1 = True Then ' Noncompliant End If End Sub @@ -1020,70 +1020,70 @@ Namespace Tests.Diagnostics End If i = Nothing - If i Is Nothing Then ' Noncompliant + If i Is Nothing Then ' Noncompliant End If - If i = True Then ' Noncompliant + If i = True Then ' Noncompliant End If - If i = False Then ' Noncompliant + If i = False Then ' Noncompliant End If i = True - If i Is Nothing Then ' Noncompliant + If i Is Nothing Then ' Noncompliant End If - If i = True Then ' Noncompliant + If i = True Then ' Noncompliant End If - If i = False Then ' Noncompliant + If i = False Then ' Noncompliant End If i = False - If i Is Nothing Then ' Noncompliant + If i Is Nothing Then ' Noncompliant End If - If i = True Then ' Noncompliant + If i = True Then ' Noncompliant End If - If i = False Then ' Noncompliant + If i = False Then ' Noncompliant End If Dim b2 As Boolean? = True - If b2 = False Then ' Noncompliant + If b2 = False Then ' Noncompliant End If Dim b3 As Boolean? = True - If b3 Is Nothing Then ' Noncompliant + If b3 Is Nothing Then ' Noncompliant End If Dim b4 As Boolean? = Nothing - If b4 = True Then ' Noncompliant + If b4 = True Then ' Noncompliant End If Dim b5 As Boolean? = Nothing - If b5 = False Then ' Noncompliant + If b5 = False Then ' Noncompliant End If Dim b6 As Boolean? = Nothing - If b6 Is Nothing Then ' Noncompliant + If b6 Is Nothing Then ' Noncompliant End If Dim b7 As Boolean? = True - If b7 = True Then ' Noncompliant + If b7 = True Then ' Noncompliant End If Dim b8 As Boolean? = False - If b8 = False Then ' Noncompliant + If b8 = False Then ' Noncompliant End If End Sub Private Sub Case3(ByVal b As Boolean?) If b Is Nothing Then - If Nothing Is b Then ' Noncompliant + If Nothing Is b Then ' Noncompliant b.ToString() End If Else @@ -1095,7 +1095,7 @@ Namespace Tests.Diagnostics Private Sub Case4(ByVal b As Boolean?) If b = True Then - If True = b Then ' Noncompliant + If True = b Then ' Noncompliant b.ToString() End If End If @@ -1117,7 +1117,7 @@ Namespace Tests.Diagnostics Private Sub Case7(ByVal b As Boolean?) If b Is Nothing Then - If If(b, False) Then ' Noncompliant + If If(b, False) Then ' Noncompliant End If End If @@ -1125,7 +1125,7 @@ Namespace Tests.Diagnostics Private Sub Case8(ByVal b As Boolean?) If b IsNot Nothing Then - If b.HasValue Then ' Noncompliant + If b.HasValue Then ' Noncompliant End If End If End Sub @@ -1133,30 +1133,18 @@ Namespace Tests.Diagnostics Private Sub Case9(ByVal b As Boolean?) If b = True Then Dim x = b.Value - If x = True Then ' Noncompliant + If x = True Then ' Noncompliant End If End If End Sub Private Sub Case10(ByVal i As Integer?) If i Is Nothing Then - If i.HasValue Then ' Noncompliant + If i.HasValue Then ' Noncompliant End If End If End Sub - ' https://github.com/SonarSource/sonar-dotnet/issues/4755 - Public Sub IfElseIfElseFlow_FromCast(ByVal value As Object) - Dim b = CType(value, Boolean?) - If b = True Then - Console.WriteLine("true") - ElseIf b = False Then ' Compliant - Console.WriteLine("false") - Else - Console.WriteLine("null") - End If - End Sub - Public Sub IfElseIfElseFlow_DirectValue(ByVal b As Boolean?) If b = True Then Console.WriteLine("true") @@ -1193,16 +1181,17 @@ Namespace Tests.Diagnostics Console.WriteLine() ' Secondary End If End Sub + Private Sub Constants() - If T Then ' Compliant it's a constant + If T Then ' Compliant it's a constant Console.WriteLine() End If - If F Then ' Compliant it's a constant + If F Then ' Compliant it's a constant Console.WriteLine() End If End Sub Private Sub WhileTrue() - While T ' Compliant it's a constant + While T ' Compliant it's a constant Console.WriteLine() End While End Sub @@ -1212,7 +1201,7 @@ Namespace Tests.Diagnostics Loop While F ' Compliant it's a constant End Sub Private Sub Condition() - Dim x = If(T, 1, 2) ' Compliant, T is constant + Dim x = If(T, 1, 2) ' Compliant, T is constant End Sub End Class @@ -1222,8 +1211,8 @@ Namespace Tests.Diagnostics Public Sub Guarded(ByVal s1 As String) Guard1(s1) - If Equals(s1, Nothing) Then ' Noncompliant, always flse - ' this branch is never executed + If Equals(s1, Nothing) Then ' Noncompliant, always false + ' this branch is never executed Else End If End Sub @@ -1265,13 +1254,13 @@ Namespace Tests.Diagnostics Catch If o IsNot Nothing Then ' Noncompliant End If - If o Is Nothing Then ' Noncompliant + If o Is Nothing Then ' Noncompliant End If Finally If o IsNot Nothing Then ' Noncompliant End If - If o Is Nothing Then ' Noncompliant + If o Is Nothing Then ' Noncompliant End If End Try End Sub @@ -1343,7 +1332,7 @@ Namespace Tests.Diagnostics Public Class TestNullCoalescing Public Sub CompliantMethod(ByVal input As Boolean?) - If If(input, False) Then ' Compliant + If If(input, False) Then ' Compliant Console.WriteLine("input is true") Else Console.WriteLine("input is false") @@ -1351,20 +1340,20 @@ Namespace Tests.Diagnostics End Sub Public Sub CompliantMethod1(ByVal input As Boolean?) - While If(input, False) ' Compliant + While If(input, False) ' Compliant Console.WriteLine("input is true") End While End Sub Public Sub CompliantMethod2(ByVal input As Boolean?, ByVal input1 As Boolean) - While If(input, False) AndAlso input1 ' Compliant + While If(input, False) AndAlso input1 ' Compliant Console.WriteLine("input is true") End While End Sub Public Sub CompliantMethod3(ByVal input As Boolean?, ByVal input1 As Boolean) - If If(If(input, False), input1, False) Then ' Compliant + If If(If(input, False), input1, False) Then ' Compliant Console.WriteLine("input is true") End If End Sub @@ -1374,19 +1363,19 @@ Namespace Tests.Diagnostics If If(input, False) Then ' Noncompliant Console.WriteLine("input is true") Else - Console.WriteLine("input is false") ' Secondary + Console.WriteLine("input is false") ' Secondary End If End Sub Public Sub NonCompliantMethod1() Dim input As Boolean? = True - While If(input, False) ' Noncompliant + While If(input, False) ' Noncompliant Console.WriteLine("input is true") End While End Sub Public Sub NonCompliantMethod2(ByVal input As Boolean?) - While If(input, False) OrElse True ' Compliant + While If(input, False) OrElse True ' Compliant Console.WriteLine("input is true") End While End Sub @@ -1665,44 +1654,44 @@ Namespace Tests.Diagnostics Return String.Empty End Function - Private Sub NullCoalesce_Useless(ByVal a As String, ByVal b As String, ByVal c As String, ByVal d As String) - Dim isNull As String = Nothing - Dim notNull = "" + Private Sub BinaryConditional_Useless(ByVal a As String, ByVal b As String, ByVal c As String, ByVal d As String) + Dim isNothing As String = Nothing + Dim isNotNothing = "" Dim notEmpty = "value" Dim ret As String ret = If(b, a) - ret = If(b, notNull) + ret = If(b, isNotNothing) ret = If(c, notEmpty) ret = If(d, "N/A") - 'Left operand: Values notNull and notEmpty are known to be not-null - ret = If(notNull, a) ' Noncompliant + 'Left operand: Values notNull and notEmpty are known to be not Nothing + ret = If(isNotNothing, a) ' Noncompliant ' Secondary@-1 - ret = If(notNull, a) ' Noncompliant + ret = If(isNotNothing, a) ' Noncompliant ' Secondary@-1 - ret = "Lorem " & If(notNull, a) & " ipsum" ' Noncompliant + ret = "Lorem " & If(isNotNothing, a) & " ipsum" ' Noncompliant ' Secondary@-1 - ret = If(notNull, "N/A") ' Noncompliant + ret = If(isNotNothing, "N/A") ' Noncompliant ' Secondary@-1 ret = If(notEmpty, "N/A") ' Noncompliant ' Secondary@-1 'Left operand: isNull is known to be null ret = If(Nothing, a) ' Noncompliant - ret = If(isNull, a) ' Noncompliant - ret = "Lorem " & If(isNull, a) & " ipsum" ' Noncompliant + ret = If(isNothing, a) ' Noncompliant + ret = "Lorem " & If(isNothing, a) & " ipsum" ' Noncompliant - 'Right operand: isNull is known to be null, therefore ?? is useless + 'Right operand: isNull is known to be null, therefore binary conditional expression is not needed ret = If(a, Nothing) ' FN: NOOP - ret = If(a, isNull) ' FN: NOOP + ret = If(a, isNothing) ' FN: NOOP ' ~~~~~~ 'Combo/Fatality - ret = If(notNull, isNull) + ret = If(isNotNothing, isNothing) ' ^^^^^^^ Noncompliant {{Change this expression which always evaluates to the same result. Some code paths are unreachable.}} ' ^^^^^^ Secondary@-1 - ret = If(isNull, Nothing) ' Noncompliant {{Change this expression which always evaluates to the same result.}} + ret = If(isNothing, Nothing) ' Noncompliant {{Change this expression which always evaluates to the same result.}} ' ^^^^^^ ret = If("Value", a) ' ^^^^^^^ Noncompliant {{Change this expression which always evaluates to the same result. Some code paths are unreachable.}} @@ -1733,7 +1722,7 @@ Namespace Tests.Diagnostics Dim s3 = If(s, "") Dim s4 = " " - If String.IsNullOrWhiteSpace(s1) Then ' Noncompliant + If String.IsNullOrWhiteSpace(s1) Then ' Noncompliant End If From 8d6368a20c718f07e5d2b5fccebc7169d690794e Mon Sep 17 00:00:00 2001 From: mary-georgiou-sonarsource Date: Fri, 11 Aug 2023 07:38:39 +0200 Subject: [PATCH 18/20] more nitpicks - remore namespaces --- .../ConditionEvaluatesToConstant.VB14.vb | 504 ++- .../Roslyn/ConditionEvaluatesToConstant.vb | 2735 ++++++++--------- 2 files changed, 1611 insertions(+), 1628 deletions(-) diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.VB14.vb b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.VB14.vb index 5a378e46fd7..4e73382d096 100644 --- a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.VB14.vb +++ b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.VB14.vb @@ -1,301 +1,293 @@ -Imports System - -Namespace Tests.Diagnostics - Public Class VB14 - - Private Sub ConditionalAccessNullPropagation(ByVal o As Object) - If o Is Nothing Then - If Equals(o?.ToString(), Nothing) Then - ' ^ Noncompliant - ' ^^^^^^^^^^^ Secondary@-1 - ' ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Noncompliant@-2 - End If - If o?.GetHashCode() Is Nothing Then - ' ^ Noncompliant - ' ^^^^^^^^^^^^^^ Secondary@-1 - ' ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Noncompliant@-2 - End If +Public Class VB14 + + Private Sub ConditionalAccessNullPropagation(ByVal o As Object) + If o Is Nothing Then + If Equals(o?.ToString(), Nothing) Then + ' ^ Noncompliant + ' ^^^^^^^^^^^ Secondary@-1 + ' ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Noncompliant@-2 End If - End Sub - - Friend Enum MyEnum - One - Two - End Enum - - Friend Class MyClassWithEnum - Public myEnum As MyEnum - End Class - - Public Sub EnumMemberAccess() - Dim m = New MyClassWithEnum() - Console.WriteLine(m.myEnum) - m = Nothing - If m?.myEnum = MyEnum.One Then + If o?.GetHashCode() Is Nothing Then ' ^ Noncompliant - ' ^^^^^^^ Secondary@-1 - ' ^^^^^^^^^^^^^^^^^^^^^^ Noncompliant@-2 + ' ^^^^^^^^^^^^^^ Secondary@-1 + ' ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Noncompliant@-2 End If - End Sub - - Friend Class FooContainer - Public Property Foo As Boolean - End Class - - Friend Class TestNullConditional - Private Sub First(ByVal fooContainer As FooContainer, ByVal bar As Boolean) - If fooContainer?.Foo = False OrElse bar Then - Console.WriteLine(If(bar, "1", "2")) - Else - Console.WriteLine(If(fooContainer IsNot Nothing, "3", "4")) - End If - End Sub - - Private Sub Second(ByVal fooContainer As FooContainer) - If fooContainer?.Foo <> True Then - Console.WriteLine("3") - If fooContainer IsNot Nothing Then - Console.WriteLine("4") - End If - End If - End Sub - - Public Class Result - Public Property Succeed As Boolean - - Public Shared Function Test(ByVal cond As Boolean) As Result - If cond Then - Return New Result() - End If - Return Nothing - End Function - End Class - - Public Shared Sub Compliant1(ByVal cond As Boolean) - Dim result = TestNullConditional.Result.Test(cond) - - If result Is Nothing OrElse Not result.Succeed Then - Console.WriteLine("shorted") - If result IsNot Nothing Then - Console.WriteLine("other") - End If - End If + End If + End Sub - If result?.Succeed <> True Then - Console.WriteLine("shorted") - If result IsNot Nothing Then - Console.WriteLine("other") - End If - End If - End Sub - - Public Shared Sub NonCompliant1() - Dim result As Result = Nothing - If result?.Succeed IsNot Nothing Then - ' ^^^^^^ Noncompliant - ' ^^^^^^^^ Secondary@-1 - ' ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Noncompliant@-2 - Console.WriteLine("shorted") ' Secondary - If result IsNot Nothing Then - Console.WriteLine("other") - End If - End If - End Sub - - Public Shared Sub NonCompliant2() - Dim result As Result = New Result() - If result?.Succeed IsNot Nothing Then - ' ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Noncompliant - ' ^^^^^^ Noncompliant@-1 - Console.WriteLine("shorted") - While result IsNot Nothing ' Noncompliant - Console.WriteLine("other") - End While - End If - End Sub - - Public Class A - Public Property booleanVal As Boolean - End Class - - Public Shared Sub Compliant2() - Dim aObj As A = Nothing - If If(aObj?.booleanVal, False) Then - ' ^^^^ Noncompliant - ' ^^^^^^^^^^^ Secondary@-1 - ' ^^^^^^^^^^^^^^^^ Noncompliant@-2 - Console.WriteLine("a") - End If - End Sub - - Public Shared Sub NonCompliant3() - Dim aObj As A = Nothing - If aObj?.booleanVal Is Nothing Then - ' ^^^^ Noncompliant - ' ^^^^^^^^^^^ Secondary@-1 - ' ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Noncompliant@-2 - Console.WriteLine("a") - End If + Friend Enum MyEnum + One + Two + End Enum - If aObj?.booleanVal IsNot Nothing Then - ' ^^^^ Noncompliant - ' ^^^^^^^^^^^ Secondary@-1 - ' ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Noncompliant@-2 - Console.WriteLine("a") ' Secondary - End If - End Sub + Friend Class MyClassWithEnum + Public myEnum As MyEnum + End Class - Public Shared Sub Compliant3(ByVal a As A) + Public Sub EnumMemberAccess() + Dim m = New MyClassWithEnum() + Console.WriteLine(m.myEnum) + m = Nothing + If m?.myEnum = MyEnum.One Then + ' ^ Noncompliant + ' ^^^^^^^ Secondary@-1 + ' ^^^^^^^^^^^^^^^^^^^^^^ Noncompliant@-2 + End If + End Sub + + Friend Class FooContainer + Public Property Foo As Boolean + End Class - If a?.booleanVal = True Then - Console.WriteLine("Compliant") - Return - End If + Friend Class TestNullConditional + Private Sub First(ByVal fooContainer As FooContainer, ByVal bar As Boolean) + If fooContainer?.Foo = False OrElse bar Then + Console.WriteLine(If(bar, "1", "2")) + Else + Console.WriteLine(If(fooContainer IsNot Nothing, "3", "4")) + End If + End Sub - If a IsNot Nothing Then ' Compliant + Private Sub Second(ByVal fooContainer As FooContainer) + If fooContainer?.Foo <> True Then + Console.WriteLine("3") + If fooContainer IsNot Nothing Then + Console.WriteLine("4") End If - End Sub + End If + End Sub - Public Shared Sub NonCompliant4(ByVal a As A) + Public Class Result + Public Property Succeed As Boolean - If a?.booleanVal Is Nothing Then - Console.WriteLine("Compliant") - Return + Public Shared Function Test(ByVal cond As Boolean) As Result + If cond Then + Return New Result() End If + Return Nothing + End Function + End Class - If a IsNot Nothing Then ' Noncompliant + Public Shared Sub Compliant1(ByVal cond As Boolean) + Dim result = TestNullConditional.Result.Test(cond) + + If result Is Nothing OrElse Not result.Succeed Then + Console.WriteLine("shorted") + If result IsNot Nothing Then + Console.WriteLine("other") End If - End Sub + End If - Public Shared Sub Compliant4(ByVal a As A) - If a?.booleanVal Is Nothing Then - Console.WriteLine("Compliant") + If result?.Succeed <> True Then + Console.WriteLine("shorted") + If result IsNot Nothing Then + Console.WriteLine("other") End If + End If + End Sub - If a IsNot Nothing Then ' Compliant + Public Shared Sub NonCompliant1() + Dim result As Result = Nothing + If result?.Succeed IsNot Nothing Then + ' ^^^^^^ Noncompliant + ' ^^^^^^^^ Secondary@-1 + ' ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Noncompliant@-2 + Console.WriteLine("shorted") ' Secondary + If result IsNot Nothing Then + Console.WriteLine("other") End If - End Sub + End If + End Sub - Public Shared Sub Compliant5(ByVal a As A) - While If(a?.booleanVal Is Nothing, True, False) ' Compliant - Console.WriteLine("Compliant") - End While - End Sub - - Public Shared Sub NonCompliant5() - Dim a As A = Nothing - While If(a?.booleanVal Is Nothing, True, False) - ' ^ Noncompliant - ' ^^^^^^^^^^^ Secondary@-1 - ' ^^^^^^^^^^^^^^^^^^^^^^^^ Noncompliant@-2 - ' ^^^^^ Secondary@-3 - Console.WriteLine("Compliant") + Public Shared Sub NonCompliant2() + Dim result As Result = New Result() + If result?.Succeed IsNot Nothing Then + ' ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Noncompliant + ' ^^^^^^ Noncompliant@-1 + Console.WriteLine("shorted") + While result IsNot Nothing ' Noncompliant + Console.WriteLine("other") End While - End Sub - - Public Class S - Public str As String = Nothing - End Class + End If + End Sub - Public Shared Sub Compliant6(ByVal sObj As S) - If sObj?.str?.Length > 2 Then - Console.WriteLine("a") - End If - End Sub - - Public Shared Sub NonCompliant6() - Dim sObj As S = Nothing - If sObj?.str?.Length > 2 Then - ' ^^^^ Noncompliant - ' ^^^^^^^ Secondary@-1 - ' ^^^^^^^^^^^^^^^^^^^^^ Noncompliant@-2 - Console.WriteLine("a") ' Secondary - End If - End Sub + Public Class A + Public Property booleanVal As Boolean End Class - End Class - Class ShouldExecute - - Public Sub AndAlsoExpression() - Dim c1 = True - Dim a = c1 AndAlso c1 ' Noncompliant - ' Secondary@-1 + Public Shared Sub Compliant2() + Dim aObj As A = Nothing + If If(aObj?.booleanVal, False) Then + ' ^^^^ Noncompliant + ' ^^^^^^^^^^^ Secondary@-1 + ' ^^^^^^^^^^^^^^^^ Noncompliant@-2 + Console.WriteLine("a") + End If End Sub - Public Sub TernaryConditionalExpression() - Dim c1 = True - Dim x = If(c1, c1, c1) ' Noncompliant - ' Secondary@-1 - End Sub + Public Shared Sub NonCompliant3() + Dim aObj As A = Nothing + If aObj?.booleanVal Is Nothing Then + ' ^^^^ Noncompliant + ' ^^^^^^^^^^^ Secondary@-1 + ' ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Noncompliant@-2 + Console.WriteLine("a") + End If - Public Shared Sub ConditionalAccessExpression() - Dim sObj = Nothing - Dim x = sObj?.str?.Length > 2 - ' ^^^^ Noncompliant - ' ^^^^^^^ Secondary@-1 + If aObj?.booleanVal IsNot Nothing Then + ' ^^^^ Noncompliant + ' ^^^^^^^^^^^ Secondary@-1 + ' ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Noncompliant@-2 + Console.WriteLine("a") ' Secondary + End If End Sub - Public Sub DoLoopUntilStatement() - Dim c1 = false - Do - Console.WriteLine("") - Loop Until c1 ' Noncompliant - End Sub + Public Shared Sub Compliant3(ByVal a As A) - Public Sub DoLoopWhileStatement() - Dim c1 = True - Do - Console.WriteLine("") - Loop While c1 ' Noncompliant - End Sub + If a?.booleanVal = True Then + Console.WriteLine("Compliant") + Return + End If - Public Sub DoUntilStatement() - Dim c1 = False - Do Until c1 ' Noncompliant - Console.WriteLine("") - Loop + If a IsNot Nothing Then ' Compliant + End If End Sub - Public Sub DoWhileStatement() - Dim c1 = True - Do While c1 ' Noncompliant - Console.WriteLine("") - Loop - End Sub + Public Shared Sub NonCompliant4(ByVal a As A) - Public Sub IfStatement() - Dim c1 = True - If c1 ' Noncompliant - Console.WriteLine("") + If a?.booleanVal Is Nothing Then + Console.WriteLine("Compliant") + Return + End If + + If a IsNot Nothing Then ' Noncompliant End If End Sub - Public Sub OrAlsoExpression() - Dim c1 = True - Dim a = c1 OrElse False ' Noncompliant - ' Secondary@-1 + Public Shared Sub Compliant4(ByVal a As A) + If a?.booleanVal Is Nothing Then + Console.WriteLine("Compliant") + End If + + If a IsNot Nothing Then ' Compliant + End If End Sub - Public Sub WhileStatement() - Dim c1 = True - While c1 ' Noncompliant - Console.WriteLine("") + Public Shared Sub Compliant5(ByVal a As A) + While If(a?.booleanVal Is Nothing, True, False) ' Compliant + Console.WriteLine("Compliant") End While End Sub - Public Sub SelectStatement() - Dim i = 10 - Dim b = True - Select Case i - Case 1 ' Noncompliant - b = False ' Secondary - End Select + Public Shared Sub NonCompliant5() + Dim a As A = Nothing + While If(a?.booleanVal Is Nothing, True, False) + ' ^ Noncompliant + ' ^^^^^^^^^^^ Secondary@-1 + ' ^^^^^^^^^^^^^^^^^^^^^^^^ Noncompliant@-2 + ' ^^^^^ Secondary@-3 + Console.WriteLine("Compliant") + End While End Sub - End Class - -End Namespace - + Public Class S + Public str As String = Nothing + End Class + Public Shared Sub Compliant6(ByVal sObj As S) + If sObj?.str?.Length > 2 Then + Console.WriteLine("a") + End If + End Sub + Public Shared Sub NonCompliant6() + Dim sObj As S = Nothing + If sObj?.str?.Length > 2 Then + ' ^^^^ Noncompliant + ' ^^^^^^^ Secondary@-1 + ' ^^^^^^^^^^^^^^^^^^^^^ Noncompliant@-2 + Console.WriteLine("a") ' Secondary + End If + End Sub + End Class +End Class + +Class ShouldExecute + + Public Sub AndAlsoExpression() + Dim c1 = True + Dim a = c1 AndAlso c1 ' Noncompliant + ' Secondary@-1 + End Sub + + Public Sub TernaryConditionalExpression() + Dim c1 = True + Dim x = If(c1, c1, c1) ' Noncompliant + ' Secondary@-1 + End Sub + + Public Shared Sub ConditionalAccessExpression() + Dim sObj = Nothing + Dim x = sObj?.str?.Length > 2 + ' ^^^^ Noncompliant + ' ^^^^^^^ Secondary@-1 + End Sub + + Public Sub DoLoopUntilStatement() + Dim c1 = false + Do + Console.WriteLine("") + Loop Until c1 ' Noncompliant + End Sub + + Public Sub DoLoopWhileStatement() + Dim c1 = True + Do + Console.WriteLine("") + Loop While c1 ' Noncompliant + End Sub + + Public Sub DoUntilStatement() + Dim c1 = False + Do Until c1 ' Noncompliant + Console.WriteLine("") + Loop + End Sub + + Public Sub DoWhileStatement() + Dim c1 = True + Do While c1 ' Noncompliant + Console.WriteLine("") + Loop + End Sub + + Public Sub IfStatement() + Dim c1 = True + If c1 ' Noncompliant + Console.WriteLine("") + End If + End Sub + + Public Sub OrAlsoExpression() + Dim c1 = True + Dim a = c1 OrElse False ' Noncompliant + ' Secondary@-1 + End Sub + + Public Sub WhileStatement() + Dim c1 = True + While c1 ' Noncompliant + Console.WriteLine("") + End While + End Sub + + Public Sub SelectStatement() + Dim i = 10 + Dim b = True + Select Case i + Case 1 ' Noncompliant + b = False ' Secondary + End Select + End Sub + +End Class diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.vb b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.vb index 0f2f4db1bf0..7980a1008f5 100644 --- a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.vb +++ b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.vb @@ -1,1760 +1,1751 @@ -Imports System -Imports System.Collections.Generic -Imports System.Diagnostics -Imports System.Threading.Tasks -Imports System.IO -Imports System.Linq -Imports Microsoft.Extensions.Primitives +Imports System.IO Imports System.Runtime.InteropServices -Namespace Tests.Diagnostics - Public Class ConditionEvaluatesToConstant - Private Const t As Boolean = True - Private Const f As Boolean = False - - Public Sub LoopsWithBreak(ByVal o1 As Object, ByVal o2 As Object, ByVal o3 As Object) - Dim c1, c2 As Boolean - c1 = c2 = True - While c1 ' Noncompliant - If o1 IsNot Nothing Then Exit While ' Secondary - End While - - Do - If o2 IsNot Nothing Then Exit Do - Loop While c2 ' Noncompliant - - End Sub - - Public Sub IfStatement() - Dim c1 = True - If c1 Then ' Noncompliant - Console.WriteLine("Always True") - End If - End Sub - - Private Sub UsingStatement() - Using writer As TextWriter = Nothing - If writer IsNot Nothing Then ' Noncompliant - Console.WriteLine("Hello world") ' Secondary - End If - End Using - End Sub - - Public Sub DoesNotRaiseForConst() - If t Then ' Compliant - no issue is raised for const fields. - Console.WriteLine("Do stuff") - End If - End Sub - - Public Sub NotExecutedLoops(ByVal o1 As Object, ByVal o2 As Object, ByVal o3 As Object) - Dim c1, c2, c3 As Boolean - c1 = c2 = c3 = False - - While c1 ' Noncompliant {{Change this condition so that it does not always evaluate to 'False'. Some code paths are unreachable.}} - If o1 IsNot Nothing Then Exit While ' Secondary - End While - - Do - If o2 IsNot Nothing Then Exit Do +Public Class ConditionEvaluatesToConstant + Private Const t As Boolean = True + Private Const f As Boolean = False + + Public Sub LoopsWithBreak(ByVal o1 As Object, ByVal o2 As Object, ByVal o3 As Object) + Dim c1, c2 As Boolean + c1 = c2 = True + While c1 ' Noncompliant + If o1 IsNot Nothing Then Exit While ' Secondary + End While + + Do + If o2 IsNot Nothing Then Exit Do + Loop While c2 ' Noncompliant + + End Sub + + Public Sub IfStatement() + Dim c1 = True + If c1 Then ' Noncompliant + Console.WriteLine("Always True") + End If + End Sub + + Private Sub UsingStatement() + Using writer As TextWriter = Nothing + If writer IsNot Nothing Then ' Noncompliant + Console.WriteLine("Hello world") ' Secondary + End If + End Using + End Sub + + Public Sub DoesNotRaiseForConst() + If t Then ' Compliant - no issue is raised for const fields. + Console.WriteLine("Do stuff") + End If + End Sub + + Public Sub NotExecutedLoops(ByVal o1 As Object, ByVal o2 As Object, ByVal o3 As Object) + Dim c1, c2, c3 As Boolean + c1 = c2 = c3 = False + + While c1 ' Noncompliant {{Change this condition so that it does not always evaluate to 'False'. Some code paths are unreachable.}} + If o1 IsNot Nothing Then Exit While ' Secondary + End While + + Do + If o2 IsNot Nothing Then Exit Do + + Loop While c2 ' Noncompliant {{Change this condition so that it does not always evaluate to 'False'.}} + ' ^^ + End Sub + + Public Sub BreakInLoop(ByVal o As Object) + Dim c = True + While c ' Noncompliant + If o IsNot Nothing Then Exit While + End While + End Sub + + Public Sub ReturnInLoop(ByVal o As Object) + Dim c = True + While c ' Noncompliant + If o IsNot Nothing Then Return + End While + End Sub + + Public Sub ThrowInLoop(ByVal o As Object) + Dim c = True + While c ' Noncompliant + If o IsNot Nothing Then Throw New Exception() + End While + End Sub + + Public Sub ConstField(ByVal a As Boolean, ByVal b As Boolean) + + Dim x = t OrElse a OrElse b ' Compliant t is const + + If t = True Then ' Noncompliant + Console.WriteLine("") + End If + + End Sub + + Public Sub Foo1(ByVal a As Boolean, ByVal b As Boolean) + Dim l = True + Dim x = l OrElse a OrElse b + ' ^ Noncompliant + ' ^^^^^^^^^^ Secondary@-1 + End Sub + + Public Sub Foo2(ByVal a As Boolean, ByVal b As Boolean) + Dim l = True + Dim x = l OrElse a OrElse b + ' ^ Noncompliant + ' ^^^^^^^^^^ Secondary@-1 + + End Sub + + Public Sub Foo3(ByVal a As Boolean, ByVal b As Boolean) + Dim l = True + Dim x = l OrElse a OrElse b + ' ^ Noncompliant + ' ^^^^^^^^^^ Secondary@-1 + End Sub + + Public Sub Foo4(ByVal a As Boolean, ByVal b As Boolean) + Dim l = True + Dim m = False + Dim x = m OrElse l OrElse a OrElse b + ' ^ Noncompliant + ' ^ Noncompliant@-1 + ' ^^^^^^^^^^ Secondary@-2 + + End Sub + + Public Sub Foo5(ByVal a As Boolean, ByVal b As Boolean) + Dim l = True + Dim m = False + Dim x = m AndAlso l OrElse a OrElse b + ' ^ Noncompliant + ' ^ Secondary@-1 + End Sub + + Public Sub Foo6(ByVal a As Boolean, ByVal b As Boolean) + Dim l = True + Dim x = If(l OrElse a, a, b) + ' ^ Noncompliant + ' ^ Secondary@-1 + ' ^ Secondary@-2 + End Sub + + Public Sub Foo7(ByVal a As Boolean, ByVal b As Boolean) + Dim l = True + If If(l OrElse a, a, b) OrElse b Then + ' ^ Noncompliant + ' ^ Secondary@-1 + ' ^ Secondary@-2 + End If + End Sub + + Private Sub TestNameof(ByVal s As String) + If Equals(Nothing, NameOf(Method1)) Then ' FN FIX + End If + End Sub + + Public Sub Method1() + Dim b = True + If b Then ' Noncompliant + Console.WriteLine() + Else + ' secondary location covers all unreachable code blocks: + Console.WriteLine(1) ' Secondary ^13#103 + While b + Console.WriteLine(2) + End While ' the secondary location ends at the end of the above line + End If + + Console.WriteLine() + End Sub + + Public Sub Method2() + Dim b = True + If b Then ' Noncompliant + Console.WriteLine() + End If - Loop While c2 ' Noncompliant {{Change this condition so that it does not always evaluate to 'False'.}} - ' ^^ - End Sub + If Not b Then ' Noncompliant + Console.WriteLine() ' Secondary + End If - Public Sub BreakInLoop(ByVal o As Object) - Dim c = True - While c ' Noncompliant - If o IsNot Nothing Then Exit While - End While - End Sub + Console.WriteLine() + End Sub - Public Sub ReturnInLoop(ByVal o As Object) - Dim c = True - While c ' Noncompliant - If o IsNot Nothing Then Return - End While - End Sub + Public Sub Method2Literals() + If True Then ' Compliant + Console.WriteLine() + End If - Public Sub ThrowInLoop(ByVal o As Object) - Dim c = True - While c ' Noncompliant - If o IsNot Nothing Then Throw New Exception() - End While - End Sub + If False Then ' Compliant + Console.WriteLine() + End If - Public Sub ConstField(ByVal a As Boolean, ByVal b As Boolean) + Console.WriteLine() + End Sub - Dim x = t OrElse a OrElse b ' Compliant t is const + Public Sub Method3() + Dim b As Boolean + TryGet(b) + If b Then + End If + End Sub - If t = True Then ' Noncompliant - Console.WriteLine("") - End If + Private Sub TryGet( ByRef b As Boolean) + b = False + End Sub - End Sub + Public Sub Method3(ByVal cond As Boolean) + While cond + Console.WriteLine() + End While - Public Sub Foo1(ByVal a As Boolean, ByVal b As Boolean) - Dim l = True - Dim x = l OrElse a OrElse b - ' ^ Noncompliant - ' ^^^^^^^^^^ Secondary@-1 - End Sub + Dim b = True + While b ' Noncompliant + Console.WriteLine() + End While - Public Sub Foo2(ByVal a As Boolean, ByVal b As Boolean) - Dim l = True - Dim x = l OrElse a OrElse b - ' ^ Noncompliant - ' ^^^^^^^^^^ Secondary@-1 + Console.WriteLine() ' Secondary + End Sub - End Sub + Public Sub Method4(ByVal cond As Boolean) + Dim i = 10 + While i < 20 + i = i + 1 + End While - Public Sub Foo3(ByVal a As Boolean, ByVal b As Boolean) - Dim l = True - Dim x = l OrElse a OrElse b - ' ^ Noncompliant - ' ^^^^^^^^^^ Secondary@-1 - End Sub + Dim b = True + While b ' Noncompliant + Console.WriteLine() + End While - Public Sub Foo4(ByVal a As Boolean, ByVal b As Boolean) - Dim l = True - Dim m = False - Dim x = m OrElse l OrElse a OrElse b - ' ^ Noncompliant - ' ^ Noncompliant@-1 - ' ^^^^^^^^^^ Secondary@-2 + Console.WriteLine() ' Secondary + End Sub - End Sub + Public Sub Method5() + While True ' Compliant + Console.WriteLine() + End While - Public Sub Foo5(ByVal a As Boolean, ByVal b As Boolean) - Dim l = True - Dim m = False - Dim x = m AndAlso l OrElse a OrElse b - ' ^ Noncompliant - ' ^ Secondary@-1 - End Sub + Console.WriteLine() + End Sub - Public Sub Foo6(ByVal a As Boolean, ByVal b As Boolean) - Dim l = True - Dim x = If(l OrElse a, a, b) - ' ^ Noncompliant - ' ^ Secondary@-1 - ' ^ Secondary@-2 - End Sub - Public Sub Foo7(ByVal a As Boolean, ByVal b As Boolean) - Dim l = True - If If(l OrElse a, a, b) OrElse b Then - ' ^ Noncompliant - ' ^ Secondary@-1 - ' ^ Secondary@-2 - End If - End Sub + Public Sub Method_Select() + Dim i = 10 + Dim b = True + Select Case i + Case 1 ' Noncompliant + b = False ' Secondary + End Select - Private Sub TestNameof(ByVal s As String) - If Equals(Nothing, NameOf(Method1)) Then ' FN FIX - End If - End Sub + If b Then ' Noncompliant + Else + End If + End Sub - Public Sub Method1() - Dim b = True - If b Then ' Noncompliant + Public Sub Method_Select_Learn(ByVal cond As Boolean) + Select Case cond + Case True + If cond Then ' Noncompliant + Console.WriteLine() + End If + End Select + End Sub + + Public Property Property1 As Boolean + Get + Dim a = New Action(Sub() + Dim b = True + If b Then ' Noncompliant + Console.WriteLine() + Else + Console.WriteLine() ' Secondary + End If + End Sub) + Return True + End Get + Set(ByVal value As Boolean) + value = True + If value Then ' Noncompliant Console.WriteLine() Else - ' secondary location covers all unreachable code blocks: - Console.WriteLine(1) ' Secondary ^17#108 - While b - Console.WriteLine(2) - End While ' the secondary location ends at the end of the above line + Console.WriteLine() ' Secondary End If + End Set + End Property - Console.WriteLine() - End Sub + Public Shared ReadOnly Property Prop As Boolean + Get + Return Prop + End Get + End Property - Public Sub Method2() - Dim b = True - If b Then ' Noncompliant - Console.WriteLine() - End If + Public Sub Method_Complex() + Dim guard1 = True + Dim guard2 = True + Dim guard3 = True - If Not b Then ' Noncompliant - Console.WriteLine() ' Secondary + While GetCondition() + If guard1 Then + guard1 = False + Else + If guard2 Then ' Noncompliant FP: loop is only analyzed twice + guard2 = False + Else + guard3 = False ' Secondary FP + End If End If + End While + If guard3 Then ' Noncompliant FP: loop is only analyzed twice Console.WriteLine() - End Sub + End If + End Sub - Public Sub Method2Literals() - If True Then ' Compliant - Console.WriteLine() - End If + Public Sub Method_Complex_2() + Dim x = False + Dim y = False - If False Then ' Compliant - Console.WriteLine() - End If + While GetCondition() + While GetCondition() + If x Then + If y Then ' Noncompliant FP: loop is only analyzed twice + End If + End If + y = True + End While + x = True + End While + End Sub + Private Shared Function GetObject() As Object + Return Nothing + End Function + Public Sub M() - Console.WriteLine() - End Sub + Dim o1 = GetObject() + Dim o2 As Object = Nothing - Public Sub Method3() - Dim b As Boolean - TryGet(b) - If b Then + If o1 IsNot Nothing Then + If Not Equals(o1.ToString(), Nothing) Then + o2 = New Object() End If - End Sub + End If - Private Sub TryGet( ByRef b As Boolean) - b = False - End Sub + If o2 Is Nothing Then + End If - Public Sub Method3(ByVal cond As Boolean) - While cond - Console.WriteLine() - End While + End Sub - Dim b = True - While b ' Noncompliant - Console.WriteLine() - End While + Public Sub NullableStructs() + Dim i As Integer? = Nothing - Console.WriteLine() ' Secondary - End Sub + If i Is Nothing Then ' Noncompliant, always true + Console.WriteLine(i) + End If - Public Sub Method4(ByVal cond As Boolean) - Dim i = 10 - While i < 20 - i = i + 1 - End While + i = New Integer?() + If i Is Nothing Then ' Noncompliant + End If - Dim b = True - While b ' Noncompliant - Console.WriteLine() - End While + Dim ii = "" + If ii Is Nothing Then ' Noncompliant, always false + Console.WriteLine(ii) ' Secondary + End If + End Sub - Console.WriteLine() ' Secondary - End Sub + Private Shared Function GetCondition() As Boolean + Return True + End Function - Public Sub Method5() - While True ' Compliant - Console.WriteLine() - End While + Public Sub Lambda(ByVal condition As Boolean) - Console.WriteLine() - End Sub + Dim fail = False + Dim a As Action = New Action(Sub() fail = condition) + a() + If fail Then ' Noncompliant FP + End If + End Sub - Public Sub Method_Select() - Dim i = 10 - Dim b = True - Select Case i - Case 1 ' Noncompliant - b = False ' Secondary - End Select + Public Sub Constraint(ByVal cond As Boolean) + Dim a = cond + Dim b = a + If a Then + If b Then ' FN: requires relation support - If b Then ' Noncompliant - Else End If - End Sub - - Public Sub Method_Select_Learn(ByVal cond As Boolean) - Select Case cond - Case True - If cond Then ' Noncompliant - Console.WriteLine() - End If - End Select - End Sub + End If + End Sub - Public Property Property1 As Boolean - Get - Dim a = New Action(Sub() - Dim b = True - If b Then ' Noncompliant - Console.WriteLine() - Else - Console.WriteLine() ' Secondary - End If - End Sub) - Return True - End Get - Set(ByVal value As Boolean) - value = True - If value Then ' Noncompliant - Console.WriteLine() - Else - Console.WriteLine() ' Secondary - End If - End Set - End Property + Public Sub Stack(ByVal cond As Boolean) + Dim a = cond + Dim b = a - Public Shared ReadOnly Property Prop As Boolean - Get - Return Prop - End Get - End Property - - Public Sub Method_Complex() - Dim guard1 = True - Dim guard2 = True - Dim guard3 = True - - While GetCondition() - If guard1 Then - guard1 = False - Else - If guard2 Then ' Noncompliant FP: loop is only analyzed twice - guard2 = False - Else - guard3 = False ' Secondary FP - End If - End If - End While - - If guard3 Then ' Noncompliant FP: loop is only analyzed twice - Console.WriteLine() + If Not a Then + If b Then ' FN: requires relation support End If - End Sub + End If - Public Sub Method_Complex_2() - Dim x = False - Dim y = False + Dim fail = False + Dim ac As Action = New Action(Sub() fail = cond) - While GetCondition() - While GetCondition() - If x Then - If y Then ' Noncompliant FP: loop is only analyzed twice - End If - End If - y = True - End While - x = True - End While - End Sub - Private Shared Function GetObject() As Object - Return Nothing - End Function - Public Sub M() + ac() - Dim o1 = GetObject() - Dim o2 As Object = Nothing + If Not fail Then ' Noncompliant FP + End If + End Sub - If o1 IsNot Nothing Then - If Not Equals(o1.ToString(), Nothing) Then - o2 = New Object() - End If + Public Sub BooleanBinary(ByVal a As Boolean, ByVal b As Boolean) + If a And Not b Then + If a Then ' FN: engine doesn't learn BoolConstraints from binary operators End If - - If o2 Is Nothing Then + If b Then ' FN: engine doesn't learn BoolConstraints from binary operators End If - End Sub - - Public Sub NullableStructs() - Dim i As Integer? = Nothing + End If - If i Is Nothing Then ' Noncompliant, always true - Console.WriteLine(i) + If Not (a Or b) Then + If a Then ' FN: engine doesn't learn BoolConstraints from binary operators End If - i = New Integer?() - If i Is Nothing Then ' Noncompliant - End If + End If - Dim ii = "" - If ii Is Nothing Then ' Noncompliant, always false - Console.WriteLine(ii) ' Secondary + If a Xor b Then + If Not a Xor Not b Then ' FN: engine doesn't learn BoolConstraints from binary operators End If - End Sub + End If - Private Shared Function GetCondition() As Boolean - Return True - End Function + a = False + If a And b Then ' Noncompliant + End If - Public Sub Lambda(ByVal condition As Boolean) + a = a Or True + If a Then ' Noncompliant + End If - Dim fail = False - Dim a As Action = New Action(Sub() fail = condition) - a() + a = a Or True + If a Then ' Noncompliant + End If - If fail Then ' Noncompliant FP - End If - End Sub + a = a Xor True + If a Then ' Noncompliant + End If - Public Sub Constraint(ByVal cond As Boolean) - Dim a = cond - Dim b = a - If a Then - If b Then ' FN: requires relation support + a = a Xor True + If a Then ' Noncompliant + End If + End Sub - End If - End If - End Sub + Public Sub CompoundAssignment(ByVal a As Boolean, ByVal b As Boolean) + ' https://learn.microsoft.com/en-us/dotnet/visual-basic/language-reference/operators/assignment-operators + a &=True + If a Then ' FN + End If - Public Sub Stack(ByVal cond As Boolean) - Dim a = cond - Dim b = a + a ^=True + If a Then ' FN + End If + End Sub - If Not a Then - If b Then ' FN: requires relation support - End If - End If + Public Sub IsAsExpression(ByVal o As Object) - Dim fail = False - Dim ac As Action = New Action(Sub() fail = cond) + If TypeOf o Is String Then + End If - ac() + Dim oo As Object = TryCast(o, String) + If oo Is Nothing Then + End If - If Not fail Then ' Noncompliant FP - End If - End Sub + o = Nothing + If TypeOf o Is Object Then ' Noncompliant + End If - Public Sub BooleanBinary(ByVal a As Boolean, ByVal b As Boolean) - If a And Not b Then - If a Then ' FN: engine doesn't learn BoolConstraints from binary operators - End If - If b Then ' FN: engine doesn't learn BoolConstraints from binary operators - End If + oo = TryCast(o, Object) + If oo Is Nothing Then ' Noncompliant + End If + End Sub + Public Overloads Sub Equals(ByVal b As Boolean) + Dim a = True + If a = b Then + If b Then ' Noncompliant End If - - If Not (a Or b) Then - If a Then ' FN: engine doesn't learn BoolConstraints from binary operators - End If - + Else + If b Then ' Noncompliant End If + End If - If a Xor b Then - If Not a Xor Not b Then ' FN: engine doesn't learn BoolConstraints from binary operators - End If + If Not a = b Then + If b Then ' Noncompliant End If - - a = False - If a And b Then ' Noncompliant + Else + If b Then ' Noncompliant End If + End If + End Sub - a = a Or True - If a Then ' Noncompliant + Public Sub NotEquals(ByVal b As Boolean) + Dim a = True + If a <> b Then + If b Then ' Noncompliant End If - - a = a Or True - If a Then ' Noncompliant + Else + If b Then ' Noncompliant End If + End If - a = a Xor True - If a Then ' Noncompliant + If Not a <> b Then + If b Then ' Noncompliant End If - - a = a Xor True - If a Then ' Noncompliant + Else + If b Then ' Noncompliant End If - End Sub + End If + End Sub - Public Sub CompoundAssignment(ByVal a As Boolean, ByVal b As Boolean) - ' https://learn.microsoft.com/en-us/dotnet/visual-basic/language-reference/operators/assignment-operators - a &=True - If a Then ' FN + Public Sub EqRelations(ByVal a As Boolean, ByVal b As Boolean) + If a = b Then + If b = a Then ' FN: requires relation support End If - - a ^=True - If a Then ' FN + If b = Not a Then ' FN: requires relation support End If - End Sub - - Public Sub IsAsExpression(ByVal o As Object) - - If TypeOf o Is String Then + If Not b = Not Not a Then ' FN: requires relation support End If - - Dim oo As Object = TryCast(o, String) - If oo Is Nothing Then + If Not a = b Then ' FN: requires relation support End If - - o = Nothing - If TypeOf o Is Object Then ' Noncompliant + Else + If b <> a Then ' FN: requires relation support End If - - oo = TryCast(o, Object) - If oo Is Nothing Then ' Noncompliant + If b <> Not a Then ' FN: requires relation support End If - End Sub - - Public Overloads Sub Equals(ByVal b As Boolean) - Dim a = True - If a = b Then - If b Then ' Noncompliant - End If - Else - If b Then ' Noncompliant - End If - End If - - If Not a = b Then - If b Then ' Noncompliant - End If - Else - If b Then ' Noncompliant - End If + If Not b <> Not Not a Then ' FN: requires relation support End If - End Sub - Public Sub NotEquals(ByVal b As Boolean) - Dim a = True - If a <> b Then - If b Then ' Noncompliant - End If - Else - If b Then ' Noncompliant - End If - End If + End If - If Not a <> b Then - If b Then ' Noncompliant - End If - Else - If b Then ' Noncompliant - End If + If a <> b Then + If b = a Then ' FN: requires relation support End If - End Sub - - Public Sub EqRelations(ByVal a As Boolean, ByVal b As Boolean) - If a = b Then - If b = a Then ' FN: requires relation support - End If - If b = Not a Then ' FN: requires relation support - End If - If Not b = Not Not a Then ' FN: requires relation support - End If - If Not a = b Then ' FN: requires relation support - End If - Else - If b <> a Then ' FN: requires relation support - End If - If b <> Not a Then ' FN: requires relation support - End If - If Not b <> Not Not a Then ' FN: requires relation support - End If - + Else + If b <> a Then ' FN: requires relation support End If + End If + End Sub - If a <> b Then - If b = a Then ' FN: requires relation support - End If - Else - If b <> a Then ' FN: requires relation support - End If - End If - End Sub + Private Shared Sub BackPropagation(ByVal a As Object, ByVal b As Object) + If a Is b AndAlso b Is Nothing Then + a.ToString() + End If + End Sub - Private Shared Sub BackPropagation(ByVal a As Object, ByVal b As Object) - If a Is b AndAlso b Is Nothing Then - a.ToString() + Public Sub RefEqualsImpliesValueEquals(ByVal a As Object, ByVal b As Object) + If Object.ReferenceEquals(a, b) Then + If Equals(a, b) Then ' FN End If - End Sub - - Public Sub RefEqualsImpliesValueEquals(ByVal a As Object, ByVal b As Object) - If Object.ReferenceEquals(a, b) Then - If Equals(a, b) Then ' FN - End If - If Equals(a, b) Then ' FN - End If - If a.Equals(b) Then ' FN - End If + If Equals(a, b) Then ' FN End If - - If Me Is a Then - If Equals(a) Then ' FN - End If - If Equals(a) Then ' FN - End If + If a.Equals(b) Then ' FN End If - End Sub + End If - Public Sub ValueEqualsDoesNotImplyRefEquals(ByVal a As Object, ByVal b As Object) - If Equals(a, b) Then ' 'a' could override Equals, so this is not a ref equality check - If a Is b Then - End If ' Compliant + If Me Is a Then + If Equals(a) Then ' FN End If - End Sub - - Public Sub ReferenceEqualsMethodCalls(ByVal a As Object, ByVal b As Object) - If Object.ReferenceEquals(a, b) Then - If a Is b Then - End If ' FN + If Equals(a) Then ' FN End If + End If + End Sub + Public Sub ValueEqualsDoesNotImplyRefEquals(ByVal a As Object, ByVal b As Object) + If Equals(a, b) Then ' 'a' could override Equals, so this is not a ref equality check If a Is b Then - If Object.ReferenceEquals(a, b) Then - End If ' FN - End If - End Sub - - Public Sub ReferenceEqualsMethodCallWithOpOverload(ByVal a As ConditionEvaluatesToConstant, ByVal b As ConditionEvaluatesToConstant) - If Object.ReferenceEquals(a, b) Then - If a Is b Then ' FN - End If - End If + End If ' Compliant + End If + End Sub + Public Sub ReferenceEqualsMethodCalls(ByVal a As Object, ByVal b As Object) + If Object.ReferenceEquals(a, b) Then If a Is b Then - If Object.ReferenceEquals(a, b) Then ' Compliant, == is doing a value comparison above. FIX - End If - End If - End Sub + End If ' FN + End If - Public Sub ReferenceEquals(ByVal a As Object, ByVal b As Object) + If a Is b Then If Object.ReferenceEquals(a, b) Then - End If - - If Object.ReferenceEquals(a, a) Then End If ' FN + End If + End Sub - a = Nothing - If Object.ReferenceEquals(Nothing, a) Then ' Noncompliant - End If - If Object.ReferenceEquals(a, a) Then ' Noncompliant + Public Sub ReferenceEqualsMethodCallWithOpOverload(ByVal a As ConditionEvaluatesToConstant, ByVal b As ConditionEvaluatesToConstant) + If Object.ReferenceEquals(a, b) Then + If a Is b Then ' FN End If + End If - If Object.ReferenceEquals(Nothing, New Object()) Then ' Noncompliant + If a Is b Then + If Object.ReferenceEquals(a, b) Then ' Compliant, == is doing a value comparison above. FIX End If + End If + End Sub - ' Because of boxing: - Dim i = 10 - If Object.ReferenceEquals(i, i) Then ' FN - End If + Public Sub ReferenceEquals(ByVal a As Object, ByVal b As Object) + If Object.ReferenceEquals(a, b) Then + End If - Dim ii As Integer? = Nothing - Dim jj As Integer? = Nothing - If Object.ReferenceEquals(ii, jj) Then ' Noncompliant - End If + If Object.ReferenceEquals(a, a) Then + End If ' FN - jj = 10 - If Object.ReferenceEquals(ii, jj) Then ' Noncompliant - End If - End Sub + a = Nothing + If Object.ReferenceEquals(Nothing, a) Then ' Noncompliant + End If + If Object.ReferenceEquals(a, a) Then ' Noncompliant + End If - Public Sub ReferenceEqualsBool() - Dim a, b As Boolean - a = b = True - If Object.ReferenceEquals(a, b) Then ' FN - End If - End Sub + If Object.ReferenceEquals(Nothing, New Object()) Then ' Noncompliant + End If - Public Overrides Function Equals(ByVal obj As Object) As Boolean - Return MyBase.Equals(obj) - End Function + ' Because of boxing: + Dim i = 10 + If Object.ReferenceEquals(i, i) Then ' FN + End If - Public Shared Operator =(ByVal a As ConditionEvaluatesToConstant, ByVal b As ConditionEvaluatesToConstant) As Boolean - Return False - End Operator + Dim ii As Integer? = Nothing + Dim jj As Integer? = Nothing + If Object.ReferenceEquals(ii, jj) Then ' Noncompliant + End If - Public Shared Operator <>(ByVal a As ConditionEvaluatesToConstant, ByVal b As ConditionEvaluatesToConstant) As Boolean - Return False - End Operator + jj = 10 + If Object.ReferenceEquals(ii, jj) Then ' Noncompliant + End If + End Sub - Public Sub StringEmpty(ByVal s1 As String) - Dim s As String = Nothing - If String.IsNullOrEmpty(s) Then ' Noncompliant - End If - If String.IsNullOrWhiteSpace(s) Then ' Noncompliant - End If - If Not Equals(String.IsInterned(s), Nothing) Then - End If - s = "" - If String.IsNullOrEmpty(s) Then ' FN - End If - - If String.IsNullOrWhiteSpace(s) Then ' FN - End If + Public Sub ReferenceEqualsBool() + Dim a, b As Boolean + a = b = True + If Object.ReferenceEquals(a, b) Then ' FN + End If + End Sub - If String.IsNullOrEmpty(s1) Then ' Compliant, we don't know anything about the argument - End If + Public Overrides Function Equals(ByVal obj As Object) As Boolean + Return MyBase.Equals(obj) + End Function - If String.IsNullOrWhiteSpace(s1) Then ' Compliant - End If + Public Shared Operator =(ByVal a As ConditionEvaluatesToConstant, ByVal b As ConditionEvaluatesToConstant) As Boolean + Return False + End Operator - If String.IsNullOrEmpty(s1) Then - If String.IsNullOrEmpty(s1) Then ' FN - End If - End If - End Sub - - Public Sub Comparisons(ByVal i As Integer, ByVal j As Integer) - If i < j Then - If j < i Then ' FN - End If - If j <= i Then ' FN - End If - If j = i Then ' FN - End If - If j <> i Then ' FN - End If - End If - End Sub - - Private Sub ValueEquals(ByVal i As Integer, ByVal j As Integer) - If i = j Then - If Equals(i, j) Then ' FN - End If - If i.Equals(j) Then ' FN - End If - End If - End Sub + Public Shared Operator <>(ByVal a As ConditionEvaluatesToConstant, ByVal b As ConditionEvaluatesToConstant) As Boolean + Return False + End Operator - Private Sub DefaultExpression(ByVal o As Object) - If Nothing Is Nothing Then ' Noncompliant - End If + Public Sub StringEmpty(ByVal s1 As String) + Dim s As String = Nothing + If String.IsNullOrEmpty(s) Then ' Noncompliant + End If + If String.IsNullOrWhiteSpace(s) Then ' Noncompliant + End If + If Not Equals(String.IsInterned(s), Nothing) Then + End If + s = "" + If String.IsNullOrEmpty(s) Then ' FN + End If - Dim nullableInt As Integer? = Nothing - If nullableInt Is Nothing Then ' Noncompliant - End If + If String.IsNullOrWhiteSpace(s) Then ' FN + End If - If Nothing Is Nothing Then ' Noncompliant - End If + If String.IsNullOrEmpty(s1) Then ' Compliant, we don't know anything about the argument + End If - If Nothing IsNot Nothing Then ' Noncompliant - End If + If String.IsNullOrWhiteSpace(s1) Then ' Compliant + End If - If Nothing IsNot Nothing Then ' Noncompliant + If String.IsNullOrEmpty(s1) Then + If String.IsNullOrEmpty(s1) Then ' FN End If - End Sub + End If + End Sub - Private Sub Cast() - Dim i = 5 - Dim o = CObj(i) - If o Is Nothing Then ' Noncompliant + Public Sub Comparisons(ByVal i As Integer, ByVal j As Integer) + If i < j Then + If j < i Then ' FN End If - - Dim x = CType(o, ConditionEvaluatesToConstant) ' This would throw and invalid cast exception - If x Is Nothing Then ' Noncompliant + If j <= i Then ' FN End If - - End Sub - - Public Async Function NotNullAfterAccess(ByVal o As Object, ByVal arr As Integer(,), ByVal coll As IEnumerable(Of Integer), ByVal task As Task) As Task - Console.WriteLine(o.ToString()) - If o Is Nothing Then ' Noncompliant + If j = i Then ' FN End If - - - Console.WriteLine(arr(42, 42)) - If arr Is Nothing Then ' Noncompliant + If j <> i Then ' FN End If + End If + End Sub - - For Each item In coll - Next - If coll Is Nothing Then ' Noncompliant + Private Sub ValueEquals(ByVal i As Integer, ByVal j As Integer) + If i = j Then + If Equals(i, j) Then ' FN End If - - - Await task - If task Is Nothing Then ' FN + If i.Equals(j) Then ' FN End If + End If + End Sub - End Function + Private Sub DefaultExpression(ByVal o As Object) + If Nothing Is Nothing Then ' Noncompliant + End If - Public Sub EqualsTest32(ByVal o As Object) - Dim o2 = o - If o Is o2 Then ' FN - End If - If Object.ReferenceEquals(o, o2) Then ' FN - End If - If o.Equals(o2) Then ' FN - End If - If Equals(o2, o) Then ' FN - End If + Dim nullableInt As Integer? = Nothing + If nullableInt Is Nothing Then ' Noncompliant + End If + If Nothing Is Nothing Then ' Noncompliant + End If - Dim i = 1 - Dim j = i - If i = j Then ' Noncompliant - End If + If Nothing IsNot Nothing Then ' Noncompliant + End If - If i.Equals(j) Then ' FN - End If + If Nothing IsNot Nothing Then ' Noncompliant + End If + End Sub - If Equals(i, j) Then ' FN - End If - End Sub + Private Sub Cast() + Dim i = 5 + Dim o = CObj(i) + If o Is Nothing Then ' Noncompliant + End If - Private Async Function Test_Await_Constraint(ByVal t As Task(Of String)) As Task - If t IsNot Nothing Then - Dim o = Await t - If Equals(o, Nothing) Then ' Compliant, might be null - End If - End If - End Function + Dim x = CType(o, ConditionEvaluatesToConstant) ' This would throw and invalid cast exception + If x Is Nothing Then ' Noncompliant + End If - Public Sub Assert(ByVal condition As Boolean, ByVal o1 As Object) - Debug.Assert(condition) + End Sub - If condition Then ' Noncompliant - End If + Public Async Function NotNullAfterAccess(ByVal o As Object, ByVal arr As Integer(,), ByVal coll As IEnumerable(Of Integer), ByVal task As Task) As Task + Console.WriteLine(o.ToString()) + If o Is Nothing Then ' Noncompliant + End If - Trace.Assert(condition) ' Compliant - If o1 IsNot Nothing Then - Debug.Assert(o1 Is Nothing, "Some message", "More details", 1, 2, 3) ' Compliant - End If - End Sub + Console.WriteLine(arr(42, 42)) + If arr Is Nothing Then ' Noncompliant + End If - Public Sub Assert(ByVal o1 As Object) - Debug.Assert(o1 IsNot Nothing) - Debug.Assert(o1 Is Nothing) - End Sub - Private Sub ComparisonTransitivity(ByVal a As Integer, ByVal b As Integer, ByVal c As Integer) - If a = b AndAlso b < c Then - If a >= c Then ' FN - End If - - End If - If a = b AndAlso b <= c Then - If a > c Then ' FN - End If + For Each item In coll + Next + If coll Is Nothing Then ' Noncompliant + End If - End If - If a > b AndAlso b > c Then - If a <= c Then ' FN - End If - End If - If a > b AndAlso b >= c Then - If a <= c Then ' FN - End If + Await task + If task Is Nothing Then ' FN + End If - End If - If a >= b AndAlso b >= c Then - If a < c Then ' FN - End If + End Function - End If - If a >= b AndAlso c <= b Then - If a < c Then ' FN - End If + Public Sub EqualsTest32(ByVal o As Object) + Dim o2 = o + If o Is o2 Then ' FN + End If + If Object.ReferenceEquals(o, o2) Then ' FN + End If + If o.Equals(o2) Then ' FN + End If + If Equals(o2, o) Then ' FN + End If - End If - If a >= b AndAlso c >= b Then - If a < c Then - End If - End If - End Sub - Friend Class Comp - Public Shared Operator <(ByVal a As Comp, ByVal b As Comp) As Boolean - Return True - End Operator - Public Shared Operator >(ByVal a As Comp, ByVal b As Comp) As Boolean - Return True - End Operator - Public Shared Operator >=(ByVal a As Comp, ByVal b As Comp) As Boolean - Return True - End Operator - Public Shared Operator <=(ByVal a As Comp, ByVal b As Comp) As Boolean - Return True - End Operator - End Class - - Private Sub RefEqTransitivity(ByVal a As Comp, ByVal b As Comp, ByVal c As Comp) - If a Is b AndAlso b Is c Then - If a IsNot c Then ' FN - End If - End If + Dim i = 1 + Dim j = i + If i = j Then ' Noncompliant + End If - If a.Equals(b) AndAlso b Is c Then - If a IsNot c Then - End If - If a Is c Then - End If - If a.Equals(c) Then ' FN - End If - If Not a.Equals(c) Then ' FN - End If - End If + If i.Equals(j) Then ' FN + End If - If a > b AndAlso b Is c Then - If a <= c Then ' FN - End If - End If - End Sub + If Equals(i, j) Then ' FN + End If + End Sub - Private Sub ValueEqTransitivity(ByVal a As Comp, ByVal b As Comp, ByVal c As Comp) - If a Is b AndAlso b.Equals(c) Then - If a.Equals(c) Then ' FN - End If + Private Async Function Test_Await_Constraint(ByVal t As Task(Of String)) As Task + If t IsNot Nothing Then + Dim o = Await t + If Equals(o, Nothing) Then ' Compliant, might be null End If + End If + End Function - If a.Equals(b) AndAlso b.Equals(c) Then - If a IsNot c Then - End If - If a Is c Then - End If - If a.Equals(c) Then ' FN - End If - If Not a.Equals(c) Then ' FN - End If - End If + Public Sub Assert(ByVal condition As Boolean, ByVal o1 As Object) + Debug.Assert(condition) - If a > b AndAlso b.Equals(c) Then - If a > c Then ' FN - End If - If a <= c Then ' FN - End If - End If + If condition Then ' Noncompliant + End If - If Not a.Equals(b) AndAlso b.Equals(c) Then - If a.Equals(c) Then ' FN - End If - If a Is c Then ' FN - End If - End If + Trace.Assert(condition) ' Compliant - If a IsNot b AndAlso b.Equals(c) Then - If a.Equals(c) Then - End If - If a Is c Then - End If - End If - End Sub + If o1 IsNot Nothing Then + Debug.Assert(o1 Is Nothing, "Some message", "More details", 1, 2, 3) ' Compliant + End If + End Sub - Private Sub NeqEqTransitivity(ByVal a As Object, ByVal b As Object, ByVal c As Object) - If a Is c AndAlso a IsNot b Then - If b Is c Then ' FN - End If + Public Sub Assert(ByVal o1 As Object) + Debug.Assert(o1 IsNot Nothing) + Debug.Assert(o1 Is Nothing) + End Sub - If b.Equals(c) Then - End If + Private Sub ComparisonTransitivity(ByVal a As Integer, ByVal b As Integer, ByVal c As Integer) + If a = b AndAlso b < c Then + If a >= c Then ' FN End If - If a Is c AndAlso Not a.Equals(b) Then - If b Is c Then ' FN - End If + End If + If a = b AndAlso b <= c Then + If a > c Then ' FN + End If - If b.Equals(c) Then ' FN - End If + End If + If a > b AndAlso b > c Then + If a <= c Then ' FN + End If + End If + If a > b AndAlso b >= c Then + If a <= c Then ' FN End If - End Sub - Public Sub LiftedOperator() - Dim i As Integer? = Nothing - Dim j As Integer? = 5 + End If + If a >= b AndAlso b >= c Then + If a < c Then ' FN + End If - If i < j Then ' Noncompliant + End If + If a >= b AndAlso c <= b Then + If a < c Then ' FN End If - If i <= j Then ' Noncompliant + End If + If a >= b AndAlso c >= b Then + If a < c Then End If + End If + End Sub + + Friend Class Comp + Public Shared Operator <(ByVal a As Comp, ByVal b As Comp) As Boolean + Return True + End Operator + Public Shared Operator >(ByVal a As Comp, ByVal b As Comp) As Boolean + Return True + End Operator + Public Shared Operator >=(ByVal a As Comp, ByVal b As Comp) As Boolean + Return True + End Operator + Public Shared Operator <=(ByVal a As Comp, ByVal b As Comp) As Boolean + Return True + End Operator + End Class - If i > j Then ' Noncompliant + Private Sub RefEqTransitivity(ByVal a As Comp, ByVal b As Comp, ByVal c As Comp) + If a Is b AndAlso b Is c Then + If a IsNot c Then ' FN End If + End If - If i >= j Then ' Noncompliant + If a.Equals(b) AndAlso b Is c Then + If a IsNot c Then + End If + If a Is c Then + End If + If a.Equals(c) Then ' FN + End If + If Not a.Equals(c) Then ' FN End If + End If - If i > 0 Then ' Noncompliant + If a > b AndAlso b Is c Then + If a <= c Then ' FN End If + End If + End Sub - If i >= 0 Then ' Noncompliant + Private Sub ValueEqTransitivity(ByVal a As Comp, ByVal b As Comp, ByVal c As Comp) + If a Is b AndAlso b.Equals(c) Then + If a.Equals(c) Then ' FN End If + End If - If i < 0 Then ' Noncompliant + If a.Equals(b) AndAlso b.Equals(c) Then + If a IsNot c Then End If + If a Is c Then + End If + If a.Equals(c) Then ' FN + End If + If Not a.Equals(c) Then ' FN + End If + End If - If i <= 0 Then ' Noncompliant + If a > b AndAlso b.Equals(c) Then + If a > c Then ' FN + End If + If a <= c Then ' FN End If + End If - If j > Nothing Then ' Noncompliant + If Not a.Equals(b) AndAlso b.Equals(c) Then + If a.Equals(c) Then ' FN End If + If a Is c Then ' FN + End If + End If - If j >= Nothing Then ' Noncompliant + If a IsNot b AndAlso b.Equals(c) Then + If a.Equals(c) Then + End If + If a Is c Then End If + End If + End Sub - If j < Nothing Then ' Noncompliant + Private Sub NeqEqTransitivity(ByVal a As Object, ByVal b As Object, ByVal c As Object) + If a Is c AndAlso a IsNot b Then + If b Is c Then ' FN End If - If j <= Nothing Then ' Noncompliant + If b.Equals(c) Then End If - End Sub + End If - Friend Class Singleton - Private Shared syncRoot As Object = New Object() + If a Is c AndAlso Not a.Equals(b) Then + If b Is c Then ' FN + End If - Private Shared instanceField As Singleton + If b.Equals(c) Then ' FN + End If - Public Shared ReadOnly Property Instance As Singleton - Get - If instanceField Is Nothing Then - SyncLock syncRoot - If instanceField Is Nothing Then ' Noncompliant FP - instanceField = New Singleton() - End If - End SyncLock - End If - Return instanceField - End Get - End Property - End Class - - Friend Structure MyStructWithNoOperator - Public Shared Sub M(ByVal a As MyStructWithNoOperator) - If a Is Nothing Then ' Noncompliant, also a compiler error - ' Error@-1 [BC30020] - End If - End Sub - End Structure + End If + End Sub - Public Class NullableCases - Private Sub Case1() - Dim b1 As Boolean? = True - If b1 = True Then ' Noncompliant - End If - End Sub + Public Sub LiftedOperator() + Dim i As Integer? = Nothing + Dim j As Integer? = 5 - Private Sub Case2(ByVal i As Boolean?) - If i Is Nothing Then + If i < j Then ' Noncompliant + End If - End If - If i = True Then + If i <= j Then ' Noncompliant + End If - End If - If i = False Then + If i > j Then ' Noncompliant + End If - End If + If i >= j Then ' Noncompliant + End If - i = Nothing - If i Is Nothing Then ' Noncompliant + If i > 0 Then ' Noncompliant + End If - End If - If i = True Then ' Noncompliant + If i >= 0 Then ' Noncompliant + End If - End If - If i = False Then ' Noncompliant + If i < 0 Then ' Noncompliant + End If - End If + If i <= 0 Then ' Noncompliant + End If - i = True - If i Is Nothing Then ' Noncompliant + If j > Nothing Then ' Noncompliant + End If - End If - If i = True Then ' Noncompliant + If j >= Nothing Then ' Noncompliant + End If - End If - If i = False Then ' Noncompliant + If j < Nothing Then ' Noncompliant + End If - End If + If j <= Nothing Then ' Noncompliant + End If + End Sub - i = False - If i Is Nothing Then ' Noncompliant + Friend Class Singleton + Private Shared syncRoot As Object = New Object() - End If - If i = True Then ' Noncompliant + Private Shared instanceField As Singleton + Public Shared ReadOnly Property Instance As Singleton + Get + If instanceField Is Nothing Then + SyncLock syncRoot + If instanceField Is Nothing Then ' Noncompliant FP + instanceField = New Singleton() + End If + End SyncLock End If - If i = False Then ' Noncompliant + Return instanceField + End Get + End Property + End Class - End If + Friend Structure MyStructWithNoOperator + Public Shared Sub M(ByVal a As MyStructWithNoOperator) + If a Is Nothing Then ' Noncompliant, also a compiler error + ' Error@-1 [BC30020] + End If + End Sub + End Structure - Dim b2 As Boolean? = True - If b2 = False Then ' Noncompliant - End If + Public Class NullableCases + Private Sub Case1() + Dim b1 As Boolean? = True + If b1 = True Then ' Noncompliant + End If + End Sub - Dim b3 As Boolean? = True - If b3 Is Nothing Then ' Noncompliant - End If + Private Sub Case2(ByVal i As Boolean?) + If i Is Nothing Then - Dim b4 As Boolean? = Nothing - If b4 = True Then ' Noncompliant - End If + End If + If i = True Then - Dim b5 As Boolean? = Nothing - If b5 = False Then ' Noncompliant - End If + End If + If i = False Then + End If - Dim b6 As Boolean? = Nothing - If b6 Is Nothing Then ' Noncompliant - End If - Dim b7 As Boolean? = True - If b7 = True Then ' Noncompliant - End If - Dim b8 As Boolean? = False - If b8 = False Then ' Noncompliant - End If + i = Nothing + If i Is Nothing Then ' Noncompliant - End Sub + End If + If i = True Then ' Noncompliant - Private Sub Case3(ByVal b As Boolean?) - If b Is Nothing Then - If Nothing Is b Then ' Noncompliant - b.ToString() - End If - Else - If b IsNot Nothing Then ' Noncompliant - b.ToString() - End If - End If - End Sub + End If + If i = False Then ' Noncompliant - Private Sub Case4(ByVal b As Boolean?) - If b = True Then - If True = b Then ' Noncompliant - b.ToString() - End If - End If - End Sub + End If - Private Sub Case5(ByVal b As Boolean?) - If b = True Then - ElseIf b = False Then - Else - End If - End Sub + i = True + If i Is Nothing Then ' Noncompliant - Private Sub Case6(ByVal b As Boolean?) - If b Is Nothing Then - ElseIf b = True Then - Else - End If - End Sub + End If + If i = True Then ' Noncompliant - Private Sub Case7(ByVal b As Boolean?) - If b Is Nothing Then - If If(b, False) Then ' Noncompliant + End If + If i = False Then ' Noncompliant - End If - End If - End Sub + End If - Private Sub Case8(ByVal b As Boolean?) - If b IsNot Nothing Then - If b.HasValue Then ' Noncompliant - End If - End If - End Sub + i = False + If i Is Nothing Then ' Noncompliant - Private Sub Case9(ByVal b As Boolean?) - If b = True Then - Dim x = b.Value - If x = True Then ' Noncompliant - End If - End If - End Sub + End If + If i = True Then ' Noncompliant - Private Sub Case10(ByVal i As Integer?) - If i Is Nothing Then - If i.HasValue Then ' Noncompliant - End If - End If - End Sub + End If + If i = False Then ' Noncompliant - Public Sub IfElseIfElseFlow_DirectValue(ByVal b As Boolean?) - If b = True Then - Console.WriteLine("true") - ElseIf b = False Then - Console.WriteLine("false") - Else - Console.WriteLine("null") - End If - End Sub - - Public Sub IfElseIfElseFlow_KnownNull() - Dim b As Boolean? = Nothing - If b = True Then ' Noncompliant - Console.WriteLine("true") ' Secondary - ElseIf b = False Then ' Noncompliant - Console.WriteLine("false") ' Secondary - Else - Console.WriteLine("null") - End If - End Sub - End Class + End If - Public Class ConstantExpressionsAreExcluded - Const T As Boolean = True - Const F As Boolean = False + Dim b2 As Boolean? = True + If b2 = False Then ' Noncompliant + End If - Private Sub LocalConstants() - Const t = True - If t Then ' Noncompliant - Console.WriteLine() - End If - Const f = False - If f Then ' Noncompliant - Console.WriteLine() ' Secondary - End If - End Sub + Dim b3 As Boolean? = True + If b3 Is Nothing Then ' Noncompliant + End If - Private Sub Constants() - If T Then ' Compliant it's a constant - Console.WriteLine() - End If - If F Then ' Compliant it's a constant - Console.WriteLine() - End If - End Sub - Private Sub WhileTrue() - While T ' Compliant it's a constant - Console.WriteLine() - End While - End Sub - Private Sub WhileFalse() - Do - Console.WriteLine() - Loop While F ' Compliant it's a constant - End Sub - Private Sub Condition() - Dim x = If(T, 1, 2) ' Compliant, T is constant - End Sub - End Class + Dim b4 As Boolean? = Nothing + If b4 = True Then ' Noncompliant + End If - End Class + Dim b5 As Boolean? = Nothing + If b5 = False Then ' Noncompliant + End If - Public Class GuardedTests - Public Sub Guarded(ByVal s1 As String) - Guard1(s1) - If Equals(s1, Nothing) Then ' Noncompliant, always false - ' this branch is never executed - Else + Dim b6 As Boolean? = Nothing + If b6 Is Nothing Then ' Noncompliant + End If + Dim b7 As Boolean? = True + If b7 = True Then ' Noncompliant + End If + Dim b8 As Boolean? = False + If b8 = False Then ' Noncompliant End If - End Sub - Public Sub Guard1(Of T As Class)( - ByVal value As T) End Sub - - Public NotInheritable Class ValidatedNotNullAttribute - Inherits Attribute - End Class - End Class - - Public Class CatchFinally - Public Sub ObjectsShouldNotBeDisposedMoreThanOnce() - Dim stream As Stream = Nothing - Try - stream = File.Open("file", FileMode.Open) - Using reader = New StreamReader(stream) - ' read the file here - - ' StreamReader will dispose the stream automatically; set stream to null - ' to prevent it from disposing twice (the recommended pattern for S3966) - stream = Nothing - End Using - - Finally - If stream IsNot Nothing Then - stream.Dispose() + Private Sub Case3(ByVal b As Boolean?) + If b Is Nothing Then + If Nothing Is b Then ' Noncompliant + b.ToString() + End If + Else + If b IsNot Nothing Then ' Noncompliant + b.ToString() End If - End Try + End If End Sub - Public Sub FalseNegatives() - Dim o As Object = Nothing - Try - Console.WriteLine("Could throw") - Catch - If o IsNot Nothing Then ' Noncompliant - End If - If o Is Nothing Then ' Noncompliant + Private Sub Case4(ByVal b As Boolean?) + If b = True Then + If True = b Then ' Noncompliant + b.ToString() End If + End If + End Sub - Finally - If o IsNot Nothing Then ' Noncompliant - End If - If o Is Nothing Then ' Noncompliant - End If - End Try + Private Sub Case5(ByVal b As Boolean?) + If b = True Then + ElseIf b = False Then + Else + End If End Sub - End Class - Friend Class UsingStatement - Public Sub Method() - Dim isTrue = True - If isTrue Then ' Noncompliant + Private Sub Case6(ByVal b As Boolean?) + If b Is Nothing Then + ElseIf b = True Then + Else End If - Using reader = New StreamReader("") - If isTrue Then ' Noncompliant + End Sub + + Private Sub Case7(ByVal b As Boolean?) + If b Is Nothing Then + If If(b, False) Then ' Noncompliant + End If - End Using - If isTrue Then ' Noncompliant End If End Sub - End Class - Friend Class AsyncAwait - Private _foo1 As Object - Private Async Function Foo(ByVal t As Task) As Task - Dim o As Object = Nothing - _foo1 = o - Await t ' awaiting clears the constraints - If _foo1 IsNot Nothing Then ' FN - End If - If _foo1 Is Nothing Then ' FN - End If - If o IsNot Nothing Then ' Noncompliant - End If - If o Is Nothing Then ' Noncompliant + Private Sub Case8(ByVal b As Boolean?) + If b IsNot Nothing Then + If b.HasValue Then ' Noncompliant + End If End If - End Function - End Class + End Sub - Public Class StaticMethods - Private _foo1 As Object - ' https://github.com/SonarSource/sonar-dotnet/issues/947 - Private Sub CallToMonitorWaitShouldResetFieldConstraints() - Dim o As Object = Nothing - _foo1 = o - Threading.Monitor.Wait(o) ' This is a multi-threaded application, the fields could change - If _foo1 IsNot Nothing Then ' Noncompliant FP - End If - If _foo1 Is Nothing Then ' Noncompliant FP - End If - If o IsNot Nothing Then ' Noncompliant - End If - If o Is Nothing Then ' Noncompliant + Private Sub Case9(ByVal b As Boolean?) + If b = True Then + Dim x = b.Value + If x = True Then ' Noncompliant + End If End If End Sub - Private Sub CallToStaticMethodsShouldResetFieldConstraints() - Dim o As Object = Nothing - _foo1 = o - Console.WriteLine() ' This particular method has no side effects - If _foo1 IsNot Nothing Then ' Noncompliant - End If - If _foo1 Is Nothing Then ' Noncompliant - End If - If o IsNot Nothing Then ' Noncompliant - End If - If o Is Nothing Then ' Noncompliant + Private Sub Case10(ByVal i As Integer?) + If i Is Nothing Then + If i.HasValue Then ' Noncompliant + End If End If End Sub - End Class - - Public Class TestNullCoalescing - Public Sub CompliantMethod(ByVal input As Boolean?) - If If(input, False) Then ' Compliant - Console.WriteLine("input is true") + Public Sub IfElseIfElseFlow_DirectValue(ByVal b As Boolean?) + If b = True Then + Console.WriteLine("true") + ElseIf b = False Then + Console.WriteLine("false") Else - Console.WriteLine("input is false") + Console.WriteLine("null") End If End Sub - Public Sub CompliantMethod1(ByVal input As Boolean?) - While If(input, False) ' Compliant - Console.WriteLine("input is true") - End While - End Sub - - Public Sub CompliantMethod2(ByVal input As Boolean?, ByVal input1 As Boolean) - While If(input, False) AndAlso input1 ' Compliant - Console.WriteLine("input is true") - End While + Public Sub IfElseIfElseFlow_KnownNull() + Dim b As Boolean? = Nothing + If b = True Then ' Noncompliant + Console.WriteLine("true") ' Secondary + ElseIf b = False Then ' Noncompliant + Console.WriteLine("false") ' Secondary + Else + Console.WriteLine("null") + End If End Sub + End Class - Public Sub CompliantMethod3(ByVal input As Boolean?, ByVal input1 As Boolean) + Public Class ConstantExpressionsAreExcluded + Const T As Boolean = True + Const F As Boolean = False - If If(If(input, False), input1, False) Then ' Compliant - Console.WriteLine("input is true") + Private Sub LocalConstants() + Const t = True + If t Then ' Noncompliant + Console.WriteLine() + End If + Const f = False + If f Then ' Noncompliant + Console.WriteLine() ' Secondary End If End Sub - Public Sub NonCompliantMethod() - Dim input As Boolean? = True - If If(input, False) Then ' Noncompliant - Console.WriteLine("input is true") - Else - Console.WriteLine("input is false") ' Secondary + Private Sub Constants() + If T Then ' Compliant it's a constant + Console.WriteLine() + End If + If F Then ' Compliant it's a constant + Console.WriteLine() End If End Sub - - Public Sub NonCompliantMethod1() - Dim input As Boolean? = True - While If(input, False) ' Noncompliant - Console.WriteLine("input is true") + Private Sub WhileTrue() + While T ' Compliant it's a constant + Console.WriteLine() End While End Sub - - Public Sub NonCompliantMethod2(ByVal input As Boolean?) - While If(input, False) OrElse True ' Compliant - Console.WriteLine("input is true") - End While + Private Sub WhileFalse() + Do + Console.WriteLine() + Loop While F ' Compliant it's a constant End Sub - - Public Sub NonCompliantMethod3(ByVal input As Boolean?, ByVal input1 As Boolean) - If If(If(input, False), False, False) Then ' Compliant - Console.WriteLine("input is true") - End If + Private Sub Condition() + Dim x = If(T, 1, 2) ' Compliant, T is constant End Sub End Class - Friend Class Program - Public Shared Function CompliantMethod4(ByVal parameter As String) As String - Dim useParameter = If(parameter, "non-empty") - If Equals(useParameter, Nothing) OrElse Equals(useParameter, "") Then Return "non-empty" ' Noncompliant - ' we don't know if this going to be excuted or not +End Class - Return "empty" - End Function +Public Class GuardedTests + Public Sub Guarded(ByVal s1 As String) + Guard1(s1) - Public Shared Function Method1347(ByVal parameter As String) As String - Dim useParameter = If(parameter, "non-empty") - If Not String.IsNullOrEmpty(useParameter) Then - Return "non-empty" - Else - End If - Return "empty" - End Function + If Equals(s1, Nothing) Then ' Noncompliant, always false + ' this branch is never executed + Else + End If + End Sub + + Public Sub Guard1(Of T As Class)( + ByVal value As T) + End Sub + + + Public NotInheritable Class ValidatedNotNullAttribute + Inherits Attribute End Class +End Class + +Public Class CatchFinally + Public Sub ObjectsShouldNotBeDisposedMoreThanOnce() + Dim stream As Stream = Nothing + Try + stream = File.Open("file", FileMode.Open) + Using reader = New StreamReader(stream) + ' read the file here + + ' StreamReader will dispose the stream automatically; set stream to null + ' to prevent it from disposing twice (the recommended pattern for S3966) + stream = Nothing + End Using - Public Class RefArgTest - Public Sub Method(ByRef s As String, ByVal x As Integer) - End Sub - Public Sub Method1(ByVal infixes As String) - If Not Equals(infixes, Nothing) Then - Method(infixes, infixes.Length) - If Equals(infixes, Nothing) Then ' Noncompliant FP: ref - Return - End If + Finally + If stream IsNot Nothing Then + stream.Dispose() + End If + End Try + End Sub + + Public Sub FalseNegatives() + Dim o As Object = Nothing + Try + Console.WriteLine("Could throw") + Catch + If o IsNot Nothing Then ' Noncompliant + End If + If o Is Nothing Then ' Noncompliant + End If + + Finally + If o IsNot Nothing Then ' Noncompliant + End If + If o Is Nothing Then ' Noncompliant + End If + End Try + End Sub +End Class + +Friend Class UsingStatement + Public Sub Method() + Dim isTrue = True + If isTrue Then ' Noncompliant + End If + Using reader = New StreamReader("") + If isTrue Then ' Noncompliant + End If + End Using + If isTrue Then ' Noncompliant + End If + End Sub +End Class + +Friend Class AsyncAwait + Private _foo1 As Object + Private Async Function Foo(ByVal t As Task) As Task + Dim o As Object = Nothing + _foo1 = o + Await t ' awaiting clears the constraints + If _foo1 IsNot Nothing Then ' FN + End If + If _foo1 Is Nothing Then ' FN + End If + If o IsNot Nothing Then ' Noncompliant + End If + If o Is Nothing Then ' Noncompliant + End If + End Function +End Class + +Public Class StaticMethods + Private _foo1 As Object + ' https://github.com/SonarSource/sonar-dotnet/issues/947 + Private Sub CallToMonitorWaitShouldResetFieldConstraints() + Dim o As Object = Nothing + _foo1 = o + Threading.Monitor.Wait(o) ' This is a multi-threaded application, the fields could change + If _foo1 IsNot Nothing Then ' Noncompliant FP + End If + If _foo1 Is Nothing Then ' Noncompliant FP + End If + If o IsNot Nothing Then ' Noncompliant + End If + If o Is Nothing Then ' Noncompliant + End If + End Sub + + Private Sub CallToStaticMethodsShouldResetFieldConstraints() + Dim o As Object = Nothing + _foo1 = o + Console.WriteLine() ' This particular method has no side effects + If _foo1 IsNot Nothing Then ' Noncompliant + End If + If _foo1 Is Nothing Then ' Noncompliant + End If + If o IsNot Nothing Then ' Noncompliant + End If + If o Is Nothing Then ' Noncompliant + End If + End Sub +End Class + + +Public Class TestNullCoalescing + Public Sub CompliantMethod(ByVal input As Boolean?) + If If(input, False) Then ' Compliant + Console.WriteLine("input is true") + Else + Console.WriteLine("input is false") + End If + End Sub + + Public Sub CompliantMethod1(ByVal input As Boolean?) + While If(input, False) ' Compliant + Console.WriteLine("input is true") + End While + End Sub + + Public Sub CompliantMethod2(ByVal input As Boolean?, ByVal input1 As Boolean) + While If(input, False) AndAlso input1 ' Compliant + Console.WriteLine("input is true") + End While + End Sub + + Public Sub CompliantMethod3(ByVal input As Boolean?, ByVal input1 As Boolean) + + If If(If(input, False), input1, False) Then ' Compliant + Console.WriteLine("input is true") + End If + End Sub + + Public Sub NonCompliantMethod() + Dim input As Boolean? = True + If If(input, False) Then ' Noncompliant + Console.WriteLine("input is true") + Else + Console.WriteLine("input is false") ' Secondary + End If + End Sub + + Public Sub NonCompliantMethod1() + Dim input As Boolean? = True + While If(input, False) ' Noncompliant + Console.WriteLine("input is true") + End While + End Sub + + Public Sub NonCompliantMethod2(ByVal input As Boolean?) + While If(input, False) OrElse True ' Compliant + Console.WriteLine("input is true") + End While + End Sub + + Public Sub NonCompliantMethod3(ByVal input As Boolean?, ByVal input1 As Boolean) + If If(If(input, False), False, False) Then ' Compliant + Console.WriteLine("input is true") + End If + End Sub +End Class + +Friend Class Program + Public Shared Function CompliantMethod4(ByVal parameter As String) As String + Dim useParameter = If(parameter, "non-empty") + If Equals(useParameter, Nothing) OrElse Equals(useParameter, "") Then Return "non-empty" ' Noncompliant + ' we don't know if this going to be excuted or not + + Return "empty" + End Function + + Public Shared Function Method1347(ByVal parameter As String) As String + Dim useParameter = If(parameter, "non-empty") + If Not String.IsNullOrEmpty(useParameter) Then + Return "non-empty" + Else + End If + Return "empty" + End Function +End Class + +Public Class RefArgTest + Public Sub Method(ByRef s As String, ByVal x As Integer) + End Sub + Public Sub Method1(ByVal infixes As String) + If Not Equals(infixes, Nothing) Then + Method(infixes, infixes.Length) + If Equals(infixes, Nothing) Then ' Noncompliant FP: ref + Return End If - End Sub + End If + End Sub - Public Sub Method2(ByVal infixes As String) - If Not Equals(infixes, Nothing) Then - Method(infixes, infixes.Length) - If Not Equals(infixes, Nothing) Then ' Noncompliant FP: ref - Return - End If + Public Sub Method2(ByVal infixes As String) + If Not Equals(infixes, Nothing) Then + Method(infixes, infixes.Length) + If Not Equals(infixes, Nothing) Then ' Noncompliant FP: ref + Return End If - End Sub + End If + End Sub - Public Sub Method3(ByVal infixes As String) - If Equals(infixes, Nothing) Then - Method(infixes, infixes.Length) - If Equals(infixes, Nothing) Then ' Noncompliant FP: ref - Return - End If + Public Sub Method3(ByVal infixes As String) + If Equals(infixes, Nothing) Then + Method(infixes, infixes.Length) + If Equals(infixes, Nothing) Then ' Noncompliant FP: ref + Return End If - End Sub + End If + End Sub - Public Sub Method4(ByVal infixes As String) - If Equals(infixes, Nothing) Then - Method(infixes, infixes.Length) - If Not Equals(infixes, Nothing) Then ' Noncompliant FP: ref - Return - End If + Public Sub Method4(ByVal infixes As String) + If Equals(infixes, Nothing) Then + Method(infixes, infixes.Length) + If Not Equals(infixes, Nothing) Then ' Noncompliant FP: ref + Return End If - End Sub + End If + End Sub - End Class +End Class - Public Class StringComparision - Public Sub Method(ByVal parameterString As String) - Dim emptyString1 = "" - Dim emptyString2 = "" - Dim nullString1 As String = Nothing - Dim nullString2 As String = Nothing - Dim fullStringa1 = "a" - Dim fullStringa2 = "a" - Dim fullStringb = "b" - Dim whiteSpaceString1 = " " - Dim whiteSpaceString2 = " " - Dim doubleWhiteSpaceString1 = " " - Dim doubleWhiteSpaceString2 = " " +Public Class StringComparision + Public Sub Method(ByVal parameterString As String) + Dim emptyString1 = "" + Dim emptyString2 = "" + Dim nullString1 As String = Nothing + Dim nullString2 As String = Nothing + Dim fullStringa1 = "a" + Dim fullStringa2 = "a" + Dim fullStringb = "b" + Dim whiteSpaceString1 = " " + Dim whiteSpaceString2 = " " + Dim doubleWhiteSpaceString1 = " " + Dim doubleWhiteSpaceString2 = " " - If Equals(emptyString1, emptyString2) Then ' FN + If Equals(emptyString1, emptyString2) Then ' FN - End If - If Equals(nullString1, nullString2) Then ' Noncompliant + End If + If Equals(nullString1, nullString2) Then ' Noncompliant - End If + End If - If Equals(fullStringa1, fullStringa2) Then + If Equals(fullStringa1, fullStringa2) Then - End If + End If - If Equals(fullStringa1, fullStringb) Then + If Equals(fullStringa1, fullStringb) Then - End If + End If - If Equals(parameterString, emptyString1) Then + If Equals(parameterString, emptyString1) Then - End If + End If - If Equals(parameterString, nullString1) Then + If Equals(parameterString, nullString1) Then - End If + End If - If Equals(emptyString1, nullString1) Then ' Noncompliant + If Equals(emptyString1, nullString1) Then ' Noncompliant - End If + End If - If Equals(emptyString1, fullStringa1) Then ' FN + If Equals(emptyString1, fullStringa1) Then ' FN - End If + End If - If Equals(nullString1, fullStringa1) Then ' Noncompliant + If Equals(nullString1, fullStringa1) Then ' Noncompliant - End If + End If - If Equals(fullStringa1, "") Then ' FN + If Equals(fullStringa1, "") Then ' FN - End If + End If - If Equals(fullStringa1, Nothing) Then ' Noncompliant + If Equals(fullStringa1, Nothing) Then ' Noncompliant - End If + End If - If Equals(whiteSpaceString1, whiteSpaceString2) Then ' FN + If Equals(whiteSpaceString1, whiteSpaceString2) Then ' FN - End If + End If - If Equals(whiteSpaceString1, " ") Then ' FN + If Equals(whiteSpaceString1, " ") Then ' FN - End If + End If - If Equals(whiteSpaceString1, emptyString1) Then ' FN + If Equals(whiteSpaceString1, emptyString1) Then ' FN - End If + End If - If Equals(whiteSpaceString1, nullString1) Then ' Noncompliant + If Equals(whiteSpaceString1, nullString1) Then ' Noncompliant - End If + End If - If Equals(whiteSpaceString1, fullStringa1) Then ' FN + If Equals(whiteSpaceString1, fullStringa1) Then ' FN - End If + End If - If Equals(whiteSpaceString1, parameterString) Then + If Equals(whiteSpaceString1, parameterString) Then - End If + End If - If Equals(doubleWhiteSpaceString1, doubleWhiteSpaceString2) Then ' FN + If Equals(doubleWhiteSpaceString1, doubleWhiteSpaceString2) Then ' FN - End If + End If - If Equals(doubleWhiteSpaceString1, emptyString1) Then ' FN + If Equals(doubleWhiteSpaceString1, emptyString1) Then ' FN - End If + End If - If Equals(doubleWhiteSpaceString1, nullString1) Then ' Noncompliant + If Equals(doubleWhiteSpaceString1, nullString1) Then ' Noncompliant - End If + End If - If Equals(doubleWhiteSpaceString1, fullStringa1) Then ' FN + If Equals(doubleWhiteSpaceString1, fullStringa1) Then ' FN - End If + End If - If Equals(doubleWhiteSpaceString1, parameterString) Then + If Equals(doubleWhiteSpaceString1, parameterString) Then - End If + End If - End Sub - End Class + End Sub +End Class - Public Class NullOrEmpty - Public Sub Method1(ByVal s As String) - Dim s1 As String = Nothing - Dim s2 = "" - Dim s3 = "a" - If String.IsNullOrEmpty(s1) Then ' Noncompliant - End If - If String.IsNullOrEmpty(s2) Then ' FN - End If +Public Class NullOrEmpty + Public Sub Method1(ByVal s As String) + Dim s1 As String = Nothing + Dim s2 = "" + Dim s3 = "a" + If String.IsNullOrEmpty(s1) Then ' Noncompliant + End If + If String.IsNullOrEmpty(s2) Then ' FN + End If - If String.IsNullOrEmpty(s) Then - End If + If String.IsNullOrEmpty(s) Then + End If - If String.IsNullOrEmpty(s3) Then ' FN - End If - End Sub + If String.IsNullOrEmpty(s3) Then ' FN + End If + End Sub - Public Sub Method2(ByVal s As String) + Public Sub Method2(ByVal s As String) - If String.IsNullOrEmpty(s) Then - End If + If String.IsNullOrEmpty(s) Then + End If - s = "" - If String.IsNullOrEmpty(s) Then ' FN - End If + s = "" + If String.IsNullOrEmpty(s) Then ' FN + End If - s = Nothing - If String.IsNullOrEmpty(s) Then ' Noncompliant - End If + s = Nothing + If String.IsNullOrEmpty(s) Then ' Noncompliant + End If - s = "a" - If String.IsNullOrEmpty(s) Then ' FN - End If - End Sub + s = "a" + If String.IsNullOrEmpty(s) Then ' FN + End If + End Sub - Public Sub Method3(ByVal s1 As String) - If String.IsNullOrEmpty(s1) Then - s1.ToString() - Else - If Equals(s1, Nothing) Then ' Noncompliant - s1.ToString() ' Secondary - End If + Public Sub Method3(ByVal s1 As String) + If String.IsNullOrEmpty(s1) Then + s1.ToString() + Else + If Equals(s1, Nothing) Then ' Noncompliant + s1.ToString() ' Secondary End If + End If - End Sub + End Sub - Public Sub Method4(ByVal s1 As String) - If Not String.IsNullOrEmpty(s1) Then - If Equals(s1, Nothing) Then ' Noncompliant - s1.ToString() ' Secondary - End If - Else - s1.ToString() + Public Sub Method4(ByVal s1 As String) + If Not String.IsNullOrEmpty(s1) Then + If Equals(s1, Nothing) Then ' Noncompliant + s1.ToString() ' Secondary End If + Else + s1.ToString() + End If - End Sub + End Sub - Public Sub Method5(ByVal s1 As String) - If Not String.IsNullOrEmpty(s1) Then - If Equals(s1, Nothing) Then ' Noncompliant - s1.ToString() ' Secondary - End If - Else - s1.ToString() + Public Sub Method5(ByVal s1 As String) + If Not String.IsNullOrEmpty(s1) Then + If Equals(s1, Nothing) Then ' Noncompliant + s1.ToString() ' Secondary End If + Else + s1.ToString() + End If - End Sub + End Sub - Public Sub Method6(ByVal s1 As String) - If String.IsNullOrEmpty(s1) OrElse Equals(s1, "a") Then - s1.ToString() - Else - If Equals(s1, Nothing) Then ' Noncompliant - s1.ToString() ' Secondary - End If + Public Sub Method6(ByVal s1 As String) + If String.IsNullOrEmpty(s1) OrElse Equals(s1, "a") Then + s1.ToString() + Else + If Equals(s1, Nothing) Then ' Noncompliant + s1.ToString() ' Secondary End If + End If - End Sub + End Sub - Public Sub Method7(ByVal s1 As String) - If String.IsNullOrEmpty(s1) AndAlso Equals(s1, "a") Then ' FN + Public Sub Method7(ByVal s1 As String) + If String.IsNullOrEmpty(s1) AndAlso Equals(s1, "a") Then ' FN + s1.ToString() + Else + If Equals(s1, Nothing) Then s1.ToString() - Else - If Equals(s1, Nothing) Then - s1.ToString() - End If End If + End If + + End Sub + + + Public Function Method8(ByVal message As String) As String + If Equals(message, Nothing) Then + Throw New ArgumentNullException($"{NameOf(message)} shouldn't be null!") + End If + + If String.IsNullOrEmpty(message) Then + Throw New ArgumentNullException($"{NameOf(message)} shouldn't be empty!") + End If + + Return String.Empty + End Function + + Private Sub BinaryConditional_Useless(ByVal a As String, ByVal b As String, ByVal c As String, ByVal d As String) + Dim isNothing As String = Nothing + Dim isNotNothing = "" + Dim notEmpty = "value" + Dim ret As String + + ret = If(b, a) + ret = If(b, isNotNothing) + ret = If(c, notEmpty) + ret = If(d, "N/A") + + 'Left operand: Values notNull and notEmpty are known to be not Nothing + ret = If(isNotNothing, a) ' Noncompliant + ' Secondary@-1 + ret = If(isNotNothing, a) ' Noncompliant + ' Secondary@-1 + ret = "Lorem " & If(isNotNothing, a) & " ipsum" ' Noncompliant + ' Secondary@-1 + ret = If(isNotNothing, "N/A") ' Noncompliant + ' Secondary@-1 + ret = If(notEmpty, "N/A") ' Noncompliant + ' Secondary@-1 + + 'Left operand: isNull is known to be null + ret = If(Nothing, a) ' Noncompliant + ret = If(isNothing, a) ' Noncompliant + ret = "Lorem " & If(isNothing, a) & " ipsum" ' Noncompliant + + 'Right operand: isNull is known to be null, therefore binary conditional expression is not needed + ret = If(a, Nothing) ' FN: NOOP + ret = If(a, isNothing) ' FN: NOOP + ' ~~~~~~~~~ + + 'Combo/Fatality + ret = If(isNotNothing, isNothing) + ' ^^^^^^^^^^^^ Noncompliant {{Change this expression which always evaluates to the same result. Some code paths are unreachable.}} + ' ^^^^^^^^^ Secondary@-1 + ret = If(isNothing, Nothing) ' Noncompliant {{Change this expression which always evaluates to the same result.}} + ' ^^^^^^^^^ + ret = If("Value", a) + ' ^^^^^^^ Noncompliant {{Change this expression which always evaluates to the same result. Some code paths are unreachable.}} + ' ^ Secondary@-1 + End Sub + + Private Function CoalesceCount(Of T)(ByVal arg As IList(Of T)) As Integer + arg = If(arg, New List(Of T)()) + Return arg.Count + End Function + + Public Class CoalesceProperty + Private messageField As Object + + Public ReadOnly Property Message As Object + Get + Return If(messageField Is Nothing, New Object(), messageField) + End Get + End Property - End Sub - - - Public Function Method8(ByVal message As String) As String - If Equals(message, Nothing) Then - Throw New ArgumentNullException($"{NameOf(message)} shouldn't be null!") - End If - - If String.IsNullOrEmpty(message) Then - Throw New ArgumentNullException($"{NameOf(message)} shouldn't be empty!") - End If - - Return String.Empty - End Function - - Private Sub BinaryConditional_Useless(ByVal a As String, ByVal b As String, ByVal c As String, ByVal d As String) - Dim isNothing As String = Nothing - Dim isNotNothing = "" - Dim notEmpty = "value" - Dim ret As String - - ret = If(b, a) - ret = If(b, isNotNothing) - ret = If(c, notEmpty) - ret = If(d, "N/A") - - 'Left operand: Values notNull and notEmpty are known to be not Nothing - ret = If(isNotNothing, a) ' Noncompliant - ' Secondary@-1 - ret = If(isNotNothing, a) ' Noncompliant - ' Secondary@-1 - ret = "Lorem " & If(isNotNothing, a) & " ipsum" ' Noncompliant - ' Secondary@-1 - ret = If(isNotNothing, "N/A") ' Noncompliant - ' Secondary@-1 - ret = If(notEmpty, "N/A") ' Noncompliant - ' Secondary@-1 - - 'Left operand: isNull is known to be null - ret = If(Nothing, a) ' Noncompliant - ret = If(isNothing, a) ' Noncompliant - ret = "Lorem " & If(isNothing, a) & " ipsum" ' Noncompliant - - 'Right operand: isNull is known to be null, therefore binary conditional expression is not needed - ret = If(a, Nothing) ' FN: NOOP - ret = If(a, isNothing) ' FN: NOOP - ' ~~~~~~ - - 'Combo/Fatality - ret = If(isNotNothing, isNothing) - ' ^^^^^^^ Noncompliant {{Change this expression which always evaluates to the same result. Some code paths are unreachable.}} - ' ^^^^^^ Secondary@-1 - ret = If(isNothing, Nothing) ' Noncompliant {{Change this expression which always evaluates to the same result.}} - ' ^^^^^^ - ret = If("Value", a) - ' ^^^^^^^ Noncompliant {{Change this expression which always evaluates to the same result. Some code paths are unreachable.}} - ' ^ Secondary@-1 - End Sub - - Private Function CoalesceCount(Of T)(ByVal arg As IList(Of T)) As Integer - arg = If(arg, New List(Of T)()) - Return arg.Count - End Function - - Public Class CoalesceProperty - Private messageField As Object - - Public ReadOnly Property Message As Object - Get - Return If(messageField Is Nothing, New Object(), messageField) - End Get - End Property - - End Class End Class +End Class - Public Class NullOrWhiteSpace - Public Sub Method1(ByVal s As String) - Dim s1 As String = Nothing - Dim s2 = "" - Dim s3 = If(s, "") - Dim s4 = " " +Public Class NullOrWhiteSpace + Public Sub Method1(ByVal s As String) + Dim s1 As String = Nothing + Dim s2 = "" + Dim s3 = If(s, "") + Dim s4 = " " - If String.IsNullOrWhiteSpace(s1) Then ' Noncompliant - End If + If String.IsNullOrWhiteSpace(s1) Then ' Noncompliant + End If - If String.IsNullOrWhiteSpace(s2) Then ' FN - If Equals(s2, "a") Then ' FN + If String.IsNullOrWhiteSpace(s2) Then ' FN + If Equals(s2, "a") Then ' FN - End If End If + End If - If String.IsNullOrWhiteSpace(s3) Then + If String.IsNullOrWhiteSpace(s3) Then - End If + End If - If String.IsNullOrWhiteSpace(s4) Then ' FN + If String.IsNullOrWhiteSpace(s4) Then ' FN - End If + End If - If Not String.IsNullOrWhiteSpace(s4) Then ' FN + If Not String.IsNullOrWhiteSpace(s4) Then ' FN - End If + End If - If Not String.IsNullOrWhiteSpace(s) Then - If Equals(s, "") Then ' FN + If Not String.IsNullOrWhiteSpace(s) Then + If Equals(s, "") Then ' FN - End If + End If - If Equals(s, " ") Then ' FN + If Equals(s, " ") Then ' FN - End If End If + End If - End Sub - End Class - -End Namespace + End Sub +End Class From b6cb8aff9ec3ef81a0654eab93034eae64bcf23d Mon Sep 17 00:00:00 2001 From: mary-georgiou-sonarsource Date: Fri, 11 Aug 2023 07:41:01 +0200 Subject: [PATCH 19/20] update rspecs --- analyzers/rspec/vbnet/S2583.html | 64 +++++++++++++++------- analyzers/rspec/vbnet/S2589.html | 91 ++++++++++++++++++++++---------- analyzers/rspec/vbnet/S2589.json | 2 +- 3 files changed, 111 insertions(+), 46 deletions(-) diff --git a/analyzers/rspec/vbnet/S2583.html b/analyzers/rspec/vbnet/S2583.html index e3ac10fbce1..a389dc4186d 100644 --- a/analyzers/rspec/vbnet/S2583.html +++ b/analyzers/rspec/vbnet/S2583.html @@ -3,22 +3,21 @@

Why is this an issue?

href="https://en.wikipedia.org/wiki/Unreachable_code">unreachable code.

In the case below, the call of Dispose() never happens.

-var a = false;
-if (a)
-{
-    Dispose(); // Never reached
-}
+Dim a = False
+
+If a Then
+    Dispose() ' Never reached
+End If
 

Exceptions

This rule will not raise an issue in either of these cases:

  • When the condition is a single const bool
    -const bool debug = false;
    -//...
    -if (debug)
    -{
    -  // Print something
    -}
    +Const debug = False
    +'...
    +If debug Then
    +    ' Print something
    +End If
     
  • When the condition is the literal true or false.
@@ -32,11 +31,39 @@

How to fix it

Code examples

Noncompliant code example

-' TODO
+Public Sub Sample(ByVal b As Boolean)
+    Dim a = False
+    If a Then                  ' Noncompliant: The true branch is never reached
+        DoSomething()          ' Never reached
+    End If
+
+    If Not a OrElse b Then      ' Noncompliant: "not a" is always "True" and the false branch is never reached
+        DoSomething()
+    Else
+        DoSomethingElse()       ' Never reached
+    End If
+
+    Dim c = "xxx"
+    Dim res = If(c, "value")    ' Noncompliant: d is always not Nothing, "value" is never used
+End Sub
 

Compliant solution

-' TODO
+Public Sub Sample(ByVal b As Boolean)
+    Dim a = False
+    If Foo(a) Then             ' Condition was updated
+        DoSomething()
+    End If
+
+    If b Then                  ' Parts of the condition were removed.
+        DoSomething()
+    Else
+        DoSomethingElse()
+    End If
+
+    Dim c = "xxx"
+    Dim res = c                ' "value" was removed
+End Sub
 

Resources

    @@ -47,10 +74,11 @@

    Resources

    Documentation

    diff --git a/analyzers/rspec/vbnet/S2589.html b/analyzers/rspec/vbnet/S2589.html index 20919778e85..080013796d8 100644 --- a/analyzers/rspec/vbnet/S2589.html +++ b/analyzers/rspec/vbnet/S2589.html @@ -2,30 +2,33 @@

    Why is this an issue?

    An operand of a boolean expression that never changes the result of the expression might not match the programmer’s intent and can lead to unexpected behavior and potential bugs.

    -var a = true;
    -if (a)
    -{
    -    DoSomething();
    -}
    +Dim a = True
    +
    +If a Then
    +    DoSomething()
    +End If
     
    -

    This also applies to the null -coalescing operator when one of the operands always evaluates to null.

    +

    This also applies to the null conditional operator +when one of the operands always evaluates to Nothing.

    -string d = null;
    -var v1 = d ?? "value";
    +  Dim d As String = Nothing
    +  Dim v1 = If(d, "value")
     

    Exceptions

    This rule will not raise an issue in either of these cases:

      -
    • When the condition is a single const bool
      -const bool debug = false;
      -//...
      -if (debug)
      -{
      -  // Print something
      -}
      -
    • -
    • When the condition is the literal true or false.
    • +
    • When the condition is a single Const bool
    • +
    +
    +Const debug = False
    +'...
    +If debug Then
    +    ' Print something
    +End If
    +
    +
      +
    • When the condition is the literal True or False.

    In these cases, it is obvious the code is as intended.

    How to fix it

    @@ -37,23 +40,57 @@

    How to fix it

    Code examples

    Noncompliant code example

    -' To be updated
    +Public Sub Sample(ByVal b As Boolean, ByVal c As Boolean)
    +    Dim a = True
    +    If a Then                  ' Noncompliant: "a" is always "true"
    +        DoSomething()
    +    End If
    +
    +    If b AndAlso a Then        ' Noncompliant: "a" is always "true"
    +        DoSomething()
    +    End If
    +
    +    If c OrElse Not a Then     ' Noncompliant: "Not a" is always "false"
    +        DoSomething()
    +    End If
    +
    +    Dim d As String = Nothing
    +    Dim v1 = If(d, "value")    ' Noncompliant: "d" is always Nothing and v1 is always "value".
    +    Dim v2 = If(s, d)          ' Noncompliant: "d" is always Nothing and v2 is always equal to s.
    +End Sub
     

    Compliant solution

    -' To be updated
    -----
    +Public Sub Sample(ByVal b As Boolean, ByVal c As Boolean, ByVal s As String)
    +    Dim a = IsAllowed()
    +    If a Then                  ' Compliant
    +        DoSomething()
    +    End If
    +
    +    If b AndAlso a Then        ' Compliant
    +        DoSomething()
    +    End If
    +
    +    If c OrElse Not a Then      ' Compliant
    +        DoSomething()
    +    End If
    +
    +    Dim d As String = GetStringData()
    +    Dim v1 = If(d, "value")  ' Compliant
    +    Dim v2 = If(s, d)        ' Compliant
    +End Sub
     

    Resources

    Documentation

    diff --git a/analyzers/rspec/vbnet/S2589.json b/analyzers/rspec/vbnet/S2589.json index 3b655f4974f..2ef13c9d15b 100644 --- a/analyzers/rspec/vbnet/S2589.json +++ b/analyzers/rspec/vbnet/S2589.json @@ -28,5 +28,5 @@ 570 ] }, - "quickfix": "unknown" + "quickfix": "targeted" } From 325ac72831a97c7b20034bd7bb14da05771aec7f Mon Sep 17 00:00:00 2001 From: mary-georgiou-sonarsource Date: Fri, 11 Aug 2023 09:11:08 +0200 Subject: [PATCH 20/20] round 2 --- .../Roslyn/ConditionEvaluatesToConstant.cs | 28 +++++--- .../Roslyn/ConditionEvaluatesToConstant.vb | 64 ++++++++++++++----- 2 files changed, 66 insertions(+), 26 deletions(-) diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.cs b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.cs index ffb8f7cbc4f..1c9bafa0438 100644 --- a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.cs +++ b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.cs @@ -570,17 +570,8 @@ public void BooleanBinary(bool a, bool b) a = false; if (a & b) { } // Noncompliant - a &= true; - if (a) { } // FN: engine doesn't learn BoolConstraints from binary operators - - a |= true; - if (a) { } // FN: engine doesn't learn BoolConstraints from binary operators - - a ^= true; - if (a) { } // FN: engine doesn't learn BoolConstraints from binary operators - a = a & true; - if (a) // FN + if (a) // Noncompliant { } a = a | true; @@ -592,6 +583,23 @@ public void BooleanBinary(bool a, bool b) { } } + public void BooleanBinary_CompoundAssignments(bool a, bool b) + { + a = false; + + a &= true; + if (a) + { } // FN: engine doesn't learn BoolConstraints from binary operators + + a |= true; + if (a) + { } // FN: engine doesn't learn BoolConstraints from binary operators + + a ^= true; + if (a) + { } // FN: engine doesn't learn BoolConstraints from binary operators + } + public void IsAsExpression(object o) { if (o is string) { } diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.vb b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.vb index 7980a1008f5..91a9373366c 100644 --- a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.vb +++ b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.vb @@ -256,6 +256,38 @@ Public Class ConditionEvaluatesToConstant End Select End Sub + Public Sub RelationshipWithConstraint(ByVal a As Boolean, ByVal b As Boolean) + If a = b AndAlso a Then + If b Then ' FN: requires relation support + ' ~ + End If + End If + + If a <> b AndAlso a Then + If b Then ' FN: requires relation support + End If + End If + + If a AndAlso b Then + If a = b Then ' Noncompliant + End If + End If + + If a AndAlso b AndAlso a = b Then + ' ^^^^^ Noncompliant + End if + + a = True + b = False + If a AndAlso b Then + ' ^ Noncompliant + ' ^ Noncompliant@-1 + + + End If +End Sub + + Public Property Property1 As Boolean Get Dim a = New Action(Sub() @@ -670,7 +702,7 @@ Public Class ConditionEvaluatesToConstant Public Sub Comparisons(ByVal i As Integer, ByVal j As Integer) If i < j Then - If j < i Then ' FN + If j < i Then ' FN End If If j <= i Then ' FN End If @@ -691,7 +723,7 @@ Public Class ConditionEvaluatesToConstant End Sub Private Sub DefaultExpression(ByVal o As Object) - If Nothing Is Nothing Then ' Noncompliant + If Nothing Is Nothing Then ' Noncompliant End If Dim nullableInt As Integer? = Nothing @@ -722,12 +754,12 @@ Public Class ConditionEvaluatesToConstant Public Async Function NotNullAfterAccess(ByVal o As Object, ByVal arr As Integer(,), ByVal coll As IEnumerable(Of Integer), ByVal task As Task) As Task Console.WriteLine(o.ToString()) - If o Is Nothing Then ' Noncompliant + If o Is Nothing Then ' Noncompliant End If Console.WriteLine(arr(42, 42)) - If arr Is Nothing Then ' Noncompliant + If arr Is Nothing Then ' Noncompliant End If @@ -930,37 +962,37 @@ Public Class ConditionEvaluatesToConstant Dim i As Integer? = Nothing Dim j As Integer? = 5 - If i < j Then ' Noncompliant + If i < j Then ' Noncompliant End If - If i <= j Then ' Noncompliant + If i <= j Then ' Noncompliant End If - If i > j Then ' Noncompliant + If i > j Then ' Noncompliant End If - If i >= j Then ' Noncompliant + If i >= j Then ' Noncompliant End If - If i > 0 Then ' Noncompliant + If i > 0 Then ' Noncompliant End If - If i >= 0 Then ' Noncompliant + If i >= 0 Then ' Noncompliant End If - If i < 0 Then ' Noncompliant + If i < 0 Then ' Noncompliant End If - If i <= 0 Then ' Noncompliant + If i <= 0 Then ' Noncompliant End If - If j > Nothing Then ' Noncompliant + If j > Nothing Then ' Noncompliant End If If j >= Nothing Then ' Noncompliant End If - If j < Nothing Then ' Noncompliant + If j < Nothing Then ' Noncompliant End If If j <= Nothing Then ' Noncompliant @@ -988,8 +1020,8 @@ Public Class ConditionEvaluatesToConstant Friend Structure MyStructWithNoOperator Public Shared Sub M(ByVal a As MyStructWithNoOperator) - If a Is Nothing Then ' Noncompliant, also a compiler error - ' Error@-1 [BC30020] + If a Is Nothing Then ' Noncompliant, also a compiler error + ' Error@-1 [BC30020] End If End Sub End Structure