如何在Roslyn中获取Invoked方法名称?

时间:2015-04-13 20:06:42

标签: c# roslyn

我有这样的代码;

class abc{
    void A()
    {
        //Some to do statements
    }
    void B()
    {
        var obj=A();
    }
    void C()
    {
        var call=B();
    }
}

我想使用roslyn找到Invoked方法名称。

就像这里o / p将是:

    方法B的
  • :调用方法A
  • 方法C的
  • :调用方法A

我想要这样的事情:

root.DescendantNodes().OfType<InvocationExpressionSyntax>().Where(md => md.Identifier.ValueText.Equals(methodName)).FirstOrDefault();

但InvocationExpression不包含要访问的标识符。 如何获取标识符名称

3 个答案:

答案 0 :(得分:12)

我同意SLaks并且如果你想要的话会增加他的答案:

“我希望接收器语法的方法调用语法节点 - 让我强调语法 - 是一个等于某个特定字符串的单个标识符”

然后您想要的查询类似于

var root = tree.GetRoot();
var nodes = from node in root.DescendantNodes()
                         .OfType<InvocationExpressionSyntax>()
            let id = node.Expression as IdentifierNameSyntax
            where id != null
            where id.Identifier.ValueText == methodName
            select node;

但我认为这可能不是你想要的。如果您想要的是“我想确切地知道调用哪个方法,无论它是写入A(...)还是Foo.Bar.A(...),那么您不想考虑语法您将需要使用语义分析器来获取与调用关联的符号,然后检查该符号是否标识了您感兴趣的方法。

您是否主要对语法语义分析感兴趣?罗斯林也做了,但你只是在看你所呈现的代码中的语法。

如果您正在寻找的是语义分析,那么您想要做这样的事情:

var tree = CSharpSyntaxTree.ParseText(code);
var c = CSharpCompilation.Create("asm.dll");
c = c.AddSyntaxTrees(tree);
var model = c.GetSemanticModel(tree);
string methodName = "A";

var root = tree.GetRoot();
var symbols = from node in root.DescendantNodes()
                           .OfType<InvocationExpressionSyntax>()
            let symbol = model.GetSymbolInfo(node.Expression).Symbol as IMethodSymbol
            where symbol != null
            where symbol.Name = methodName
            select symbol;

答案 1 :(得分:4)

InvocationExpressionSyntax没有Identifier的原因,因为它可能具有这种情况var obj = this.A()所以这就是为什么InvocationExpressionSyntax将包含类型为ExpressionSyntax的属性Expression(可能是IdentifierNameSyntax类型),

1.对于您的案例,简单的答案就是您可以像这样访问属性Expression。

foreach (var item in root.DescendantNodes()
.OfType<InvocationExpressionSyntax>())
             {
                var expr = item.Expression;
                if (expr is IdentifierNameSyntax)
                {
                    IdentifierNameSyntax identifierName = r as IdentifierNameSyntax; // identifierName is your method name
                }

                if (expr is MemberAccessExpressionSyntax)
                {
                    MemberAccessExpressionSyntax memberAccessExpressionSyntax = r as MemberAccessExpressionSyntax;
                    //memberAccessExpressionSyntax.Name is your method name
                }
            }

2.但是对于精确查找,调用方法与您声明必须使用语义信息的方法相同,如Roslyn项目中的示例所示 https://github.com/dotnet/roslyn/wiki/FAQ#how-do-i-find-all-calls-in-a-compilation-into-a-particular-namespace

答案 2 :(得分:3)

您误解了这些节点在语法树中的作用。

您应该在VS中使用Roslyn语法Visualizer来查看方法调用的节点实际上是什么样的。

简而言之:InvocationExpression仅表示someExpression(some arguments)。该表达式可以是许多内容,例如构造函数调用,成员访问,数组访问或解析为方法或委托的任何其他表达式。
您需要检查Kind的{​​{1}}并找出您希望如何处理每种可能的表达方式。