diff --git a/rules-tests/CodeQuality/Rector/Class_/ControllerMethodInjectionToConstructorRector/Fixture/internal_method_call_arg_removal.php.inc b/rules-tests/CodeQuality/Rector/Class_/ControllerMethodInjectionToConstructorRector/Fixture/internal_method_call_arg_removal.php.inc new file mode 100644 index 00000000..3f4c7e06 --- /dev/null +++ b/rules-tests/CodeQuality/Rector/Class_/ControllerMethodInjectionToConstructorRector/Fixture/internal_method_call_arg_removal.php.inc @@ -0,0 +1,56 @@ +problematic($logger); + } + + public function problematic(LoggerInterface $logger, ?string $optional = 'test') + { + $logger->log('level', 'value'); + dump($optional); + } +} + +?> +----- +problematic(); + } + + public function problematic(?string $optional = 'test') + { + $this->logger->log('level', 'value'); + dump($optional); + } +} + +?> diff --git a/rules/CodeQuality/Rector/Class_/ControllerMethodInjectionToConstructorRector.php b/rules/CodeQuality/Rector/Class_/ControllerMethodInjectionToConstructorRector.php index 23f6a317..376d2ad3 100644 --- a/rules/CodeQuality/Rector/Class_/ControllerMethodInjectionToConstructorRector.php +++ b/rules/CodeQuality/Rector/Class_/ControllerMethodInjectionToConstructorRector.php @@ -7,6 +7,7 @@ use Exception; use PhpParser\Node; use PhpParser\Node\Expr\Closure; +use PhpParser\Node\Expr\MethodCall; use PhpParser\Node\Expr\PropertyFetch; use PhpParser\Node\Expr\Variable; use PhpParser\Node\Name\FullyQualified; @@ -137,6 +138,9 @@ public function refactor(Node $node): ?Node /** @var array $methodParamNamesToReplace */ $methodParamNamesToReplace = []; + /** @var array $removedMethodArgPositions */ + $removedMethodArgPositions = []; + foreach ($node->getMethods() as $classMethod) { if ($this->shouldSkipClassMethod($classMethod)) { continue; @@ -223,6 +227,7 @@ public function refactor(Node $node): ?Node $paramsToRemove[] = [$classMethod, $key]; $propertyMetadatas[$paramName] = new PropertyMetadata($paramName, $paramType); $methodParamNamesToReplace[$classMethod->name->toString()][] = $paramName; + $removedMethodArgPositions[$classMethod->name->toString()][] = $key; } } @@ -254,9 +259,57 @@ public function refactor(Node $node): ?Node $this->replaceParamUseWithPropertyFetch($classMethod, $methodParamNamesToReplace[$methodName]); } + $this->updateCallSitesForRemovedParams($node, $removedMethodArgPositions); + return $node; } + /** + * @param array $removedArgPositionsByMethod + */ + private function updateCallSitesForRemovedParams(Class_ $class, array $removedArgPositionsByMethod): void + { + if ($removedArgPositionsByMethod === []) { + return; + } + + foreach ($class->getMethods() as $classMethod) { + if ($classMethod->stmts === null) { + continue; + } + + $this->traverseNodesWithCallable($classMethod->stmts, function (Node $node) use ( + $removedArgPositionsByMethod + ): ?MethodCall { + if (! $node instanceof MethodCall) { + return null; + } + + if (! $node->var instanceof Variable) { + return null; + } + + if (! $this->isName($node->var, 'this')) { + return null; + } + + $methodName = $this->getName($node->name); + if ($methodName === null || ! isset($removedArgPositionsByMethod[$methodName])) { + return null; + } + + $removedPositions = $removedArgPositionsByMethod[$methodName]; + rsort($removedPositions); + foreach ($removedPositions as $removedPosition) { + unset($node->args[$removedPosition]); + } + + $node->args = array_values($node->args); + return $node; + }); + } + } + private function shouldSkipClassMethod(ClassMethod $classMethod): bool { if ($classMethod->isMagic() && ! $this->isName($classMethod->name, MethodName::INVOKE)) {