コード例 #1
0
        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));
        }
コード例 #2
0
        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));
        }
コード例 #3
0
        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));
        }
コード例 #4
0
        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);
        }
コード例 #5
0
        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);
        }
コード例 #6
0
        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);
        }
コード例 #7
0
        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);
        }
コード例 #8
0
        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]));
        }
コード例 #9
0
        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]));
        }
コード例 #10
0
        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));
        }
コード例 #11
0
        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));
        }
コード例 #12
0
        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]));
        }
コード例 #13
0
        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));
        }