From 3fb8989640823babdea135e56fef64bd3151a102 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Mon, 15 Sep 2025 20:38:24 +0700 Subject: [PATCH 1/5] [TypeDeclarationDocblocks] use empty array shape array{} for returns empty array on DocblockReturnArrayFromDirectArrayInstanceRector --- .../Fixture/return_empty.php.inc | 2 +- .../DocblockReturnArrayFromDirectArrayInstanceRector.php | 9 ++++++++- .../TypeResolver/ConstantArrayTypeGeneralizer.php | 5 ----- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/rules-tests/TypeDeclarationDocblocks/Rector/ClassMethod/DocblockReturnArrayFromDirectArrayInstanceRector/Fixture/return_empty.php.inc b/rules-tests/TypeDeclarationDocblocks/Rector/ClassMethod/DocblockReturnArrayFromDirectArrayInstanceRector/Fixture/return_empty.php.inc index a68fbdab672..4beb2996db5 100644 --- a/rules-tests/TypeDeclarationDocblocks/Rector/ClassMethod/DocblockReturnArrayFromDirectArrayInstanceRector/Fixture/return_empty.php.inc +++ b/rules-tests/TypeDeclarationDocblocks/Rector/ClassMethod/DocblockReturnArrayFromDirectArrayInstanceRector/Fixture/return_empty.php.inc @@ -19,7 +19,7 @@ namespace Rector\Tests\TypeDeclarationDocblocks\Rector\ClassMethod\DocblockRetur class ReturnEmpty { /** - * @return array + * @return array{} */ public function run(): array { diff --git a/rules/TypeDeclarationDocblocks/Rector/ClassMethod/DocblockReturnArrayFromDirectArrayInstanceRector.php b/rules/TypeDeclarationDocblocks/Rector/ClassMethod/DocblockReturnArrayFromDirectArrayInstanceRector.php index deca987e725..ea0ee09294c 100644 --- a/rules/TypeDeclarationDocblocks/Rector/ClassMethod/DocblockReturnArrayFromDirectArrayInstanceRector.php +++ b/rules/TypeDeclarationDocblocks/Rector/ClassMethod/DocblockReturnArrayFromDirectArrayInstanceRector.php @@ -10,7 +10,9 @@ use PhpParser\Node\Stmt\Function_; use PhpParser\Node\Stmt\Return_; use PHPStan\PhpDocParser\Ast\PhpDoc\ReturnTagValueNode; +use PHPStan\PhpDocParser\Ast\Type\ArrayShapeNode; use PHPStan\Type\Constant\ConstantArrayType; +use PHPStan\Type\NeverType; use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfoFactory; use Rector\Comments\NodeDocBlock\DocBlockUpdater; use Rector\Rector\AbstractRector; @@ -106,7 +108,12 @@ public function refactor(Node $node): ?Node $genericTypeNode = $this->constantArrayTypeGeneralizer->generalize($returnedType); - $returnTagValueNode = new ReturnTagValueNode($genericTypeNode, ''); + if ($returnedType->getItemType() instanceof NeverType) { + $returnTagValueNode = new ReturnTagValueNode(ArrayShapeNode::createSealed([]), ''); + } else { + $returnTagValueNode = new ReturnTagValueNode($genericTypeNode, ''); + } + $phpDocInfo->addTagValueNode($returnTagValueNode); $this->docBlockUpdater->updateRefactoredNodeWithPhpDocInfo($node); diff --git a/rules/TypeDeclarationDocblocks/TypeResolver/ConstantArrayTypeGeneralizer.php b/rules/TypeDeclarationDocblocks/TypeResolver/ConstantArrayTypeGeneralizer.php index 4e52fe717d5..5243097d6e3 100644 --- a/rules/TypeDeclarationDocblocks/TypeResolver/ConstantArrayTypeGeneralizer.php +++ b/rules/TypeDeclarationDocblocks/TypeResolver/ConstantArrayTypeGeneralizer.php @@ -7,7 +7,6 @@ use PHPStan\PhpDocParser\Ast\Type\GenericTypeNode; use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode; use PHPStan\Type\Constant\ConstantArrayType; -use PHPStan\Type\IntegerType; use PHPStan\Type\MixedType; use PHPStan\Type\NeverType; use PHPStan\Type\Type; @@ -40,10 +39,6 @@ public function generalize(ConstantArrayType $constantArrayType, bool $isFresh = $genericKeyType = $this->typeNormalizer->generalizeConstantTypes($constantArrayType->getKeyType()); - if ($constantArrayType->getItemType() instanceof NeverType) { - $genericKeyType = new IntegerType(); - } - $itemType = $constantArrayType->getItemType(); if ($itemType instanceof ConstantArrayType) { From 2b1b0d9b09098e6737b225d4229cea60f42a452d Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Mon, 15 Sep 2025 20:48:33 +0700 Subject: [PATCH 2/5] move check on ConstantArrayTypeGeneralizer --- .../DocblockReturnArrayFromDirectArrayInstanceRector.php | 6 +----- .../TypeResolver/ConstantArrayTypeGeneralizer.php | 7 ++++++- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/rules/TypeDeclarationDocblocks/Rector/ClassMethod/DocblockReturnArrayFromDirectArrayInstanceRector.php b/rules/TypeDeclarationDocblocks/Rector/ClassMethod/DocblockReturnArrayFromDirectArrayInstanceRector.php index ea0ee09294c..5befa4e036c 100644 --- a/rules/TypeDeclarationDocblocks/Rector/ClassMethod/DocblockReturnArrayFromDirectArrayInstanceRector.php +++ b/rules/TypeDeclarationDocblocks/Rector/ClassMethod/DocblockReturnArrayFromDirectArrayInstanceRector.php @@ -108,11 +108,7 @@ public function refactor(Node $node): ?Node $genericTypeNode = $this->constantArrayTypeGeneralizer->generalize($returnedType); - if ($returnedType->getItemType() instanceof NeverType) { - $returnTagValueNode = new ReturnTagValueNode(ArrayShapeNode::createSealed([]), ''); - } else { - $returnTagValueNode = new ReturnTagValueNode($genericTypeNode, ''); - } + $returnTagValueNode = new ReturnTagValueNode($genericTypeNode, ''); $phpDocInfo->addTagValueNode($returnTagValueNode); diff --git a/rules/TypeDeclarationDocblocks/TypeResolver/ConstantArrayTypeGeneralizer.php b/rules/TypeDeclarationDocblocks/TypeResolver/ConstantArrayTypeGeneralizer.php index 5243097d6e3..920f09b5ada 100644 --- a/rules/TypeDeclarationDocblocks/TypeResolver/ConstantArrayTypeGeneralizer.php +++ b/rules/TypeDeclarationDocblocks/TypeResolver/ConstantArrayTypeGeneralizer.php @@ -4,6 +4,7 @@ namespace Rector\TypeDeclarationDocblocks\TypeResolver; +use PHPStan\PhpDocParser\Ast\Type\ArrayShapeNode; use PHPStan\PhpDocParser\Ast\Type\GenericTypeNode; use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode; use PHPStan\Type\Constant\ConstantArrayType; @@ -29,7 +30,7 @@ public function __construct( ) { } - public function generalize(ConstantArrayType $constantArrayType, bool $isFresh = true): GenericTypeNode + public function generalize(ConstantArrayType $constantArrayType, bool $isFresh = true): GenericTypeNode|ArrayShapeNode { if ($isFresh) { $this->currentNesting = 0; @@ -41,6 +42,10 @@ public function generalize(ConstantArrayType $constantArrayType, bool $isFresh = $itemType = $constantArrayType->getItemType(); + if ($itemType instanceof NeverType) { + return ArrayShapeNode::createSealed([]); + } + if ($itemType instanceof ConstantArrayType) { if ($this->currentNesting >= self::MAX_NESTING) { $genericItemType = new MixedType(); From 631bb3c3e2a6b731ac2bd6646b8d58586631f18b Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Mon, 15 Sep 2025 20:49:07 +0700 Subject: [PATCH 3/5] move check on ConstantArrayTypeGeneralizer --- .../DocblockReturnArrayFromDirectArrayInstanceRector.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/rules/TypeDeclarationDocblocks/Rector/ClassMethod/DocblockReturnArrayFromDirectArrayInstanceRector.php b/rules/TypeDeclarationDocblocks/Rector/ClassMethod/DocblockReturnArrayFromDirectArrayInstanceRector.php index 5befa4e036c..bb35b278c31 100644 --- a/rules/TypeDeclarationDocblocks/Rector/ClassMethod/DocblockReturnArrayFromDirectArrayInstanceRector.php +++ b/rules/TypeDeclarationDocblocks/Rector/ClassMethod/DocblockReturnArrayFromDirectArrayInstanceRector.php @@ -10,9 +10,7 @@ use PhpParser\Node\Stmt\Function_; use PhpParser\Node\Stmt\Return_; use PHPStan\PhpDocParser\Ast\PhpDoc\ReturnTagValueNode; -use PHPStan\PhpDocParser\Ast\Type\ArrayShapeNode; use PHPStan\Type\Constant\ConstantArrayType; -use PHPStan\Type\NeverType; use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfoFactory; use Rector\Comments\NodeDocBlock\DocBlockUpdater; use Rector\Rector\AbstractRector; @@ -107,7 +105,6 @@ public function refactor(Node $node): ?Node } $genericTypeNode = $this->constantArrayTypeGeneralizer->generalize($returnedType); - $returnTagValueNode = new ReturnTagValueNode($genericTypeNode, ''); $phpDocInfo->addTagValueNode($returnTagValueNode); From e0d80462618f1fce233cfc0ebc8be57cbdd15307 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Mon, 15 Sep 2025 20:49:28 +0700 Subject: [PATCH 4/5] move check on ConstantArrayTypeGeneralizer --- .../DocblockReturnArrayFromDirectArrayInstanceRector.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rules/TypeDeclarationDocblocks/Rector/ClassMethod/DocblockReturnArrayFromDirectArrayInstanceRector.php b/rules/TypeDeclarationDocblocks/Rector/ClassMethod/DocblockReturnArrayFromDirectArrayInstanceRector.php index bb35b278c31..deca987e725 100644 --- a/rules/TypeDeclarationDocblocks/Rector/ClassMethod/DocblockReturnArrayFromDirectArrayInstanceRector.php +++ b/rules/TypeDeclarationDocblocks/Rector/ClassMethod/DocblockReturnArrayFromDirectArrayInstanceRector.php @@ -105,8 +105,8 @@ public function refactor(Node $node): ?Node } $genericTypeNode = $this->constantArrayTypeGeneralizer->generalize($returnedType); - $returnTagValueNode = new ReturnTagValueNode($genericTypeNode, ''); + $returnTagValueNode = new ReturnTagValueNode($genericTypeNode, ''); $phpDocInfo->addTagValueNode($returnTagValueNode); $this->docBlockUpdater->updateRefactoredNodeWithPhpDocInfo($node); From 7ddd6e3cec118951af01abb318973f778d01c739 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Mon, 15 Sep 2025 20:52:57 +0700 Subject: [PATCH 5/5] Fix phpstan --- .../TypeResolver/ConstantArrayTypeGeneralizer.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rules/TypeDeclarationDocblocks/TypeResolver/ConstantArrayTypeGeneralizer.php b/rules/TypeDeclarationDocblocks/TypeResolver/ConstantArrayTypeGeneralizer.php index 920f09b5ada..e3067597f3b 100644 --- a/rules/TypeDeclarationDocblocks/TypeResolver/ConstantArrayTypeGeneralizer.php +++ b/rules/TypeDeclarationDocblocks/TypeResolver/ConstantArrayTypeGeneralizer.php @@ -64,7 +64,7 @@ public function generalize(ConstantArrayType $constantArrayType, bool $isFresh = return $this->createArrayGenericTypeNode($genericKeyType, $genericItemType); } - private function createArrayGenericTypeNode(Type $keyType, Type|GenericTypeNode $itemType): GenericTypeNode + private function createArrayGenericTypeNode(Type $keyType, Type|GenericTypeNode|ArrayShapeNode $itemType): GenericTypeNode { $keyDocTypeNode = $this->staticTypeMapper->mapPHPStanTypeToPHPStanPhpDocTypeNode($keyType);