Skip to content

Commit 7d06001

Browse files
committed
Revert "[internal] Move RectorNodeTraverser logic up to AbstractImmutableNodeTraverser (rectorphp#7827)"
This reverts commit 1e75743.
1 parent 9460a2c commit 7d06001

3 files changed

Lines changed: 124 additions & 90 deletions

File tree

phpstan.neon

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ includes:
55
parameters:
66
level: 8
77

8-
reportUnmatchedIgnoredErrors: false
8+
# reportUnmatchedIgnoredErrors: false
99

1010
errorFormat: symplify
1111

@@ -373,6 +373,9 @@ parameters:
373373
- '#Method Rector\\Utils\\Rector\\RemoveRefactorDuplicatedNodeInstanceCheckRector\:\:getInstanceofNodeClass\(\) should return class\-string<PhpParser\\Node>\|null but returns class\-string#'
374374

375375
# copied from /vendor, to keep as original as possible
376+
-
377+
identifier: missingType.iterableValue
378+
path: src/PhpParser/NodeTraverser/AbstractImmutableNodeTraverser.php
376379
-
377380
identifier: symplify.noDynamicName
378381
path: src/PhpParser/NodeTraverser/AbstractImmutableNodeTraverser.php

src/PhpParser/NodeTraverser/AbstractImmutableNodeTraverser.php

Lines changed: 13 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,7 @@
1010
use PhpParser\Node\Stmt;
1111
use PhpParser\NodeTraverserInterface;
1212
use PhpParser\NodeVisitor;
13-
use Rector\Configuration\ConfigurationRuleFilter;
14-
use Rector\Contract\Rector\RectorInterface;
1513
use Rector\Exception\ShouldNotHappenException;
16-
use Rector\PhpParser\Node\CustomNode\FileWithoutNamespace;
17-
use Rector\PhpParser\Node\FileNode;
18-
use Rector\VersionBonding\PhpVersionedFilter;
19-
use Webmozart\Assert\Assert;
2014

2115
abstract class AbstractImmutableNodeTraverser implements NodeTraverserInterface
2216
{
@@ -30,21 +24,14 @@ abstract class AbstractImmutableNodeTraverser implements NodeTraverserInterface
3024
*/
3125
protected bool $stopTraversal;
3226

33-
private bool $areNodeVisitorsPrepared = false;
34-
3527
/**
36-
* @var array<class-string<Node>, NodeVisitor[]>
37-
*/
38-
private array $visitorsPerNodeClass = [];
39-
40-
/**
41-
* @param RectorInterface[] $rectors
28+
* Create a traverser with the given visitors.
29+
*
30+
* @param NodeVisitor ...$visitors Node visitors
4231
*/
43-
public function __construct(
44-
private readonly PhpVersionedFilter $phpVersionedFilter,
45-
private readonly ConfigurationRuleFilter $configurationRuleFilter,
46-
private array $rectors
47-
) {
32+
public function __construct(NodeVisitor ...$visitors)
33+
{
34+
$this->visitors = $visitors;
4835
}
4936

5037
public function addVisitor(NodeVisitor $visitor): void
@@ -58,13 +45,14 @@ public function removeVisitor(NodeVisitor $visitor): void
5845
}
5946

6047
/**
61-
* @param Node[] $nodes
62-
* @return Node[]
48+
* Traverses an array of nodes using the registered visitors.
49+
*
50+
* @param Node[] $nodes Array of nodes
51+
*
52+
* @return Node[] Traversed array of nodes
6353
*/
6454
public function traverse(array $nodes): array
6555
{
66-
$this->prepareNodeVisitors();
67-
6856
$this->stopTraversal = false;
6957
foreach ($this->visitors as $visitor) {
7058
if (null !== $return = $visitor->beforeTraverse($nodes)) {
@@ -83,54 +71,10 @@ public function traverse(array $nodes): array
8371
return $nodes;
8472
}
8573

86-
/**
87-
* @param RectorInterface[] $rectors
88-
* @api used in tests to update the active rules
89-
*
90-
* @internal Used only in Rector core, not supported outside. Might change any time.
91-
*/
92-
public function refreshPhpRectors(array $rectors): void
93-
{
94-
Assert::allIsInstanceOf($rectors, RectorInterface::class);
95-
96-
$this->rectors = $rectors;
97-
$this->visitors = [];
98-
$this->visitorsPerNodeClass = [];
99-
100-
$this->areNodeVisitorsPrepared = false;
101-
102-
$this->prepareNodeVisitors();
103-
}
104-
10574
/**
10675
* @return NodeVisitor[]
10776
*/
108-
public function getVisitorsForNode(Node $node): array
109-
{
110-
$nodeClass = $node::class;
111-
112-
if (! isset($this->visitorsPerNodeClass[$nodeClass])) {
113-
$this->visitorsPerNodeClass[$nodeClass] = [];
114-
115-
/** @var RectorInterface $visitor */
116-
foreach ($this->visitors as $visitor) {
117-
foreach ($visitor->getNodeTypes() as $nodeType) {
118-
// BC layer matching
119-
if ($nodeType === FileWithoutNamespace::class && $nodeClass === FileNode::class) {
120-
$this->visitorsPerNodeClass[$nodeClass][] = $visitor;
121-
continue;
122-
}
123-
124-
if (is_a($nodeClass, $nodeType, true)) {
125-
$this->visitorsPerNodeClass[$nodeClass][] = $visitor;
126-
continue 2;
127-
}
128-
}
129-
}
130-
}
131-
132-
return $this->visitorsPerNodeClass[$nodeClass];
133-
}
77+
abstract public function getVisitorsForNode(Node $node): array;
13478

13579
protected function traverseNode(Node $node): void
13680
{
@@ -195,7 +139,7 @@ protected function traverseNode(Node $node): void
195139

196140
/**
197141
* @param Node[] $nodes
198-
* @return Node[]
142+
* @return array Result of traversal (may be original array or changed one)
199143
*/
200144
protected function traverseArray(array $nodes): array
201145
{
@@ -289,24 +233,4 @@ private function ensureReplacementReasonable(Node $old, Node $new): void
289233
);
290234
}
291235
}
292-
293-
/**
294-
* This must happen after $this->configuration is set after ProcessCommand::execute() is run, otherwise we get default false positives.
295-
*
296-
* This should be removed after https://github.com/rectorphp/rector/issues/5584 is resolved
297-
*/
298-
private function prepareNodeVisitors(): void
299-
{
300-
if ($this->areNodeVisitorsPrepared) {
301-
return;
302-
}
303-
304-
// filer out by version
305-
$this->visitors = $this->phpVersionedFilter->filter($this->rectors);
306-
307-
// filter by configuration
308-
$this->visitors = $this->configurationRuleFilter->filter($this->visitors);
309-
310-
$this->areNodeVisitorsPrepared = true;
311-
}
312236
}

src/PhpParser/NodeTraverser/RectorNodeTraverser.php

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,116 @@
44

55
namespace Rector\PhpParser\NodeTraverser;
66

7+
use PhpParser\Node;
8+
use PhpParser\Node\Stmt;
9+
use PhpParser\NodeVisitor;
10+
use Rector\Configuration\ConfigurationRuleFilter;
11+
use Rector\Contract\Rector\RectorInterface;
12+
use Rector\PhpParser\Node\CustomNode\FileWithoutNamespace;
13+
use Rector\PhpParser\Node\FileNode;
14+
use Rector\VersionBonding\PhpVersionedFilter;
15+
use Webmozart\Assert\Assert;
16+
717
/**
818
* @see \Rector\Tests\PhpParser\NodeTraverser\RectorNodeTraverserTest
919
*/
1020
final class RectorNodeTraverser extends AbstractImmutableNodeTraverser
1121
{
22+
private bool $areNodeVisitorsPrepared = false;
23+
24+
/**
25+
* @var array<class-string<Node>, NodeVisitor[]>
26+
*/
27+
private array $visitorsPerNodeClass = [];
28+
29+
/**
30+
* @param RectorInterface[] $rectors
31+
*/
32+
public function __construct(
33+
private array $rectors,
34+
private readonly PhpVersionedFilter $phpVersionedFilter,
35+
private readonly ConfigurationRuleFilter $configurationRuleFilter,
36+
) {
37+
parent::__construct();
38+
}
39+
40+
/**
41+
* @param Stmt[] $nodes
42+
* @return Stmt[]
43+
*/
44+
public function traverse(array $nodes): array
45+
{
46+
$this->prepareNodeVisitors();
47+
48+
return parent::traverse($nodes);
49+
}
50+
51+
/**
52+
* @param RectorInterface[] $rectors
53+
* @api used in tests to update the active rules
54+
*
55+
* @internal Used only in Rector core, not supported outside. Might change any time.
56+
*/
57+
public function refreshPhpRectors(array $rectors): void
58+
{
59+
Assert::allIsInstanceOf($rectors, RectorInterface::class);
60+
61+
$this->rectors = $rectors;
62+
$this->visitors = [];
63+
$this->visitorsPerNodeClass = [];
64+
65+
$this->areNodeVisitorsPrepared = false;
66+
67+
$this->prepareNodeVisitors();
68+
}
69+
70+
/**
71+
* @return NodeVisitor[]
72+
*/
73+
public function getVisitorsForNode(Node $node): array
74+
{
75+
$nodeClass = $node::class;
76+
77+
if (! isset($this->visitorsPerNodeClass[$nodeClass])) {
78+
$this->visitorsPerNodeClass[$nodeClass] = [];
79+
80+
/** @var RectorInterface $visitor */
81+
foreach ($this->visitors as $visitor) {
82+
foreach ($visitor->getNodeTypes() as $nodeType) {
83+
// BC layer matching
84+
if ($nodeType === FileWithoutNamespace::class && $nodeClass === FileNode::class) {
85+
$this->visitorsPerNodeClass[$nodeClass][] = $visitor;
86+
continue;
87+
}
88+
89+
if (is_a($nodeClass, $nodeType, true)) {
90+
$this->visitorsPerNodeClass[$nodeClass][] = $visitor;
91+
continue 2;
92+
}
93+
}
94+
}
95+
}
96+
97+
return $this->visitorsPerNodeClass[$nodeClass];
98+
}
99+
100+
/**
101+
* This must happen after $this->configuration is set after ProcessCommand::execute() is run, otherwise we get default false positives.
102+
*
103+
* This should be removed after https://github.com/rectorphp/rector/issues/5584 is resolved
104+
*/
105+
private function prepareNodeVisitors(): void
106+
{
107+
if ($this->areNodeVisitorsPrepared) {
108+
return;
109+
}
110+
111+
// filer out by version
112+
$this->visitors = $this->phpVersionedFilter->filter($this->rectors);
113+
114+
// filter by configuration
115+
$this->visitors = $this->configurationRuleFilter->filter($this->visitors);
116+
117+
$this->areNodeVisitorsPrepared = true;
118+
}
12119
}

0 commit comments

Comments
 (0)