使用Roslyn查找特定方法的参数值

时间:2019-02-08 15:03:35

标签: c# roslyn

我需要查找所有发生的方法调用。

示例: 我有这样的课程:

public class Foo
{
   public string Bar(string firstParam, string secondParam){}
}

我需要做的是打开一个解决方案,并在Foo类中找到Bar方法的所有用法。现在,对于每种用法,我想检索第一个参数作为字符串传递时的值。

因此,如果我在代码中的某处有此行:

foo.Bar("some value", "something else")

然后我应该检索“一些值”。

现在,如果我有:

foo.Bar(someProperty, "something else")

那我应该忽略它。

在研究过程中确实找到了很多资料,但似乎找不到有效的方法。

1 个答案:

答案 0 :(得分:1)

我自己找到了答案。

该解决方案基于Visual Studio中的“独立代码分析工具”项目模板。

此模板随解决方案打开和工作区创建一起提供,因此我将跳过这一部分。

private static async Task<List<INamedTypeSymbol>> GetDeclarationOfType(string typeName, Solution solution)
{
     var symbols = await SymbolFinder.FindSourceDeclarationsAsync(solution, x => x.Equals(typeName));
     return symbols.Where(x => x.Kind == SymbolKind.NamedType).Cast<INamedTypeSymbol>().ToList();
}

在这里,我只是使用SymbolFinder来查找我要查找的类型的声明。

对于每个返回的符号,我然后获取其名称是我的类名称的成员(然后是方法):

var members = symbol.GetMembers().Where(x => x.Name.Equals("MyMethod"));

然后,对于每个匹配的成员,我将获得所有引用:

var references = await SymbolFinder.FindReferencesAsync(member, solution);

该解决方案部分基于this one,但我已根据需要对其进行了修改。

因此,对于每个引用,我将导航源代码树,直到找到调用为止。 当我找到一个参数时,我将得到我要寻找的参数(基于此处的索引),如果它的类型为SyntaxKind.StringLiteralExpression,那么我便拥有了我所需要的:

foreach (var referencedSymbol in references)
{
    foreach (var location in referencedSymbol.Locations)
    {
        var theToken = location.Location.SourceTree.GetRoot().FindToken(location.Location.SourceSpan.Start);
        var theNode = theToken.Parent;
        while (!theNode.IsKind(SyntaxKind.InvocationExpression))
        {
            theNode = theNode.Parent;
            if (theNode == null) break; // There isn't an InvocationExpression in this branch of the tree
        }

        if (theNode != null)
        {
            var argument = ((InvocationExpressionSyntax) theNode).ArgumentList.Arguments[searchPattern.ArgumentIndex];
            if (argument.Expression.IsKind(SyntaxKind.StringLiteralExpression))
            {
                textToTranslate.Add(argument.ToString());
            }
        }
    }
}

在参数本身上调用ToString()返回参数的实际值,因此,传递给方法的参数的字符串值。

作为参考,我的用例是从我的解决方案中提取所有可翻译的字符串。 这是一个非常大的解决方案(超过170个项目),它使用5种不同的方法来翻译字符串,而我需要一种在一种可以自动化的工具中自动在代码中查找它们的方法。

这可能不是最好的解决方案,但至少现在我会做。