From 39d6a69bfd526fb681c023a13c5714f9714cd50f Mon Sep 17 00:00:00 2001 From: Jorg Sowa Date: Thu, 10 Oct 2024 00:31:38 +0200 Subject: [PATCH 1/8] Add new rule for rounding modes in PHP 8.4 --- .../Fixture/do_not_reprint_node_type.php.inc | 25 +++++ .../RoundingModeEnumRectorTest.php | 28 +++++ .../config/configured_rule.php | 13 +++ .../FuncCall/RoundingModeEnumRector.php | 104 ++++++++++++++++++ src/ValueObject/PhpVersionFeature.php | 6 + 5 files changed, 176 insertions(+) create mode 100644 rules-tests/Php84/Rector/FuncCall/RoundingModeEnumRector/Fixture/do_not_reprint_node_type.php.inc create mode 100644 rules-tests/Php84/Rector/FuncCall/RoundingModeEnumRector/RoundingModeEnumRectorTest.php create mode 100644 rules-tests/Php84/Rector/FuncCall/RoundingModeEnumRector/config/configured_rule.php create mode 100644 rules/Php84/Rector/FuncCall/RoundingModeEnumRector.php diff --git a/rules-tests/Php84/Rector/FuncCall/RoundingModeEnumRector/Fixture/do_not_reprint_node_type.php.inc b/rules-tests/Php84/Rector/FuncCall/RoundingModeEnumRector/Fixture/do_not_reprint_node_type.php.inc new file mode 100644 index 00000000000..501f5eba181 --- /dev/null +++ b/rules-tests/Php84/Rector/FuncCall/RoundingModeEnumRector/Fixture/do_not_reprint_node_type.php.inc @@ -0,0 +1,25 @@ + +----- + diff --git a/rules-tests/Php84/Rector/FuncCall/RoundingModeEnumRector/RoundingModeEnumRectorTest.php b/rules-tests/Php84/Rector/FuncCall/RoundingModeEnumRector/RoundingModeEnumRectorTest.php new file mode 100644 index 00000000000..0dab7f73cb8 --- /dev/null +++ b/rules-tests/Php84/Rector/FuncCall/RoundingModeEnumRector/RoundingModeEnumRectorTest.php @@ -0,0 +1,28 @@ +doTestFile($filePath); + } + + public static function provideData(): Iterator + { + return self::yieldFilesFromDirectory(__DIR__ . '/Fixture'); + } + + public function provideConfigFilePath(): string + { + return __DIR__ . '/config/configured_rule.php'; + } +} diff --git a/rules-tests/Php84/Rector/FuncCall/RoundingModeEnumRector/config/configured_rule.php b/rules-tests/Php84/Rector/FuncCall/RoundingModeEnumRector/config/configured_rule.php new file mode 100644 index 00000000000..68ca3b74849 --- /dev/null +++ b/rules-tests/Php84/Rector/FuncCall/RoundingModeEnumRector/config/configured_rule.php @@ -0,0 +1,13 @@ +rule(RoundingModeEnumRector::class); + + $rectorConfig->phpVersion(PhpVersion::PHP_84); +}; diff --git a/rules/Php84/Rector/FuncCall/RoundingModeEnumRector.php b/rules/Php84/Rector/FuncCall/RoundingModeEnumRector.php new file mode 100644 index 00000000000..ac9c6bd111a --- /dev/null +++ b/rules/Php84/Rector/FuncCall/RoundingModeEnumRector.php @@ -0,0 +1,104 @@ +isName($node, 'round')) { + return null; + } + + $args = $node->getArgs(); + + if (count($args) !== 3) { + return null; + } + + $modeArg = $args[2]->value; + + if ($modeArg instanceof ConstFetch) { + if (isset($modeArg->name->getParts()[0])) { + $enumCase = match ($modeArg->name->getParts()[0]) { + 'PHP_ROUND_HALF_UP' => 'HalfAwayFromZero', + 'PHP_ROUND_HALF_DOWN' => 'HalfTowardsZero', + 'PHP_ROUND_HALF_EVEN' => 'HalfEven', + 'PHP_ROUND_HALF_ODD' => 'HalfOdd', + default => null, + }; + + if ($enumCase === null) { + return null; + } + + $args[2]->value = new Node\Expr\ClassConstFetch(new Name('RoundingMode'), $enumCase); + } + } + + + return $node; + } + + public function provideMinPhpVersion(): int + { + return PhpVersionFeature::ROUNDING_MODES; + } +} diff --git a/src/ValueObject/PhpVersionFeature.php b/src/ValueObject/PhpVersionFeature.php index 86de5ba52f7..5ee796b58ae 100644 --- a/src/ValueObject/PhpVersionFeature.php +++ b/src/ValueObject/PhpVersionFeature.php @@ -678,6 +678,12 @@ final class PhpVersionFeature */ public const DEPRECATE_IMPLICIT_NULLABLE_PARAM_TYPE = PhpVersion::PHP_84; + /** + * @see https://wiki.php.net/rfc/correctly_name_the_rounding_mode_and_make_it_an_enum + * @var int + */ + public const ROUNDING_MODES = PhpVersion::PHP_84; + /** * @see https://www.php.net/manual/en/migration83.deprecated.php#migration83.deprecated.ldap * @var int From 8d12d5187cee7cdc2d56df9bccdb7b713ba59e0e Mon Sep 17 00:00:00 2001 From: Jorg Sowa Date: Fri, 11 Oct 2024 23:29:39 +0200 Subject: [PATCH 2/8] Added namespace to test --- .../Fixture/do_not_reprint_node_type.php.inc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/rules-tests/Php84/Rector/FuncCall/RoundingModeEnumRector/Fixture/do_not_reprint_node_type.php.inc b/rules-tests/Php84/Rector/FuncCall/RoundingModeEnumRector/Fixture/do_not_reprint_node_type.php.inc index 501f5eba181..482557a736c 100644 --- a/rules-tests/Php84/Rector/FuncCall/RoundingModeEnumRector/Fixture/do_not_reprint_node_type.php.inc +++ b/rules-tests/Php84/Rector/FuncCall/RoundingModeEnumRector/Fixture/do_not_reprint_node_type.php.inc @@ -1,5 +1,7 @@ Date: Fri, 11 Oct 2024 23:39:35 +0200 Subject: [PATCH 3/8] Improve tests --- ...nt_node_type.php.inc => rounding_constants.php.inc} | 0 .../Fixture/skip_indirect_use_of_constants.php.inc | 10 ++++++++++ 2 files changed, 10 insertions(+) rename rules-tests/Php84/Rector/FuncCall/RoundingModeEnumRector/Fixture/{do_not_reprint_node_type.php.inc => rounding_constants.php.inc} (100%) create mode 100644 rules-tests/Php84/Rector/FuncCall/RoundingModeEnumRector/Fixture/skip_indirect_use_of_constants.php.inc diff --git a/rules-tests/Php84/Rector/FuncCall/RoundingModeEnumRector/Fixture/do_not_reprint_node_type.php.inc b/rules-tests/Php84/Rector/FuncCall/RoundingModeEnumRector/Fixture/rounding_constants.php.inc similarity index 100% rename from rules-tests/Php84/Rector/FuncCall/RoundingModeEnumRector/Fixture/do_not_reprint_node_type.php.inc rename to rules-tests/Php84/Rector/FuncCall/RoundingModeEnumRector/Fixture/rounding_constants.php.inc diff --git a/rules-tests/Php84/Rector/FuncCall/RoundingModeEnumRector/Fixture/skip_indirect_use_of_constants.php.inc b/rules-tests/Php84/Rector/FuncCall/RoundingModeEnumRector/Fixture/skip_indirect_use_of_constants.php.inc new file mode 100644 index 00000000000..be3441a4fa3 --- /dev/null +++ b/rules-tests/Php84/Rector/FuncCall/RoundingModeEnumRector/Fixture/skip_indirect_use_of_constants.php.inc @@ -0,0 +1,10 @@ + From c09bd5ebecab692a02a2e8521647d3bde733535c Mon Sep 17 00:00:00 2001 From: Jorg Sowa Date: Fri, 11 Oct 2024 23:39:43 +0200 Subject: [PATCH 4/8] Fixed namespace --- .../RoundingModeEnumRector/RoundingModeEnumRectorTest.php | 2 +- rules/Php84/Rector/FuncCall/RoundingModeEnumRector.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rules-tests/Php84/Rector/FuncCall/RoundingModeEnumRector/RoundingModeEnumRectorTest.php b/rules-tests/Php84/Rector/FuncCall/RoundingModeEnumRector/RoundingModeEnumRectorTest.php index 0dab7f73cb8..51c2e48eb1f 100644 --- a/rules-tests/Php84/Rector/FuncCall/RoundingModeEnumRector/RoundingModeEnumRectorTest.php +++ b/rules-tests/Php84/Rector/FuncCall/RoundingModeEnumRector/RoundingModeEnumRectorTest.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Php84\Rector\FuncCall\RoundingModeEnumRector; +namespace Rector\Tests\Php84\Rector\FuncCall\RoundingModeEnumRector; use Iterator; use PHPUnit\Framework\Attributes\DataProvider; diff --git a/rules/Php84/Rector/FuncCall/RoundingModeEnumRector.php b/rules/Php84/Rector/FuncCall/RoundingModeEnumRector.php index ac9c6bd111a..b5b66681e90 100644 --- a/rules/Php84/Rector/FuncCall/RoundingModeEnumRector.php +++ b/rules/Php84/Rector/FuncCall/RoundingModeEnumRector.php @@ -25,7 +25,7 @@ use Symplify\RuleDocGenerator\ValueObject\RuleDefinition; /** - * @see \Rector\Tests\Php84\Rector\Param\ExplicitNullableParamTypeRector\ExplicitNullableParamTypeRectorTest //TODO + * @see \Rector\Tests\Php84\Rector\FuncCall\RoundingModeEnumRector\RoundingModeEnumRectorTest */ final class RoundingModeEnumRector extends AbstractRector implements MinPhpVersionInterface { From 39e289897b31d49bea8de693931c781cad6a7a83 Mon Sep 17 00:00:00 2001 From: Jorg Sowa Date: Fri, 11 Oct 2024 23:41:33 +0200 Subject: [PATCH 5/8] Skip first class callable --- .../FuncCall/RoundingModeEnumRector.php | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/rules/Php84/Rector/FuncCall/RoundingModeEnumRector.php b/rules/Php84/Rector/FuncCall/RoundingModeEnumRector.php index b5b66681e90..65628456cb1 100644 --- a/rules/Php84/Rector/FuncCall/RoundingModeEnumRector.php +++ b/rules/Php84/Rector/FuncCall/RoundingModeEnumRector.php @@ -5,18 +5,11 @@ namespace Rector\Php84\Rector\FuncCall; use PhpParser\Node; -use PhpParser\Node\ComplexType; use PhpParser\Node\Expr\ConstFetch; use PhpParser\Node\Expr\FuncCall; -use PhpParser\Node\IntersectionType; use PhpParser\Node\Name; -use PhpParser\Node\NullableType; use PhpParser\Node\Param; -use PhpParser\Node\UnionType; -use PHPStan\Type\MixedType; -use PHPStan\Type\TypeCombinator; use Rector\PhpParser\Node\Value\ValueResolver; -use Rector\PHPStanStaticTypeMapper\Enum\TypeKind; use Rector\Rector\AbstractRector; use Rector\StaticTypeMapper\StaticTypeMapper; use Rector\ValueObject\PhpVersionFeature; @@ -30,10 +23,9 @@ final class RoundingModeEnumRector extends AbstractRector implements MinPhpVersionInterface { public function __construct( - private readonly ValueResolver $valueResolver, + private readonly ValueResolver $valueResolver, private readonly StaticTypeMapper $staticTypeMapper - ) - { + ) { } public function getRuleDefinition(): RuleDefinition @@ -63,7 +55,11 @@ public function getNodeTypes(): array public function refactor(Node $node): ?Node\Expr\FuncCall { - if (!$this->isName($node, 'round')) { + if (! $this->isName($node, 'round')) { + return null; + } + + if ($node->isFirstClassCallable()) { return null; } @@ -93,7 +89,6 @@ public function refactor(Node $node): ?Node\Expr\FuncCall } } - return $node; } From a6858ae5e1bec8fc1cbd144bd5117205737c6a5b Mon Sep 17 00:00:00 2001 From: Jorg Sowa Date: Fri, 11 Oct 2024 23:43:50 +0200 Subject: [PATCH 6/8] Used FullyQualified instead of name --- .../Fixture/rounding_constants.php.inc | 8 ++++---- rules/Php84/Rector/FuncCall/RoundingModeEnumRector.php | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/rules-tests/Php84/Rector/FuncCall/RoundingModeEnumRector/Fixture/rounding_constants.php.inc b/rules-tests/Php84/Rector/FuncCall/RoundingModeEnumRector/Fixture/rounding_constants.php.inc index 482557a736c..2a70b9d247d 100644 --- a/rules-tests/Php84/Rector/FuncCall/RoundingModeEnumRector/Fixture/rounding_constants.php.inc +++ b/rules-tests/Php84/Rector/FuncCall/RoundingModeEnumRector/Fixture/rounding_constants.php.inc @@ -19,10 +19,10 @@ namespace Rector\Tests\Php84\Rector\FuncCall\RoundingModeEnumRector; round(1.5, 0); round(1.5); -round(1.5, 0, RoundingMode::HalfAwayFromZero); -round(1.5, 0, RoundingMode::HalfTowardsZero); -round(1.5, 0, RoundingMode::HalfEven); -round(1.5, 0, RoundingMode::HalfOdd); +round(1.5, 0, \RoundingMode::HalfAwayFromZero); +round(1.5, 0, \RoundingMode::HalfTowardsZero); +round(1.5, 0, \RoundingMode::HalfEven); +round(1.5, 0, \RoundingMode::HalfOdd); round(1.5, 0, 'invalid'); round(1.5, 0, PHP_INT_MAX); diff --git a/rules/Php84/Rector/FuncCall/RoundingModeEnumRector.php b/rules/Php84/Rector/FuncCall/RoundingModeEnumRector.php index 65628456cb1..e24cf4c83da 100644 --- a/rules/Php84/Rector/FuncCall/RoundingModeEnumRector.php +++ b/rules/Php84/Rector/FuncCall/RoundingModeEnumRector.php @@ -7,7 +7,7 @@ use PhpParser\Node; use PhpParser\Node\Expr\ConstFetch; use PhpParser\Node\Expr\FuncCall; -use PhpParser\Node\Name; +use PhpParser\Node\Name\FullyQualified; use PhpParser\Node\Param; use Rector\PhpParser\Node\Value\ValueResolver; use Rector\Rector\AbstractRector; @@ -85,7 +85,7 @@ public function refactor(Node $node): ?Node\Expr\FuncCall return null; } - $args[2]->value = new Node\Expr\ClassConstFetch(new Name('RoundingMode'), $enumCase); + $args[2]->value = new Node\Expr\ClassConstFetch(new FullyQualified('RoundingMode'), $enumCase); } } From d04dcfd88f3ee62b5b06f29571ec5ac918158908 Mon Sep 17 00:00:00 2001 From: Jorg Sowa Date: Fri, 11 Oct 2024 23:46:13 +0200 Subject: [PATCH 7/8] Added RoundingModeEnumRector to php84.php --- config/set/php84.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/config/set/php84.php b/config/set/php84.php index 8a015ad0d4c..3231419d58a 100644 --- a/config/set/php84.php +++ b/config/set/php84.php @@ -3,8 +3,9 @@ declare(strict_types=1); use Rector\Config\RectorConfig; +use Rector\Php84\Rector\FuncCall\RoundingModeEnumRector; use Rector\Php84\Rector\Param\ExplicitNullableParamTypeRector; return static function (RectorConfig $rectorConfig): void { - $rectorConfig->rules([ExplicitNullableParamTypeRector::class]); + $rectorConfig->rules([ExplicitNullableParamTypeRector::class, RoundingModeEnumRector::class]); }; From 8531c37d4954e388aa210988aedcb4630faa8ce9 Mon Sep 17 00:00:00 2001 From: Jorg Sowa Date: Fri, 11 Oct 2024 23:47:00 +0200 Subject: [PATCH 8/8] Removed constructor --- rules/Php84/Rector/FuncCall/RoundingModeEnumRector.php | 6 ------ 1 file changed, 6 deletions(-) diff --git a/rules/Php84/Rector/FuncCall/RoundingModeEnumRector.php b/rules/Php84/Rector/FuncCall/RoundingModeEnumRector.php index e24cf4c83da..1ed3e08e5ea 100644 --- a/rules/Php84/Rector/FuncCall/RoundingModeEnumRector.php +++ b/rules/Php84/Rector/FuncCall/RoundingModeEnumRector.php @@ -22,12 +22,6 @@ */ final class RoundingModeEnumRector extends AbstractRector implements MinPhpVersionInterface { - public function __construct( - private readonly ValueResolver $valueResolver, - private readonly StaticTypeMapper $staticTypeMapper - ) { - } - public function getRuleDefinition(): RuleDefinition { return new RuleDefinition('Replace rounding mode constant to RoundMode enum in round()', [