Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Finding all references to a method with Roslyn

I'm looking to scan a group of .cs files to see which ones call the Value property of a Nullable<T> (finding all references). For example, this would match:

class Program
{
    static void Main()
    {
        int? nullable = 123;
        int value = nullable.Value;
    }
}

I found out about Roslyn and looked at some of the samples, but many of them are outdated and the API is huge. How would I go about doing this?

I'm stuck after parsing the syntax tree. This is what I have so far:

public static void Analyze(string sourceCode)
{
    var tree = CSharpSyntaxTree.ParseText(sourceCode);

    tree./* ??? What goes here? */
}
like image 990
James Ko Avatar asked Aug 06 '15 17:08

James Ko


2 Answers

You're probably looking for the SymbolFinder class and specifically the FindAllReferences method.

It sounds like you're having some trouble getting familiar with Roslyn. I've got a series of blog posts to help people get introduced to Roslyn called Learn Roslyn Now.

As @SLaks mentions you're going to need access to the semantic model which I cover in Part 7: Introduction to the Semantic Model

Here's a sample that shows you how the API can be used. If you're able to, I'd use MSBuildWorkspace and load the project from disk instead of creating it in an AdHocWorkspace like this.

var mscorlib = PortableExecutableReference.CreateFromAssembly(typeof(object).Assembly);
var ws = new AdhocWorkspace();
//Create new solution
var solId = SolutionId.CreateNewId();
var solutionInfo = SolutionInfo.Create(solId, VersionStamp.Create());
//Create new project
var project = ws.AddProject("Sample", "C#");
project = project.AddMetadataReference(mscorlib);
//Add project to workspace
ws.TryApplyChanges(project.Solution);
string text = @"
class C
{
    void M()
    {
        M();
        M();
    }
}";
var sourceText = SourceText.From(text);
//Create new document
var doc = ws.AddDocument(project.Id, "NewDoc", sourceText);
//Get the semantic model
var model = doc.GetSemanticModelAsync().Result;
//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;
like image 96
JoshVarty Avatar answered Nov 13 '22 17:11

JoshVarty


A journal of problems, and eventual fixes, I had getting Roslyn to work with VS2017:

The reason for empty VS2017 projects becomes visible when the MSBuildWorkspace WorkspaceFailed event is hooked into.

The first round of failures was:

MSB0001: Internal MSBuild Error: Type information for Microsoft.Build.Utilities.ToolLocationHelper was present in the whitelist cache as Microsoft.Build.Utilities.ToolLocationHelper, Microsoft.Build.Utilities.Core, Version=15.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a but the type could not be loaded. unexpectedly null])

This was fixed by installing NuGet packages Microsoft.Build.Locator 1.1.2 & Microsoft.Build.Utilities.Core 15.9.20

The second round of failures was:

Msbuild failed when processing the file 'C:\Users...vbproj' with message: C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\MSBuild\15.0\Bin\Microsoft.Common.CurrentVersion.targets: (1491, 5): The "Microsoft.Build.Tasks.AssignProjectConfiguration" task could not be loaded from the assembly Microsoft.Build.Tasks.Core, Version=15.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a. Could not load file or assembly 'Microsoft.Build.Tasks.Core, Version=15.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. The system cannot find the file specified. Confirm that the declaration is correct, that the assembly and all its dependencies are available, and that the task contains a public class that implements Microsoft.Build.Framework.ITask.])

This was fixed by adding NuGet Microsoft.Build.Tasks.Core 15.9.20

The third round of failures was: === Msbuild failed when processing the file 'C:\Users...vbproj' with message: C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\MSBuild\15.0\Bin\Microsoft.Common.CurrentVersion.targets: (1657, 5): The "GetReferenceNearestTargetFrameworkTask" task could not be instantiated from the assembly "C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\Common7\IDE\CommonExtensions\Microsoft\NuGet\NuGet.Build.Tasks.dll". Please verify the task assembly has been built using the same version of the Microsoft.Build.Framework assembly as the one installed on your computer and that your host application is not missing a binding redirect for Microsoft.Build.Framework. Unable to cast object of type 'NuGet.Build.Tasks.GetReferenceNearestTargetFrameworkTask' to type 'Microsoft.Build.Framework.ITask'.])

Note that the project's Microsoft.Build.Framework.dll = 15.1.0.0 but the message mentions "MSBuild\15.0\Bin"

Adding to app.config - fixed it! cf enter link description here I can now load projects from VS2017 solutions

  <!-- vvv Roslyn manual fixup https://github.com/Microsoft/msbuild/issues/2369 -->
  <dependentAssembly>
    <assemblyIdentity name="Microsoft.Build.Framework" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
    <bindingRedirect oldVersion="0.0.0.0-15.1.0.0" newVersion="15.1.0.0" />
  </dependentAssembly>
  <dependentAssembly>
    <assemblyIdentity name="Microsoft.Build" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
    <bindingRedirect oldVersion="0.0.0.0-15.1.0.0" newVersion="15.1.0.0" />
  </dependentAssembly>
  <dependentAssembly>
    <assemblyIdentity name="Microsoft.Build.Utilities.Core" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
    <bindingRedirect oldVersion="0.0.0.0-15.1.0.0" newVersion="15.1.0.0" />
  </dependentAssembly>
  <dependentAssembly>
    <assemblyIdentity name="Microsoft.Build.Tasks.Core" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
    <bindingRedirect oldVersion="0.0.0.0-15.1.0.0" newVersion="15.1.0.0" />
  </dependentAssembly>
  <!-- ^^^ Roslyn manual fixup https://github.com/Microsoft/msbuild/issues/2369 -->
like image 23
brewmanz Avatar answered Nov 13 '22 17:11

brewmanz