Find specific invocation

Topics: APIs, C# Language Design
Dec 17, 2014 at 1:33 PM
Hey boys and girls!
I've got a specific method invocation similar to:

Foo.Format(CultureInfo.CurrentCulture, ResourceFile.SomeString, x, y);

I only want to place all calls of this mehod under extra scrutiny and now I'm desperately looking for a lightweight way of finding all invocations of this method. The problem is, that these calls can be on all kinds of layers. I know that there is a FindNodes() that I can call on the root element of the syntax tree, but I can't figure out how to do this.
Does anybody have any experience with a similar issue?

THX!!!!!!!
Developer
Dec 17, 2014 at 7:54 PM
What you want to do is get the method symbol for the method in question, then use the symbol finder to discover everywhere it is used.
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.FindSymbols;
using Microsoft.CodeAnalysis.MSBuild;

class FindAllUsesOfMethodInSolution
{
    static void Main(string[] args)
    {
        var cts = new CancellationTokenSource();
        Console.CancelKeyPress += (sender, e) => cts.Cancel();
        Run(
            solutionFilePath: args[0],
            projectName:  args[1],
            metadataNameOfMethodsContainingType:  args[2],
            methodMetadataName:  args[3],
            cancellationToken:  cts.Token)
                .GetAwaiter()
                .GetResult();
    }

    static async Task Run(
        string solutionFilePath, 
        string projectName, 
        string metadataNameOfMethodsContainingType, 
        string methodMetadataName, 
        CancellationToken cancellationToken)
    {
        // First open the solution.
        var workspace = MSBuildWorkspace.Create();
        var solution = await workspace
            .OpenSolutionAsync(solutionFilePath, cancellationToken)
            .ConfigureAwait(false);

        // Next get the project where your method is defined.
        var project = solution.Projects
            .Where(proj => proj.Name == projectName)
            .Single();

        // Get the compilation an look for the desired type by its meta-data name.
        var compilation = await project
            .GetCompilationAsync(cancellationToken).ConfigureAwait(false);
        var typeSymbol = compilation
            .GetTypeByMetadataName(metadataNameOfMethodsContainingType);

        // Get the desired method symbol by its meta-data name.
        var methodSymbol = typeSymbol.GetMembers()
            .OfType<IMethodSymbol>()
            .Where(method => method.MetadataName == methodMetadataName)
            .Single();

        // Use the symbol finder to locate everywhere this method is used in the solution.
        var references = await SymbolFinder
            .FindReferencesAsync(typeSymbol, solution, cancellationToken).ConfigureAwait(false);

        // Enumerate the results and print out the locations.
        foreach (var referenceLocation in references.SelectMany(reference => reference.Locations))
        {
            cancellationToken.ThrowIfCancellationRequested();
            var location = referenceLocation.Location;
            if (location.IsInSource)
            {
                var text = await location
                    .SourceTree.GetTextAsync(cancellationToken).ConfigureAwait(false);
                var lineNumber = location
                    .GetLineSpan().StartLinePosition.Line;
                var line = text.Lines[lineNumber];
                Console.WriteLine("method found at {0} with line text: {1}", location, line.Text);
            }
        }
    }
}