[Php80] Add default case when variable initialized on ChangeSwitchToMatchRector (#6230)

* Add failing test fixture for ChangeSwitchToMatchRector

# Failing Test for ChangeSwitchToMatchRector

Based on https://getrector.org/demo/f7f2ba48-3c19-4fdb-bc0a-e956e037eefd

It's important to add the default case to prevent this error when passing another code:
```
Fatal error: Uncaught UnhandledMatchError: Unhandled match value of type int
```

https://3v4l.org/E64Um

* Closes #6216

* phpstan

* phpstan

Co-authored-by: Ruud Kamphuis <ruudk@users.noreply.github.com>
This commit is contained in:
Abdul Malik Ikhsan 2021-04-25 14:07:36 +07:00 committed by GitHub
parent 774ac29000
commit 0ac5412aa0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 66 additions and 1 deletions

View File

@ -0,0 +1,40 @@
<?php
namespace Rector\Php80\Tests\Rector\Switch_\ChangeSwitchToMatchRector\Fixture;
final class AddDefaultCaseWhenVariableIsInitialized
{
public function getError(int $code) : ?string
{
$error = null;
switch ($code) {
case 10:
$error = 'code_10';
break;
case 11:
$error = 'code_11';
break;
}
return $error;
}
}
?>
-----
<?php
namespace Rector\Php80\Tests\Rector\Switch_\ChangeSwitchToMatchRector\Fixture;
final class AddDefaultCaseWhenVariableIsInitialized
{
public function getError(int $code) : ?string
{
$error = match ($code) {
10 => 'code_10',
11 => 'code_11',
default => null,
};
return $error;
}
}
?>

View File

@ -9,10 +9,12 @@ use PhpParser\Node\Expr;
use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Expr\Match_;
use PhpParser\Node\MatchArm;
use PhpParser\Node\Name;
use PhpParser\Node\Stmt\Expression;
use PhpParser\Node\Stmt\Return_;
use PhpParser\Node\Stmt\Switch_;
use Rector\Core\Rector\AbstractRector;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\Php80\NodeAnalyzer\SwitchAnalyzer;
use Rector\Php80\NodeResolver\SwitchExprsResolver;
use Rector\Php80\ValueObject\CondAndExpr;
@ -135,12 +137,35 @@ CODE_SAMPLE
}
if ($this->assignExpr) {
return new Assign($this->assignExpr, $match);
/** @var Expr $assignExpr */
$assignExpr = $this->assignExpr;
return $this->changeToAssign($node, $match, $assignExpr);
}
return $match;
}
private function changeToAssign(Switch_ $switch, Match_ $match, Expr $assignExpr): Assign
{
$prevInitializedAssign = $this->betterNodeFinder->findFirstPreviousOfNode($switch, function (Node $node) use ($assignExpr): bool {
return $node instanceof Assign && $this->nodeComparator->areNodesEqual($node->var, $assignExpr);
});
$assign = new Assign($assignExpr, $match);
if ($prevInitializedAssign instanceof Assign) {
/** @var Match_ $expr */
$expr = $assign->expr;
$expr->arms[] = new MatchArm(null, $prevInitializedAssign->expr);
$parentAssign = $prevInitializedAssign->getAttribute(AttributeKey::PARENT_NODE);
if ($parentAssign instanceof Expression) {
$this->removeNode($parentAssign);
}
}
return $assign;
}
private function shouldSkipSwitch(Switch_ $switch): bool
{
if (! $this->switchAnalyzer->hasEachCaseBreak($switch)) {