修改语法树,然后获取更新的语义模型

时间:2012-08-28 17:51:21

标签: c# roslyn

我正在尝试修改语法树,然后更新语义模型。以下是我到目前为止的情况:

var tree = Roslyn.Compilers.CSharp.SyntaxTree.ParseCompilationUnit(code);
var compilation = Roslyn.Compilers.CSharp.Compilation.Create(
                        "MyCompilation",
                        syntaxTrees: new[] { tree },
                        references: new[] { mscorlib });
var semanticModel = compilation.GetSemanticModel(tree);
...
var oldStatementNode = (parent as ExpressionStatementSyntax); //some SyntaxNode in the tree
var oldExpressionNode = oldStatementNode.Expression;
var newExpressionNode = Syntax.ParenthesizedExpression(oldExpressionNode);
var newRootNode = tree.GetRoot().ReplaceNode(oldExpressionNode, newExpressionNode);

var semanticInfo = semanticModel.GetTypeInfo(newExpressionNode); //throws exception "Syntax node is not within syntax tree"

如果我在调用semanticModel = compilation.GetSemanticModel(tree);之前尝试调用tree或甚至使用GetTypeInfo()进行新编译 - 同样的例外。

那么如何更新SemanticModel? (当然我可以修改源代码并从头开始做所有事情,但我想有更有效的方法)。

我遗漏了一些显而易见的东西我敢肯定,或许在某处创建了一个新的语法树?

1 个答案:

答案 0 :(得分:15)

Roslyn类型是不可变的,因此您需要为SyntaxTree构建一个新的newRootNode,然后调用compilation.UpdateSyntaxTree以获取新的Compilation,然后您就可以了致电newCompilation.GetSemanticModel(newTree)以获取新的SemanticModel

考虑升级到服务级别并改为使用ISolution。类似的东西:

var doc = Solution.Create(SolutionId.CreateNewId()).AddCSharpProject("MyCompilation", "MyCompilation").AddMetadataReference(mscorlib).AddDocument("MyFile", code);

var semanticModel = (SemanticModel)doc.GetSemanticModel();
var root = (CompilationUnitSyntax)doc.GetSyntaxRoot();

SyntaxNode parent = null;
var oldStatementNode = (parent as ExpressionStatementSyntax); //some SyntaxNode in the tree
var oldExpressionNode = oldStatementNode.Expression;
var newExpressionNode = Syntax.ParenthesizedExpression(oldExpressionNode);
var newRootNode = root.ReplaceNode(oldExpressionNode, newExpressionNode);

doc = doc.UpdateSyntaxRoot(newRootNode);
semanticModel = (SemanticModel)doc.GetSemanticModel();