diff --git a/rules-tests/TypeDeclarationDocblocks/Rector/Class_/DocblockVarArrayFromPropertyDefaultsRector/Fixture/array_union_generic_same_type.php.inc b/rules-tests/TypeDeclarationDocblocks/Rector/Class_/DocblockVarArrayFromPropertyDefaultsRector/Fixture/array_union_generic_same_type.php.inc new file mode 100644 index 00000000000..6eb037a11d9 --- /dev/null +++ b/rules-tests/TypeDeclarationDocblocks/Rector/Class_/DocblockVarArrayFromPropertyDefaultsRector/Fixture/array_union_generic_same_type.php.inc @@ -0,0 +1,36 @@ + +----- +|class-string<\DateTime>> + */ + protected array $dependencies = [ + stdClass::class, + DateTime::class, + ]; +} + +?> diff --git a/src/BetterPhpDocParser/ValueObject/Type/SpacingAwareArrayTypeNode.php b/src/BetterPhpDocParser/ValueObject/Type/SpacingAwareArrayTypeNode.php index 6a8349d2e2c..4e33184ab26 100644 --- a/src/BetterPhpDocParser/ValueObject/Type/SpacingAwareArrayTypeNode.php +++ b/src/BetterPhpDocParser/ValueObject/Type/SpacingAwareArrayTypeNode.php @@ -6,6 +6,7 @@ use PHPStan\PhpDocParser\Ast\Type\ArrayTypeNode; use PHPStan\PhpDocParser\Ast\Type\CallableTypeNode; +use PHPStan\PhpDocParser\Ast\Type\GenericTypeNode; use PHPStan\PhpDocParser\Ast\Type\TypeNode; use PHPStan\PhpDocParser\Ast\Type\UnionTypeNode; use Rector\PHPStanStaticTypeMapper\TypeMapper\ArrayTypeMapper; @@ -60,12 +61,44 @@ private function printArrayType(ArrayTypeNode $arrayTypeNode): string private function printUnionType(BracketsAwareUnionTypeNode $bracketsAwareUnionTypeNode): string { - $unionedTypes = []; - if ($bracketsAwareUnionTypeNode->isWrappedInBrackets()) { return $bracketsAwareUnionTypeNode . '[]'; } + // If all types in the union are GenericTypeNode, use array syntax + $allGeneric = true; + $firstGenericTypeName = null; + + foreach ($bracketsAwareUnionTypeNode->types as $unionedType) { + if (! $unionedType instanceof GenericTypeNode) { + $allGeneric = false; + break; + } + + // ensure only check on base level + // avoid mix usage without [] added + if (count($unionedType->genericTypes) !== 1) { + $allGeneric = false; + break; + } + + // ensure all generic types has the same base type + $currentTypeName = $unionedType->type->name; + + if ($firstGenericTypeName === null) { + $firstGenericTypeName = $currentTypeName; + } elseif ($firstGenericTypeName !== $currentTypeName) { + // Different generic base types (e.g., class-string vs array) + $allGeneric = false; + break; + } + } + + if ($allGeneric) { + return sprintf('array', (string) $bracketsAwareUnionTypeNode); + } + + $unionedTypes = []; foreach ($bracketsAwareUnionTypeNode->types as $unionedType) { $unionedTypes[] = $unionedType . '[]'; }