55namespace Rector \Renaming \Rector \Name ;
66
77use PhpParser \Node ;
8- use PhpParser \Node \Expr \ClassConstFetch ;
98use PhpParser \Node \FunctionLike ;
10- use PhpParser \Node \Identifier ;
119use PhpParser \Node \Name ;
1210use PhpParser \Node \Name \FullyQualified ;
1311use PhpParser \Node \Stmt \ClassLike ;
1412use PhpParser \Node \Stmt \Expression ;
1513use PhpParser \Node \Stmt \If_ ;
1614use PhpParser \Node \Stmt \Property ;
17- use PhpParser \NodeVisitor ;
1815use PHPStan \Reflection \ReflectionProvider ;
1916use Rector \Configuration \RenamedClassesDataCollector ;
2017use 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,23 @@ 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
139142 foreach ($ oldToNewClasses as $ oldClass => $ newClass ) {
140- if (! $ this ->isName ($ classConstFetch -> class , $ oldClass )) {
143+ if (! $ this ->isName ($ fullyQualified , $ oldClass )) {
141144 continue ;
142145 }
143146
@@ -146,20 +149,14 @@ private function processClassConstFetch(ClassConstFetch $classConstFetch, array
146149 }
147150
148151 $ classReflection = $ this ->reflectionProvider ->getClass ($ newClass );
149- if (! $ classReflection ->isInterface ()) {
150- continue ;
151- }
152-
153152 $ oldClassReflection = $ this ->reflectionProvider ->getClass ($ oldClass );
154153
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 ;
154+ if ($ oldClassReflection ->hasConstant ($ constFetchName ) && ! $ classReflection ->hasConstant ($ constFetchName )) {
155+ // should be skipped as new class does not have access to the constant
156+ return true ;
159157 }
160158 }
161159
162- // continue to next Name usage
163- return null ;
160+ return false ;
164161 }
165162}
0 commit comments