2020-01-05 12:10:01 +00:00
|
|
|
<?php
|
|
|
|
|
|
|
|
declare(strict_types=1);
|
|
|
|
|
|
|
|
namespace Rector\SOLID\Rector\If_;
|
|
|
|
|
|
|
|
use PhpParser\Node;
|
2020-01-05 17:19:27 +00:00
|
|
|
use PhpParser\Node\Expr\BinaryOp;
|
2020-01-05 12:10:01 +00:00
|
|
|
use PhpParser\Node\Stmt\If_;
|
|
|
|
use PhpParser\Node\Stmt\Return_;
|
2020-01-05 17:19:27 +00:00
|
|
|
use Rector\Exception\NotImplementedException;
|
2020-01-05 12:10:01 +00:00
|
|
|
use Rector\NodeTypeResolver\Node\AttributeKey;
|
|
|
|
use Rector\PhpParser\Node\Manipulator\BinaryOpManipulator;
|
|
|
|
use Rector\PhpParser\Node\Manipulator\IfManipulator;
|
|
|
|
use Rector\Rector\AbstractRector;
|
|
|
|
use Rector\RectorDefinition\CodeSample;
|
|
|
|
use Rector\RectorDefinition\RectorDefinition;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @see \Rector\SOLID\Tests\Rector\If_\ChangeNestedIfsToEarlyReturnRector\ChangeNestedIfsToEarlyReturnRectorTest
|
|
|
|
*/
|
|
|
|
final class ChangeNestedIfsToEarlyReturnRector extends AbstractRector
|
|
|
|
{
|
|
|
|
/**
|
|
|
|
* @var IfManipulator
|
|
|
|
*/
|
|
|
|
private $ifManipulator;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @var BinaryOpManipulator
|
|
|
|
*/
|
|
|
|
private $binaryOpManipulator;
|
|
|
|
|
|
|
|
public function __construct(IfManipulator $ifManipulator, BinaryOpManipulator $binaryOpManipulator)
|
|
|
|
{
|
|
|
|
$this->ifManipulator = $ifManipulator;
|
|
|
|
$this->binaryOpManipulator = $binaryOpManipulator;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getDefinition(): RectorDefinition
|
|
|
|
{
|
|
|
|
return new RectorDefinition('Change nested ifs to early return', [
|
|
|
|
new CodeSample(
|
|
|
|
<<<'PHP'
|
|
|
|
class SomeClass
|
|
|
|
{
|
|
|
|
public function run()
|
|
|
|
{
|
|
|
|
if ($value === 5) {
|
|
|
|
if ($value2 === 10) {
|
|
|
|
return 'yes';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 'no';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
PHP
|
|
|
|
,
|
|
|
|
<<<'PHP'
|
|
|
|
class SomeClass
|
|
|
|
{
|
|
|
|
public function run()
|
|
|
|
{
|
|
|
|
if ($value !== 5) {
|
|
|
|
return 'no';
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($value2 === 10) {
|
|
|
|
return 'yes';
|
|
|
|
}
|
|
|
|
|
|
|
|
return 'no';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
PHP
|
|
|
|
|
|
|
|
),
|
|
|
|
]);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return string[]
|
|
|
|
*/
|
|
|
|
public function getNodeTypes(): array
|
|
|
|
{
|
|
|
|
return [If_::class];
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param If_ $node
|
|
|
|
*/
|
|
|
|
public function refactor(Node $node): ?Node
|
|
|
|
{
|
|
|
|
// A. next node is return
|
|
|
|
$nextNode = $node->getAttribute(AttributeKey::NEXT_NODE);
|
|
|
|
if (! $nextNode instanceof Return_) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
$nestedIfsWithOnlyReturn = $this->ifManipulator->collectNestedIfsWithOnlyReturn($node);
|
|
|
|
if ($nestedIfsWithOnlyReturn === []) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2020-01-05 17:19:27 +00:00
|
|
|
$this->processNestedIfsWIthOnlyReturn($node, $nestedIfsWithOnlyReturn, $nextNode);
|
|
|
|
$this->removeNode($node);
|
|
|
|
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param If_[] $nestedIfsWithOnlyReturn
|
|
|
|
*/
|
|
|
|
private function processNestedIfsWIthOnlyReturn(If_ $if, array $nestedIfsWithOnlyReturn, Return_ $nextReturn): void
|
|
|
|
{
|
2020-01-05 12:10:01 +00:00
|
|
|
// add nested if openly after this
|
|
|
|
$nestedIfsWithOnlyReturnCount = count($nestedIfsWithOnlyReturn);
|
|
|
|
|
2020-01-05 17:19:27 +00:00
|
|
|
/** @var int $key */
|
2020-01-05 12:10:01 +00:00
|
|
|
foreach ($nestedIfsWithOnlyReturn as $key => $nestedIfWithOnlyReturn) {
|
|
|
|
// last item → the return node
|
|
|
|
if ($nestedIfsWithOnlyReturnCount === $key + 1) {
|
2020-01-05 17:19:27 +00:00
|
|
|
$this->addNodeAfterNode($nestedIfWithOnlyReturn, $if);
|
2020-01-05 12:10:01 +00:00
|
|
|
} else {
|
2020-01-05 17:19:27 +00:00
|
|
|
if (! $nestedIfWithOnlyReturn->cond instanceof BinaryOp) {
|
|
|
|
throw new NotImplementedException(__METHOD__);
|
|
|
|
}
|
|
|
|
|
2020-01-05 12:10:01 +00:00
|
|
|
$inversedCondition = $this->binaryOpManipulator->inverseCondition($nestedIfWithOnlyReturn->cond);
|
|
|
|
if ($inversedCondition === null) {
|
2020-01-05 17:19:27 +00:00
|
|
|
throw new NotImplementedException(__METHOD__);
|
2020-01-05 12:10:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
$nestedIfWithOnlyReturn->cond = $inversedCondition;
|
2020-01-05 17:19:27 +00:00
|
|
|
$nestedIfWithOnlyReturn->stmts = [clone $nextReturn];
|
2020-01-05 12:10:01 +00:00
|
|
|
|
2020-01-05 17:19:27 +00:00
|
|
|
$this->addNodeAfterNode($nestedIfWithOnlyReturn, $if);
|
2020-01-05 12:10:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|