Skip to content

Commit

Permalink
MyCLabs enum equals + keeping methods (#4645)
Browse files Browse the repository at this point in the history
* MyCLabs enums: keep enum custom methods (#8051)

* Enabled more usage variants of MyCLabs\Enum->equals()

* Removed tests cases for invalid use cases - there is no need to refactor non existing enum constant

* Code quality improvements
  • Loading branch information
K0nias committed Sep 4, 2023
1 parent dca3e9d commit 7571792
Show file tree
Hide file tree
Showing 7 changed files with 170 additions and 68 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

namespace Rector\Tests\Php81\Rector\Class_\MyCLabsClassToEnumRector\Fixture;

use MyCLabs\Enum\Enum;

final class KeepMethods extends Enum
{
private const VIEW = 'view';

private const EDIT = 'edit';

public function isItSame(self $other): bool
{
return $this === $other;
}
}

?>
-----
<?php

namespace Rector\Tests\Php81\Rector\Class_\MyCLabsClassToEnumRector\Fixture;

use MyCLabs\Enum\Enum;

enum KeepMethods : string
{
case VIEW = 'view';
case EDIT = 'edit';
public function isItSame(self $other): bool
{
return $this === $other;
}
}

?>

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ final class UsageOfEquals
$compare = SomeEnum::USED_TO_BE_CONST()->equals(SomeEnum::USED_TO_BE_CONST());
$compare = SomeEnum::USED_TO_BE_CONST()->equals($var);
$compare = SomeEnum::USED_TO_BE_CONST()->equals($this->prop);
$compare = SomeEnum::USED_TO_BE_CONST()->equals($this->getEnum());
$compare = SomeEnum::USED_TO_BE_CONST()->equals(self::getStaticEnum());
$compare = SomeEnum::create()->equals(self::getStaticEnum());

$compare = $var->equals(SomeEnum::USED_TO_BE_CONST());
$compare = $var->equals($var);
Expand All @@ -23,6 +26,30 @@ final class UsageOfEquals
$compare = $this->prop->equals(SomeEnum::USED_TO_BE_CONST());
$compare = $this->prop->equals($var);
$compare = $this->prop->equals($this->prop);

$compare = $this->getEnum()->equals(SomeEnum::USED_TO_BE_CONST());
$compare = $this->getEnum()->equals($var);
$compare = $this->getEnum()->equals($this->prop);

$compare = self::getStaticEnum()->equals(SomeEnum::USED_TO_BE_CONST());
$compare = self::getStaticEnum()->equals($var);
$compare = self::getStaticEnum()->equals($this->prop);

$compare = $var->equals($this->getEnum());
$compare = $this->prop->equals($this->getEnum());

$compare = $var->equals(self::getStaticEnum());
$compare = $this->prop->equals(self::getStaticEnum());
}

public function getEnum(): SomeEnum
{
return SomeEnum::USED_TO_BE_CONST();
}

public static function getStaticEnum(): SomeEnum
{
return SomeEnum::USED_TO_BE_CONST();
}
}

Expand All @@ -45,6 +72,9 @@ final class UsageOfEquals
$compare = \Rector\Tests\Php81\Rector\MethodCall\MyCLabsMethodCallToEnumConstRector\Source\SomeEnum::USED_TO_BE_CONST === \Rector\Tests\Php81\Rector\MethodCall\MyCLabsMethodCallToEnumConstRector\Source\SomeEnum::USED_TO_BE_CONST;
$compare = \Rector\Tests\Php81\Rector\MethodCall\MyCLabsMethodCallToEnumConstRector\Source\SomeEnum::USED_TO_BE_CONST === $var;
$compare = \Rector\Tests\Php81\Rector\MethodCall\MyCLabsMethodCallToEnumConstRector\Source\SomeEnum::USED_TO_BE_CONST === $this->prop;
$compare = \Rector\Tests\Php81\Rector\MethodCall\MyCLabsMethodCallToEnumConstRector\Source\SomeEnum::USED_TO_BE_CONST === $this->getEnum();
$compare = \Rector\Tests\Php81\Rector\MethodCall\MyCLabsMethodCallToEnumConstRector\Source\SomeEnum::USED_TO_BE_CONST === self::getStaticEnum();
$compare = SomeEnum::create() === self::getStaticEnum();

$compare = $var === \Rector\Tests\Php81\Rector\MethodCall\MyCLabsMethodCallToEnumConstRector\Source\SomeEnum::USED_TO_BE_CONST;
$compare = $var === $var;
Expand All @@ -53,6 +83,30 @@ final class UsageOfEquals
$compare = $this->prop === \Rector\Tests\Php81\Rector\MethodCall\MyCLabsMethodCallToEnumConstRector\Source\SomeEnum::USED_TO_BE_CONST;
$compare = $this->prop === $var;
$compare = $this->prop === $this->prop;

$compare = $this->getEnum() === \Rector\Tests\Php81\Rector\MethodCall\MyCLabsMethodCallToEnumConstRector\Source\SomeEnum::USED_TO_BE_CONST;
$compare = $this->getEnum() === $var;
$compare = $this->getEnum() === $this->prop;

$compare = self::getStaticEnum() === \Rector\Tests\Php81\Rector\MethodCall\MyCLabsMethodCallToEnumConstRector\Source\SomeEnum::USED_TO_BE_CONST;
$compare = self::getStaticEnum() === $var;
$compare = self::getStaticEnum() === $this->prop;

$compare = $var === $this->getEnum();
$compare = $this->prop === $this->getEnum();

$compare = $var === self::getStaticEnum();
$compare = $this->prop === self::getStaticEnum();
}

public function getEnum(): SomeEnum
{
return \Rector\Tests\Php81\Rector\MethodCall\MyCLabsMethodCallToEnumConstRector\Source\SomeEnum::USED_TO_BE_CONST;
}

public static function getStaticEnum(): SomeEnum
{
return \Rector\Tests\Php81\Rector\MethodCall\MyCLabsMethodCallToEnumConstRector\Source\SomeEnum::USED_TO_BE_CONST;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,9 @@
final class SomeEnum extends Enum
{
const USED_TO_BE_CONST = 'value';

public static function create(): self
{
return SomeEnum::USED_TO_BE_CONST();
}
}
2 changes: 2 additions & 0 deletions rules/Php81/NodeFactory/EnumFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ public function createFromClass(Class_ $class): Enum_
}
}

$enum->stmts = array_merge($enum->stmts, $class->getMethods());

return $enum;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\Expr\StaticCall;
use PhpParser\Node\Expr\Variable;
use PHPStan\Reflection\ReflectionProvider;
use PHPStan\Type\ObjectType;
use Rector\Core\Rector\AbstractRector;
use Rector\Core\ValueObject\PhpVersionFeature;
Expand All @@ -33,6 +34,11 @@ final class MyCLabsMethodCallToEnumConstRector extends AbstractRector implements
*/
private const ENUM_METHODS = ['from', 'values', 'keys', 'isValid', 'search', 'toArray', 'assertValidValue'];

public function __construct(
private readonly ReflectionProvider $reflectionProvider,
) {
}

public function getRuleDefinition(): RuleDefinition
{
return new RuleDefinition('Refactor MyCLabs enum fetch to Enum const', [
Expand Down Expand Up @@ -88,9 +94,20 @@ public function refactor(Node $node): ?Node
return null;
}

if (! $this->isEnumConstant($className, $enumCaseName)) {
return null;
}

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

private function isEnumConstant(string $className, string $constant): bool
{
$classReflection = $this->reflectionProvider->getClass($className);

return $classReflection->hasConstant($constant);
}

public function provideMinPhpVersion(): int
{
return PhpVersionFeature::ENUM;
Expand Down Expand Up @@ -148,24 +165,73 @@ private function refactorGetValueMethodCall(MethodCall $methodCall): ?PropertyFe

private function refactorEqualsMethodCall(MethodCall $methodCall): ?Identical
{
$expr = $this->getValidEnumExpr($methodCall->var);
if (! $expr instanceof Expr) {
return null;
$expr = $this->getNonEnumReturnTypeExpr($methodCall->var);
if ($expr === null) {
$expr = $this->getValidEnumExpr($methodCall->var);
if (! $expr instanceof Expr) {
return null;
}
}

$arg = $methodCall->getArgs()[0] ?? null;
if (! $arg instanceof Arg) {
return null;
}

$right = $this->getValidEnumExpr($arg->value);
if (! $right instanceof Expr) {
return null;
$right = $this->getNonEnumReturnTypeExpr($arg->value);
if ($right === null) {
$right = $this->getValidEnumExpr($arg->value);
if (! $right instanceof Expr) {
return null;
}
}

return new Identical($expr, $right);
}

private function isCallerClassEnum(StaticCall|MethodCall $node): bool
{
if ($node instanceof StaticCall) {
return $this->isObjectType($node->class, new ObjectType('MyCLabs\Enum\Enum'));
}

return $this->isObjectType($node->var, new ObjectType('MyCLabs\Enum\Enum'));
}

private function getNonEnumReturnTypeExpr(Node $node): null|ClassConstFetch|Expr
{
if (! $node instanceof StaticCall && ! $node instanceof MethodCall) {
return null;
}

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

if ($node instanceof StaticCall) {
$className = $this->getName($node->class);
}

if ($node instanceof MethodCall) {
$className = $this->getName($node->var);
}

if ($className === null) {
return null;
}

$classReflection = $this->reflectionProvider->getClass($className);
// method self::getValidEnumExpr process enum static methods from constants
if ($classReflection->hasConstant($methodName)) {
return null;
}
}

return $node;
}

private function getValidEnumExpr(Node $node): null|ClassConstFetch|Expr
{
return match ($node::class) {
Expand Down

0 comments on commit 7571792

Please sign in to comment.