From 49eef5ca22303d4594f4cf92bdacded8f7e8e473 Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Fri, 13 Jun 2025 13:34:04 +0200 Subject: [PATCH] [typed-collections] Add CurrentOnCollectionToArrayRector --- config/sets/typed-collections.php | 2 + .../CurrentOnCollectionToArrayRectorTest.php | 28 ++++++ .../Fixture/simple_class.php.inc | 45 +++++++++ .../Fixture/skip_non_collection.php.inc | 18 ++++ .../config/configured_rule.php | 10 ++ .../CurrentOnCollectionToArrayRector.php | 96 +++++++++++++++++++ 6 files changed, 199 insertions(+) create mode 100644 rules-tests/TypedCollections/Rector/FuncCall/CurrentOnCollectionToArrayRector/CurrentOnCollectionToArrayRectorTest.php create mode 100644 rules-tests/TypedCollections/Rector/FuncCall/CurrentOnCollectionToArrayRector/Fixture/simple_class.php.inc create mode 100644 rules-tests/TypedCollections/Rector/FuncCall/CurrentOnCollectionToArrayRector/Fixture/skip_non_collection.php.inc create mode 100644 rules-tests/TypedCollections/Rector/FuncCall/CurrentOnCollectionToArrayRector/config/configured_rule.php create mode 100644 rules/TypedCollections/Rector/FuncCall/CurrentOnCollectionToArrayRector.php diff --git a/config/sets/typed-collections.php b/config/sets/typed-collections.php index 558fdd24..24c97ea9 100644 --- a/config/sets/typed-collections.php +++ b/config/sets/typed-collections.php @@ -25,6 +25,7 @@ use Rector\Doctrine\TypedCollections\Rector\Expression\RemoveCoalesceAssignOnCollectionRector; use Rector\Doctrine\TypedCollections\Rector\FuncCall\ArrayMapOnCollectionToArrayRector; use Rector\Doctrine\TypedCollections\Rector\FuncCall\ArrayMergeOnCollectionToArrayRector; +use Rector\Doctrine\TypedCollections\Rector\FuncCall\CurrentOnCollectionToArrayRector; use Rector\Doctrine\TypedCollections\Rector\FuncCall\InArrayOnCollectionToContainsCallRector; use Rector\Doctrine\TypedCollections\Rector\If_\RemoveIfCollectionIdenticalToNullRector; use Rector\Doctrine\TypedCollections\Rector\If_\RemoveIfInstanceofCollectionRector; @@ -54,6 +55,7 @@ ArrayOffsetSetToSetCollectionCallRector::class, ArrayMapOnCollectionToArrayRector::class, ArrayMergeOnCollectionToArrayRector::class, + CurrentOnCollectionToArrayRector::class, EmptyOnCollectionToIsEmptyCallRector::class, InArrayOnCollectionToContainsCallRector::class, diff --git a/rules-tests/TypedCollections/Rector/FuncCall/CurrentOnCollectionToArrayRector/CurrentOnCollectionToArrayRectorTest.php b/rules-tests/TypedCollections/Rector/FuncCall/CurrentOnCollectionToArrayRector/CurrentOnCollectionToArrayRectorTest.php new file mode 100644 index 00000000..9ca2b8bf --- /dev/null +++ b/rules-tests/TypedCollections/Rector/FuncCall/CurrentOnCollectionToArrayRector/CurrentOnCollectionToArrayRectorTest.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/TypedCollections/Rector/FuncCall/CurrentOnCollectionToArrayRector/Fixture/simple_class.php.inc b/rules-tests/TypedCollections/Rector/FuncCall/CurrentOnCollectionToArrayRector/Fixture/simple_class.php.inc new file mode 100644 index 00000000..13a4413d --- /dev/null +++ b/rules-tests/TypedCollections/Rector/FuncCall/CurrentOnCollectionToArrayRector/Fixture/simple_class.php.inc @@ -0,0 +1,45 @@ + + */ + public $items; + + public function merge() + { + return current($this->items); + } +} + +?> +----- + + */ + public $items; + + public function merge() + { + return current($this->items->toArray()); + } +} + +?> diff --git a/rules-tests/TypedCollections/Rector/FuncCall/CurrentOnCollectionToArrayRector/Fixture/skip_non_collection.php.inc b/rules-tests/TypedCollections/Rector/FuncCall/CurrentOnCollectionToArrayRector/Fixture/skip_non_collection.php.inc new file mode 100644 index 00000000..2c76d346 --- /dev/null +++ b/rules-tests/TypedCollections/Rector/FuncCall/CurrentOnCollectionToArrayRector/Fixture/skip_non_collection.php.inc @@ -0,0 +1,18 @@ + + */ + public $items; + + public function merge() + { + return current($this->items); + } +} diff --git a/rules-tests/TypedCollections/Rector/FuncCall/CurrentOnCollectionToArrayRector/config/configured_rule.php b/rules-tests/TypedCollections/Rector/FuncCall/CurrentOnCollectionToArrayRector/config/configured_rule.php new file mode 100644 index 00000000..e8db2885 --- /dev/null +++ b/rules-tests/TypedCollections/Rector/FuncCall/CurrentOnCollectionToArrayRector/config/configured_rule.php @@ -0,0 +1,10 @@ +rule(CurrentOnCollectionToArrayRector::class); +}; diff --git a/rules/TypedCollections/Rector/FuncCall/CurrentOnCollectionToArrayRector.php b/rules/TypedCollections/Rector/FuncCall/CurrentOnCollectionToArrayRector.php new file mode 100644 index 00000000..d869dc05 --- /dev/null +++ b/rules/TypedCollections/Rector/FuncCall/CurrentOnCollectionToArrayRector.php @@ -0,0 +1,96 @@ +toArray() call, to always provide an array', + [ + new CodeSample( + <<<'CODE_SAMPLE' +use Doctrine\Common\Collections\Collection; + +final class SimpleClass +{ + /** + * @var Collection + */ + public $items; + + public function merge() + { + return current($this->items); + } +} +CODE_SAMPLE + , + <<<'CODE_SAMPLE' +use Doctrine\Common\Collections\Collection; + +final class SimpleClass +{ + /** + * @var Collection + */ + public $items; + + public function merge() + { + return current($this->items->toArray()); + } +} +CODE_SAMPLE + ), + ] + ); + } + + public function getNodeTypes(): array + { + return [FuncCall::class]; + } + + /** + * @param FuncCall $node + */ + public function refactor(Node $node): ?FuncCall + { + if ($node->isFirstClassCallable()) { + return null; + } + + if (! $this->isName($node->name, 'current')) { + return null; + } + + $secondArg = $node->getArgs()[0]; + if (! $this->collectionTypeDetector->isCollectionType($secondArg->value)) { + return null; + } + + $secondArg->value = new MethodCall($secondArg->value, 'toArray'); + + return $node; + } +}