拥有 IMethodSymbol 是否有可能在 Roslyn 中从该方法中找出所有方法和字段 used/called?
Having IMethodSymbol is it possible in Roslyn to figure out all the methods and fields used/called from within that method?
我有 IMethodSymbol
对象,我想从该方法中找出所有方法和字段 used/called。
我已经用 Mono.Cecil 做了。然而,这还不够好,因为任何涉及动态类型的代码都只是反射。因此,检查二进制代码在这里没有用 - 我们必须检查源代码。
因此,我知道使用动态参数的方法的 IMethodSymbol
(它调用 Binder.InvokeMember
)。我知道源代码分析可以告诉我正在调用什么方法。
我熟悉 SymbolFinder
class 并且能够使用它的 FindReferencesAsync
方法。但是我不知道如何将它用于我的目的,即给定方法找到它使用的所有符号。
我错过了什么?
编辑 1
所以我想出了如何获得顶级操作:
var op = model.GetOperation(method.DeclaringSyntaxReferences[0].GetSyntax());
其中 model
是各自的 SemanticModel
实例,method
是我的 IMethodSymbol
。但是确实有无数种 IOperation
。我需要一种方便的方式来导航它们。我想 OperationWalker
是我需要的。会继续探索。
我找到了路 - OperationWalker
。
就我而言,我有以下“助行器”(进行中):
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Operations;
using System;
using System.Collections.Generic;
namespace CSTool
{
public class DynamicOperationWalker : OperationWalker
{
public readonly List<IMethodSymbol> Result = new();
public readonly List<(SyntaxNode,string)> Unresolved = new();
public override void VisitDynamicIndexerAccess(IDynamicIndexerAccessOperation operation)
{
throw new NotImplementedException();
}
public override void VisitDynamicInvocation(IDynamicInvocationOperation operation)
{
var memberReferenceOp = (IDynamicMemberReferenceOperation)operation.Operation;
switch (memberReferenceOp.Instance.Type)
{
case INamedTypeSymbol type:
{
var memberName = memberReferenceOp.MemberName;
var members = type.GetMembers(memberName);
if (members.Length > 1)
{
throw new NotImplementedException();
}
Result.Add((IMethodSymbol)members[0]);
break;
}
case IDynamicTypeSymbol dynamicType:
Unresolved.Add((operation.Syntax, memberReferenceOp.MemberName));
break;
}
}
public override void VisitDynamicMemberReference(IDynamicMemberReferenceOperation operation)
{
throw new NotImplementedException();
}
public override void VisitDynamicObjectCreation(IDynamicObjectCreationOperation operation)
{
throw new NotImplementedException();
}
}
}
我这样调用它是为了检查 methodSymbol
:
给出的方法的主体
var op = model.GetOperation(methodSymbol.DeclaringSyntaxReferences[0].GetSyntax());
var walker = new DynamicOperationWalker();
walker.Visit(op);
我只对动态调用感兴趣,因为非动态调用是 Mono.Cecil
给我的。
我有 IMethodSymbol
对象,我想从该方法中找出所有方法和字段 used/called。
我已经用 Mono.Cecil 做了。然而,这还不够好,因为任何涉及动态类型的代码都只是反射。因此,检查二进制代码在这里没有用 - 我们必须检查源代码。
因此,我知道使用动态参数的方法的 IMethodSymbol
(它调用 Binder.InvokeMember
)。我知道源代码分析可以告诉我正在调用什么方法。
我熟悉 SymbolFinder
class 并且能够使用它的 FindReferencesAsync
方法。但是我不知道如何将它用于我的目的,即给定方法找到它使用的所有符号。
我错过了什么?
编辑 1
所以我想出了如何获得顶级操作:
var op = model.GetOperation(method.DeclaringSyntaxReferences[0].GetSyntax());
其中 model
是各自的 SemanticModel
实例,method
是我的 IMethodSymbol
。但是确实有无数种 IOperation
。我需要一种方便的方式来导航它们。我想 OperationWalker
是我需要的。会继续探索。
我找到了路 - OperationWalker
。
就我而言,我有以下“助行器”(进行中):
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Operations;
using System;
using System.Collections.Generic;
namespace CSTool
{
public class DynamicOperationWalker : OperationWalker
{
public readonly List<IMethodSymbol> Result = new();
public readonly List<(SyntaxNode,string)> Unresolved = new();
public override void VisitDynamicIndexerAccess(IDynamicIndexerAccessOperation operation)
{
throw new NotImplementedException();
}
public override void VisitDynamicInvocation(IDynamicInvocationOperation operation)
{
var memberReferenceOp = (IDynamicMemberReferenceOperation)operation.Operation;
switch (memberReferenceOp.Instance.Type)
{
case INamedTypeSymbol type:
{
var memberName = memberReferenceOp.MemberName;
var members = type.GetMembers(memberName);
if (members.Length > 1)
{
throw new NotImplementedException();
}
Result.Add((IMethodSymbol)members[0]);
break;
}
case IDynamicTypeSymbol dynamicType:
Unresolved.Add((operation.Syntax, memberReferenceOp.MemberName));
break;
}
}
public override void VisitDynamicMemberReference(IDynamicMemberReferenceOperation operation)
{
throw new NotImplementedException();
}
public override void VisitDynamicObjectCreation(IDynamicObjectCreationOperation operation)
{
throw new NotImplementedException();
}
}
}
我这样调用它是为了检查 methodSymbol
:
var op = model.GetOperation(methodSymbol.DeclaringSyntaxReferences[0].GetSyntax());
var walker = new DynamicOperationWalker();
walker.Visit(op);
我只对动态调用感兴趣,因为非动态调用是 Mono.Cecil
给我的。