Skip to content

Commit

Permalink
refactors Spatie enum method calls to native enums (#3226)
Browse files Browse the repository at this point in the history
Co-authored-by: jools <julien.dephix.nagoya@accopilot.com>
  • Loading branch information
JoolsMcFly and jools committed Dec 28, 2022
1 parent ac2f853 commit 384e84a
Show file tree
Hide file tree
Showing 9 changed files with 327 additions and 1 deletion.
21 changes: 20 additions & 1 deletion build/target-repository/docs/rector_rules_overview.md
Expand Up @@ -46,7 +46,7 @@

- [Php80](#php80) (20)

- [Php81](#php81) (11)
- [Php81](#php81) (12)

- [Php82](#php82) (2)

Expand Down Expand Up @@ -6549,6 +6549,25 @@ Refactor Spatie enum class to native Enum

<br>

### SpatieEnumMethodCallToEnumConstRector

Refactor Spatie enum method calls

- class: [`Rector\Php81\Rector\MethodCall\SpatieEnumMethodCallToEnumConstRector`](../rules/Php81/Rector/MethodCall/SpatieEnumMethodCallToEnumConstRector.php)

```diff
-$value1 = SomeEnum::SOME_CONSTANT()->getValue();
-$value2 = SomeEnum::SOME_CONSTANT()->value;
-$name1 = SomeEnum::SOME_CONSTANT()->getName();
-$name2 = SomeEnum::SOME_CONSTANT()->name;
+$value1 = SomeEnum::SOME_CONSTANT->value;
+$value2 = SomeEnum::SOME_CONSTANT->value;
+$name1 = SomeEnum::SOME_CONSTANT->name;
+$name2 = SomeEnum::SOME_CONSTANT->name;
```

<br>

## Php82

### ReadOnlyClassRector
Expand Down
2 changes: 2 additions & 0 deletions config/set/php81.php
Expand Up @@ -12,6 +12,7 @@
use Rector\Php81\Rector\FuncCall\Php81ResourceReturnToObjectRector;
use Rector\Php81\Rector\FunctionLike\IntersectionTypesRector;
use Rector\Php81\Rector\MethodCall\MyCLabsMethodCallToEnumConstRector;
use Rector\Php81\Rector\MethodCall\SpatieEnumMethodCallToEnumConstRector;
use Rector\Php81\Rector\Property\ReadOnlyPropertyRector;
use Rector\TypeDeclaration\Rector\ClassMethod\ReturnNeverTypeRector;

Expand All @@ -22,6 +23,7 @@
$rectorConfig->rule(FinalizePublicClassConstantRector::class);
$rectorConfig->rule(ReadOnlyPropertyRector::class);
$rectorConfig->rule(SpatieEnumClassToEnumRector::class);
$rectorConfig->rule(SpatieEnumMethodCallToEnumConstRector::class);
$rectorConfig->rule(Php81ResourceReturnToObjectRector::class);
$rectorConfig->rule(NewInInitializerRector::class);
$rectorConfig->rule(IntersectionTypesRector::class);
Expand Down
@@ -0,0 +1,33 @@
<?php

namespace Rector\Tests\Php81\Rector\MethodCall\SpatieEnumMethodCallToEnumConstRector\Fixture;

use \Rector\Tests\Php81\Rector\MethodCall\SpatieEnumMethodCallToEnumConstRector;

final class NameOrGetNameToNameProperty
{
public function run($value)
{
$archivedName = \Rector\Tests\Php81\Rector\MethodCall\SpatieEnumMethodCallToEnumConstRector\Source\StatusEnum::archived()->getName();
$draftName = SpatieEnumMethodCallToEnumConstRector\Source\StatusEnum::draft()->name;
}
}

?>
-----
<?php

namespace Rector\Tests\Php81\Rector\MethodCall\SpatieEnumMethodCallToEnumConstRector\Fixture;

use \Rector\Tests\Php81\Rector\MethodCall\SpatieEnumMethodCallToEnumConstRector;

final class NameOrGetNameToNameProperty
{
public function run($value)
{
$archivedName = \Rector\Tests\Php81\Rector\MethodCall\SpatieEnumMethodCallToEnumConstRector\Source\StatusEnum::ARCHIVED->name;
$draftName = \Rector\Tests\Php81\Rector\MethodCall\SpatieEnumMethodCallToEnumConstRector\Source\StatusEnum::DRAFT->name;
}
}

?>
@@ -0,0 +1,33 @@
<?php

namespace Rector\Tests\Php81\Rector\MethodCall\SpatieEnumMethodCallToEnumConstRector\Fixture;

use \Rector\Tests\Php81\Rector\MethodCall\SpatieEnumMethodCallToEnumConstRector;

final class StaticMethodCallToStaticProperty
{
public function run($value)
{
$archived = \Rector\Tests\Php81\Rector\MethodCall\SpatieEnumMethodCallToEnumConstRector\Source\StatusEnum::archived();
$published = SpatieEnumMethodCallToEnumConstRector\Source\StatusEnum::published();
}
}

?>
-----
<?php

namespace Rector\Tests\Php81\Rector\MethodCall\SpatieEnumMethodCallToEnumConstRector\Fixture;

use \Rector\Tests\Php81\Rector\MethodCall\SpatieEnumMethodCallToEnumConstRector;

final class StaticMethodCallToStaticProperty
{
public function run($value)
{
$archived = \Rector\Tests\Php81\Rector\MethodCall\SpatieEnumMethodCallToEnumConstRector\Source\StatusEnum::ARCHIVED;
$published = \Rector\Tests\Php81\Rector\MethodCall\SpatieEnumMethodCallToEnumConstRector\Source\StatusEnum::PUBLISHED;
}
}

?>
@@ -0,0 +1,33 @@
<?php

namespace Rector\Tests\Php81\Rector\MethodCall\SpatieEnumMethodCallToEnumConstRector\Fixture;

use \Rector\Tests\Php81\Rector\MethodCall\SpatieEnumMethodCallToEnumConstRector;

final class ValueOrGetValueToValueProperty
{
public function run($value)
{
$archivedName = \Rector\Tests\Php81\Rector\MethodCall\SpatieEnumMethodCallToEnumConstRector\Source\StatusEnum::archived()->getValue();
$draftName = SpatieEnumMethodCallToEnumConstRector\Source\StatusEnum::draft()->value;
}
}

?>
-----
<?php

namespace Rector\Tests\Php81\Rector\MethodCall\SpatieEnumMethodCallToEnumConstRector\Fixture;

use \Rector\Tests\Php81\Rector\MethodCall\SpatieEnumMethodCallToEnumConstRector;

final class ValueOrGetValueToValueProperty
{
public function run($value)
{
$archivedName = \Rector\Tests\Php81\Rector\MethodCall\SpatieEnumMethodCallToEnumConstRector\Source\StatusEnum::ARCHIVED->value;
$draftName = \Rector\Tests\Php81\Rector\MethodCall\SpatieEnumMethodCallToEnumConstRector\Source\StatusEnum::DRAFT->value;
}
}

?>
@@ -0,0 +1,16 @@
<?php

declare(strict_types=1);

namespace Rector\Tests\Php81\Rector\MethodCall\SpatieEnumMethodCallToEnumConstRector\Source;

use Spatie\Enum\Enum;

/**
* @method static self draft()
* @method static self published()
* @method static self archived()
*/
class StatusEnum extends Enum
{
}
@@ -0,0 +1,29 @@
<?php

declare(strict_types=1);

namespace Rector\Tests\Php81\Rector\MethodCall\SpatieEnumMethodCallToEnumConstRector;

use Iterator;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;

final class SpatieEnumMethodCallToEnumConstRectorTest extends AbstractRectorTestCase
{
/**
* @dataProvider provideData()
*/
public function test(string $filePath): void
{
$this->doTestFile($filePath);
}

public function provideData(): Iterator
{
return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture');
}

public function provideConfigFilePath(): string
{
return __DIR__ . '/config/configured_rule.php';
}
}
@@ -0,0 +1,10 @@
<?php

declare(strict_types=1);

use Rector\Config\RectorConfig;
use Rector\Php81\Rector\MethodCall\SpatieEnumMethodCallToEnumConstRector;

return static function (RectorConfig $rectorConfig): void {
$rectorConfig->rule(SpatieEnumMethodCallToEnumConstRector::class);
};
@@ -0,0 +1,151 @@
<?php

declare(strict_types=1);

namespace Rector\Php81\Rector\MethodCall;

use PhpParser\Node;
use PhpParser\Node\Expr;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\Expr\StaticCall;
use PHPStan\Type\ObjectType;
use Rector\Core\Rector\AbstractRector;
use Rector\Core\ValueObject\PhpVersionFeature;
use Rector\VersionBonding\Contract\MinPhpVersionInterface;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;

/**
* @changelog https://wiki.php.net/rfc/enumerations
*
* @see \Rector\Tests\Php81\Rector\MethodCall\MyCLabsMethodCallToEnumConstRector\MyCLabsMethodCallToEnumConstRectorTest
*/
final class SpatieEnumMethodCallToEnumConstRector extends AbstractRector implements MinPhpVersionInterface
{
private const SPATIE_FQN = 'Spatie\Enum\Enum';

/**
* @var string[]
*/
private const ENUM_METHODS = ['from', 'values', 'keys', 'isValid', 'search', 'toArray', 'assertValidValue'];

public function getRuleDefinition(): RuleDefinition
{
return new RuleDefinition('Refactor Spatie enum method calls', [
new CodeSample(
<<<'CODE_SAMPLE'
$value1 = SomeEnum::SOME_CONSTANT()->getValue();
$value2 = SomeEnum::SOME_CONSTANT()->value;
$name1 = SomeEnum::SOME_CONSTANT()->getName();
$name2 = SomeEnum::SOME_CONSTANT()->name;
CODE_SAMPLE
,
<<<'CODE_SAMPLE'
$value1 = SomeEnum::SOME_CONSTANT->value;
$value2 = SomeEnum::SOME_CONSTANT->value;
$name1 = SomeEnum::SOME_CONSTANT->name;
$name2 = SomeEnum::SOME_CONSTANT->name;
CODE_SAMPLE
),
]);
}

/**
* @return array<class-string<Node>>
*/
public function getNodeTypes(): array
{
return [MethodCall::class, StaticCall::class];
}

/**
* @param MethodCall|StaticCall $node
*/
public function refactor(Node $node): ?Node
{
if ($node->name instanceof Expr) {
return null;
}

$enumCaseName = $this->getName($node->name);
if ($enumCaseName === null) {
return null;
}

if ($this->shouldOmitEnumCase($enumCaseName)) {
return null;
}

if ($node instanceof MethodCall) {
return $this->refactorMethodCall($node, $enumCaseName);
}

if (! $this->isObjectType($node->class, new ObjectType(self::SPATIE_FQN))) {
return null;
}

$className = $this->getName($node->class);
if (! is_string($className)) {
return null;
}

$constantName = strtoupper($enumCaseName);

return $this->nodeFactory->createClassConstFetch($className, $constantName);
}

public function provideMinPhpVersion(): int
{
return PhpVersionFeature::ENUM;
}

private function refactorGetterToMethodCall(MethodCall $methodCall, string $property): ?PropertyFetch
{
if (! $methodCall->var instanceof StaticCall) {
return null;
}

$staticCall = $methodCall->var;
$className = $this->getName($staticCall->class);
if ($className === null) {
return null;
}

$enumCaseName = $this->getName($staticCall->name);
if ($enumCaseName === null) {
return null;
}

if ($this->shouldOmitEnumCase($enumCaseName)) {
return null;
}

$upperCaseName = strtoupper($enumCaseName);
$enumConstFetch = $this->nodeFactory->createClassConstFetch($className, $upperCaseName);

return new PropertyFetch($enumConstFetch, $property);
}

private function refactorMethodCall(MethodCall $methodCall, string $methodName): null|PropertyFetch
{
if (! $this->isObjectType($methodCall->var, new ObjectType(self::SPATIE_FQN))) {
return null;
}

if ($methodName === 'getName' || $methodName === 'label') {
return $this->refactorGetterToMethodCall($methodCall, 'name');
}

if ($methodName === 'getValue' || $methodName === 'value') {
return $this->refactorGetterToMethodCall($methodCall, 'value');
}

return null;
}

private function shouldOmitEnumCase(string $enumCaseName): bool
{
return in_array($enumCaseName, self::ENUM_METHODS, true);
}
}

0 comments on commit 384e84a

Please sign in to comment.