diff --git a/rules-tests/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromStrictNewArrayRector/Fixture/deep_nested_array.php.inc b/rules-tests/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromStrictNewArrayRector/Fixture/deep_nested_array.php.inc index 13e60a7da7f..a992123127e 100644 --- a/rules-tests/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromStrictNewArrayRector/Fixture/deep_nested_array.php.inc +++ b/rules-tests/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromStrictNewArrayRector/Fixture/deep_nested_array.php.inc @@ -32,9 +32,6 @@ namespace Rector\Tests\TypeDeclaration\Rector\ClassMethod\ReturnTypeFromStrictNe final class DeepNestedArray { - /** - * @return non-empty-array[] - */ public function test(): array { $arr = []; $rows = $this->getRows(); diff --git a/rules-tests/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromStrictNewArrayRector/Fixture/union_reservation_array_shapes_no_doc.php.inc b/rules-tests/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromStrictNewArrayRector/Fixture/union_reservation_array_shapes_no_doc.php.inc new file mode 100644 index 00000000000..73f9e146e79 --- /dev/null +++ b/rules-tests/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromStrictNewArrayRector/Fixture/union_reservation_array_shapes_no_doc.php.inc @@ -0,0 +1,73 @@ + 'EUR', + 'creation_date' => 'd', + 'guarantee' => 1, + 'invoice_recipient_id' => 5, + 'invoice_free_text' => 't', + 'status' => 'ok', + 'type' => 'a', + ]; + } else { + $data[] = [ + 'currency' => 'EUR', + 'creation_date' => 'd', + 'guarantee' => 1, + 'status' => 'ok', + 'type' => 'a', + ]; + } + } + + return $data; + } +} + +?> +----- + 'EUR', + 'creation_date' => 'd', + 'guarantee' => 1, + 'invoice_recipient_id' => 5, + 'invoice_free_text' => 't', + 'status' => 'ok', + 'type' => 'a', + ]; + } else { + $data[] = [ + 'currency' => 'EUR', + 'creation_date' => 'd', + 'guarantee' => 1, + 'status' => 'ok', + 'type' => 'a', + ]; + } + } + + return $data; + } +} + +?> diff --git a/rules/TypeDeclaration/NodeAnalyzer/StrictReturnNewArrayResolver.php b/rules/TypeDeclaration/NodeAnalyzer/StrictReturnNewArrayResolver.php index 796271f4d42..10fda6a5a8a 100644 --- a/rules/TypeDeclaration/NodeAnalyzer/StrictReturnNewArrayResolver.php +++ b/rules/TypeDeclaration/NodeAnalyzer/StrictReturnNewArrayResolver.php @@ -17,11 +17,9 @@ use PHPStan\Type\Constant\ConstantArrayType; use PHPStan\Type\IntersectionType; use PHPStan\Type\MixedType; -use PHPStan\Type\NeverType; use PHPStan\Type\Type; use PHPStan\Type\TypeCombinator; use PHPStan\Type\TypeTraverser; -use PHPStan\Type\UnionType; use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfoFactory; use Rector\BetterPhpDocParser\PhpDocManipulator\PhpDocTypeChanger; use Rector\NodeNameResolver\NodeNameResolver; @@ -204,55 +202,22 @@ private function matchArrayAssignedVariable(array $stmts): array private function shouldAddReturnArrayDocType(Type $arrayType): bool { - // a union of multiple distinct array shapes produces a noisy doc type, skip it - if ($this->hasNoisyArrayShapeUnion($arrayType)) { - return false; - } - - if ($arrayType instanceof ConstantArrayType) { - if ($arrayType->getIterableValueType() instanceof NeverType) { - return false; - } - - // handle only simple arrays - if (! $arrayType->getIterableKeyType()->isInteger()->yes()) { - return false; - } - } - - return true; + // only plain list<> and generic array<> doc types are worth adding; + // array shapes produce noisy, fragile doc types, skip them + return ! $this->hasArrayShape($arrayType); } - private function hasNoisyArrayShapeUnion(Type $type): bool + private function hasArrayShape(Type $type): bool { - $isNoisy = false; - TypeTraverser::map($type, function (Type $currentType, callable $traverse) use (&$isNoisy): Type { - if ($currentType instanceof UnionType && $this->hasMultipleArrayVariants($currentType)) { - $isNoisy = true; + $hasArrayShape = false; + TypeTraverser::map($type, function (Type $currentType, callable $traverse) use (&$hasArrayShape): Type { + if ($currentType instanceof ConstantArrayType && $currentType->getKeyTypes() !== [] && ! $currentType->isList()->yes()) { + $hasArrayShape = true; } return $traverse($currentType); }); - return $isNoisy; - } - - private function hasMultipleArrayVariants(UnionType $unionType): bool - { - $arrayVariantCount = 0; - foreach ($unionType->getTypes() as $type) { - if (! $type->isArray()->yes()) { - continue; - } - - // an empty array [] collapses into the sibling variant, ignore it - if ($type->getIterableValueType() instanceof NeverType) { - continue; - } - - ++$arrayVariantCount; - } - - return $arrayVariantCount >= 2; + return $hasArrayShape; } }