From caf2ae8ec2db7d650d99c3af8cabd07a2852a617 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Mon, 10 Nov 2025 00:54:19 +0700 Subject: [PATCH 1/2] [TypeDeclaration] Also update generic collection docblock on NarrowObjectReturnTypeRector --- ...update_generic_collection_docblock.php.inc | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 rules-tests/TypeDeclaration/Rector/ClassMethod/NarrowObjectReturnTypeRector/Fixture/also_update_generic_collection_docblock.php.inc diff --git a/rules-tests/TypeDeclaration/Rector/ClassMethod/NarrowObjectReturnTypeRector/Fixture/also_update_generic_collection_docblock.php.inc b/rules-tests/TypeDeclaration/Rector/ClassMethod/NarrowObjectReturnTypeRector/Fixture/also_update_generic_collection_docblock.php.inc new file mode 100644 index 00000000000..bbdf8a63297 --- /dev/null +++ b/rules-tests/TypeDeclaration/Rector/ClassMethod/NarrowObjectReturnTypeRector/Fixture/also_update_generic_collection_docblock.php.inc @@ -0,0 +1,41 @@ + + */ + protected function build(): Collection + { + return new ArrayCollection([new stdClass()]); + } +} + +?> +----- + + */ + protected function build(): \Doctrine\Common\Collections\ArrayCollection + { + return new ArrayCollection([new stdClass()]); + } +} + +?> From 25f57881206e6dd7fd3c009fb71aeacbc1146628 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Mon, 10 Nov 2025 01:05:39 +0700 Subject: [PATCH 2/2] Fix --- .../NarrowObjectReturnTypeRector.php | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/rules/TypeDeclaration/Rector/ClassMethod/NarrowObjectReturnTypeRector.php b/rules/TypeDeclaration/Rector/ClassMethod/NarrowObjectReturnTypeRector.php index 08da3729d4c..b4d4ef931c6 100644 --- a/rules/TypeDeclaration/Rector/ClassMethod/NarrowObjectReturnTypeRector.php +++ b/rules/TypeDeclaration/Rector/ClassMethod/NarrowObjectReturnTypeRector.php @@ -8,8 +8,14 @@ use PhpParser\Node\Identifier; use PhpParser\Node\Name\FullyQualified; use PhpParser\Node\Stmt\ClassMethod; +use PHPStan\PhpDocParser\Ast\PhpDoc\ReturnTagValueNode; +use PHPStan\PhpDocParser\Ast\Type\GenericTypeNode; use PHPStan\Reflection\ClassReflection; use PHPStan\Type\ObjectType; +use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo; +use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfoFactory; +use Rector\BetterPhpDocParser\ValueObject\Type\FullyQualifiedIdentifierTypeNode; +use Rector\Comments\NodeDocBlock\DocBlockUpdater; use Rector\PhpParser\AstResolver; use Rector\PhpParser\Node\BetterNodeFinder; use Rector\Rector\AbstractRector; @@ -28,6 +34,8 @@ public function __construct( private readonly BetterNodeFinder $betterNodeFinder, private readonly ReflectionResolver $reflectionResolver, private readonly AstResolver $astResolver, + private readonly PhpDocInfoFactory $phpDocInfoFactory, + private readonly DocBlockUpdater $docBlockUpdater ) { } @@ -140,9 +148,31 @@ public function refactor(Node $node): ?Node $node->returnType = new FullyQualified($actualReturnClass); + $this->updateDocblock($node, $actualReturnClass); + return $node; } + private function updateDocblock(ClassMethod $classMethod, string $actualReturnClass): void + { + $phpDocInfo = $this->phpDocInfoFactory->createFromNode($classMethod); + if (! $phpDocInfo instanceof PhpDocInfo) { + return; + } + + $returnTagValueNode = $phpDocInfo->getReturnTagValue(); + if (! $returnTagValueNode instanceof ReturnTagValueNode) { + return; + } + + if (! $returnTagValueNode->type instanceof GenericTypeNode) { + return; + } + + $returnTagValueNode->type->type = new FullyQualifiedIdentifierTypeNode($actualReturnClass); + $this->docBlockUpdater->updateRefactoredNodeWithPhpDocInfo($classMethod); + } + private function isDeclaredTypeFinal(string $declaredType): bool { if ($declaredType === 'object') {