Skip to content

Commit 1557822

Browse files
authored
[DowngradePhp80] Handle infinite loop in array dim fetch on DowngradeMatchToSwitchRector (#365)
* [DowngradePhp80] Handle in array dim fetch on DowngradeMatchToSwitchRector * fix phpstan
1 parent f02926e commit 1557822

3 files changed

Lines changed: 72 additions & 2 deletions

File tree

phpstan.neon

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ parameters:
107107
- rules/DowngradePhp74/Rector/MethodCall/DowngradeReflectionGetTypeRector.php
108108
- rules/DowngradePhp80/Rector/MethodCall/DowngradeReflectionGetAttributesRector.php
109109
- rules/DowngradePhp73/Rector/String_/DowngradeFlexibleHeredocSyntaxRector.php
110+
- rules/DowngradePhp80/Rector/Expression/DowngradeMatchToSwitchRector.php
110111

111112
# local attribute key
112113
- '#Parameter \#2 \$attributeKey of static method Rector\\PhpParser\\NodeTraverser\\SimpleNodeTraverser\:\:decorateWithAttributeValue\(\) expects#'
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?php
2+
3+
namespace Rector\Tests\DowngradePhp80\Rector\Expression\DowngradeMatchToSwitchRector\Fixture;
4+
5+
class InArrayDimFetch
6+
{
7+
public function run($c, $n, $v)
8+
{
9+
$properties[match ($c) {
10+
'Error' => 'TypeError',
11+
'Exception' => 'ErrorException',
12+
default => $c,
13+
}][$n] = $v;
14+
}
15+
}
16+
17+
?>
18+
-----
19+
<?php
20+
21+
namespace Rector\Tests\DowngradePhp80\Rector\Expression\DowngradeMatchToSwitchRector\Fixture;
22+
23+
class InArrayDimFetch
24+
{
25+
public function run($c, $n, $v)
26+
{
27+
switch ($c) {
28+
case 'Error':
29+
$match = 'TypeError';
30+
break;
31+
case 'Exception':
32+
$match = 'ErrorException';
33+
break;
34+
default:
35+
$match = $c;
36+
break;
37+
}
38+
$properties[$match][$n] = $v;
39+
}
40+
}
41+
42+
?>

rules/DowngradePhp80/Rector/Expression/DowngradeMatchToSwitchRector.php

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use PhpParser\Node\Arg;
99
use PhpParser\Node\ArrayItem;
1010
use PhpParser\Node\Expr;
11+
use PhpParser\Node\Expr\ArrayDimFetch;
1112
use PhpParser\Node\Expr\ArrowFunction;
1213
use PhpParser\Node\Expr\Assign;
1314
use PhpParser\Node\Expr\BinaryOp;
@@ -19,6 +20,7 @@
1920
use PhpParser\Node\Expr\NullsafeMethodCall;
2021
use PhpParser\Node\Expr\StaticCall;
2122
use PhpParser\Node\Expr\Throw_;
23+
use PhpParser\Node\Expr\Variable;
2224
use PhpParser\Node\MatchArm;
2325
use PhpParser\Node\Stmt;
2426
use PhpParser\Node\Stmt\Break_;
@@ -29,6 +31,7 @@
2931
use PhpParser\Node\Stmt\Switch_;
3032
use PhpParser\NodeVisitor;
3133
use PHPStan\Analyser\Scope;
34+
use Rector\Naming\Naming\VariableNaming;
3235
use Rector\NodeTypeResolver\Node\AttributeKey;
3336
use Rector\Php72\NodeFactory\AnonymousFunctionFactory;
3437
use Rector\PHPStan\ScopeFetcher;
@@ -44,7 +47,8 @@
4447
final class DowngradeMatchToSwitchRector extends AbstractRector
4548
{
4649
public function __construct(
47-
private readonly AnonymousFunctionFactory $anonymousFunctionFactory
50+
private readonly AnonymousFunctionFactory $anonymousFunctionFactory,
51+
private readonly VariableNaming $variableNaming
4852
) {
4953
}
5054

@@ -102,14 +106,37 @@ public function getNodeTypes(): array
102106
/**
103107
* @param Echo_|Expression|Return_ $node
104108
*/
105-
public function refactor(Node $node): ?Node
109+
public function refactor(Node $node): null|Node|array
106110
{
107111
/** @var Match_|null $match */
108112
$match = null;
109113
$hasChanged = false;
110114

111115
$scope = ScopeFetcher::fetch($node);
112116

117+
if ($node instanceof Expression
118+
&& $node->expr instanceof Assign
119+
&& $node->expr->var instanceof ArrayDimFetch
120+
&& $node->expr->var->var instanceof ArrayDimFetch
121+
&& $node->expr->var->var->dim instanceof Match_) {
122+
$matchVariable = new Variable($this->variableNaming->createCountedValueName('match', $scope));
123+
$expression = new Expression(new Assign($matchVariable, $node->expr->var->var->dim));
124+
$expression->setAttribute(AttributeKey::SCOPE, $scope);
125+
$refactored = $this->refactor($expression);
126+
127+
if ($refactored === null) {
128+
return null;
129+
}
130+
131+
$node->expr->var->var->dim = $matchVariable;
132+
133+
$stmts = is_array($refactored)
134+
? $refactored :
135+
[$refactored];
136+
137+
return [...$stmts, $node];
138+
}
139+
113140
$this->traverseNodesWithCallable(
114141
$node,
115142
function (Node $subNode) use ($node, &$match, &$hasChanged, $scope) {

0 commit comments

Comments
 (0)