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..8233b7d0 100644 --- a/src/Printer/CollectorMetadataPrinter.php +++ b/src/Printer/CollectorMetadataPrinter.php @@ -15,6 +15,7 @@ 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\Type\ClosureType; @@ -88,29 +89,56 @@ 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 instanceof Type) { + $printedParamType = $this->printTypeToString($phpdocType); + } else { + $paramType = $this->transformSelfToClassName($param->type, $className); + + if ($paramType instanceof NullableType) { + // unite to phpstan type + $paramType = new UnionType([$paramType->type, new Identifier('null')]); + } - $printedParamType = $this->standard->prettyPrint([$paramType]); - $printedParamType = str_replace('\Closure', 'callable', $printedParamType); - $printedParamType = ltrim($printedParamType, '\\'); - $printedParamType = str_replace('|\\', '|', $printedParamType); + 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); 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); + } } +