Skip to content

Commit 8152f51

Browse files
authored
[typed-collections] Add CurrentOnCollectionToArrayRector (#438)
1 parent b11f55f commit 8152f51

6 files changed

Lines changed: 199 additions & 0 deletions

File tree

config/sets/typed-collections.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
use Rector\Doctrine\TypedCollections\Rector\Expression\RemoveCoalesceAssignOnCollectionRector;
2626
use Rector\Doctrine\TypedCollections\Rector\FuncCall\ArrayMapOnCollectionToArrayRector;
2727
use Rector\Doctrine\TypedCollections\Rector\FuncCall\ArrayMergeOnCollectionToArrayRector;
28+
use Rector\Doctrine\TypedCollections\Rector\FuncCall\CurrentOnCollectionToArrayRector;
2829
use Rector\Doctrine\TypedCollections\Rector\FuncCall\InArrayOnCollectionToContainsCallRector;
2930
use Rector\Doctrine\TypedCollections\Rector\If_\RemoveIfCollectionIdenticalToNullRector;
3031
use Rector\Doctrine\TypedCollections\Rector\If_\RemoveIfInstanceofCollectionRector;
@@ -54,6 +55,7 @@
5455
ArrayOffsetSetToSetCollectionCallRector::class,
5556
ArrayMapOnCollectionToArrayRector::class,
5657
ArrayMergeOnCollectionToArrayRector::class,
58+
CurrentOnCollectionToArrayRector::class,
5759
EmptyOnCollectionToIsEmptyCallRector::class,
5860
InArrayOnCollectionToContainsCallRector::class,
5961

Lines changed: 28 additions & 0 deletions
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\FuncCall\CurrentOnCollectionToArrayRector;
6+
7+
use Iterator;
8+
use PHPUnit\Framework\Attributes\DataProvider;
9+
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
10+
11+
final class CurrentOnCollectionToArrayRectorTest 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: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Rector\Doctrine\Tests\TypedCollections\Rector\FuncCall\CurrentOnCollectionToArrayRector\Fixture;
6+
7+
use Doctrine\Common\Collections\Collection;
8+
9+
final class SimpleClass
10+
{
11+
/**
12+
* @var Collection<int, string>
13+
*/
14+
public $items;
15+
16+
public function merge()
17+
{
18+
return current($this->items);
19+
}
20+
}
21+
22+
?>
23+
-----
24+
<?php
25+
26+
declare(strict_types=1);
27+
28+
namespace Rector\Doctrine\Tests\TypedCollections\Rector\FuncCall\CurrentOnCollectionToArrayRector\Fixture;
29+
30+
use Doctrine\Common\Collections\Collection;
31+
32+
final class SimpleClass
33+
{
34+
/**
35+
* @var Collection<int, string>
36+
*/
37+
public $items;
38+
39+
public function merge()
40+
{
41+
return current($this->items->toArray());
42+
}
43+
}
44+
45+
?>
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Rector\Doctrine\Tests\TypedCollections\Rector\FuncCall\CurrentOnCollectionToArrayRector\Fixture;
6+
7+
final class SkipNonCollection
8+
{
9+
/**
10+
* @var array<int, string>
11+
*/
12+
public $items;
13+
14+
public function merge()
15+
{
16+
return current($this->items);
17+
}
18+
}
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\FuncCall\CurrentOnCollectionToArrayRector;
7+
8+
return static function (RectorConfig $rectorConfig): void {
9+
$rectorConfig->rule(CurrentOnCollectionToArrayRector::class);
10+
};
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Rector\Doctrine\TypedCollections\Rector\FuncCall;
6+
7+
use PhpParser\Node;
8+
use PhpParser\Node\Expr\FuncCall;
9+
use PhpParser\Node\Expr\MethodCall;
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\FuncCall\CurrentOnCollectionToArrayRector\CurrentOnCollectionToArrayRectorTest
17+
*/
18+
final class CurrentOnCollectionToArrayRector 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(
28+
'Change current() on Collection typed property to ->toArray() call, to always provide an array',
29+
[
30+
new CodeSample(
31+
<<<'CODE_SAMPLE'
32+
use Doctrine\Common\Collections\Collection;
33+
34+
final class SimpleClass
35+
{
36+
/**
37+
* @var Collection<int, string>
38+
*/
39+
public $items;
40+
41+
public function merge()
42+
{
43+
return current($this->items);
44+
}
45+
}
46+
CODE_SAMPLE
47+
,
48+
<<<'CODE_SAMPLE'
49+
use Doctrine\Common\Collections\Collection;
50+
51+
final class SimpleClass
52+
{
53+
/**
54+
* @var Collection<int, string>
55+
*/
56+
public $items;
57+
58+
public function merge()
59+
{
60+
return current($this->items->toArray());
61+
}
62+
}
63+
CODE_SAMPLE
64+
),
65+
]
66+
);
67+
}
68+
69+
public function getNodeTypes(): array
70+
{
71+
return [FuncCall::class];
72+
}
73+
74+
/**
75+
* @param FuncCall $node
76+
*/
77+
public function refactor(Node $node): ?FuncCall
78+
{
79+
if ($node->isFirstClassCallable()) {
80+
return null;
81+
}
82+
83+
if (! $this->isName($node->name, 'current')) {
84+
return null;
85+
}
86+
87+
$secondArg = $node->getArgs()[0];
88+
if (! $this->collectionTypeDetector->isCollectionType($secondArg->value)) {
89+
return null;
90+
}
91+
92+
$secondArg->value = new MethodCall($secondArg->value, 'toArray');
93+
94+
return $node;
95+
}
96+
}

0 commit comments

Comments
 (0)