Search code examples
c#roslynroslyn-code-analysiscontrol-flow-graph

Create control flow graph for c# code using the .Net compiler Roslyn


I can't find a way to construct a control flow graph for c# code using Roslyn.

I know there is a namespace in the Roslyn compiler called "Microsoft.CodeAnalysis.FlowAnalysis" that contains some classes to create a control flow graph but I don't know how to use it.

https://learn.microsoft.com/en-us/dotnet/api/microsoft.codeanalysis.flowanalysis?view=roslyn-dotnet

there is a class called ControlFlowGraph.cs but the problem i can't create an object or a subclass from this class. https://learn.microsoft.com/en-us/dotnet/api/microsoft.codeanalysis.flowanalysis.controlflowgraph?view=roslyn-dotnet

please if anyone knows how to use this namespace to construct a control flow graph or if there is an example to use. thank you


Solution

  • I have manage to create the CFG from a method node:

    CSharpParseOptions options = CSharpParseOptions.Default
        .WithFeatures(new[] { new KeyValuePair<string, string>("flow-analysis", "")     
    });
    
    MSBuildWorkspace workspace = MSBuildWorkspace.Create();
    Solution solution = workspace.OpenSolutionAsync(solutionUrl).Result; // path to your SLN file
    
    ProjectDependencyGraph projectGraph = solution.GetProjectDependencyGraph();
    Dictionary<string, Stream> assemblies = new Dictionary<string, Stream>();
    
    var projects = projectGraph.GetTopologicallySortedProjects().ToDictionary(
        p => p,
        p => solution.GetProject(p).Name);
    
    var bllProjectId = projects.First(p => p.Value == "<your project name>").Key; // choose project for analysis
    var projectId = bllProjectId;
    solution = solution.WithProjectParseOptions(projectId, options);
    
    Compilation compilation = solution.GetProject(projectId).GetCompilationAsync().Result;
    if (compilation != null && !string.IsNullOrEmpty(compilation.AssemblyName))
    {
        var syntaxTree = compilation.SyntaxTrees.First();
    
        // get syntax nodes for methods
        var methodNodes = from methodDeclaration in syntaxTree.GetRoot().DescendantNodes()
                .Where(x => x is MethodDeclarationSyntax)
            select methodDeclaration;
    
        foreach (MethodDeclarationSyntax node in methodNodes)
        {
            var model = compilation.GetSemanticModel(node.SyntaxTree);
            node.Identifier.ToString().Dump();
            if (node.SyntaxTree.Options.Features.Any())
            {
                var graph = ControlFlowGraph.Create(node, model); // CFG is here
            }
            else
            {
                // "No features".Dump();
            }
        }
    }
    

    The next step will be anaylysis of the CFG ...

    Karel