Skip to content

Commit 7843966

Browse files
authored
[Renaming] Add RenameCastRector (#7117)
While there is already `RealToFloatTypeCastRector` to handle the deprecation of the `(real)` cast, this generalized rector rule will allow to configure the cast renaming and thus also support other types of cast renamings.
1 parent 1e7f7ea commit 7843966

File tree

5 files changed

+178
-0
lines changed

5 files changed

+178
-0
lines changed
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php
2+
3+
namespace Rector\Tests\Renaming\Rector\Cast\RenameCastRector\Fixture;
4+
5+
$real = (real) $real;
6+
$double = (double) $double;
7+
8+
?>
9+
-----
10+
<?php
11+
12+
namespace Rector\Tests\Renaming\Rector\Cast\RenameCastRector\Fixture;
13+
14+
$real = (float) $real;
15+
$double = (float) $double;
16+
17+
?>
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php
2+
3+
namespace Rector\Tests\Renaming\Rector\Cast\RenameCastRector;
4+
5+
use Iterator;
6+
use PHPUnit\Framework\Attributes\DataProvider;
7+
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
8+
9+
class RenameCastRectorTest extends AbstractRectorTestCase
10+
{
11+
#[DataProvider('provideData')]
12+
public function test(string $filePath): void
13+
{
14+
$this->doTestFile($filePath);
15+
}
16+
17+
public static function provideData(): Iterator
18+
{
19+
return self::yieldFilesFromDirectory(__DIR__ . '/Fixture');
20+
}
21+
22+
public function provideConfigFilePath(): string
23+
{
24+
return __DIR__ . '/config/configured_rule.php';
25+
}
26+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
use PhpParser\Node\Expr\Cast\Double;
6+
use Rector\Config\RectorConfig;
7+
use Rector\Renaming\Rector\Cast\RenameCastRector;
8+
use Rector\Renaming\ValueObject\RenameCast;
9+
10+
return static function (RectorConfig $rectorConfig): void {
11+
$rectorConfig
12+
->ruleWithConfiguration(RenameCastRector::class, [
13+
new RenameCast(Double::class, Double::KIND_REAL, Double::KIND_FLOAT),
14+
new RenameCast(Double::class, Double::KIND_DOUBLE, Double::KIND_FLOAT),
15+
]);
16+
};
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Rector\Renaming\Rector\Cast;
6+
7+
use PhpParser\Node;
8+
use PhpParser\Node\Expr\Cast;
9+
use PhpParser\Node\Expr\Cast\Double;
10+
use Rector\Contract\Rector\ConfigurableRectorInterface;
11+
use Rector\NodeTypeResolver\Node\AttributeKey;
12+
use Rector\Rector\AbstractRector;
13+
use Rector\Renaming\ValueObject\RenameCast;
14+
use Symplify\RuleDocGenerator\ValueObject\CodeSample\ConfiguredCodeSample;
15+
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
16+
use Webmozart\Assert\Assert;
17+
18+
/**
19+
* @see \Rector\Tests\Renaming\Rector\Cast\RenameCastRector\RenameCastRectorTest
20+
*/
21+
final class RenameCastRector extends AbstractRector implements ConfigurableRectorInterface
22+
{
23+
/**
24+
* @var array<RenameCast>
25+
*/
26+
private array $renameCasts = [];
27+
28+
public function getRuleDefinition(): RuleDefinition
29+
{
30+
return new RuleDefinition('Renames casts', [
31+
new ConfiguredCodeSample(
32+
'$real = (real) $real;',
33+
'$real = (float) $real;',
34+
[new RenameCast(Double::class, Double::KIND_REAL, Double::KIND_FLOAT)]
35+
),
36+
]);
37+
}
38+
39+
/**
40+
* @return array<class-string<Node>>
41+
*/
42+
public function getNodeTypes(): array
43+
{
44+
return [Cast::class];
45+
}
46+
47+
/**
48+
* @param Cast $node
49+
*/
50+
public function refactor(Node $node): ?Node
51+
{
52+
foreach ($this->renameCasts as $renameCast) {
53+
$expectedClassName = $renameCast->getFromCastExprClass();
54+
if (
55+
! $node instanceof $expectedClassName
56+
|| $node->getAttribute(AttributeKey::KIND) !== $renameCast->getFromCastKind()
57+
) {
58+
continue;
59+
}
60+
61+
$node->setAttribute(AttributeKey::KIND, $renameCast->getToCastKind());
62+
$node->setAttribute(AttributeKey::ORIGINAL_NODE, null);
63+
64+
return $node;
65+
}
66+
67+
return null;
68+
}
69+
70+
/**
71+
* @param mixed[] $configuration
72+
*/
73+
public function configure(array $configuration): void
74+
{
75+
Assert::allIsInstanceOf($configuration, RenameCast::class);
76+
77+
$this->renameCasts = $configuration;
78+
}
79+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Rector\Renaming\ValueObject;
6+
7+
use PhpParser\Node\Expr\Cast;
8+
use Rector\Validation\RectorAssert;
9+
use Webmozart\Assert\Assert;
10+
11+
final readonly class RenameCast
12+
{
13+
public function __construct(
14+
/** @var class-string<Cast> */
15+
private string $fromCastExprClass,
16+
private int $fromCastKind,
17+
private int $toCastKind,
18+
) {
19+
RectorAssert::className($fromCastExprClass);
20+
Assert::subclassOf($fromCastExprClass, Cast::class);
21+
}
22+
23+
/**
24+
* @return class-string<Cast>
25+
*/
26+
public function getFromCastExprClass(): string
27+
{
28+
return $this->fromCastExprClass;
29+
}
30+
31+
public function getFromCastKind(): int
32+
{
33+
return $this->fromCastKind;
34+
}
35+
36+
public function getToCastKind(): int
37+
{
38+
return $this->toCastKind;
39+
}
40+
}

0 commit comments

Comments
 (0)