How do I create a new root by adding and removing nodes retrieved from the old root?

前端 未结 2 1471
南笙
南笙 2020-12-09 05:21

I am creating a Code Fix that changes this:

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

into this:

var caste         


        
相关标签:
2条回答
  • 2020-12-09 05:44

    I have managed to do something very similar in the following manner. I extract the while condition and move it before the while and replace the condition with a new node. In the body of while, I add a new statement. In your case, instead of adding a statement, you will remove the desired statement from the body.

    Start at

    Refactor(BlockSyntax oldBody)
    

    STEP 1: I first visit and mark the nodes that I want to change and at the same time generate new nodes, but don't add the new ones yet.

    STEP 2: Track the marked nodes and replace with new ones.

    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;
            }
    
        }
    
    0 讨论(0)
  • 2020-12-09 06:00

    Have you looked at the DocumentEditor class ? It is very useful when dealing with modifying syntax, especially when the changes that are applied to the tree might cause invalidation problems. The operations are pretty much the same as the ones you already have defined, just use the DocumentEditor methods instead and see if that helps. I can't verify if that solves your problem ATM, but I think it solved the a similar problem for me once in the past. I'll test it out later if I can.

    Something like this will do it:

    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();
    
    0 讨论(0)
提交回复
热议问题