From 579e9e118a7b1fdd8338cddb171fb49dfe830e67 Mon Sep 17 00:00:00 2001 From: mary-georgiou-sonarsource Date: Fri, 14 Jun 2024 11:42:32 +0200 Subject: [PATCH] Add tests --- .../RoslynLiveVariableAnalysisTest.cs | 206 ++++++++++++++++++ 1 file changed, 206 insertions(+) diff --git a/analyzers/tests/SonarAnalyzer.Test/LiveVariableAnalysis/RoslynLiveVariableAnalysisTest.cs b/analyzers/tests/SonarAnalyzer.Test/LiveVariableAnalysis/RoslynLiveVariableAnalysisTest.cs index 86878d58fa6..17eca3538d2 100644 --- a/analyzers/tests/SonarAnalyzer.Test/LiveVariableAnalysis/RoslynLiveVariableAnalysisTest.cs +++ b/analyzers/tests/SonarAnalyzer.Test/LiveVariableAnalysis/RoslynLiveVariableAnalysisTest.cs @@ -1000,6 +1000,212 @@ public Sample() new Context(code, SyntaxKind.Block).ValidateAllEmpty(); } + #region CaptureReferenceTests + + [TestMethod] + public void FlowCaptrure_NullCoalescingAssignment() + { + /* Block 1 + * #0=stringParam + * | + * Block 2 + * #1=#0 + * #1 is null --+ + * | | + * Block 3 | + * #0=Hello | + * | | + * Exit <-----+ + */ + const string code = """stringParam ??= "Hello";"""; + var context = CreateContextCS(code, additionalParameters: "string stringParam"); + context.ValidateEntry(LiveIn("stringParam"), LiveOut("stringParam")); + context.Validate(context.Cfg.Blocks[1], null, LiveIn("stringParam"), LiveOut("stringParam")); + context.Validate(context.Cfg.Blocks[2], null, LiveIn("stringParam")); + context.Validate(context.Cfg.Blocks[3], null); + context.ValidateExit(); + } + + [TestMethod] + public void FlowCaptrure_NullCoalescingOperator() + { + /* Block 1 + * #0=stringParam + * #0 is null + * / \ + * / \ + * Block 3 Block 4 + * #1=#0 #1="Hello" + * \ / + * Block 5 + * s=#1 + * | + * Exit + */ + const string code = """string s = stringParam ?? "Hello";"""; + var context = CreateContextCS(code, additionalParameters: "string stringParam"); + context.ValidateEntry(LiveIn("stringParam"), LiveOut("stringParam")); + context.Validate(context.Cfg.Blocks[1], null, LiveIn("stringParam"), LiveOut("stringParam")); + context.Validate(context.Cfg.Blocks[2], null, LiveIn("stringParam"), LiveOut("stringParam")); + context.Validate(context.Cfg.Blocks[3], null, LiveIn("stringParam"), LiveOut("stringParam")); + context.Validate(context.Cfg.Blocks[4], null); + context.Validate(context.Cfg.Blocks[5], null, LiveIn("stringParam")); + context.ValidateExit(); + } + + [TestMethod] + public void FlowCaptrure_NullConditionalOperators() + { + /* Block 1 + * #0=stringParam + * #0 is null + * / \ + * / \ + * Block 2 Block 3 + * #1=Length #1="Hello" + * \ / + * Block 4 + * result=#1 + * | + * Exit + */ + const string code = """int? anInt = stringParam.?Length;"""; + var context = CreateContextCS(code, additionalParameters: "string stringParam"); + context.ValidateEntry(LiveIn("stringParam"), LiveOut("stringParam")); + context.Validate(context.Cfg.Blocks[1], null, LiveIn("stringParam"), LiveOut("stringParam")); + context.Validate(context.Cfg.Blocks[2], null); + context.Validate(context.Cfg.Blocks[3], null, LiveIn("stringParam"), LiveOut("stringParam")); + context.Validate(context.Cfg.Blocks[4], null, LiveIn("stringParam")); + context.ValidateExit(); + } + + [TestMethod] + public void FlowCaptrure_TernaryConditionalOperator() + { + /* Block 1 + * boolParameter + * / \ + * / \ + * Block 2 Block 3 + * #0=test #0="Hello" + * \ / + * Block 4 + * result=#0 + * | + * Exit + */ + const string code = """string s = boolParameter ? stringParam : "Hello";"""; + var context = CreateContextCS(code, additionalParameters: "string stringParam"); + context.ValidateEntry(LiveIn("boolParameter", "stringParam"), LiveOut("boolParameter", "stringParam")); + context.Validate(context.Cfg.Blocks[1], null, LiveIn("boolParameter", "stringParam"), LiveOut("stringParam")); + context.Validate(context.Cfg.Blocks[2], null, LiveIn("stringParam"), LiveOut("stringParam")); + context.Validate(context.Cfg.Blocks[3], null, LiveIn("stringParam"), LiveOut("stringParam")); + context.Validate(context.Cfg.Blocks[4], null, LiveIn("stringParam")); + context.ValidateExit(); + } + + [TestMethod] + public void FlowCaptrure_NullCoalescingOperator_ConsequentCalls() + { + /* Block 1 + * #0=s1 + * #0 is null + * / \ + * / \ + * Block 2 Block 3 +--F--> Block 4 --------+ + * #1=#0 #2=s2 | #1=#2 | + * \ / | | + * Block 6 <-+ +--T--> Block 5-------->| + * s=#1 | #1="Hello" | + * | +-------------------------+ + * Exit + */ + const string code = """string s = s1 ?? s2 ?? "Hello";"""; + var context = CreateContextCS(code, additionalParameters: "string s1, string s2"); + context.ValidateEntry(LiveIn("s1", "s2"), LiveOut("s1", "s2")); + context.Validate(context.Cfg.Blocks[1], null, LiveIn("s1", "s2"), LiveOut("s1, s2")); + context.Validate(context.Cfg.Blocks[2], null, LiveIn("s1", "s2"), LiveOut("s1")); + context.Validate(context.Cfg.Blocks[3], null, LiveIn("s1", "s2"), LiveOut("s2")); + context.Validate(context.Cfg.Blocks[4], null, LiveIn("s2"), LiveOut("s2")); + context.Validate(context.Cfg.Blocks[5], null, LiveIn("s2")); + context.Validate(context.Cfg.Blocks[6], null, LiveIn("s1, s2")); + context.ValidateExit(); + } + + [TestMethod] + public void FlowCaptrure_NullCoalescingOperator_Nested() + { + /* Block 1 + * #0=s1 + * #0 is null + * / \ + * / \ + * Block 2 Block 3 +------F----> Block 4 --------+ + * #1=#0 s2 is null | #2="NestedTrue" | + * \ / | | + * Block 6 +------T----> Block 5-------->| + * s=#1 #2="NestedFalse" | + * | | + * | Block6<--+ + * | #2 is null + * | / \ + * | T F + * | / \ + * | Block8 Block7 + * | #1="Hello" #1=#2" + * | | | + * +------------>Block9<---------+---------+ + * s1=#1 + * | + * Exit + */ + const string code = """string s = s1 ?? (s2 is null? "NestedTrue" : "NestedFalse") ?? "Hello";"""; + var context = CreateContextCS(code, additionalParameters: "string s1, string s2"); + context.ValidateEntry(LiveIn("s1", "s2"), LiveOut("s1", "s2")); + context.Validate(context.Cfg.Blocks[1], null, LiveIn("s1", "s2"), LiveOut("s1, s2")); + context.Validate(context.Cfg.Blocks[2], null, LiveIn("s1", "s2"), LiveOut("s1")); + context.Validate(context.Cfg.Blocks[3], null, LiveIn("s1", "s2"), LiveOut("s2")); + context.Validate(context.Cfg.Blocks[4], null, LiveIn("s2"), LiveOut("s2")); + context.Validate(context.Cfg.Blocks[5], null, LiveIn("s2"), LiveOut("s2")); + context.Validate(context.Cfg.Blocks[6], null, LiveIn("s2"), LiveOut("s2")); + context.Validate(context.Cfg.Blocks[7], null, LiveIn("s2"), LiveOut("s2")); + context.Validate(context.Cfg.Blocks[8], null, LiveIn("s2")); + context.Validate(context.Cfg.Blocks[9], null, LiveIn("s1, s2")); + context.ValidateExit(); + } + + [TestMethod] + public void FlowCaptrure_NullCoalescingOperator_Overwrite() + { + /* Block 1 + * #0=s1 + * | + * Block 2 + * #1=(s1="overwrite") + * #1 is null + * / \ + * T F + * / \ + * Block3 Block4 + * #2=#1 #2="value" + * \ / + * \ / + * Block5 + * s1=#2 + */ + const string code = """s1 = (s1 = "overwrite") ?? "value";"""; + var context = CreateContextCS(code, additionalParameters: "string s1"); + context.ValidateEntry(LiveIn("s1"), LiveOut("s1")); + context.Validate(context.Cfg.Blocks[1], null, LiveIn("s1"), LiveOut("s1")); + context.Validate(context.Cfg.Blocks[2], null, LiveIn("s1"), LiveOut("s1")); + context.Validate(context.Cfg.Blocks[3], null); + context.Validate(context.Cfg.Blocks[4], null); + context.Validate(context.Cfg.Blocks[5], null); + context.ValidateExit(); + } + + #endregion + private static Context CreateContextCS(string methodBody, string localFunctionName = null, string additionalParameters = null) { additionalParameters = additionalParameters is null ? null : ", " + additionalParameters;