From 4eeb41f6f4aec6623b81be6df45408682d2fb481 Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Sun, 28 Jun 2026 19:37:10 +0200 Subject: [PATCH] [Arguments] Drop AstResolver from named-arg position resolution Replace AstResolver->resolveClassMethodOrFunctionFromCall() with ReflectionResolver in RemoveMethodCallParamRector and ArgumentDefaultValueReplacer. Both rules only need the parameter *name* at a given position to map it to a named-argument position. AstResolver re-parses the callee's source file into AST just to read that name; ParameterReflection (via ParametersAcceptorSelector) already exposes it without parsing. --- .../ArgumentDefaultValueReplacer.php | 25 ++++++++--------- .../RemoveMethodCallParamRector.php | 27 ++++++++++--------- 2 files changed, 28 insertions(+), 24 deletions(-) diff --git a/rules/Arguments/ArgumentDefaultValueReplacer.php b/rules/Arguments/ArgumentDefaultValueReplacer.php index c2e447c1403..8df454fab78 100644 --- a/rules/Arguments/ArgumentDefaultValueReplacer.php +++ b/rules/Arguments/ArgumentDefaultValueReplacer.php @@ -12,16 +12,17 @@ use PhpParser\Node\Expr\MethodCall; use PhpParser\Node\Expr\New_; use PhpParser\Node\Expr\StaticCall; -use PhpParser\Node\Expr\Variable; use PhpParser\Node\Identifier; use PhpParser\Node\Name; use PhpParser\Node\Stmt\ClassMethod; use PHPStan\Reflection\ClassReflection; +use PHPStan\Reflection\FunctionReflection; +use PHPStan\Reflection\MethodReflection; +use PHPStan\Reflection\ParametersAcceptorSelector; use Rector\Arguments\Contract\ReplaceArgumentDefaultValueInterface; use Rector\Arguments\ValueObject\ReplaceArgumentDefaultValue; use Rector\NodeAnalyzer\ArgsAnalyzer; use Rector\NodeTypeResolver\NodeTypeResolver; -use Rector\PhpParser\AstResolver; use Rector\PhpParser\Node\NodeFactory; use Rector\PhpParser\Node\Value\ValueResolver; use Rector\Reflection\ReflectionResolver; @@ -33,7 +34,6 @@ public function __construct( private NodeFactory $nodeFactory, private ValueResolver $valueResolver, private ArgsAnalyzer $argsAnalyzer, - private AstResolver $astResolver, private NodeTypeResolver $nodeTypeResolver, private ReflectionResolver $reflectionResolver ) { @@ -125,20 +125,21 @@ private function processArgs( // if it is, we use the position of the named argyment as the position to replace // if it is not, we cannot replace it if ($firstNamedArgPosition !== null && $position >= $firstNamedArgPosition) { - $call = $this->astResolver->resolveClassMethodOrFunctionFromCall($expr); - if ($call === null) { + $reflection = $this->reflectionResolver->resolveFunctionLikeReflectionFromCall($expr); + if (! $reflection instanceof MethodReflection && ! $reflection instanceof FunctionReflection) { return null; } - $paramName = null; - $variable = $call->params[$position]->var; - if ($variable instanceof Variable) { - $paramName = $variable->name; - } + $parametersAcceptor = ParametersAcceptorSelector::combineAcceptors($reflection->getVariants()); + $parameterReflection = $parametersAcceptor->getParameters()[$position] ?? null; $newPosition = -1; - if (is_string($paramName)) { - $newPosition = $this->argsAnalyzer->resolveArgPosition($arguments, $paramName, $newPosition); + if ($parameterReflection !== null) { + $newPosition = $this->argsAnalyzer->resolveArgPosition( + $arguments, + $parameterReflection->getName(), + $newPosition + ); } if ($newPosition === -1) { diff --git a/rules/Arguments/Rector/MethodCall/RemoveMethodCallParamRector.php b/rules/Arguments/Rector/MethodCall/RemoveMethodCallParamRector.php index e70daba48d2..edc37404665 100644 --- a/rules/Arguments/Rector/MethodCall/RemoveMethodCallParamRector.php +++ b/rules/Arguments/Rector/MethodCall/RemoveMethodCallParamRector.php @@ -7,12 +7,14 @@ use PhpParser\Node; use PhpParser\Node\Expr\MethodCall; use PhpParser\Node\Expr\StaticCall; -use PhpParser\Node\Expr\Variable; +use PHPStan\Reflection\FunctionReflection; +use PHPStan\Reflection\MethodReflection; +use PHPStan\Reflection\ParametersAcceptorSelector; use Rector\Arguments\ValueObject\RemoveMethodCallParam; use Rector\Contract\Rector\ConfigurableRectorInterface; use Rector\NodeAnalyzer\ArgsAnalyzer; -use Rector\PhpParser\AstResolver; use Rector\Rector\AbstractRector; +use Rector\Reflection\ReflectionResolver; use Symplify\RuleDocGenerator\ValueObject\CodeSample\ConfiguredCodeSample; use Symplify\RuleDocGenerator\ValueObject\RuleDefinition; use Webmozart\Assert\Assert; @@ -29,7 +31,7 @@ final class RemoveMethodCallParamRector extends AbstractRector implements Config private array $removeMethodCallParams = []; public function __construct( - private readonly AstResolver $astResolver, + private readonly ReflectionResolver $reflectionResolver, private readonly ArgsAnalyzer $argsAnalyzer, ) { } @@ -100,20 +102,21 @@ public function refactor(Node $node): ?Node // if it is, we use the position of the named argument as the position to remove // if it is not, we cannot remove it if ($firstNamedArgPosition !== null && $position >= $firstNamedArgPosition) { - $call = $this->astResolver->resolveClassMethodOrFunctionFromCall($node); - if ($call === null) { + $reflection = $this->reflectionResolver->resolveFunctionLikeReflectionFromCall($node); + if (! $reflection instanceof MethodReflection && ! $reflection instanceof FunctionReflection) { return null; } - $paramName = null; - $variable = $call->params[$position]->var; - if ($variable instanceof Variable) { - $paramName = $variable->name; - } + $parametersAcceptor = ParametersAcceptorSelector::combineAcceptors($reflection->getVariants()); + $parameterReflection = $parametersAcceptor->getParameters()[$position] ?? null; $newPosition = -1; - if (is_string($paramName)) { - $newPosition = $this->argsAnalyzer->resolveArgPosition($args, $paramName, $newPosition); + if ($parameterReflection !== null) { + $newPosition = $this->argsAnalyzer->resolveArgPosition( + $args, + $parameterReflection->getName(), + $newPosition + ); } if ($newPosition === -1) {