diff --git a/rules-tests/TypeDeclaration/Rector/ClassMethod/NarrowObjectReturnTypeRector/Fixture/skip_no_key_generic_object_return_doc.php.inc b/rules-tests/TypeDeclaration/Rector/ClassMethod/NarrowObjectReturnTypeRector/Fixture/skip_no_key_generic_object_return_doc.php.inc new file mode 100644 index 00000000000..f762a77f14b --- /dev/null +++ b/rules-tests/TypeDeclaration/Rector/ClassMethod/NarrowObjectReturnTypeRector/Fixture/skip_no_key_generic_object_return_doc.php.inc @@ -0,0 +1,15 @@ + + */ + public function run(): \Iterator + { + $arr = [new \stdClass]; + return new \ArrayIterator($arr); + } +} diff --git a/rules/TypeDeclaration/Rector/ClassMethod/NarrowObjectReturnTypeRector.php b/rules/TypeDeclaration/Rector/ClassMethod/NarrowObjectReturnTypeRector.php index 826b960a60f..708bd0a9782 100644 --- a/rules/TypeDeclaration/Rector/ClassMethod/NarrowObjectReturnTypeRector.php +++ b/rules/TypeDeclaration/Rector/ClassMethod/NarrowObjectReturnTypeRector.php @@ -12,6 +12,7 @@ use PHPStan\PhpDocParser\Ast\Type\GenericTypeNode; use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode; use PHPStan\Reflection\ClassReflection; +use PHPStan\Type\Generic\GenericObjectType; use PHPStan\Type\ObjectType; use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo; use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfoFactory; @@ -147,7 +148,7 @@ public function refactor(Node $node): ?Node return null; } - if (! $this->isNarrowingValid($declaredType, $actualReturnClass)) { + if (! $this->isNarrowingValid($node, $declaredType, $actualReturnClass)) { return null; } @@ -228,7 +229,7 @@ private function isActualTypeAnonymous(string $actualType): bool return $classReflection->isAnonymous(); } - private function isNarrowingValid(string $declaredType, string $actualType): bool + private function isNarrowingValid(ClassMethod $classMethod, string $declaredType, string $actualType): bool { if ($declaredType === 'object') { return true; @@ -237,8 +238,18 @@ private function isNarrowingValid(string $declaredType, string $actualType): boo $actualObjectType = new ObjectType($actualType); $declaredObjectType = new ObjectType($declaredType); - return $declaredObjectType->isSuperTypeOf($actualObjectType) - ->yes(); + if (! $declaredObjectType->isSuperTypeOf($actualObjectType) + ->yes()) { + return false; + } + + $phpDocInfo = $this->phpDocInfoFactory->createFromNode($classMethod); + if (! $phpDocInfo instanceof PhpDocInfo) { + return true; + } + + $returnType = $phpDocInfo->getReturnType(); + return ! $returnType instanceof GenericObjectType; } private function hasParentMethodWithNonObjectReturn(ClassMethod $classMethod): bool