diff --git a/rules-tests/DeadCode/Rector/Foreach_/RemoveUnusedForeachKeyRector/Fixture/skip_key_used_in_next_stmt.php.inc b/rules-tests/DeadCode/Rector/Foreach_/RemoveUnusedForeachKeyRector/Fixture/skip_key_used_in_next_stmt.php.inc new file mode 100644 index 00000000000..d473d4dbb52 --- /dev/null +++ b/rules-tests/DeadCode/Rector/Foreach_/RemoveUnusedForeachKeyRector/Fixture/skip_key_used_in_next_stmt.php.inc @@ -0,0 +1,16 @@ + $value) { + // next + } + + return $result; + } +} diff --git a/rules/DeadCode/Rector/Foreach_/RemoveUnusedForeachKeyRector.php b/rules/DeadCode/Rector/Foreach_/RemoveUnusedForeachKeyRector.php index ed2172fe2d1..0d65fd1df47 100644 --- a/rules/DeadCode/Rector/Foreach_/RemoveUnusedForeachKeyRector.php +++ b/rules/DeadCode/Rector/Foreach_/RemoveUnusedForeachKeyRector.php @@ -5,8 +5,10 @@ namespace Rector\DeadCode\Rector\Foreach_; use PhpParser\Node; -use PhpParser\Node\Expr; +use PhpParser\Node\Expr\Variable; use PhpParser\Node\Stmt\Foreach_; +use Rector\Core\Contract\PhpParser\Node\StmtsAwareInterface; +use Rector\Core\NodeManipulator\StmtsManipulator; use Rector\Core\PhpParser\Node\BetterNodeFinder; use Rector\Core\Rector\AbstractRector; use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample; @@ -18,7 +20,8 @@ final class RemoveUnusedForeachKeyRector extends AbstractRector { public function __construct( - private readonly BetterNodeFinder $betterNodeFinder + private readonly BetterNodeFinder $betterNodeFinder, + private readonly StmtsManipulator $stmtsManipulator ) { } @@ -48,31 +51,51 @@ public function getRuleDefinition(): RuleDefinition */ public function getNodeTypes(): array { - return [Foreach_::class]; + return [StmtsAwareInterface::class]; } /** - * @param Foreach_ $node + * @param StmtsAwareInterface $node */ public function refactor(Node $node): ?Node { - if (! $node->keyVar instanceof Expr) { + if ($node->stmts === null) { return null; } - $keyVar = $node->keyVar; + $hasChanged = false; + foreach ($node->stmts as $key => $stmt) { + if (! $stmt instanceof Foreach_) { + continue; + } - $isNodeUsed = (bool) $this->betterNodeFinder->findFirst( - $node->stmts, - fn (Node $node): bool => $this->nodeComparator->areNodesEqual($node, $keyVar) - ); + if (! $stmt->keyVar instanceof Variable) { + continue; + } - if ($isNodeUsed) { - return null; + $keyVar = $stmt->keyVar; + + $isNodeUsed = (bool) $this->betterNodeFinder->findFirst( + $stmt->stmts, + fn (Node $node): bool => $this->nodeComparator->areNodesEqual($node, $keyVar) + ); + + if ($isNodeUsed) { + continue; + } + + if ($this->stmtsManipulator->isVariableUsedInNextStmt($node, $key + 1, (string) $this->getName($keyVar))) { + continue; + } + + $stmt->keyVar = null; + $hasChanged = true; } - $node->keyVar = null; + if ($hasChanged) { + return $node; + } - return $node; + return null; } }