public void BodyWithSingleInvocation() { var invokerSource = @"var a = 10; Method(a);"; var invokerCfg = CreateControlFlowGraph(invokerSource); var methodSource = @" class Test { private void Method(int x) { } }"; var semanticModel = DocumentFactory.Create().CreateSemanticModel(methodSource); var methodCode = semanticModel.SyntaxTree.GetRoot().DescendantNodes() .OfType <MethodDeclarationSyntax>() .Select(declaration => CodeFactory.CreateMethod(declaration, semanticModel)) .Single(); var methodCfg = ControlFlowGraphFactory.Create(methodCode, "Method", true); var procedureCfgs = new Dictionary <string, ControlFlowGraph> { { "Method", methodCfg } }; var callGraph = CallGraphFactory.Create(invokerCfg, procedureCfgs); Assert.AreEqual(4, callGraph.Edges.Count); Assert.IsTrue(callGraph.Edges.Any(edge => edge.From is FlowInvocation && _IsExpectedTransfer(edge.To, "<root>", "Method", true, false))); Assert.IsTrue(callGraph.Edges.Any(edge => _IsExpectedTransfer(edge.From, "<root>", "Method", true, false) && _IsExpectedBoundary(edge.To, "Method", FlowKind.Start))); Assert.IsTrue(callGraph.Edges.Any(edge => _IsExpectedBoundary(edge.From, "Method", FlowKind.End) && _IsExpectedTransfer(edge.To, "Method", "<root>", false, true))); Assert.IsTrue(callGraph.Edges.Any(edge => _IsExpectedTransfer(edge.From, "Method", "<root>", false, true) && edge.To is FlowInvocation)); Debug.WriteLine(new[] { invokerCfg }.Concat(procedureCfgs.Values).ToDot(callGraph)); }
public ControlFlowGraph CreateControlFlowGraph(string methodDeclaration) { var code = $"class Test {{ {methodDeclaration} }}"; var semanticModel = DocumentFactory.Create().CreateSemanticModel(code); var method = semanticModel.SyntaxTree.GetRoot().DescendantNodes() .OfType <MethodDeclarationSyntax>() .Single(); return(ControlFlowGraphFactory.Create(CodeFactory.CreateMethod(method, semanticModel), true)); }
private Code CreateCode(string methodDeclaration, string methodName) { var code = $"class Test {{ {methodDeclaration} }}"; var semanticModel = DocumentFactory.Create().CreateSemanticModel(code); var method = semanticModel.SyntaxTree.GetRoot().DescendantNodes() .OfType <MethodDeclarationSyntax>() .Where(declaration => declaration.Identifier.Text.Equals(methodName)) .Single(); return(CodeFactory.CreateMethod(method, semanticModel)); }
private static (string Name, ControlFlowGraph Cfg) _GetCodeOfMethod(MethodDeclarationSyntax method, SemanticModel semanticModel) { var methodName = method.Identifier.Text; try { var code = ThreeAddressCodeFactory.Create(CodeFactory.CreateMethod(method, semanticModel)); var optimized = OptimizationRunner.Optimize(code); Debug.WriteLine($"got optimized code for {methodName}"); return(methodName, ControlFlowGraphFactory.Create(optimized.Code, methodName, true)); } catch (UnsupportedSyntaxException e) { Debug.WriteLine($"method '{methodName}' cannot be utilized in interprocedural anaylsis: {e.Message}"); } return(null, null); }
public void PreventsGenerationOfCodeForMethodsAccessingPropertyArrays() { var source = @" class Test { private int[] Array { get; } public void Run() { var current = Array[0]; } }"; var semanticModel = DocumentFactory.Create().CreateSemanticModel(source); var method = semanticModel.SyntaxTree.GetRoot().DescendantNodes() .OfType <MethodDeclarationSyntax>() .Single(); CodeFactory.CreateMethod(method, semanticModel); }
public void DoesNotSupportWriteAccessToProperties() { var code = @" class Test { private int Value { get; set; } public void Run() { Value = 1; } }"; var semanticModel = DocumentFactory.Create().CreateSemanticModel(code); var method = semanticModel.SyntaxTree.GetRoot().DescendantNodes() .OfType <MethodDeclarationSyntax>() .Single(); CodeFactory.CreateMethod(method, semanticModel); }
public void DoesNotSupportInvocationsOfLambdaExpressions() { var code = @" using System; class Test { private readonly Func<int> Value = () => 1; public void Run() { var value = Value(); } }"; var semanticModel = DocumentFactory.Create().CreateSemanticModel(code); var method = semanticModel.SyntaxTree.GetRoot().DescendantNodes() .OfType <MethodDeclarationSyntax>() .Single(); CodeFactory.CreateMethod(method, semanticModel); }
public void LoopIndexLostThroughRecursion() { var invokerSource = @"Method(i);"; var invokerCfg = CreateControlFlowGraph(invokerSource); var methodSource = @" class Test { private int Method(int x) { if(x > 0) { return Method(x - 1); } return x; } }"; var semanticModel = DocumentFactory.Create().CreateSemanticModel(methodSource); var methodCode = semanticModel.SyntaxTree.GetRoot().DescendantNodes() .OfType <MethodDeclarationSyntax>() .Select(declaration => CodeFactory.CreateMethod(declaration, semanticModel)) .Single(); var methodCfg = ControlFlowGraphFactory.Create(methodCode, "Method", true); var procedureCfgs = new Dictionary <string, ControlFlowGraph> { { "Method", methodCfg } }; var callGraph = CallGraphFactory.Create(invokerCfg, procedureCfgs); var analysis = LoopDependenceAnalysis.Analyze(invokerCfg, "i", callGraph, procedureCfgs.Values); // Outer body Assert.AreEqual(4, analysis.Entry[invokerCfg.Start].Count); Assert.AreEqual("{i != 0, i@, i|, i+}", GetString(analysis.Entry[invokerCfg.Start])); Assert.AreEqual(10, analysis.Exit[invokerCfg.End].Count); Assert.AreEqual("{$arg_Method_0 != 0, $arg_Method_0@, $arg_Method_0|, $arg_Method_0+, $result_Method@, $result_Method@, i != 0, i@, i|, i+}", GetString(analysis.Exit[invokerCfg.End])); // invoked method Assert.AreEqual(2, analysis.Entry[methodCfg.Start].Count); Assert.AreEqual("{$arg_Method_0@, $arg_Method_0@}", GetString(analysis.Entry[methodCfg.Start])); Debug.WriteLine(GetString(analysis.Exit[methodCfg.End])); Assert.AreEqual(5, analysis.Exit[methodCfg.End].Count); Assert.AreEqual("{$arg_Method_0@, $arg_Method_0@, $result_Method@, $result_Method@, x@}", GetString(analysis.Exit[methodCfg.End])); }
public void LoopIndexAndRegularPassingWithExchangeRemovesInformation() { var invokerSource = @"var a = 0; var b = Recursive(i, a);"; var invokerCfg = CreateControlFlowGraph(invokerSource); var methodSource = @" class Test { private void Recursive(int x, int y) { if(x > y) { Recursive(y, x); } return x; } }"; var semanticModel = DocumentFactory.Create().CreateSemanticModel(methodSource); var methodCode = semanticModel.SyntaxTree.GetRoot().DescendantNodes() .OfType <MethodDeclarationSyntax>() .Select(declaration => CodeFactory.CreateMethod(declaration, semanticModel)) .Single(); var methodCfg = ControlFlowGraphFactory.Create(methodCode, "Recursive", true); var procedureCfgs = new Dictionary <string, ControlFlowGraph> { { "Recursive", methodCfg } }; var callGraph = CallGraphFactory.Create(invokerCfg, procedureCfgs); var analysis = LoopDependenceAnalysis.Analyze(invokerCfg, "i", callGraph, procedureCfgs.Values); // Outer body Assert.AreEqual(4, analysis.Entry[invokerCfg.Start].Count); Assert.AreEqual("{i != 0, i@, i|, i+}", GetString(analysis.Entry[invokerCfg.Start])); Assert.AreEqual(16, analysis.Exit[invokerCfg.End].Count); Assert.AreEqual("{$arg_Recursive_0 != 0, $arg_Recursive_0@, $arg_Recursive_0|, $arg_Recursive_0+, $arg_Recursive_1 = 0, $arg_Recursive_1/, $arg_Recursive_1@, $result_Recursive@, a = 0, a/, a@, b@, i != 0, i@, i|, i+}", GetString(analysis.Exit[invokerCfg.End])); // invoked method Assert.AreEqual(4, analysis.Entry[methodCfg.Start].Count); Assert.AreEqual("{$arg_Recursive_0@, $arg_Recursive_0@, $arg_Recursive_1@, $arg_Recursive_1@}", GetString(analysis.Entry[methodCfg.Start])); Assert.AreEqual(7, analysis.Exit[methodCfg.End].Count); Assert.AreEqual("{$arg_Recursive_0@, $arg_Recursive_0@, $arg_Recursive_1@, $arg_Recursive_1@, $result_Recursive@, x@, y@}", GetString(analysis.Exit[methodCfg.End])); }
public void SupportsUsageOfSafeApis() { var source = @" using System; class Test { public void Run() { var current = Math.Pow(2, 4); } }"; var semanticModel = DocumentFactory.Create().CreateSemanticModel(source); var method = semanticModel.SyntaxTree.GetRoot().DescendantNodes() .OfType <MethodDeclarationSyntax>() .Single(); var code = CodeFactory.CreateMethod(method, semanticModel); var expected = @" DECL current current = $SafeApi(2, 4) LABEL #0"; Assert.AreEqual(expected.Trim(), CodeStringifier.Generate(code)); }
public void SupportsReadAccessFromProperties() { var source = @" class Test { private int Value { get; } public void Run() { var current = Value; } }"; var semanticModel = DocumentFactory.Create().CreateSemanticModel(source); var method = semanticModel.SyntaxTree.GetRoot().DescendantNodes() .OfType <MethodDeclarationSyntax>() .Single(); var code = CodeFactory.CreateMethod(method, semanticModel); var expected = @" DECL current current = Value LABEL #0"; Assert.AreEqual(expected.Trim(), CodeStringifier.Generate(code)); }
public void LoopIndexPassingToSingleArgumentWithReturnValue() { var invokerSource = @"var a = Method(i);"; var invokerCfg = CreateControlFlowGraph(invokerSource); var methodSource = @" class Test { private void Method(int x) { return x; } }"; var semanticModel = DocumentFactory.Create().CreateSemanticModel(methodSource); var methodCode = semanticModel.SyntaxTree.GetRoot().DescendantNodes() .OfType <MethodDeclarationSyntax>() .Select(declaration => CodeFactory.CreateMethod(declaration, semanticModel)) .Single(); var methodCfg = ControlFlowGraphFactory.Create(methodCode, "Method", true); var procedureCfgs = new Dictionary <string, ControlFlowGraph> { { "Method", methodCfg } }; var callGraph = CallGraphFactory.Create(invokerCfg, procedureCfgs); var analysis = LoopDependenceAnalysis.Analyze(invokerCfg, "i", callGraph, procedureCfgs.Values); // Outer body Assert.AreEqual(4, analysis.Entry[invokerCfg.Start].Count); Assert.AreEqual("{i != 0, i@, i|, i+}", GetString(analysis.Entry[invokerCfg.Start])); Assert.AreEqual(16, analysis.Exit[invokerCfg.End].Count); Assert.AreEqual("{$arg_Method_0 != 0, $arg_Method_0@, $arg_Method_0|, $arg_Method_0+, $result_Method != 0, $result_Method@, $result_Method|, $result_Method+, a != 0, a@, a|, a+, i != 0, i@, i|, i+}", GetString(analysis.Exit[invokerCfg.End])); // invoked method Assert.AreEqual(4, analysis.Entry[methodCfg.Start].Count); Assert.AreEqual("{$arg_Method_0 != 0, $arg_Method_0@, $arg_Method_0|, $arg_Method_0+}", GetString(analysis.Entry[methodCfg.Start])); Assert.AreEqual(12, analysis.Exit[methodCfg.End].Count); Assert.AreEqual("{$arg_Method_0 != 0, $arg_Method_0@, $arg_Method_0|, $arg_Method_0+, $result_Method != 0, $result_Method@, $result_Method|, $result_Method+, x != 0, x@, x|, x+}", GetString(analysis.Exit[methodCfg.End])); }
public void NestedRecursion() { var invokerSource = @"var a = 10; Recursive1(a);"; var invokerCfg = CreateControlFlowGraph(invokerSource); var methodSource = @" class Test { private void Recursive1(int x) { Recursive2(x); } private void Recursive2(int x) { if(x > 0) { Recursive1(x - 1); } } }"; var semanticModel = DocumentFactory.Create().CreateSemanticModel(methodSource); var recursive1Code = semanticModel.SyntaxTree.GetRoot().DescendantNodes() .OfType <MethodDeclarationSyntax>() .Where(declaration => declaration.Identifier.Text.Equals("Recursive1")) .Select(declaration => CodeFactory.CreateMethod(declaration, semanticModel)) .Single(); var recursive2Code = semanticModel.SyntaxTree.GetRoot().DescendantNodes() .OfType <MethodDeclarationSyntax>() .Where(declaration => declaration.Identifier.Text.Equals("Recursive2")) .Select(declaration => CodeFactory.CreateMethod(declaration, semanticModel)) .Single(); var recursive1Cfg = ControlFlowGraphFactory.Create(recursive1Code, "Recursive1", true); var recursive2Cfg = ControlFlowGraphFactory.Create(recursive2Code, "Recursive2", true); var procedureCfgs = new Dictionary <string, ControlFlowGraph> { { "Recursive1", recursive1Cfg }, { "Recursive2", recursive2Cfg } }; var callGraph = CallGraphFactory.Create(invokerCfg, procedureCfgs); Assert.AreEqual(12, callGraph.Edges.Count); // Initial call Assert.IsTrue(callGraph.Edges.Any(edge => edge.From is FlowInvocation && _IsExpectedTransfer(edge.To, "<root>", "Recursive1", true, false))); Assert.IsTrue(callGraph.Edges.Any(edge => _IsExpectedTransfer(edge.From, "<root>", "Recursive1", true, false) && _IsExpectedBoundary(edge.To, "Recursive1", FlowKind.Start))); Assert.IsTrue(callGraph.Edges.Any(edge => _IsExpectedBoundary(edge.From, "Recursive1", FlowKind.End) && _IsExpectedTransfer(edge.To, "Recursive1", "<root>", false, true))); Assert.IsTrue(callGraph.Edges.Any(edge => _IsExpectedTransfer(edge.From, "Recursive1", "<root>", false, true) && edge.To is FlowInvocation)); // Recursive 1 call Assert.IsTrue(callGraph.Edges.Any(edge => edge.From is FlowInvocation && _IsExpectedTransfer(edge.To, "Recursive1", "Recursive2", true, false))); Assert.IsTrue(callGraph.Edges.Any(edge => _IsExpectedTransfer(edge.From, "Recursive1", "Recursive2", true, false) && _IsExpectedBoundary(edge.To, "Recursive2", FlowKind.Start))); Assert.IsTrue(callGraph.Edges.Any(edge => _IsExpectedBoundary(edge.From, "Recursive2", FlowKind.End) && _IsExpectedTransfer(edge.To, "Recursive2", "Recursive1", false, true))); Assert.IsTrue(callGraph.Edges.Any(edge => _IsExpectedTransfer(edge.From, "Recursive2", "Recursive1", false, true) && edge.To is FlowInvocation)); // Recursive 2 call Assert.IsTrue(callGraph.Edges.Any(edge => edge.From is FlowInvocation && _IsExpectedTransfer(edge.To, "Recursive2", "Recursive1", true, false))); Assert.IsTrue(callGraph.Edges.Any(edge => _IsExpectedTransfer(edge.From, "Recursive2", "Recursive1", true, false) && _IsExpectedBoundary(edge.To, "Recursive1", FlowKind.Start))); Assert.IsTrue(callGraph.Edges.Any(edge => _IsExpectedBoundary(edge.From, "Recursive1", FlowKind.End) && _IsExpectedTransfer(edge.To, "Recursive1", "Recursive2", false, true))); Assert.IsTrue(callGraph.Edges.Any(edge => _IsExpectedTransfer(edge.From, "Recursive1", "Recursive2", false, true) && edge.To is FlowInvocation)); Debug.WriteLine(new[] { invokerCfg }.Concat(procedureCfgs.Values).ToDot(callGraph)); }