Roslyn:如何将多个项目的编译合并为 1 个单独的编译?

Posted

技术标签:

【中文标题】Roslyn:如何将多个项目的编译合并为 1 个单独的编译?【英文标题】:Roslyn: How to combine multiple project's compilation into 1 single compilation? 【发布时间】:2016-11-21 22:11:28 【问题描述】:

是否可以将每个单独项目的所有编译合并为 1 个编译?我目前正在研究静态代码分析器,因此,例如,当一个方法调用来自同一解决方案中另一个项目的另一个方法时,当我尝试使用 compilation.GetSemanticModel(SyntaxTree) 获取语义模型时,我会出错,因为将另一个项目的一个类的SyntaxTree 传递给当前项目的Compilation 会破坏我的代码。

编辑: 我想到了获取每个项目的引用和语法树并将它们组合起来,然后基于它创建一个编译。

        List<MetadataReference> refs = new List<MetadataReference>();
        List<SyntaxTree> syntaxtrees = new List<SyntaxTree>();
        foreach (var project in projectToAnalyze)
        
            Compilation compilation = project.GetCompilationAsync().Result;

            var references = compilation.References;
            refs.AddRange(references);
            var trees = compilation.SyntaxTrees;
            syntaxtrees.AddRange(trees);
            //analysis(project, config, compilation);
        


        var mycompilation = CSharpCompilation.Create("test").AddReferences(refs).AddSyntaxTrees(syntaxtrees);

但是,虽然我这样做没有出错,但某些操作现在似乎不起作用。例如,当我现在使用SymbolFinder.FindImplementationsAsync 时,它不再返回我的实现。

Edit2:例如 MyAnalyzer:

class MyAnalyzer 

    private Compilation compilation;
    private SemanticModel model;
    private SyntaxTree tree;

    public MyAnalyzer(SyntaxTree tree, Compilation compilation) 
        this.compilation = compilation;
        this.tree = tree;
        this.model = compilation.GetSemanticModel(tree);

    //Various override Visit functions for analysis
    public override void VisitInvocationExpression(node) 
         //
         //lets say i just pass the syntaxtree belonging to ClassB
         //into a new instance of MyAnalyzer
         MyAnalyzer newAnalysis = new MyAnalyzer(classB's syntaxtree, this.compilation)
    

要分析的代码:

class A 

ClassB B = new ClassB();
B.method();

如果假设ClassB 来自同一解决方案中的另一个项目,那么我通过传入树并从我的Main.cs 编译来运行我的分析器,那么当我尝试在VisitInvocationExpression 中创建一个新的分析实例时由于ClassBSyntaxTree 来自另一个项目,我将当前实例编译this.compilation 传递到新实例中,因此compilation.GetSemanticModel(tree) 将无法在此处工作。因此,我产生了将编译合并为一个编译的想法。

【问题讨论】:

生成的编译是否有Diagnostics 所有这些集合都是不可变的。 这是个坏主意;不同的项目可能有冲突的名称或引用或设置。您应该修复您的代码以使用每个语法树的正确编译。 确实,合并为一个 Compilation 不是可行的方法。有几种方法可以在编译之间移动,具体取决于您要执行的操作。我怀疑你的心智模型不在这里;尝试在上下文中重申您最初的问题,我们可能会提供更好的帮助。 看看Edit2,谢谢回复!顺便说一句,roslyn 中是否有任何 API 允许您从 SyntaxTree 获取编译? 【参考方案1】:

我对我的问题的解决方案是,如果我传递给类的编译不包含 @987654322,我没有将编译组合成 1 个单一编译,而是围绕语句 compilation.GetSemanticModel(tree) 做了一个 try-catch 块@,catch 块将循环遍历 IEnumerable&lt;Project&gt; 的全局变量,从而我存储 Solution 的项目我正在分析并循环遍历每个项目的编译以查找包含树的编译。

【讨论】:

以上是关于Roslyn:如何将多个项目的编译合并为 1 个单独的编译?的主要内容,如果未能解决你的问题,请参考以下文章

初步了解到C#编译器Roslyn是一个开源的,但是却不知道如何安装Roslyn,希望懂的大神说明一下

使用 Roslyn 编译时自动解析依赖关系

Roslyn

Roslyn - 如何用多个节点替换多个节点?

使用roslyn编译website项目

[006] 了解 Roslyn 编译器