From 4547621f6c32cf18b9eb20e438e5b6853dd47918 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Mon, 6 Oct 2025 10:00:27 +0200 Subject: [PATCH 1/4] Fix reproducer --- .../Fixture/Generics/SkipPassedGenerics.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/Rules/NarrowPublicClassMethodParamTypeRule/Fixture/Generics/SkipPassedGenerics.php b/tests/Rules/NarrowPublicClassMethodParamTypeRule/Fixture/Generics/SkipPassedGenerics.php index 309ba5c5..0ad4fc8d 100644 --- a/tests/Rules/NarrowPublicClassMethodParamTypeRule/Fixture/Generics/SkipPassedGenerics.php +++ b/tests/Rules/NarrowPublicClassMethodParamTypeRule/Fixture/Generics/SkipPassedGenerics.php @@ -15,10 +15,10 @@ class User public function doFoo(GenericA $g):void { } -} -/** @param GenericA $g */ -function doFoo($g):void { - $user = new User(); - $user->doFoo($g); + /** @param GenericA $g */ + function doBar($g):void { + $this->doFoo($g); + } } + From 71a6fa1b5ceffea5c015cd1d6caf68694ecddff4 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Mon, 6 Oct 2025 10:11:32 +0200 Subject: [PATCH 2/4] fix --- .../PublicClassMethodParamTypesCollector.php | 3 +- src/Printer/CollectorMetadataPrinter.php | 52 ++++++++++++++----- 2 files changed, 41 insertions(+), 14 deletions(-) diff --git a/src/Collector/ClassMethod/PublicClassMethodParamTypesCollector.php b/src/Collector/ClassMethod/PublicClassMethodParamTypesCollector.php index 3f43878d..6835c5d5 100644 --- a/src/Collector/ClassMethod/PublicClassMethodParamTypesCollector.php +++ b/src/Collector/ClassMethod/PublicClassMethodParamTypesCollector.php @@ -73,7 +73,8 @@ public function processNode(Node $node, Scope $scope): ?array $printedParamTypesString = $this->collectorMetadataPrinter->printParamTypesToString( $node, - $classReflection->getName() + $classReflection, + $scope ); return [$classReflection->getName(), $methodName, $printedParamTypesString, $node->getLine()]; } diff --git a/src/Printer/CollectorMetadataPrinter.php b/src/Printer/CollectorMetadataPrinter.php index b84a51b2..064f6eae 100644 --- a/src/Printer/CollectorMetadataPrinter.php +++ b/src/Printer/CollectorMetadataPrinter.php @@ -15,8 +15,10 @@ use PhpParser\Node\UnionType; use PhpParser\PrettyPrinter\Standard; use PHPStan\Analyser\Scope; +use PHPStan\Reflection\ClassReflection; use PHPStan\Reflection\ExtendedMethodReflection; use PHPStan\Reflection\ParametersAcceptorSelector; +use PHPStan\Reflection\ReflectionProvider; use PHPStan\Type\ClosureType; use PHPStan\Type\IntegerRangeType; use PHPStan\Type\IntersectionType; @@ -88,29 +90,53 @@ public function printArgTypesAsString( return implode('|', $stringArgTypes); } - public function printParamTypesToString(ClassMethod $classMethod, string $className): string + public function printParamTypesToString(ClassMethod $classMethod, ClassReflection $classReflection, Scope $scope): string { + $className = $classReflection->getName(); + + $parametersReflection = []; + if ($classReflection->hasMethod($classMethod->name->name)) { + $methodReflection = $classReflection->getMethod($classMethod->name->name, $scope); + $variants = $methodReflection->getVariants(); + if (count($variants) === 1) { + $parametersReflection = $variants[0]->getParameters(); + } + } + $printedParamTypes = []; - foreach ($classMethod->params as $param) { + foreach ($classMethod->params as $i => $param) { if ($param->type === null) { $printedParamTypes[] = ''; continue; } - $paramType = $this->transformSelfToClassName($param->type, $className); - if ($paramType instanceof NullableType) { - // unite to phpstan type - $paramType = new UnionType([$paramType->type, new Identifier('null')]); + $phpdocType = null; + if (array_key_exists($i, $parametersReflection)) { + $paramphpdocType = $parametersReflection[$i]->getPhpDocType(); + if (!$paramphpdocType instanceof MixedType) { + $phpdocType = $paramphpdocType; + } } - if ($paramType instanceof UnionType || $paramType instanceof NodeIntersectionType) { - $paramType = $this->resolveSortedTypes($paramType, $className); - } + if ($phpdocType) { + $printedParamType = $this->printTypeToString($phpdocType); + } else { + $paramType = $this->transformSelfToClassName($param->type, $className); - $printedParamType = $this->standard->prettyPrint([$paramType]); - $printedParamType = str_replace('\Closure', 'callable', $printedParamType); - $printedParamType = ltrim($printedParamType, '\\'); - $printedParamType = str_replace('|\\', '|', $printedParamType); + if ($paramType instanceof NullableType) { + // unite to phpstan type + $paramType = new UnionType([$paramType->type, new Identifier('null')]); + } + + if ($paramType instanceof UnionType || $paramType instanceof NodeIntersectionType) { + $paramType = $this->resolveSortedTypes($paramType, $className); + } + + $printedParamType = $this->standard->prettyPrint([$paramType]); + $printedParamType = str_replace('\Closure', 'callable', $printedParamType); + $printedParamType = ltrim($printedParamType, '\\'); + $printedParamType = str_replace('|\\', '|', $printedParamType); + } // to avoid DateTime vs DateTimeImmutable vs DateTimeInterface conflicts $printedParamType = $this->normalizeDateTime($printedParamType); From f553fac8088c89a316cbf0499cc3cce6810d9166 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Mon, 6 Oct 2025 10:12:47 +0200 Subject: [PATCH 3/4] cs --- src/Printer/CollectorMetadataPrinter.php | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/Printer/CollectorMetadataPrinter.php b/src/Printer/CollectorMetadataPrinter.php index 064f6eae..50ba99f0 100644 --- a/src/Printer/CollectorMetadataPrinter.php +++ b/src/Printer/CollectorMetadataPrinter.php @@ -18,7 +18,6 @@ use PHPStan\Reflection\ClassReflection; use PHPStan\Reflection\ExtendedMethodReflection; use PHPStan\Reflection\ParametersAcceptorSelector; -use PHPStan\Reflection\ReflectionProvider; use PHPStan\Type\ClosureType; use PHPStan\Type\IntegerRangeType; use PHPStan\Type\IntersectionType; @@ -90,8 +89,11 @@ public function printArgTypesAsString( return implode('|', $stringArgTypes); } - public function printParamTypesToString(ClassMethod $classMethod, ClassReflection $classReflection, Scope $scope): string - { + public function printParamTypesToString( + ClassMethod $classMethod, + ClassReflection $classReflection, + Scope $scope + ): string { $className = $classReflection->getName(); $parametersReflection = []; @@ -113,7 +115,7 @@ public function printParamTypesToString(ClassMethod $classMethod, ClassReflectio $phpdocType = null; if (array_key_exists($i, $parametersReflection)) { $paramphpdocType = $parametersReflection[$i]->getPhpDocType(); - if (!$paramphpdocType instanceof MixedType) { + if (! $paramphpdocType instanceof MixedType) { $phpdocType = $paramphpdocType; } } From fe16b09288f31a147926245c6e45bb6014f8b9b7 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Mon, 6 Oct 2025 10:14:19 +0200 Subject: [PATCH 4/4] fix rector --- src/Printer/CollectorMetadataPrinter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Printer/CollectorMetadataPrinter.php b/src/Printer/CollectorMetadataPrinter.php index 50ba99f0..8233b7d0 100644 --- a/src/Printer/CollectorMetadataPrinter.php +++ b/src/Printer/CollectorMetadataPrinter.php @@ -120,7 +120,7 @@ public function printParamTypesToString( } } - if ($phpdocType) { + if ($phpdocType instanceof Type) { $printedParamType = $this->printTypeToString($phpdocType); } else { $paramType = $this->transformSelfToClassName($param->type, $className);