From 3dfe44cea195d05a11e010125a18e0db22b7e0ce Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Thu, 31 Jul 2025 12:31:17 +0700 Subject: [PATCH 01/11] [DowngradePhp74] Handle merge const on DowngradeArraySpreadStringKeyRector + DowngradeArraySpreadRector --- .../Fixture/merge_const.php.inc | 103 ++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 tests/Issues/IssueDowngradeArraySpread/Fixture/merge_const.php.inc diff --git a/tests/Issues/IssueDowngradeArraySpread/Fixture/merge_const.php.inc b/tests/Issues/IssueDowngradeArraySpread/Fixture/merge_const.php.inc new file mode 100644 index 00000000..8df1cf0e --- /dev/null +++ b/tests/Issues/IssueDowngradeArraySpread/Fixture/merge_const.php.inc @@ -0,0 +1,103 @@ + +----- + From a2c986e3b8723014b382ad210d115a464736242b Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Mon, 4 Aug 2025 08:24:01 +0700 Subject: [PATCH 02/11] update fixture --- .../Fixture/merge_const.php.inc | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/tests/Issues/IssueDowngradeArraySpread/Fixture/merge_const.php.inc b/tests/Issues/IssueDowngradeArraySpread/Fixture/merge_const.php.inc index 8df1cf0e..2b66ac41 100644 --- a/tests/Issues/IssueDowngradeArraySpread/Fixture/merge_const.php.inc +++ b/tests/Issues/IssueDowngradeArraySpread/Fixture/merge_const.php.inc @@ -20,8 +20,10 @@ class MergeConst private const EXPECTED_KINDS_GENERIC = [ \T_ABSTRACT, - \T_FINAL, \T_PRIVATE, - \T_PROTECTED, \T_PUBLIC, + \T_FINAL, + \T_PRIVATE, + \T_PROTECTED, + \T_PUBLIC, \T_STATIC, \T_VAR, CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PUBLIC, @@ -78,8 +80,10 @@ class MergeConst private const EXPECTED_KINDS_PROPERTY_KINDS = [ \T_ABSTRACT, - \T_FINAL, \T_PRIVATE, - \T_PROTECTED, \T_PUBLIC, + \T_FINAL, + \T_PRIVATE, + \T_PROTECTED, + \T_PUBLIC, \T_STATIC, \T_VAR, CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PUBLIC, From 74424117eb530de4ae45c88ccf1184a2a7ac4493 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Mon, 4 Aug 2025 08:24:50 +0700 Subject: [PATCH 03/11] update fixture --- .../IssueDowngradeArraySpread/config/configured_rule.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/Issues/IssueDowngradeArraySpread/config/configured_rule.php b/tests/Issues/IssueDowngradeArraySpread/config/configured_rule.php index b826c5b5..a5a37c94 100644 --- a/tests/Issues/IssueDowngradeArraySpread/config/configured_rule.php +++ b/tests/Issues/IssueDowngradeArraySpread/config/configured_rule.php @@ -8,7 +8,10 @@ use Rector\ValueObject\PhpVersion; return static function (RectorConfig $rectorConfig): void { - $rectorConfig->rules([DowngradeArraySpreadStringKeyRector::class, DowngradeArraySpreadRector::class]); + $rectorConfig->rules([ + DowngradeArraySpreadStringKeyRector::class, + DowngradeArraySpreadRector::class + ]); $rectorConfig->phpVersion(PhpVersion::PHP_81); }; From 166904e519c0d697b979042461460e59f472cfac Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Mon, 4 Aug 2025 08:32:54 +0700 Subject: [PATCH 04/11] update fixture --- .../IssueDowngradeArraySpread/Fixture/merge_const.php.inc | 6 ++++-- .../IssueDowngradeArraySpread/config/configured_rule.php | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/Issues/IssueDowngradeArraySpread/Fixture/merge_const.php.inc b/tests/Issues/IssueDowngradeArraySpread/Fixture/merge_const.php.inc index 2b66ac41..181651e3 100644 --- a/tests/Issues/IssueDowngradeArraySpread/Fixture/merge_const.php.inc +++ b/tests/Issues/IssueDowngradeArraySpread/Fixture/merge_const.php.inc @@ -65,8 +65,10 @@ class MergeConst private const EXPECTED_KINDS_GENERIC = [ \T_ABSTRACT, - \T_FINAL, \T_PRIVATE, - \T_PROTECTED, \T_PUBLIC, + \T_FINAL, + \T_PRIVATE, + \T_PROTECTED, + \T_PUBLIC, \T_STATIC, \T_VAR, CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PUBLIC, diff --git a/tests/Issues/IssueDowngradeArraySpread/config/configured_rule.php b/tests/Issues/IssueDowngradeArraySpread/config/configured_rule.php index a5a37c94..535ef1ec 100644 --- a/tests/Issues/IssueDowngradeArraySpread/config/configured_rule.php +++ b/tests/Issues/IssueDowngradeArraySpread/config/configured_rule.php @@ -9,7 +9,7 @@ return static function (RectorConfig $rectorConfig): void { $rectorConfig->rules([ - DowngradeArraySpreadStringKeyRector::class, + //DowngradeArraySpreadStringKeyRector::class, DowngradeArraySpreadRector::class ]); From 80fc36da9d95c364810702153f439b7f40e2d7cf Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Sun, 10 Aug 2025 09:28:16 +0700 Subject: [PATCH 05/11] remove comment --- .../Issues/IssueDowngradeArraySpread/config/configured_rule.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Issues/IssueDowngradeArraySpread/config/configured_rule.php b/tests/Issues/IssueDowngradeArraySpread/config/configured_rule.php index 535ef1ec..a5a37c94 100644 --- a/tests/Issues/IssueDowngradeArraySpread/config/configured_rule.php +++ b/tests/Issues/IssueDowngradeArraySpread/config/configured_rule.php @@ -9,7 +9,7 @@ return static function (RectorConfig $rectorConfig): void { $rectorConfig->rules([ - //DowngradeArraySpreadStringKeyRector::class, + DowngradeArraySpreadStringKeyRector::class, DowngradeArraySpreadRector::class ]); From 221d5c8a4dad621cd5b9ed334cb686b6a296645b Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Sun, 10 Aug 2025 02:28:56 +0000 Subject: [PATCH 06/11] [ci-review] Rector Rectify --- .../IssueDowngradeArraySpread/config/configured_rule.php | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/tests/Issues/IssueDowngradeArraySpread/config/configured_rule.php b/tests/Issues/IssueDowngradeArraySpread/config/configured_rule.php index a5a37c94..b826c5b5 100644 --- a/tests/Issues/IssueDowngradeArraySpread/config/configured_rule.php +++ b/tests/Issues/IssueDowngradeArraySpread/config/configured_rule.php @@ -8,10 +8,7 @@ use Rector\ValueObject\PhpVersion; return static function (RectorConfig $rectorConfig): void { - $rectorConfig->rules([ - DowngradeArraySpreadStringKeyRector::class, - DowngradeArraySpreadRector::class - ]); + $rectorConfig->rules([DowngradeArraySpreadStringKeyRector::class, DowngradeArraySpreadRector::class]); $rectorConfig->phpVersion(PhpVersion::PHP_81); }; From 4f369842ef921821828e54302bc53932ce81e877 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Sun, 10 Aug 2025 10:34:30 +0700 Subject: [PATCH 07/11] Fix --- .../Fixture/on_class_constant.php.inc | 6 +---- .../Array_/DowngradeArraySpreadRector.php | 25 +++++++++++++------ .../Fixture/merge_const.php.inc | 25 +------------------ 3 files changed, 19 insertions(+), 37 deletions(-) diff --git a/rules-tests/DowngradePhp74/Rector/Array_/DowngradeArraySpreadRector/Fixture/on_class_constant.php.inc b/rules-tests/DowngradePhp74/Rector/Array_/DowngradeArraySpreadRector/Fixture/on_class_constant.php.inc index 6bfa8f33..b87cb0c4 100644 --- a/rules-tests/DowngradePhp74/Rector/Array_/DowngradeArraySpreadRector/Fixture/on_class_constant.php.inc +++ b/rules-tests/DowngradePhp74/Rector/Array_/DowngradeArraySpreadRector/Fixture/on_class_constant.php.inc @@ -24,11 +24,7 @@ abstract class OnClassConstant { private const TYPE_END_TOKENS = [')', [T_CALLABLE], [T_NS_SEPARATOR], [T_STATIC], [T_STRING], [CT::T_ARRAY_TYPEHINT]]; - private const TYPE_TOKENS = [ - '|', '&', '(', ')', [T_CALLABLE], [T_NS_SEPARATOR], [T_STATIC], [T_STRING], [CT::T_ARRAY_TYPEHINT], - [CT::T_TYPE_ALTERNATION], [CT::T_TYPE_INTERSECTION], - [T_WHITESPACE], [T_COMMENT], [T_DOC_COMMENT], - ]; + private const TYPE_TOKENS = ['|', '&', '(', ')', [T_CALLABLE], [T_NS_SEPARATOR], [T_STATIC], [T_STRING], [CT::T_ARRAY_TYPEHINT], [CT::T_TYPE_ALTERNATION], [CT::T_TYPE_INTERSECTION], [T_WHITESPACE], [T_COMMENT], [T_DOC_COMMENT]]; } ?> diff --git a/rules/DowngradePhp74/Rector/Array_/DowngradeArraySpreadRector.php b/rules/DowngradePhp74/Rector/Array_/DowngradeArraySpreadRector.php index 88c2adf0..39df6186 100644 --- a/rules/DowngradePhp74/Rector/Array_/DowngradeArraySpreadRector.php +++ b/rules/DowngradePhp74/Rector/Array_/DowngradeArraySpreadRector.php @@ -12,7 +12,6 @@ use PhpParser\Node\Name; use PhpParser\Node\Stmt\ClassConst; use PhpParser\Node\Stmt\ClassLike; -use PHPStan\Analyser\MutatingScope; use PHPStan\Type\Type; use Rector\DowngradePhp81\NodeAnalyzer\ArraySpreadAnalyzer; use Rector\DowngradePhp81\NodeFactory\ArrayMergeFromArraySpreadFactory; @@ -23,6 +22,7 @@ use Rector\StaticTypeMapper\ValueObject\Type\FullyQualifiedObjectType; use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample; use Symplify\RuleDocGenerator\ValueObject\RuleDefinition; +use PHPStan\Analyser\MutatingScope; /** * @changelog https://wiki.php.net/rfc/spread_operator_for_array @@ -123,12 +123,19 @@ private function refactorUnderClassConst(ClassConst $classConst): ?ClassConst $hasChanged = false; - foreach ($arrays as $array) { - $refactorArrayConstValue = $this->refactorArrayConstValue($array); + $this->traverseNodesWithCallable($classConst->consts, function (Node $subNode) use (&$hasChanged): ?Node { + if (! $subNode instanceof Array_) { + return null; + } + + $refactorArrayConstValue = $this->refactorArrayConstValue($subNode); if ($refactorArrayConstValue instanceof Array_) { $hasChanged = true; + return $refactorArrayConstValue; } - } + + return null; + }); if ($hasChanged) { return $classConst; @@ -166,9 +173,11 @@ private function refactorArrayConstValue(Array_ $array): ?Array_ { $hasChanged = false; - foreach ($array->items as $key => $item) { + $newArray = new Array_(); + foreach ($array->items as $item) { $type = $this->resolveItemType($item); if (! $type instanceof FullyQualifiedObjectType) { + $newArray->items[] = $item; continue; } @@ -179,6 +188,7 @@ private function refactorArrayConstValue(Array_ $array): ?Array_ /** @var Identifier $name */ $classLike = $this->astResolver->resolveClassFromName($type->getClassName()); if (! $classLike instanceof ClassLike) { + $newArray->items[] = $item; continue; } @@ -188,8 +198,7 @@ private function refactorArrayConstValue(Array_ $array): ?Array_ $const = $constant->consts[0]; if ($const->name->toString() === $name->toString() && $const->value instanceof Array_) { - unset($array->items[$key]); - array_splice($array->items, $key, 0, $const->value->items); + $newArray->items = array_merge($newArray->items, $const->value->items); $hasChanged = true; } @@ -197,7 +206,7 @@ private function refactorArrayConstValue(Array_ $array): ?Array_ } if ($hasChanged) { - return $array; + return $newArray; } return null; diff --git a/tests/Issues/IssueDowngradeArraySpread/Fixture/merge_const.php.inc b/tests/Issues/IssueDowngradeArraySpread/Fixture/merge_const.php.inc index 181651e3..b5e317dc 100644 --- a/tests/Issues/IssueDowngradeArraySpread/Fixture/merge_const.php.inc +++ b/tests/Issues/IssueDowngradeArraySpread/Fixture/merge_const.php.inc @@ -80,30 +80,7 @@ class MergeConst FCT::T_PUBLIC_SET ]; - private const EXPECTED_KINDS_PROPERTY_KINDS = [ - \T_ABSTRACT, - \T_FINAL, - \T_PRIVATE, - \T_PROTECTED, - \T_PUBLIC, - \T_STATIC, - \T_VAR, - CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PUBLIC, - CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PROTECTED, - CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PRIVATE, - FCT::T_READONLY, - FCT::T_PRIVATE_SET, - FCT::T_PROTECTED_SET, - FCT::T_PUBLIC_SET, - \T_STRING, - \T_NS_SEPARATOR, - CT::T_NULLABLE_TYPE, - CT::T_ARRAY_TYPEHINT, - CT::T_TYPE_ALTERNATION, - CT::T_TYPE_INTERSECTION, - CT::T_DISJUNCTIVE_NORMAL_FORM_TYPE_PARENTHESIS_OPEN, - CT::T_DISJUNCTIVE_NORMAL_FORM_TYPE_PARENTHESIS_CLOSE - ]; + private const EXPECTED_KINDS_PROPERTY_KINDS = [\T_ABSTRACT, \T_FINAL, \T_PRIVATE, \T_PROTECTED, \T_PUBLIC, \T_STATIC, \T_VAR, CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PUBLIC, CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PROTECTED, CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PRIVATE, FCT::T_READONLY, FCT::T_PRIVATE_SET, FCT::T_PROTECTED_SET, FCT::T_PUBLIC_SET, \T_STRING, \T_NS_SEPARATOR, CT::T_NULLABLE_TYPE, CT::T_ARRAY_TYPEHINT, CT::T_TYPE_ALTERNATION, CT::T_TYPE_INTERSECTION, CT::T_DISJUNCTIVE_NORMAL_FORM_TYPE_PARENTHESIS_OPEN, CT::T_DISJUNCTIVE_NORMAL_FORM_TYPE_PARENTHESIS_CLOSE]; } ?> From b6569e13108b8c84c4622c1b28b0a1e3ae5565b0 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Sun, 10 Aug 2025 03:35:16 +0000 Subject: [PATCH 08/11] [ci-review] Rector Rectify --- .../DowngradePhp74/Rector/Array_/DowngradeArraySpreadRector.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rules/DowngradePhp74/Rector/Array_/DowngradeArraySpreadRector.php b/rules/DowngradePhp74/Rector/Array_/DowngradeArraySpreadRector.php index 39df6186..618066cf 100644 --- a/rules/DowngradePhp74/Rector/Array_/DowngradeArraySpreadRector.php +++ b/rules/DowngradePhp74/Rector/Array_/DowngradeArraySpreadRector.php @@ -12,6 +12,7 @@ use PhpParser\Node\Name; use PhpParser\Node\Stmt\ClassConst; use PhpParser\Node\Stmt\ClassLike; +use PHPStan\Analyser\MutatingScope; use PHPStan\Type\Type; use Rector\DowngradePhp81\NodeAnalyzer\ArraySpreadAnalyzer; use Rector\DowngradePhp81\NodeFactory\ArrayMergeFromArraySpreadFactory; @@ -22,7 +23,6 @@ use Rector\StaticTypeMapper\ValueObject\Type\FullyQualifiedObjectType; use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample; use Symplify\RuleDocGenerator\ValueObject\RuleDefinition; -use PHPStan\Analyser\MutatingScope; /** * @changelog https://wiki.php.net/rfc/spread_operator_for_array From d2d205fe307edd6e6894b4100c77e4e5a13b10f8 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Sun, 10 Aug 2025 10:37:28 +0700 Subject: [PATCH 09/11] avoid invalid append --- .../Rector/Array_/DowngradeArraySpreadRector.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/rules/DowngradePhp74/Rector/Array_/DowngradeArraySpreadRector.php b/rules/DowngradePhp74/Rector/Array_/DowngradeArraySpreadRector.php index 618066cf..f6b6dbb0 100644 --- a/rules/DowngradePhp74/Rector/Array_/DowngradeArraySpreadRector.php +++ b/rules/DowngradePhp74/Rector/Array_/DowngradeArraySpreadRector.php @@ -194,6 +194,7 @@ private function refactorArrayConstValue(Array_ $array): ?Array_ $constants = $classLike->getConstants(); + $hasChangedOnCurrentIteration = false; foreach ($constants as $constant) { $const = $constant->consts[0]; @@ -201,8 +202,14 @@ private function refactorArrayConstValue(Array_ $array): ?Array_ $newArray->items = array_merge($newArray->items, $const->value->items); $hasChanged = true; + $hasChangedOnCurrentIteration = true; } } + + if (! $hasChangedOnCurrentIteration) { + $newArray->items[] = $item; + } + } if ($hasChanged) { From 250b41626c7f7c3a555ff47f6bb63db08c10b73d Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Sun, 10 Aug 2025 10:42:39 +0700 Subject: [PATCH 10/11] Revert "avoid invalid append" This reverts commit d2d205fe307edd6e6894b4100c77e4e5a13b10f8. --- .../Rector/Array_/DowngradeArraySpreadRector.php | 7 ------- 1 file changed, 7 deletions(-) diff --git a/rules/DowngradePhp74/Rector/Array_/DowngradeArraySpreadRector.php b/rules/DowngradePhp74/Rector/Array_/DowngradeArraySpreadRector.php index f6b6dbb0..618066cf 100644 --- a/rules/DowngradePhp74/Rector/Array_/DowngradeArraySpreadRector.php +++ b/rules/DowngradePhp74/Rector/Array_/DowngradeArraySpreadRector.php @@ -194,7 +194,6 @@ private function refactorArrayConstValue(Array_ $array): ?Array_ $constants = $classLike->getConstants(); - $hasChangedOnCurrentIteration = false; foreach ($constants as $constant) { $const = $constant->consts[0]; @@ -202,14 +201,8 @@ private function refactorArrayConstValue(Array_ $array): ?Array_ $newArray->items = array_merge($newArray->items, $const->value->items); $hasChanged = true; - $hasChangedOnCurrentIteration = true; } } - - if (! $hasChangedOnCurrentIteration) { - $newArray->items[] = $item; - } - } if ($hasChanged) { From f9c163ce96a453f212958ff6963077ce691648b1 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Sun, 10 Aug 2025 15:12:26 +0700 Subject: [PATCH 11/11] clean up --- .../Fixture/on_class_constant.php.inc | 6 +++++- .../Rector/Array_/DowngradeArraySpreadRector.php | 6 ++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/rules-tests/DowngradePhp74/Rector/Array_/DowngradeArraySpreadRector/Fixture/on_class_constant.php.inc b/rules-tests/DowngradePhp74/Rector/Array_/DowngradeArraySpreadRector/Fixture/on_class_constant.php.inc index b87cb0c4..6bfa8f33 100644 --- a/rules-tests/DowngradePhp74/Rector/Array_/DowngradeArraySpreadRector/Fixture/on_class_constant.php.inc +++ b/rules-tests/DowngradePhp74/Rector/Array_/DowngradeArraySpreadRector/Fixture/on_class_constant.php.inc @@ -24,7 +24,11 @@ abstract class OnClassConstant { private const TYPE_END_TOKENS = [')', [T_CALLABLE], [T_NS_SEPARATOR], [T_STATIC], [T_STRING], [CT::T_ARRAY_TYPEHINT]]; - private const TYPE_TOKENS = ['|', '&', '(', ')', [T_CALLABLE], [T_NS_SEPARATOR], [T_STATIC], [T_STRING], [CT::T_ARRAY_TYPEHINT], [CT::T_TYPE_ALTERNATION], [CT::T_TYPE_INTERSECTION], [T_WHITESPACE], [T_COMMENT], [T_DOC_COMMENT]]; + private const TYPE_TOKENS = [ + '|', '&', '(', ')', [T_CALLABLE], [T_NS_SEPARATOR], [T_STATIC], [T_STRING], [CT::T_ARRAY_TYPEHINT], + [CT::T_TYPE_ALTERNATION], [CT::T_TYPE_INTERSECTION], + [T_WHITESPACE], [T_COMMENT], [T_DOC_COMMENT], + ]; } ?> diff --git a/rules/DowngradePhp74/Rector/Array_/DowngradeArraySpreadRector.php b/rules/DowngradePhp74/Rector/Array_/DowngradeArraySpreadRector.php index 618066cf..a6b552f5 100644 --- a/rules/DowngradePhp74/Rector/Array_/DowngradeArraySpreadRector.php +++ b/rules/DowngradePhp74/Rector/Array_/DowngradeArraySpreadRector.php @@ -174,10 +174,12 @@ private function refactorArrayConstValue(Array_ $array): ?Array_ $hasChanged = false; $newArray = new Array_(); + $newArray->setAttributes($array->getAttributes()); + foreach ($array->items as $item) { + $newArray->items[] = $item; $type = $this->resolveItemType($item); if (! $type instanceof FullyQualifiedObjectType) { - $newArray->items[] = $item; continue; } @@ -188,7 +190,6 @@ private function refactorArrayConstValue(Array_ $array): ?Array_ /** @var Identifier $name */ $classLike = $this->astResolver->resolveClassFromName($type->getClassName()); if (! $classLike instanceof ClassLike) { - $newArray->items[] = $item; continue; } @@ -198,6 +199,7 @@ private function refactorArrayConstValue(Array_ $array): ?Array_ $const = $constant->consts[0]; if ($const->name->toString() === $name->toString() && $const->value instanceof Array_) { + array_pop($newArray->items); $newArray->items = array_merge($newArray->items, $const->value->items); $hasChanged = true;