Roslyn 对 SyntaxTree 构造表示怀疑

本文关键字:表示 怀疑 SyntaxTree Roslyn | 更新日期: 2023-09-27 18:19:10

免责声明

我很确定我错过了一些明显的东西,但即使在阅读了官方文档之后,我也不清楚 Roslyn 是如何创建语法树的。

请考虑以下简单代码:

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;
        }
    }
}

我得到了这段代码的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) 
                     {
                        
                     }
                 }
             }
        }

而且效果很好。

麻烦

但是,在ReadFromUsb()方法中添加注释就足够了,如下所示

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

ChildNodes()调用{1}标记的行,因为 CLASS (???( 返回 0。

问题

为什么要在成员函数中添加注释,重置父CLASS子语法节点的集合?

我错过了什么?

Roslyn 对 SyntaxTree 构造表示怀疑

在聊天讨论之后,我们确定问题是要解析的代码是用以下方法构建的:

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

这会将所有代码放在一行上。 因此,//之后的所有内容都成为评论。 解决方案只是使用 Environment.NewLine 作为连接字符,或使用 ReadAllText 而不是 ReadAllLines

由于注释可以出现在源代码中的任何位置,因此它们不会被建模为ChildNode,这是为真正的语法元素保留的。相反,它们被认为是 SyntaxTrivia . 在您的示例中,您应该能够查看方法的LeadingTrivia并查看注释。

此外,由于这是一个XML文档注释,它可能有自己的有趣结构,因此将被建模为它自己的小树,您可以使用SyntaxTriviaGetStructure()方法获得。

对于这种情况,使用 CSharpSyntaxWalker 可能会有很大帮助。

以下是从Josh 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());
}

还可以通过在语法节点上调用 GetLeadingTriviaGetTrailingTrivia 方法来打印琐事。