Support REMOVE_NODE from enterNode()

This commit is contained in:
Nikita Popov 2022-09-03 18:15:36 +02:00
parent a44faa6328
commit c42290ae42
3 changed files with 43 additions and 2 deletions

View File

@ -201,6 +201,9 @@ class NodeTraverser implements NodeTraverserInterface {
if ($return instanceof Node) {
$this->ensureReplacementReasonable($node, $return);
$node = $return;
} else if (self::REMOVE_NODE === $return) {
$doNodes[] = [$i, []];
continue 2;
} elseif (self::DONT_TRAVERSE_CHILDREN === $return) {
$traverseChildren = false;
} elseif (self::DONT_TRAVERSE_CURRENT_AND_CHILDREN === $return) {

View File

@ -22,8 +22,13 @@ interface NodeVisitor {
* Return value semantics:
* * null
* => $node stays as-is
* * NodeTraverser::REMOVE_NODE
* => $node is removed from the parent array
* * NodeTraverser::DONT_TRAVERSE_CHILDREN
* => Children of $node are not traversed. $node stays as-is
* * NodeTraverser::DONT_TRAVERSE_CURRENT_AND_CHILDREN
* => Further visitors for the current node are skipped, and its children are not
* traversed. $node stays as-is.
* * NodeTraverser::STOP_TRAVERSAL
* => Traversal is aborted. $node stays as-is
* * otherwise

View File

@ -61,18 +61,51 @@ class NodeTraverserTest extends \PHPUnit\Framework\TestCase {
], $visitor2->trace);
}
public function testRemove() {
public function testRemoveFromLeave() {
$str1Node = new String_('Foo');
$str2Node = new String_('Bar');
$visitor = new NodeVisitorForTesting([
['leaveNode', $str1Node, NodeTraverser::REMOVE_NODE],
]);
$visitor2 = new NodeVisitorForTesting();
$traverser = new NodeTraverser();
$traverser->addVisitor($visitor);
$traverser->addVisitor($visitor2);
$this->assertEquals([$str2Node], $traverser->traverse([$str1Node, $str2Node]));
$stmts = [$str1Node, $str2Node];
$this->assertEquals([$str2Node], $traverser->traverse($stmts));
$this->assertEquals([
['beforeTraverse', $stmts],
['enterNode', $str1Node],
['enterNode', $str2Node],
['leaveNode', $str2Node],
['afterTraverse', [$str2Node]],
], $visitor2->trace);
}
public function testRemoveFromEnter() {
$str1Node = new String_('Foo');
$str2Node = new String_('Bar');
$visitor = new NodeVisitorForTesting([
['enterNode', $str1Node, NodeTraverser::REMOVE_NODE],
]);
$visitor2 = new NodeVisitorForTesting();
$traverser = new NodeTraverser();
$traverser->addVisitor($visitor);
$traverser->addVisitor($visitor2);
$stmts = [$str1Node, $str2Node];
$this->assertEquals([$str2Node], $traverser->traverse($stmts));
$this->assertEquals([
['beforeTraverse', $stmts],
['enterNode', $str2Node],
['leaveNode', $str2Node],
['afterTraverse', [$str2Node]],
], $visitor2->trace);
}
public function testMerge() {