Skip to content

Commit 843ad10

Browse files
committed
[int] merge AbstractImmutableNodeTraverser and RectorNodeTraverser as sole child and tight design
1 parent 2b641d4 commit 843ad10

3 files changed

Lines changed: 19 additions & 7 deletions

File tree

phpstan.neon

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,7 @@ parameters:
376376
-
377377
identifier: symplify.noDynamicName
378378
path: src/PhpParser/NodeTraverser/RectorNodeTraverser.php
379+
379380
-
380381
identifier: offsetAccess.nonArray
381382
path: src/PhpParser/NodeTraverser/RectorNodeTraverser.php

src/PhpParser/NodeTraverser/RectorNodeTraverser.php

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,12 @@
1919
use Webmozart\Assert\Assert;
2020

2121
/**
22+
* Based on native NodeTraverser class, but heavily customized for Rector needs.
23+
*
24+
* The main differences are:
25+
* - no leaveNode(), as we do all in enterNode() that calls refactor() method
26+
* - cached visitors per node class for performance, e.g. when we find rules for Class_ node, they're cached for next time
27+
* - immutability features, register Rector rules once, then use; no changes on the fly
2228
* @see \Rector\Tests\PhpParser\NodeTraverser\RectorNodeTraverserTest
2329
*/
2430
final class RectorNodeTraverser implements NodeTraverserInterface
@@ -33,7 +39,7 @@ final class RectorNodeTraverser implements NodeTraverserInterface
3339
private bool $areNodeVisitorsPrepared = false;
3440

3541
/**
36-
* @var array<class-string<Node>, NodeVisitor[]>
42+
* @var array<class-string<Node>, RectorInterface[]>
3743
*/
3844
private array $visitorsPerNodeClass = [];
3945

@@ -103,26 +109,30 @@ public function refreshPhpRectors(array $rectors): void
103109
}
104110

105111
/**
106-
* @return NodeVisitor[]
112+
* @api used in tests
113+
* @return RectorInterface[]
107114
*/
108115
public function getVisitorsForNode(Node $node): array
109116
{
110117
$nodeClass = $node::class;
111118

119+
if (! $this->areNodeVisitorsPrepared) {
120+
$this->prepareNodeVisitors();
121+
}
122+
112123
if (! isset($this->visitorsPerNodeClass[$nodeClass])) {
113124
$this->visitorsPerNodeClass[$nodeClass] = [];
114125

115-
/** @var RectorInterface $visitor */
116-
foreach ($this->visitors as $visitor) {
117-
foreach ($visitor->getNodeTypes() as $nodeType) {
126+
foreach ($this->rectors as $rector) {
127+
foreach ($rector->getNodeTypes() as $nodeType) {
118128
// BC layer matching
119129
if ($nodeType === FileWithoutNamespace::class && $nodeClass === FileNode::class) {
120-
$this->visitorsPerNodeClass[$nodeClass][] = $visitor;
130+
$this->visitorsPerNodeClass[$nodeClass][] = $rector;
121131
continue;
122132
}
123133

124134
if (is_a($nodeClass, $nodeType, true)) {
125-
$this->visitorsPerNodeClass[$nodeClass][] = $visitor;
135+
$this->visitorsPerNodeClass[$nodeClass][] = $rector;
126136
continue 2;
127137
}
128138
}

tests/PhpParser/NodeTraverser/RectorNodeTraverserTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ public function testGetVisitorsForNodeWhenNoVisitorsMatch(): void
5858
public function testGetVisitorsForNodeWhenSomeVisitorsMatch(): void
5959
{
6060
$class = new Class_('test');
61+
6162
$this->rectorNodeTraverser->refreshPhpRectors([
6263
$this->ruleUsingFunctionRector,
6364
$this->ruleUsingClassRector,

0 commit comments

Comments
 (0)