2021-06-07 21:47:57 +00:00
|
|
|
<?php
|
|
|
|
|
|
|
|
declare (strict_types=1);
|
2022-06-06 17:12:56 +00:00
|
|
|
namespace Rector\Php80\NodeAnalyzer;
|
2021-06-07 21:47:57 +00:00
|
|
|
|
2022-06-06 17:12:56 +00:00
|
|
|
use PhpParser\Node;
|
|
|
|
use PhpParser\Node\Expr;
|
|
|
|
use PhpParser\Node\Expr\ArrayDimFetch;
|
|
|
|
use PhpParser\Node\Expr\Assign;
|
|
|
|
use PhpParser\Node\Expr\Match_;
|
2022-08-19 12:43:13 +00:00
|
|
|
use PhpParser\Node\Stmt;
|
2022-06-06 17:12:56 +00:00
|
|
|
use PhpParser\Node\Stmt\Expression;
|
|
|
|
use PhpParser\Node\Stmt\Return_;
|
|
|
|
use PhpParser\Node\Stmt\Switch_;
|
|
|
|
use PhpParser\Node\Stmt\Throw_;
|
|
|
|
use Rector\NodeNameResolver\NodeNameResolver;
|
|
|
|
use Rector\Php80\Enum\MatchKind;
|
|
|
|
use Rector\Php80\ValueObject\CondAndExpr;
|
2024-01-02 02:40:38 +00:00
|
|
|
use Rector\PhpParser\Comparing\NodeComparator;
|
|
|
|
use Rector\PhpParser\Printer\BetterStandardPrinter;
|
2021-06-07 21:47:57 +00:00
|
|
|
final class MatchSwitchAnalyzer
|
|
|
|
{
|
|
|
|
/**
|
2023-06-11 23:01:39 +00:00
|
|
|
* @readonly
|
2021-06-07 21:47:57 +00:00
|
|
|
* @var \Rector\Php80\NodeAnalyzer\SwitchAnalyzer
|
|
|
|
*/
|
|
|
|
private $switchAnalyzer;
|
|
|
|
/**
|
2023-06-11 23:01:39 +00:00
|
|
|
* @readonly
|
2021-06-07 21:47:57 +00:00
|
|
|
* @var \Rector\NodeNameResolver\NodeNameResolver
|
|
|
|
*/
|
|
|
|
private $nodeNameResolver;
|
2022-05-19 16:31:50 +00:00
|
|
|
/**
|
2023-06-11 23:01:39 +00:00
|
|
|
* @readonly
|
2024-01-02 02:40:38 +00:00
|
|
|
* @var \Rector\PhpParser\Comparing\NodeComparator
|
2022-05-19 16:31:50 +00:00
|
|
|
*/
|
|
|
|
private $nodeComparator;
|
2023-03-02 12:25:38 +00:00
|
|
|
/**
|
2023-06-11 23:01:39 +00:00
|
|
|
* @readonly
|
2024-01-02 02:40:38 +00:00
|
|
|
* @var \Rector\PhpParser\Printer\BetterStandardPrinter
|
2023-03-02 12:25:38 +00:00
|
|
|
*/
|
|
|
|
private $betterStandardPrinter;
|
|
|
|
public function __construct(\Rector\Php80\NodeAnalyzer\SwitchAnalyzer $switchAnalyzer, NodeNameResolver $nodeNameResolver, NodeComparator $nodeComparator, BetterStandardPrinter $betterStandardPrinter)
|
2021-06-07 21:47:57 +00:00
|
|
|
{
|
|
|
|
$this->switchAnalyzer = $switchAnalyzer;
|
|
|
|
$this->nodeNameResolver = $nodeNameResolver;
|
2022-05-19 16:31:50 +00:00
|
|
|
$this->nodeComparator = $nodeComparator;
|
2023-03-02 12:25:38 +00:00
|
|
|
$this->betterStandardPrinter = $betterStandardPrinter;
|
2021-06-07 21:47:57 +00:00
|
|
|
}
|
2022-08-19 14:05:38 +00:00
|
|
|
/**
|
|
|
|
* @param CondAndExpr[] $condAndExprs
|
|
|
|
*/
|
|
|
|
public function isReturnCondsAndExprs(array $condAndExprs) : bool
|
|
|
|
{
|
|
|
|
foreach ($condAndExprs as $condAndExpr) {
|
|
|
|
if ($condAndExpr->equalsMatchKind(MatchKind::RETURN)) {
|
|
|
|
return \true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return \false;
|
|
|
|
}
|
2021-06-07 23:07:01 +00:00
|
|
|
/**
|
|
|
|
* @param CondAndExpr[] $condAndExprs
|
|
|
|
*/
|
2022-08-19 12:43:13 +00:00
|
|
|
public function shouldSkipSwitch(Switch_ $switch, array $condAndExprs, ?Stmt $nextStmt) : bool
|
2021-06-07 21:47:57 +00:00
|
|
|
{
|
2021-06-07 23:07:01 +00:00
|
|
|
if ($condAndExprs === []) {
|
|
|
|
return \true;
|
|
|
|
}
|
2021-06-07 21:47:57 +00:00
|
|
|
if (!$this->switchAnalyzer->hasEachCaseBreak($switch)) {
|
|
|
|
return \true;
|
|
|
|
}
|
2022-11-15 20:31:43 +00:00
|
|
|
if ($this->switchAnalyzer->hasDifferentTypeCases($switch->cases, $switch->cond)) {
|
2022-04-24 15:27:24 +00:00
|
|
|
return \true;
|
|
|
|
}
|
2021-06-07 21:47:57 +00:00
|
|
|
if (!$this->switchAnalyzer->hasEachCaseSingleStmt($switch)) {
|
|
|
|
return \false;
|
|
|
|
}
|
2022-03-31 11:04:24 +00:00
|
|
|
if ($this->switchAnalyzer->hasDefaultSingleStmt($switch)) {
|
2021-06-08 11:02:16 +00:00
|
|
|
return \false;
|
|
|
|
}
|
|
|
|
// is followed by return? is considered implicit default
|
2022-08-19 12:43:13 +00:00
|
|
|
if ($this->isNextStmtReturnWithExpr($switch, $nextStmt)) {
|
2021-06-08 13:06:20 +00:00
|
|
|
return \false;
|
2021-06-08 11:02:16 +00:00
|
|
|
}
|
2022-08-19 12:43:13 +00:00
|
|
|
return !$nextStmt instanceof Throw_;
|
2021-06-07 21:47:57 +00:00
|
|
|
}
|
|
|
|
/**
|
|
|
|
* @param CondAndExpr[] $condAndExprs
|
|
|
|
*/
|
|
|
|
public function haveCondAndExprsMatchPotential(array $condAndExprs) : bool
|
|
|
|
{
|
2021-06-07 23:07:01 +00:00
|
|
|
$uniqueCondAndExprKinds = $this->resolveUniqueKindsWithoutThrows($condAndExprs);
|
2021-06-07 21:47:57 +00:00
|
|
|
if (\count($uniqueCondAndExprKinds) > 1) {
|
|
|
|
return \false;
|
|
|
|
}
|
|
|
|
$assignVariableNames = [];
|
|
|
|
foreach ($condAndExprs as $condAndExpr) {
|
|
|
|
$expr = $condAndExpr->getExpr();
|
2022-06-07 08:22:29 +00:00
|
|
|
if (!$expr instanceof Assign) {
|
2021-06-07 21:47:57 +00:00
|
|
|
continue;
|
|
|
|
}
|
2022-06-07 08:22:29 +00:00
|
|
|
if ($expr->var instanceof ArrayDimFetch) {
|
2023-03-02 12:25:38 +00:00
|
|
|
$assignVariableNames[] = $this->betterStandardPrinter->print($expr->var);
|
2021-06-07 21:47:57 +00:00
|
|
|
} else {
|
|
|
|
$assignVariableNames[] = \get_class($expr->var) . $this->nodeNameResolver->getName($expr->var);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
$assignVariableNames = \array_unique($assignVariableNames);
|
|
|
|
return \count($assignVariableNames) <= 1;
|
|
|
|
}
|
2022-08-19 13:25:59 +00:00
|
|
|
/**
|
|
|
|
* @param CondAndExpr[] $condAndExprs
|
|
|
|
*/
|
|
|
|
public function hasCondsAndExprDefaultValue(array $condAndExprs) : bool
|
|
|
|
{
|
|
|
|
foreach ($condAndExprs as $condAndExpr) {
|
|
|
|
if ($condAndExpr->getCondExprs() === null) {
|
|
|
|
return \true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return \false;
|
|
|
|
}
|
2022-06-07 08:22:29 +00:00
|
|
|
public function hasDefaultValue(Match_ $match) : bool
|
2021-06-08 11:02:16 +00:00
|
|
|
{
|
|
|
|
foreach ($match->arms as $matchArm) {
|
|
|
|
if ($matchArm->conds === null) {
|
|
|
|
return \true;
|
|
|
|
}
|
|
|
|
if ($matchArm->conds === []) {
|
|
|
|
return \true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return \false;
|
|
|
|
}
|
2021-06-07 21:47:57 +00:00
|
|
|
/**
|
|
|
|
* @param CondAndExpr[] $condAndExprs
|
2022-05-29 22:41:07 +00:00
|
|
|
* @return array<MatchKind::*>
|
2021-06-07 21:47:57 +00:00
|
|
|
*/
|
2021-06-07 23:07:01 +00:00
|
|
|
private function resolveUniqueKindsWithoutThrows(array $condAndExprs) : array
|
2021-06-07 21:47:57 +00:00
|
|
|
{
|
|
|
|
$condAndExprKinds = [];
|
|
|
|
foreach ($condAndExprs as $condAndExpr) {
|
2022-06-07 08:22:29 +00:00
|
|
|
if ($condAndExpr->equalsMatchKind(MatchKind::THROW)) {
|
2021-06-07 23:07:01 +00:00
|
|
|
continue;
|
|
|
|
}
|
2021-06-28 21:18:55 +00:00
|
|
|
$condAndExprKinds[] = $condAndExpr->getMatchKind();
|
2021-06-07 21:47:57 +00:00
|
|
|
}
|
|
|
|
return \array_unique($condAndExprKinds);
|
|
|
|
}
|
2022-08-19 12:43:13 +00:00
|
|
|
private function isNextStmtReturnWithExpr(Switch_ $switch, ?Stmt $nextStmt) : bool
|
2021-06-08 13:06:20 +00:00
|
|
|
{
|
2022-08-19 12:43:13 +00:00
|
|
|
if (!$nextStmt instanceof Return_) {
|
2021-06-08 13:06:20 +00:00
|
|
|
return \false;
|
|
|
|
}
|
2022-08-19 12:43:13 +00:00
|
|
|
if (!$nextStmt->expr instanceof Expr) {
|
2022-05-19 16:31:50 +00:00
|
|
|
return \false;
|
|
|
|
}
|
|
|
|
foreach ($switch->cases as $case) {
|
|
|
|
/** @var Expression[] $expressions */
|
2022-06-21 15:38:46 +00:00
|
|
|
$expressions = \array_filter($case->stmts, static function (Node $node) : bool {
|
2022-06-07 08:22:29 +00:00
|
|
|
return $node instanceof Expression;
|
2022-05-19 16:31:50 +00:00
|
|
|
});
|
|
|
|
foreach ($expressions as $expression) {
|
2022-06-07 08:22:29 +00:00
|
|
|
if (!$expression->expr instanceof Assign) {
|
2022-05-19 16:31:50 +00:00
|
|
|
continue;
|
|
|
|
}
|
2022-08-19 12:43:13 +00:00
|
|
|
if (!$this->nodeComparator->areNodesEqual($expression->expr->var, $nextStmt->expr)) {
|
2022-05-19 16:31:50 +00:00
|
|
|
return \false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return \true;
|
2021-06-08 13:06:20 +00:00
|
|
|
}
|
2021-06-07 21:47:57 +00:00
|
|
|
}
|