Search code examples
c#.netroslynroslyn-code-analysis

How to create a compilation unit from an AST


I am writing a solution which requires an AST to be generated and then this AST should be parsed in order to generate a valid compilation unit with semantics available.

  1. The AST is generated by means of SyntaxFactory class.
  2. Then I will need to get a Compilation somehow.
  3. Then I will get a reference to SemanticModel from the compilation unit.

Creating the AST

The code I run for generating the AST is something like:

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

Missing parts

The first part is ok as you can see. I can get my AST. But now I need to convert it into code? How to invoke the compiler on the AST?:

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

Note that the part relative to getting the SemanticModel is covered as I simly need to use the Compilation object and call GetSemanticModel on that by passing the CSharpSyntaxTree.

If you are wondering why this, it is because of a testing tool I am writing. Regardless of the use, this scenario should be possible. How?


Solution

  • To create Compilation in Roslyn, you need a valid syntax tree, to get a valid syntax tree you can just parse text like:

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

    Or you can use SyntaxFactory (or SyntaxGenerator) like you wrote. (just add usings and namespace unless you writing a CSharpScript, its required, You can also check RoslynQuoter to get a valid SyntaxTree)

    When you have a valid SyntaxTree you can write this to get a Compilation and 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);