Example #1
0
        public void Serialize_Jump_Using()
        {
            var code = @"
class C
{
    void Foo()
    {
        using (x)
        {
            Bar();
        }
    }
}
";
            var dot  = CfgSerializer.Serialize("Foo", GetCfgForMethod(code, "Foo"));

            dot.Should().BeIgnoringLineEndings(@"digraph ""Foo"" {
0 [shape=record label=""{JUMP:UsingStatement|x}""]
0 -> 1
1 [shape=record label=""{USING:UsingStatement|Bar|Bar()}""]
1 -> 2
2 [shape=record label=""{EXIT}""]
}
");
        }
Example #2
0
        public void Serialize_BinaryBranch_Simple()
        {
            var code = @"
class C
{
    void Foo()
    {
        if (true)
        {
            Bar();
        }
    }
    void Bar() { }
}
";
            var dot  = CfgSerializer.Serialize("Foo", GetCfgForMethod(code, "Foo"));

            dot.Should().BeIgnoringLineEndings(@"digraph ""Foo"" {
0 [shape=record label=""{BINARY:TrueLiteralExpression|true}""]
0 -> 1 [label=""True""]
0 -> 2 [label=""False""]
1 [shape=record label=""{SIMPLE|Bar|Bar()}""]
1 -> 2
2 [shape=record label=""{EXIT}""]
}
");
        }
Example #3
0
        public void Serialize_Lock_Simple()
        {
            var code = @"
class C
{
    void Foo()
    {
        lock (x)
        {
            Bar();
        }
    }
}
";
            var dot  = CfgSerializer.Serialize("Foo", GetCfgForMethod(code, "Foo"));

            dot.Should().BeIgnoringLineEndings(@"digraph ""Foo"" {
0 [shape=record label=""{LOCK:LockStatement|x}""]
0 -> 1
1 [shape=record label=""{SIMPLE|Bar|Bar()}""]
1 -> 2
2 [shape=record label=""{EXIT}""]
}
");
        }
Example #4
0
        public void Serialize_For_Binary_Simple()
        {
            var code = @"
class C
{
    void Foo()
    {
        for (var i = 0; i < 10; i++)
        {
            Bar();
        }
    }
}
";
            var dot  = CfgSerializer.Serialize("Foo", GetCfgForMethod(code, "Foo"));

            dot.Should().BeIgnoringLineEndings(@"digraph ""Foo"" {
0 [shape=record label=""{FOR:ForStatement|0|i = 0}""]
0 -> 1
1 [shape=record label=""{BINARY:ForStatement|i|10|i \< 10}""]
1 -> 2 [label=""True""]
1 -> 3 [label=""False""]
2 [shape=record label=""{SIMPLE|Bar|Bar()}""]
2 -> 4
4 [shape=record label=""{SIMPLE|i|i++}""]
4 -> 1
3 [shape=record label=""{EXIT}""]
}
");
        }
Example #5
0
        public void Serialize_Foreach_Binary_VarDeclaration()
        {
            var code = @"
namespace Namespace
    {
        public class Test
        {
            public void ForEach((string key, string value)[] values)
            {
                foreach (var (key, value) in values)
                {
                    string i = key;
                    string j = value;
                }
            }
        }
    };";

            var dot = CfgSerializer.Serialize("ForEach", GetCfgForMethod(code, "ForEach"));

            dot.Should().BeIgnoringLineEndings(@"digraph ""ForEach"" {
0 [shape=record label=""{FOREACH:ForEachVariableStatement|values}""]
0 -> 1
1 [shape=record label=""{BINARY:ForEachVariableStatement}""]
1 -> 2 [label=""True""]
1 -> 3 [label=""False""]
2 [shape=record label=""{SIMPLE|key|i = key|value|j = value}""]
2 -> 1
3 [shape=record label=""{EXIT}""]
}
");
        }
Example #6
0
        public void Serialize_Foreach_Binary_Simple()
        {
            var code = @"
class C
{
    void Foo()
    {
        foreach (var i in items)
        {
            Bar();
        }
    }
}
";
            var dot  = CfgSerializer.Serialize("Foo", GetCfgForMethod(code, "Foo"));

            dot.Should().BeIgnoringLineEndings(@"digraph ""Foo"" {
0 [shape=record label=""{FOREACH:ForEachStatement|items}""]
0 -> 1
1 [shape=record label=""{BINARY:ForEachStatement}""]
1 -> 2 [label=""True""]
1 -> 3 [label=""False""]
2 [shape=record label=""{SIMPLE|Bar|Bar()}""]
2 -> 1
3 [shape=record label=""{EXIT}""]
}
");
        }
        public void Serialize_Branch_Jump()
        {
            var code = @"
class C
{
    void Foo(int a)
    {
        switch (a)
        {
            case 1:
                c1();
                break;
            case 2:
                c2();
                break;
        }
    }
}
";
            var dot  = CfgSerializer.Serialize("Foo", GetCfgForMethod(code, "Foo"));

            dot.Should().BeIgnoringLineEndings(@"digraph ""Foo"" {
0 [shape=record label=""{BRANCH:SwitchStatement|a}""]
0 -> 1
0 -> 2
0 -> 3
2 [shape=record label=""{JUMP:BreakStatement|c2|c2()}""]
2 -> 3
1 [shape=record label=""{JUMP:BreakStatement|c1|c1()}""]
1 -> 3
3 [shape=record label=""{EXIT}""]
}
");
        }
Example #8
0
        public void Serialize_Empty_Method()
        {
            var code = @"
class C
{
    void Foo()
    {
    }
}
";
            var dot  = CfgSerializer.Serialize("Foo", GetCfgForMethod(code, "Foo"));

            dot.Should().BeIgnoringLineEndings(@"digraph ""Foo"" {
0 [shape=record label=""{EXIT}""]
}
");
        }
Example #9
0
        public void Serialize_IndexInRange()
        {
            var code = @"
internal class Test
{
    public void Range()
    {
        Range range = ^2..^0;
    }
}
";
            var dot  = CfgSerializer.Serialize("Range", GetCfgForMethod(code, "Range"));

            dot.Should().BeIgnoringLineEndings(@"digraph ""Range"" {
0 [shape=record label=""{SIMPLE|^2..^0|range = ^2..^0}""]
0 -> 1
1 [shape=record label=""{EXIT}""]
}
");
        }
Example #10
0
        public void Serialize_Index()
        {
            var code = @"
internal class Test
{
    public void Index()
    {
        Index index = ^1;
    }
}
";
            var dot  = CfgSerializer.Serialize("Index", GetCfgForMethod(code, "Index"));

            dot.Should().BeIgnoringLineEndings(@"digraph ""Index"" {
0 [shape=record label=""{SIMPLE|^1|index = ^1}""]
0 -> 1
1 [shape=record label=""{EXIT}""]
}
");
        }
Example #11
0
        public void Serialize_RangeInIndexer()
        {
            var code = @"
internal class Test
{
    public void Range()
    {
        var ints = new[] { 1, 2 };
        var lastTwo = ints[^2..^1];
    }
}
";
            var dot  = CfgSerializer.Serialize("Range", GetCfgForMethod(code, "Range"));

            dot.Should().BeIgnoringLineEndings(@"digraph ""Range"" {
0 [shape=record label=""{SIMPLE|new[] \{ 1, 2 \}|1|2|\{ 1, 2 \}|ints = new[] \{ 1, 2 \}|ints|^2..^1|ints[^2..^1]|lastTwo = ints[^2..^1]}""]
0 -> 1
1 [shape=record label=""{EXIT}""]
}
");
        }
Example #12
0
        public void Serialize_Lambda()
        {
            var code = @"
class C
{
    void Foo()
    {
        Bar(x =>
        {
            return 1 + 1;
        });
    }
}
";
            var dot  = CfgSerializer.Serialize("Foo", GetCfgForMethod(code, "Foo"));

            dot.Should().BeIgnoringLineEndings(@"digraph ""Foo"" {
0 [shape=record label=""{SIMPLE|Bar|x =\>\n        \{\n            return 1 + 1;\n        \}|Bar(x =\>\n        \{\n            return 1 + 1;\n        \})}""]
0 -> 1
1 [shape=record label=""{EXIT}""]
}
");
        }
Example #13
0
        private void WriteUCFG <TDeclarationSyntax>(SyntaxNodeAnalysisContext context, Func <TDeclarationSyntax, CSharpSyntaxNode> getBody)
            where TDeclarationSyntax : SyntaxNode
        {
            var declaration = (TDeclarationSyntax)context.Node;

            var symbol = context.SemanticModel.GetDeclaredSymbol(declaration);

            var methodSymbol = (symbol is IPropertySymbol propertySymbol)
                ? propertySymbol.GetMethod // We are in PropertyDeclarationSyntax
                : symbol as IMethodSymbol; // all other are methods

            if (methodSymbol == null ||
                methodSymbol.IsAbstract ||
                methodSymbol.IsExtern ||
                !CSharpControlFlowGraph.TryGet(getBody(declaration), context.SemanticModel, out var cfg))
            {
                return;
            }

            var ucfg = new UniversalControlFlowGraphBuilder()
                       .Build(context.SemanticModel, declaration, methodSymbol, cfg);

            if (IsValid(ucfg))
            {
                var fileName = $"{projectBuildId}_{Interlocked.Increment(ref protobufFileIndex)}";

                WriteProtobuf(ucfg, Path.Combine(protobufDirectory, $"ucfg_{fileName}.pb"));

                if (ShouldGenerateDot)
                {
                    WriteDot(Path.Combine(protobufDirectory, $"ucfg_{fileName}.dot"), writer => UcfgSerializer.Serialize(ucfg, writer));
                    WriteDot(Path.Combine(protobufDirectory, $"cfg_{fileName}.dot"), writer => CfgSerializer.Serialize(ucfg.MethodId, cfg, writer));
                }
            }
        }
        private void WriteUcfg <TDeclarationSyntax>(SyntaxNodeAnalysisContext context, Func <TDeclarationSyntax, CSharpSyntaxNode> getBody)
            where TDeclarationSyntax : SyntaxNode
        {
            var declaration = (TDeclarationSyntax)context.Node;

            var symbol = context.SemanticModel.GetDeclaredSymbol(declaration);

            var methodSymbol = (symbol is IPropertySymbol propertySymbol)
                ? propertySymbol.GetMethod // We are in PropertyDeclarationSyntax
                : symbol as IMethodSymbol; // all other are methods

            if (methodSymbol == null ||
                methodSymbol.IsAbstract ||
                methodSymbol.IsExtern ||
                !CSharpControlFlowGraph.TryGet(getBody(declaration), context.SemanticModel, out var cfg))
            {
                return;
            }

            try
            {
                var ucfg = new UcfgFactory(context.SemanticModel)
                           .Create(declaration, methodSymbol, cfg);

                if (!IsValid(ucfg))
                {
                    return;
                }

                var fileName = $"{this.projectBuildId}_{Interlocked.Increment(ref this.protobufFileIndex)}";

                WriteProtobuf(ucfg, Path.Combine(this.protobufDirectory, $"ucfg_{fileName}.pb"));

                if (ShouldGenerateDot)
                {
                    WriteDot(Path.Combine(this.protobufDirectory, $"ucfg_{fileName}.dot"), writer => UcfgSerializer.Serialize(ucfg, writer));
                    WriteDot(Path.Combine(this.protobufDirectory, $"cfg_{fileName}.dot"), writer => CfgSerializer.Serialize(ucfg.MethodId, cfg, writer));
                }
            }
            catch (UcfgException) when(!DebugHelper.IsInternalDebuggingContext())
            {
                // Ignore the exception in production
            }
        }
Example #15
0
 public static string GetCfgGraph(string code, string methodName)
 {
     return(CfgSerializer.Serialize(methodName, GetCfgForMethod(code, methodName)));
 }