diff --git a/rules-tests/Php72/Rector/FuncCall/ParseStrWithResultArgumentRector/Fixture/multiple_parse_str_usage.php.inc b/rules-tests/Php72/Rector/FuncCall/ParseStrWithResultArgumentRector/Fixture/multiple_parse_str_usage.php.inc new file mode 100644 index 00000000000..529eff703c4 --- /dev/null +++ b/rules-tests/Php72/Rector/FuncCall/ParseStrWithResultArgumentRector/Fixture/multiple_parse_str_usage.php.inc @@ -0,0 +1,39 @@ + +----- + diff --git a/rules/Php72/Rector/FuncCall/ParseStrWithResultArgumentRector.php b/rules/Php72/Rector/FuncCall/ParseStrWithResultArgumentRector.php index 4f66b986a26..90e7ac89064 100644 --- a/rules/Php72/Rector/FuncCall/ParseStrWithResultArgumentRector.php +++ b/rules/Php72/Rector/FuncCall/ParseStrWithResultArgumentRector.php @@ -9,9 +9,10 @@ use PhpParser\Node\Expr\FuncCall; use PhpParser\Node\Expr\Variable; use PhpParser\Node\Stmt; +use PhpParser\Node\Stmt\Expression; +use Rector\Core\Contract\PhpParser\Node\StmtsAwareInterface; use Rector\Core\Rector\AbstractRector; use Rector\Core\ValueObject\PhpVersionFeature; -use Rector\NodeTypeResolver\Node\AttributeKey; use Rector\VersionBonding\Contract\MinPhpVersionInterface; use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample; use Symplify\RuleDocGenerator\ValueObject\RuleDefinition; @@ -53,47 +54,83 @@ public function getRuleDefinition(): RuleDefinition */ public function getNodeTypes(): array { - return [FuncCall::class]; + return [StmtsAwareInterface::class]; } /** - * @param FuncCall $node + * @param StmtsAwareInterface $node */ - public function refactor(Node $node): ?Node + public function refactor(Node $node): ?StmtsAwareInterface { - if (! $this->isName($node, 'parse_str')) { - return null; - } + return $this->processStrWithResult($node, false); + } - if (isset($node->args[1])) { + private function processStrWithResult( + StmtsAwareInterface $stmtsAware, + bool $hasChanged, + int $jumpToKey = 0 + ): null|StmtsAwareInterface { + if ($stmtsAware->stmts === null) { return null; } - $resultVariable = new Variable('result'); - $node->args[1] = new Arg($resultVariable); + $totalKeys = array_key_last($stmtsAware->stmts); + for ($key = $jumpToKey; $key < $totalKeys; ++$key) { + if (! isset($stmtsAware->stmts[$key], $stmtsAware->stmts[$key + 1])) { + break; + } - $currentStmt = $this->betterNodeFinder->resolveCurrentStatement($node); - if (! $currentStmt instanceof Stmt) { - return null; + $stmt = $stmtsAware->stmts[$key]; + if ($this->shouldSkip($stmt)) { + continue; + } + + /** + * @var Expression $stmt + * @var FuncCall $expr + */ + $expr = $stmt->expr; + $resultVariable = new Variable('result'); + $expr->args[1] = new Arg($resultVariable); + + $nextExpression = $stmtsAware->stmts[$key + 1]; + $this->traverseNodesWithCallable($nextExpression, function (Node $node) use ($resultVariable, &$hasChanged): ?Variable { + if (! $node instanceof FuncCall) { + return null; + } + + if (! $this->isName($node, 'get_defined_vars')) { + return null; + } + + $hasChanged = true; + return $resultVariable; + }); + + return $this->processStrWithResult($stmtsAware, $hasChanged, $key + 2); } - $nextExpression = $currentStmt->getAttribute(AttributeKey::NEXT_NODE); - if (! $nextExpression instanceof Node) { - return null; + if ($hasChanged) { + return $stmtsAware; } - $this->traverseNodesWithCallable($nextExpression, function (Node $node) use ($resultVariable): ?Variable { - if (! $node instanceof FuncCall) { - return null; - } + return null; + } - if (! $this->isName($node, 'get_defined_vars')) { - return null; - } + private function shouldSkip(Stmt $stmt): bool + { + if (! $stmt instanceof Expression) { + return true; + } - return $resultVariable; - }); + if (! $stmt->expr instanceof FuncCall) { + return true; + } + + if (! $this->isName($stmt->expr, 'parse_str')) { + return true; + } - return $node; + return isset($stmt->expr->args[1]); } }