2015-05-31 15 views
11

Io sono la creazione di un Fix codice che cambia in questo modo:Come posso creare una nuova radice aggiungendo e rimuovendo i nodi recuperati dalla vecchia radice?

if(obj is MyClass) 
{ 
    var castedObj = obj as MyClass; 
} 

in questo:

var castedObj = obj as MyClass; 
if(castedObj != null) 
{ 
} 

Questo significa che devo fare 3 cose:

  • cambiare la condizione in if dichiarazione.
  • Spostare il cast direttamente sopra l'istruzione if.
  • Rimuovi l'istruzione nel corpo.

Finora, tutti i miei tentativi mi hanno impedito di sfruttare al massimo 2 di queste cose.

Credo che questo problema si verifichi perché fondamentalmente si hanno 2 nodi di sintassi allo stesso livello. In quanto tale, la modifica di uno di essi invalida la posizione dell'altro. O qualcosa di simile. Per farla breve: riesco a copiare l'assegnazione della variabile al di fuori dell'istruzione if o riesco a modificare la condizione + rimuovere l'assegnazione della variabile. Mai tutto 3.

Come risolverei questo?

Per buona misura, qui è il mio codice, che cambia la condizione e rimuove l'assegnazione:

var newIfStatement = ifStatement.RemoveNode(
            variableDeclaration, 
            SyntaxRemoveOptions.KeepExteriorTrivia); 
newIfStatement = newIfStatement.ReplaceNode(newIfStatement.Condition, newCondition); 

var ifParent = ifStatement.Parent; 
var newParent = ifParent.ReplaceNode(ifStatement, newIfStatement); 
newParent = newParent.InsertNodesBefore(
          newIfStatement, 
          new[] { variableDeclaration }) 
          .WithAdditionalAnnotations(Formatter.Annotation); 

var newRoot = root.ReplaceNode(ifParent, newParent); 

risposta

14

hai guardato la classe DocumentEditor? È molto utile quando si ha a che fare con la modifica della sintassi, specialmente quando le modifiche applicate all'albero possono causare problemi di invalidazione. Le operazioni sono praticamente le stesse che hai già definito, usa invece i metodi DocumentEditor e vedi se questo aiuta. Non riesco a verificare se questo risolva il tuo problema ATM, ma penso che abbia risolto un problema simile per me una volta in passato. Lo metterò alla prova più tardi, se posso.

Qualcosa di simile lo farà:

var editor = await DocumentEditor.CreateAsync(document); 
editor.RemoveNode(variableDeclaration); 
editor.ReplaceNode(ifStatement.Condition, newCondition); 
editor.InsertBefore(ifStatement, 
    new[] { variableDeclaration.WithAdditionalAnnotations(Formatter.Annotation) }); 

var newDocument = editor.GetChangedDocument(); 
+2

Vorrei averlo saputo prima di questa lezione: nessuna scocciatura con nodi immutabili non funzionanti. Solo poche righe di codice per sostituire tutto quanto sopra e si legge in modo molto scorrevole. Modificherò la tua risposta per includere il codice che ho usato per essere completo. –

0

sono riuscito a fare qualcosa di molto simile nel modo seguente. Estraggo la condizione while e la sposto prima del tempo e sostituisco la condizione con un nuovo nodo. Nel frattempo, aggiungo una nuova dichiarazione. Nel tuo caso, invece di aggiungere un'istruzione, rimuovi l'istruzione desiderata dal corpo.

Inizia dai

Refactor(BlockSyntax oldBody) 

FASE 1: ho prima visita e segnare i nodi che voglio cambiare e allo stesso tempo generare nuovi nodi, ma non aggiungo ancora quelli nuovi.

PASSO 2: Monitorare i nodi contrassegnati e sostituirli con nuovi.

class WhileConditionRefactoringVisitor : CSharpSyntaxRewriter 
{ 
    private static int CONDITION_COUNTER = 0; 
    private static string CONDITION_VAR = "whileCondition_"; 

    private static string ConditionIdentifier 
    { 
     get { return CONDITION_VAR + CONDITION_COUNTER++; } 
    } 

    private readonly List<SyntaxNode> markedNodes = new List<SyntaxNode>(); 

    private readonly List<Tuple<ExpressionSyntax, IdentifierNameSyntax, StatementSyntax, WhileStatementSyntax>> replacementNodes = 
     new List<Tuple<ExpressionSyntax, IdentifierNameSyntax, StatementSyntax, WhileStatementSyntax>>(); 


     //STEP 1 
     public override SyntaxNode VisitWhileStatement(WhileStatementSyntax node) 
    { 
     var nodeVisited = (WhileStatementSyntax) base.VisitWhileStatement(node); 

     var condition = nodeVisited.Condition; 
     if (condition.Kind() == SyntaxKind.IdentifierName) 
      return nodeVisited; 


     string conditionVarIdentifier = ConditionIdentifier; 
     var newConditionVar = SyntaxFactoryExtensions.GenerateLocalVariableDeclaration(conditionVarIdentifier, 
      condition, SyntaxKind.BoolKeyword).NormalizeWhitespace().WithTriviaFrom(nodeVisited); 
     var newCondition = SyntaxFactory.IdentifierName(conditionVarIdentifier).WithTriviaFrom(condition); 

     markedNodes.Add(condition); 
     markedNodes.Add(node); 
     replacementNodes.Add(new Tuple<ExpressionSyntax, IdentifierNameSyntax, StatementSyntax, WhileStatementSyntax>(condition, newCondition, newConditionVar, node)); 

     return nodeVisited; 
    } 

     //STEP 2 
     private BlockSyntax ReplaceNodes(BlockSyntax oldBody) 
    { 
     oldBody = oldBody.TrackNodes(this.markedNodes); 
     foreach (var tuple in this.replacementNodes) 
     { 
      var currentA = oldBody.GetCurrentNode(tuple.Item1); 
      if (currentA != null) 
      { 
       var whileStatement = currentA.Parent; 
       oldBody = oldBody.InsertNodesBefore(whileStatement, new List<SyntaxNode>() { tuple.Item3 }); 
       var currentB = oldBody.GetCurrentNode(tuple.Item1); 
       oldBody = oldBody.ReplaceNode(currentB, tuple.Item2); 
       var currentWhile = oldBody.GetCurrentNode(tuple.Item4); 
       //modify body 
       var whileBody = currentWhile.Statement as BlockSyntax; 
       //create new statement 
       var localCondition = tuple.Item3 as LocalDeclarationStatementSyntax; 
       var initializer = localCondition.Declaration.Variables.First(); 
       var assignment = SyntaxFactory.ExpressionStatement(SyntaxFactory.AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, 
        SyntaxFactory.IdentifierName(initializer.Identifier), initializer.Initializer.Value)); 
       var newStatements = whileBody.Statements.Add(assignment); 
       whileBody = whileBody.WithStatements(newStatements); 
       //updateWhile 
       var newWhile = currentWhile.WithStatement(whileBody); 
       oldBody = oldBody.ReplaceNode(currentWhile, newWhile); 
      } 
     } 
     return oldBody; 
    } 

     public BlockSyntax Refactor(BlockSyntax oldBody) 
     { 
      markedNodes.Clear(); 
      replacementNodes.Clear(); 
      //STEP 1 
      oldBody = (BlockSyntax)this.Visit(oldBody); 
      //STEP 2 
      oldBody = this.ReplaceNodes(oldBody); 

      return oldBody; 
     } 

    }