2020-01-05 12:10:01 +00:00
< ? php
2021-05-09 20:15:43 +00:00
declare ( strict_types = 1 );
2020-12-12 16:59:09 +00:00
namespace Rector\EarlyReturn\Rector\If_ ;
2020-01-05 12:10:01 +00:00
use PhpParser\Node ;
2020-01-12 21:44:42 +00:00
use PhpParser\Node\Expr\BinaryOp\BooleanAnd ;
2020-01-05 21:19:26 +00:00
use PhpParser\Node\Expr\BooleanNot ;
2022-05-07 09:28:12 +00:00
use PhpParser\Node\Stmt ;
2020-01-05 12:10:01 +00:00
use PhpParser\Node\Stmt\If_ ;
use PhpParser\Node\Stmt\Return_ ;
2022-05-07 09:28:12 +00:00
use Rector\CodeQuality\NodeTypeGroup ;
2021-02-08 12:33:17 +00:00
use Rector\Core\NodeManipulator\IfManipulator ;
2020-02-06 21:48:18 +00:00
use Rector\Core\Rector\AbstractRector ;
2020-12-12 16:59:09 +00:00
use Rector\EarlyReturn\NodeTransformer\ConditionInverter ;
2020-11-16 17:50:38 +00:00
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample ;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition ;
2022-05-08 00:33:36 +00:00
use RectorPrefix20220508\Webmozart\Assert\Assert ;
2020-01-05 12:10:01 +00:00
/**
2021-03-12 22:20:25 +00:00
* @ see \Rector\Tests\EarlyReturn\Rector\If_\ChangeNestedIfsToEarlyReturnRector\ChangeNestedIfsToEarlyReturnRectorTest
2020-01-05 12:10:01 +00:00
*/
2021-05-10 22:23:08 +00:00
final class ChangeNestedIfsToEarlyReturnRector extends \Rector\Core\Rector\AbstractRector
2020-01-05 12:10:01 +00:00
{
/**
2021-12-04 12:47:17 +00:00
* @ readonly
2021-05-10 23:39:21 +00:00
* @ var \Rector\EarlyReturn\NodeTransformer\ConditionInverter
2020-01-05 12:10:01 +00:00
*/
2021-05-10 23:39:21 +00:00
private $conditionInverter ;
2020-01-05 12:10:01 +00:00
/**
2021-12-04 12:47:17 +00:00
* @ readonly
2021-05-10 23:39:21 +00:00
* @ var \Rector\Core\NodeManipulator\IfManipulator
2020-01-05 12:10:01 +00:00
*/
2021-05-10 23:39:21 +00:00
private $ifManipulator ;
2021-05-10 22:23:08 +00:00
public function __construct ( \Rector\EarlyReturn\NodeTransformer\ConditionInverter $conditionInverter , \Rector\Core\NodeManipulator\IfManipulator $ifManipulator )
2020-01-05 12:10:01 +00:00
{
2020-02-22 12:35:26 +00:00
$this -> conditionInverter = $conditionInverter ;
2021-05-10 23:39:21 +00:00
$this -> ifManipulator = $ifManipulator ;
2020-01-05 12:10:01 +00:00
}
2021-05-10 22:23:08 +00:00
public function getRuleDefinition () : \Symplify\RuleDocGenerator\ValueObject\RuleDefinition
2020-01-05 12:10:01 +00:00
{
2021-05-10 22:23:08 +00:00
return new \Symplify\RuleDocGenerator\ValueObject\RuleDefinition ( 'Change nested ifs to early return' , [ new \Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample ( <<< 'CODE_SAMPLE'
2020-01-05 12:10:01 +00:00
class SomeClass
{
public function run ()
{
if ( $value === 5 ) {
if ( $value2 === 10 ) {
return 'yes' ;
}
}
return 'no' ;
}
}
2020-09-15 08:23:13 +00:00
CODE_SAMPLE
2021-05-09 20:15:43 +00:00
, <<< 'CODE_SAMPLE'
2020-01-05 12:10:01 +00:00
class SomeClass
{
public function run ()
{
if ( $value !== 5 ) {
return 'no' ;
}
if ( $value2 === 10 ) {
return 'yes' ;
}
return 'no' ;
}
}
2020-09-15 08:23:13 +00:00
CODE_SAMPLE
2021-05-09 20:15:43 +00:00
)]);
2020-01-05 12:10:01 +00:00
}
/**
2021-02-27 00:06:15 +00:00
* @ return array < class - string < Node >>
2020-01-05 12:10:01 +00:00
*/
2021-05-09 20:15:43 +00:00
public function getNodeTypes () : array
2020-01-05 12:10:01 +00:00
{
2022-05-07 09:28:12 +00:00
return \Rector\CodeQuality\NodeTypeGroup :: STMTS_AWARE ;
2020-01-05 12:10:01 +00:00
}
2021-12-10 10:22:23 +00:00
public function refactor ( \PhpParser\Node $node ) : ? \PhpParser\Node
2020-01-05 12:10:01 +00:00
{
2022-05-08 00:33:36 +00:00
\RectorPrefix20220508\Webmozart\Assert\Assert :: propertyExists ( $node , 'stmts' );
2022-05-07 09:28:12 +00:00
$stmts = $node -> stmts ;
if ( $stmts === null ) {
2020-01-05 12:10:01 +00:00
return null ;
}
2022-05-07 09:28:12 +00:00
foreach ( $stmts as $key => $stmt ) {
$nextStmt = $stmts [ $key + 1 ] ? ? null ;
if ( ! $nextStmt instanceof \PhpParser\Node\Stmt\Return_ ) {
continue ;
}
if ( ! $stmt instanceof \PhpParser\Node\Stmt\If_ ) {
continue ;
}
$nestedIfsWithOnlyReturn = $this -> ifManipulator -> collectNestedIfsWithOnlyReturn ( $stmt );
if ( $nestedIfsWithOnlyReturn === []) {
continue ;
}
$node -> stmts = $this -> processNestedIfsWithOnlyReturn ( $nestedIfsWithOnlyReturn , $nextStmt );
return $node ;
2020-01-05 12:10:01 +00:00
}
2020-01-05 17:19:27 +00:00
return null ;
}
/**
* @ param If_ [] $nestedIfsWithOnlyReturn
2022-05-07 09:28:12 +00:00
* @ return Stmt []
2020-01-05 17:19:27 +00:00
*/
2022-05-07 09:28:12 +00:00
private function processNestedIfsWithOnlyReturn ( array $nestedIfsWithOnlyReturn , \PhpParser\Node\Stmt\Return_ $nextReturn ) : array
2020-01-05 17:19:27 +00:00
{
2020-01-05 12:10:01 +00:00
// add nested if openly after this
2021-05-09 20:15:43 +00:00
$nestedIfsWithOnlyReturnCount = \count ( $nestedIfsWithOnlyReturn );
2022-05-07 09:28:12 +00:00
$newStmts = [];
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 ) {
2022-05-07 09:28:12 +00:00
$newStmts [] = $nestedIfWithOnlyReturn ;
2020-01-05 12:10:01 +00:00
} else {
2022-05-07 09:28:12 +00:00
$standaloneIfs = $this -> createStandaloneIfsWithReturn ( $nestedIfWithOnlyReturn , $nextReturn );
$newStmts = \array_merge ( $newStmts , $standaloneIfs );
2020-01-05 21:19:26 +00:00
}
}
2022-05-07 09:28:12 +00:00
$newStmts [] = $nextReturn ;
return $newStmts ;
2020-01-05 21:19:26 +00:00
}
2022-05-07 09:28:12 +00:00
/**
* @ return Stmt []
*/
private function createStandaloneIfsWithReturn ( \PhpParser\Node\Stmt\If_ $nestedIfWithOnlyReturn , \PhpParser\Node\Stmt\Return_ $return ) : array
2020-01-05 21:19:26 +00:00
{
2020-02-22 12:35:26 +00:00
$invertedCondition = $this -> conditionInverter -> createInvertedCondition ( $nestedIfWithOnlyReturn -> cond );
2020-01-05 21:19:26 +00:00
// special case
2021-05-10 22:23:08 +00:00
if ( $invertedCondition instanceof \PhpParser\Node\Expr\BooleanNot && $invertedCondition -> expr instanceof \PhpParser\Node\Expr\BinaryOp\BooleanAnd ) {
$booleanNotPartIf = new \PhpParser\Node\Stmt\If_ ( new \PhpParser\Node\Expr\BooleanNot ( $invertedCondition -> expr -> left ));
2020-01-19 19:45:01 +00:00
$booleanNotPartIf -> stmts = [ clone $return ];
2021-11-24 20:49:18 +00:00
$secondBooleanNotPartIf = new \PhpParser\Node\Stmt\If_ ( new \PhpParser\Node\Expr\BooleanNot ( $invertedCondition -> expr -> right ));
$secondBooleanNotPartIf -> stmts = [ clone $return ];
2022-05-07 09:28:12 +00:00
return [ $booleanNotPartIf , $secondBooleanNotPartIf ];
2020-01-05 12:10:01 +00:00
}
2020-01-05 21:19:26 +00:00
$nestedIfWithOnlyReturn -> cond = $invertedCondition ;
2022-05-07 09:28:12 +00:00
$nestedIfWithOnlyReturn -> stmts = [ $return ];
return [ $nestedIfWithOnlyReturn ];
2020-01-05 12:10:01 +00:00
}
}