Can I move the Declaration or Triva syntax at a certain position?

Answered Can I move the Declaration or Triva syntax at a certain position?

  • Donnerstag, 26. April 2012 10:14
     
      Enthält Code

    Dear everyone,

    I'm trying to create some small program to play with Roslyn, I just want to add [OperationContract] for every methods in interface, and it works fine. And you can see the result's like this:

    using System;
    using System.ServiceModel;
    namespace Solution
    {
        public class IInterface
        {
    
            [OperationContract]
            /*
             * We have comments here
             */
            string Method1(string value);
        }
    }

    But I wonder that if we can change the [OperationContract] attribute is right above the "Method1" or not?, and MultilineComments trivia is above the attribute.

    Thanks in advance.

    Bui Duc Nha.


    • Bearbeitet Bui Duc Nha Donnerstag, 26. April 2012 10:22
    •  

Alle Antworten

  • Donnerstag, 26. April 2012 22:48
    Besitzer
     
     Beantwortet Enthält Code

    Hi - You should be able to do this by removing the leading trivia from the MethodDeclarationSyntax and attaching it to your new Attribute. The below example demonstrates a couple of ways to do this.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using Roslyn.Compilers.CSharp;
     
    class Program
    {
        static void Main()
        {
            var code = @"
    using System;
    using System.ServiceModel;
    namespace Solution
    {
        public interface IInterface
        {
     
            /*
             * We have comments here
             */
            string Method1(string value);
            string Method2(string value);
        }
    }";
            SyntaxTree tree = SyntaxTree.ParseCompilationUnit(code);
            var rewriter = new AttributeInserter(tree);
            var newRoot = (CompilationUnitSyntax)rewriter.Visit(tree.Root);
     
            // newRoot = newRoot.Format(); // This is required in case of Option2 below.
            Console.WriteLine(newRoot.GetFullText());
     
            var newTree = SyntaxTree.Create("MyFile.cs", newRoot);
        }
     
        class AttributeInserter : SyntaxRewriter
        {
            SyntaxTree tree;
            public AttributeInserter(SyntaxTree tree)
            {
                this.tree = tree;
            }
     
            private IEnumerable<SyntaxTrivia> GetAllLeadingWhitespaceThatIsOnSameLineAsNode(SyntaxNode node)
            {
                var line = tree.GetLineSpan(node.Span, false).StartLinePosition.Line;
                return node.GetLeadingTrivia()
                    .Where(t => t.Kind == SyntaxKind.WhitespaceTrivia && 
                                tree.GetLineSpan(t.Span, false).StartLinePosition.Line == line);
            }
     
            protected override SyntaxNode VisitMethodDeclaration(MethodDeclarationSyntax methodDeclaration)
            {
                if (methodDeclaration.Parent.Kind == SyntaxKind.InterfaceDeclaration)
                {
                    // Create new attribute.
                    var attribute = Syntax.AttributeDeclaration(attributes: Syntax.SeparatedList<AttributeSyntax>(
                        Syntax.Attribute(Syntax.ParseName("OperationContract"))));
     
                    // Copy all leading trivia from method declaration (including comments) onto the attribute.
                    attribute = attribute
                        .WithLeadingTrivia(methodDeclaration.GetLeadingTrivia())
                        .WithTrailingTrivia(Syntax.EndOfLine("\r\n"));
     
                    // Remove leading trivia from the method declaration since we
                    // have now copied those over to the attribute.
     
                    // Option1:
                    // We can preserve just the leading whitespace trivia that exists on the
                    // same line as the method declaration to preserve formatting.
                    methodDeclaration = methodDeclaration.WithLeadingTrivia(
                        GetAllLeadingWhitespaceThatIsOnSameLineAsNode(methodDeclaration));
     
                    // Option2: If you don't want to worry about formatting now, you could
                    // remove 'all' leading trivia from the method declaration
                    // and just call .Format() to normalize whitespace on 'newRoot' above.
                    // node = node.WithLeadingTrivia();
     
                    // Update the method declaration with the new attribute.
                    methodDeclaration = methodDeclaration.Update(
                        attributes: Syntax.List<AttributeDeclarationSyntax>(attribute),
                        modifiers: methodDeclaration.Modifiers,
                        returnType: methodDeclaration.ReturnType,
                        explicitInterfaceSpecifierOpt: methodDeclaration.ExplicitInterfaceSpecifierOpt,
                        identifier: methodDeclaration.Identifier,
                        typeParameterListOpt: methodDeclaration.TypeParameterListOpt,
                        parameterList: methodDeclaration.ParameterList,
                        constraintClauses: methodDeclaration.ConstraintClauses,
                        bodyOpt: methodDeclaration.BodyOpt,
                        semicolonTokenOpt: methodDeclaration.SemicolonTokenOpt);
                }
     
                return methodDeclaration;
            }
        }
    }

    Hope this helps!


    Shyam Namboodiripad | Software Development Engineer in Test | Roslyn Compilers Team

    • Als Antwort markiert Bui Duc Nha Freitag, 27. April 2012 01:57
    •  
  • Freitag, 27. April 2012 01:59
     
     
    That's exactly What I need, thanks a lot!