44
55namespace Rector \CodingStyle \Rector \Enum_ ;
66
7+ use PHPStan \Reflection \ClassReflection ;
78use PhpParser \Node ;
89use PhpParser \Node \Expr \ClassConstFetch ;
910use PhpParser \Node \Identifier ;
1011use PhpParser \Node \Name ;
1112use PhpParser \Node \Stmt \Enum_ ;
1213use PhpParser \Node \Stmt \EnumCase ;
13- use PHPStan \BetterReflection \Reflection \ReflectionEnum ;
14- use PHPStan \BetterReflection \Reflector \DefaultReflector ;
15- use PHPStan \BetterReflection \Reflector \Exception \IdentifierNotFound ;
16- use PHPStan \Reflection \ReflectionProvider ;
1714use Rector \Configuration \Option ;
1815use Rector \Configuration \Parameter \SimpleParameterProvider ;
19- use Rector \NodeTypeResolver \Reflection \BetterReflection \SourceLocatorProvider \DynamicSourceLocatorProvider ;
2016use Rector \Rector \AbstractRector ;
2117use Rector \Skipper \FileSystem \PathNormalizer ;
2218use Symplify \RuleDocGenerator \ValueObject \CodeSample \CodeSample ;
2723 */
2824final class EnumCaseToPascalCaseRector extends AbstractRector
2925{
30- public function __construct (
31- private readonly ReflectionProvider $ reflectionProvider ,
32- private readonly DynamicSourceLocatorProvider $ dynamicSourceLocatorProvider ,
33- ) {
34- }
35-
3626 public function getRuleDefinition (): RuleDefinition
3727 {
3828 return new RuleDefinition (
@@ -122,43 +112,40 @@ private function refactorClassConstFetch(ClassConstFetch $classConstFetch): ?Nod
122112 return null ;
123113 }
124114
125- if ($ this ->nodeTypeResolver ->getType ($ classConstFetch ->class )->isEnum ()->no ()) {
126- return null ;
127- }
128-
129115 $ constName = $ classConstFetch ->name ->toString ();
116+ $ pascalCaseName = $ this ->convertToPascalCase ($ constName );
130117
131- // Skip "class" constant
132- if ($ constName === ' class ' ) {
118+ // short circuit if already in pascal case
119+ if ($ constName === $ pascalCaseName ) {
133120 return null ;
134121 }
135122
136- $ enumClassName = $ classConstFetch ->class ->toString ();
137- if (! $ this ->reflectionProvider ->hasClass ($ enumClassName )) {
123+ $ classReflection = $ this ->nodeTypeResolver ->getType ($ classConstFetch ->class )
124+ ->getObjectClassReflections ()[0 ] ?? null ;
125+
126+ if ($ classReflection === null || ! $ classReflection ->isEnum ()) {
138127 return null ;
139128 }
140129
141- $ sourceLocator = $ this ->dynamicSourceLocatorProvider ->provide ();
142- $ defaultReflector = new DefaultReflector ($ sourceLocator );
143-
144- try {
145- $ classIdentifier = $ defaultReflector ->reflectClass ($ classConstFetch ->class ->toString ());
146- } catch (IdentifierNotFound ) {
147- // source is outside the paths defined in withPaths(), eg: vendor
130+ if (! $ this ->isEnumCase ($ classReflection , $ constName , $ pascalCaseName )) {
148131 return null ;
149132 }
150133
151- // ensure exactly ReflectionEnum
152- if (! $ classIdentifier instanceof ReflectionEnum) {
134+ if ($ this ->isUsedOutsideOfProject ($ classReflection )) {
153135 return null ;
154136 }
155137
156- // ensure not part of definition in ->withAutoloadPaths()
157- $ fileTarget = $ classIdentifier ->getFileName ();
138+ $ classConstFetch ->name = new Identifier ($ pascalCaseName );
139+ return $ classConstFetch ;
140+ }
141+
142+ private function isUsedOutsideOfProject (ClassReflection $ classReflection ): bool
143+ {
144+ $ fileTarget = $ classReflection ->getFileName ();
158145
159146 // possibly native
160147 if ($ fileTarget === null ) {
161- return null ;
148+ return true ;
162149 }
163150
164151 $ autoloadPaths = SimpleParameterProvider::provideArrayParameter (Option::AUTOLOAD_PATHS );
@@ -168,21 +155,21 @@ private function refactorClassConstFetch(ClassConstFetch $classConstFetch): ?Nod
168155 $ normalizedAutoloadPath = PathNormalizer::normalize ($ autoloadPath );
169156
170157 if ($ autoloadPath === $ fileTarget ) {
171- return null ;
158+ return true ;
172159 }
173160
174161 if (str_starts_with ($ normalizedFileTarget , $ normalizedAutoloadPath . '/ ' )) {
175- return null ;
162+ return true ;
176163 }
177164 }
178165
179- $ pascalCaseName = $ this ->convertToPascalCase ($ constName );
180- if ($ constName !== $ pascalCaseName ) {
181- $ classConstFetch ->name = new Identifier ($ pascalCaseName );
182- return $ classConstFetch ;
183- }
166+ return false ;
167+ }
184168
185- return null ;
169+ private function isEnumCase (ClassReflection $ classReflection , string $ name , string $ pascalName ): bool
170+ {
171+ // the enum case might have already been renamed, need to check both
172+ return $ classReflection ->hasEnumCase ($ name ) || $ classReflection ->hasEnumCase ($ pascalName );
186173 }
187174
188175 private function convertToPascalCase (string $ name ): string
0 commit comments