Skip to content

Commit 3b8b78a

Browse files
[DeadCode] Add RemoveDefaultValueFromAssignedPropertyRector (#8207)
Co-authored-by: GitHub Action <actions@github.com>
1 parent 0d55511 commit 3b8b78a

14 files changed

Lines changed: 275 additions & 4 deletions
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
namespace Rector\Tests\DeadCode\Rector\Property\RemoveDefaultValueFromAssignedPropertyRector\Fixture;
4+
5+
final class NonNullDefault
6+
{
7+
private int $value = 5;
8+
9+
public function __construct(int $value)
10+
{
11+
$this->value = $value;
12+
}
13+
}
14+
15+
?>
16+
-----
17+
<?php
18+
19+
namespace Rector\Tests\DeadCode\Rector\Property\RemoveDefaultValueFromAssignedPropertyRector\Fixture;
20+
21+
final class NonNullDefault
22+
{
23+
private int $value;
24+
25+
public function __construct(int $value)
26+
{
27+
$this->value = $value;
28+
}
29+
}
30+
31+
?>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<?php
2+
3+
namespace Rector\Tests\DeadCode\Rector\Property\RemoveDefaultValueFromAssignedPropertyRector\Fixture;
4+
5+
use stdClass;
6+
7+
final class NullableTypedProperty
8+
{
9+
private ?stdClass $value = null;
10+
11+
public function __construct(stdClass $value)
12+
{
13+
$this->value = $value;
14+
}
15+
}
16+
17+
?>
18+
-----
19+
<?php
20+
21+
namespace Rector\Tests\DeadCode\Rector\Property\RemoveDefaultValueFromAssignedPropertyRector\Fixture;
22+
23+
use stdClass;
24+
25+
final class NullableTypedProperty
26+
{
27+
private ?stdClass $value;
28+
29+
public function __construct(stdClass $value)
30+
{
31+
$this->value = $value;
32+
}
33+
}
34+
35+
?>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php
2+
3+
namespace Rector\Tests\DeadCode\Rector\Property\RemoveDefaultValueFromAssignedPropertyRector\Fixture;
4+
5+
use stdClass;
6+
7+
final class SkipConditionallyAssigned
8+
{
9+
private ?stdClass $value = null;
10+
11+
public function __construct(?stdClass $value)
12+
{
13+
if ($value instanceof stdClass) {
14+
$this->value = $value;
15+
}
16+
}
17+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
namespace Rector\Tests\DeadCode\Rector\Property\RemoveDefaultValueFromAssignedPropertyRector\Fixture;
4+
5+
use stdClass;
6+
7+
final class SkipNoConstructor
8+
{
9+
private ?stdClass $value = null;
10+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?php
2+
3+
namespace Rector\Tests\DeadCode\Rector\Property\RemoveDefaultValueFromAssignedPropertyRector\Fixture;
4+
5+
use stdClass;
6+
7+
final class SkipNotAssigned
8+
{
9+
private ?stdClass $value = null;
10+
11+
public function __construct()
12+
{
13+
}
14+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?php
2+
3+
namespace Rector\Tests\DeadCode\Rector\Property\RemoveDefaultValueFromAssignedPropertyRector\Fixture;
4+
5+
// untyped property is handled by RemoveNullPropertyInitializationRector
6+
final class SkipUntypedProperty
7+
{
8+
private $value = null;
9+
10+
public function __construct(int $value)
11+
{
12+
$this->value = $value;
13+
}
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Rector\Tests\DeadCode\Rector\Property\RemoveDefaultValueFromAssignedPropertyRector;
6+
7+
use Iterator;
8+
use PHPUnit\Framework\Attributes\DataProvider;
9+
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
10+
11+
final class RemoveDefaultValueFromAssignedPropertyRectorTest 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: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
use Rector\Config\RectorConfig;
6+
use Rector\DeadCode\Rector\Property\RemoveDefaultValueFromAssignedPropertyRector;
7+
8+
return RectorConfig::configure()
9+
->withRules([RemoveDefaultValueFromAssignedPropertyRector::class]);

‎rules/DeadCode/Rector/ConstFetch/RemovePhpVersionIdCheckRector.php‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ final class RemovePhpVersionIdCheckRector extends AbstractRector
2828
/**
2929
* @var PhpVersion::*|null
3030
*/
31-
private int|null $phpVersion = null;
31+
private int|null $phpVersion;
3232

3333
public function __construct(
3434
private readonly PhpVersionProvider $phpVersionProvider,
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Rector\DeadCode\Rector\Property;
6+
7+
use PhpParser\Node;
8+
use PhpParser\Node\Expr;
9+
use PhpParser\Node\Stmt\Class_;
10+
use PhpParser\Node\Stmt\ClassMethod;
11+
use Rector\Rector\AbstractRector;
12+
use Rector\TypeDeclaration\AlreadyAssignDetector\ConstructorAssignDetector;
13+
use Rector\ValueObject\MethodName;
14+
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
15+
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
16+
17+
/**
18+
* @see \Rector\Tests\DeadCode\Rector\Property\RemoveDefaultValueFromAssignedPropertyRector\RemoveDefaultValueFromAssignedPropertyRectorTest
19+
*/
20+
final class RemoveDefaultValueFromAssignedPropertyRector extends AbstractRector
21+
{
22+
public function __construct(
23+
private readonly ConstructorAssignDetector $constructorAssignDetector
24+
) {
25+
}
26+
27+
public function getRuleDefinition(): RuleDefinition
28+
{
29+
return new RuleDefinition(
30+
'Remove redundant default value from property that is always assigned in the constructor',
31+
[
32+
new CodeSample(
33+
<<<'CODE_SAMPLE'
34+
class SomeClass
35+
{
36+
private ?SomeType $someType = null;
37+
38+
public function __construct(SomeType $someType)
39+
{
40+
$this->someType = $someType;
41+
}
42+
}
43+
CODE_SAMPLE
44+
,
45+
<<<'CODE_SAMPLE'
46+
class SomeClass
47+
{
48+
private ?SomeType $someType;
49+
50+
public function __construct(SomeType $someType)
51+
{
52+
$this->someType = $someType;
53+
}
54+
}
55+
CODE_SAMPLE
56+
),
57+
]
58+
);
59+
}
60+
61+
/**
62+
* @return array<class-string<Node>>
63+
*/
64+
public function getNodeTypes(): array
65+
{
66+
return [Class_::class];
67+
}
68+
69+
/**
70+
* @param Class_ $node
71+
*/
72+
public function refactor(Node $node): ?Node
73+
{
74+
if (! $node->getMethod(MethodName::CONSTRUCT) instanceof ClassMethod) {
75+
return null;
76+
}
77+
78+
$hasChanged = false;
79+
80+
foreach ($node->getProperties() as $property) {
81+
// untyped properties are handled by RemoveNullPropertyInitializationRector
82+
if (! $property->type instanceof Node) {
83+
continue;
84+
}
85+
86+
if ($property->hooks !== []) {
87+
continue;
88+
}
89+
90+
foreach ($property->props as $propertyProperty) {
91+
if (! $propertyProperty->default instanceof Expr) {
92+
continue;
93+
}
94+
95+
$propertyName = $this->getName($propertyProperty);
96+
if (! $this->constructorAssignDetector->isPropertyAssigned($node, $propertyName)) {
97+
continue;
98+
}
99+
100+
$propertyProperty->default = null;
101+
$hasChanged = true;
102+
}
103+
}
104+
105+
if ($hasChanged) {
106+
return $node;
107+
}
108+
109+
return null;
110+
}
111+
}

0 commit comments

Comments
 (0)