2012-08-28 64 views
7

我试图修改语法树,然后获取语义模型更新。以下是我迄今为止:修改语法树,然后获取更新的语义模型

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);甚至调用GetTypeInfo()之前做出新的编译与tree - 相同的异常。

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

我错过了一些明显的东西,我敢肯定,也许有一个新的语法树在某处创建?

回答

14

罗斯林类型是不可改变的,所以你需要建立一个新的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();