简体   繁体   English

Roslyn怀疑SyntaxTree的构造

[英]Roslyn doubts on SyntaxTree construction

Disclaimer 放弃

I'm pretty sure I'm missing something obvious, but even after reading official documentation I don't clearly understand how Roslyn create a syntax tree. 我很确定我错过了一些明显的东西,但即使在阅读官方文档之后,我也不清楚Roslyn如何创建语法树。

Example

Consider the following, simple code: 请考虑以下简单代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace aopsample
{

    class UsbReadWriter
    {

        public bool ReadFromUsb()
        {
            return true;
        }

        public virtual bool WriteToUsb()
        {
            return true;
        }
    }
}

I get a SyntaxTree for this code and make something like this, very rough and simple, but I just need to understand. 我为这段代码得到了一个SyntaxTree ,做了类似的东西,非常粗糙和简单,但我只需要理解。

  string[]lines =  System.IO.File.ReadAllLines(filename);      
  string tocompile = string.Join(string.Empty, lines);  

  SyntaxNode root = tree.GetRoot(new CancellationToken());
  foreach (SyntaxNode sn in root.ChildNodes())
  {
      if (sn.Kind == SyntaxKind.NamespaceDeclaration)
      {
         //I get a namespace, so it's Child node just will be class
         foreach (SyntaxNode sname in sn.ChildNodes())
         {
             if (sname.Kind == SyntaxKind.ClassDeclaration)
             {
                 //I get class, so it's  Children will be methods of the class        
                 foreach (SyntaxNode sclass in sname.ChildNodes()) // **{1}** 
                 {
                     if (sclass.Kind == SyntaxKind.MethodDeclaration) 
                     {

                     }
                 }
             }
        }

And it works pretty well. 它运作得很好。

Trouble 麻烦

But, it's enough to add a comment to the ReadFromUsb() method, something like this 但是,它足以为ReadFromUsb()方法添加注释,就像这样

/// <summary>
/// Reads a data from Usb
/// </summary>
/// <returns></returns>
public bool ReadFromUsb()
{
    return true;
}

And ChildNodes() call on {1} marked line, for CLASS (???) returns 0. 并且ChildNodes()调用{1}标记的行,因为CLASS (???)返回0。

Question

Why adding a comment to member function, resets the collection of parent CLASS children Syntax nodes ? 为什么在成员函数中添加注释,重置父CLASS子句语法节点的集合?

What am I missing ? 我错过了什么?

Following a chat discussion, we determined that the problem was the the code to parse was being constructed with: 在聊天讨论之后,我们确定问题是正在构建的解析代码:

string[]lines = System.IO.File.ReadAllLines(filename); 
string tocompile = string.Join(string.Empty, lines);

Which puts all of the code onto a single line. 这将所有代码放在一行上。 Therefore everything after // becomes a comment. 因此//之后的所有内容都成为评论。 The solution is just to use Environment.NewLine as the join character, or use ReadAllText instead of ReadAllLines . 该解决方案是只使用Environment.NewLine作为连接字符,或使用ReadAllText代替ReadAllLines

Since comments can appear anywhere at all in source code, they are not modeled as a ChildNode , which are reserved for true syntactic elements. 由于注释可以出现在源代码中的任何位置,因此它们不会被建模为ChildNode ,它们是为真正的语法元素保留的。 Instead, they are considered SyntaxTrivia . 相反,它们被认为是SyntaxTrivia In your example, you should be able to look at the LeadingTrivia of the method and see the comment. 在您的示例中,您应该能够查看方法的LeadingTrivia并查看注释。

Additionally, since this is an XML doc comment which may have interesting structure of it's own, that will be modeled as it's own little tree that you can get with the GetStructure() method of the SyntaxTrivia . 另外,由于这是一个XML文档注释,它可能具有它自己的有趣结构,因此它将被建模为它自己的小树,您可以使用GetStructure()方法获得SyntaxTrivia

For such situations, Using CSharpSyntaxWalker can be of great help. 对于这种情况,使用CSharpSyntaxWalker可能会有很大帮助。

Following is sample extracted from Josh Varty's blog here which helps to print syntax tree on console : 以下是从提取样品乔希Varty的博客在这里有助于对控制台打印语法树:

 public class CustomWalker : CSharpSyntaxWalker
{
    static int Tabs = 0;
    public override void Visit(SyntaxNode node)
    {
        Tabs++;
        var indents = new String('\t', Tabs);
        Console.WriteLine(indents + node.Kind());
        base.Visit(node);
        Tabs--;
    }
}

static void Main(string[] args)
{
    var tree = CSharpSyntaxTree.ParseText(@"
        public class MyClass
        {
            public void MyMethod()
            {
            }
            public void MyMethod(int n)
            {
            }
       ");

    var walker = new CustomWalker();
    walker.Visit(tree.GetRoot());
}

You can also print trivias by calling GetLeadingTrivia and GetTrailingTrivia methods on syntax nodes. 您还可以通过在语法节点上调用GetLeadingTriviaGetTrailingTrivia方法来打印trivias。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM