Skip to content

Commit aeb1421

Browse files
authored
[typed-collections] Add RemoveNullsafeOnCollectionRector (#420)
1 parent 5717673 commit aeb1421

7 files changed

Lines changed: 177 additions & 0 deletions

File tree

config/sets/typed-collections.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
use Rector\Doctrine\TypedCollections\Rector\If_\RemoveIsArrayOnCollectionRector;
2929
use Rector\Doctrine\TypedCollections\Rector\MethodCall\SetArrayToNewCollectionRector;
3030
use Rector\Doctrine\TypedCollections\Rector\New_\RemoveNewArrayCollectionWrapRector;
31+
use Rector\Doctrine\TypedCollections\Rector\NullsafeMethodCall\RemoveNullsafeOnCollectionRector;
3132
use Rector\Doctrine\TypedCollections\Rector\Property\NarrowPropertyUnionToCollectionRector;
3233
use Rector\Doctrine\TypedCollections\Rector\Property\TypedPropertyFromToManyRelationTypeRector;
3334

@@ -76,5 +77,8 @@
7677
ReturnArrayToNewArrayCollectionRector::class,
7778
SetArrayToNewCollectionRector::class,
7879
RemoveNewArrayCollectionWrapRector::class,
80+
81+
// cleanup
82+
RemoveNullsafeOnCollectionRector::class,
7983
]);
8084
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php
2+
3+
namespace Rector\Doctrine\Tests\TypedCollections\Rector\NullsafeMethodCall\RemoveNullsafeOnCollectionRector\Fixture;
4+
5+
use Doctrine\Common\Collections\ArrayCollection;
6+
use Doctrine\Common\Collections\Collection;
7+
8+
final class RedundantNullsafeOnCollection
9+
{
10+
public Collection $items;
11+
12+
public function someMethod()
13+
{
14+
$values = $this->items?->count();
15+
}
16+
}
17+
18+
?>
19+
-----
20+
<?php
21+
22+
namespace Rector\Doctrine\Tests\TypedCollections\Rector\NullsafeMethodCall\RemoveNullsafeOnCollectionRector\Fixture;
23+
24+
use Doctrine\Common\Collections\ArrayCollection;
25+
use Doctrine\Common\Collections\Collection;
26+
27+
final class RedundantNullsafeOnCollection
28+
{
29+
public Collection $items;
30+
31+
public function someMethod()
32+
{
33+
$values = $this->items->count();
34+
}
35+
}
36+
37+
?>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
namespace Rector\Doctrine\Tests\TypedCollections\Rector\NullsafeMethodCall\RemoveNullsafeOnCollectionRector\Fixture;
4+
5+
use Doctrine\Common\Collections\ArrayCollection;
6+
use Doctrine\Common\Collections\Collection;
7+
8+
final class SkipAnotherType
9+
{
10+
public $items;
11+
12+
public function someMethod()
13+
{
14+
$values = $this->items?->count();
15+
}
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Rector\Doctrine\Tests\TypedCollections\Rector\NullsafeMethodCall\RemoveNullsafeOnCollectionRector;
6+
7+
use Iterator;
8+
use PHPUnit\Framework\Attributes\DataProvider;
9+
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
10+
11+
final class RemoveNullsafeOnCollectionRectorTest extends AbstractRectorTestCase
12+
{
13+
#[DataProvider('provideData')]
14+
public function test(string $filePath): void
15+
{
16+
$this->doTestFile($filePath);
17+
}
18+
19+
public static function provideData(): Iterator
20+
{
21+
return self::yieldFilesFromDirectory(__DIR__ . '/Fixture');
22+
}
23+
24+
public function provideConfigFilePath(): string
25+
{
26+
return __DIR__ . '/config/configured_rule.php';
27+
}
28+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
use Rector\Config\RectorConfig;
6+
use Rector\Doctrine\TypedCollections\Rector\NullsafeMethodCall\RemoveNullsafeOnCollectionRector;
7+
8+
return static function (RectorConfig $rectorConfig): void {
9+
$rectorConfig->rule(RemoveNullsafeOnCollectionRector::class);
10+
};
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Rector\Doctrine\TypedCollections\Rector\NullsafeMethodCall;
6+
7+
use PhpParser\Node;
8+
use PhpParser\Node\Expr\MethodCall;
9+
use PhpParser\Node\Expr\NullsafeMethodCall;
10+
use Rector\Doctrine\TypedCollections\TypeAnalyzer\CollectionTypeDetector;
11+
use Rector\Rector\AbstractRector;
12+
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
13+
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
14+
15+
/**
16+
* @see \Rector\Doctrine\Tests\TypedCollections\Rector\NullsafeMethodCall\RemoveNullsafeOnCollectionRector\RemoveNullsafeOnCollectionRectorTest
17+
*/
18+
final class RemoveNullsafeOnCollectionRector extends AbstractRector
19+
{
20+
public function __construct(
21+
private readonly CollectionTypeDetector $collectionTypeDetector
22+
) {
23+
}
24+
25+
public function getRuleDefinition(): RuleDefinition
26+
{
27+
return new RuleDefinition('Remove nullsafe check on method call on a Collection type', [
28+
new CodeSample(
29+
<<<'CODE_SAMPLE'
30+
use Doctrine\Common\Collections\Collection;
31+
32+
class SomeClass
33+
{
34+
private Collection $collection;
35+
36+
public function run()
37+
{
38+
return $this->collection?->empty();
39+
}
40+
}
41+
CODE_SAMPLE
42+
,
43+
<<<'CODE_SAMPLE'
44+
use Doctrine\Common\Collections\Collection;
45+
46+
class SomeClass
47+
{
48+
private Collection $collection;
49+
50+
public function run()
51+
{
52+
return $this->collection->empty();
53+
}
54+
}
55+
CODE_SAMPLE
56+
),
57+
]);
58+
}
59+
60+
public function getNodeTypes(): array
61+
{
62+
return [NullsafeMethodCall::class];
63+
}
64+
65+
/**
66+
* @param NullsafeMethodCall $node
67+
*/
68+
public function refactor(Node $node): ?MethodCall
69+
{
70+
if (! $this->collectionTypeDetector->isCollectionNonNullableType($node->var)) {
71+
return null;
72+
}
73+
74+
return new MethodCall($node->var, $node->name);
75+
}
76+
}

rules/TypedCollections/TypeAnalyzer/CollectionTypeDetector.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,12 @@ public function __construct(
2020
) {
2121
}
2222

23+
public function isCollectionNonNullableType(Expr $expr): bool
24+
{
25+
$exprType = $this->nodeTypeResolver->getType($expr);
26+
return $this->isCollectionObjectType($exprType);
27+
}
28+
2329
public function isCollectionType(Expr $expr): bool
2430
{
2531
$exprType = $this->nodeTypeResolver->getType($expr);

0 commit comments

Comments
 (0)