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

问题描述 投票:0回答:1

我正在尝试在 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

无需转换即可工作如果我不执行转换并使用旧的

SemanticModel
,则符号已成功检索!

我做错了什么?

c# .net abstract-syntax-tree roslyn
1个回答
0
投票

这是一个迟到的答案,但我希望它对某人有用。根据我的经验,如果用

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;
}

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

© www.soinside.com 2019 - 2024. All rights reserved.