如何通过添加和删除从旧根检索到的节点来创建新根?
How do I create a new root by adding and removing nodes retrieved from the old root?
我正在创建一个代码修复来改变这个:
if(obj is MyClass)
{
var castedObj = obj as MyClass;
}
进入这个:
var castedObj = obj as MyClass;
if(castedObj != null)
{
}
这意味着我必须做 3 件事:
- 更改
if
语句中的条件。
- 将转换移到
if
语句的正上方。
- 删除正文中的声明。
到目前为止,我的所有尝试都让我最多只能让其中的 2 个东西起作用。
我认为出现此问题是因为您基本上在同一级别上有 2 个语法节点。因此,对其中一个进行更改会使另一个的位置无效。或类似的东西。长话短说:我要么设法在 if
语句之外复制变量赋值,要么设法更改条件 + 删除变量赋值。从来没有全部 3.
我该如何解决这个问题?
为了更好地衡量,这是我的代码,它更改了条件并删除了分配:
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);
你看过 DocumentEditor
class 了吗?这在处理修改语法时非常有用,尤其是当应用于树的更改可能导致失效问题时。这些操作与您已经定义的操作几乎相同,只需改用 DocumentEditor
方法,看看是否有帮助。我无法验证这是否解决了您的 ATM 问题,但我认为它曾经为我解决过类似的问题。可以的话我稍后再测试一下。
像这样就可以了:
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();
我已经设法通过以下方式做了一些非常相似的事情。
我提取 while 条件并将其移动到 while 之前,并用新节点替换该条件。
在 while 的正文中,我添加了一条新语句。
在您的情况下,不是添加语句,而是从正文中删除所需的语句。
开始于
Refactor(BlockSyntax oldBody)
STEP 1:我首先访问并标记我要更改的节点,同时生成新节点,但还没有添加新节点。
第 2 步:跟踪标记的节点并替换为新节点。
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;
}
}
我正在创建一个代码修复来改变这个:
if(obj is MyClass)
{
var castedObj = obj as MyClass;
}
进入这个:
var castedObj = obj as MyClass;
if(castedObj != null)
{
}
这意味着我必须做 3 件事:
- 更改
if
语句中的条件。 - 将转换移到
if
语句的正上方。 - 删除正文中的声明。
到目前为止,我的所有尝试都让我最多只能让其中的 2 个东西起作用。
我认为出现此问题是因为您基本上在同一级别上有 2 个语法节点。因此,对其中一个进行更改会使另一个的位置无效。或类似的东西。长话短说:我要么设法在 if
语句之外复制变量赋值,要么设法更改条件 + 删除变量赋值。从来没有全部 3.
我该如何解决这个问题?
为了更好地衡量,这是我的代码,它更改了条件并删除了分配:
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);
你看过 DocumentEditor
class 了吗?这在处理修改语法时非常有用,尤其是当应用于树的更改可能导致失效问题时。这些操作与您已经定义的操作几乎相同,只需改用 DocumentEditor
方法,看看是否有帮助。我无法验证这是否解决了您的 ATM 问题,但我认为它曾经为我解决过类似的问题。可以的话我稍后再测试一下。
像这样就可以了:
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();
我已经设法通过以下方式做了一些非常相似的事情。 我提取 while 条件并将其移动到 while 之前,并用新节点替换该条件。 在 while 的正文中,我添加了一条新语句。 在您的情况下,不是添加语句,而是从正文中删除所需的语句。
开始于
Refactor(BlockSyntax oldBody)
STEP 1:我首先访问并标记我要更改的节点,同时生成新节点,但还没有添加新节点。
第 2 步:跟踪标记的节点并替换为新节点。
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;
}
}