SymbolFinder.FindReferencesAsync doesn't find anything

你说的曾经没有我的故事 提交于 2019-12-22 12:30:09

问题


I want to find all PropertyChangedEventHandler events in my solution, and then find all listeners added to those events. But I can't seem to get a list of the events.

This is all the code in the solution being analyzed:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace RoslynTarget
{
    public class Example : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged = delegate { };

        public void DoNothing() { }
    }
}

And this is my code for analyzing it. references.Count == 1 and r.Locations.Count == 0, but exactly one location should be found. What's going on here?

Program.cs

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.FindSymbols;
using Microsoft.CodeAnalysis.MSBuild;

namespace RoslynTest
{
    class Program
    {
        static void Main(string[] args)
        {
            const string solutionPath = @"C:\Users\<user>\Code\RoslynTarget\RoslynTarget.sln";
            const string projectName = "RoslynTarget";

            var msWorkspace = MSBuildWorkspace.Create(new Dictionary<string, string> { { "CheckForSystemRuntimeDependency", "true" } });
            var solution = msWorkspace.OpenSolutionAsync(solutionPath).Result;

            var project =
                solution.Projects
                    .Where(proj => proj.Name == projectName)
                    .First();

            var compilation = project.GetCompilationAsync().Result;
            var eventType = compilation.ResolveType("System.ComponentModel.PropertyChangedEventHandler").First();
            var references = SymbolFinder.FindReferencesAsync(eventType, solution).Result;

            foreach (var r in references)
            {
                foreach (var loc in r.Locations)
                {
                    // ...
                }
            }
        }
    }
}

Extensions.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;

namespace RoslynTest
{
    public static class Extensions
    {
        public static IEnumerable<INamedTypeSymbol> ResolveType(this Compilation compilation, string classFullName)
        {
            return new IAssemblySymbol[] { compilation.Assembly }
                .Concat(compilation.References
                    .Select(compilation.GetAssemblyOrModuleSymbol)
                    .OfType<IAssemblySymbol>())
                .Select(asm => asm.GetTypeByMetadataName(classFullName))
                .Where(cls => cls != null);
        }
    }
}

回答1:


Recently I've done similar thing where I was trying to find the reference of a method in complete solution. To use FindReferenceAsync you have create symantic model first and find the symbol from there. Once you have the symbol you can use the FindReferenceAsync.

Here's the snippet that I used and it's working:

var solution = msWorkspace.OpenSolutionAsync(solutionPath).Result;
foreach (var project in solution.Projects)
{
    foreach (var document in project.Documents)
    {
        var model = document.GetSemanticModelAsync().Result;

        var methodInvocation = document.GetSyntaxRootAsync().Result;
        InvocationExpressionSyntax node = null;
        try
        {
            node = methodInvocation.DescendantNodes().OfType<InvocationExpressionSyntax>()
             .Where(x => ((MemberAccessExpressionSyntax)x.Expression).Name.ToString() == methodName).FirstOrDefault();

            if (node == null)
                continue;
        }
        catch(Exception exception)
        {
            // Swallow the exception of type cast. 
            // Could be avoided by a better filtering on above linq.
            continue;
        }

        methodSymbol = model.GetSymbolInfo(node).Symbol;
        found = true;
        break;
    }

    if (found) break;
}

foreach (var item in SymbolFinder.FindReferencesAsync(methodSymbol, solution).Result)
{
    foreach (var location in item.Locations)
    {
        Console.ForegroundColor = ConsoleColor.Green;
        Console.WriteLine("Project Assembly -> {0}", location.Document.Project.AssemblyName);
        Console.ResetColor();
    }

}

Here's the complete working code. If you want to visualize the Roslyn tree then you can try using Roslyn tree visualizer to see code structuring.

Update

As per discussion in comments with OP Installing Roslyn SDK fixed the issue. Assuming that there might be some updates in SDK to generate Symbols information as compared to Nuget dlls when using GetCompilationAsync.



来源:https://stackoverflow.com/questions/34340828/symbolfinder-findreferencesasync-doesnt-find-anything

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