Skip to content

Commit dd29784

Browse files
committed
[cleanup] handle stop traverse in ClassConstFetchNodeVisitor
1 parent 90067ca commit dd29784

File tree

4 files changed

+70
-26
lines changed

4 files changed

+70
-26
lines changed

rules/Renaming/Rector/Name/RenameClassRector.php

Lines changed: 35 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,13 @@
55
namespace Rector\Renaming\Rector\Name;
66

77
use PhpParser\Node;
8-
use PhpParser\Node\Expr\ClassConstFetch;
98
use PhpParser\Node\FunctionLike;
10-
use PhpParser\Node\Identifier;
119
use PhpParser\Node\Name;
1210
use PhpParser\Node\Name\FullyQualified;
1311
use PhpParser\Node\Stmt\ClassLike;
1412
use PhpParser\Node\Stmt\Expression;
1513
use PhpParser\Node\Stmt\If_;
1614
use PhpParser\Node\Stmt\Property;
17-
use PhpParser\NodeVisitor;
1815
use PHPStan\Reflection\ReflectionProvider;
1916
use Rector\Configuration\RenamedClassesDataCollector;
2017
use Rector\Contract\Rector\ConfigurableRectorInterface;
@@ -80,7 +77,6 @@ function someFunction(SomeNewClass $someOldClass): SomeNewClass
8077
public function getNodeTypes(): array
8178
{
8279
return [
83-
ClassConstFetch::class,
8480
// place FullyQualified before Name on purpose executed early before the Name as parent
8581
FullyQualified::class,
8682
// Name as parent of FullyQualified executed later for fallback annotation to attribute rename to Name
@@ -94,19 +90,21 @@ public function getNodeTypes(): array
9490
}
9591

9692
/**
97-
* @param ClassConstFetch|FunctionLike|FullyQualified|Name|ClassLike|Expression|Property|If_ $node
98-
* @return null|NodeVisitor::DONT_TRAVERSE_CHILDREN|Node
93+
* @param FunctionLike|FullyQualified|Name|ClassLike|Expression|Property|If_ $node
9994
*/
100-
public function refactor(Node $node): int|null|Node
95+
public function refactor(Node $node): ?Node
10196
{
10297
$oldToNewClasses = $this->renamedClassesDataCollector->getOldToNewClasses();
10398

10499
if ($oldToNewClasses === []) {
105100
return null;
106101
}
107102

108-
if ($node instanceof ClassConstFetch) {
109-
return $this->processClassConstFetch($node, $oldToNewClasses);
103+
if ($node instanceof FullyQualified && $this->shouldSkipClassConstFetchForMissingConstantName(
104+
$node,
105+
$oldToNewClasses
106+
)) {
107+
return null;
110108
}
111109

112110
$scope = $node->getAttribute(AttributeKey::SCOPE);
@@ -126,18 +124,29 @@ public function configure(array $configuration): void
126124

127125
/**
128126
* @param array<string, string> $oldToNewClasses
129-
* @return null|NodeVisitor::DONT_TRAVERSE_CHILDREN
130127
*/
131-
private function processClassConstFetch(ClassConstFetch $classConstFetch, array $oldToNewClasses): int|null
132-
{
133-
if (! $classConstFetch->class instanceof FullyQualified
134-
|| ! $classConstFetch->name instanceof Identifier
135-
|| ! $this->reflectionProvider->hasClass($classConstFetch->class->toString())) {
136-
return null;
128+
private function shouldSkipClassConstFetchForMissingConstantName(
129+
FullyQualified $fullyQualified,
130+
array $oldToNewClasses
131+
): bool {
132+
if (! $this->reflectionProvider->hasClass($fullyQualified->toString())) {
133+
return false;
134+
}
135+
136+
// not part of class const fetch (e.g. SomeClass::SOME_VALUE)
137+
$constFetchName = $fullyQualified->getAttribute(AttributeKey::CLASS_CONST_FETCH_NAME);
138+
if (! is_string($constFetchName)) {
139+
return false;
137140
}
138141

142+
// if (! $classConstFetch->class instanceof FullyQualified
143+
// || ! $classConstFetch->name instanceof Identifier
144+
// || ! $this->reflectionProvider->hasClass($classConstFetch->class->toString())) {
145+
// return null;
146+
// }
147+
139148
foreach ($oldToNewClasses as $oldClass => $newClass) {
140-
if (! $this->isName($classConstFetch->class, $oldClass)) {
149+
if (! $this->isName($fullyQualified, $oldClass)) {
141150
continue;
142151
}
143152

@@ -146,20 +155,20 @@ private function processClassConstFetch(ClassConstFetch $classConstFetch, array
146155
}
147156

148157
$classReflection = $this->reflectionProvider->getClass($newClass);
149-
if (! $classReflection->isInterface()) {
150-
continue;
151-
}
158+
// if (! $classReflection->isInterface()) {
159+
// continue;
160+
// }
152161

153162
$oldClassReflection = $this->reflectionProvider->getClass($oldClass);
154163

155-
if ($oldClassReflection->hasConstant($classConstFetch->name->toString())
156-
&& ! $classReflection->hasConstant($classConstFetch->name->toString())) {
157-
// no constant found on new interface? skip node below ClassConstFetch on this rule
158-
return NodeVisitor::DONT_TRAVERSE_CHILDREN;
164+
if ($oldClassReflection->hasConstant($constFetchName) && ! $classReflection->hasConstant($constFetchName)) {
165+
// should be skipped
166+
return true;
159167
}
160168
}
161169

162-
// continue to next Name usage
163-
return null;
170+
return false;
171+
172+
// return $this->classRenamer->renameNode($fullyQualified, $oldToNewClasses, $scope);
164173
}
165174
}

src/DependencyInjection/LazyContainerFactory.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@
9999
use Rector\NodeTypeResolver\PHPStan\Scope\NodeVisitor\AssignedToNodeVisitor;
100100
use Rector\NodeTypeResolver\PHPStan\Scope\NodeVisitor\ByRefReturnNodeVisitor;
101101
use Rector\NodeTypeResolver\PHPStan\Scope\NodeVisitor\ByRefVariableNodeVisitor;
102+
use Rector\NodeTypeResolver\PHPStan\Scope\NodeVisitor\ClassConstFetchNodeVisitor;
102103
use Rector\NodeTypeResolver\PHPStan\Scope\NodeVisitor\ContextNodeVisitor;
103104
use Rector\NodeTypeResolver\PHPStan\Scope\NodeVisitor\GlobalVariableNodeVisitor;
104105
use Rector\NodeTypeResolver\PHPStan\Scope\NodeVisitor\NameNodeVisitor;
@@ -247,6 +248,7 @@ final class LazyContainerFactory
247248
NameNodeVisitor::class,
248249
StaticVariableNodeVisitor::class,
249250
PropertyOrClassConstDefaultNodeVisitor::class,
251+
ClassConstFetchNodeVisitor::class,
250252
];
251253

252254
/**

src/NodeTypeResolver/Node/AttributeKey.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,4 +294,6 @@ final class AttributeKey
294294
public const IS_INSIDE_SYMFONY_PHP_CLOSURE = 'is_inside_symfony_php_closure';
295295

296296
public const IS_INSIDE_BYREF_FUNCTION_LIKE = 'is_inside_byref_function_like';
297+
298+
public const CLASS_CONST_FETCH_NAME = 'class_const_fetch_name';
297299
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Rector\NodeTypeResolver\PHPStan\Scope\NodeVisitor;
6+
7+
use PhpParser\Node;
8+
use PhpParser\Node\Expr\ClassConstFetch;
9+
use PhpParser\Node\Identifier;
10+
use PhpParser\NodeVisitorAbstract;
11+
use Rector\Contract\PhpParser\DecoratingNodeVisitorInterface;
12+
use Rector\NodeTypeResolver\Node\AttributeKey;
13+
14+
final class ClassConstFetchNodeVisitor extends NodeVisitorAbstract implements DecoratingNodeVisitorInterface
15+
{
16+
public function enterNode(Node $node): ?Node
17+
{
18+
if (! $node instanceof ClassConstFetch) {
19+
return null;
20+
}
21+
22+
// pass value metadata to class node
23+
if (! $node->name instanceof Identifier) {
24+
return null;
25+
}
26+
27+
$node->class->setAttribute(AttributeKey::CLASS_CONST_FETCH_NAME, $node->name->toString());
28+
29+
return null;
30+
}
31+
}

0 commit comments

Comments
 (0)