mirror of
https://github.com/rectorphp/rector.git
synced 2025-02-24 11:44:14 +01:00
Merge pull request #2948 from rectorphp/dead-if-return
[DeadCode] Add RemoveDuplicatedIfReturnRector
This commit is contained in:
commit
35e95f9db5
@ -34,3 +34,4 @@ services:
|
|||||||
Rector\DeadCode\Rector\TryCatch\RemoveDeadTryCatchRector: null
|
Rector\DeadCode\Rector\TryCatch\RemoveDeadTryCatchRector: null
|
||||||
Rector\DeadCode\Rector\ClassConst\RemoveUnusedClassConstantRector: null
|
Rector\DeadCode\Rector\ClassConst\RemoveUnusedClassConstantRector: null
|
||||||
Rector\DeadCode\Rector\Assign\RemoveUnusedVariableAssignRector: null
|
Rector\DeadCode\Rector\Assign\RemoveUnusedVariableAssignRector: null
|
||||||
|
Rector\DeadCode\Rector\FunctionLike\RemoveDuplicatedIfReturnRector: null
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# All 463 Rectors Overview
|
# All 464 Rectors Overview
|
||||||
|
|
||||||
- [Projects](#projects)
|
- [Projects](#projects)
|
||||||
- [General](#general)
|
- [General](#general)
|
||||||
@ -2791,6 +2791,33 @@ Remove duplicated key in defined arrays.
|
|||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
|
### `RemoveDuplicatedIfReturnRector`
|
||||||
|
|
||||||
|
- class: [`Rector\DeadCode\Rector\FunctionLike\RemoveDuplicatedIfReturnRector`](/../master/rules/dead-code/src/Rector/FunctionLike/RemoveDuplicatedIfReturnRector.php)
|
||||||
|
- [test fixtures](/../master/rules/dead-code/tests/Rector/FunctionLike/RemoveDuplicatedIfReturnRector/Fixture)
|
||||||
|
|
||||||
|
Remove duplicated if stmt with return in function/method body
|
||||||
|
|
||||||
|
```diff
|
||||||
|
class SomeClass
|
||||||
|
{
|
||||||
|
public function run($value)
|
||||||
|
{
|
||||||
|
if ($value) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$value2 = 100;
|
||||||
|
-
|
||||||
|
- if ($value) {
|
||||||
|
- return true;
|
||||||
|
- }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
### `RemoveDuplicatedInstanceOfRector`
|
### `RemoveDuplicatedInstanceOfRector`
|
||||||
|
|
||||||
- class: [`Rector\DeadCode\Rector\Instanceof_\RemoveDuplicatedInstanceOfRector`](/../master/rules/dead-code/src/Rector/Instanceof_/RemoveDuplicatedInstanceOfRector.php)
|
- class: [`Rector\DeadCode\Rector\Instanceof_\RemoveDuplicatedInstanceOfRector`](/../master/rules/dead-code/src/Rector/Instanceof_/RemoveDuplicatedInstanceOfRector.php)
|
||||||
|
@ -0,0 +1,200 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Rector\DeadCode\Rector\FunctionLike;
|
||||||
|
|
||||||
|
use PhpParser\Node;
|
||||||
|
use PhpParser\Node\Expr\Assign;
|
||||||
|
use PhpParser\Node\Expr\Variable;
|
||||||
|
use PhpParser\Node\FunctionLike;
|
||||||
|
use PhpParser\Node\Stmt\If_;
|
||||||
|
use PhpParser\NodeTraverser;
|
||||||
|
use Rector\Core\PhpParser\Node\Manipulator\IfManipulator;
|
||||||
|
use Rector\Core\Rector\AbstractRector;
|
||||||
|
use Rector\Core\RectorDefinition\CodeSample;
|
||||||
|
use Rector\Core\RectorDefinition\RectorDefinition;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see https://github.com/rectorphp/rector/issues/2945
|
||||||
|
*
|
||||||
|
* @see \Rector\DeadCode\Tests\Rector\FunctionLike\RemoveDuplicatedIfReturnRector\RemoveDuplicatedIfReturnRectorTest
|
||||||
|
*/
|
||||||
|
final class RemoveDuplicatedIfReturnRector extends AbstractRector
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var IfManipulator
|
||||||
|
*/
|
||||||
|
private $ifManipulator;
|
||||||
|
|
||||||
|
public function __construct(IfManipulator $ifManipulator)
|
||||||
|
{
|
||||||
|
$this->ifManipulator = $ifManipulator;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDefinition(): RectorDefinition
|
||||||
|
{
|
||||||
|
return new RectorDefinition('Remove duplicated if stmt with return in function/method body', [
|
||||||
|
new CodeSample(
|
||||||
|
<<<'PHP'
|
||||||
|
class SomeClass
|
||||||
|
{
|
||||||
|
public function run($value)
|
||||||
|
{
|
||||||
|
if ($value) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$value2 = 100;
|
||||||
|
|
||||||
|
if ($value) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PHP
|
||||||
|
,
|
||||||
|
<<<'PHP'
|
||||||
|
class SomeClass
|
||||||
|
{
|
||||||
|
public function run($value)
|
||||||
|
{
|
||||||
|
if ($value) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$value2 = 100;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PHP
|
||||||
|
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string[]
|
||||||
|
*/
|
||||||
|
public function getNodeTypes(): array
|
||||||
|
{
|
||||||
|
return [FunctionLike::class];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param FunctionLike $node
|
||||||
|
*/
|
||||||
|
public function refactor(Node $node): ?Node
|
||||||
|
{
|
||||||
|
$ifWithOnlyReturnsByHash = $this->collectDuplicatedIfWithOnlyReturnByHash($node);
|
||||||
|
if ($ifWithOnlyReturnsByHash === []) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($ifWithOnlyReturnsByHash as $stmts) {
|
||||||
|
// keep first one
|
||||||
|
array_shift($stmts);
|
||||||
|
|
||||||
|
foreach ($stmts as $stmt) {
|
||||||
|
$this->removeNode($stmt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $node;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return If_[][]
|
||||||
|
*/
|
||||||
|
private function collectDuplicatedIfWithOnlyReturnByHash(FunctionLike $functionLike): array
|
||||||
|
{
|
||||||
|
$ifWithOnlyReturnsByHash = [];
|
||||||
|
$modifiedVariableNames = [];
|
||||||
|
|
||||||
|
foreach ((array) $functionLike->getStmts() as $stmt) {
|
||||||
|
if (! $this->ifManipulator->isIfWithOnlyReturn($stmt)) {
|
||||||
|
// variable modification
|
||||||
|
$modifiedVariableNames += $this->collectModifiedVariableNames($stmt);
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->containsVariableNames($stmt, $modifiedVariableNames)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @var If_ $stmt */
|
||||||
|
$hash = $this->printWithoutComments($stmt);
|
||||||
|
$ifWithOnlyReturnsByHash[$hash][] = $stmt;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->filterOutSingleItemStmts($ifWithOnlyReturnsByHash);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param If_[][] $ifWithOnlyReturnsByHash
|
||||||
|
* @return If_[][]
|
||||||
|
*/
|
||||||
|
private function filterOutSingleItemStmts(array $ifWithOnlyReturnsByHash): array
|
||||||
|
{
|
||||||
|
return array_filter($ifWithOnlyReturnsByHash, function (array $stmts) {
|
||||||
|
return count($stmts) >= 2;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string[]
|
||||||
|
*/
|
||||||
|
private function collectModifiedVariableNames(Node $node): array
|
||||||
|
{
|
||||||
|
$modifiedVariableNames = [];
|
||||||
|
|
||||||
|
$this->traverseNodesWithCallable($node, function (Node $node) use (&$modifiedVariableNames) {
|
||||||
|
if (! $node instanceof Assign) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! $node->var instanceof Variable) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$variableName = $this->getName($node->var);
|
||||||
|
if ($variableName === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$modifiedVariableNames[] = $variableName;
|
||||||
|
});
|
||||||
|
|
||||||
|
return $modifiedVariableNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string[] $modifiedVariableNames
|
||||||
|
*/
|
||||||
|
private function containsVariableNames(Node $node, array $modifiedVariableNames): bool
|
||||||
|
{
|
||||||
|
if ($modifiedVariableNames === []) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$containsVariableNames = false;
|
||||||
|
$this->traverseNodesWithCallable($node, function (Node $node) use (
|
||||||
|
$modifiedVariableNames,
|
||||||
|
&$containsVariableNames
|
||||||
|
) {
|
||||||
|
if (! $node instanceof Variable) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! $this->isNames($node, $modifiedVariableNames)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$containsVariableNames = true;
|
||||||
|
|
||||||
|
return NodeTraverser::STOP_TRAVERSAL;
|
||||||
|
});
|
||||||
|
|
||||||
|
return $containsVariableNames;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,39 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Rector\DeadCode\Tests\Rector\FunctionLike\RemoveDuplicatedIfReturnRector\Fixture;
|
||||||
|
|
||||||
|
class SomeClass
|
||||||
|
{
|
||||||
|
public function run($value)
|
||||||
|
{
|
||||||
|
if ($value) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$value2 = 100;
|
||||||
|
|
||||||
|
if ($value) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
|
-----
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Rector\DeadCode\Tests\Rector\FunctionLike\RemoveDuplicatedIfReturnRector\Fixture;
|
||||||
|
|
||||||
|
class SomeClass
|
||||||
|
{
|
||||||
|
public function run($value)
|
||||||
|
{
|
||||||
|
if ($value) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$value2 = 100;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Rector\DeadCode\Tests\Rector\FunctionLike\RemoveDuplicatedIfReturnRector\Fixture;
|
||||||
|
|
||||||
|
class SkipModifiedValue
|
||||||
|
{
|
||||||
|
public function run()
|
||||||
|
{
|
||||||
|
$value = random_int(1, 5);
|
||||||
|
if ($value) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$value = random_int(1, 5);
|
||||||
|
if ($value) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Rector\DeadCode\Tests\Rector\FunctionLike\RemoveDuplicatedIfReturnRector\Fixture;
|
||||||
|
|
||||||
|
class SkipThis
|
||||||
|
{
|
||||||
|
public function run($value)
|
||||||
|
{
|
||||||
|
if ($value) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$value2 = 100;
|
||||||
|
|
||||||
|
if ($value2) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Rector\DeadCode\Tests\Rector\FunctionLike\RemoveDuplicatedIfReturnRector\Fixture;
|
||||||
|
|
||||||
|
class SkipWithDifferentValue
|
||||||
|
{
|
||||||
|
public function run($value)
|
||||||
|
{
|
||||||
|
// is yml/yaml file
|
||||||
|
if (Strings::match($possibleFileNodeAsString, '#\.(yml|yaml)(\'|")$#')) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// is probably a file variable
|
||||||
|
if (Strings::match($possibleFileNodeAsString, '#\File$#')) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Rector\DeadCode\Tests\Rector\FunctionLike\RemoveDuplicatedIfReturnRector;
|
||||||
|
|
||||||
|
use Iterator;
|
||||||
|
use Rector\Core\Testing\PHPUnit\AbstractRectorTestCase;
|
||||||
|
use Rector\DeadCode\Rector\FunctionLike\RemoveDuplicatedIfReturnRector;
|
||||||
|
|
||||||
|
final class RemoveDuplicatedIfReturnRectorTest extends AbstractRectorTestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @dataProvider provideData()
|
||||||
|
*/
|
||||||
|
public function test(string $file): void
|
||||||
|
{
|
||||||
|
$this->doTestFile($file);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function provideData(): Iterator
|
||||||
|
{
|
||||||
|
return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getRectorClass(): string
|
||||||
|
{
|
||||||
|
return RemoveDuplicatedIfReturnRector::class;
|
||||||
|
}
|
||||||
|
}
|
@ -263,6 +263,19 @@ final class IfManipulator
|
|||||||
return $ifs;
|
return $ifs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function isIfWithOnlyReturn(Node $node): bool
|
||||||
|
{
|
||||||
|
if (! $node instanceof If_) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! $this->isIfWithoutElseAndElseIfs($node)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->hasOnlyStmtOfType($node, Return_::class);
|
||||||
|
}
|
||||||
|
|
||||||
private function matchComparedAndReturnedNode(NotIdentical $notIdentical, Return_ $returnNode): ?Expr
|
private function matchComparedAndReturnedNode(NotIdentical $notIdentical, Return_ $returnNode): ?Expr
|
||||||
{
|
{
|
||||||
if ($this->betterStandardPrinter->areNodesEqual(
|
if ($this->betterStandardPrinter->areNodesEqual(
|
||||||
|
@ -376,7 +376,7 @@ final class BetterStandardPrinter extends Standard
|
|||||||
$printerNode = Strings::replace($printerNode, '#\/*\*(.*?)\*\/#');
|
$printerNode = Strings::replace($printerNode, '#\/*\*(.*?)\*\/#');
|
||||||
|
|
||||||
// remove # ...
|
// remove # ...
|
||||||
$printerNode = Strings::replace($printerNode, '#\#(.*?)$#m');
|
$printerNode = Strings::replace($printerNode, '#^(\s+)?\#(.*?)$#m');
|
||||||
|
|
||||||
// remove // ...
|
// remove // ...
|
||||||
return Strings::replace($printerNode, '#\/\/(.*?)$#m');
|
return Strings::replace($printerNode, '#\/\/(.*?)$#m');
|
||||||
|
Loading…
x
Reference in New Issue
Block a user