2015-06-23 88 views
1

我正在使用Roslyn語法樹來更新if/else語句。這裏是我的代碼:Roslyn IfStatement

foreach (StatementSyntax statement in blockNode.Statements) 
{ 
    if (statement.IsKind(SyntaxKind.IfStatement)) 
    { 
     BlockSyntax ifBlock = statement.ChildNodes().OfType<BlockSyntax>().FirstOrDefault(); 
     if (ifBlock != null) 
     { 
      ReturnStatementSyntax newRSS = ifBlock.ChildNodes().OfType<ReturnStatementSyntax>().FirstOrDefault(); 
      blockNode = blockNode.InsertNodesBefore(newRSS, newExitCode); 
     } 
     ElseClauseSyntax elseBlock = statement.ChildNodes().OfType<ElseClauseSyntax>().FirstOrDefault(); 
     if (elseBlock != null) 
     { 
      BlockSyntax block = elseBlock.ChildNodes().OfType<BlockSyntax>().FirstOrDefault(); 
      if (block != null) 
      { 
       ReturnStatementSyntax newRSS = block.ChildNodes().OfType<ReturnStatementSyntax>().FirstOrDefault(); 
       blockNode = blockNode.InsertNodesBefore(newRSS, newExitCode); 
      } 
     } 
     newBlock = newBlock.AddRange(blockNode.Statements); 
    } 
} 

任何人都可以解釋爲什麼第一個blockNode插入節點的作品,但第二個不?我看到了我要插入的代碼,但只有第一個更新語法樹。第二個什麼都不做。

更新:我做了JoshVarty建議的更改。我使用DocumentEditor來加載更改。當我調用GetChangedDocument時,我現在得到一個異常。這裏是我的代碼:

DocumentEditor editor = DocumentEditor.CreateAsync(doc).Result; 
editor.InsertBefore(blockNode, newEntryCode); 
editor.InsertAfter(blockNode, newExitCode); 
Document newDoc = editor.GetChangedDocument(); 

唯一的例外是:「System.InvalidOperationException」類型的異常出現在Microsoft.CodeAnalysis.CSharp.dll但在用戶代碼

其他信息沒有處理:指定的項目不是列表的元素。

我必須使用發生器嗎?我錯過了什麼?

感謝

回答

1

下面是我解決問題的方法。我使用SyntaxGenerator來重寫if語句,然後使用DocumentEditor在重寫某些方法時保留對語法樹的所有更改。以下是相關的代碼:

SyntaxGenerator synGen = editor.Generator; 
foreach (StatementSyntax statement in blockNode.Statements) 
{ 
    if (statement.IsKind(SyntaxKind.IfStatement)) 
    { 
     IfStatementSyntax ifs = statement as IfStatementSyntax; 
     SyntaxList<StatementSyntax> trueStatements = new SyntaxList<StatementSyntax>(); 
     SyntaxList<StatementSyntax> falseStatements = new SyntaxList<StatementSyntax>(); 

     BlockSyntax ifBlock = ifs.ChildNodes().OfType<BlockSyntax>().FirstOrDefault(); 
     if (ifBlock != null) 
     { 
      ReturnStatementSyntax newRSS = ifBlock.ChildNodes().OfType<ReturnStatementSyntax>().FirstOrDefault(); 
      SyntaxList<StatementSyntax> ifStatements = ifBlock.Statements; 
      foreach (StatementSyntax ss in ifStatements) 
      { 
       if (ss.Kind() != SyntaxKind.ReturnStatement) 
       { 
        trueStatements = trueStatements.Add(ss); 
       } 
      } 
      foreach (StatementSyntax ss in newExitCode) 
      { 
       trueStatements = trueStatements.Add(ss); 
      } 
      trueStatements = trueStatements.Add(newRSS); 
      ElseClauseSyntax elseBlock = ifs.ChildNodes().OfType<ElseClauseSyntax>().FirstOrDefault(); 
      if (elseBlock != null) 
      { 
       BlockSyntax block = elseBlock.ChildNodes().OfType<BlockSyntax>().FirstOrDefault(); 
       if (block != null) 
       { 
        ReturnStatementSyntax newRSS = block.ChildNodes().OfType<ReturnStatementSyntax>().FirstOrDefault(); 
        SyntaxList<StatementSyntax> elseStatements = block.Statements; 
        foreach (StatementSyntax ss in elseStatements) 
        { 
         if (ss.Kind() != SyntaxKind.ReturnStatement) 
         { 
          falseStatements = falseStatements.Add(ss); 
         } 
        } 
        foreach (StatementSyntax ss in newExitCode) 
        { 
         falseStatements = falseStatements.Add(ss); 
        } 
        falseStatements = falseStatements.Add(newRSS); 
       } 
      } 
      IfStatementSyntax newIfStatement = (IfStatementSyntax)synGen.IfStatement(ifs.Condition, trueStatements, falseStatements); 
      newBlock = newBlock.Add(newIfStatement); 
     } 
     else 
     { 
      if (!statement.IsKind(SyntaxKind.ReturnStatement)) 
      { 
       newBlock = newBlock.Add(statement); 
      } 
      else 
      { 
       newBlock = newBlock.AddRange(newExitCode); 
       newBlock = newBlock.Add(statement); 
      } 
     } 
    } 
} 
var newBody = SyntaxFactory.Block(SyntaxFactory.Token(SyntaxKind.OpenBraceToken), newBlock, SyntaxFactory.Token(SyntaxKind.CloseBraceToken)); 
var newMethod = SyntaxFactory.MethodDeclaration(mds.AttributeLists, mds.Modifiers, mds.ReturnType, mds.ExplicitInterfaceSpecifier, mds.Identifier, mds.TypeParameterList, mds.ParameterList, mds.ConstraintClauses, newBody, mds.ExpressionBody); 
editor.ReplaceNode(mds, newMethod); 
SyntaxNode newRoot = editor.GetChangedRoot(); 
var newFormattedRoot = Formatter.Format(newRoot, Workspace); 
Document newDoc = editor.GetChangedDocument(); 
doc = doc.WithSyntaxRoot(newFormattedRoot); 
methodsChanged++; 

感謝Josh Varty和Jeroen Vannevel爲他們提供的幫助。

6

我相信這裏的問題是,你從statement創建一個新的樹,然後嘗試使用新樹的部分來比較statement之後。

基本上這條線沒有做任何事情,第二次左右:

blockNode = blockNode.InsertNodesBefore(newRSS, newExitCode); 

blockNode是你已經創建了一個全新的樹,不包含newRSS。所以它找不到newRss並插入你的newExitCode

  • newRssblock
  • blockelseBlock
  • elseBlock是從原來的statement

有嘗試多次更改一次應用於語法樹時,你有三種選擇:

  1. 使用DocumentEditor - 請參閱:https://stackoverflow.com/a/30563669/300908
  2. 使用Annotations(行235和239)
  3. 使用.TrackNodes()

我的理解是DocumentEditor是最簡單的選項,並採取跟蹤護理/註釋節點爲你在封面下。

+1

另一種選擇是明確使用重寫器,並執行單個自底向上重寫通過。 –