From c7e2512e1b1cf42dff64b9ea9df7a9edaa52de2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=8Caba=20=C5=A0agi?= Date: Mon, 21 Mar 2022 15:50:16 +0100 Subject: [PATCH] S2E1 --- .../SymbolicExecution/Roslyn/ProgramState.cs | 3 +- .../Roslyn/RoslynSymbolicExecution.cs | 4 +-- .../Roslyn/ProgramStateTest.SymbolValue.cs | 4 +-- .../RoslynSymbolicExecutionTest.Branching.cs | 4 +-- .../RoslynSymbolicExecutionTest.Loops.cs | 7 ++-- .../Roslyn/RoslynSymbolicExecutionTest.cs | 33 +++---------------- .../SymbolicExecution/PreserveTestCheck.cs | 3 +- 7 files changed, 16 insertions(+), 42 deletions(-) diff --git a/analyzers/src/SonarAnalyzer.Common/SymbolicExecution/Roslyn/ProgramState.cs b/analyzers/src/SonarAnalyzer.Common/SymbolicExecution/Roslyn/ProgramState.cs index dd4038e6c49..f5af01b1af0 100644 --- a/analyzers/src/SonarAnalyzer.Common/SymbolicExecution/Roslyn/ProgramState.cs +++ b/analyzers/src/SonarAnalyzer.Common/SymbolicExecution/Roslyn/ProgramState.cs @@ -114,8 +114,7 @@ other is not null && other.OperationValue.DictionaryEquals(OperationValue) && other.SymbolValue.DictionaryEquals(SymbolValue) && other.CaptureOperation.DictionaryEquals(CaptureOperation) - && other.PreservedSymbols.Count == PreservedSymbols.Count - && other.PreservedSymbols.All(x => PreservedSymbols.Contains(x)); + && other.PreservedSymbols.SetEquals(PreservedSymbols); public override string ToString() => Equals(Empty) ? "Empty" : SerializeSymbols() + SerializeOperations() + SerializeCaptures(); diff --git a/analyzers/src/SonarAnalyzer.Common/SymbolicExecution/Roslyn/RoslynSymbolicExecution.cs b/analyzers/src/SonarAnalyzer.Common/SymbolicExecution/Roslyn/RoslynSymbolicExecution.cs index 1ebcd37f85d..5341187cc78 100644 --- a/analyzers/src/SonarAnalyzer.Common/SymbolicExecution/Roslyn/RoslynSymbolicExecution.cs +++ b/analyzers/src/SonarAnalyzer.Common/SymbolicExecution/Roslyn/RoslynSymbolicExecution.cs @@ -24,6 +24,7 @@ using Microsoft.CodeAnalysis; using SonarAnalyzer.CFG.LiveVariableAnalysis; using SonarAnalyzer.CFG.Roslyn; +using SonarAnalyzer.Helpers; using SonarAnalyzer.SymbolicExecution.Constraints; using SonarAnalyzer.SymbolicExecution.Roslyn.Checks; using SonarAnalyzer.SymbolicExecution.Roslyn.OperationProcessors; @@ -93,7 +94,6 @@ private IEnumerable ProcessBranching(ExplodedNode node) } else if (node.Block.ContainsThrow()) { - node = new ExplodedNode(cfg.ExitBlock, CleanUnusedState(node.State, node.Block), null); yield return CreateNode(cfg.ExitBlock, null, null); } else @@ -174,7 +174,7 @@ private static ProgramState ProcessOperation(SymbolicContext context) => private ProgramState CleanUnusedState(ProgramState programState, BasicBlock block) { - var liveVariables = lva.LiveOut(block); + var liveVariables = lva.LiveOut(block).ToHashSet(); return programState.RemoveSymbols(x => (x is ILocalSymbol or IParameterSymbol { RefKind: RefKind.None }) && !liveVariables.Contains(x)); } diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/SymbolicExecution/Roslyn/ProgramStateTest.SymbolValue.cs b/analyzers/tests/SonarAnalyzer.UnitTest/SymbolicExecution/Roslyn/ProgramStateTest.SymbolValue.cs index 3a3c587042e..3baf0a95303 100644 --- a/analyzers/tests/SonarAnalyzer.UnitTest/SymbolicExecution/Roslyn/ProgramStateTest.SymbolValue.cs +++ b/analyzers/tests/SonarAnalyzer.UnitTest/SymbolicExecution/Roslyn/ProgramStateTest.SymbolValue.cs @@ -121,7 +121,7 @@ public void SymbolsWith_IgnoreNullValue() } [TestMethod] - public void Preserve_PreservedSymbolCannotBeDeleted() + public void Preserve_PreservedSymbolCannotBeRemoved() { var symbolicValue = new SymbolicValue(new()).WithConstraint(DummyConstraint.Dummy); var symbol = CreateSymbols().First(); @@ -132,7 +132,7 @@ public void Preserve_PreservedSymbolCannotBeDeleted() } [TestMethod] - public void RemoveSymbols_RemovesTheSymbolMatchingThePredicate() + public void RemoveSymbols_RemovesSymbolsMatchingThePredicate() { var symbolicValue = new SymbolicValue(new()).WithConstraint(DummyConstraint.Dummy); var symbols = CreateSymbols().ToArray(); diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/SymbolicExecution/Roslyn/RoslynSymbolicExecutionTest.Branching.cs b/analyzers/tests/SonarAnalyzer.UnitTest/SymbolicExecution/Roslyn/RoslynSymbolicExecutionTest.Branching.cs index 3f9e6792db1..7856208a713 100644 --- a/analyzers/tests/SonarAnalyzer.UnitTest/SymbolicExecution/Roslyn/RoslynSymbolicExecutionTest.Branching.cs +++ b/analyzers/tests/SonarAnalyzer.UnitTest/SymbolicExecution/Roslyn/RoslynSymbolicExecutionTest.Branching.cs @@ -265,7 +265,7 @@ public void Branching_FieldSymbolsAreNotCleaned() [DataTestMethod] [DataRow("out", "outParam")] [DataRow("ref", "refParam")] - public void Branching_RefAndOutParameters_NotCleared(string paramType, string paramName) + public void Branching_RefAndOutParameters_NotCleared(string refKind, string paramName) { var code = $@" if (boolParameter) @@ -293,7 +293,7 @@ public void Branching_RefAndOutParameters_NotCleared(string paramType, string pa } return x.State; }); - var validator = SETestContext.CreateCS(code, $", {paramType} int {paramName}", postProcess).Validator; + var validator = SETestContext.CreateCS(code, $", {refKind} int {paramName}", postProcess).Validator; validator.ValidateExitReachCount(2); // Once with First constraint, once with Second constraint on "value" validator.TagValues("End").Should().HaveCount(2) .And.ContainSingle(x => x.HasConstraint(TestConstraint.First)) diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/SymbolicExecution/Roslyn/RoslynSymbolicExecutionTest.Loops.cs b/analyzers/tests/SonarAnalyzer.UnitTest/SymbolicExecution/Roslyn/RoslynSymbolicExecutionTest.Loops.cs index 7f57406eda0..2a3b4515e39 100644 --- a/analyzers/tests/SonarAnalyzer.UnitTest/SymbolicExecution/Roslyn/RoslynSymbolicExecutionTest.Loops.cs +++ b/analyzers/tests/SonarAnalyzer.UnitTest/SymbolicExecution/Roslyn/RoslynSymbolicExecutionTest.Loops.cs @@ -55,7 +55,7 @@ public void Loops_InstructionVisitedMaxTwice_EvenWithMultipleStates() { const string code = @" var value = 42; -bool condition; +bool condition = false; if(boolParameter) // This generates two different ProgramStates, each tracks its own visits condition = true; else @@ -64,10 +64,9 @@ public void Loops_InstructionVisitedMaxTwice_EvenWithMultipleStates() { value.ToString(); // Add another constraint to 'value' } while (boolParameter); -Tag(""HoldRef"", condition); Tag(""End"", value);"; - var validator = SETestContext.CreateCS(code, ", int[] items", new AddConstraintOnInvocationCheck()).Validator; - validator.ValidateExitReachCount(1); + var validator = SETestContext.CreateCS(code, ", int[] items", new AddConstraintOnInvocationCheck(), new PreserveTestCheck("condition")).Validator; + validator.ValidateExitReachCount(2); var states = validator.TagStates("End"); var condition = states.SelectMany(x => x.SymbolsWith(BoolConstraint.False)).First(); // "False" is never set for "value" var value = states.SelectMany(x => x.SymbolsWith(TestConstraint.First)).First(); // "First" is never set for "condition" diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/SymbolicExecution/Roslyn/RoslynSymbolicExecutionTest.cs b/analyzers/tests/SonarAnalyzer.UnitTest/SymbolicExecution/Roslyn/RoslynSymbolicExecutionTest.cs index 4903bc15fd8..29138de4de1 100644 --- a/analyzers/tests/SonarAnalyzer.UnitTest/SymbolicExecution/Roslyn/RoslynSymbolicExecutionTest.cs +++ b/analyzers/tests/SonarAnalyzer.UnitTest/SymbolicExecution/Roslyn/RoslynSymbolicExecutionTest.cs @@ -179,51 +179,28 @@ static ISymbol LocalReferenceOperationSymbol(IOperationWrapperSonar operation) = public void Execute_UnusedVariable_ClearedAfterBlock() { const string code = @" -bool first; -if(boolParameter) - first = true; -else - first = false; +var first = boolParameter ? true : false; Tag(""BeforeLastUse""); bool second = first; if(boolParameter) -boolParameter.ToString(); + boolParameter.ToString(); Tag(""AfterLastUse""); -bool third = second; -if(boolParameter) -boolParameter.ToString(); -Tag(""END""); "; ISymbol firstSymbol = null; - ISymbol secondSymbol = null; var postProcess = new PostProcessTestCheck(x => { if (x.Operation.Instance.TrackedSymbol() is { } symbol) { - if (symbol.Name.Equals("first")) + if (symbol.Name == "first") { firstSymbol = symbol; } - else if (symbol.Name.Equals("second")) - { - secondSymbol = symbol; - } } return x.State; }); var validator = SETestContext.CreateCS(code, postProcess).Validator; - validator.ValidateTagOrder( - "BeforeLastUse", - "BeforeLastUse", - "AfterLastUse", - "AfterLastUse", - "END"); - var beforeLastUseStates = validator.TagStates("BeforeLastUse"); - beforeLastUseStates.Should().HaveCount(2); - beforeLastUseStates.All(x => x[firstSymbol] != null).Should().BeTrue(); - var afterLastUseStates = validator.TagStates("AfterLastUse"); - afterLastUseStates.Should().HaveCount(2); - afterLastUseStates.All(x => x[firstSymbol] == null && x[secondSymbol] != null).Should().BeTrue(); + validator.TagStates("BeforeLastUse").Should().HaveCount(2).And.OnlyContain(x => x[firstSymbol] != null); + validator.TagStates("AfterLastUse").Should().HaveCount(1).And.OnlyContain(x => x[firstSymbol] == null); } [TestMethod] diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/TestFramework/SymbolicExecution/PreserveTestCheck.cs b/analyzers/tests/SonarAnalyzer.UnitTest/TestFramework/SymbolicExecution/PreserveTestCheck.cs index 584744de335..e54ed0eddee 100644 --- a/analyzers/tests/SonarAnalyzer.UnitTest/TestFramework/SymbolicExecution/PreserveTestCheck.cs +++ b/analyzers/tests/SonarAnalyzer.UnitTest/TestFramework/SymbolicExecution/PreserveTestCheck.cs @@ -30,8 +30,7 @@ public PreserveTestCheck(string symbolName) => this.symbolName = symbolName; protected override ProgramState PreProcessSimple(SymbolicContext context) => - context.Operation.Instance.TrackedSymbol() is { } symbol - && symbol.Name == symbolName + context.Operation.Instance.TrackedSymbol() is { } symbol && symbol.Name == symbolName ? context.State.Preserve(symbol) : context.State; }