.net 如何在更改SyntaxTree后更新Roslyn中的SemanticModel?

zdwk9cvp  于 2023-08-08  发布在  .NET
关注(0)|答案(1)|浏览(111)

我正在尝试在Roslyn中执行语法转换。AST重排工作正常,但是,由于我正在更改内容,我需要获得更新的SemanticModel,以反映我的SyntaxTree的新结构。

转化树

这部分工作,我可以告诉,因为我做了大量的调试。

CSharpSyntaxTree tree = RetrieveTree(); // Just successfully gets the original tree
CSharpCompilation compilation = CSharpCompilation.Create(...); // Retrieves the compilation object

CompilationUnitSyntax node = tree.GetRoot();

// Doing stuff to change the tree
node = node.RemoveNodes(...);
node = node.AddMembers(...);

字符串
我可以得到新的树:

CSharpSyntaxTree newTree = node.SyntaxTree as CSharpSyntaxTree;


通过调试,我可以看到newTree具有新的结构,而tree具有旧的结构。我也可以成功地遍历newTree并在AST上操作。所以改造是成功的。

更新树和语义

我认为问题从这里开始当我试图更新CSharpCompilation和当我得到SemanticModel了。

CSharpCompilation newCompilation = compilation.ReplaceSyntaxTree(tree, newTree);
SemanticModel newSemanticModel = newCompilation.GetSemanticModel(newTree);


因为当我尝试:

TypeSyntax myClassTypeNode = GetSourceCodeClassTypeNode(); // Just successfully gets a node
var symbol = newSemanticModel.getSymbolInfo(myClassTypeNode).Symbol;


symbol为null。当然,如果我尝试使用原始的SemanticModel,它也会保持为null

不转换也可以如果我不执行转换,使用旧的SemanticModel,符号被成功检索!

我做错了什么?

xjreopfe

xjreopfe1#

这是一个迟来的答案,但我希望它对某人有用。根据我的经验,如果在用SyntaxNode.ReplaceNode替换节点并用CompilationReplaceSyntaxTree更新编译后,无法从语义模型中获取符号,这是因为在替换节点时引入了错误。当插入使用SyntaxFactory API创建的节点时,很容易引入细微的错误,这些节点只是看起来正确(但实际上并不正确),因为一些类似的节点发出相同的代码,并且替换函数将非常宽松,只是为了在稍后的语义分析中发现错误。我发现的一个技巧是使用以下扩展方法测试编译错误:

public static List<string> GetCompilationErrors(this Compilation compilation)
{
    var diagnostics = compilation.GetDiagnostics()
        .Where(d => d.Severity == DiagnosticSeverity.Error)
        .Select(d => $"{d.Location}, {d.Id}: {d.GetMessage()}")
        .ToList();
    return diagnostics;
}

字符串
假设树操作在语义上是正确的,如果用上述函数没有检测到错误,则语义模型应该产生预期的结果。

相关问题