Skip to content

Commit 2de6166

Browse files
committed
fix: EnumCaseToPascalCaseRector bugs
1 parent 77b0f25 commit 2de6166

File tree

8 files changed

+76
-80
lines changed

8 files changed

+76
-80
lines changed
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
namespace Rector\Tests\CodingStyle\Rector\Enum_\EnumCaseToPascalCaseRector\Fixture;
4+
5+
enum CaseOnSelf
6+
{
7+
case PENDING;
8+
9+
function isPending(): bool
10+
{
11+
return $this === self::PENDING;
12+
}
13+
}
14+
15+
?>
16+
-----
17+
<?php
18+
19+
namespace Rector\Tests\CodingStyle\Rector\Enum_\EnumCaseToPascalCaseRector\Fixture;
20+
21+
enum CaseOnSelf
22+
{
23+
case Pending;
24+
25+
function isPending(): bool
26+
{
27+
return $this === self::Pending;
28+
}
29+
}
30+
31+
?>
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?php
2+
3+
namespace Rector\Tests\CodingStyle\Rector\Enum_\EnumCaseToPascalCaseRector\Fixture;
4+
5+
enum SkipEnumConst
6+
{
7+
const FOO = 'foo';
8+
9+
case Pending;
10+
11+
function test(): void
12+
{
13+
echo self::FOO;
14+
}
15+
}

rules-tests/CodingStyle/Rector/Enum_/EnumCaseToPascalCaseRector/Fixture/skip_enum_usage_in_other_package.php.inc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
namespace Rector\Tests\CodingStyle\Rector\Enum_\EnumCaseToPascalCaseRector\Fixture;
44

5-
use Rector\Tests\CodingStyle\Rector\Enum_\EnumCaseToPascalCaseRector\Source\StatusEnum;
5+
use Rector\Tests\CodingStyle\Rector\Enum_\EnumCaseToPascalCaseRector\Source\Autoload\StatusEnum;
66

77
class SkipEnumUsageInOtherPackage {
88
public function isValid(StatusEnum $status): bool {

rules-tests/CodingStyle/Rector/Enum_/EnumCaseToPascalCaseRector/Source/StatusEnum.php renamed to rules-tests/CodingStyle/Rector/Enum_/EnumCaseToPascalCaseRector/Source/Autoload/StatusEnum.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?php
22

3-
namespace Rector\Tests\CodingStyle\Rector\Enum_\EnumCaseToPascalCaseRector\Source;
3+
namespace Rector\Tests\CodingStyle\Rector\Enum_\EnumCaseToPascalCaseRector\Source\Autoload;
44

55
enum StatusEnum
66
{

rules-tests/CodingStyle/Rector/Enum_/EnumCaseToPascalCaseRector/WithAutoloadPathsTest.php

Lines changed: 0 additions & 28 deletions
This file was deleted.

rules-tests/CodingStyle/Rector/Enum_/EnumCaseToPascalCaseRector/config/configured_rule.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,5 @@
66
use Rector\Config\RectorConfig;
77

88
return RectorConfig::configure()
9-
->withRules([EnumCaseToPascalCaseRector::class]);
9+
->withRules([EnumCaseToPascalCaseRector::class])
10+
->withAutoloadPaths([__DIR__ . '/../Source/Autoload']);

rules-tests/CodingStyle/Rector/Enum_/EnumCaseToPascalCaseRector/config/with_autoload_configured_rule.php

Lines changed: 0 additions & 10 deletions
This file was deleted.

rules/CodingStyle/Rector/Enum_/EnumCaseToPascalCaseRector.php

Lines changed: 26 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,15 @@
44

55
namespace Rector\CodingStyle\Rector\Enum_;
66

7+
use PHPStan\Reflection\ClassReflection;
78
use PhpParser\Node;
89
use PhpParser\Node\Expr\ClassConstFetch;
910
use PhpParser\Node\Identifier;
1011
use PhpParser\Node\Name;
1112
use PhpParser\Node\Stmt\Enum_;
1213
use 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;
1714
use Rector\Configuration\Option;
1815
use Rector\Configuration\Parameter\SimpleParameterProvider;
19-
use Rector\NodeTypeResolver\Reflection\BetterReflection\SourceLocatorProvider\DynamicSourceLocatorProvider;
2016
use Rector\Rector\AbstractRector;
2117
use Rector\Skipper\FileSystem\PathNormalizer;
2218
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
@@ -27,12 +23,6 @@
2723
*/
2824
final 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

Comments
 (0)