使用Roslyn查找方法的所有引用

30

我希望扫描一组 .cs 文件,查找哪些文件调用了 Nullable<T> 类型的 Value 属性(查找所有引用)。例如,以下代码将匹配:

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

我了解了Roslyn并查看了一些示例,但其中许多示例已经过时,而且API非常庞大。我该怎么做呢?

在解析语法树后,我卡住了。目前为止,这就是我的代码:

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

    tree./* ??? What goes here? */
}

2
你需要一个语义模型,它来自于编译。 - SLaks
请问CSharpSyntaxTree在哪个程序集中找到? - Colonel Panic
@Colonel Panic,CSharpSyntaxTree位于Microsoft.CodeAnalysis.CSharp程序集中。 - Anssssss
2个回答

58

你可能正在寻找 SymbolFinder 类以及特别是FindAllReferences 方法。

看起来你在使用Roslyn方面遇到了一些困难。我写了一系列博客帮助人们介绍Roslyn,称为Learn Roslyn Now

如@SLaks所提到的,你需要访问语义模型,在我写的第七部分:介绍语义模型中进行了探讨。

以下是一个示例,展示了如何使用API。如果可以的话,我建议使用MSBuildWorkspace并从磁盘加载项目,而不是像这样在AdHocWorkspace中创建它。

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;

使用MSBuildWorkspace(2.10.0.0)从磁盘加载项目的问题在于,它将VS2017(自15.3.2以来,至少到15.9.7)作为空项目加载。如https://developercommunity.visualstudio.com/content/problem/102157/roslyn-broken-after-upgrading-to-vs2017-1532.html中所述,这个问题已被标记为“非错误”。 - brewmanz

4

我在将Roslyn与VS2017配合使用时遇到的问题及解决方法的日志:

为什么空的VS2017项目变得可见是因为MSBuildWorkspace WorkspaceFailed事件被钩入了。

第一轮失败是:

MSB0001:内部MSBuild错误:Microsoft.Build.Utilities.ToolLocationHelper的类型信息在白名单缓存中存在,例如Microsoft.Build.Utilities.ToolLocationHelper,Microsoft.Build.Utilities.Core,Version = 15.1.0.0,Culture = neutral,PublicKeyToken = b03f5f7f11d50a3a ,但无法加载该类型。意外为空])

通过安装NuGet包Microsoft.Build.Locator 1.1.2和Microsoft.Build.Utilities.Core 15.9.20来解决此问题

第二轮失败是:

Msbuild在处理文件'C:\ Users ... vbproj'时失败,消息如下: C:\ Program Files(x86)\ Microsoft Visual Studio \ 2017 \ Enterprise \ MSBuild \ 15.0 \ Bin \ Microsoft.Common.CurrentVersion.targets:(1491,5): 任务“Microsoft.Build.Tasks.AssignProjectConfiguration”无法从程序集Microsoft.Build.Tasks.Core、Version=15.1.0.0、Culture=neutral、PublicKeyToken=b03f5f7f11d50a3a中加载。 无法加载文件或程序集'Microsoft.Build.Tasks.Core、Version=15.1.0.0、Culture=neutral、PublicKeyToken=b03f5f7f11d50a3a'或它的某个依赖项。 系统找不到指定的文件。请确认声明正确,程序集及其所有依赖项可用,并且任务包含实现Microsoft.Build.Framework.ITask的公共类。])

通过添加NuGet Microsoft.Build.Tasks.Core 15.9.20来解决此问题

第三轮失败是: === Msbuild在处理文件'C:\ Users ... vbproj'时失败,消息如下: C:\ Program Files(x86)\ Microsoft Visual Studio \ 2017 \ Enterprise \ MSBuild \ 15.0 \ Bin \ Microsoft.Common.CurrentVersion.targets:(1657,5): 无法从程序集“C:\ Program Files(x86)\ Microsoft Visual Studio \ 2017 \ Enterprise \ Common7 \ IDE \ CommonExtensions \ Microsoft \ NuGet \ NuGet.Build.Tasks.dll”实例化“GetReferenceNearestTargetFrameworkTask”任务。 请验证任务程序集是使用与计算机上安装的Microsoft.Build.Framework程序集相同的版本构建的, 并且您的主机应用程序没有缺少Microsoft.Build.Framework的绑定重定向。 无法将类型为'NuGet.Build.Tasks.GetReferenceNearestTargetFrameworkTask'的对象转换为类型'Microsoft.Build.Framework.ITask'。)

请注意项目的Microsoft.Build.Framework.dll = 15.1.0.0但消息提到了“MSBuild \ 15.0 \ Bin”

添加到app.config - 解决了!cf 链接在此 我现在可以从VS2017解决方案中加载项目。

  <!-- 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 -->

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接