从 Roslyn SyntaxRewriter 中修改后的 SyntaxNode 访问 SymbolInfo

Accessing SymbolInfo from modified SyntaxNode in Roslyn SyntaxRewriter

我正在创建一个 SyntaxRewriter,如果 class 继承自某种类型

,它会将 classes 标记为部分,将方法标记为虚拟

为此,我正在重写器中的语义模型中查找 SymbolInfo,我遇到的问题是,一旦我修改了语法树以生成 class 部分,我就已经失效SemanticModel 并且不能使用它来获取方法的 SymbolInfo。

下面是一个重写器的粗略示例,.InheritsFrom< T >() 是一种扩展方法,它只是遍历继承以查找特定类型的用法,我只是将 IDisposable 作为示例插入其中,但它不是类型是什么非常重要。 .WithPartialModifier() 再次只是一种扩展方法,用于将部分添加到 class syntaxnode 修饰符。

可能我需要改变我的方法或使用新的语法树更新编译,但我不确定如何继续。

public class RewriterPartial : CSharpSyntaxRewriter
{
    private readonly CSharpCompilation _compiler;

    public RewriterPartial(CSharpCompilation compiler)
    {
        this._compiler = compiler;
    }

    public override SyntaxNode VisitClassDeclaration(ClassDeclarationSyntax node)
    {
        var symbol = _compiler.GetSemanticModel(node.SyntaxTree).GetDeclaredSymbol(node);
        if (symbol.InheritsFrom<System.IDisposable>())
        {
            if (!node.Modifiers.Any(SyntaxKind.PartialKeyword))
            {
                node = node.WithPartialModifier();
            }
        }

        return base.VisitClassDeclaration(node);
    }

    public override SyntaxNode VisitMethodDeclaration(MethodDeclarationSyntax node)
    {
        var model = _compiler.GetSemanticModel(node.SyntaxTree);
        // fails above here as the node modified above 
        // and its SyntaxTree have no CompilationUnit
        // and I need to repeat the .InheritsFrom<T> call
        // to check if the method comes from a class in the syntaxtree
        // that inherits from the specific type
        return node;
    }
}

您可以先访问和修改最深的节点,方法是在修改树之前调用base.VisitClassDeclaration(node);

尝试以下操作:

public class RewriterPartial : CSharpSyntaxRewriter
{
    private readonly CSharpCompilation _compilation;
    public RewriterPartial(CSharpCompilation compilation, SemanticModel model)
    {
        this._compilation = compilation;
    }

    public override SyntaxNode VisitClassDeclaration(ClassDeclarationSyntax node)
    {
        //Visit the deepest nodes before modifying the tree.
        var newNode = (ClassDeclarationSyntax)base.VisitClassDeclaration(node);
        if (!newNode.Modifiers.Any(SyntaxKind.PartialKeyword))
        {
            newNode = newNode.WithModifiers(
                SyntaxFactory.TokenList(
                    SyntaxFactory.Token(SyntaxKind.PartialKeyword)));
        }
        return newNode;
    }

    public override SyntaxNode VisitMethodDeclaration(MethodDeclarationSyntax node)
    {
        var model = _compilation.GetSemanticModel(node.SyntaxTree);
        var symbol = model.GetDeclaredSymbol(node);
        //Do whatever you need to here
        return node;
    }
}