Updated Rector to commit 6712529d24205b4b08e86f8da79876fb0d122c49

6712529d24 [PHP 8.0] Refactor ChangeSwitchToMatchRector to StmstAwareInterface (#2801)
This commit is contained in:
Tomas Votruba 2022-08-19 12:43:13 +00:00
parent 237f7bb846
commit 8629ef2977
7 changed files with 116 additions and 98 deletions

View File

@ -8,13 +8,13 @@ use PhpParser\Node\Expr;
use PhpParser\Node\Expr\ArrayDimFetch;
use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Expr\Match_;
use PhpParser\Node\Stmt;
use PhpParser\Node\Stmt\Expression;
use PhpParser\Node\Stmt\Return_;
use PhpParser\Node\Stmt\Switch_;
use PhpParser\Node\Stmt\Throw_;
use Rector\Core\PhpParser\Comparing\NodeComparator;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\Php80\Enum\MatchKind;
use Rector\Php80\ValueObject\CondAndExpr;
final class MatchSwitchAnalyzer
@ -43,7 +43,7 @@ final class MatchSwitchAnalyzer
/**
* @param CondAndExpr[] $condAndExprs
*/
public function shouldSkipSwitch(Switch_ $switch, array $condAndExprs) : bool
public function shouldSkipSwitch(Switch_ $switch, array $condAndExprs, ?Stmt $nextStmt) : bool
{
if ($condAndExprs === []) {
return \true;
@ -61,10 +61,10 @@ final class MatchSwitchAnalyzer
return \false;
}
// is followed by return? is considered implicit default
if ($this->isNextStmtReturnWithExpr($switch)) {
if ($this->isNextStmtReturnWithExpr($switch, $nextStmt)) {
return \false;
}
return !$this->isNextStmtThrows($switch);
return !$nextStmt instanceof Throw_;
}
/**
* @param CondAndExpr[] $condAndExprs
@ -118,13 +118,12 @@ final class MatchSwitchAnalyzer
}
return \array_unique($condAndExprKinds);
}
private function isNextStmtReturnWithExpr(Switch_ $switch) : bool
private function isNextStmtReturnWithExpr(Switch_ $switch, ?Stmt $nextStmt) : bool
{
$nextNode = $switch->getAttribute(AttributeKey::NEXT_NODE);
if (!$nextNode instanceof Return_) {
if (!$nextStmt instanceof Return_) {
return \false;
}
if (!$nextNode->expr instanceof Expr) {
if (!$nextStmt->expr instanceof Expr) {
return \false;
}
foreach ($switch->cases as $case) {
@ -136,16 +135,11 @@ final class MatchSwitchAnalyzer
if (!$expression->expr instanceof Assign) {
continue;
}
if (!$this->nodeComparator->areNodesEqual($expression->expr->var, $nextNode->expr)) {
if (!$this->nodeComparator->areNodesEqual($expression->expr->var, $nextStmt->expr)) {
return \false;
}
}
}
return \true;
}
private function isNextStmtThrows(Switch_ $switch) : bool
{
$next = $switch->getAttribute(AttributeKey::NEXT_NODE);
return $next instanceof Throw_;
}
}

View File

@ -15,6 +15,7 @@ use PhpParser\Node\Stmt\Expression;
use PhpParser\Node\Stmt\Return_;
use PhpParser\Node\Stmt\Switch_;
use PhpParser\Node\Stmt\Throw_ as ThrowsStmt;
use Rector\Core\Contract\PhpParser\Node\StmtsAwareInterface;
use Rector\Core\Rector\AbstractRector;
use Rector\Core\ValueObject\PhpVersionFeature;
use Rector\NodeTypeResolver\Node\AttributeKey;
@ -83,67 +84,91 @@ CODE_SAMPLE
*/
public function getNodeTypes() : array
{
// @todo refactor to stmts aware interface to move away from NEXT_NODE
return [Switch_::class];
return [StmtsAwareInterface::class];
}
/**
* @param Switch_ $node
* @param StmtsAwareInterface $node
*/
public function refactor(Node $node) : ?Node
{
$condAndExprs = $this->switchExprsResolver->resolve($node);
if ($this->matchSwitchAnalyzer->shouldSkipSwitch($node, $condAndExprs)) {
if (!\is_array($node->stmts)) {
return null;
}
if (!$this->matchSwitchAnalyzer->haveCondAndExprsMatchPotential($condAndExprs)) {
return null;
}
$isReturn = \false;
foreach ($condAndExprs as $condAndExpr) {
if ($condAndExpr->equalsMatchKind(MatchKind::RETURN)) {
$isReturn = \true;
break;
}
$expr = $condAndExpr->getExpr();
if ($expr instanceof Throw_) {
$hasChanged = \false;
foreach ($node->stmts as $key => $stmt) {
if (!$stmt instanceof Switch_) {
continue;
}
if (!$expr instanceof Assign) {
return null;
$nextStmt = $node->stmts[$key + 1] ?? null;
$condAndExprs = $this->switchExprsResolver->resolve($stmt);
if ($this->matchSwitchAnalyzer->shouldSkipSwitch($stmt, $condAndExprs, $nextStmt)) {
continue;
}
if (!$this->matchSwitchAnalyzer->haveCondAndExprsMatchPotential($condAndExprs)) {
continue;
}
$isReturn = \false;
foreach ($condAndExprs as $condAndExpr) {
if ($condAndExpr->equalsMatchKind(MatchKind::RETURN)) {
$isReturn = \true;
break;
}
$expr = $condAndExpr->getExpr();
if ($expr instanceof Throw_) {
continue;
}
if (!$expr instanceof Assign) {
continue 2;
}
}
$match = $this->matchFactory->createFromCondAndExprs($stmt->cond, $condAndExprs);
// implicit return default after switch
$match = $this->processImplicitReturnAfterSwitch($match, $condAndExprs, $nextStmt);
if (!$match instanceof Match_) {
continue;
}
$match = $this->processImplicitThrowsAfterSwitch($stmt, $match, $condAndExprs, $nextStmt);
$assignVar = $this->resolveAssignVar($condAndExprs);
$hasDefaultValue = $this->matchSwitchAnalyzer->hasDefaultValue($match);
if ($assignVar instanceof Expr) {
$previousStmt = $node->stmts[$key - 1] ?? null;
$assign = $this->changeToAssign($match, $assignVar, $hasDefaultValue, $previousStmt, $nextStmt);
if (!$assign instanceof Assign) {
continue;
}
$node->stmts[$key] = new Expression($assign);
$hasChanged = \true;
continue;
}
if (!$hasDefaultValue) {
continue;
}
$node->stmts[$key] = $isReturn ? new Return_($match) : new Expression($match);
$hasChanged = \true;
}
$match = $this->matchFactory->createFromCondAndExprs($node->cond, $condAndExprs);
// implicit return default after switch
$match = $this->processImplicitReturnAfterSwitch($node, $match, $condAndExprs);
if (!$match instanceof Match_) {
return null;
if ($hasChanged) {
return $node;
}
$match = $this->processImplicitThrowsAfterSwitch($node, $match, $condAndExprs);
$assignVar = $this->resolveAssignVar($condAndExprs);
$hasDefaultValue = $this->matchSwitchAnalyzer->hasDefaultValue($match);
if ($assignVar instanceof Expr) {
return $this->changeToAssign($node, $match, $assignVar, $hasDefaultValue);
}
if (!$hasDefaultValue) {
return null;
}
return $isReturn ? new Return_($match) : $match;
return null;
}
public function provideMinPhpVersion() : int
{
return PhpVersionFeature::MATCH_EXPRESSION;
}
private function changeToAssign(Switch_ $switch, Match_ $match, Expr $expr, bool $hasDefaultValue) : ?Assign
private function changeToAssign(Match_ $match, Expr $expr, bool $hasDefaultValue, ?Stmt $previousStmt, ?Stmt $nextStmt) : ?Assign
{
/** @var Stmt|null $nextStmt */
$nextStmt = $switch->getAttribute(AttributeKey::NEXT_NODE);
// containts next this expr?
if (!$hasDefaultValue && $this->isFollowedByReturnWithExprUsage($nextStmt, $expr)) {
return null;
}
$prevInitializedAssign = $this->betterNodeFinder->findFirstInlinedPrevious($switch, function (Node $node) use($expr) : bool {
return $node instanceof Assign && $this->nodeComparator->areNodesEqual($node->var, $expr);
});
// @todo extract?
$prevInitializedAssign = null;
if ($previousStmt instanceof Expression) {
$previousExpr = $previousStmt->expr;
if ($previousExpr instanceof Assign && $this->nodeComparator->areNodesEqual($previousExpr->var, $expr)) {
$prevInitializedAssign = $previousExpr;
}
}
$assign = new Assign($expr, $match);
if (!$prevInitializedAssign instanceof Assign) {
return $this->resolveCurrentAssign($hasDefaultValue, $assign);
@ -154,11 +179,12 @@ CODE_SAMPLE
return $assign;
}
} else {
$match->arms[\count($match->arms)] = new MatchArm(null, $prevInitializedAssign->expr);
$lastArmPosition = \count($match->arms);
$match->arms[$lastArmPosition] = new MatchArm(null, $prevInitializedAssign->expr);
}
$parentAssign = $prevInitializedAssign->getAttribute(AttributeKey::PARENT_NODE);
if ($parentAssign instanceof Expression) {
$this->removeNode($parentAssign);
$node = $prevInitializedAssign->getAttribute(AttributeKey::PARENT_NODE);
if ($node instanceof Expression) {
$this->removeNode($node);
}
return $assign;
}
@ -183,9 +209,8 @@ CODE_SAMPLE
/**
* @param CondAndExpr[] $condAndExprs
*/
private function processImplicitReturnAfterSwitch(Switch_ $switch, Match_ $match, array $condAndExprs) : ?Match_
private function processImplicitReturnAfterSwitch(Match_ $match, array $condAndExprs, ?Stmt $nextStmt) : ?Match_
{
$nextStmt = $switch->getAttribute(AttributeKey::NEXT_NODE);
if (!$nextStmt instanceof Return_) {
return $match;
}
@ -204,22 +229,21 @@ CODE_SAMPLE
$this->removeNode($nextStmt);
}
$condAndExprs[] = new CondAndExpr([], $returnedExpr, MatchKind::RETURN);
return $this->matchFactory->createFromCondAndExprs($switch->cond, $condAndExprs);
return $this->matchFactory->createFromCondAndExprs($match->cond, $condAndExprs);
}
/**
* @param CondAndExpr[] $condAndExprs
*/
private function processImplicitThrowsAfterSwitch(Switch_ $switch, Match_ $match, array $condAndExprs) : Match_
private function processImplicitThrowsAfterSwitch(Switch_ $switch, Match_ $match, array $condAndExprs, ?Stmt $nextStmt) : Match_
{
$nextNode = $switch->getAttribute(AttributeKey::NEXT_NODE);
if (!$nextNode instanceof ThrowsStmt) {
if (!$nextStmt instanceof ThrowsStmt) {
return $match;
}
if ($this->matchSwitchAnalyzer->hasDefaultValue($match)) {
return $match;
}
$this->removeNode($nextNode);
$throw = new Throw_($nextNode->expr);
$this->removeNode($nextStmt);
$throw = new Throw_($nextStmt->expr);
$condAndExprs[] = new CondAndExpr([], $throw, MatchKind::RETURN);
return $this->matchFactory->createFromCondAndExprs($switch->cond, $condAndExprs);
}

View File

@ -17,12 +17,12 @@ final class VersionResolver
* @api
* @var string
*/
public const PACKAGE_VERSION = '236b0ffe16821d82446dffd3603e5ccb8cba8621';
public const PACKAGE_VERSION = '6712529d24205b4b08e86f8da79876fb0d122c49';
/**
* @api
* @var string
*/
public const RELEASE_DATE = '2022-08-19 13:14:30';
public const RELEASE_DATE = '2022-08-19 14:37:58';
/**
* @var int
*/

View File

@ -265,25 +265,6 @@ final class BetterNodeFinder
return $this->nodeComparator->areNodesEqual($node->var, $expr);
});
}
/**
* Only search in previous Node/Stmt
* @api
*
* @param callable(Node $node): bool $filter
*/
public function findFirstInlinedPrevious(Node $node, callable $filter) : ?Node
{
$previousNode = $node->getAttribute(AttributeKey::PREVIOUS_NODE);
if (!$previousNode instanceof Node) {
return null;
}
$foundNode = $this->findFirst($previousNode, $filter);
// we found what we need
if ($foundNode instanceof Node) {
return $foundNode;
}
return $this->findFirstInlinedPrevious($previousNode, $filter);
}
/**
* Search in previous Node/Stmt, when no Node found, lookup previous Stmt of Parent Node
*
@ -468,6 +449,25 @@ final class BetterNodeFinder
}
return null;
}
/**
* Only search in previous Node/Stmt
* @api
*
* @param callable(Node $node): bool $filter
*/
private function findFirstInlinedPrevious(Node $node, callable $filter) : ?Node
{
$previousNode = $node->getAttribute(AttributeKey::PREVIOUS_NODE);
if (!$previousNode instanceof Node) {
return null;
}
$foundNode = $this->findFirst($previousNode, $filter);
// we found what we need
if ($foundNode instanceof Node) {
return $foundNode;
}
return $this->findFirstInlinedPrevious($previousNode, $filter);
}
/**
* @template T of Node
* @param \PhpParser\Node|mixed[] $nodes

2
vendor/autoload.php vendored
View File

@ -9,4 +9,4 @@ if (PHP_VERSION_ID < 50600) {
require_once __DIR__ . '/composer/autoload_real.php';
return ComposerAutoloaderInit85e0a1cc036e2557594b72be869a863f::getLoader();
return ComposerAutoloaderInitae68ab1a4f19e6758219b7e98a29a94f::getLoader();

View File

@ -2,7 +2,7 @@
// autoload_real.php @generated by Composer
class ComposerAutoloaderInit85e0a1cc036e2557594b72be869a863f
class ComposerAutoloaderInitae68ab1a4f19e6758219b7e98a29a94f
{
private static $loader;
@ -22,19 +22,19 @@ class ComposerAutoloaderInit85e0a1cc036e2557594b72be869a863f
return self::$loader;
}
spl_autoload_register(array('ComposerAutoloaderInit85e0a1cc036e2557594b72be869a863f', 'loadClassLoader'), true, true);
spl_autoload_register(array('ComposerAutoloaderInitae68ab1a4f19e6758219b7e98a29a94f', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
spl_autoload_unregister(array('ComposerAutoloaderInit85e0a1cc036e2557594b72be869a863f', 'loadClassLoader'));
spl_autoload_unregister(array('ComposerAutoloaderInitae68ab1a4f19e6758219b7e98a29a94f', 'loadClassLoader'));
require __DIR__ . '/autoload_static.php';
call_user_func(\Composer\Autoload\ComposerStaticInit85e0a1cc036e2557594b72be869a863f::getInitializer($loader));
call_user_func(\Composer\Autoload\ComposerStaticInitae68ab1a4f19e6758219b7e98a29a94f::getInitializer($loader));
$loader->setClassMapAuthoritative(true);
$loader->register(true);
$includeFiles = \Composer\Autoload\ComposerStaticInit85e0a1cc036e2557594b72be869a863f::$files;
$includeFiles = \Composer\Autoload\ComposerStaticInitae68ab1a4f19e6758219b7e98a29a94f::$files;
foreach ($includeFiles as $fileIdentifier => $file) {
composerRequire85e0a1cc036e2557594b72be869a863f($fileIdentifier, $file);
composerRequireae68ab1a4f19e6758219b7e98a29a94f($fileIdentifier, $file);
}
return $loader;
@ -46,7 +46,7 @@ class ComposerAutoloaderInit85e0a1cc036e2557594b72be869a863f
* @param string $file
* @return void
*/
function composerRequire85e0a1cc036e2557594b72be869a863f($fileIdentifier, $file)
function composerRequireae68ab1a4f19e6758219b7e98a29a94f($fileIdentifier, $file)
{
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
$GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;

View File

@ -4,7 +4,7 @@
namespace Composer\Autoload;
class ComposerStaticInit85e0a1cc036e2557594b72be869a863f
class ComposerStaticInitae68ab1a4f19e6758219b7e98a29a94f
{
public static $files = array (
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php',
@ -3253,9 +3253,9 @@ class ComposerStaticInit85e0a1cc036e2557594b72be869a863f
public static function getInitializer(ClassLoader $loader)
{
return \Closure::bind(function () use ($loader) {
$loader->prefixLengthsPsr4 = ComposerStaticInit85e0a1cc036e2557594b72be869a863f::$prefixLengthsPsr4;
$loader->prefixDirsPsr4 = ComposerStaticInit85e0a1cc036e2557594b72be869a863f::$prefixDirsPsr4;
$loader->classMap = ComposerStaticInit85e0a1cc036e2557594b72be869a863f::$classMap;
$loader->prefixLengthsPsr4 = ComposerStaticInitae68ab1a4f19e6758219b7e98a29a94f::$prefixLengthsPsr4;
$loader->prefixDirsPsr4 = ComposerStaticInitae68ab1a4f19e6758219b7e98a29a94f::$prefixDirsPsr4;
$loader->classMap = ComposerStaticInitae68ab1a4f19e6758219b7e98a29a94f::$classMap;
}, null, ClassLoader::class);
}