如何从AST创建编译单元

时间:2017-05-17 11:41:11

标签: c# .net roslyn roslyn-code-analysis

我正在编写一个需要生成AST的解决方案,然后应该解析这个AST,以便生成一个有语义的有效编译单元。

  1. AST是通过SyntaxFactory类生成的。
  2. 然后我需要以某种方式获得Compilation
  3. 然后我将从编译单元获得对SemanticModel的引用。
  4. 创建AST

    我为生成AST而运行的代码类似于:

    var classNode = SyntaxFactory.ClassDeclaration("MyCLass");
    classNode = classNode.AddMembers(
      SyntaxFactory.MethodDeclaration(SyntaxFactory.ParseTypeName("string"), "DoIt")
        .WithBody(...));
    ...
    

    缺少部分

    第一部分是正常的,你可以看到。我可以得到我的AST。但现在我需要将其转换为代码? 如何在AST上调用编译器?

                  Compiler                Compilation.GetSemanticModel(AST)
                  |                       |
         +-----+  v  +-----------------+  v  +---------------+
    +----> AST +-----> CompilationUnit +-----> SemanticModel |
      ^  +-----+     +-----------------+     +---------------+
      |              ^                 ^
      |              |-----------------|
      Factories              ???
    

    请注意,相对于获取SemanticModel的部分,我需要使用Compilation对象并通过传递GetSemanticModel来调用CSharpSyntaxTree。 / p>

    如果你想知道为什么会这样,那是因为我正在写一个测试工具。无论使用什么,这种情况应该是可能的。怎么样?

1 个答案:

答案 0 :(得分:0)

要在Roslyn中创建Compilation,您需要一个有效的语法树,以获得一个有效的语法树,您只需解析文本:

var tree = CSharpSyntaxTree.ParseText(@"using System;
              namespace HelloWorld
              {
                public class MyType{public void MyMethod(){} public void MySecondMethod(){}}
              }"));

或者你可以像你写的那样使用SyntaxFactory(或SyntaxGenerator)。 (只需添加usingsnamespace除非您撰写CSharpScript,但必须添加SyntaxTree,您还可以查看RoslynQuoter以获得有效的SyntaxTree

如果您拥有有效的Compilation,则可以将其写为SemanticModel var options = new CSharpCompilationOptions(kind); var root = (CompilationUnitSyntax)tree.GetRoot(); var compilation = CSharpCompilation.Create("HelloWorld", options: options). AddReferences(MetadataReference.CreateFromFile(typeof(object).Assembly.Location)). AddSyntaxTrees(tree); var model = compilation.GetSemanticModel(tree);

public Boolean isFooHere(final Foo foo) {

   Criteria criteria = createCriteria();

   criteria.add(Restrictions.eq("foo.id", foo.getId()));

   if(criteria.uniqueResult() != null)
      return true;

   return false;
}