使用 .Net 编译器 Roslyn 为 C# 代码创建控制流图

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

我找不到使用 Roslyn 为 C# 代码构建控制流图的方法。

我知道 Roslyn 编译器中有一个名为 "Microsoft.CodeAnalysis.FlowAnalysis" 的名称空间,其中包含一些 classes 来创建控制流图,但我不知道如何使用它。

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

有一个名为 ControlFlowGraph.cs 的 class,但问题是我无法从这个 class 创建对象或子 class。 https://docs.microsoft.com/en-us/dotnet/api/microsoft.codeanalysis.flowanalysis.controlflowgraph?view=roslyn-dotnet

请问有谁知道如何使用这个命名空间来构造控制流图或者有例子可以使用。 谢谢

我已经设法从方法节点创建 CFG:

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();
        }
    }
}

下一步将分析 CFG ...

卡雷尔

根据 Karel 的回答和评论,这是创建无错误控制流图的方法:

var source = @"
class C
{
    int M(int x)
    {
      x = 0;
      int y = x * 3;
      return y;
    }
}";

        CSharpParseOptions options = CSharpParseOptions.Default
       .WithFeatures(new[] { new KeyValuePair<string, string>("flow-analysis", "")});

        var tree = CSharpSyntaxTree.ParseText(source, options);
        var compilation = CSharpCompilation.Create("c", new[] { tree });
        var model = compilation.GetSemanticModel(tree, ignoreAccessibility: true);

        var methodBodySyntax = tree.GetCompilationUnitRoot().DescendantNodes().OfType<BaseMethodDeclarationSyntax>().Last();

        var cfgFromSyntax = ControlFlowGraph.Create(methodBodySyntax, model);