我正在使用Roslyn编写代码分析器,我当前的任务是找到程序集中未使用的所有内部方法。
我从MethodDeclarationSyntax
开始并从中获取符号。然后我在FindCallersAsync
中使用SymbolFinder
方法,但即使我在程序集中的某个地方调用了相关方法,它也会返回一个空集合。请参阅下面的代码。
protected override void Analyze(SyntaxNodeAnalysisContext context)
{
NodeToAnalyze = context.Node;
var methodDeclaration = NodeToAnalyze as MethodDeclarationSyntax;
if (methodDeclaration == null)
return;
var methodSymbol = context.SemanticModel.GetDeclaredSymbol(methodDeclaration) as ISymbol;
if (methodSymbol.DeclaredAccessibility != Accessibility.Internal)
return;
var solutionPath = GetSolutionPath();
var msWorkspace = MSBuildWorkspace.Create();
var solution = msWorkspace.OpenSolutionAsync(solutionPath).Result;
var callers = SymbolFinder.FindCallersAsync(symbol, solution).Result; // Returns empty collection.
...
}
我见过类似的代码here,但在该示例中,方法符号是使用GetSymbolInfo
上的InvocationExpressionSyntax
获得的:
//Get the syntax node for the first invocation to M()
var methodInvocation = doc.GetSyntaxRootAsync().Result.DescendantNodes().OfType<InvocationExpressionSyntax>().First();
var methodSymbol = model.GetSymbolInfo(methodInvocation).Symbol;
//Finds all references to M()
var referencesToM = SymbolFinder.FindReferencesAsync(methodSymbol, doc.Project.Solution).Result;
但是,在我的情况下,我需要从声明中找到调用(如果有的话)。如果我首先获得调用并从GetSymbolInfo
传入符号,则会正确返回对方法的调用 - 因此问题似乎与symbol
参数有关,而不是solution
。
由于我试图获取声明的基础符号,因此我无法使用GetSymbolInfo
,而是使用GetDeclaredSymbol
代替(建议使用here)。
我对this文章的理解是,GetDeclaredSymbol
和GetSymbolInfo
返回的符号应该相同。但是,使用Equals
进行简单比较会返回false
。
有没有人知道返回的两个符号之间有什么区别,以及如何获得有效的“正确”符号?或者也许完全有更好的方法?我的所有研究似乎都指向FindCallersAsync
,但我无法让它发挥作用。
答案 0 :(得分:3)
我对本文的理解是,GetDeclaredSymbol和GetSymbolInfo返回的符号应该相同。但是,使用Equals进行简单比较会返回false。
这是因为它们不是同一个符号;它们来自完全不同的编辑,可能会也可能不会有所不同。一个来自正在积极编译的编译器,一个来自MSBuildWorkspace。
从根本上说,不支持在分析器中使用MSBuildWorkspace。完全。不要那样做。这不仅真的慢,而且还有各种正确性问题,特别是如果你在Visual Studio中运行你的分析器。如果你的目标是在解决方案的任何地方找到未使用的方法,那么我们并不真正支持实现分析器,因为这涉及跨项目分析。