从Roslyn SyntaxRewriter中修改的SyntaxNode访问SymbolInfo

时间:2015-02-14 12:12:16

标签: c# roslyn

我创建一个SyntaxRewriter,如果类继承某种类型,则将类标记为partial,将方法标记为virtual

为了做到这一点,我从重写器内部的语义模型中查找SymbolInfo,我遇到的问题是,一旦我修改了syntaxtree以使类成为局部,我已经使SemanticModel无效并且不能用它来获取方法的SymbolInfo。

下面是重写器的一个粗略的例子,.InheritsFrom< T>()是一种扩展方法,只是遍历继承以查找特定类型的用法,我只是将IDisposable作为一个例子,但它并不是真正重要的类型。 .WithPartialModifier()只是一个将partial添加到类syntaxnode修饰符的扩展方法。

我可能需要切换我的方法或使用新的syntaxtree更新编译,但我不确定如何继续。

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

1 个答案:

答案 0 :(得分:3)

在修改树之前,您可以先调用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;
    }
}