Skip to content

Commit 45057d0

Browse files
Optimise checking the node types allowed for each rule
1 parent 1884cdd commit 45057d0

File tree

3 files changed

+90
-1
lines changed

3 files changed

+90
-1
lines changed

composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,8 @@
139139
"https://raw.githubusercontent.com/rectorphp/vendor-patches/main/patches/nikic-php-parser-lib-phpparser-node-stmt-if-php.patch",
140140
"https://raw.githubusercontent.com/rectorphp/vendor-patches/main/patches/nikic-php-parser-lib-phpparser-node-stmt-case-php.patch",
141141
"https://raw.githubusercontent.com/rectorphp/vendor-patches/main/patches/nikic-php-parser-lib-phpparser-node-stmt-elseif-php.patch",
142-
"https://raw.githubusercontent.com/rectorphp/vendor-patches/main/patches/nikic-php-parser-lib-phpparser-node-stmt-namespace-php.patch"
142+
"https://raw.githubusercontent.com/rectorphp/vendor-patches/main/patches/nikic-php-parser-lib-phpparser-node-stmt-namespace-php.patch",
143+
"patches/nikic-php-parser-lib-phpparser-nodetraverser-php.patch"
143144
]
144145
},
145146
"composer-exit-on-patch-failure": true,
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
--- /dev/null
2+
+++ ../lib/PhpParser/NodeTraverser.php
3+
@@ -119,7 +119,8 @@
4+
$traverseChildren = true;
5+
$breakVisitorIndex = null;
6+
7+
- foreach ($this->visitors as $visitorIndex => $visitor) {
8+
+ $visitors = $this->getVisitorsForNode($subNode);
9+
+ foreach ($visitors as $visitorIndex => $visitor) {
10+
$return = $visitor->enterNode($subNode);
11+
if (null !== $return) {
12+
if ($return instanceof Node) {
13+
@@ -149,7 +150,7 @@
14+
}
15+
}
16+
17+
- foreach ($this->visitors as $visitorIndex => $visitor) {
18+
+ foreach ($visitors as $visitorIndex => $visitor) {
19+
$return = $visitor->leaveNode($subNode);
20+
21+
if (null !== $return) {
22+
@@ -196,7 +197,8 @@
23+
$traverseChildren = true;
24+
$breakVisitorIndex = null;
25+
26+
- foreach ($this->visitors as $visitorIndex => $visitor) {
27+
+ $visitors = $this->getVisitorsForNode($node);
28+
+ foreach ($visitors as $visitorIndex => $visitor) {
29+
$return = $visitor->enterNode($node);
30+
if (null !== $return) {
31+
if ($return instanceof Node) {
32+
@@ -226,7 +228,7 @@
33+
}
34+
}
35+
36+
- foreach ($this->visitors as $visitorIndex => $visitor) {
37+
+ foreach ($visitors as $visitorIndex => $visitor) {
38+
$return = $visitor->leaveNode($node);
39+
40+
if (null !== $return) {
41+
@@ -270,6 +272,14 @@
42+
}
43+
44+
return $nodes;
45+
+ }
46+
+
47+
+ /**
48+
+ * @return NodeVisitor[]
49+
+ */
50+
+ protected function getVisitorsForNode(Node $node)
51+
+ {
52+
+ return $this->visitors;
53+
}
54+
55+
private function ensureReplacementReasonable($old, $new) {

src/PhpParser/NodeTraverser/RectorNodeTraverser.php

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,22 @@
44

55
namespace Rector\PhpParser\NodeTraverser;
66

7+
use PhpParser\Node;
78
use PhpParser\Node\Stmt;
89
use PhpParser\NodeTraverser;
10+
use PhpParser\NodeVisitor;
911
use Rector\Contract\Rector\RectorInterface;
1012
use Rector\VersionBonding\PhpVersionedFilter;
1113

1214
final class RectorNodeTraverser extends NodeTraverser
1315
{
1416
private bool $areNodeVisitorsPrepared = false;
1517

18+
/**
19+
* @var array<class-string<Node>,RectorInterface[]>
20+
*/
21+
private array $visitorsPerNodeClass;
22+
1623
/**
1724
* @param RectorInterface[] $rectors
1825
*/
@@ -46,6 +53,31 @@ public function refreshPhpRectors(array $rectors): void
4653
$this->areNodeVisitorsPrepared = false;
4754
}
4855

56+
/**
57+
* We return the list of visitors (rector rules) that can be applied to each node class
58+
* This list is cached so that we don't need to continually check if a rule can be applied to a node
59+
*
60+
* @return NodeVisitor[]
61+
*/
62+
protected function getVisitorsForNode(Node $node): array
63+
{
64+
$nodeClass = $node::class;
65+
if (! isset($this->visitorsPerNodeClass[$nodeClass])) {
66+
$this->visitorsPerNodeClass[$nodeClass] = [];
67+
foreach ($this->visitors as $visitor) {
68+
assert($visitor instanceof RectorInterface);
69+
foreach ($visitor->getNodeTypes() as $nodeType) {
70+
if (is_a($nodeClass, $nodeType, true)) {
71+
$this->visitorsPerNodeClass[$nodeClass][] = $visitor;
72+
break;
73+
}
74+
}
75+
}
76+
}
77+
78+
return $this->visitorsPerNodeClass[$nodeClass];
79+
}
80+
4981
/**
5082
* This must happen after $this->configuration is set after ProcessCommand::execute() is run,
5183
* otherwise we get default false positives.
@@ -60,6 +92,7 @@ private function prepareNodeVisitors(): void
6092

6193
// filer out by version
6294
$this->visitors = $this->phpVersionedFilter->filter($this->rectors);
95+
$this->visitorsPerNodeClass = [];
6396
$this->areNodeVisitorsPrepared = true;
6497
}
6598
}

0 commit comments

Comments
 (0)