Skip to content

Commit 184dd02

Browse files
[dead-code] Add RemoveVoidDocblockFromMagicMethodRector (#7822)
* feature: add handling for void magic methods * rename to shorter RemoveVoidDocblockFromMagicMethodsRector * singular, register in dead-code level * combine if * misc --------- Co-authored-by: Paul Rijke <[email protected]>
1 parent 7891d87 commit 184dd02

File tree

9 files changed

+255
-11
lines changed

9 files changed

+255
-11
lines changed
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<?php
2+
3+
namespace Rector\Tests\DeadCode\Rector\ClassMethod\RemoveVoidDocblockFromMagicMethodRector\Fixture;
4+
5+
class RemoveReturnClone
6+
{
7+
/**
8+
* Other comments
9+
*
10+
* @return void
11+
*/
12+
function __clone()
13+
{
14+
//
15+
}
16+
}
17+
18+
?>
19+
-----
20+
<?php
21+
22+
namespace Rector\Tests\DeadCode\Rector\ClassMethod\RemoveVoidDocblockFromMagicMethodRector\Fixture;
23+
24+
class RemoveReturnClone
25+
{
26+
/**
27+
* Other comments
28+
*/
29+
function __clone()
30+
{
31+
//
32+
}
33+
}
34+
35+
?>
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
namespace Rector\Tests\DeadCode\Rector\ClassMethod\RemoveVoidDocblockFromMagicMethodRector\Fixture;
4+
5+
class RemoveReturnConstruct
6+
{
7+
/**
8+
* @return void
9+
*/
10+
function __construct()
11+
{
12+
//
13+
}
14+
}
15+
16+
?>
17+
-----
18+
<?php
19+
20+
namespace Rector\Tests\DeadCode\Rector\ClassMethod\RemoveVoidDocblockFromMagicMethodRector\Fixture;
21+
22+
class RemoveReturnConstruct
23+
{
24+
function __construct()
25+
{
26+
//
27+
}
28+
}
29+
30+
?>
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
namespace Rector\Tests\DeadCode\Rector\ClassMethod\RemoveVoidDocblockFromMagicMethodRector\Fixture;
4+
5+
class RemoveReturnDestruct
6+
{
7+
/**
8+
* @return void
9+
*/
10+
function __destruct()
11+
{
12+
//
13+
}
14+
}
15+
16+
?>
17+
-----
18+
<?php
19+
20+
namespace Rector\Tests\DeadCode\Rector\ClassMethod\RemoveVoidDocblockFromMagicMethodRector\Fixture;
21+
22+
class RemoveReturnDestruct
23+
{
24+
function __destruct()
25+
{
26+
//
27+
}
28+
}
29+
30+
?>
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\ClassMethod\RemoveVoidDocblockFromMagicMethodRector;
6+
7+
use Iterator;
8+
use PHPUnit\Framework\Attributes\DataProvider;
9+
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
10+
11+
final class RemoveVoidDocblockFromMagicMethodRectorTest 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\ClassMethod\RemoveVoidDocblockFromMagicMethodRector;
7+
8+
return RectorConfig::configure()
9+
->withRules([RemoveVoidDocblockFromMagicMethodRector::class]);
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Rector\DeadCode\Rector\ClassMethod;
6+
7+
use PhpParser\Node;
8+
use PhpParser\Node\Stmt\ClassMethod;
9+
use PHPStan\PhpDocParser\Ast\PhpDoc\ReturnTagValueNode;
10+
use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
11+
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfoFactory;
12+
use Rector\Comments\NodeDocBlock\DocBlockUpdater;
13+
use Rector\Rector\AbstractRector;
14+
use Rector\ValueObject\MethodName;
15+
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
16+
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
17+
18+
/**
19+
* @see \Rector\Tests\DeadCode\Rector\ClassMethod\RemoveVoidDocblockFromMagicMethodRector\RemoveVoidDocblockFromMagicMethodRectorTest
20+
*/
21+
final class RemoveVoidDocblockFromMagicMethodRector extends AbstractRector
22+
{
23+
public function __construct(
24+
private readonly DocBlockUpdater $docBlockUpdater,
25+
private readonly PhpDocInfoFactory $phpDocInfoFactory,
26+
) {
27+
}
28+
29+
public function getRuleDefinition(): RuleDefinition
30+
{
31+
return new RuleDefinition(
32+
'Remove useless @return void docblock from magic methods __construct, __destruct, and __clone',
33+
[
34+
new CodeSample(
35+
<<<'CODE_SAMPLE'
36+
class SomeClass
37+
{
38+
/**
39+
* @return void
40+
*/
41+
public function __construct() {}
42+
43+
/**
44+
* @return void
45+
*/
46+
public function __destruct() {}
47+
48+
/**
49+
* @return void
50+
*/
51+
public function __clone() {}
52+
}
53+
CODE_SAMPLE
54+
,
55+
<<<'CODE_SAMPLE'
56+
class SomeClass
57+
{
58+
public function __construct() {}
59+
60+
public function __destruct() {}
61+
62+
public function __clone() {}
63+
}
64+
CODE_SAMPLE
65+
),
66+
]
67+
);
68+
}
69+
70+
public function getNodeTypes(): array
71+
{
72+
return [ClassMethod::class];
73+
}
74+
75+
/**
76+
* @param ClassMethod $node
77+
*/
78+
public function refactor(Node $node): ?Node
79+
{
80+
if ($node->returnType instanceof Node) {
81+
return null;
82+
}
83+
84+
if (! $this->isNames($node, [MethodName::CONSTRUCT, MethodName::DESTRUCT, MethodName::CLONE])) {
85+
return null;
86+
}
87+
88+
$phpDocInfo = $this->phpDocInfoFactory->createFromNodeOrEmpty($node);
89+
90+
$returnTagValueNode = $phpDocInfo->getReturnTagValue();
91+
if (! $returnTagValueNode instanceof ReturnTagValueNode) {
92+
return null;
93+
}
94+
95+
if ($returnTagValueNode->description !== '') {
96+
return null;
97+
}
98+
99+
if (! $returnTagValueNode->type instanceof IdentifierTypeNode || $returnTagValueNode->type->name !== 'void') {
100+
return null;
101+
}
102+
103+
$phpDocInfo->removeByType(ReturnTagValueNode::class);
104+
105+
$this->docBlockUpdater->updateRefactoredNodeWithPhpDocInfo($node);
106+
return $node;
107+
}
108+
}

rules/DeadCode/Rector/If_/RemoveDeadIfBlockRector.php

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use PhpParser\Node;
88
use PhpParser\Node\Expr\BinaryOp\BooleanAnd;
99
use PhpParser\Node\Stmt\Else_;
10+
use PhpParser\Node\Stmt\ElseIf_;
1011
use PhpParser\Node\Stmt\If_;
1112
use PhpParser\NodeVisitor;
1213
use Rector\DeadCode\SideEffect\SideEffectNodeDetector;
@@ -100,16 +101,16 @@ public function refactor(Node $node): int|null|If_
100101
return $this->refactor($node) ?? $node;
101102
}
102103

103-
if ($node->elseifs !== []) {
104-
foreach ($node->elseifs as $elseif) {
105-
$keep_elseifs = array_filter(
106-
$node->elseifs,
107-
fn ($elseif) => $elseif->stmts !== [] || $this->sideEffectNodeDetector->detect($elseif->cond)
108-
);
109-
if (count($node->elseifs) !== count($keep_elseifs)) {
110-
$node->elseifs = $keep_elseifs;
111-
return $this->refactor($node) ?? $node;
112-
}
104+
foreach ($node->elseifs as $elseif) {
105+
$keep_elseifs = array_filter(
106+
$node->elseifs,
107+
fn (ElseIf_ $elseif): bool => $elseif->stmts !== [] || $this->sideEffectNodeDetector->detect(
108+
$elseif->cond
109+
)
110+
);
111+
if (count($node->elseifs) !== count($keep_elseifs)) {
112+
$node->elseifs = $keep_elseifs;
113+
return $this->refactor($node) ?? $node;
113114
}
114115
}
115116

@@ -141,6 +142,7 @@ public function refactor(Node $node): int|null|If_
141142
if (count($node->elseifs) > 1) {
142143
$if->elseifs = \array_slice($node->elseifs, 1);
143144
}
145+
144146
return $this->refactor($if) ?? $if;
145147
}
146148

src/Config/Level/DeadCodeLevel.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
use Rector\DeadCode\Rector\ClassMethod\RemoveUselessParamTagRector;
2828
use Rector\DeadCode\Rector\ClassMethod\RemoveUselessReturnExprInConstructRector;
2929
use Rector\DeadCode\Rector\ClassMethod\RemoveUselessReturnTagRector;
30+
use Rector\DeadCode\Rector\ClassMethod\RemoveVoidDocblockFromMagicMethodRector;
3031
use Rector\DeadCode\Rector\Closure\RemoveUnusedClosureVariableUseRector;
3132
use Rector\DeadCode\Rector\Concat\RemoveConcatAutocastRector;
3233
use Rector\DeadCode\Rector\ConstFetch\RemovePhpVersionIdCheckRector;
@@ -109,6 +110,7 @@ final class DeadCodeLevel
109110
RemoveDeadZeroAndOneOperationRector::class,
110111

111112
// docblock
113+
RemoveVoidDocblockFromMagicMethodRector::class,
112114
RemoveUselessParamTagRector::class,
113115
RemoveUselessReturnTagRector::class,
114116
RemoveUselessReadOnlyTagRector::class,

src/PhpParser/Node/BetterNodeFinder.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@
44

55
namespace Rector\PhpParser\Node;
66

7-
use PhpParser\Node\Stmt\ClassMethod;
87
use PhpParser\Node;
98
use PhpParser\Node\Expr\Variable;
109
use PhpParser\Node\Expr\Yield_;
1110
use PhpParser\Node\Expr\YieldFrom;
1211
use PhpParser\Node\FunctionLike;
1312
use PhpParser\Node\Stmt;
1413
use PhpParser\Node\Stmt\Class_;
14+
use PhpParser\Node\Stmt\ClassMethod;
1515
use PhpParser\Node\Stmt\Return_;
1616
use PhpParser\NodeFinder;
1717
use PhpParser\NodeVisitor;

0 commit comments

Comments
 (0)