diff --git a/config/sets/typed-collections.php b/config/sets/typed-collections.php index 970de922..558fdd24 100644 --- a/config/sets/typed-collections.php +++ b/config/sets/typed-collections.php @@ -29,6 +29,7 @@ use Rector\Doctrine\TypedCollections\Rector\If_\RemoveIfCollectionIdenticalToNullRector; use Rector\Doctrine\TypedCollections\Rector\If_\RemoveIfInstanceofCollectionRector; use Rector\Doctrine\TypedCollections\Rector\If_\RemoveIsArrayOnCollectionRector; +use Rector\Doctrine\TypedCollections\Rector\If_\RemoveUselessIsEmptyAssignRector; use Rector\Doctrine\TypedCollections\Rector\MethodCall\AssertNullOnCollectionToAssertEmptyRector; use Rector\Doctrine\TypedCollections\Rector\MethodCall\AssertSameCountOnCollectionToAssertCountRector; use Rector\Doctrine\TypedCollections\Rector\MethodCall\SetArrayToNewCollectionRector; @@ -87,6 +88,7 @@ // cleanup RemoveNullsafeOnCollectionRector::class, + RemoveUselessIsEmptyAssignRector::class, // test assertions RemoveAssertNotNullOnCollectionRector::class, diff --git a/rules-tests/TypedCollections/Rector/If_/RemoveUselessIsEmptyAssignRector/Fixture/remove_useless.php.inc b/rules-tests/TypedCollections/Rector/If_/RemoveUselessIsEmptyAssignRector/Fixture/remove_useless.php.inc new file mode 100644 index 00000000..1df028e7 --- /dev/null +++ b/rules-tests/TypedCollections/Rector/If_/RemoveUselessIsEmptyAssignRector/Fixture/remove_useless.php.inc @@ -0,0 +1,41 @@ +items->isEmpty()) { + $this->items = new ArrayCollection(); + } + + return $this->items; + } +} + +?> +----- +items; + } +} + +?> diff --git a/rules-tests/TypedCollections/Rector/If_/RemoveUselessIsEmptyAssignRector/Fixture/skip_different_new.php.inc b/rules-tests/TypedCollections/Rector/If_/RemoveUselessIsEmptyAssignRector/Fixture/skip_different_new.php.inc new file mode 100644 index 00000000..fe0c5f1d --- /dev/null +++ b/rules-tests/TypedCollections/Rector/If_/RemoveUselessIsEmptyAssignRector/Fixture/skip_different_new.php.inc @@ -0,0 +1,20 @@ +items->isEmpty()) { + $this->items = new \stdClass(); + } + + return $this->items; + } +} diff --git a/rules-tests/TypedCollections/Rector/If_/RemoveUselessIsEmptyAssignRector/Fixture/skip_different_variable.php.inc b/rules-tests/TypedCollections/Rector/If_/RemoveUselessIsEmptyAssignRector/Fixture/skip_different_variable.php.inc new file mode 100644 index 00000000..65169ba4 --- /dev/null +++ b/rules-tests/TypedCollections/Rector/If_/RemoveUselessIsEmptyAssignRector/Fixture/skip_different_variable.php.inc @@ -0,0 +1,20 @@ +items->isEmpty()) { + $this->another = new ArrayCollection(); + } + + return $this->items; + } +} diff --git a/rules-tests/TypedCollections/Rector/If_/RemoveUselessIsEmptyAssignRector/RemoveUselessIsEmptyAssignRectorTest.php b/rules-tests/TypedCollections/Rector/If_/RemoveUselessIsEmptyAssignRector/RemoveUselessIsEmptyAssignRectorTest.php new file mode 100644 index 00000000..d898bc78 --- /dev/null +++ b/rules-tests/TypedCollections/Rector/If_/RemoveUselessIsEmptyAssignRector/RemoveUselessIsEmptyAssignRectorTest.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/If_/RemoveUselessIsEmptyAssignRector/config/configured_rule.php b/rules-tests/TypedCollections/Rector/If_/RemoveUselessIsEmptyAssignRector/config/configured_rule.php new file mode 100644 index 00000000..937120a3 --- /dev/null +++ b/rules-tests/TypedCollections/Rector/If_/RemoveUselessIsEmptyAssignRector/config/configured_rule.php @@ -0,0 +1,10 @@ +rule(RemoveUselessIsEmptyAssignRector::class); +}; diff --git a/rules/TypedCollections/Rector/If_/RemoveUselessIsEmptyAssignRector.php b/rules/TypedCollections/Rector/If_/RemoveUselessIsEmptyAssignRector.php new file mode 100644 index 00000000..0ee37a6e --- /dev/null +++ b/rules/TypedCollections/Rector/If_/RemoveUselessIsEmptyAssignRector.php @@ -0,0 +1,132 @@ +cond instanceof MethodCall) { + return null; + } + + $methodCall = $node->cond; + if (! $this->isName($methodCall->name, 'isEmpty')) { + return null; + } + + if (! $this->collectionTypeDetector->isCollectionType($methodCall->var)) { + return null; + } + + if (count($node->stmts) !== 1) { + return null; + } + + $soleStmts = $node->stmts[0]; + + if (! $soleStmts instanceof Expression) { + return null; + } + + if (! $soleStmts->expr instanceof Assign) { + return null; + } + + $assign = $soleStmts->expr; + if (! $this->nodeNameResolver->areNamesEqual($assign->var, $methodCall->var)) { + return null; + } + + if (! $this->isArrayCollectionNewInstance($assign->expr)) { + return null; + } + + return NodeVisitor::REMOVE_NODE; + } + + public function getRuleDefinition(): RuleDefinition + { + return new RuleDefinition( + 'Remove useless isEmpty() check on collection with following new ArrayCollection() instance', + [ + new CodeSample( + <<<'CODE_SAMPLE' +use Doctrine\Common\Collections\Collection; + +final class SomeClass +{ + private Collection $collection; + + public function someMethod() + { + if ($this->collection->isEmpty()) { + $this->collection = new ArrayCollection(); + } + + return $this->collection; + } +} +CODE_SAMPLE + , + <<<'CODE_SAMPLE' +use Doctrine\Common\Collections\Collection; + +final class SomeClass +{ + private Collection $collection; + + public function someMethod() + { + return $this->collection; + } +} +CODE_SAMPLE + ), + + ] + ); + } + + private function isArrayCollectionNewInstance(Expr $expr): bool + { + if (! $expr instanceof New_) { + return true; + } + + return $this->isName($expr->class, DoctrineClass::ARRAY_COLLECTION); + } +}