【问题标题】:How do I get a IMethodSymbol or the syntax node of the method declaration from a InvocationExpressionSyntax node which calls the method?如何从调用方法的 InvocationExpressionSyntax 节点获取 IMethodSymbol 或方法声明的语法节点?
【发布时间】:2017-06-29 19:16:29
【问题描述】:

在我的分析器的实现中,我使用AnalyzeSymbol 方法:

public override void Initialize(AnalysisContext context)
{
  context.RegisterSymbolAction(AnalyzeSymbol, SymbolKind.Method);
}

private static void AnalyzeSymbol(SymbolAnalysisContext context)
{
  // here I look through the syntax of the method body in order to find invocations.
  var methodSymbol = context.Symbol as IMethodSymbol;
  var location = methodSymbol.Locations.FirstOrDefault();
  var methodNode = location.SourceTree.GetCompilationUnitRoot().FindNode(locati‌​on.SourceSpan);
  var blockNode = methodNode.ChildNodes().FirstOrDefault(s => s is BlockSyntax);
  var invocations = blockNode.DescendantNodes()
    .Select(s => s as InvocationExpressionSyntax)
    .Where(s => s != null)

  foreach(InvocationExpressionSyntax i in invocations i)
  {
    // look at the signature of the method which is invoked
    // in order to figure out if the arguments are attributed
  }
}

对于我找到的每个InvocationExpressionSyntax 节点,我需要检查在调用调用的声明方法的签名中声明参数的属性(即我的[ReadOnly] 属性,参见here)。据我了解,我需要以某种方式从InvocationExpressionSyntax 对象到相应的IMethodSymbol,但我不知道如何。不像FieldDeclarationSyntax,它有一个属性Declarations,通过它我得到一个IFieldSymbol,就像发布的here一样,InvocationExpressionSyntax没有,我尝试的以下代码为该符号产生null:

var model = context.Compilation.GetSemanticModel(ies.SyntaxTree);
var symbol = model.GetDeclaredSymbol(ies.Expression);

我做错了什么?

我的分析器应该分析的示例代码是:

void Foo()
{
  int i = 42;

  // coming from this InvocationExpressionSyntax node I want to find out that i is an parameter for an argument which has an [ReadOnly] attribute
  Bar(i);

  // coming from this InvocationExpressionSyntax node I want to find out that i is an parameter for an argument which has NOT an [ReadOnly] attribute
  Baz(i);
}

void Bar([ReadOnly] int i)
{
}

void Baz(int i)
{
}

【问题讨论】:

  • 你能举例说明InvocationExpressionSyntax是什么吗?你能不能解释一下为什么你需要一个符号,也许有一种方法可以不使用符号来做到这一点
  • @johnny5 查看我的编辑。我认为获得被调用方法的声明的语法节点也足够了。
  • 你知道调用是对方法的实际调用,属性不会在调用上,但会在方法声明本身上
  • 这就是为什么我需要声明方法的位置的语法节点。
  • 所以你实际上应该寻找 MethodDeclarationSyntax 而不是 InvocationDeclarationSyntax

标签: c# roslyn roslyn-code-analysis


【解决方案1】:

您可以使用SymbolFinder 获取InvocationExpressionSyntax 的声明符号

Workspace workspace;
Workspace.TryGetWorkspace(location.SourceTree.GetText().Container, out workspace);
if (workspace != null)
{
    var invocMethodSymbol = model.GetSymbolInfo(ies.Expression).Symbol;
    // Await this task if you can
    var declarationMethodSymbol = SymbolFinder.FindSourceDefinitionAsync(invocMethodSymbol, workspace.CurrentSolution).Result;
}

【讨论】:

  • 代码不会检查 ref 或 out 参数是否存在 [ReadOnly] 属性。它仅检查调用是否包含 ref 或 out 参数。
  • @David 我明白你想知道调用你的方法在声明中有[ReadOnly] 参数,而不是你将[ReadOnly] 参数传递给某个方法?
  • @David 我没有等待您的评论并编辑了答案。希望我正确理解了您的问题。所以请检查答案。
  • @GeorgeAlexandria 你可以这样获得工作空间吗?我必须反思以获取解决方案的选项
  • @johnny5 我知道有些情况下您无法以这种方式获得工作空间,例如,它并不总是适用于MSBuildWorkspace,我不知道为什么它不总是有效。但是,这种方式适用于我测试的RoslynVisualStudioWorkspace。所以最好的方法是在这段代码上方的某个地方获取解决方案并使用它
猜你喜欢
  • 1970-01-01
  • 2020-09-17
  • 2021-07-10
  • 1970-01-01
  • 1970-01-01
  • 2019-10-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多