Search code examples
c#code-generationroslynregion

How can I wrap a SyntaxTree or UnitCompilationRoot in a region or comment using Roslyn?


I'm using CSharpSyntaxTree.ParseText to create a syntax tree from an arbitrary block of code; I'd like to be able to wrap or encapsulate either that SyntaxTree or its UnitCompilationRoot in a region. I'm aware of the Quoter website that allows you to see how any arbitrary code could be written using the Roslyn API, but the way it breaks down the code into its raw components doesn't help with the use-case of adding a region to a SyntaxTree or UnitCompilationRoot.

Example using arbitrary code

// Create syntax tree from template
var str = @"public class Foo { }"
var syntaxTree = CSharpSyntaxTree.ParseText(str);

// Add Region
// ????

Solution

  • Regions are represented by Roslyn as special kind of SyntaxTrivia. So for the purpose of wrapping block of code into region you may get target SyntaxNode and replace it's leading and trailing trivia with regions trivia. The following code demonstrates how this can be done:

    public static T AddRegion<T>(this T node, string regionName) where T : SyntaxNode
    {
        return node
            // inserts #region RegionName before node
            .WithLeadingTrivia(node.GetLeadingTrivia().Insert(0, GetRegionLeadingTrivia(regionName)))
            // inserts #endregion after node
            .WithTrailingTrivia(node.GetTrailingTrivia().Add(GetRegionTrailingTrivia()));
    }
    
    public static SyntaxTrivia GetRegionLeadingTrivia(string regionName)
    {
        return SyntaxFactory.Trivia(
            SyntaxFactory
                .RegionDirectiveTrivia(true)
                .WithEndOfDirectiveToken(
                    SyntaxFactory.Token(
                        SyntaxFactory.TriviaList(SyntaxFactory.PreprocessingMessage(regionName)),
                        SyntaxKind.EndOfDirectiveToken,
                        SyntaxFactory.TriviaList())));
    }
    
    public static SyntaxTrivia GetRegionTrailingTrivia()
    {
        return SyntaxFactory.Trivia(SyntaxFactory.EndRegionDirectiveTrivia(true));
    }
    

    To perform more complex operations you may use CSharpSyntaxRewriter class. Some examples of using that class may be found at here.