Coding for fun: Write your code in comments with Roslyn

Sometimes, you have some very basic methods and you could find useless to comment them but sometimes you have to comment them in order to generate help file.

Some tools allow you to generate comments using the method signature.

For fun, I will use another way: I will write the method code in the comment.

I have a ConsoleApplication:

class Program
{
    
static void Main(string
[] args)
     {
        
Console.WriteLine("a ?"
);
        
int a = int.Parse(Console
.ReadLine());
        
Console.WriteLine("b ?"
);
        
int b = int.Parse(Console
.ReadLine());
        
Console.WriteLine("{0} + {1} = {2}"
, a, b, Add(a, b));
        
Console
.ReadLine();
     }



/// <summary> /// return a + b; /// </summary> /// <param name="a"></param> /// <param name="b"></param> /// <returns></returns> public static int Add(int a, int
b)
{
        
throw new NotImplementedException();
} }


The code of the Add method (return a + b;) is commented.



Now I will write my own C# compiler using Roslyn:



class Program
{
    
static void Main(string
[] args)
     {
        
string
solutionPath = args[0];
        
string
binaryDirectory = args[1];
        
var solution = Solution
.Load(solutionPath);
        
List<IProject
> notSortedProjects = solution.Projects.ToList();
        
List<IProject> projects = new List<IProject
>();
        
do
         {
            
foreach (IProject project in
notSortedProjects.ToList())
             {
                
if
(project.ProjectReferences.All(prId => projects.Any(p => p.Id == prId)))
                 {
                     projects.Add(project);
                     notSortedProjects.Remove(project);
                 }
             }
         }
while
(notSortedProjects.Count != 0);


        
foreach (var project in
projects)
         {
            
foreach (var document in
project.Documents)
             {
                
var
documentTree = document.GetSyntaxTree();
                
var newDocumentTree = new CodeInCommentsRewriter().Visit((SyntaxNode
)documentTree.Root);
                
var newDocumentTreeText = new StringText
(newDocumentTree.ToString());
                 solution = solution.UpdateDocument(document.Id, newDocumentTreeText);
             }
            
using (var stream = new FileStream(string.Format("{0}.{1}"
,
                 
Path
.Combine(binaryDirectory, project.AssemblyName),
                  project.CompilationOptions.AssemblyKind ==
AssemblyKind.DynamicallyLinkedLibrary ? "dll" : "exe"), FileMode
.Create))
             {
                
var
emitResult = solution.Projects.First(p => p.Id == project.Id).GetCompilation().Emit(stream);
                
if
(!emitResult.Success)
                    
throw new InvalidOperationException();
             }
         }
     } }


public class CodeInCommentsRewriter : SyntaxRewriter
{
    
protected override SyntaxNode VisitMethodDeclaration(MethodDeclarationSyntax
node)
     {
        
IEnumerator<SyntaxNode
> bodySyntaxNodesEnumerator = node.BodyOpt.ChildNodes().GetEnumerator();
        
if
(bodySyntaxNodesEnumerator.MoveNext())
         {
            
ThrowStatementSyntax childNode = bodySyntaxNodesEnumerator.Current as ThrowStatementSyntax
;
            
if (!bodySyntaxNodesEnumerator.MoveNext()// only one child node                 && childNode != null
)
             {
                
var comment = node.GetLeadingTrivia().Select(t => Regex.Match(t.GetText(), "return (.?)*").Value).FirstOrDefault(v => ! string
.IsNullOrEmpty(v));
                
if (comment != null
)
                 {
                    
return Syntax
.MethodDeclaration(
                         node.Attributes,
                         node.Modifiers,
                         node.ReturnType,
                         node.ExplicitInterfaceSpecifierOpt,
                         node.Identifier,
                         node.TypeParameterListOpt,
                         node.ParameterList,
                         node.ConstraintClauses,
                        
Syntax
.Block(
                             node.BodyOpt.OpenBraceToken,
                            
Syntax
.List(
                                
Syntax
.ParseStatement(comment)),
                             node.BodyOpt.CloseBraceToken),
                         node.SemicolonTokenOpt);
                 }
             }
         }
        
return base.VisitMethodDeclaration(node);
     } }


And here we are! // I use some shortcut (the code is a return in one line)



If I execute my compiler and then the generated exe, I can see in the Console that 1 + 2 = 3.

This entry was posted in 16402, 7671, 7672. Bookmark the permalink.

6 Responses to Coding for fun: Write your code in comments with Roslyn

  1. ilya says:

    Hello!
    How to add the comment to a method with Roslyn?

    For example:
    Input (without comment):
    void f()
    {
    }

    Output (with comment):
    ///

    /// some message
    ///

    void f()
    {
    }

    Thanks!

  2. ilya says:

    Hello!
    How to add the comment to a method with Roslyn?

    For example:
    Input (without comment):
    void f()
    {
    }

    Output (with comment):
    /// [summary]
    /// some message
    /// [/summary]
    void f()
    {
    }

    Thanks!

  3. I thoroughly enjoy your blog posts and I consciously put into practice your concepts as they allow us to..

  4. paperleader says:

    Truly remarkable labor with the blog. I do like your inflexible service and will wait for more post from.

  5. samedayessay says:

    That is very kind of you to write this share for us, thanks a lot

  6. Truly remarkable labor with the blog. I do like your inflexible service and will wait for more post from.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>