From cfee18a155ab7bf547d822d6a414cc9e45eebbbd Mon Sep 17 00:00:00 2001 From: Zsolt Kolbay <121798625+zsolt-kolbay-sonarsource@users.noreply.github.com> Date: Tue, 19 Dec 2023 13:39:43 +0100 Subject: [PATCH] Fix S2583/S2589 FP: Tuple deconstruction assignment (#8461) --- .../Roslyn/Extensions/IOperationExtensions.cs | 9 ++ .../Roslyn/OperationDispatcher.cs | 1 + .../DeconstructionAssignment.cs | 85 ++++++++++++++++ .../SymbolicExecution/Roslyn/ProgramState.cs | 10 ++ ...rogramStateTest.OperationAndSymbolValue.cs | 58 +++++++++++ .../ConditionEvaluatesToConstant.CSharp10.cs | 32 +++++++ .../ConditionEvaluatesToConstant.CSharp7.cs | 4 +- .../ConditionEvaluatesToConstant.CSharp8.cs | 6 +- .../ConditionEvaluatesToConstant.CSharp9.cs | 4 +- .../Roslyn/ConditionEvaluatesToConstant.cs | 96 ++++++++++++++++--- ...llectionsShouldNotBeEnumerated.CSharp10.cs | 4 +- .../EmptyNullableValueAccess.CSharp10.cs | 2 +- .../Roslyn/EmptyNullableValueAccess.cs | 22 ++--- ...hesShouldHaveUnpredictableSalt.CSharp10.cs | 2 +- ...ializationVectorShouldBeRandom.CSharp10.cs | 2 +- .../Roslyn/NullPointerDereference.CSharp10.cs | 5 +- .../ObjectsShouldNotBeDisposedMoreThanOnce.cs | 2 +- 17 files changed, 304 insertions(+), 40 deletions(-) create mode 100644 analyzers/src/SonarAnalyzer.Common/SymbolicExecution/Roslyn/OperationProcessors/DeconstructionAssignment.cs create mode 100644 analyzers/tests/SonarAnalyzer.UnitTest/SymbolicExecution/Roslyn/ProgramStateTest.OperationAndSymbolValue.cs diff --git a/analyzers/src/SonarAnalyzer.Common/SymbolicExecution/Roslyn/Extensions/IOperationExtensions.cs b/analyzers/src/SonarAnalyzer.Common/SymbolicExecution/Roslyn/Extensions/IOperationExtensions.cs index aad5714ecc0..0e9119f27ac 100644 --- a/analyzers/src/SonarAnalyzer.Common/SymbolicExecution/Roslyn/Extensions/IOperationExtensions.cs +++ b/analyzers/src/SonarAnalyzer.Common/SymbolicExecution/Roslyn/Extensions/IOperationExtensions.cs @@ -51,6 +51,9 @@ OperationKindEx.PropertyReference when operation.ToPropertyReference() is { Prop internal static IConversionOperationWrapper? AsConversion(this IOperation operation) => operation.As(OperationKindEx.Conversion, IConversionOperationWrapper.FromOperation); + internal static IDeclarationExpressionOperationWrapper? AsDeclarationExpression(this IOperation operation) => + operation.As(OperationKindEx.DeclarationExpression, IDeclarationExpressionOperationWrapper.FromOperation); + internal static IDeclarationPatternOperationWrapper? AsDeclarationPattern(this IOperation operation) => operation.As(OperationKindEx.DeclarationPattern, IDeclarationPatternOperationWrapper.FromOperation); @@ -69,6 +72,9 @@ OperationKindEx.PropertyReference when operation.ToPropertyReference() is { Prop internal static IPropertyReferenceOperationWrapper? AsPropertyReference(this IOperation operation) => operation.As(OperationKindEx.PropertyReference, IPropertyReferenceOperationWrapper.FromOperation); + internal static ITupleOperationWrapper? AsTuple(this IOperation operation) => + operation.As(OperationKindEx.Tuple, ITupleOperationWrapper.FromOperation); + internal static IAwaitOperationWrapper ToAwait(this IOperation operation) => IAwaitOperationWrapper.FromOperation(operation); @@ -123,6 +129,9 @@ internal static IParameterReferenceOperationWrapper ToParameterReference(this IO internal static IEventReferenceOperationWrapper ToEventReference(this IOperation operation) => IEventReferenceOperationWrapper.FromOperation(operation); + internal static ITupleOperationWrapper ToTuple(this IOperation operation) => + ITupleOperationWrapper.FromOperation(operation); + internal static IUnaryOperationWrapper ToUnary(this IOperation operation) => IUnaryOperationWrapper.FromOperation(operation); diff --git a/analyzers/src/SonarAnalyzer.Common/SymbolicExecution/Roslyn/OperationDispatcher.cs b/analyzers/src/SonarAnalyzer.Common/SymbolicExecution/Roslyn/OperationDispatcher.cs index 8bfbeb47c9c..e20c87f3d23 100644 --- a/analyzers/src/SonarAnalyzer.Common/SymbolicExecution/Roslyn/OperationDispatcher.cs +++ b/analyzers/src/SonarAnalyzer.Common/SymbolicExecution/Roslyn/OperationDispatcher.cs @@ -45,6 +45,7 @@ internal static class OperationDispatcher { OperationKindEx.CompoundAssignment, new CompoundAssignment() }, { OperationKindEx.Conversion, new Conversion() }, { OperationKindEx.DeclarationPattern, new DeclarationPattern() }, + { OperationKindEx.DeconstructionAssignment, new DeconstructionAssignment() }, { OperationKindEx.Decrement, new IncrementOrDecrement() }, { OperationKindEx.DefaultValue, new DefaultValue() }, { OperationKindEx.DelegateCreation, new NotNullOperation() }, diff --git a/analyzers/src/SonarAnalyzer.Common/SymbolicExecution/Roslyn/OperationProcessors/DeconstructionAssignment.cs b/analyzers/src/SonarAnalyzer.Common/SymbolicExecution/Roslyn/OperationProcessors/DeconstructionAssignment.cs new file mode 100644 index 00000000000..4accfa85eba --- /dev/null +++ b/analyzers/src/SonarAnalyzer.Common/SymbolicExecution/Roslyn/OperationProcessors/DeconstructionAssignment.cs @@ -0,0 +1,85 @@ +/* + * 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.OperationProcessors; + +internal sealed class DeconstructionAssignment : SimpleProcessor +{ + protected override IDeconstructionAssignmentOperationWrapper Convert(IOperation operation) => + IDeconstructionAssignmentOperationWrapper.FromOperation(operation); + + protected override ProgramState Process(SymbolicContext context, IDeconstructionAssignmentOperationWrapper assignment) + { + var operationValues = TupleElementValues(context.State, assignment.Target, assignment.Value); + var newState = context.State; + foreach (var (tupleMember, value) in operationValues) + { + newState = newState.SetOperationAndSymbolValue(tupleMember, value); + } + return newState; + } + + private static IEnumerable TupleElementValues(ProgramState state, IOperation target, IOperation value) + { + var operationValues = new List(); + var leftTupleElements = TupleElements(Unwrap(target, state).ToTuple(), state); + // If the right side is a tuple, then every symbol/constraint is copied to the left side. + if (Unwrap(value, state).AsTuple() is { } rightSideTuple) + { + var rightTupleElements = TupleElements(rightSideTuple, state); + for (var i = 0; i < leftTupleElements.Length; i++) + { + var leftTupleMember = leftTupleElements[i]; + var rightTupleMember = rightTupleElements[i]; + if (leftTupleMember.Kind == OperationKindEx.Discard) + { + continue; + } + else if (leftTupleMember.AsTuple() is { } nestedTuple) + { + operationValues.AddRange(TupleElementValues(state, nestedTuple.WrappedOperation, rightTupleMember)); + } + else + { + operationValues.Add(new(leftTupleMember, state[rightTupleMember])); + } + } + } + // If the right side is not a tuple, then every member of the left side tuple is set to empty. + else + { + operationValues.AddRange(leftTupleElements + .Where(x => x.Kind != OperationKindEx.Discard) + .Select(x => new OperationValue(x, SymbolicValue.Empty))); + } + return operationValues; + } + + private static IOperation[] TupleElements(ITupleOperationWrapper operation, ProgramState state) => + operation.Elements.Select(x => Unwrap(x, state)).ToArray(); + + private static IOperation Unwrap(IOperation operation, ProgramState state) + { + var unwrapped = state.ResolveCaptureAndUnwrapConversion(operation); + return unwrapped.AsDeclarationExpression()?.Expression ?? unwrapped; + } + + private sealed record OperationValue(IOperation Operation, SymbolicValue Value); +} diff --git a/analyzers/src/SonarAnalyzer.Common/SymbolicExecution/Roslyn/ProgramState.cs b/analyzers/src/SonarAnalyzer.Common/SymbolicExecution/Roslyn/ProgramState.cs index 1931f74c1d8..29be2be48b8 100644 --- a/analyzers/src/SonarAnalyzer.Common/SymbolicExecution/Roslyn/ProgramState.cs +++ b/analyzers/src/SonarAnalyzer.Common/SymbolicExecution/Roslyn/ProgramState.cs @@ -63,6 +63,16 @@ protected ProgramState(ProgramState original) // Custom record override constr Exceptions = original.Exceptions; } + public ProgramState SetOperationAndSymbolValue(IOperation operation, SymbolicValue value) + { + var newState = SetOperationValue(operation, value); + if (operation.TrackedSymbol(this) is { } symbol) + { + newState = newState.SetSymbolValue(symbol, value); + } + return newState; + } + public ProgramState SetOperationValue(IOperationWrapper operation, SymbolicValue value) => operation is null ? throw new ArgumentNullException(nameof(operation)) diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/SymbolicExecution/Roslyn/ProgramStateTest.OperationAndSymbolValue.cs b/analyzers/tests/SonarAnalyzer.UnitTest/SymbolicExecution/Roslyn/ProgramStateTest.OperationAndSymbolValue.cs new file mode 100644 index 00000000000..9efc57ef66c --- /dev/null +++ b/analyzers/tests/SonarAnalyzer.UnitTest/SymbolicExecution/Roslyn/ProgramStateTest.OperationAndSymbolValue.cs @@ -0,0 +1,58 @@ +/* + * 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. + */ + +using SonarAnalyzer.SymbolicExecution.Roslyn; +using SonarAnalyzer.UnitTest.TestFramework.SymbolicExecution; + +namespace SonarAnalyzer.UnitTest.SymbolicExecution.Roslyn; + +public partial class ProgramStateTest +{ + [TestMethod] + public void SetOperationAndSymbolValue_TrackedSymbol() + { + var operations = TestHelper.CompileCfgBodyCS("bool b = true;").Blocks[1].Operations; + var localReference = operations[0].ChildOperations.First().ToLocalReference(); + var symbol = localReference.Local; + var sut = ProgramState.Empty; + + sut[localReference].Should().BeNull(); + sut[symbol].Should().BeNull(); + + sut = sut.SetOperationAndSymbolValue(localReference.WrappedOperation, SymbolicValue.True); + + sut[localReference].Should().Be(SymbolicValue.True); + sut[symbol].Should().Be(SymbolicValue.True); + } + + [TestMethod] + public void SetOperationAndSymbolValue_NotTrackedSymbol() + { + var operations = TestHelper.CompileCfgBodyCS("""var texts = new string[] { }; texts[42] = string.Empty;""").Blocks[1].Operations; + var arrayElementReference = operations[1].ChildOperations.First().ChildOperations.First().ToArrayElementReference(); + var sut = ProgramState.Empty; + + sut[arrayElementReference].Should().BeNull(); + + sut = sut.SetOperationAndSymbolValue(arrayElementReference.WrappedOperation, SymbolicValue.NotNull); + + sut[arrayElementReference].Should().Be(SymbolicValue.NotNull); + } +} diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.CSharp10.cs b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.CSharp10.cs index ee7913755f9..067c4afdf84 100644 --- a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.CSharp10.cs +++ b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.CSharp10.cs @@ -26,3 +26,35 @@ public static void DoSomething() else if (myStruct.y) { } // FN } } + +// https://github.com/SonarSource/sonar-dotnet/issues/7057 +public class Repro_7057 +{ + private (string, int) SomeTuple() => ("hello", 1); + private string SomeString() => "hello"; + + public void WithTuple() + { + string text1 = null; + (text1, var (text2, _)) = (SomeString(), SomeTuple()); + if (text1 == null) // Compliant + { + Console.WriteLine(); + } + if (text2 == null) // Compliant + { + Console.WriteLine(); + } + + string text3 = null; + ((text3, _), var (text4, _)) = ((null, 42), ("hello", 42)); + if (text3 == null) // Noncompliant + { + Console.WriteLine(); + } + if (text4 == null) // Noncompliant + { + Console.WriteLine(); // Secondary + } + } +} diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.CSharp7.cs b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.CSharp7.cs index f13b139fdaa..fa347eef33e 100644 --- a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.CSharp7.cs +++ b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.CSharp7.cs @@ -294,7 +294,7 @@ public void GoGoGo() { var tmp = 0; var flag = true; - while (flag) // Noncompliant + while (flag) // Compliant { (flag, tmp) = (false, 5); } @@ -329,7 +329,7 @@ public void MutedNull() { var tmp = 0; var flag = "x"; - while (flag != null) // Noncompliant + while (flag != null) // Compliant { (flag, tmp) = (null, 5); } 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 6d5bb711a33..4238bfa0c5f 100644 --- a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.CSharp8.cs +++ b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.CSharp8.cs @@ -133,8 +133,8 @@ public void ParenthesizedVariableDesignation_Nested(object arg) public void NestedDeconstructionAssignment() { var (a, (b, _)) = (true, (true, true)); - if (a) { } // FN - if (b) { } // FN + if (a) { } // Noncompliant + if (b) { } // Noncompliant } int UsingDeclaration_Null() @@ -330,7 +330,7 @@ public void AssignmentTarget(bool arg) { } - if (b) // FN + if (b) // Noncompliant { } } 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 12b5ce83377..2b33b3831d0 100644 --- a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.CSharp9.cs +++ b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.CSharp9.cs @@ -121,11 +121,11 @@ public object InitWithTupleAssignment { var tmp = 0; var flag = true; - while (flag) // Noncompliant + while (flag) // Compliant { (flag, tmp) = (false, 5); } - o = value; // Secondary + o = value; } } } diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.cs b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.cs index c1a053690cb..590238bb90e 100644 --- a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.cs +++ b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ConditionEvaluatesToConstant.cs @@ -3125,7 +3125,7 @@ public void Go() (memoryStream, str) = GetData(); - if (memoryStream != null) // Noncompliant FP: memoryStream was reassigned as a tuple + if (memoryStream != null) // Compliant: memoryStream was reassigned as a tuple { // some code } @@ -3142,27 +3142,97 @@ public class Repro_7057 public void WithTuple() { - string current = null; - string last; - do + string text1 = null; + (text1, _) = SomeTuple(); + if (text1 == null) // Compliant + { + Console.WriteLine(); + } + + string text2 = ""; + (text2, _) = (null, 42); + if (text2 == null) // Noncompliant + { + Console.WriteLine(); + } + + string text3 = null; + ((text3, _), _) = (SomeTuple(), 42); + if (text3 == null) // Compliant + { + Console.WriteLine(); + } + + var (text4, _) = SomeTuple(); + if (text4 == null) // Compliant + { + Console.WriteLine(); + } + + var (text5, _) = (null as string, 42); + if (text5 == null) // Noncompliant + { + Console.WriteLine(); + } + + string text6 = null; + (_, (text6, _)) = (42, SomeTuple()); + if (text6 == null) // Compliant { - last = current; - (current, _) = SomeTuple(); + Console.WriteLine(); + } + + string text7 = ""; + (_, (text7, _)) = (SomeTuple(), (null, 42)); + if (text7 == null) // Noncompliant + { + Console.WriteLine(); + } + + string text8, text9, text10; + text8 = text9 = text10 = SomeString(); + (text8, (text9, text10)) = ("", ("", "")); + if (text8 == null // Noncompliant + || text9 == null // Noncompliant + || text10 == null) // Noncompliant + { + Console.WriteLine(); // Secondary + } + + var tuple = ("hello", 42); + if (tuple.Item1 == null) // FN + { + Console.WriteLine(); + } + + string text11 = SomeString(); + string text12 = null; + (text11, text12) = (text12, text11); + if (text11 == null) // Noncompliant + { + Console.WriteLine(); + } + if (text12 == null) // Compliant + { + Console.WriteLine(); + } + + string text13; + (text13, text13) = (SomeString(), null); + if (text11 == null) // Noncompliant + { + Console.WriteLine(); } - while (last == null); // Noncompliant FP } public void WithString() { string current = null; - string last; - - do + current = SomeString(); + if (current == null) // Compliant { - last = current; - current = SomeString(); + Console.WriteLine(); } - while (last == null); } } diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/EmptyCollectionsShouldNotBeEnumerated.CSharp10.cs b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/EmptyCollectionsShouldNotBeEnumerated.CSharp10.cs index da8398655f0..2ba1f80c06e 100644 --- a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/EmptyCollectionsShouldNotBeEnumerated.CSharp10.cs +++ b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/EmptyCollectionsShouldNotBeEnumerated.CSharp10.cs @@ -8,12 +8,12 @@ public void Method() List list; (list, var a) = (new List(), 42); - list.Clear(); // FN + list.Clear(); // Noncompliant list.Add(42); list.Clear(); (var list2, var b) = (new List(), 42); - list2.Clear(); // FN + list2.Clear(); // Noncompliant list2.Add(42); list2.Clear(); diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/EmptyNullableValueAccess.CSharp10.cs b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/EmptyNullableValueAccess.CSharp10.cs index 5bc7bbdbc72..dc703e1e5b9 100644 --- a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/EmptyNullableValueAccess.CSharp10.cs +++ b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/EmptyNullableValueAccess.CSharp10.cs @@ -7,7 +7,7 @@ public void Destructuring() int? nullable; (nullable, _) = (null, 42); - var v = nullable.Value; // FN + var v = nullable.Value; // Noncompliant nullable = null; v = nullable.Value; // Noncompliant diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/EmptyNullableValueAccess.cs b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/EmptyNullableValueAccess.cs index 91553cee746..84b38eccec4 100644 --- a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/EmptyNullableValueAccess.cs +++ b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/EmptyNullableValueAccess.cs @@ -148,13 +148,13 @@ class AssignmentAndDeconstruction void TypeInference() { (int? discard, int? b) = (null, null); - _ = b.Value; // FN: b is empty + _ = b.Value; // Noncompliant } void FirstLevel() { var (b, _) = (null as bool?, null as bool?); - _ = b.Value; // FN: b is empty + _ = b.Value; // Noncompliant } void SecondLevel() @@ -162,7 +162,7 @@ void SecondLevel() (int? i1, (int? i2, int? i3)) = (42, (42, null)); _ = i1.Value; // Compliant _ = i2.Value; // Compliant - _ = i3.Value; // FN + _ = i3.Value; // Noncompliant } void ThirdLevel() @@ -171,7 +171,7 @@ void ThirdLevel() _ = i1.Value; // Compliant _ = i2.Value; // Compliant _ = i3.Value; // Compliant - _ = i4.Value; // FN + _ = i4.Value; // Noncompliant _ = i5.Value; // Compliant } @@ -179,7 +179,7 @@ void WithDiscard() { (_, (int? i1, (int?, int?) _, int? i2)) = (42, (42, (42, null), null)); _ = i1.Value; // Compliant - _ = i2.Value; // FN + _ = i2.Value; // Noncompliant } void TwoWaySwapping() @@ -187,8 +187,8 @@ void TwoWaySwapping() bool? b1 = null; bool? b2 = true; (b1, b2) = (b2, b1); - _ = b1.Value; // Noncompliant, FP: after swapping is non-empty - _ = b2.Value; // FN: after swapping is empty + _ = b1.Value; // Compliant: after swapping is non-empty + _ = b2.Value; // Noncompliant } void ThreeWaySwapping() @@ -197,9 +197,9 @@ void ThreeWaySwapping() bool? b2 = true; bool? b3 = null; (b1, b2, b3) = (b2, b3, b2); - _ = b1.Value; // Noncompliant, FP: after swapping is non-empty - _ = b2.Value; // FN: after swapping is empty - _ = b3.Value; // Noncompliant, FP: after swapping is non-empty + _ = b1.Value; // Compliant: after swapping is non-empty + _ = b2.Value; // Noncompliant + _ = b3.Value; // Compliant: after swapping is non-empty } void CustomDeconstruction() @@ -209,7 +209,7 @@ void CustomDeconstruction() _ = i1.Value; // Compliant _ = i2.Value; // Compliant, unknown _ = i3.Value; // Compliant, unknown - _ = i4.Value; // FN + _ = i4.Value; // Noncompliant } struct DeconstructableStruct diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/HashesShouldHaveUnpredictableSalt.CSharp10.cs b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/HashesShouldHaveUnpredictableSalt.CSharp10.cs index 56984d14156..e4fcd05e66c 100644 --- a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/HashesShouldHaveUnpredictableSalt.CSharp10.cs +++ b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/HashesShouldHaveUnpredictableSalt.CSharp10.cs @@ -5,6 +5,6 @@ public class Sample public void Examples(byte[] passwordBytes) { (var shortSalt, int a) = (new byte[15], 42); - PasswordDeriveBytes aes = new PasswordDeriveBytes(passwordBytes, shortSalt); // FN + PasswordDeriveBytes aes = new PasswordDeriveBytes(passwordBytes, shortSalt); // Noncompliant } } diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/InitializationVectorShouldBeRandom.CSharp10.cs b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/InitializationVectorShouldBeRandom.CSharp10.cs index 28ac6be3f71..f4a0327a7bb 100644 --- a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/InitializationVectorShouldBeRandom.CSharp10.cs +++ b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/InitializationVectorShouldBeRandom.CSharp10.cs @@ -9,6 +9,6 @@ public void Examples() AesCng aes = new AesCng(); aes.CreateEncryptor(); (var rgb, int a) = (new byte[16], 42); - aes.CreateEncryptor(aes.Key, rgb); // FN + aes.CreateEncryptor(aes.Key, rgb); // Noncompliant } } diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/NullPointerDereference.CSharp10.cs b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/NullPointerDereference.CSharp10.cs index a6e12c81531..ef74e9a3e7b 100644 --- a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/NullPointerDereference.CSharp10.cs +++ b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/NullPointerDereference.CSharp10.cs @@ -8,16 +8,15 @@ public class Sample public void Examples() { StringBuilder sb = new(); - (sb, int a) = (null, 42); - sb.ToString(); // FN + sb.ToString(); // Noncompliant } public void Unassigned() { StringBuilder isNull, hasValue; (isNull, hasValue) = (null, new StringBuilder()); - isNull.ToString(); // FN + isNull.ToString(); // Noncompliant hasValue.ToString(); } } diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ObjectsShouldNotBeDisposedMoreThanOnce.cs b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ObjectsShouldNotBeDisposedMoreThanOnce.cs index eb4447bfe0a..adebcfb720f 100644 --- a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ObjectsShouldNotBeDisposedMoreThanOnce.cs +++ b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SymbolicExecution/Roslyn/ObjectsShouldNotBeDisposedMoreThanOnce.cs @@ -250,7 +250,7 @@ public static void LoopOfTuples(List disposables, List<(int I, IDis disposable.Dispose(); // Compliant foreach (var (_, disposable) in tuples) - disposable.Dispose(); // Noncompliant FP + disposable.Dispose(); // Compliant } }