Building a SyntaxTree from the ground up

c#, roslyn

Solution

This will build up your entire compilation unit tree in one expression.

var cu = SyntaxFactory.CompilationUnit()
            .AddMembers(
                SyntaxFactory.NamespaceDeclaration(Syntax.IdentifierName("ACO"))
                        .AddMembers(
                        SyntaxFactory.ClassDeclaration("MainForm")
                            .AddBaseListTypes(SyntaxFactory.ParseTypeName("System.Windows.Forms.Form"))
                            .WithModifiers(SyntaxFactory.Token(SyntaxKind.PublicKeyword))
                            .AddMembers(
                                Syntax.PropertyDeclaration(SyntaxFactory.ParseTypeName("System.Windows.Forms.Timer"), "Ticker")
                                        .AddAccessorListAccessors(
                                        SyntaxFactory.AccessorDeclaration(SyntaxKind.GetAccessorDeclaration).WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)),
                                        SyntaxFactory.AccessorDeclaration(SyntaxKind.SetAccessorDeclaration).WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken))),
                                SyntaxFactory.MethodDeclaration(SyntaxFactory.ParseTypeName("void"), "Main")
                                        .AddModifiers(SyntaxFactory.Token(SyntaxKind.PublicKeyword))
                                        .AddAttributes(SyntaxFactory.AttributeDeclaration().AddAttributes(SyntaxFactory.Attribute(SyntaxFactory.IdentifierName("STAThread"))))
                                        .WithBody(SyntaxFactory.Block())
                                )
                        )
                );

Of course, you don't have to do it as a single expression. I could have used separate local variables to collect the pieces I wanted and then added them in the construction of the containing syntax piece.

Problem

I previously asked this question, which was answered, but someone gave a suggestion that might help me prevent making similar mistakes as I move forward. Adding Auto-Implemented Property to class using Roslyn The suggestion was that I build the Syntax Tree from the bottom up and not from the top down. Could someone provide a small demo or a link that shows how I would do this from the ground up? Here is the code again: ``` var root = (CompilationUnitSyntax)document.GetSyntaxRoot(); // Add the namespace var namespaceAnnotation = new SyntaxAnnotation(); root = root.WithMembers( Syntax.NamespaceDeclaration( Syntax.ParseName("ACO")) .NormalizeWhitespace() .WithAdditionalAnnotations(namespaceAnnotation)); document = document.UpdateSyntaxRoot(root); // Add a class to the newly created namespace, and update the document var namespaceNode = (NamespaceDeclarationSyntax)root .GetAnnotatedNodesAndTokens(namespaceAnnotation) .Single() .AsNode(); var classAnnotation = new SyntaxAnnotation(); var baseTypeName = Syntax.ParseTypeName("System.Windows.Forms.Form"); SyntaxTokenList syntaxTokenList = new SyntaxTokenList() { Syntax.Token(SyntaxKind.PublicKeyword) }; var newNamespaceNode = namespaceNode .WithMembers( Syntax.List<MemberDeclarationSyntax>( Syntax.ClassDeclaration("MainForm") .WithAdditionalAnnotations(classAnnotation) .AddBaseListTypes(baseTypeName) .WithModifiers(Syntax.Token(SyntaxKind.PublicKeyword)))); root = root.ReplaceNode(namespaceNode, newNamespaceNode).NormalizeWhitespace(); document = document.UpdateSyntaxRoot(root); var attributes = Syntax.List(Syntax.AttributeDeclaration(Syntax.SeparatedList(Syntax.Attribute(Syntax.ParseName("STAThread"))))); // Find the class just created, add a method to it and update the document var classNode = (ClassDeclarationSyntax)root .GetAnnotatedNodesAndTokens(classAnnotation) .Single() .AsNode(); var syntaxList = Syntax.List<MemberDeclarationSyntax>( Syntax.MethodDeclaration( Syntax.ParseTypeName("void"), "Main") .WithModifiers(Syntax.TokenList(Syntax.Token(SyntaxKind.PublicKeyword))) .WithAttributes(attributes) .WithBody( Syntax.Block())); syntaxList = syntaxList.Add(Syntax.PropertyDeclaration(Syntax.ParseTypeName("System.Windows.Forms.Timer"), "Ticker")); var newClassNode = classNode .WithMembers(syntaxList); root = root.ReplaceNode(classNode, newClassNode).NormalizeWhitespace(); document = document.UpdateSyntaxRoot(root); ``` So how would I do the same thing, but from the ground up? Thanks in advance, Bob P.S. My property is also missing the "get; set;" text within it. Could someone comment on what I am forgetting to add which causes this text to be added to the property?

Original source

Related problems