Find all method calls for a specific method using Roslyn

大憨熊 提交于 2020-01-13 05:18:46

问题


I am working on a code analyser using Roslyn and my current task is to find all internal methods which are unused in the assembly.

I start with a MethodDeclarationSyntax and get the symbol from that. I then use the FindCallersAsync method in SymbolFinder, but it returns an empty collection even when I am making a call to the method in question somewhere in the assembly. See the code below.

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.

    ...
}

I have seen similar code here, but in that example the method symbol is obtained using GetSymbolInfo on an 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;

However, in my case, I need to find the invocations (if any) from a declaration. If I do get the invocation first and pass in the symbol from GetSymbolInfo the calls to the method are returned correctly - so the issue seems to be with the symbol parameter and not solution.

Since I am trying to get the underlying symbol of a declaration, I cannot use GetSymbolInfo, but use GetDeclaredSymbol instead (as suggested here).

My understanding from this article is that the symbols returned from GetDeclaredSymbol and GetSymbolInfo should be the same. However, a simple comparison using Equals returns false.

Does anyone have any idea of what the difference is between the two symbols returned and how I can get the 'correct' one which works? Or perhaps there is a better approach entirely? All my research seems to point to FindCallersAsync, but I just can't get it to work.


回答1:


My understanding from this article is that the symbols returned from GetDeclaredSymbol and GetSymbolInfo should be the same. However, a simple comparison using Equals returns false.

This is because they're not the same symbol; they are coming from entirely different compilations which might or might not be different. One is coming from the compiler that is actively compiling, one is coming from MSBuildWorkspace.

Fundamentally, using MSBuildWorkspace in an analyzer is unsupported. Completely. Don't do that. Not only would that be really slow, but it also has various correctness issues, especially if you're running your analyzer in Visual Studio. If your goal is to find unused methods anywhere in a solution, that's something we don't really support implementing as an analyzer either, since that involves cross-project analysis.



来源:https://stackoverflow.com/questions/35459474/find-all-method-calls-for-a-specific-method-using-roslyn

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!