diff --git a/rules/TypeDeclaration/Rector/ClassMethod/StrictArrayParamDimFetchRector.php b/rules/TypeDeclaration/Rector/ClassMethod/StrictArrayParamDimFetchRector.php index e44dcc82d16..df6d9921355 100644 --- a/rules/TypeDeclaration/Rector/ClassMethod/StrictArrayParamDimFetchRector.php +++ b/rules/TypeDeclaration/Rector/ClassMethod/StrictArrayParamDimFetchRector.php @@ -96,12 +96,22 @@ public function getNodeTypes(): array */ public function refactor(Node $node): ?Node { - // cheap bail - nothing to add, skip costly parent reflection guards below - $hasUntypedParam = array_any( - $node->getParams(), - static fn (Param $param): bool => ! $param->type instanceof Node && ! $param->variadic - ); - if (! $hasUntypedParam) { + // cheap bail - collect untyped params, skip costly parent reflection guards below + $untypedParamNames = []; + foreach ($node->getParams() as $param) { + if ($param->type instanceof Node || $param->variadic) { + continue; + } + + $untypedParamNames[] = $this->getName($param); + } + + if ($untypedParamNames === []) { + return null; + } + + // cheap syntactic bail - no param is dim-fetched at all, skip reflection and type resolution + if (! $this->hasArrayDimFetchOnParamNames($node, $untypedParamNames)) { return null; } @@ -151,6 +161,45 @@ public function refactor(Node $node): ?Node return null; } + /** + * @param string[] $paramNames + */ + private function hasArrayDimFetchOnParamNames( + ClassMethod|Function_|Closure $functionLike, + array $paramNames + ): bool { + if ($functionLike->stmts === null) { + return false; + } + + $hasArrayDimFetch = false; + $this->traverseNodesWithCallable($functionLike->stmts, function (Node $node) use ( + $paramNames, + &$hasArrayDimFetch, + ): int|null { + if ($node instanceof Class_ || $node instanceof FunctionLike) { + return NodeVisitor::DONT_TRAVERSE_CURRENT_AND_CHILDREN; + } + + if (! $node instanceof ArrayDimFetch) { + return null; + } + + if (! $node->var instanceof Variable) { + return null; + } + + if (! in_array($this->getName($node->var), $paramNames, true)) { + return null; + } + + $hasArrayDimFetch = true; + return NodeVisitor::STOP_TRAVERSAL; + }); + + return $hasArrayDimFetch; + } + private function isParamAccessedArrayDimFetch(Param $param, ClassMethod|Function_|Closure $functionLike): bool { if ($functionLike->stmts === null) {