我正在使用Roslyn并试图构建一个分析器,该分析器将遍历方法的整个源(包括所有子方法),以便为用户提供洞察力。
我不知道如何进入MemberAccessExpression(指向方法),以便我可以开始浏览包含该方法的文件。
我尝试遍历ChildNodes
和ChildTokens
,也查看了调试器中的对象,但没有看到可用于加载MemberAccessExpression的类/方法的属性。指。
遍历树找到我感兴趣的探索方法后,我将执行以下操作:
private void AnalyzeSyntaxNode(SyntaxNode syntaxNode)
{
if (this.foundMethod)
{
return;
}
if (syntaxNode is InvocationExpressionSyntax invocationExpressionSyntax)
{
this.foundMethod = true;
PrintNodeAndChildren(invocationExpressionSyntax);
}
var children = syntaxNode.ChildNodes();
foreach (var child in children)
{
AnalyzeSyntaxNode(child);
}
}
private void PrintNodeAndChildren(SyntaxNode node)
{
Console.WriteLine($"Child: {node}");
var children = node.ChildNodes();
if (children.Any())
{
foreach (var child in children)
{
PrintNodeAndChildren(child);
}
}
}
我想访问包含该方法的类以及该方法本身的主体。
在下面的示例中,我开始遍历Caller
的语法树,并且我想访问Callee.DoSomethingElse
的正文。实际上,我的目标是将_visited = true
中的_visited = 99
替换为Callee.DoSomethingElse
,但是,如果我能弄清楚如何访问树的那部分,我感觉好像可以替换自己。
public class Caller
{
private Callee _callee = new Callee();
public void DoSomething()
{
_callee.DoSomethingElse();
}
}
public class Callee
{
private int _visited = 0;
public void DoSomethingElse()
{
_visited = 1;
}
}
这是一个任意的,荒谬的例子,但我觉得似乎可以理解。
答案 0 :(得分:0)
事实证明,为此使用的正确类是CSharpSyntaxRewriter
,是CSharpSyntaxVisitor
的子类,可以大大简化语法树的导航。
它在功能上与CSharpSyntaxVisitor
相同,但是允许修改语法节点。
这是我对此类的实现:
public class AssignmentReplacer : CSharpSyntaxRewriter
{
private string inMethod;
public override SyntaxNode VisitMethodDeclaration(MethodDeclarationSyntax node)
{
inMethod = node.Identifier.ValueText;
return base.VisitMethodDeclaration(node);
}
public override SyntaxNode VisitAssignmentExpression(AssignmentExpressionSyntax node)
{
if (inMethod == "DoSomethingElse")
{
if (node.Left is IdentifierNameSyntax name &&
name.Identifier.Text == "_visited")
{
return node.Update(node.Left,
node.OperatorToken,
SyntaxFactory.LiteralExpression(SyntaxKind.TrueLiteralExpression));
}
}
return base.VisitAssignmentExpression(node);
}
}
在深度优先的情况下,它会在私有字段中从VisitMethodDeclaration
跟踪其当前方法的位置。它使用VisitAssignmentExpression
中的值来确保修改节点时采用正确的方法。
一旦在正确的方法内标识了一个AssignmentExpressionSyntax
节点,它将创建该节点的修改后的副本,并在右侧将其更改为新的LiteralExpression
。
您可能必须对此进行更多检查,以确保您正在修改正确的节点,但这适用于简单的示例数据。
您可以使用此类:
var programText =
@"public class Callee
{
private bool _visited = false;
public void DoSomethingElse()
{
_visited = false;
}
}";
var tree = CSharpSyntaxTree.ParseText(programText);
var root = tree.GetRoot();
var visitor = new AssignmentReplacer();
var updated = visitor.Visit(root);
运行访问者后,updated
将包含修改后的代码:
public class Callee { private bool _visited = true; public void DoSomethingElse() { _visited = true; } }
提醒一下,这是我第一次这样做,因此它可能不是最有效或最佳的方法。
谢谢你一个有趣的挑战!
可以here找到完整的LINQPad示例。