From fd2ca07fe4837cbce472462ce61c3d3ee8ce6748 Mon Sep 17 00:00:00 2001 From: "ondrej@mirtes.cz" Date: Wed, 28 Oct 2026 19:16:02 +0000 Subject: [PATCH 1/2] Use PHPStan Type::toNativePhpTypeNode() instead of mapToPhpParserNode() Amp-Thread-ID: https://ampcode.com/threads/T-01a179f2-995f-7745-8d8c-4c174ba5c0ce --- UPGRADING.md | 4 + phpstan.neon | 5 - .../Fixture/has_property_type.php.inc | 53 ++++ .../Fixture/skip_has_property_type.php.inc | 26 -- .../return_anonymous_class_and_other.php.inc | 35 +++ ...p_return_anonymous_class_and_other.php.inc | 17 -- .../anonymous_class_and_other_object.php.inc | 31 +++ .../anonymous_class_and_other_object2.php.inc | 33 +++ ...p_anonymous_class_and_other_object.php.inc | 15 -- ..._anonymous_class_and_other_object2.php.inc | 16 -- .../Fixture/union_array.php.inc | 2 +- .../Fixture/union_multi.php.inc | 2 +- .../NodeManipulator/AddUnionReturnType.php | 6 +- .../ClassMethod/ReturnNullableTypeRector.php | 6 +- .../LazyContainerFactory.php | 21 -- .../ObjectWithoutClassTypeWithParentTypes.php | 14 + .../Contract/TypeMapperInterface.php | 12 - src/PHPStanStaticTypeMapper/Enum/TypeKind.php | 2 - .../PHPStanStaticTypeMapper.php | 17 -- .../TypeMapper/AccessoryArrayTypeMapper.php | 6 - .../TypeMapper/AccessoryStringTypeMapper.php | 18 -- .../TypeMapper/ArrayTypeMapper.php | 9 - .../TypeMapper/BooleanTypeMapper.php | 42 --- .../TypeMapper/CallableTypeMapper.php | 17 -- .../TypeMapper/ClassStringTypeMapper.php | 21 -- .../TypeMapper/ClosureTypeMapper.php | 47 ---- .../ConditionalTypeForParameterMapper.php | 21 -- .../TypeMapper/ConditionalTypeMapper.php | 21 -- .../TypeMapper/ConstantArrayTypeMapper.php | 18 -- .../TypeMapper/FloatTypeMapper.php | 21 -- .../TypeMapper/HasMethodTypeMapper.php | 14 - .../TypeMapper/HasPropertyTypeMapper.php | 14 - .../TypeMapper/IntegerTypeMapper.php | 21 -- .../TypeMapper/IntersectionTypeMapper.php | 61 ----- .../TypeMapper/IterableTypeMapper.php | 9 - .../TypeMapper/MixedTypeMapper.php | 30 --- .../TypeMapper/NeverTypeMapper.php | 9 - .../NonexistentParentClassTypeMapper.php | 10 - .../TypeMapper/NullTypeMapper.php | 33 --- .../TypeMapper/ObjectTypeMapper.php | 39 --- .../ObjectWithoutClassTypeMapper.php | 34 --- .../TypeMapper/ParentStaticTypeMapper.php | 10 - .../TypeMapper/ResourceTypeMapper.php | 9 - .../TypeMapper/StaticTypeMapper.php | 32 --- .../TypeMapper/StrictMixedTypeMapper.php | 28 -- .../TypeMapper/StringTypeMapper.php | 18 -- .../TypeWithClassNameTypeMapper.php | 21 -- .../TypeMapper/UnionTypeMapper.php | 243 +----------------- .../TypeMapper/VoidTypeMapper.php | 29 --- src/StaticTypeMapper/StaticTypeMapper.php | 39 ++- .../ValueObject/Type/AliasedObjectType.php | 7 + .../Type/FullyQualifiedObjectType.php | 7 + .../Type/NonExistingObjectType.php | 9 + .../ValueObject/Type/ParentStaticType.php | 6 + .../ValueObject/Type/SelfObjectType.php | 6 + .../ValueObject/Type/SelfStaticType.php | 6 + .../ValueObject/Type/ShortenedObjectType.php | 8 + .../NonexistentParentClassTypeMapperTest.php | 13 - 58 files changed, 263 insertions(+), 1060 deletions(-) create mode 100644 rules-tests/TypeDeclaration/Rector/ClassMethod/AddMethodCallBasedStrictParamTypeRector/Fixture/has_property_type.php.inc delete mode 100644 rules-tests/TypeDeclaration/Rector/ClassMethod/AddMethodCallBasedStrictParamTypeRector/Fixture/skip_has_property_type.php.inc create mode 100644 rules-tests/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromReturnNewRector/Fixture/return_anonymous_class_and_other.php.inc delete mode 100644 rules-tests/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromReturnNewRector/Fixture/skip_return_anonymous_class_and_other.php.inc create mode 100644 rules-tests/TypeDeclaration/Rector/ClassMethod/ReturnUnionTypeRector/Fixture/anonymous_class_and_other_object.php.inc create mode 100644 rules-tests/TypeDeclaration/Rector/ClassMethod/ReturnUnionTypeRector/Fixture/anonymous_class_and_other_object2.php.inc delete mode 100644 rules-tests/TypeDeclaration/Rector/ClassMethod/ReturnUnionTypeRector/Fixture/skip_anonymous_class_and_other_object.php.inc delete mode 100644 rules-tests/TypeDeclaration/Rector/ClassMethod/ReturnUnionTypeRector/Fixture/skip_anonymous_class_and_other_object2.php.inc diff --git a/UPGRADING.md b/UPGRADING.md index f2089bac57d..de4d26099fa 100644 --- a/UPGRADING.md +++ b/UPGRADING.md @@ -1,3 +1,7 @@ +# Upgrading to the next Rector release + +* `TypeMapperInterface::mapToPhpParserNode()` is removed; custom type mappers only map to PHPDoc nodes now. A custom `Type` controls its native declaration by overriding `toNativePhpTypeNode()`. + # Upgrading from Rector 2.2.14 to 2.3 * `FileWithoutNamespace` is deprecated, and replaced by `FileNode` that represents both namespaced and non-namespaced files and allow changes inside diff --git a/phpstan.neon b/phpstan.neon index 4ca5ab2b499..42728a62310 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -284,11 +284,6 @@ parameters: paths: - src/NodeTypeResolver/PHPStan/Type/TypeFactory.php - # from mapper interface - - - identifier: return.unusedType - message: '#mapToPhpParserNode\(\) never returns PhpParser\\.* so it can be removed from the return#' - # false positive - identifier: return.unusedType diff --git a/rules-tests/TypeDeclaration/Rector/ClassMethod/AddMethodCallBasedStrictParamTypeRector/Fixture/has_property_type.php.inc b/rules-tests/TypeDeclaration/Rector/ClassMethod/AddMethodCallBasedStrictParamTypeRector/Fixture/has_property_type.php.inc new file mode 100644 index 00000000000..fa3353b29c6 --- /dev/null +++ b/rules-tests/TypeDeclaration/Rector/ClassMethod/AddMethodCallBasedStrictParamTypeRector/Fixture/has_property_type.php.inc @@ -0,0 +1,53 @@ +type)) { + return; + } + + if ($data->type === 'value') { + $this->runData($data); + } + } + + private function runData($data) + { + } +} +----- +type)) { + return; + } + + if ($data->type === 'value') { + $this->runData($data); + } + } + + private function runData(object $data) + { + } +} diff --git a/rules-tests/TypeDeclaration/Rector/ClassMethod/AddMethodCallBasedStrictParamTypeRector/Fixture/skip_has_property_type.php.inc b/rules-tests/TypeDeclaration/Rector/ClassMethod/AddMethodCallBasedStrictParamTypeRector/Fixture/skip_has_property_type.php.inc deleted file mode 100644 index a3ceb5af64c..00000000000 --- a/rules-tests/TypeDeclaration/Rector/ClassMethod/AddMethodCallBasedStrictParamTypeRector/Fixture/skip_has_property_type.php.inc +++ /dev/null @@ -1,26 +0,0 @@ -type)) { - return; - } - - if ($data->type === 'value') { - $this->runData($data); - } - } - - private function runData($data) - { - } -} diff --git a/rules-tests/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromReturnNewRector/Fixture/return_anonymous_class_and_other.php.inc b/rules-tests/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromReturnNewRector/Fixture/return_anonymous_class_and_other.php.inc new file mode 100644 index 00000000000..c8b2ff08a54 --- /dev/null +++ b/rules-tests/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromReturnNewRector/Fixture/return_anonymous_class_and_other.php.inc @@ -0,0 +1,35 @@ +unionTypeMapper->mapToPhpParserNode($inferReturnType, TypeKind::RETURN); + $returnType = $this->staticTypeMapper->mapPHPStanTypeToPhpParserNode($inferReturnType, TypeKind::RETURN); if (! $returnType instanceof Node) { return null; } diff --git a/rules/TypeDeclaration/Rector/ClassMethod/ReturnNullableTypeRector.php b/rules/TypeDeclaration/Rector/ClassMethod/ReturnNullableTypeRector.php index c2a734be845..a48c1c634c4 100644 --- a/rules/TypeDeclaration/Rector/ClassMethod/ReturnNullableTypeRector.php +++ b/rules/TypeDeclaration/Rector/ClassMethod/ReturnNullableTypeRector.php @@ -11,10 +11,10 @@ use PHPStan\Type\UnionType; use Rector\PHPStan\ScopeFetcher; use Rector\PHPStanStaticTypeMapper\Enum\TypeKind; -use Rector\PHPStanStaticTypeMapper\TypeMapper\UnionTypeMapper; use Rector\Rector\AbstractRector; use Rector\RuleDoc\CodeSample\CodeSample; use Rector\RuleDoc\RuleDefinition; +use Rector\StaticTypeMapper\StaticTypeMapper; use Rector\TypeDeclaration\TypeInferer\ReturnTypeInferer; use Rector\ValueObject\PhpVersion; use Rector\VendorLocker\NodeVendorLocker\ClassMethodReturnTypeOverrideGuard; @@ -26,7 +26,7 @@ final class ReturnNullableTypeRector extends AbstractRector implements MinPhpVersionInterface { public function __construct( - private readonly UnionTypeMapper $unionTypeMapper, + private readonly StaticTypeMapper $staticTypeMapper, private readonly ClassMethodReturnTypeOverrideGuard $classMethodReturnTypeOverrideGuard, private readonly ReturnTypeInferer $returnTypeInferer, ) { @@ -108,7 +108,7 @@ public function refactor(Node $node): ?Node return null; } - $returnType = $this->unionTypeMapper->mapToPhpParserNode($inferReturnType, TypeKind::RETURN); + $returnType = $this->staticTypeMapper->mapPHPStanTypeToPhpParserNode($inferReturnType, TypeKind::RETURN); if (! $returnType instanceof Node) { return null; } diff --git a/src/DependencyInjection/LazyContainerFactory.php b/src/DependencyInjection/LazyContainerFactory.php index 1cb851e9149..592e142d756 100644 --- a/src/DependencyInjection/LazyContainerFactory.php +++ b/src/DependencyInjection/LazyContainerFactory.php @@ -57,8 +57,6 @@ use Rector\PhpParser\NodeVisitor\PhpVersionConditionNodeVisitor; use Rector\PHPStanStaticTypeMapper\PHPStanStaticTypeMapper; use Rector\PHPStanStaticTypeMapper\TypeMapper\ArrayTypeMapper; -use Rector\PHPStanStaticTypeMapper\TypeMapper\ConditionalTypeForParameterMapper; -use Rector\PHPStanStaticTypeMapper\TypeMapper\ConditionalTypeMapper; use Rector\PHPStanStaticTypeMapper\TypeMapper\UnionTypeMapper; use Rector\PostRector\Application\PostFileProcessor; use Rector\Rector\AbstractRector; @@ -177,24 +175,6 @@ static function (ArrayTypeMapper $arrayTypeMapper) use ($rectorConfig): void { } ); - $rectorConfig->afterResolving( - ConditionalTypeForParameterMapper::class, - static function ( - ConditionalTypeForParameterMapper $conditionalTypeForParameterMapper - ) use ($rectorConfig): void { - $phpStanStaticTypeMapper = $rectorConfig->make(PHPStanStaticTypeMapper::class); - $conditionalTypeForParameterMapper->autowire($phpStanStaticTypeMapper); - } - ); - - $rectorConfig->afterResolving( - ConditionalTypeMapper::class, - static function (ConditionalTypeMapper $conditionalTypeMapper) use ($rectorConfig): void { - $phpStanStaticTypeMapper = $rectorConfig->make(PHPStanStaticTypeMapper::class); - $conditionalTypeMapper->autowire($phpStanStaticTypeMapper); - } - ); - $rectorConfig->afterResolving( UnionTypeMapper::class, static function (UnionTypeMapper $unionTypeMapper) use ($rectorConfig): void { @@ -202,7 +182,6 @@ static function (UnionTypeMapper $unionTypeMapper) use ($rectorConfig): void { $unionTypeMapper->autowire($phpStanStaticTypeMapper); } ); - } private function registerNodeNameResolvers(RectorConfig $rectorConfig): void diff --git a/src/NodeTypeResolver/PHPStan/ObjectWithoutClassTypeWithParentTypes.php b/src/NodeTypeResolver/PHPStan/ObjectWithoutClassTypeWithParentTypes.php index 4b89d93898d..a22bc3c295a 100644 --- a/src/NodeTypeResolver/PHPStan/ObjectWithoutClassTypeWithParentTypes.php +++ b/src/NodeTypeResolver/PHPStan/ObjectWithoutClassTypeWithParentTypes.php @@ -4,6 +4,10 @@ namespace Rector\NodeTypeResolver\PHPStan; +use PhpParser\Node\ComplexType; +use PhpParser\Node\Identifier; +use PhpParser\Node\Name; +use PHPStan\Type\NativeTypePosition; use PHPStan\Type\ObjectWithoutClassType; use PHPStan\Type\Type; use PHPStan\Type\TypeWithClassName; @@ -27,4 +31,14 @@ public function getParentTypes(): array { return $this->parentTypes; } + + public function toNativePhpTypeNode(NativeTypePosition $position): Identifier|Name|ComplexType|null + { + // anonymous class implementing a single other type + if (count($this->parentTypes) === 1) { + return $this->parentTypes[0]->toNativePhpTypeNode($position); + } + + return parent::toNativePhpTypeNode($position); + } } diff --git a/src/PHPStanStaticTypeMapper/Contract/TypeMapperInterface.php b/src/PHPStanStaticTypeMapper/Contract/TypeMapperInterface.php index 36e49ef8019..5650bee33c0 100644 --- a/src/PHPStanStaticTypeMapper/Contract/TypeMapperInterface.php +++ b/src/PHPStanStaticTypeMapper/Contract/TypeMapperInterface.php @@ -4,13 +4,8 @@ namespace Rector\PHPStanStaticTypeMapper\Contract; -use PhpParser\Node; -use PhpParser\Node\ComplexType; -use PhpParser\Node\Identifier; -use PhpParser\Node\Name; use PHPStan\PhpDocParser\Ast\Type\TypeNode; use PHPStan\Type\Type; -use Rector\PHPStanStaticTypeMapper\Enum\TypeKind; /** * @template TType of Type @@ -29,11 +24,4 @@ public function getNodeClasses(): array; * @param TType $type */ public function mapToPHPStanPhpDocTypeNode(Type $type): TypeNode; - - /** - * @param TType $type - * @param TypeKind::* $typeKind - * @return Name|ComplexType|Identifier|null - */ - public function mapToPhpParserNode(Type $type, string $typeKind): ?Node; } diff --git a/src/PHPStanStaticTypeMapper/Enum/TypeKind.php b/src/PHPStanStaticTypeMapper/Enum/TypeKind.php index 49d6de14834..c7fb7623001 100644 --- a/src/PHPStanStaticTypeMapper/Enum/TypeKind.php +++ b/src/PHPStanStaticTypeMapper/Enum/TypeKind.php @@ -11,6 +11,4 @@ final class TypeKind public const string RETURN = 'return'; public const string PARAM = 'param'; - - public const string UNION = 'union'; } diff --git a/src/PHPStanStaticTypeMapper/PHPStanStaticTypeMapper.php b/src/PHPStanStaticTypeMapper/PHPStanStaticTypeMapper.php index 5dbdbb96081..9d654319099 100644 --- a/src/PHPStanStaticTypeMapper/PHPStanStaticTypeMapper.php +++ b/src/PHPStanStaticTypeMapper/PHPStanStaticTypeMapper.php @@ -4,14 +4,10 @@ namespace Rector\PHPStanStaticTypeMapper; -use PhpParser\Node\ComplexType; -use PhpParser\Node\Identifier; -use PhpParser\Node\Name; use PHPStan\PhpDocParser\Ast\Type\TypeNode; use PHPStan\Type\Type; use Rector\Exception\NotImplementedYetException; use Rector\PHPStanStaticTypeMapper\Contract\TypeMapperInterface; -use Rector\PHPStanStaticTypeMapper\Enum\TypeKind; use Webmozart\Assert\Assert; final readonly class PHPStanStaticTypeMapper @@ -35,19 +31,6 @@ public function mapToPHPStanPhpDocTypeNode(Type $type): TypeNode return $typeMapper->mapToPHPStanPhpDocTypeNode($type); } - /** - * @param TypeKind::* $typeKind - */ - public function mapToPhpParserNode(Type $type, string $typeKind): Name|ComplexType|Identifier|null - { - $typeMapper = $this->matchTypeMapper($type); - if (! $typeMapper instanceof TypeMapperInterface) { - throw new NotImplementedYetException(__METHOD__ . ' for ' . $type::class); - } - - return $typeMapper->mapToPhpParserNode($type, $typeKind); - } - /** * Match the most specific mapper: when a type is handled by both a mapper for a parent * class and one for its subclass, the subclass mapper wins, regardless of registration order. diff --git a/src/PHPStanStaticTypeMapper/TypeMapper/AccessoryArrayTypeMapper.php b/src/PHPStanStaticTypeMapper/TypeMapper/AccessoryArrayTypeMapper.php index 14b073970d3..bc098fa8b8d 100644 --- a/src/PHPStanStaticTypeMapper/TypeMapper/AccessoryArrayTypeMapper.php +++ b/src/PHPStanStaticTypeMapper/TypeMapper/AccessoryArrayTypeMapper.php @@ -4,7 +4,6 @@ namespace Rector\PHPStanStaticTypeMapper\TypeMapper; -use PhpParser\Node\Identifier; use PHPStan\PhpDocParser\Ast\Type\TypeNode; use PHPStan\Type\Accessory\HasOffsetType; use PHPStan\Type\Accessory\HasOffsetValueType; @@ -37,9 +36,4 @@ public function mapToPHPStanPhpDocTypeNode(Type $type): TypeNode { return $type->toPhpDocNode(); } - - public function mapToPhpParserNode(Type $type, string $typeKind): Identifier - { - return new Identifier('array'); - } } diff --git a/src/PHPStanStaticTypeMapper/TypeMapper/AccessoryStringTypeMapper.php b/src/PHPStanStaticTypeMapper/TypeMapper/AccessoryStringTypeMapper.php index 6fa39774cd5..59d401d111e 100644 --- a/src/PHPStanStaticTypeMapper/TypeMapper/AccessoryStringTypeMapper.php +++ b/src/PHPStanStaticTypeMapper/TypeMapper/AccessoryStringTypeMapper.php @@ -4,17 +4,13 @@ namespace Rector\PHPStanStaticTypeMapper\TypeMapper; -use PhpParser\Node; -use PhpParser\Node\Identifier; use PHPStan\PhpDocParser\Ast\Type\TypeNode; use PHPStan\Type\Accessory\AccessoryLiteralStringType; use PHPStan\Type\Accessory\AccessoryNonEmptyStringType; use PHPStan\Type\Accessory\AccessoryNonFalsyStringType; use PHPStan\Type\Accessory\AccessoryNumericStringType; use PHPStan\Type\Type; -use Rector\Php\PhpVersionProvider; use Rector\PHPStanStaticTypeMapper\Contract\TypeMapperInterface; -use Rector\ValueObject\PhpVersion; /** * Every accessory string type narrows "string" with an extra guarantee, so they all map back to "string" @@ -23,11 +19,6 @@ */ final readonly class AccessoryStringTypeMapper implements TypeMapperInterface { - public function __construct( - private PhpVersionProvider $phpVersionProvider - ) { - } - /** * @return array> */ @@ -45,13 +36,4 @@ public function mapToPHPStanPhpDocTypeNode(Type $type): TypeNode { return $type->toPhpDocNode(); } - - public function mapToPhpParserNode(Type $type, string $typeKind): ?Node - { - if (! $this->phpVersionProvider->isAtLeastPhpVersion(PhpVersion::PHP_70)) { - return null; - } - - return new Identifier('string'); - } } diff --git a/src/PHPStanStaticTypeMapper/TypeMapper/ArrayTypeMapper.php b/src/PHPStanStaticTypeMapper/TypeMapper/ArrayTypeMapper.php index e3766509add..06a079317b1 100644 --- a/src/PHPStanStaticTypeMapper/TypeMapper/ArrayTypeMapper.php +++ b/src/PHPStanStaticTypeMapper/TypeMapper/ArrayTypeMapper.php @@ -4,7 +4,6 @@ namespace Rector\PHPStanStaticTypeMapper\TypeMapper; -use PhpParser\Node\Identifier; use PHPStan\PhpDocParser\Ast\Type\ArrayTypeNode; use PHPStan\PhpDocParser\Ast\Type\GenericTypeNode; use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode; @@ -63,14 +62,6 @@ public function mapToPHPStanPhpDocTypeNode(Type $type): TypeNode return $this->splitUnionItemType($this->createArrayTypeNode($type)); } - /** - * @param ArrayType $type - */ - public function mapToPhpParserNode(Type $type, string $typeKind): Identifier - { - return new Identifier('array'); - } - /** * Returns "(A|B)[]" as is, the union item type is split later */ diff --git a/src/PHPStanStaticTypeMapper/TypeMapper/BooleanTypeMapper.php b/src/PHPStanStaticTypeMapper/TypeMapper/BooleanTypeMapper.php index cf72c0c41b6..a93c8eb2b4c 100644 --- a/src/PHPStanStaticTypeMapper/TypeMapper/BooleanTypeMapper.php +++ b/src/PHPStanStaticTypeMapper/TypeMapper/BooleanTypeMapper.php @@ -4,26 +4,16 @@ namespace Rector\PHPStanStaticTypeMapper\TypeMapper; -use PhpParser\Node; -use PhpParser\Node\Identifier; use PHPStan\PhpDocParser\Ast\Type\TypeNode; use PHPStan\Type\BooleanType; use PHPStan\Type\Type; -use Rector\Php\PhpVersionProvider; use Rector\PHPStanStaticTypeMapper\Contract\TypeMapperInterface; -use Rector\PHPStanStaticTypeMapper\Enum\TypeKind; -use Rector\ValueObject\PhpVersion; /** * @implements TypeMapperInterface */ final readonly class BooleanTypeMapper implements TypeMapperInterface { - public function __construct( - private PhpVersionProvider $phpVersionProvider - ) { - } - /** * @return array> */ @@ -39,36 +29,4 @@ public function mapToPHPStanPhpDocTypeNode(Type $type): TypeNode { return $type->toPhpDocNode(); } - - /** - * @param BooleanType $type - */ - public function mapToPhpParserNode(Type $type, string $typeKind): ?Node - { - if (! $this->phpVersionProvider->isAtLeastPhpVersion(PhpVersion::PHP_70)) { - return null; - } - - if ($typeKind === TypeKind::PROPERTY) { - return new Identifier('bool'); - } - - if ($typeKind === TypeKind::UNION && $type->isFalse()->yes()) { - return new Identifier('false'); - } - - if (! $this->phpVersionProvider->isAtLeastPhpVersion(PhpVersion::PHP_82)) { - return new Identifier('bool'); - } - - if ($type->isTrue()->yes()) { - return new Identifier('true'); - } - - if ($type->isFalse()->yes()) { - return new Identifier('false'); - } - - return new Identifier('bool'); - } } diff --git a/src/PHPStanStaticTypeMapper/TypeMapper/CallableTypeMapper.php b/src/PHPStanStaticTypeMapper/TypeMapper/CallableTypeMapper.php index e953961ea88..8eb24a3e902 100644 --- a/src/PHPStanStaticTypeMapper/TypeMapper/CallableTypeMapper.php +++ b/src/PHPStanStaticTypeMapper/TypeMapper/CallableTypeMapper.php @@ -4,14 +4,10 @@ namespace Rector\PHPStanStaticTypeMapper\TypeMapper; -use PhpParser\Node; -use PhpParser\Node\Identifier; use PHPStan\PhpDocParser\Ast\Type\TypeNode; use PHPStan\Type\CallableType; -use PHPStan\Type\ClosureType; use PHPStan\Type\Type; use Rector\PHPStanStaticTypeMapper\Contract\TypeMapperInterface; -use Rector\PHPStanStaticTypeMapper\Enum\TypeKind; /** * @implements TypeMapperInterface @@ -33,17 +29,4 @@ public function mapToPHPStanPhpDocTypeNode(Type $type): TypeNode { return $type->toPhpDocNode(); } - - /** - * @param TypeKind::* $typeKind - * @param CallableType|ClosureType $type - */ - public function mapToPhpParserNode(Type $type, string $typeKind): ?Node - { - if ($typeKind === TypeKind::PROPERTY) { - return null; - } - - return new Identifier('callable'); - } } diff --git a/src/PHPStanStaticTypeMapper/TypeMapper/ClassStringTypeMapper.php b/src/PHPStanStaticTypeMapper/TypeMapper/ClassStringTypeMapper.php index 9dd3e76cf21..7903e8bcdd0 100644 --- a/src/PHPStanStaticTypeMapper/TypeMapper/ClassStringTypeMapper.php +++ b/src/PHPStanStaticTypeMapper/TypeMapper/ClassStringTypeMapper.php @@ -4,27 +4,18 @@ namespace Rector\PHPStanStaticTypeMapper\TypeMapper; -use PhpParser\Node; -use PhpParser\Node\Identifier; use PHPStan\PhpDocParser\Ast\Type\TypeNode; use PHPStan\Type\ClassStringType; use PHPStan\Type\ObjectType; use PHPStan\Type\Type; use PHPStan\Type\TypeTraverser; -use Rector\Php\PhpVersionProvider; use Rector\PHPStanStaticTypeMapper\Contract\TypeMapperInterface; -use Rector\ValueObject\PhpVersion; /** * @implements TypeMapperInterface */ final readonly class ClassStringTypeMapper implements TypeMapperInterface { - public function __construct( - private PhpVersionProvider $phpVersionProvider - ) { - } - /** * @return array> */ @@ -54,16 +45,4 @@ public function mapToPHPStanPhpDocTypeNode(Type $type): TypeNode return $type->toPhpDocNode(); } - - /** - * @param ClassStringType $type - */ - public function mapToPhpParserNode(Type $type, string $typeKind): ?Node - { - if (! $this->phpVersionProvider->isAtLeastPhpVersion(PhpVersion::PHP_70)) { - return null; - } - - return new Identifier('string'); - } } diff --git a/src/PHPStanStaticTypeMapper/TypeMapper/ClosureTypeMapper.php b/src/PHPStanStaticTypeMapper/TypeMapper/ClosureTypeMapper.php index 7853101336c..f34f48b29a4 100644 --- a/src/PHPStanStaticTypeMapper/TypeMapper/ClosureTypeMapper.php +++ b/src/PHPStanStaticTypeMapper/TypeMapper/ClosureTypeMapper.php @@ -4,8 +4,6 @@ namespace Rector\PHPStanStaticTypeMapper\TypeMapper; -use PhpParser\Node; -use PhpParser\Node\Name\FullyQualified; use PHPStan\PhpDocParser\Ast\Node as AstNode; use PHPStan\PhpDocParser\Ast\NodeTraverser; use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode; @@ -13,22 +11,14 @@ use PHPStan\Type\ClosureType; use PHPStan\Type\Type; use Rector\BetterPhpDocParser\ValueObject\Type\FullyQualifiedIdentifierTypeNode; -use Rector\Php\PhpVersionProvider; use Rector\PhpDocParser\PhpDocParser\PhpDocNodeVisitor\CallablePhpDocNodeVisitor; use Rector\PHPStanStaticTypeMapper\Contract\TypeMapperInterface; -use Rector\PHPStanStaticTypeMapper\Enum\TypeKind; -use Rector\ValueObject\PhpVersion; /** * @implements TypeMapperInterface */ final readonly class ClosureTypeMapper implements TypeMapperInterface { - public function __construct( - private PhpVersionProvider $phpVersionProvider - ) { - } - /** * @return array> */ @@ -61,41 +51,4 @@ static function (AstNode $astNode): ?FullyQualifiedIdentifierTypeNode { return $typeNode; } - - /** - * @param TypeKind::* $typeKind - * @param ClosureType $type - */ - public function mapToPhpParserNode(Type $type, string $typeKind): ?Node - { - // ref https://3v4l.org/iKMK6#v5.3.29 - if ($typeKind === TypeKind::PARAM && $this->phpVersionProvider->isAtLeastPhpVersion( - PhpVersion::PHP_53 - )) { - return new FullyQualified('Closure'); - } - - // ref https://3v4l.org/g8WvW#v7.4.0 - if ($typeKind === TypeKind::PROPERTY && $this->phpVersionProvider->isAtLeastPhpVersion( - PhpVersion::PHP_74 - )) { - return new FullyQualified('Closure'); - } - - // ref https://3v4l.org/nUreN#v7.0.0 - if ($typeKind === TypeKind::RETURN && $this->phpVersionProvider->isAtLeastPhpVersion( - PhpVersion::PHP_70 - )) { - return new FullyQualified('Closure'); - } - - // ref https://3v4l.org/ruh5g#v8.0.0 - if ($typeKind === TypeKind::UNION && $this->phpVersionProvider->isAtLeastPhpVersion( - PhpVersion::PHP_80 - )) { - return new FullyQualified('Closure'); - } - - return null; - } } diff --git a/src/PHPStanStaticTypeMapper/TypeMapper/ConditionalTypeForParameterMapper.php b/src/PHPStanStaticTypeMapper/TypeMapper/ConditionalTypeForParameterMapper.php index ce6698893cb..a5cf77572f9 100644 --- a/src/PHPStanStaticTypeMapper/TypeMapper/ConditionalTypeForParameterMapper.php +++ b/src/PHPStanStaticTypeMapper/TypeMapper/ConditionalTypeForParameterMapper.php @@ -4,27 +4,16 @@ namespace Rector\PHPStanStaticTypeMapper\TypeMapper; -use PhpParser\Node; use PHPStan\PhpDocParser\Ast\Type\TypeNode; use PHPStan\Type\ConditionalTypeForParameter; use PHPStan\Type\Type; -use PHPStan\Type\TypeCombinator; use Rector\PHPStanStaticTypeMapper\Contract\TypeMapperInterface; -use Rector\PHPStanStaticTypeMapper\Enum\TypeKind; -use Rector\PHPStanStaticTypeMapper\PHPStanStaticTypeMapper; /** * @implements TypeMapperInterface */ final class ConditionalTypeForParameterMapper implements TypeMapperInterface { - private PHPStanStaticTypeMapper $phpStanStaticTypeMapper; - - public function autowire(PHPStanStaticTypeMapper $phpStanStaticTypeMapper): void - { - $this->phpStanStaticTypeMapper = $phpStanStaticTypeMapper; - } - /** * @return array> */ @@ -40,14 +29,4 @@ public function mapToPHPStanPhpDocTypeNode(Type $type): TypeNode { return $type->toPhpDocNode(); } - - /** - * @param ConditionalTypeForParameter $type - * @param TypeKind::* $typeKind - */ - public function mapToPhpParserNode(Type $type, string $typeKind): ?Node - { - $type = TypeCombinator::union($type->getIf(), $type->getElse()); - return $this->phpStanStaticTypeMapper->mapToPhpParserNode($type, $typeKind); - } } diff --git a/src/PHPStanStaticTypeMapper/TypeMapper/ConditionalTypeMapper.php b/src/PHPStanStaticTypeMapper/TypeMapper/ConditionalTypeMapper.php index 72c567911b0..e49bbe8cf49 100644 --- a/src/PHPStanStaticTypeMapper/TypeMapper/ConditionalTypeMapper.php +++ b/src/PHPStanStaticTypeMapper/TypeMapper/ConditionalTypeMapper.php @@ -5,30 +5,19 @@ namespace Rector\PHPStanStaticTypeMapper\TypeMapper; use Nette\Utils\Strings; -use PhpParser\Node; use PHPStan\PhpDocParser\Ast\Type\TypeNode; use PHPStan\Reflection\ClassReflection; use PHPStan\Type\ConditionalType; use PHPStan\Type\ObjectType; use PHPStan\Type\Type; -use PHPStan\Type\TypeCombinator; use PHPStan\Type\TypeTraverser; use Rector\PHPStanStaticTypeMapper\Contract\TypeMapperInterface; -use Rector\PHPStanStaticTypeMapper\Enum\TypeKind; -use Rector\PHPStanStaticTypeMapper\PHPStanStaticTypeMapper; /** * @implements TypeMapperInterface */ final class ConditionalTypeMapper implements TypeMapperInterface { - private PHPStanStaticTypeMapper $phpStanStaticTypeMapper; - - public function autowire(PHPStanStaticTypeMapper $phpStanStaticTypeMapper): void - { - $this->phpStanStaticTypeMapper = $phpStanStaticTypeMapper; - } - /** * @return array> */ @@ -53,14 +42,4 @@ public function mapToPHPStanPhpDocTypeNode(Type $type): TypeNode return $type->toPhpDocNode(); } - - /** - * @param ConditionalType $type - * @param TypeKind::* $typeKind - */ - public function mapToPhpParserNode(Type $type, string $typeKind): ?Node - { - $type = TypeCombinator::union($type->getIf(), $type->getElse()); - return $this->phpStanStaticTypeMapper->mapToPhpParserNode($type, $typeKind); - } } diff --git a/src/PHPStanStaticTypeMapper/TypeMapper/ConstantArrayTypeMapper.php b/src/PHPStanStaticTypeMapper/TypeMapper/ConstantArrayTypeMapper.php index 4fb46d028a2..5ac9b458252 100644 --- a/src/PHPStanStaticTypeMapper/TypeMapper/ConstantArrayTypeMapper.php +++ b/src/PHPStanStaticTypeMapper/TypeMapper/ConstantArrayTypeMapper.php @@ -4,25 +4,16 @@ namespace Rector\PHPStanStaticTypeMapper\TypeMapper; -use PhpParser\Node; -use PhpParser\Node\Identifier; use PHPStan\PhpDocParser\Ast\Type\TypeNode; use PHPStan\Type\Constant\ConstantArrayType; use PHPStan\Type\Type; -use Rector\Php\PhpVersionProvider; use Rector\PHPStanStaticTypeMapper\Contract\TypeMapperInterface; -use Rector\ValueObject\PhpVersion; /** * @implements TypeMapperInterface */ final readonly class ConstantArrayTypeMapper implements TypeMapperInterface { - public function __construct( - private PhpVersionProvider $phpVersionProvider - ) { - } - /** * @return array> */ @@ -38,13 +29,4 @@ public function mapToPHPStanPhpDocTypeNode(Type $type): TypeNode { return $type->toPhpDocNode(); } - - public function mapToPhpParserNode(Type $type, string $typeKind): ?Node - { - if (! $this->phpVersionProvider->isAtLeastPhpVersion(PhpVersion::PHP_70)) { - return null; - } - - return new Identifier('array'); - } } diff --git a/src/PHPStanStaticTypeMapper/TypeMapper/FloatTypeMapper.php b/src/PHPStanStaticTypeMapper/TypeMapper/FloatTypeMapper.php index 51f86b5a830..ff7e3a262f9 100644 --- a/src/PHPStanStaticTypeMapper/TypeMapper/FloatTypeMapper.php +++ b/src/PHPStanStaticTypeMapper/TypeMapper/FloatTypeMapper.php @@ -4,25 +4,16 @@ namespace Rector\PHPStanStaticTypeMapper\TypeMapper; -use PhpParser\Node; -use PhpParser\Node\Identifier; use PHPStan\PhpDocParser\Ast\Type\TypeNode; use PHPStan\Type\FloatType; use PHPStan\Type\Type; -use Rector\Php\PhpVersionProvider; use Rector\PHPStanStaticTypeMapper\Contract\TypeMapperInterface; -use Rector\ValueObject\PhpVersion; /** * @implements TypeMapperInterface */ final readonly class FloatTypeMapper implements TypeMapperInterface { - public function __construct( - private PhpVersionProvider $phpVersionProvider - ) { - } - /** * @return array> */ @@ -38,16 +29,4 @@ public function mapToPHPStanPhpDocTypeNode(Type $type): TypeNode { return $type->toPhpDocNode(); } - - /** - * @param FloatType $type - */ - public function mapToPhpParserNode(Type $type, string $typeKind): ?Node - { - if (! $this->phpVersionProvider->isAtLeastPhpVersion(PhpVersion::PHP_70)) { - return null; - } - - return new Identifier('float'); - } } diff --git a/src/PHPStanStaticTypeMapper/TypeMapper/HasMethodTypeMapper.php b/src/PHPStanStaticTypeMapper/TypeMapper/HasMethodTypeMapper.php index 7d390862d95..9bc805d9e49 100644 --- a/src/PHPStanStaticTypeMapper/TypeMapper/HasMethodTypeMapper.php +++ b/src/PHPStanStaticTypeMapper/TypeMapper/HasMethodTypeMapper.php @@ -4,7 +4,6 @@ namespace Rector\PHPStanStaticTypeMapper\TypeMapper; -use PhpParser\Node; use PHPStan\PhpDocParser\Ast\Type\TypeNode; use PHPStan\Type\Accessory\HasMethodType; use PHPStan\Type\Type; @@ -15,11 +14,6 @@ */ final readonly class HasMethodTypeMapper implements TypeMapperInterface { - public function __construct( - private ObjectWithoutClassTypeMapper $objectWithoutClassTypeMapper - ) { - } - /** * @return array> */ @@ -35,12 +29,4 @@ public function mapToPHPStanPhpDocTypeNode(Type $type): TypeNode { return $type->toPhpDocNode(); } - - /** - * @param HasMethodType $type - */ - public function mapToPhpParserNode(Type $type, string $typeKind): ?Node - { - return $this->objectWithoutClassTypeMapper->mapToPhpParserNode($type, $typeKind); - } } diff --git a/src/PHPStanStaticTypeMapper/TypeMapper/HasPropertyTypeMapper.php b/src/PHPStanStaticTypeMapper/TypeMapper/HasPropertyTypeMapper.php index 01ffe7fa2ed..b7de4e4c2e3 100644 --- a/src/PHPStanStaticTypeMapper/TypeMapper/HasPropertyTypeMapper.php +++ b/src/PHPStanStaticTypeMapper/TypeMapper/HasPropertyTypeMapper.php @@ -4,7 +4,6 @@ namespace Rector\PHPStanStaticTypeMapper\TypeMapper; -use PhpParser\Node; use PHPStan\PhpDocParser\Ast\Type\TypeNode; use PHPStan\Type\Accessory\HasPropertyType; use PHPStan\Type\Type; @@ -15,11 +14,6 @@ */ final readonly class HasPropertyTypeMapper implements TypeMapperInterface { - public function __construct( - private ObjectWithoutClassTypeMapper $objectWithoutClassTypeMapper - ) { - } - /** * @return array> */ @@ -35,12 +29,4 @@ public function mapToPHPStanPhpDocTypeNode(Type $type): TypeNode { return $type->toPhpDocNode(); } - - /** - * @param HasPropertyType $type - */ - public function mapToPhpParserNode(Type $type, string $typeKind): ?Node - { - return $this->objectWithoutClassTypeMapper->mapToPhpParserNode($type, $typeKind); - } } diff --git a/src/PHPStanStaticTypeMapper/TypeMapper/IntegerTypeMapper.php b/src/PHPStanStaticTypeMapper/TypeMapper/IntegerTypeMapper.php index dbccc5e30a9..2a776ad604c 100644 --- a/src/PHPStanStaticTypeMapper/TypeMapper/IntegerTypeMapper.php +++ b/src/PHPStanStaticTypeMapper/TypeMapper/IntegerTypeMapper.php @@ -4,25 +4,16 @@ namespace Rector\PHPStanStaticTypeMapper\TypeMapper; -use PhpParser\Node; -use PhpParser\Node\Identifier; use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode; use PHPStan\Type\IntegerType; use PHPStan\Type\Type; -use Rector\Php\PhpVersionProvider; use Rector\PHPStanStaticTypeMapper\Contract\TypeMapperInterface; -use Rector\ValueObject\PhpVersion; /** * @implements TypeMapperInterface */ final readonly class IntegerTypeMapper implements TypeMapperInterface { - public function __construct( - private PhpVersionProvider $phpVersionProvider - ) { - } - /** * @return array> */ @@ -39,16 +30,4 @@ public function mapToPHPStanPhpDocTypeNode(Type $type): IdentifierTypeNode // note: cannot be handled by PHPStan as uses explicit values return new IdentifierTypeNode('int'); } - - /** - * @param IntegerType $type - */ - public function mapToPhpParserNode(Type $type, string $typeKind): ?Node - { - if (! $this->phpVersionProvider->isAtLeastPhpVersion(PhpVersion::PHP_70)) { - return null; - } - - return new Identifier('int'); - } } diff --git a/src/PHPStanStaticTypeMapper/TypeMapper/IntersectionTypeMapper.php b/src/PHPStanStaticTypeMapper/TypeMapper/IntersectionTypeMapper.php index dafaa306b84..86cf2d6223f 100644 --- a/src/PHPStanStaticTypeMapper/TypeMapper/IntersectionTypeMapper.php +++ b/src/PHPStanStaticTypeMapper/TypeMapper/IntersectionTypeMapper.php @@ -4,9 +4,6 @@ namespace Rector\PHPStanStaticTypeMapper\TypeMapper; -use PhpParser\Node; -use PhpParser\Node\Identifier; -use PhpParser\Node\Name\FullyQualified; use PHPStan\PhpDocParser\Ast\Node as AstNode; use PHPStan\PhpDocParser\Ast\NodeTraverser; use PHPStan\PhpDocParser\Ast\Type\ArrayShapeItemNode; @@ -15,15 +12,10 @@ use PHPStan\PhpDocParser\Ast\Type\UnionTypeNode; use PHPStan\Type\IntersectionType; use PHPStan\Type\MixedType; -use PHPStan\Type\ObjectType; -use PHPStan\Type\ObjectWithoutClassType; use PHPStan\Type\Type; -use Rector\Php\PhpVersionProvider; use Rector\PhpDocParser\PhpDocParser\PhpDocNodeVisitor\CallablePhpDocNodeVisitor; use Rector\PHPStanStaticTypeMapper\Contract\TypeMapperInterface; -use Rector\PHPStanStaticTypeMapper\Enum\TypeKind; use Rector\StaticTypeMapper\Mapper\ScalarStringToTypeMapper; -use Rector\ValueObject\PhpVersion; /** * @implements TypeMapperInterface @@ -31,9 +23,6 @@ final readonly class IntersectionTypeMapper implements TypeMapperInterface { public function __construct( - private PhpVersionProvider $phpVersionProvider, - private ObjectWithoutClassTypeMapper $objectWithoutClassTypeMapper, - private ObjectTypeMapper $objectTypeMapper, private ScalarStringToTypeMapper $scalarStringToTypeMapper, ) { } @@ -92,54 +81,4 @@ function (AstNode $astNode) use ($typeNode): int|IdentifierTypeNode|null { return $typeNode; } - - /** - * @param IntersectionType $type - */ - public function mapToPhpParserNode(Type $type, string $typeKind): ?Node - { - // accessory string types, e.g. "numeric-string&non-falsy-string", are just "string" - if ($type->isString()->yes()) { - return new Identifier('string'); - } - - if (! $this->phpVersionProvider->isAtLeastPhpVersion(PhpVersion::PHP_81)) { - return null; - } - - $intersectionedTypeNodes = []; - foreach ($type->getTypes() as $type) { - if ($type instanceof ObjectWithoutClassType) { - return $this->objectWithoutClassTypeMapper->mapToPhpParserNode($type, $typeKind); - } - - if (! $type instanceof ObjectType) { - return null; - } - - $resolvedType = $this->objectTypeMapper->mapToPhpParserNode($type, $typeKind); - - if (! $resolvedType instanceof FullyQualified) { - return null; - } - - $intersectionedTypeNodes[] = $resolvedType; - } - - if ($intersectionedTypeNodes === []) { - return null; - } - - if (count($intersectionedTypeNodes) === 1) { - return current($intersectionedTypeNodes); - } - - if ($typeKind === TypeKind::UNION && ! $this->phpVersionProvider->isAtLeastPhpVersion( - PhpVersion::PHP_82 - )) { - return null; - } - - return new Node\IntersectionType($intersectionedTypeNodes); - } } diff --git a/src/PHPStanStaticTypeMapper/TypeMapper/IterableTypeMapper.php b/src/PHPStanStaticTypeMapper/TypeMapper/IterableTypeMapper.php index 27db268db96..dc343d0fc9c 100644 --- a/src/PHPStanStaticTypeMapper/TypeMapper/IterableTypeMapper.php +++ b/src/PHPStanStaticTypeMapper/TypeMapper/IterableTypeMapper.php @@ -4,7 +4,6 @@ namespace Rector\PHPStanStaticTypeMapper\TypeMapper; -use PhpParser\Node\Identifier; use PHPStan\PhpDocParser\Ast\Type\TypeNode; use PHPStan\Type\IterableType; use PHPStan\Type\Type; @@ -30,12 +29,4 @@ public function mapToPHPStanPhpDocTypeNode(Type $type): TypeNode { return $type->toPhpDocNode(); } - - /** - * @param IterableType $type - */ - public function mapToPhpParserNode(Type $type, string $typeKind): Identifier - { - return new Identifier('iterable'); - } } diff --git a/src/PHPStanStaticTypeMapper/TypeMapper/MixedTypeMapper.php b/src/PHPStanStaticTypeMapper/TypeMapper/MixedTypeMapper.php index f87cdccab57..7301a7c27d3 100644 --- a/src/PHPStanStaticTypeMapper/TypeMapper/MixedTypeMapper.php +++ b/src/PHPStanStaticTypeMapper/TypeMapper/MixedTypeMapper.php @@ -4,26 +4,16 @@ namespace Rector\PHPStanStaticTypeMapper\TypeMapper; -use PhpParser\Node; -use PhpParser\Node\Identifier; use PHPStan\PhpDocParser\Ast\Type\TypeNode; use PHPStan\Type\MixedType; use PHPStan\Type\Type; -use Rector\Php\PhpVersionProvider; use Rector\PHPStanStaticTypeMapper\Contract\TypeMapperInterface; -use Rector\PHPStanStaticTypeMapper\Enum\TypeKind; -use Rector\ValueObject\PhpVersion; /** * @implements TypeMapperInterface */ final readonly class MixedTypeMapper implements TypeMapperInterface { - public function __construct( - private PhpVersionProvider $phpVersionProvider - ) { - } - /** * @return array> */ @@ -39,24 +29,4 @@ public function mapToPHPStanPhpDocTypeNode(Type $type): TypeNode { return $type->toPhpDocNode(); } - - /** - * @param MixedType $type - */ - public function mapToPhpParserNode(Type $type, string $typeKind): ?Node - { - if (! $this->phpVersionProvider->isAtLeastPhpVersion(PhpVersion::PHP_80)) { - return null; - } - - if (! $type->isExplicitMixed()) { - return null; - } - - if ($typeKind === TypeKind::UNION) { - return null; - } - - return new Identifier('mixed'); - } } diff --git a/src/PHPStanStaticTypeMapper/TypeMapper/NeverTypeMapper.php b/src/PHPStanStaticTypeMapper/TypeMapper/NeverTypeMapper.php index ea94feb2759..584f736e664 100644 --- a/src/PHPStanStaticTypeMapper/TypeMapper/NeverTypeMapper.php +++ b/src/PHPStanStaticTypeMapper/TypeMapper/NeverTypeMapper.php @@ -4,7 +4,6 @@ namespace Rector\PHPStanStaticTypeMapper\TypeMapper; -use PhpParser\Node; use PHPStan\PhpDocParser\Ast\Type\TypeNode; use PHPStan\Type\NeverType; use PHPStan\Type\Type; @@ -30,12 +29,4 @@ public function mapToPHPStanPhpDocTypeNode(Type $type): TypeNode { return $type->toPhpDocNode(); } - - /** - * @param NeverType $type - */ - public function mapToPhpParserNode(Type $type, string $typeKind): ?Node - { - return null; - } } diff --git a/src/PHPStanStaticTypeMapper/TypeMapper/NonexistentParentClassTypeMapper.php b/src/PHPStanStaticTypeMapper/TypeMapper/NonexistentParentClassTypeMapper.php index f2d88a35dd3..44df721481a 100644 --- a/src/PHPStanStaticTypeMapper/TypeMapper/NonexistentParentClassTypeMapper.php +++ b/src/PHPStanStaticTypeMapper/TypeMapper/NonexistentParentClassTypeMapper.php @@ -4,11 +4,9 @@ namespace Rector\PHPStanStaticTypeMapper\TypeMapper; -use PhpParser\Node\Name; use PHPStan\PhpDocParser\Ast\Type\TypeNode; use PHPStan\Type\NonexistentParentClassType; use PHPStan\Type\Type; -use Rector\Enum\ObjectReference; use Rector\PHPStanStaticTypeMapper\Contract\TypeMapperInterface; /** @@ -36,12 +34,4 @@ public function mapToPHPStanPhpDocTypeNode(Type $type): TypeNode { return $type->toPhpDocNode(); } - - /** - * @param NonexistentParentClassType $type - */ - public function mapToPhpParserNode(Type $type, string $typeKind): Name - { - return new Name(ObjectReference::PARENT); - } } diff --git a/src/PHPStanStaticTypeMapper/TypeMapper/NullTypeMapper.php b/src/PHPStanStaticTypeMapper/TypeMapper/NullTypeMapper.php index 41a8bf637ee..8d53d8fa25c 100644 --- a/src/PHPStanStaticTypeMapper/TypeMapper/NullTypeMapper.php +++ b/src/PHPStanStaticTypeMapper/TypeMapper/NullTypeMapper.php @@ -4,26 +4,16 @@ namespace Rector\PHPStanStaticTypeMapper\TypeMapper; -use PhpParser\Node; -use PhpParser\Node\Identifier; use PHPStan\PhpDocParser\Ast\Type\TypeNode; use PHPStan\Type\NullType; use PHPStan\Type\Type; -use Rector\Php\PhpVersionProvider; use Rector\PHPStanStaticTypeMapper\Contract\TypeMapperInterface; -use Rector\PHPStanStaticTypeMapper\Enum\TypeKind; -use Rector\ValueObject\PhpVersion; /** * @implements TypeMapperInterface */ final readonly class NullTypeMapper implements TypeMapperInterface { - public function __construct( - private PhpVersionProvider $phpVersionProvider - ) { - } - /** * @return array> */ @@ -39,27 +29,4 @@ public function mapToPHPStanPhpDocTypeNode(Type $type): TypeNode { return $type->toPhpDocNode(); } - - /** - * @param TypeKind::* $typeKind - * @param NullType $type - */ - public function mapToPhpParserNode(Type $type, string $typeKind): ?Node - { - // can be a standalone type, only case where null makes sense - if ($this->phpVersionProvider->isAtLeastPhpVersion( - PhpVersion::PHP_82 - ) && $typeKind === TypeKind::RETURN) { - return new Identifier('null'); - } - - // if part of union, can be added even in PHP 8.0 - if ($typeKind === TypeKind::UNION && $this->phpVersionProvider->isAtLeastPhpVersion( - PhpVersion::PHP_71 - )) { - return new Identifier('null'); - } - - return null; - } } diff --git a/src/PHPStanStaticTypeMapper/TypeMapper/ObjectTypeMapper.php b/src/PHPStanStaticTypeMapper/TypeMapper/ObjectTypeMapper.php index 5df7718ffd5..1face548f9d 100644 --- a/src/PHPStanStaticTypeMapper/TypeMapper/ObjectTypeMapper.php +++ b/src/PHPStanStaticTypeMapper/TypeMapper/ObjectTypeMapper.php @@ -4,10 +4,6 @@ namespace Rector\PHPStanStaticTypeMapper\TypeMapper; -use Nette\Utils\Strings; -use PhpParser\Node; -use PhpParser\Node\Name; -use PhpParser\Node\Name\FullyQualified; use PHPStan\PhpDocParser\Ast\Type\TypeNode; use PHPStan\Type\ArrayType; use PHPStan\Type\Generic\GenericObjectType; @@ -16,11 +12,7 @@ use PHPStan\Type\Type; use PHPStan\Type\TypeTraverser; use Rector\PHPStanStaticTypeMapper\Contract\TypeMapperInterface; -use Rector\StaticTypeMapper\ValueObject\Type\AliasedObjectType; use Rector\StaticTypeMapper\ValueObject\Type\FullyQualifiedObjectType; -use Rector\StaticTypeMapper\ValueObject\Type\NonExistingObjectType; -use Rector\StaticTypeMapper\ValueObject\Type\SelfObjectType; -use Rector\StaticTypeMapper\ValueObject\Type\ShortenedObjectType; /** * @implements TypeMapperInterface @@ -69,35 +61,4 @@ public function mapToPHPStanPhpDocTypeNode(Type $type): TypeNode return $type->toPhpDocNode(); } - - /** - * @param ObjectType $type - */ - public function mapToPhpParserNode(Type $type, string $typeKind): ?Node - { - if ($type instanceof SelfObjectType) { - return new Name('self'); - } - - if ($type instanceof ShortenedObjectType || $type instanceof AliasedObjectType) { - return new FullyQualified($type->getFullyQualifiedName()); - } - - if ($type instanceof FullyQualifiedObjectType) { - $className = $type->getClassName(); - - if (str_starts_with($className, '\\')) { - // skip leading \ - return new FullyQualified(Strings::substring($className, 1)); - } - - return new FullyQualified($className); - } - - if ($type instanceof NonExistingObjectType) { - return null; - } - - return new FullyQualified($type->getClassName()); - } } diff --git a/src/PHPStanStaticTypeMapper/TypeMapper/ObjectWithoutClassTypeMapper.php b/src/PHPStanStaticTypeMapper/TypeMapper/ObjectWithoutClassTypeMapper.php index 7b579cbb1fc..7ee3075a60b 100644 --- a/src/PHPStanStaticTypeMapper/TypeMapper/ObjectWithoutClassTypeMapper.php +++ b/src/PHPStanStaticTypeMapper/TypeMapper/ObjectWithoutClassTypeMapper.php @@ -4,29 +4,16 @@ namespace Rector\PHPStanStaticTypeMapper\TypeMapper; -use PhpParser\Node; -use PhpParser\Node\Identifier; -use PhpParser\Node\Name\FullyQualified; use PHPStan\PhpDocParser\Ast\Type\TypeNode; -use PHPStan\Type\Accessory\HasMethodType; -use PHPStan\Type\Accessory\HasPropertyType; use PHPStan\Type\ObjectWithoutClassType; use PHPStan\Type\Type; -use Rector\NodeTypeResolver\PHPStan\ObjectWithoutClassTypeWithParentTypes; -use Rector\Php\PhpVersionProvider; use Rector\PHPStanStaticTypeMapper\Contract\TypeMapperInterface; -use Rector\ValueObject\PhpVersion; /** * @implements TypeMapperInterface */ final readonly class ObjectWithoutClassTypeMapper implements TypeMapperInterface { - public function __construct( - private PhpVersionProvider $phpVersionProvider - ) { - } - /** * @return array> */ @@ -42,25 +29,4 @@ public function mapToPHPStanPhpDocTypeNode(Type $type): TypeNode { return $type->toPhpDocNode(); } - - /** - * @param ObjectWithoutClassType|HasMethodType|HasPropertyType $type - */ - public function mapToPhpParserNode(Type $type, string $typeKind): ?Node - { - // special case for anonymous classes that implement another type - if ($type instanceof ObjectWithoutClassTypeWithParentTypes) { - $parentTypes = $type->getParentTypes(); - if (count($parentTypes) === 1) { - $parentType = $parentTypes[0]; - return new FullyQualified($parentType->getClassName()); - } - } - - if (! $this->phpVersionProvider->isAtLeastPhpVersion(PhpVersion::PHP_72)) { - return null; - } - - return new Identifier('object'); - } } diff --git a/src/PHPStanStaticTypeMapper/TypeMapper/ParentStaticTypeMapper.php b/src/PHPStanStaticTypeMapper/TypeMapper/ParentStaticTypeMapper.php index db27b9dd2b0..ac8cc99b93a 100644 --- a/src/PHPStanStaticTypeMapper/TypeMapper/ParentStaticTypeMapper.php +++ b/src/PHPStanStaticTypeMapper/TypeMapper/ParentStaticTypeMapper.php @@ -4,10 +4,8 @@ namespace Rector\PHPStanStaticTypeMapper\TypeMapper; -use PhpParser\Node\Name; use PHPStan\PhpDocParser\Ast\Type\TypeNode; use PHPStan\Type\Type; -use Rector\Enum\ObjectReference; use Rector\PHPStanStaticTypeMapper\Contract\TypeMapperInterface; use Rector\StaticTypeMapper\ValueObject\Type\ParentStaticType; @@ -31,12 +29,4 @@ public function mapToPHPStanPhpDocTypeNode(Type $type): TypeNode { return $type->toPhpDocNode(); } - - /** - * @param ParentStaticType $type - */ - public function mapToPhpParserNode(Type $type, string $typeKind): Name - { - return new Name(ObjectReference::PARENT); - } } diff --git a/src/PHPStanStaticTypeMapper/TypeMapper/ResourceTypeMapper.php b/src/PHPStanStaticTypeMapper/TypeMapper/ResourceTypeMapper.php index f2b2ebb6e95..da1570df0ef 100644 --- a/src/PHPStanStaticTypeMapper/TypeMapper/ResourceTypeMapper.php +++ b/src/PHPStanStaticTypeMapper/TypeMapper/ResourceTypeMapper.php @@ -4,7 +4,6 @@ namespace Rector\PHPStanStaticTypeMapper\TypeMapper; -use PhpParser\Node; use PHPStan\PhpDocParser\Ast\Type\TypeNode; use PHPStan\Type\ResourceType; use PHPStan\Type\Type; @@ -30,12 +29,4 @@ public function mapToPHPStanPhpDocTypeNode(Type $type): TypeNode { return $type->toPhpDocNode(); } - - /** - * @param ResourceType $type - */ - public function mapToPhpParserNode(Type $type, string $typeKind): ?Node - { - return null; - } } diff --git a/src/PHPStanStaticTypeMapper/TypeMapper/StaticTypeMapper.php b/src/PHPStanStaticTypeMapper/TypeMapper/StaticTypeMapper.php index bcd234e5124..de0f992145d 100644 --- a/src/PHPStanStaticTypeMapper/TypeMapper/StaticTypeMapper.php +++ b/src/PHPStanStaticTypeMapper/TypeMapper/StaticTypeMapper.php @@ -4,17 +4,10 @@ namespace Rector\PHPStanStaticTypeMapper\TypeMapper; -use PhpParser\Node\Name; use PHPStan\PhpDocParser\Ast\Type\TypeNode; use PHPStan\Type\StaticType; use PHPStan\Type\Type; -use Rector\Enum\ObjectReference; -use Rector\Php\PhpVersionProvider; use Rector\PHPStanStaticTypeMapper\Contract\TypeMapperInterface; -use Rector\PHPStanStaticTypeMapper\Enum\TypeKind; -use Rector\StaticTypeMapper\ValueObject\Type\SelfStaticType; -use Rector\StaticTypeMapper\ValueObject\Type\SimpleStaticType; -use Rector\ValueObject\PhpVersion; /** * @see \Rector\Tests\NodeTypeResolver\StaticTypeMapper\StaticTypeMapperTest @@ -23,11 +16,6 @@ */ final readonly class StaticTypeMapper implements TypeMapperInterface { - public function __construct( - private PhpVersionProvider $phpVersionProvider - ) { - } - /** * @return array> */ @@ -43,24 +31,4 @@ public function mapToPHPStanPhpDocTypeNode(Type $type): TypeNode { return $type->toPhpDocNode(); } - - /** - * @param SimpleStaticType|StaticType $type - */ - public function mapToPhpParserNode(Type $type, string $typeKind): Name - { - if ($type instanceof SelfStaticType) { - return new Name(ObjectReference::SELF); - } - - if ($typeKind !== TypeKind::RETURN) { - return new Name(ObjectReference::SELF); - } - - if (! $this->phpVersionProvider->isAtLeastPhpVersion(PhpVersion::PHP_80)) { - return new Name(ObjectReference::SELF); - } - - return new Name(ObjectReference::STATIC); - } } diff --git a/src/PHPStanStaticTypeMapper/TypeMapper/StrictMixedTypeMapper.php b/src/PHPStanStaticTypeMapper/TypeMapper/StrictMixedTypeMapper.php index 90c58411d43..4ec27858436 100644 --- a/src/PHPStanStaticTypeMapper/TypeMapper/StrictMixedTypeMapper.php +++ b/src/PHPStanStaticTypeMapper/TypeMapper/StrictMixedTypeMapper.php @@ -4,28 +4,16 @@ namespace Rector\PHPStanStaticTypeMapper\TypeMapper; -use PhpParser\Node; -use PhpParser\Node\Identifier; use PHPStan\PhpDocParser\Ast\Type\TypeNode; use PHPStan\Type\StrictMixedType; use PHPStan\Type\Type; -use Rector\Php\PhpVersionProvider; use Rector\PHPStanStaticTypeMapper\Contract\TypeMapperInterface; -use Rector\PHPStanStaticTypeMapper\Enum\TypeKind; -use Rector\ValueObject\PhpVersion; /** * @implements TypeMapperInterface */ final readonly class StrictMixedTypeMapper implements TypeMapperInterface { - private const string MIXED = 'mixed'; - - public function __construct( - private PhpVersionProvider $phpVersionProvider - ) { - } - /** * @return array> */ @@ -41,20 +29,4 @@ public function mapToPHPStanPhpDocTypeNode(Type $type): TypeNode { return $type->toPhpDocNode(); } - - /** - * @param StrictMixedType $type - */ - public function mapToPhpParserNode(Type $type, string $typeKind): ?Node - { - if (! $this->phpVersionProvider->isAtLeastPhpVersion(PhpVersion::PHP_80)) { - return null; - } - - if ($typeKind === TypeKind::UNION) { - return null; - } - - return new Identifier(self::MIXED); - } } diff --git a/src/PHPStanStaticTypeMapper/TypeMapper/StringTypeMapper.php b/src/PHPStanStaticTypeMapper/TypeMapper/StringTypeMapper.php index b4149f93d3d..880021dee0f 100644 --- a/src/PHPStanStaticTypeMapper/TypeMapper/StringTypeMapper.php +++ b/src/PHPStanStaticTypeMapper/TypeMapper/StringTypeMapper.php @@ -4,25 +4,16 @@ namespace Rector\PHPStanStaticTypeMapper\TypeMapper; -use PhpParser\Node; -use PhpParser\Node\Identifier; use PHPStan\PhpDocParser\Ast\Type\TypeNode; use PHPStan\Type\StringType; use PHPStan\Type\Type; -use Rector\Php\PhpVersionProvider; use Rector\PHPStanStaticTypeMapper\Contract\TypeMapperInterface; -use Rector\ValueObject\PhpVersion; /** * @implements TypeMapperInterface */ final readonly class StringTypeMapper implements TypeMapperInterface { - public function __construct( - private PhpVersionProvider $phpVersionProvider - ) { - } - /** * @return array> */ @@ -38,13 +29,4 @@ public function mapToPHPStanPhpDocTypeNode(Type $type): TypeNode { return $type->toPhpDocNode(); } - - public function mapToPhpParserNode(Type $type, string $typeKind): ?Node - { - if (! $this->phpVersionProvider->isAtLeastPhpVersion(PhpVersion::PHP_70)) { - return null; - } - - return new Identifier('string'); - } } diff --git a/src/PHPStanStaticTypeMapper/TypeMapper/TypeWithClassNameTypeMapper.php b/src/PHPStanStaticTypeMapper/TypeMapper/TypeWithClassNameTypeMapper.php index 3a6f46a2930..452b11d7e1f 100644 --- a/src/PHPStanStaticTypeMapper/TypeMapper/TypeWithClassNameTypeMapper.php +++ b/src/PHPStanStaticTypeMapper/TypeMapper/TypeWithClassNameTypeMapper.php @@ -4,25 +4,16 @@ namespace Rector\PHPStanStaticTypeMapper\TypeMapper; -use PhpParser\Node; -use PhpParser\Node\Identifier; use PHPStan\PhpDocParser\Ast\Type\TypeNode; use PHPStan\Type\Type; use PHPStan\Type\TypeWithClassName; -use Rector\Php\PhpVersionProvider; use Rector\PHPStanStaticTypeMapper\Contract\TypeMapperInterface; -use Rector\ValueObject\PhpVersion; /** * @implements TypeMapperInterface */ final readonly class TypeWithClassNameTypeMapper implements TypeMapperInterface { - public function __construct( - private PhpVersionProvider $phpVersionProvider - ) { - } - /** * @return array> */ @@ -38,16 +29,4 @@ public function mapToPHPStanPhpDocTypeNode(Type $type): TypeNode { return $type->toPhpDocNode(); } - - /** - * @param TypeWithClassName $type - */ - public function mapToPhpParserNode(Type $type, string $typeKind): ?Node - { - if (! $this->phpVersionProvider->isAtLeastPhpVersion(PhpVersion::PHP_70)) { - return null; - } - - return new Identifier('string'); - } } diff --git a/src/PHPStanStaticTypeMapper/TypeMapper/UnionTypeMapper.php b/src/PHPStanStaticTypeMapper/TypeMapper/UnionTypeMapper.php index 0d68d41dcd5..485a997cc34 100644 --- a/src/PHPStanStaticTypeMapper/TypeMapper/UnionTypeMapper.php +++ b/src/PHPStanStaticTypeMapper/TypeMapper/UnionTypeMapper.php @@ -4,28 +4,14 @@ namespace Rector\PHPStanStaticTypeMapper\TypeMapper; -use PhpParser\Node; -use PhpParser\Node\ComplexType; -use PhpParser\Node\Identifier; -use PhpParser\Node\IntersectionType as PHPParserNodeIntersectionType; -use PhpParser\Node\Name; -use PhpParser\Node\Name\FullyQualified; -use PhpParser\Node\NullableType; -use PhpParser\Node\UnionType as PhpParserUnionType; use PHPStan\PhpDocParser\Ast\Type\UnionTypeNode; use PHPStan\Type\ArrayType; use PHPStan\Type\MixedType; use PHPStan\Type\NeverType; use PHPStan\Type\Type; use PHPStan\Type\UnionType; -use Rector\NodeAnalyzer\PropertyAnalyzer; -use Rector\Php\PhpVersionProvider; use Rector\PHPStanStaticTypeMapper\Contract\TypeMapperInterface; -use Rector\PHPStanStaticTypeMapper\Enum\TypeKind; use Rector\PHPStanStaticTypeMapper\PHPStanStaticTypeMapper; -use Rector\ValueObject\PhpVersion; -use Webmozart\Assert\Assert; -use Webmozart\Assert\InvalidArgumentException; /** * @implements TypeMapperInterface @@ -34,12 +20,6 @@ final class UnionTypeMapper implements TypeMapperInterface { private PHPStanStaticTypeMapper $phpStanStaticTypeMapper; - public function __construct( - private readonly PhpVersionProvider $phpVersionProvider, - private readonly PropertyAnalyzer $propertyAnalyzer - ) { - } - public function autowire(PHPStanStaticTypeMapper $phpStanStaticTypeMapper): void { $this->phpStanStaticTypeMapper = $phpStanStaticTypeMapper; @@ -56,7 +36,7 @@ public function getNodeClasses(): array /** * @param UnionType $type */ - public function mapToPHPStanPhpDocTypeNode(Type $type): UnionTypeNode + public function mapToPHPStanPhpDocTypeNode(Type $type): BracketsAwareUnionTypeNode { $unionTypesNodes = []; @@ -78,225 +58,4 @@ public function mapToPHPStanPhpDocTypeNode(Type $type): UnionTypeNode return new UnionTypeNode(array_values($unionTypesNodes)); } - - /** - * @param UnionType $type - */ - public function mapToPhpParserNode(Type $type, string $typeKind): ?Node - { - $phpParserUnionType = $this->matchPhpParserUnionType($type, $typeKind); - if ($phpParserUnionType instanceof PhpParserUnionType) { - return $this->resolveUnionTypeNode($phpParserUnionType); - } - - return $phpParserUnionType; - } - - /** - * If type is nullable, and has only one other value, - * this creates at least "?Type" in case of PHP 7.1-7.4 - */ - private function resolveTypeWithNullablePHPParserUnionType( - PhpParserUnionType $phpParserUnionType - ): PhpParserUnionType|NullableType|null { - $totalTypes = count($phpParserUnionType->types); - if ($totalTypes === 2) { - $firstType = $phpParserUnionType->types[0]; - $secondType = $phpParserUnionType->types[1]; - - try { - Assert::isAnyOf($firstType, [Name::class, Identifier::class]); - Assert::isAnyOf($secondType, [Name::class, Identifier::class]); - } catch (InvalidArgumentException) { - return $this->resolveUnionTypes($phpParserUnionType); - } - - $firstTypeValue = $firstType->toString(); - $secondTypeValue = $secondType->toString(); - - if ($firstTypeValue === $secondTypeValue) { - return $this->resolveUnionTypes($phpParserUnionType); - } - - if ($firstTypeValue === 'null') { - return $this->resolveNullableType(new NullableType($secondType)); - } - - if ($secondTypeValue === 'null') { - return $this->resolveNullableType(new NullableType($firstType)); - } - } - - return $this->resolveUnionTypes($phpParserUnionType); - } - - private function resolveNullableType(NullableType $nullableType): null|NullableType|PhpParserUnionType - { - if (! $this->phpVersionProvider->isAtLeastPhpVersion(PhpVersion::PHP_71)) { - return null; - } - - /** @var PHPParserNodeIntersectionType|Identifier|Name $type */ - $type = $nullableType->type; - if (! $type instanceof PHPParserNodeIntersectionType) { - // ?false is allowed only since PHP 8.2+, lets fallback to bool instead - if ($type->toString() === 'false' && ! $this->phpVersionProvider->isAtLeastPhpVersion( - PhpVersion::PHP_82 - )) { - return new NullableType(new Identifier('bool')); - } - - return $nullableType; - } - - if (! $this->phpVersionProvider->isAtLeastPhpVersion(PhpVersion::PHP_80)) { - return null; - } - - $types = [$type]; - $types[] = new Identifier('null'); - - return new PhpParserUnionType($types); - } - - private function resolveUnionTypes(PhpParserUnionType $phpParserUnionType): ?PhpParserUnionType - { - if (! $this->phpVersionProvider->isAtLeastPhpVersion(PhpVersion::PHP_80)) { - return null; - } - - return $phpParserUnionType; - } - - private function hasObjectAndStaticType(PhpParserUnionType $phpParserUnionType): bool - { - $hasAnonymousObjectType = false; - $hasObjectType = false; - foreach ($phpParserUnionType->types as $type) { - if ($type instanceof Identifier && $type->toString() === 'object') { - $hasAnonymousObjectType = true; - continue; - } - - if ($type instanceof FullyQualified || ($type instanceof Name && $type->isSpecialClassName())) { - $hasObjectType = true; - continue; - } - } - - return $hasObjectType && $hasAnonymousObjectType; - } - - /** - * @return Name|FullyQualified|ComplexType|Identifier|null - */ - private function matchPhpParserUnionType(UnionType $unionType, string $typeKind): ?Node - { - $phpParserUnionedTypes = []; - - foreach ($unionType->getTypes() as $unionedType) { - // NullType or ConstantBooleanType with false value inside UnionType is allowed - // void type and mixed type are not allowed in union - $phpParserNode = $this->phpStanStaticTypeMapper->mapToPhpParserNode($unionedType, TypeKind::UNION); - if ($phpParserNode === null) { - return null; - } - - // special callable type only not allowed on property - if ($typeKind === TypeKind::PROPERTY && $this->propertyAnalyzer->isForbiddenType($unionedType)) { - return null; - } - - $phpParserUnionedTypes[] = $phpParserNode; - } - - /** @var Identifier[]|Name[] $phpParserUnionedTypes */ - $phpParserUnionedTypes = array_unique($phpParserUnionedTypes, SORT_REGULAR); - $phpParserUnionedTypes = $this->removeRedundantIntersectionTypes($phpParserUnionedTypes); - - $countPhpParserUnionedTypes = count($phpParserUnionedTypes); - if ($countPhpParserUnionedTypes === 1) { - return $phpParserUnionedTypes[0]; - } - - return $this->resolveTypeWithNullablePHPParserUnionType(new PhpParserUnionType($phpParserUnionedTypes)); - } - - /** - * PHP rejects e.g. "A|(A&B)" with "Type A&B is redundant as it is more restrictive than type A", - * so drop intersections that contain all parts of another member of the union - * - * @param array $phpParserUnionedTypes - * @return list - */ - private function removeRedundantIntersectionTypes(array $phpParserUnionedTypes): array - { - $typeNames = []; - foreach ($phpParserUnionedTypes as $key => $phpParserUnionedType) { - $typeNames[$key] = $this->resolveIntersectionPartNames($phpParserUnionedType); - } - - foreach ($phpParserUnionedTypes as $key => $phpParserUnionedType) { - if (! $phpParserUnionedType instanceof PHPParserNodeIntersectionType) { - continue; - } - - foreach ($typeNames as $otherKey => $otherTypeNames) { - if ($otherKey === $key || $otherTypeNames === []) { - continue; - } - - // already removed - if (! isset($phpParserUnionedTypes[$otherKey])) { - continue; - } - - if (array_diff($otherTypeNames, $typeNames[$key]) === []) { - unset($phpParserUnionedTypes[$key]); - continue 2; - } - } - } - - return array_values($phpParserUnionedTypes); - } - - /** - * @return string[] - */ - private function resolveIntersectionPartNames(Node $node): array - { - if ($node instanceof Name) { - return [$node->toString()]; - } - - if (! $node instanceof PHPParserNodeIntersectionType) { - return []; - } - - $names = []; - foreach ($node->types as $type) { - if (! $type instanceof Name) { - return []; - } - - $names[] = $type->toString(); - } - - return $names; - } - - private function resolveUnionTypeNode(PhpParserUnionType $phpParserUnionType): ?PhpParserUnionType - { - if (! $this->phpVersionProvider->isAtLeastPhpVersion(PhpVersion::PHP_80)) { - return null; - } - - // special case that would crash, when stdClass and object is used, - if ($this->hasObjectAndStaticType($phpParserUnionType)) { - return null; - } - - return $phpParserUnionType; - } } diff --git a/src/PHPStanStaticTypeMapper/TypeMapper/VoidTypeMapper.php b/src/PHPStanStaticTypeMapper/TypeMapper/VoidTypeMapper.php index 7b771ba1807..4b4687569ee 100644 --- a/src/PHPStanStaticTypeMapper/TypeMapper/VoidTypeMapper.php +++ b/src/PHPStanStaticTypeMapper/TypeMapper/VoidTypeMapper.php @@ -4,28 +4,16 @@ namespace Rector\PHPStanStaticTypeMapper\TypeMapper; -use PhpParser\Node; -use PhpParser\Node\Identifier; use PHPStan\PhpDocParser\Ast\Type\TypeNode; use PHPStan\Type\Type; use PHPStan\Type\VoidType; -use Rector\Php\PhpVersionProvider; use Rector\PHPStanStaticTypeMapper\Contract\TypeMapperInterface; -use Rector\PHPStanStaticTypeMapper\Enum\TypeKind; -use Rector\ValueObject\PhpVersion; /** * @implements TypeMapperInterface */ final readonly class VoidTypeMapper implements TypeMapperInterface { - private const string VOID = 'void'; - - public function __construct( - private PhpVersionProvider $phpVersionProvider - ) { - } - /** * @return array> */ @@ -41,21 +29,4 @@ public function mapToPHPStanPhpDocTypeNode(Type $type): TypeNode { return $type->toPhpDocNode(); } - - /** - * @param TypeKind::* $typeKind - * @param VoidType $type - */ - public function mapToPhpParserNode(Type $type, string $typeKind): ?Node - { - if (! $this->phpVersionProvider->isAtLeastPhpVersion(PhpVersion::PHP_71)) { - return null; - } - - if (in_array($typeKind, [TypeKind::PARAM, TypeKind::PROPERTY, TypeKind::UNION], true)) { - return null; - } - - return new Identifier(self::VOID); - } } diff --git a/src/StaticTypeMapper/StaticTypeMapper.php b/src/StaticTypeMapper/StaticTypeMapper.php index 98e9705766f..73b19b2222e 100644 --- a/src/StaticTypeMapper/StaticTypeMapper.php +++ b/src/StaticTypeMapper/StaticTypeMapper.php @@ -8,6 +8,7 @@ use PhpParser\Node\ComplexType; use PhpParser\Node\Identifier; use PhpParser\Node\Name; +use PHPStan\Php\PhpVersion; use PHPStan\PhpDocParser\Ast\PhpDoc\ParamTagValueNode; use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagValueNode; use PHPStan\PhpDocParser\Ast\PhpDoc\ReturnTagValueNode; @@ -15,9 +16,13 @@ use PHPStan\PhpDocParser\Ast\PhpDoc\ThrowsTagValueNode; use PHPStan\PhpDocParser\Ast\PhpDoc\VarTagValueNode; use PHPStan\PhpDocParser\Ast\Type\TypeNode; +use PHPStan\Type\BooleanType; use PHPStan\Type\MixedType; +use PHPStan\Type\NativeTypePosition; use PHPStan\Type\Type; +use PHPStan\Type\TypeTraverser; use Rector\Exception\NotImplementedYetException; +use Rector\Php\PhpVersionProvider; use Rector\PHPStanStaticTypeMapper\Enum\TypeKind; use Rector\PHPStanStaticTypeMapper\PHPStanStaticTypeMapper; use Rector\StaticTypeMapper\Mapper\PhpParserNodeMapper; @@ -34,7 +39,8 @@ public function __construct( private NameScopeFactory $nameScopeFactory, private PHPStanStaticTypeMapper $phpStanStaticTypeMapper, private PhpDocTypeMapper $phpDocTypeMapper, - private PhpParserNodeMapper $phpParserNodeMapper + private PhpParserNodeMapper $phpParserNodeMapper, + private PhpVersionProvider $phpVersionProvider ) { } @@ -45,11 +51,31 @@ public function mapPHPStanTypeToPHPStanPhpDocTypeNode(Type $phpStanType): TypeNo /** * @param TypeKind::* $typeKind - * @return Name|ComplexType|Identifier|null */ - public function mapPHPStanTypeToPhpParserNode(Type $phpStanType, string $typeKind): ?Node + public function mapPHPStanTypeToPhpParserNode(Type $phpStanType, string $typeKind): Name|ComplexType|Identifier|null { - return $this->phpStanStaticTypeMapper->mapToPhpParserNode($phpStanType, $typeKind); + if ($typeKind === TypeKind::PARAM) { + return $phpStanType->toNativePhpTypeNode(NativeTypePosition::parameter($this->getPhpVersion())); + } + + if ($typeKind === TypeKind::RETURN) { + return $phpStanType->toNativePhpTypeNode(NativeTypePosition::returnType($this->getPhpVersion())); + } + + // Rector policy: a property or constant holding only true, false or null is too narrow to be useful + if ($phpStanType->isNull()->yes()) { + return null; + } + + $phpStanType = TypeTraverser::map($phpStanType, static function (Type $type, callable $traverse): Type { + if ($type->isTrue()->yes() || $type->isFalse()->yes()) { + return new BooleanType(); + } + + return $traverse($type); + }); + + return $phpStanType->toNativePhpTypeNode(NativeTypePosition::property($this->getPhpVersion())); } public function mapPhpParserNodePHPStanType(Node $node): Type @@ -81,4 +107,9 @@ public function mapPHPStanPhpDocTypeNodeToPHPStanType(TypeNode $typeNode, Node $ $nameScope = $this->nameScopeFactory->createNameScopeFromNodeWithoutTemplateTypes($node); return $this->phpDocTypeMapper->mapToPHPStanType($typeNode, $node, $nameScope); } + + private function getPhpVersion(): PhpVersion + { + return new PhpVersion($this->phpVersionProvider->provide()); + } } diff --git a/src/StaticTypeMapper/ValueObject/Type/AliasedObjectType.php b/src/StaticTypeMapper/ValueObject/Type/AliasedObjectType.php index 30dddc4966a..6f3898b563a 100644 --- a/src/StaticTypeMapper/ValueObject/Type/AliasedObjectType.php +++ b/src/StaticTypeMapper/ValueObject/Type/AliasedObjectType.php @@ -5,10 +5,12 @@ namespace Rector\StaticTypeMapper\ValueObject\Type; use PhpParser\Node\Name; +use PhpParser\Node\Name\FullyQualified; use PhpParser\Node\Stmt\Use_; use PhpParser\Node\UseItem; use PHPStan\PhpDocParser\Ast\Type\RelativeNameNode; use PHPStan\PhpDocParser\Ast\Type\TypeNode; +use PHPStan\Type\NativeTypePosition; use PHPStan\Type\ObjectType; use PHPStan\Type\Type; use Rector\StaticTypeMapper\Resolver\ClassNameFromObjectTypeResolver; @@ -70,6 +72,11 @@ public function equals(Type $type): bool return parent::equals($type); } + public function toNativePhpTypeNode(NativeTypePosition $position): ?Name + { + return $position->isClassNameAllowed() ? new FullyQualified($this->fullyQualifiedClass) : null; + } + public function toPhpDocNode(): TypeNode { return new RelativeNameNode($this->getShortName()); diff --git a/src/StaticTypeMapper/ValueObject/Type/FullyQualifiedObjectType.php b/src/StaticTypeMapper/ValueObject/Type/FullyQualifiedObjectType.php index 88aaa413f1d..bd745af33e3 100644 --- a/src/StaticTypeMapper/ValueObject/Type/FullyQualifiedObjectType.php +++ b/src/StaticTypeMapper/ValueObject/Type/FullyQualifiedObjectType.php @@ -6,8 +6,10 @@ use Nette\Utils\Strings; use PhpParser\Node\Name; +use PhpParser\Node\Name\FullyQualified; use PhpParser\Node\Stmt\Use_; use PhpParser\Node\UseItem; +use PHPStan\Type\NativeTypePosition; use PHPStan\Type\ObjectType; use PHPStan\Type\Type; use Rector\NodeTypeResolver\Node\AttributeKey; @@ -77,4 +79,9 @@ public function equals(Type $type): bool return false; } + + public function toNativePhpTypeNode(NativeTypePosition $position): ?Name + { + return $position->isClassNameAllowed() ? new FullyQualified(ltrim($this->getClassName(), '\\')) : null; + } } diff --git a/src/StaticTypeMapper/ValueObject/Type/NonExistingObjectType.php b/src/StaticTypeMapper/ValueObject/Type/NonExistingObjectType.php index 8ea12223b31..18c1de9e7d9 100644 --- a/src/StaticTypeMapper/ValueObject/Type/NonExistingObjectType.php +++ b/src/StaticTypeMapper/ValueObject/Type/NonExistingObjectType.php @@ -4,8 +4,12 @@ namespace Rector\StaticTypeMapper\ValueObject\Type; +use PhpParser\Node\ComplexType; +use PhpParser\Node\Identifier; +use PhpParser\Node\Name; use PHPStan\PhpDocParser\Ast\Type\RelativeNameNode; use PHPStan\PhpDocParser\Ast\Type\TypeNode; +use PHPStan\Type\NativeTypePosition; use PHPStan\Type\ObjectType; use PHPStan\Type\Type; @@ -26,6 +30,11 @@ public function equals(Type $type): bool return false; } + public function toNativePhpTypeNode(NativeTypePosition $position): Identifier|Name|ComplexType|null + { + return null; + } + /** * printed as resolved by Rector, which keeps names written with a namespace as they are */ diff --git a/src/StaticTypeMapper/ValueObject/Type/ParentStaticType.php b/src/StaticTypeMapper/ValueObject/Type/ParentStaticType.php index ab95077abc7..bbc6a2d5fc2 100644 --- a/src/StaticTypeMapper/ValueObject/Type/ParentStaticType.php +++ b/src/StaticTypeMapper/ValueObject/Type/ParentStaticType.php @@ -4,8 +4,14 @@ namespace Rector\StaticTypeMapper\ValueObject\Type; +use PhpParser\Node\Name; +use PHPStan\Type\NativeTypePosition; use PHPStan\Type\StaticType; final class ParentStaticType extends StaticType { + public function toNativePhpTypeNode(NativeTypePosition $position): ?Name + { + return $position->isClassNameAllowed() ? new Name('parent') : null; + } } diff --git a/src/StaticTypeMapper/ValueObject/Type/SelfObjectType.php b/src/StaticTypeMapper/ValueObject/Type/SelfObjectType.php index 9a1c02cce22..1f61241f630 100644 --- a/src/StaticTypeMapper/ValueObject/Type/SelfObjectType.php +++ b/src/StaticTypeMapper/ValueObject/Type/SelfObjectType.php @@ -4,8 +4,14 @@ namespace Rector\StaticTypeMapper\ValueObject\Type; +use PhpParser\Node\Name; +use PHPStan\Type\NativeTypePosition; use PHPStan\Type\ObjectType; final class SelfObjectType extends ObjectType { + public function toNativePhpTypeNode(NativeTypePosition $position): ?Name + { + return $position->isClassNameAllowed() ? new Name('self') : null; + } } diff --git a/src/StaticTypeMapper/ValueObject/Type/SelfStaticType.php b/src/StaticTypeMapper/ValueObject/Type/SelfStaticType.php index d415523eb8f..f67ca5f13b0 100644 --- a/src/StaticTypeMapper/ValueObject/Type/SelfStaticType.php +++ b/src/StaticTypeMapper/ValueObject/Type/SelfStaticType.php @@ -4,8 +4,14 @@ namespace Rector\StaticTypeMapper\ValueObject\Type; +use PhpParser\Node\Name; +use PHPStan\Type\NativeTypePosition; use PHPStan\Type\ThisType; final class SelfStaticType extends ThisType { + public function toNativePhpTypeNode(NativeTypePosition $position): ?Name + { + return $position->isClassNameAllowed() ? new Name('self') : null; + } } diff --git a/src/StaticTypeMapper/ValueObject/Type/ShortenedObjectType.php b/src/StaticTypeMapper/ValueObject/Type/ShortenedObjectType.php index 820a62d6132..f40533edb48 100644 --- a/src/StaticTypeMapper/ValueObject/Type/ShortenedObjectType.php +++ b/src/StaticTypeMapper/ValueObject/Type/ShortenedObjectType.php @@ -4,9 +4,12 @@ namespace Rector\StaticTypeMapper\ValueObject\Type; +use PhpParser\Node\Name; +use PhpParser\Node\Name\FullyQualified; use PHPStan\PhpDocParser\Ast\Type\RelativeNameNode; use PHPStan\PhpDocParser\Ast\Type\TypeNode; use PHPStan\Type\IsSuperTypeOfResult; +use PHPStan\Type\NativeTypePosition; use PHPStan\Type\ObjectType; use PHPStan\Type\Type; @@ -59,6 +62,11 @@ public function equals(Type $type): bool return false; } + public function toNativePhpTypeNode(NativeTypePosition $position): ?Name + { + return $position->isClassNameAllowed() ? new FullyQualified($this->fullyQualifiedName) : null; + } + public function toPhpDocNode(): TypeNode { return new RelativeNameNode($this->getShortName()); diff --git a/tests/PHPStanStaticTypeMapper/TypeMapper/NonexistentParentClassTypeMapperTest.php b/tests/PHPStanStaticTypeMapper/TypeMapper/NonexistentParentClassTypeMapperTest.php index cd5c4100c1e..91f45df83fc 100644 --- a/tests/PHPStanStaticTypeMapper/TypeMapper/NonexistentParentClassTypeMapperTest.php +++ b/tests/PHPStanStaticTypeMapper/TypeMapper/NonexistentParentClassTypeMapperTest.php @@ -4,9 +4,7 @@ namespace Rector\Tests\PHPStanStaticTypeMapper\TypeMapper; -use PhpParser\Node\Name; use PHPStan\Type\NonexistentParentClassType; -use Rector\PHPStanStaticTypeMapper\Enum\TypeKind; use Rector\PHPStanStaticTypeMapper\PHPStanStaticTypeMapper; use Rector\Testing\PHPUnit\AbstractLazyTestCase; @@ -21,17 +19,6 @@ protected function setUp(): void $this->phpStanStaticTypeMapper = $this->make(PHPStanStaticTypeMapper::class); } - public function testMapToPhpParserNode(): void - { - $node = $this->phpStanStaticTypeMapper->mapToPhpParserNode( - new NonexistentParentClassType(), - TypeKind::RETURN - ); - - $this->assertInstanceOf(Name::class, $node); - $this->assertSame('parent', $node->toString()); - } - public function testMapToPHPStanPhpDocTypeNode(): void { $typeNode = $this->phpStanStaticTypeMapper->mapToPHPStanPhpDocTypeNode(new NonexistentParentClassType()); From dc6eb78e9a9c256858eb99f5083191844dc6edb5 Mon Sep 17 00:00:00 2001 From: "ondrej@mirtes.cz" Date: Wed, 28 Oct 2026 21:59:28 +0000 Subject: [PATCH 2/2] Use PHPStan Type::toPhpDocNode() instead of PHPStanStaticTypeMapper PHPStan now returns phpdoc-parser 2.4's FullyQualifiedNameNode for class names from Type::toPhpDocNode(), so Rector no longer needs its own mapToPHPStanPhpDocTypeNode() mappers to tell class names from keywords. The PHPStanStaticTypeMapper package is removed. StaticTypeMapper keeps Rector's docblock style (A|B, A[], plain int) on top of toPhpDocNode(). Rector's shortened and aliased object types return a RelativeNameNode. The name importing and class renaming PHPDoc visitors also handle name nodes, and code reading the name of a generic or callable type node no longer assumes an IdentifierTypeNode. Amp-Thread-ID: https://ampcode.com/threads/T-01a179f2-995f-7745-8d8c-4c174ba5c0ce --- .../Fixture/different_usage.php.inc | 2 +- .../with_array_filter_and_array_walk.php.inc | 2 +- .../Fixture/Nesting/complex_array.php.inc | 2 +- .../Fixture/Nesting/not_too_complex.php.inc | 2 +- .../Fixture/covert-implicit-key.php.inc | 2 +- .../Fixture/covert-object-return.php.inc | 2 +- .../Fixture/repeated_item_type.php.inc | 2 +- .../with_duplicated_nested_array.php.inc | 2 +- .../Fixture/cover_mixed_and_known.php.inc | 2 +- .../multiple_calls_with_various_types.php.inc | 2 +- .../Fixture/union_objects.php.inc | 2 +- .../Fixture/unique_types.php.inc | 2 +- .../array_union_generic_same_type.php.inc | 2 +- .../Fixture/int_key_inside.php.inc | 4 +- .../NodeTypeAnalyzer/DetailedTypeAnalyzer.php | 45 --- .../GenericClassStringTypeNormalizer.php | 17 -- .../LazyContainerFactory.php | 24 -- .../Contract/TypeMapperInterface.php | 27 -- .../PHPStanStaticTypeMapper.php | 60 ---- .../TypeMapper/AccessoryArrayTypeMapper.php | 39 --- .../TypeMapper/AccessoryStringTypeMapper.php | 39 --- .../TypeMapper/ArrayTypeMapper.php | 288 ------------------ .../TypeMapper/BooleanTypeMapper.php | 32 -- .../TypeMapper/CallableTypeMapper.php | 32 -- .../TypeMapper/ClassStringTypeMapper.php | 48 --- .../TypeMapper/ClosureTypeMapper.php | 54 ---- .../ConditionalTypeForParameterMapper.php | 32 -- .../TypeMapper/ConditionalTypeMapper.php | 45 --- .../TypeMapper/ConstantArrayTypeMapper.php | 32 -- .../TypeMapper/FloatTypeMapper.php | 32 -- .../TypeMapper/HasMethodTypeMapper.php | 32 -- .../TypeMapper/HasPropertyTypeMapper.php | 32 -- .../TypeMapper/IntegerTypeMapper.php | 33 -- .../TypeMapper/IntersectionTypeMapper.php | 84 ----- .../TypeMapper/IterableTypeMapper.php | 32 -- .../TypeMapper/MixedTypeMapper.php | 32 -- .../TypeMapper/NeverTypeMapper.php | 32 -- .../NonexistentParentClassTypeMapper.php | 37 --- .../TypeMapper/NullTypeMapper.php | 32 -- .../TypeMapper/ObjectTypeMapper.php | 64 ---- .../ObjectWithoutClassTypeMapper.php | 32 -- .../TypeMapper/ParentStaticTypeMapper.php | 32 -- .../TypeMapper/ResourceTypeMapper.php | 32 -- .../TypeMapper/StaticTypeMapper.php | 34 --- .../TypeMapper/StrictMixedTypeMapper.php | 32 -- .../TypeMapper/StringTypeMapper.php | 32 -- .../TypeWithClassNameTypeMapper.php | 32 -- .../TypeMapper/UnionTypeMapper.php | 61 ---- .../TypeMapper/VoidTypeMapper.php | 32 -- src/StaticTypeMapper/StaticTypeMapper.php | 101 +++++- ...FullyQualifiedIdentifierDocblockRector.php | 4 +- .../TypeMapper/ArrayTypeMapperTest.php | 94 ------ .../NonexistentParentClassTypeMapperTest.php | 27 -- .../TypeMapperOrderTest.php | 38 --- 54 files changed, 115 insertions(+), 1754 deletions(-) delete mode 100644 rules/TypeDeclaration/NodeTypeAnalyzer/DetailedTypeAnalyzer.php delete mode 100644 rules/TypeDeclaration/TypeAnalyzer/GenericClassStringTypeNormalizer.php delete mode 100644 src/PHPStanStaticTypeMapper/Contract/TypeMapperInterface.php delete mode 100644 src/PHPStanStaticTypeMapper/PHPStanStaticTypeMapper.php delete mode 100644 src/PHPStanStaticTypeMapper/TypeMapper/AccessoryArrayTypeMapper.php delete mode 100644 src/PHPStanStaticTypeMapper/TypeMapper/AccessoryStringTypeMapper.php delete mode 100644 src/PHPStanStaticTypeMapper/TypeMapper/ArrayTypeMapper.php delete mode 100644 src/PHPStanStaticTypeMapper/TypeMapper/BooleanTypeMapper.php delete mode 100644 src/PHPStanStaticTypeMapper/TypeMapper/CallableTypeMapper.php delete mode 100644 src/PHPStanStaticTypeMapper/TypeMapper/ClassStringTypeMapper.php delete mode 100644 src/PHPStanStaticTypeMapper/TypeMapper/ClosureTypeMapper.php delete mode 100644 src/PHPStanStaticTypeMapper/TypeMapper/ConditionalTypeForParameterMapper.php delete mode 100644 src/PHPStanStaticTypeMapper/TypeMapper/ConditionalTypeMapper.php delete mode 100644 src/PHPStanStaticTypeMapper/TypeMapper/ConstantArrayTypeMapper.php delete mode 100644 src/PHPStanStaticTypeMapper/TypeMapper/FloatTypeMapper.php delete mode 100644 src/PHPStanStaticTypeMapper/TypeMapper/HasMethodTypeMapper.php delete mode 100644 src/PHPStanStaticTypeMapper/TypeMapper/HasPropertyTypeMapper.php delete mode 100644 src/PHPStanStaticTypeMapper/TypeMapper/IntegerTypeMapper.php delete mode 100644 src/PHPStanStaticTypeMapper/TypeMapper/IntersectionTypeMapper.php delete mode 100644 src/PHPStanStaticTypeMapper/TypeMapper/IterableTypeMapper.php delete mode 100644 src/PHPStanStaticTypeMapper/TypeMapper/MixedTypeMapper.php delete mode 100644 src/PHPStanStaticTypeMapper/TypeMapper/NeverTypeMapper.php delete mode 100644 src/PHPStanStaticTypeMapper/TypeMapper/NonexistentParentClassTypeMapper.php delete mode 100644 src/PHPStanStaticTypeMapper/TypeMapper/NullTypeMapper.php delete mode 100644 src/PHPStanStaticTypeMapper/TypeMapper/ObjectTypeMapper.php delete mode 100644 src/PHPStanStaticTypeMapper/TypeMapper/ObjectWithoutClassTypeMapper.php delete mode 100644 src/PHPStanStaticTypeMapper/TypeMapper/ParentStaticTypeMapper.php delete mode 100644 src/PHPStanStaticTypeMapper/TypeMapper/ResourceTypeMapper.php delete mode 100644 src/PHPStanStaticTypeMapper/TypeMapper/StaticTypeMapper.php delete mode 100644 src/PHPStanStaticTypeMapper/TypeMapper/StrictMixedTypeMapper.php delete mode 100644 src/PHPStanStaticTypeMapper/TypeMapper/StringTypeMapper.php delete mode 100644 src/PHPStanStaticTypeMapper/TypeMapper/TypeWithClassNameTypeMapper.php delete mode 100644 src/PHPStanStaticTypeMapper/TypeMapper/UnionTypeMapper.php delete mode 100644 src/PHPStanStaticTypeMapper/TypeMapper/VoidTypeMapper.php delete mode 100644 tests/PHPStanStaticTypeMapper/TypeMapper/ArrayTypeMapperTest.php delete mode 100644 tests/PHPStanStaticTypeMapper/TypeMapper/NonexistentParentClassTypeMapperTest.php delete mode 100644 tests/PHPStanStaticTypeMapper/TypeMapperOrderTest.php diff --git a/rules-tests/TypeDeclaration/Rector/ClassMethod/AddParamArrayDocblockBasedOnCallableNativeFuncCallRector/Fixture/different_usage.php.inc b/rules-tests/TypeDeclaration/Rector/ClassMethod/AddParamArrayDocblockBasedOnCallableNativeFuncCallRector/Fixture/different_usage.php.inc index 4e77ccb4457..b71a4c09674 100644 --- a/rules-tests/TypeDeclaration/Rector/ClassMethod/AddParamArrayDocblockBasedOnCallableNativeFuncCallRector/Fixture/different_usage.php.inc +++ b/rules-tests/TypeDeclaration/Rector/ClassMethod/AddParamArrayDocblockBasedOnCallableNativeFuncCallRector/Fixture/different_usage.php.inc @@ -33,7 +33,7 @@ use stdClass; final class DifferentUsage { /** - * @param \stdClass[]|\DateTime[] $items + * @param \DateTime[]|\stdClass[] $items */ public function process(array $items): void { diff --git a/rules-tests/TypeDeclaration/Rector/ClassMethod/AddParamArrayDocblockBasedOnCallableNativeFuncCallRector/Fixture/with_array_filter_and_array_walk.php.inc b/rules-tests/TypeDeclaration/Rector/ClassMethod/AddParamArrayDocblockBasedOnCallableNativeFuncCallRector/Fixture/with_array_filter_and_array_walk.php.inc index cdd7a0e2d49..0e4f6379507 100644 --- a/rules-tests/TypeDeclaration/Rector/ClassMethod/AddParamArrayDocblockBasedOnCallableNativeFuncCallRector/Fixture/with_array_filter_and_array_walk.php.inc +++ b/rules-tests/TypeDeclaration/Rector/ClassMethod/AddParamArrayDocblockBasedOnCallableNativeFuncCallRector/Fixture/with_array_filter_and_array_walk.php.inc @@ -33,7 +33,7 @@ use stdClass; final class WithArrayFilterAndArrayWalk { /** - * @param string[]|\stdClass[] $items + * @param \stdClass[]|string[] $items */ public function process(array $items): void { diff --git a/rules-tests/TypeDeclarationDocblocks/Rector/ClassMethod/DocblockReturnArrayFromDirectArrayInstanceRector/Fixture/Nesting/complex_array.php.inc b/rules-tests/TypeDeclarationDocblocks/Rector/ClassMethod/DocblockReturnArrayFromDirectArrayInstanceRector/Fixture/Nesting/complex_array.php.inc index eb21f0e1aaf..67b8e55950c 100644 --- a/rules-tests/TypeDeclarationDocblocks/Rector/ClassMethod/DocblockReturnArrayFromDirectArrayInstanceRector/Fixture/Nesting/complex_array.php.inc +++ b/rules-tests/TypeDeclarationDocblocks/Rector/ClassMethod/DocblockReturnArrayFromDirectArrayInstanceRector/Fixture/Nesting/complex_array.php.inc @@ -36,7 +36,7 @@ namespace Rector\Tests\TypeDeclarationDocblocks\Rector\ClassMethod\DocblockRetur class ComplexArray { /** - * @return array>|array|bool> + * @return array|int|string>|bool> */ public function run(): array { diff --git a/rules-tests/TypeDeclarationDocblocks/Rector/ClassMethod/DocblockReturnArrayFromDirectArrayInstanceRector/Fixture/Nesting/not_too_complex.php.inc b/rules-tests/TypeDeclarationDocblocks/Rector/ClassMethod/DocblockReturnArrayFromDirectArrayInstanceRector/Fixture/Nesting/not_too_complex.php.inc index 20f86cb5131..bf28bd4a243 100644 --- a/rules-tests/TypeDeclarationDocblocks/Rector/ClassMethod/DocblockReturnArrayFromDirectArrayInstanceRector/Fixture/Nesting/not_too_complex.php.inc +++ b/rules-tests/TypeDeclarationDocblocks/Rector/ClassMethod/DocblockReturnArrayFromDirectArrayInstanceRector/Fixture/Nesting/not_too_complex.php.inc @@ -26,7 +26,7 @@ namespace Rector\Tests\TypeDeclarationDocblocks\Rector\ClassMethod\DocblockRetur final class AvoidExtremeNesting { /** - * @return array + * @return array */ public function run(): array { diff --git a/rules-tests/TypeDeclarationDocblocks/Rector/ClassMethod/DocblockReturnArrayFromDirectArrayInstanceRector/Fixture/covert-implicit-key.php.inc b/rules-tests/TypeDeclarationDocblocks/Rector/ClassMethod/DocblockReturnArrayFromDirectArrayInstanceRector/Fixture/covert-implicit-key.php.inc index 6efd75479a4..d8194433e41 100644 --- a/rules-tests/TypeDeclarationDocblocks/Rector/ClassMethod/DocblockReturnArrayFromDirectArrayInstanceRector/Fixture/covert-implicit-key.php.inc +++ b/rules-tests/TypeDeclarationDocblocks/Rector/ClassMethod/DocblockReturnArrayFromDirectArrayInstanceRector/Fixture/covert-implicit-key.php.inc @@ -28,7 +28,7 @@ namespace Rector\Tests\TypeDeclarationDocblocks\Rector\ClassMethod\DocblockRetur final class CoverImplicitKey { /** - * @return array> + * @return array> */ private static function getExpectedAllOwners(): array { diff --git a/rules-tests/TypeDeclarationDocblocks/Rector/ClassMethod/DocblockReturnArrayFromDirectArrayInstanceRector/Fixture/covert-object-return.php.inc b/rules-tests/TypeDeclarationDocblocks/Rector/ClassMethod/DocblockReturnArrayFromDirectArrayInstanceRector/Fixture/covert-object-return.php.inc index 63ca0a557a4..671c48ba721 100644 --- a/rules-tests/TypeDeclarationDocblocks/Rector/ClassMethod/DocblockReturnArrayFromDirectArrayInstanceRector/Fixture/covert-object-return.php.inc +++ b/rules-tests/TypeDeclarationDocblocks/Rector/ClassMethod/DocblockReturnArrayFromDirectArrayInstanceRector/Fixture/covert-object-return.php.inc @@ -26,7 +26,7 @@ final class CoverObjectReturn private ?\Rector\Tests\TypeDeclarationDocblocks\Rector\ClassMethod\DocblockReturnArrayFromDirectArrayInstanceRector\Source\SomeObjectInDirectArray $item = null; /** - * @return array + * @return array */ public function toArray(): array { diff --git a/rules-tests/TypeDeclarationDocblocks/Rector/ClassMethod/DocblockReturnArrayFromDirectArrayInstanceRector/Fixture/repeated_item_type.php.inc b/rules-tests/TypeDeclarationDocblocks/Rector/ClassMethod/DocblockReturnArrayFromDirectArrayInstanceRector/Fixture/repeated_item_type.php.inc index 6dc7d5caf9b..9ac3c15f517 100644 --- a/rules-tests/TypeDeclarationDocblocks/Rector/ClassMethod/DocblockReturnArrayFromDirectArrayInstanceRector/Fixture/repeated_item_type.php.inc +++ b/rules-tests/TypeDeclarationDocblocks/Rector/ClassMethod/DocblockReturnArrayFromDirectArrayInstanceRector/Fixture/repeated_item_type.php.inc @@ -44,7 +44,7 @@ final class RepeatedItemType ) {} /** - * @return array> + * @return array|string> */ public function toRequestPayload(): array { diff --git a/rules-tests/TypeDeclarationDocblocks/Rector/ClassMethod/DocblockReturnArrayFromDirectArrayInstanceRector/Fixture/with_duplicated_nested_array.php.inc b/rules-tests/TypeDeclarationDocblocks/Rector/ClassMethod/DocblockReturnArrayFromDirectArrayInstanceRector/Fixture/with_duplicated_nested_array.php.inc index aa21e75ba02..63242d692e1 100644 --- a/rules-tests/TypeDeclarationDocblocks/Rector/ClassMethod/DocblockReturnArrayFromDirectArrayInstanceRector/Fixture/with_duplicated_nested_array.php.inc +++ b/rules-tests/TypeDeclarationDocblocks/Rector/ClassMethod/DocblockReturnArrayFromDirectArrayInstanceRector/Fixture/with_duplicated_nested_array.php.inc @@ -34,7 +34,7 @@ namespace Rector\Tests\TypeDeclarationDocblocks\Rector\ClassMethod\DocblockRetur final class WithDuplicatedNestedArray { /** - * @return array + * @return array */ public static function run(): iterable { diff --git a/rules-tests/TypeDeclarationDocblocks/Rector/Class_/ClassMethodArrayDocblockParamFromLocalCallsRector/Fixture/cover_mixed_and_known.php.inc b/rules-tests/TypeDeclarationDocblocks/Rector/Class_/ClassMethodArrayDocblockParamFromLocalCallsRector/Fixture/cover_mixed_and_known.php.inc index 01833c54588..e926b0c003c 100644 --- a/rules-tests/TypeDeclarationDocblocks/Rector/Class_/ClassMethodArrayDocblockParamFromLocalCallsRector/Fixture/cover_mixed_and_known.php.inc +++ b/rules-tests/TypeDeclarationDocblocks/Rector/Class_/ClassMethodArrayDocblockParamFromLocalCallsRector/Fixture/cover_mixed_and_known.php.inc @@ -32,7 +32,7 @@ final class CoverMixedAndKnown } /** - * @param string[]|mixed[] $items + * @param mixed[] $items */ private function run(array $items) { diff --git a/rules-tests/TypeDeclarationDocblocks/Rector/Class_/ClassMethodArrayDocblockParamFromLocalCallsRector/Fixture/multiple_calls_with_various_types.php.inc b/rules-tests/TypeDeclarationDocblocks/Rector/Class_/ClassMethodArrayDocblockParamFromLocalCallsRector/Fixture/multiple_calls_with_various_types.php.inc index 7515deb7f05..215392d4343 100644 --- a/rules-tests/TypeDeclarationDocblocks/Rector/Class_/ClassMethodArrayDocblockParamFromLocalCallsRector/Fixture/multiple_calls_with_various_types.php.inc +++ b/rules-tests/TypeDeclarationDocblocks/Rector/Class_/ClassMethodArrayDocblockParamFromLocalCallsRector/Fixture/multiple_calls_with_various_types.php.inc @@ -30,7 +30,7 @@ final class MultipleCallsWithVariousTypes } /** - * @param string[]|int[] $items + * @param int[]|string[] $items */ private function run(array $items) { diff --git a/rules-tests/TypeDeclarationDocblocks/Rector/Class_/ClassMethodArrayDocblockParamFromLocalCallsRector/Fixture/union_objects.php.inc b/rules-tests/TypeDeclarationDocblocks/Rector/Class_/ClassMethodArrayDocblockParamFromLocalCallsRector/Fixture/union_objects.php.inc index 100062d9b76..b2f8dd0b917 100644 --- a/rules-tests/TypeDeclarationDocblocks/Rector/Class_/ClassMethodArrayDocblockParamFromLocalCallsRector/Fixture/union_objects.php.inc +++ b/rules-tests/TypeDeclarationDocblocks/Rector/Class_/ClassMethodArrayDocblockParamFromLocalCallsRector/Fixture/union_objects.php.inc @@ -42,7 +42,7 @@ final class UnionObjects } /** - * @param \Rector\Tests\TypeDeclarationDocblocks\Rector\Class_\ClassMethodArrayDocblockParamFromLocalCallsRector\Source\SomeReturnedObject[]|\Rector\Tests\TypeDeclarationDocblocks\Rector\Class_\ClassMethodArrayDocblockParamFromLocalCallsRector\Source\AnotherReturnedObject[] $items + * @param \Rector\Tests\TypeDeclarationDocblocks\Rector\Class_\ClassMethodArrayDocblockParamFromLocalCallsRector\Source\AnotherReturnedObject[]|\Rector\Tests\TypeDeclarationDocblocks\Rector\Class_\ClassMethodArrayDocblockParamFromLocalCallsRector\Source\SomeReturnedObject[] $items */ private function run(array $items) { diff --git a/rules-tests/TypeDeclarationDocblocks/Rector/Class_/ClassMethodArrayDocblockParamFromLocalCallsRector/Fixture/unique_types.php.inc b/rules-tests/TypeDeclarationDocblocks/Rector/Class_/ClassMethodArrayDocblockParamFromLocalCallsRector/Fixture/unique_types.php.inc index 8db2d62a7db..1bb09f15c69 100644 --- a/rules-tests/TypeDeclarationDocblocks/Rector/Class_/ClassMethodArrayDocblockParamFromLocalCallsRector/Fixture/unique_types.php.inc +++ b/rules-tests/TypeDeclarationDocblocks/Rector/Class_/ClassMethodArrayDocblockParamFromLocalCallsRector/Fixture/unique_types.php.inc @@ -32,7 +32,7 @@ class UniqueTypes } /** - * @param string[]|int[] $items + * @param int[]|string[] $items */ private function run(array $items) { 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 index 5167555baf3..18e27679cd1 100644 --- 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 @@ -25,7 +25,7 @@ use stdClass; class ArrayUnionGenericSameType { /** - * @var array|class-string<\DateTime>> + * @var array|class-string<\stdClass>> */ private array $dependencies = [ stdClass::class, diff --git a/rules-tests/TypeDeclarationDocblocks/Rector/Class_/DocblockVarArrayFromPropertyDefaultsRector/Fixture/int_key_inside.php.inc b/rules-tests/TypeDeclarationDocblocks/Rector/Class_/DocblockVarArrayFromPropertyDefaultsRector/Fixture/int_key_inside.php.inc index 5c16a52841d..b548d0e2851 100644 --- a/rules-tests/TypeDeclarationDocblocks/Rector/Class_/DocblockVarArrayFromPropertyDefaultsRector/Fixture/int_key_inside.php.inc +++ b/rules-tests/TypeDeclarationDocblocks/Rector/Class_/DocblockVarArrayFromPropertyDefaultsRector/Fixture/int_key_inside.php.inc @@ -23,7 +23,7 @@ namespace Rector\Tests\TypeDeclarationDocblocks\Rector\Class_\DocblockVarArrayFr final class IntKeyInside { /** - * @var array>>> + * @var array>>> */ private array $array = [ 'a' => [ @@ -35,4 +35,4 @@ final class IntKeyInside ]; } -?> \ No newline at end of file +?> diff --git a/rules/TypeDeclaration/NodeTypeAnalyzer/DetailedTypeAnalyzer.php b/rules/TypeDeclaration/NodeTypeAnalyzer/DetailedTypeAnalyzer.php deleted file mode 100644 index d44fa1ce1bc..00000000000 --- a/rules/TypeDeclaration/NodeTypeAnalyzer/DetailedTypeAnalyzer.php +++ /dev/null @@ -1,45 +0,0 @@ -getTypes()) > self::MAX_NUMBER_OF_TYPES; - } - - if ($type instanceof ConstantArrayType) { - return count($type->getValueTypes()) > self::MAX_NUMBER_OF_TYPES; - } - - if ($type instanceof GenericObjectType) { - return $this->isTooDetailedGenericObjectType($type); - } - - return false; - } - - private function isTooDetailedGenericObjectType(GenericObjectType $genericObjectType): bool - { - if (count($genericObjectType->getTypes()) !== 1) { - return false; - } - - $genericType = $genericObjectType->getTypes()[0]; - return $this->isTooDetailed($genericType); - } -} diff --git a/rules/TypeDeclaration/TypeAnalyzer/GenericClassStringTypeNormalizer.php b/rules/TypeDeclaration/TypeAnalyzer/GenericClassStringTypeNormalizer.php deleted file mode 100644 index 72d8f123bda..00000000000 --- a/rules/TypeDeclaration/TypeAnalyzer/GenericClassStringTypeNormalizer.php +++ /dev/null @@ -1,17 +0,0 @@ -getTypes(), fn (Type $type): bool => $type instanceof GenericClassStringType); - } -} diff --git a/src/DependencyInjection/LazyContainerFactory.php b/src/DependencyInjection/LazyContainerFactory.php index 592e142d756..e6e5a1590e0 100644 --- a/src/DependencyInjection/LazyContainerFactory.php +++ b/src/DependencyInjection/LazyContainerFactory.php @@ -55,9 +55,6 @@ use Rector\PhpParser\NodeVisitor\LocalVariableScopeNodeVisitor; use Rector\PhpParser\NodeVisitor\NameAndArgNodeVisitor; use Rector\PhpParser\NodeVisitor\PhpVersionConditionNodeVisitor; -use Rector\PHPStanStaticTypeMapper\PHPStanStaticTypeMapper; -use Rector\PHPStanStaticTypeMapper\TypeMapper\ArrayTypeMapper; -use Rector\PHPStanStaticTypeMapper\TypeMapper\UnionTypeMapper; use Rector\PostRector\Application\PostFileProcessor; use Rector\Rector\AbstractRector; use Symfony\Component\Console\Application; @@ -102,7 +99,6 @@ public function create(): RectorConfig $this->registerConsole($rectorConfig); $this->registerFileProcessing($rectorConfig); $this->registerCachingAndResettables($rectorConfig); - $this->registerTypeMappers($rectorConfig); $this->registerNodeNameResolvers($rectorConfig); $this->registerRectorAutowiring($rectorConfig); $this->registerTaggedServices($rectorConfig); @@ -165,25 +161,6 @@ private function registerCachingAndResettables(RectorConfig $rectorConfig): void }); } - private function registerTypeMappers(RectorConfig $rectorConfig): void - { - // tagged services - $rectorConfig->afterResolving( - ArrayTypeMapper::class, - static function (ArrayTypeMapper $arrayTypeMapper) use ($rectorConfig): void { - $arrayTypeMapper->autowire($rectorConfig->make(PHPStanStaticTypeMapper::class)); - } - ); - - $rectorConfig->afterResolving( - UnionTypeMapper::class, - static function (UnionTypeMapper $unionTypeMapper) use ($rectorConfig): void { - $phpStanStaticTypeMapper = $rectorConfig->make(PHPStanStaticTypeMapper::class); - $unionTypeMapper->autowire($phpStanStaticTypeMapper); - } - ); - } - private function registerNodeNameResolvers(RectorConfig $rectorConfig): void { // node name resolvers @@ -216,7 +193,6 @@ private function registerTaggedServices(RectorConfig $rectorConfig): void // PHP 8.0 attributes $rectorConfig->autodiscover(__DIR__ . '/../PhpAttribute/AnnotationToAttributeMapper'); - $rectorConfig->autodiscover(__DIR__ . '/../PHPStanStaticTypeMapper/TypeMapper'); $rectorConfig->autodiscover(__DIR__ . '/../StaticTypeMapper/PhpDocParser'); $rectorConfig->autodiscover(__DIR__ . '/../NodeNameResolver/NodeNameResolver'); $rectorConfig->autodiscover(__DIR__ . '/../NodeTypeResolver/NodeTypeResolver'); diff --git a/src/PHPStanStaticTypeMapper/Contract/TypeMapperInterface.php b/src/PHPStanStaticTypeMapper/Contract/TypeMapperInterface.php deleted file mode 100644 index 5650bee33c0..00000000000 --- a/src/PHPStanStaticTypeMapper/Contract/TypeMapperInterface.php +++ /dev/null @@ -1,27 +0,0 @@ -> - */ - public function getNodeClasses(): array; - - /** - * @param TType $type - */ - public function mapToPHPStanPhpDocTypeNode(Type $type): TypeNode; -} diff --git a/src/PHPStanStaticTypeMapper/PHPStanStaticTypeMapper.php b/src/PHPStanStaticTypeMapper/PHPStanStaticTypeMapper.php deleted file mode 100644 index 9d654319099..00000000000 --- a/src/PHPStanStaticTypeMapper/PHPStanStaticTypeMapper.php +++ /dev/null @@ -1,60 +0,0 @@ -matchTypeMapper($type); - if (! $typeMapper instanceof TypeMapperInterface) { - throw new NotImplementedYetException(__METHOD__ . ' for ' . $type::class); - } - - return $typeMapper->mapToPHPStanPhpDocTypeNode($type); - } - - /** - * Match the most specific mapper: when a type is handled by both a mapper for a parent - * class and one for its subclass, the subclass mapper wins, regardless of registration order. - * - * @return TypeMapperInterface|null - */ - private function matchTypeMapper(Type $type): ?TypeMapperInterface - { - $matchedTypeMapper = null; - $matchedNodeClass = null; - - foreach ($this->typeMappers as $typeMapper) { - foreach ($typeMapper->getNodeClasses() as $nodeClass) { - if (! $type instanceof $nodeClass) { - continue; - } - - if ($matchedNodeClass === null || is_a($nodeClass, $matchedNodeClass, true)) { - $matchedNodeClass = $nodeClass; - $matchedTypeMapper = $typeMapper; - } - } - } - - return $matchedTypeMapper; - } -} diff --git a/src/PHPStanStaticTypeMapper/TypeMapper/AccessoryArrayTypeMapper.php b/src/PHPStanStaticTypeMapper/TypeMapper/AccessoryArrayTypeMapper.php deleted file mode 100644 index bc098fa8b8d..00000000000 --- a/src/PHPStanStaticTypeMapper/TypeMapper/AccessoryArrayTypeMapper.php +++ /dev/null @@ -1,39 +0,0 @@ - - */ -final class AccessoryArrayTypeMapper implements TypeMapperInterface -{ - /** - * @return array> - */ - public function getNodeClasses(): array - { - return [ - HasOffsetType::class, - HasOffsetValueType::class, - NonEmptyArrayType::class, - OversizedArrayType::class, - ]; - } - - public function mapToPHPStanPhpDocTypeNode(Type $type): TypeNode - { - return $type->toPhpDocNode(); - } -} diff --git a/src/PHPStanStaticTypeMapper/TypeMapper/AccessoryStringTypeMapper.php b/src/PHPStanStaticTypeMapper/TypeMapper/AccessoryStringTypeMapper.php deleted file mode 100644 index 59d401d111e..00000000000 --- a/src/PHPStanStaticTypeMapper/TypeMapper/AccessoryStringTypeMapper.php +++ /dev/null @@ -1,39 +0,0 @@ - - */ -final readonly class AccessoryStringTypeMapper implements TypeMapperInterface -{ - /** - * @return array> - */ - public function getNodeClasses(): array - { - return [ - AccessoryLiteralStringType::class, - AccessoryNonEmptyStringType::class, - AccessoryNonFalsyStringType::class, - AccessoryNumericStringType::class, - ]; - } - - public function mapToPHPStanPhpDocTypeNode(Type $type): TypeNode - { - return $type->toPhpDocNode(); - } -} diff --git a/src/PHPStanStaticTypeMapper/TypeMapper/ArrayTypeMapper.php b/src/PHPStanStaticTypeMapper/TypeMapper/ArrayTypeMapper.php deleted file mode 100644 index 06a079317b1..00000000000 --- a/src/PHPStanStaticTypeMapper/TypeMapper/ArrayTypeMapper.php +++ /dev/null @@ -1,288 +0,0 @@ - - */ -final class ArrayTypeMapper implements TypeMapperInterface -{ - private PHPStanStaticTypeMapper $phpStanStaticTypeMapper; - - public function __construct( - private readonly GenericClassStringTypeNormalizer $genericClassStringTypeNormalizer, - private readonly DetailedTypeAnalyzer $detailedTypeAnalyzer - ) { - } - - // To avoid circular dependency - - public function autowire(PHPStanStaticTypeMapper $phpStanStaticTypeMapper): void - { - $this->phpStanStaticTypeMapper = $phpStanStaticTypeMapper; - } - - /** - * @return array> - */ - public function getNodeClasses(): array - { - return [ArrayType::class]; - } - - /** - * @param ArrayType $type - */ - public function mapToPHPStanPhpDocTypeNode(Type $type): TypeNode - { - return $this->splitUnionItemType($this->createArrayTypeNode($type)); - } - - /** - * Returns "(A|B)[]" as is, the union item type is split later - */ - private function createArrayTypeNode(ArrayType $type): TypeNode - { - // this cannot be handled by PHPStan $type->toPhpDocNode() as requires space removal around "|" in union type - // then e.g. "int" instead of explicit number, and nice arrays - $itemType = $type->getIterableValueType(); - - $isGenericArray = $this->isGenericArrayCandidate($type); - - if ($itemType instanceof UnionType && ! $isGenericArray) { - return $this->createArrayTypeNodeFromUnionType($itemType); - } - - if ($itemType instanceof ArrayType && $this->isGenericArrayCandidate($itemType)) { - return $this->createGenericArrayType($type, true); - } - - if ($isGenericArray) { - return $this->createGenericArrayType($type, true); - } - - // keep "int" key in arary - if ($type->getKeyType() instanceof IntegerType) { - $keyTypeNode = $this->phpStanStaticTypeMapper->mapToPHPStanPhpDocTypeNode($type->getKeyType()); - - if (! $type->isList()->maybe()) { - $nestedTypeNode = $this->phpStanStaticTypeMapper->mapToPHPStanPhpDocTypeNode($type->getItemType()); - - return new GenericTypeNode(new IdentifierTypeNode('array'), [$keyTypeNode, $nestedTypeNode]); - } - } - - $itemTypeNode = $this->phpStanStaticTypeMapper->mapToPHPStanPhpDocTypeNode($itemType); - return new ArrayTypeNode($itemTypeNode); - } - - /** - * "(A|B)[]" becomes "A[]|B[]", or "array|A>" when all items are generics of the same type - */ - private function splitUnionItemType(TypeNode $typeNode): TypeNode - { - if (! $typeNode instanceof ArrayTypeNode || ! $typeNode->type instanceof UnionTypeNode) { - return $typeNode; - } - - $unionTypeNode = $typeNode->type; - if ($this->hasOnlySameGenericTypes($unionTypeNode)) { - return new GenericTypeNode(new IdentifierTypeNode('array'), [ - new IdentifierTypeNode('int'), - $unionTypeNode, - ]); - } - - $arrayTypeNodes = []; - foreach ($unionTypeNode->types as $unionedTypeNode) { - $arrayTypeNodes[] = new ArrayTypeNode($unionedTypeNode); - } - - return new UnionTypeNode($arrayTypeNodes); - } - - private function hasOnlySameGenericTypes(UnionTypeNode $unionTypeNode): bool - { - $genericTypeName = null; - - foreach ($unionTypeNode->types as $unionedTypeNode) { - if (! $unionedTypeNode instanceof GenericTypeNode) { - return false; - } - - if (count($unionedTypeNode->genericTypes) !== 1) { - return false; - } - - if (! $unionedTypeNode->type instanceof IdentifierTypeNode) { - return false; - } - - $genericTypeName ??= $unionedTypeNode->type->name; - if ($genericTypeName !== $unionedTypeNode->type->name) { - return false; - } - } - - return true; - } - - /** - * Value type in "array" uses "array" instead of "A[]|B[]" - */ - private function createGenericArrayValueTypeNode(Type $itemType): TypeNode - { - if (! $itemType instanceof ArrayType) { - return $this->phpStanStaticTypeMapper->mapToPHPStanPhpDocTypeNode($itemType); - } - - $arrayTypeNode = $this->createArrayTypeNode($itemType); - if ($arrayTypeNode instanceof ArrayTypeNode - && ($arrayTypeNode->type instanceof UnionTypeNode || $arrayTypeNode->type instanceof ArrayTypeNode)) { - return new GenericTypeNode(new IdentifierTypeNode('array'), [$arrayTypeNode->type]); - } - - return $this->splitUnionItemType($arrayTypeNode); - } - - private function createArrayTypeNodeFromUnionType(UnionType $unionType): ArrayTypeNode - { - $unionedArrayType = []; - foreach ($unionType->getTypes() as $unionedType) { - $typeNode = $this->phpStanStaticTypeMapper->mapToPHPStanPhpDocTypeNode($unionedType); - $unionedArrayType[(string) $typeNode] = $typeNode; - } - - if (count($unionedArrayType) > 1) { - return new ArrayTypeNode(new UnionTypeNode($unionedArrayType)); - } - - /** @var TypeNode $arrayType */ - $arrayType = array_shift($unionedArrayType); - return new ArrayTypeNode($arrayType); - } - - private function isGenericArrayCandidate(ArrayType $arrayType): bool - { - if ($arrayType->getKeyType() instanceof MixedType) { - return false; - } - - if ($this->isClassStringArrayType($arrayType)) { - return true; - } - - // skip simple arrays, like "string[]", from converting to obvious "array" - if ($this->isIntegerKeyAndNonNestedArray($arrayType)) { - return false; - } - - if ($arrayType->getKeyType() instanceof NeverType) { - return false; - } - - // make sure the integer key type is not natural/implicit array int keys - $keysArrayType = $arrayType->getKeysArray(); - if (! $keysArrayType instanceof ConstantArrayType) { - return true; - } - - foreach ($keysArrayType->getValueTypes() as $key => $keyType) { - if (! $keyType instanceof ConstantIntegerType) { - return true; - } - - if ($key !== $keyType->getValue()) { - return true; - } - } - - return false; - } - - private function createGenericArrayType(ArrayType $arrayType, bool $withKey = false): GenericTypeNode - { - $itemType = $arrayType->getIterableValueType(); - $identifierTypeNode = new IdentifierTypeNode('array'); - - // is class-string[] list only - if ($this->isClassStringArrayType($arrayType)) { - $withKey = false; - } - - if (! $withKey) { - $itemTypeNode = $this->phpStanStaticTypeMapper->mapToPHPStanPhpDocTypeNode($itemType); - return new GenericTypeNode($identifierTypeNode, [$itemTypeNode]); - } - - $keyTypeNode = $this->phpStanStaticTypeMapper->mapToPHPStanPhpDocTypeNode($arrayType->getKeyType()); - $itemTypeNode = $this->createGenericArrayValueTypeNode($itemType); - - if ($itemTypeNode instanceof UnionTypeNode && $this->isPairClassTooDetailed($itemType)) { - $itemTypeNode = $this->phpStanStaticTypeMapper->mapToPHPStanPhpDocTypeNode(new ClassStringType()); - } - - return new GenericTypeNode($identifierTypeNode, [$keyTypeNode, $itemTypeNode]); - } - - private function isPairClassTooDetailed(Type $itemType): bool - { - if (! $itemType instanceof UnionType) { - return false; - } - - if (! $this->genericClassStringTypeNormalizer->isAllGenericClassStringType($itemType)) { - return false; - } - - return $this->detailedTypeAnalyzer->isTooDetailed($itemType); - } - - private function isIntegerKeyAndNonNestedArray(ArrayType $arrayType): bool - { - if (! $arrayType->getKeyType()->isInteger()->yes()) { - return false; - } - - return ! $arrayType->getIterableValueType() - ->isArray() - ->yes(); - } - - private function isClassStringArrayType(ArrayType $arrayType): bool - { - if ($arrayType->getKeyType() instanceof MixedType) { - return $arrayType->getIterableValueType() instanceof GenericClassStringType; - } - - if ($arrayType->getKeyType() instanceof ConstantIntegerType) { - return $arrayType->getIterableValueType() instanceof GenericClassStringType; - } - - return false; - } -} diff --git a/src/PHPStanStaticTypeMapper/TypeMapper/BooleanTypeMapper.php b/src/PHPStanStaticTypeMapper/TypeMapper/BooleanTypeMapper.php deleted file mode 100644 index a93c8eb2b4c..00000000000 --- a/src/PHPStanStaticTypeMapper/TypeMapper/BooleanTypeMapper.php +++ /dev/null @@ -1,32 +0,0 @@ - - */ -final readonly class BooleanTypeMapper implements TypeMapperInterface -{ - /** - * @return array> - */ - public function getNodeClasses(): array - { - return [BooleanType::class]; - } - - /** - * @param BooleanType $type - */ - public function mapToPHPStanPhpDocTypeNode(Type $type): TypeNode - { - return $type->toPhpDocNode(); - } -} diff --git a/src/PHPStanStaticTypeMapper/TypeMapper/CallableTypeMapper.php b/src/PHPStanStaticTypeMapper/TypeMapper/CallableTypeMapper.php deleted file mode 100644 index 8eb24a3e902..00000000000 --- a/src/PHPStanStaticTypeMapper/TypeMapper/CallableTypeMapper.php +++ /dev/null @@ -1,32 +0,0 @@ - - */ -final class CallableTypeMapper implements TypeMapperInterface -{ - /** - * @return array> - */ - public function getNodeClasses(): array - { - return [CallableType::class]; - } - - /** - * @param CallableType $type - */ - public function mapToPHPStanPhpDocTypeNode(Type $type): TypeNode - { - return $type->toPhpDocNode(); - } -} diff --git a/src/PHPStanStaticTypeMapper/TypeMapper/ClassStringTypeMapper.php b/src/PHPStanStaticTypeMapper/TypeMapper/ClassStringTypeMapper.php deleted file mode 100644 index 7903e8bcdd0..00000000000 --- a/src/PHPStanStaticTypeMapper/TypeMapper/ClassStringTypeMapper.php +++ /dev/null @@ -1,48 +0,0 @@ - - */ -final readonly class ClassStringTypeMapper implements TypeMapperInterface -{ - /** - * @return array> - */ - public function getNodeClasses(): array - { - return [ClassStringType::class]; - } - - /** - * @param ClassStringType $type - */ - public function mapToPHPStanPhpDocTypeNode(Type $type): TypeNode - { - $type = TypeTraverser::map($type, static function (Type $type, callable $traverse): Type { - if (! $type instanceof ObjectType) { - return $traverse($type); - } - - $typeClass = $type::class; - - if ($typeClass === 'PHPStan\Type\ObjectType') { - return new ObjectType('\\' . $type->getClassName()); - } - - return $traverse($type); - }); - - return $type->toPhpDocNode(); - } -} diff --git a/src/PHPStanStaticTypeMapper/TypeMapper/ClosureTypeMapper.php b/src/PHPStanStaticTypeMapper/TypeMapper/ClosureTypeMapper.php deleted file mode 100644 index f34f48b29a4..00000000000 --- a/src/PHPStanStaticTypeMapper/TypeMapper/ClosureTypeMapper.php +++ /dev/null @@ -1,54 +0,0 @@ - - */ -final readonly class ClosureTypeMapper implements TypeMapperInterface -{ - /** - * @return array> - */ - public function getNodeClasses(): array - { - return [ClosureType::class]; - } - - /** - * @param ClosureType $type - */ - public function mapToPHPStanPhpDocTypeNode(Type $type): TypeNode - { - $typeNode = $type->toPhpDocNode(); - - $phpDocNodeTraverser = new NodeTraverser([new CallablePhpDocNodeVisitor( - static function (AstNode $astNode): ?FullyQualifiedIdentifierTypeNode { - if (! $astNode instanceof IdentifierTypeNode) { - return null; - } - - if ($astNode->name !== 'Closure') { - return null; - } - - return new FullyQualifiedIdentifierTypeNode('Closure'); - } - )]); - $phpDocNodeTraverser->traverse([$typeNode]); - - return $typeNode; - } -} diff --git a/src/PHPStanStaticTypeMapper/TypeMapper/ConditionalTypeForParameterMapper.php b/src/PHPStanStaticTypeMapper/TypeMapper/ConditionalTypeForParameterMapper.php deleted file mode 100644 index a5cf77572f9..00000000000 --- a/src/PHPStanStaticTypeMapper/TypeMapper/ConditionalTypeForParameterMapper.php +++ /dev/null @@ -1,32 +0,0 @@ - - */ -final class ConditionalTypeForParameterMapper implements TypeMapperInterface -{ - /** - * @return array> - */ - public function getNodeClasses(): array - { - return [ConditionalTypeForParameter::class]; - } - - /** - * @param ConditionalTypeForParameter $type - */ - public function mapToPHPStanPhpDocTypeNode(Type $type): TypeNode - { - return $type->toPhpDocNode(); - } -} diff --git a/src/PHPStanStaticTypeMapper/TypeMapper/ConditionalTypeMapper.php b/src/PHPStanStaticTypeMapper/TypeMapper/ConditionalTypeMapper.php deleted file mode 100644 index e49bbe8cf49..00000000000 --- a/src/PHPStanStaticTypeMapper/TypeMapper/ConditionalTypeMapper.php +++ /dev/null @@ -1,45 +0,0 @@ - - */ -final class ConditionalTypeMapper implements TypeMapperInterface -{ - /** - * @return array> - */ - public function getNodeClasses(): array - { - return [ConditionalType::class]; - } - - /** - * @param ConditionalType $type - */ - public function mapToPHPStanPhpDocTypeNode(Type $type): TypeNode - { - $type = TypeTraverser::map($type, static function (Type $type, callable $traverse): Type { - if ($type instanceof ObjectType && ! $type->getClassReflection() instanceof ClassReflection) { - $newClassName = (string) Strings::after($type->getClassName(), '\\', -1); - return $traverse(new ObjectType($newClassName)); - } - - return $traverse($type); - }); - - return $type->toPhpDocNode(); - } -} diff --git a/src/PHPStanStaticTypeMapper/TypeMapper/ConstantArrayTypeMapper.php b/src/PHPStanStaticTypeMapper/TypeMapper/ConstantArrayTypeMapper.php deleted file mode 100644 index 5ac9b458252..00000000000 --- a/src/PHPStanStaticTypeMapper/TypeMapper/ConstantArrayTypeMapper.php +++ /dev/null @@ -1,32 +0,0 @@ - - */ -final readonly class ConstantArrayTypeMapper implements TypeMapperInterface -{ - /** - * @return array> - */ - public function getNodeClasses(): array - { - return [ConstantArrayType::class]; - } - - /** - * @param ConstantArrayType $type - */ - public function mapToPHPStanPhpDocTypeNode(Type $type): TypeNode - { - return $type->toPhpDocNode(); - } -} diff --git a/src/PHPStanStaticTypeMapper/TypeMapper/FloatTypeMapper.php b/src/PHPStanStaticTypeMapper/TypeMapper/FloatTypeMapper.php deleted file mode 100644 index ff7e3a262f9..00000000000 --- a/src/PHPStanStaticTypeMapper/TypeMapper/FloatTypeMapper.php +++ /dev/null @@ -1,32 +0,0 @@ - - */ -final readonly class FloatTypeMapper implements TypeMapperInterface -{ - /** - * @return array> - */ - public function getNodeClasses(): array - { - return [FloatType::class]; - } - - /** - * @param FloatType $type - */ - public function mapToPHPStanPhpDocTypeNode(Type $type): TypeNode - { - return $type->toPhpDocNode(); - } -} diff --git a/src/PHPStanStaticTypeMapper/TypeMapper/HasMethodTypeMapper.php b/src/PHPStanStaticTypeMapper/TypeMapper/HasMethodTypeMapper.php deleted file mode 100644 index 9bc805d9e49..00000000000 --- a/src/PHPStanStaticTypeMapper/TypeMapper/HasMethodTypeMapper.php +++ /dev/null @@ -1,32 +0,0 @@ - - */ -final readonly class HasMethodTypeMapper implements TypeMapperInterface -{ - /** - * @return array> - */ - public function getNodeClasses(): array - { - return [HasMethodType::class]; - } - - /** - * @param HasMethodType $type - */ - public function mapToPHPStanPhpDocTypeNode(Type $type): TypeNode - { - return $type->toPhpDocNode(); - } -} diff --git a/src/PHPStanStaticTypeMapper/TypeMapper/HasPropertyTypeMapper.php b/src/PHPStanStaticTypeMapper/TypeMapper/HasPropertyTypeMapper.php deleted file mode 100644 index b7de4e4c2e3..00000000000 --- a/src/PHPStanStaticTypeMapper/TypeMapper/HasPropertyTypeMapper.php +++ /dev/null @@ -1,32 +0,0 @@ - - */ -final readonly class HasPropertyTypeMapper implements TypeMapperInterface -{ - /** - * @return array> - */ - public function getNodeClasses(): array - { - return [HasPropertyType::class]; - } - - /** - * @param HasPropertyType $type - */ - public function mapToPHPStanPhpDocTypeNode(Type $type): TypeNode - { - return $type->toPhpDocNode(); - } -} diff --git a/src/PHPStanStaticTypeMapper/TypeMapper/IntegerTypeMapper.php b/src/PHPStanStaticTypeMapper/TypeMapper/IntegerTypeMapper.php deleted file mode 100644 index 2a776ad604c..00000000000 --- a/src/PHPStanStaticTypeMapper/TypeMapper/IntegerTypeMapper.php +++ /dev/null @@ -1,33 +0,0 @@ - - */ -final readonly class IntegerTypeMapper implements TypeMapperInterface -{ - /** - * @return array> - */ - public function getNodeClasses(): array - { - return [IntegerType::class]; - } - - /** - * @param IntegerType $type - */ - public function mapToPHPStanPhpDocTypeNode(Type $type): IdentifierTypeNode - { - // note: cannot be handled by PHPStan as uses explicit values - return new IdentifierTypeNode('int'); - } -} diff --git a/src/PHPStanStaticTypeMapper/TypeMapper/IntersectionTypeMapper.php b/src/PHPStanStaticTypeMapper/TypeMapper/IntersectionTypeMapper.php deleted file mode 100644 index 86cf2d6223f..00000000000 --- a/src/PHPStanStaticTypeMapper/TypeMapper/IntersectionTypeMapper.php +++ /dev/null @@ -1,84 +0,0 @@ - - */ -final readonly class IntersectionTypeMapper implements TypeMapperInterface -{ - public function __construct( - private ScalarStringToTypeMapper $scalarStringToTypeMapper, - ) { - } - - /** - * @return array> - */ - public function getNodeClasses(): array - { - return [IntersectionType::class]; - } - - /** - * @param IntersectionType $type - */ - public function mapToPHPStanPhpDocTypeNode(Type $type): TypeNode - { - $typeNode = $type->toPhpDocNode(); - - $phpDocNodeTraverser = new NodeTraverser([new CallablePhpDocNodeVisitor( - function (AstNode $astNode) use ($typeNode): int|IdentifierTypeNode|null { - if ($astNode === $typeNode) { - return null; - } - - if ($astNode instanceof UnionTypeNode) { - return NodeTraverser::DONT_TRAVERSE_CURRENT_AND_CHILDREN; - } - - if ($astNode instanceof ArrayShapeItemNode) { - return NodeTraverser::DONT_TRAVERSE_CURRENT_AND_CHILDREN; - } - - if (! $astNode instanceof IdentifierTypeNode) { - return NodeTraverser::DONT_TRAVERSE_CURRENT_AND_CHILDREN; - } - - $type = $this->scalarStringToTypeMapper->mapScalarStringToType($astNode->name); - if ($type->isScalar()->yes()) { - return NodeTraverser::DONT_TRAVERSE_CURRENT_AND_CHILDREN; - } - - if ($type->isArray()->yes()) { - return NodeTraverser::DONT_TRAVERSE_CURRENT_AND_CHILDREN; - } - - if ($type instanceof MixedType && $type->isExplicitMixed()) { - return NodeTraverser::DONT_TRAVERSE_CURRENT_AND_CHILDREN; - } - - $astNode->name = '\\' . ltrim($astNode->name, '\\'); - return $astNode; - } - )]); - $phpDocNodeTraverser->traverse([$typeNode]); - - return $typeNode; - } -} diff --git a/src/PHPStanStaticTypeMapper/TypeMapper/IterableTypeMapper.php b/src/PHPStanStaticTypeMapper/TypeMapper/IterableTypeMapper.php deleted file mode 100644 index dc343d0fc9c..00000000000 --- a/src/PHPStanStaticTypeMapper/TypeMapper/IterableTypeMapper.php +++ /dev/null @@ -1,32 +0,0 @@ - - */ -final class IterableTypeMapper implements TypeMapperInterface -{ - /** - * @return array> - */ - public function getNodeClasses(): array - { - return [IterableType::class]; - } - - /** - * @param IterableType $type - */ - public function mapToPHPStanPhpDocTypeNode(Type $type): TypeNode - { - return $type->toPhpDocNode(); - } -} diff --git a/src/PHPStanStaticTypeMapper/TypeMapper/MixedTypeMapper.php b/src/PHPStanStaticTypeMapper/TypeMapper/MixedTypeMapper.php deleted file mode 100644 index 7301a7c27d3..00000000000 --- a/src/PHPStanStaticTypeMapper/TypeMapper/MixedTypeMapper.php +++ /dev/null @@ -1,32 +0,0 @@ - - */ -final readonly class MixedTypeMapper implements TypeMapperInterface -{ - /** - * @return array> - */ - public function getNodeClasses(): array - { - return [MixedType::class]; - } - - /** - * @param MixedType $type - */ - public function mapToPHPStanPhpDocTypeNode(Type $type): TypeNode - { - return $type->toPhpDocNode(); - } -} diff --git a/src/PHPStanStaticTypeMapper/TypeMapper/NeverTypeMapper.php b/src/PHPStanStaticTypeMapper/TypeMapper/NeverTypeMapper.php deleted file mode 100644 index 584f736e664..00000000000 --- a/src/PHPStanStaticTypeMapper/TypeMapper/NeverTypeMapper.php +++ /dev/null @@ -1,32 +0,0 @@ - - */ -final class NeverTypeMapper implements TypeMapperInterface -{ - /** - * @return array> - */ - public function getNodeClasses(): array - { - return [NeverType::class]; - } - - /** - * @param NeverType $type - */ - public function mapToPHPStanPhpDocTypeNode(Type $type): TypeNode - { - return $type->toPhpDocNode(); - } -} diff --git a/src/PHPStanStaticTypeMapper/TypeMapper/NonexistentParentClassTypeMapper.php b/src/PHPStanStaticTypeMapper/TypeMapper/NonexistentParentClassTypeMapper.php deleted file mode 100644 index 44df721481a..00000000000 --- a/src/PHPStanStaticTypeMapper/TypeMapper/NonexistentParentClassTypeMapper.php +++ /dev/null @@ -1,37 +0,0 @@ - - * @see \Rector\Tests\PHPStanStaticTypeMapper\TypeMapper\NonexistentParentClassTypeMapperTest - */ -final class NonexistentParentClassTypeMapper implements TypeMapperInterface -{ - /** - * @return array> - */ - public function getNodeClasses(): array - { - return [NonexistentParentClassType::class]; - } - - /** - * @param NonexistentParentClassType $type - */ - public function mapToPHPStanPhpDocTypeNode(Type $type): TypeNode - { - return $type->toPhpDocNode(); - } -} diff --git a/src/PHPStanStaticTypeMapper/TypeMapper/NullTypeMapper.php b/src/PHPStanStaticTypeMapper/TypeMapper/NullTypeMapper.php deleted file mode 100644 index 8d53d8fa25c..00000000000 --- a/src/PHPStanStaticTypeMapper/TypeMapper/NullTypeMapper.php +++ /dev/null @@ -1,32 +0,0 @@ - - */ -final readonly class NullTypeMapper implements TypeMapperInterface -{ - /** - * @return array> - */ - public function getNodeClasses(): array - { - return [NullType::class]; - } - - /** - * @param NullType $type - */ - public function mapToPHPStanPhpDocTypeNode(Type $type): TypeNode - { - return $type->toPhpDocNode(); - } -} diff --git a/src/PHPStanStaticTypeMapper/TypeMapper/ObjectTypeMapper.php b/src/PHPStanStaticTypeMapper/TypeMapper/ObjectTypeMapper.php deleted file mode 100644 index 1face548f9d..00000000000 --- a/src/PHPStanStaticTypeMapper/TypeMapper/ObjectTypeMapper.php +++ /dev/null @@ -1,64 +0,0 @@ - - */ -final class ObjectTypeMapper implements TypeMapperInterface -{ - /** - * @return array> - */ - public function getNodeClasses(): array - { - return [ObjectType::class]; - } - - /** - * @param ObjectType $type - */ - public function mapToPHPStanPhpDocTypeNode(Type $type): TypeNode - { - $type = TypeTraverser::map($type, static function (Type $type, callable $traverse): Type { - if ($type instanceof ArrayType && ($type->getItemType() instanceof MixedType && $type->getKeyType() instanceof MixedType)) { - return new ArrayType(new MixedType(), new MixedType(true)); - } - - if (! $type instanceof ObjectType) { - return $traverse($type); - } - - $typeClass = $type::class; - - // early native ObjectType check - if ($typeClass === 'PHPStan\Type\ObjectType') { - return new ObjectType('\\' . $type->getClassName()); - } - - if ($type instanceof FullyQualifiedObjectType) { - return new ObjectType('\\' . $type->getClassName()); - } - - if ($type instanceof GenericObjectType) { - return $traverse(new GenericObjectType('\\' . $type->getClassName(), $type->getTypes())); - } - - return $traverse($type); - }); - - return $type->toPhpDocNode(); - } -} diff --git a/src/PHPStanStaticTypeMapper/TypeMapper/ObjectWithoutClassTypeMapper.php b/src/PHPStanStaticTypeMapper/TypeMapper/ObjectWithoutClassTypeMapper.php deleted file mode 100644 index 7ee3075a60b..00000000000 --- a/src/PHPStanStaticTypeMapper/TypeMapper/ObjectWithoutClassTypeMapper.php +++ /dev/null @@ -1,32 +0,0 @@ - - */ -final readonly class ObjectWithoutClassTypeMapper implements TypeMapperInterface -{ - /** - * @return array> - */ - public function getNodeClasses(): array - { - return [ObjectWithoutClassType::class]; - } - - /** - * @param ObjectWithoutClassType $type - */ - public function mapToPHPStanPhpDocTypeNode(Type $type): TypeNode - { - return $type->toPhpDocNode(); - } -} diff --git a/src/PHPStanStaticTypeMapper/TypeMapper/ParentStaticTypeMapper.php b/src/PHPStanStaticTypeMapper/TypeMapper/ParentStaticTypeMapper.php deleted file mode 100644 index ac8cc99b93a..00000000000 --- a/src/PHPStanStaticTypeMapper/TypeMapper/ParentStaticTypeMapper.php +++ /dev/null @@ -1,32 +0,0 @@ - - */ -final class ParentStaticTypeMapper implements TypeMapperInterface -{ - /** - * @return array> - */ - public function getNodeClasses(): array - { - return [ParentStaticType::class]; - } - - /** - * @param ParentStaticType $type - */ - public function mapToPHPStanPhpDocTypeNode(Type $type): TypeNode - { - return $type->toPhpDocNode(); - } -} diff --git a/src/PHPStanStaticTypeMapper/TypeMapper/ResourceTypeMapper.php b/src/PHPStanStaticTypeMapper/TypeMapper/ResourceTypeMapper.php deleted file mode 100644 index da1570df0ef..00000000000 --- a/src/PHPStanStaticTypeMapper/TypeMapper/ResourceTypeMapper.php +++ /dev/null @@ -1,32 +0,0 @@ - - */ -final class ResourceTypeMapper implements TypeMapperInterface -{ - /** - * @return array> - */ - public function getNodeClasses(): array - { - return [ResourceType::class]; - } - - /** - * @param ResourceType $type - */ - public function mapToPHPStanPhpDocTypeNode(Type $type): TypeNode - { - return $type->toPhpDocNode(); - } -} diff --git a/src/PHPStanStaticTypeMapper/TypeMapper/StaticTypeMapper.php b/src/PHPStanStaticTypeMapper/TypeMapper/StaticTypeMapper.php deleted file mode 100644 index de0f992145d..00000000000 --- a/src/PHPStanStaticTypeMapper/TypeMapper/StaticTypeMapper.php +++ /dev/null @@ -1,34 +0,0 @@ - - */ -final readonly class StaticTypeMapper implements TypeMapperInterface -{ - /** - * @return array> - */ - public function getNodeClasses(): array - { - return [StaticType::class]; - } - - /** - * @param StaticType $type - */ - public function mapToPHPStanPhpDocTypeNode(Type $type): TypeNode - { - return $type->toPhpDocNode(); - } -} diff --git a/src/PHPStanStaticTypeMapper/TypeMapper/StrictMixedTypeMapper.php b/src/PHPStanStaticTypeMapper/TypeMapper/StrictMixedTypeMapper.php deleted file mode 100644 index 4ec27858436..00000000000 --- a/src/PHPStanStaticTypeMapper/TypeMapper/StrictMixedTypeMapper.php +++ /dev/null @@ -1,32 +0,0 @@ - - */ -final readonly class StrictMixedTypeMapper implements TypeMapperInterface -{ - /** - * @return array> - */ - public function getNodeClasses(): array - { - return [StrictMixedType::class]; - } - - /** - * @param StrictMixedType $type - */ - public function mapToPHPStanPhpDocTypeNode(Type $type): TypeNode - { - return $type->toPhpDocNode(); - } -} diff --git a/src/PHPStanStaticTypeMapper/TypeMapper/StringTypeMapper.php b/src/PHPStanStaticTypeMapper/TypeMapper/StringTypeMapper.php deleted file mode 100644 index 880021dee0f..00000000000 --- a/src/PHPStanStaticTypeMapper/TypeMapper/StringTypeMapper.php +++ /dev/null @@ -1,32 +0,0 @@ - - */ -final readonly class StringTypeMapper implements TypeMapperInterface -{ - /** - * @return array> - */ - public function getNodeClasses(): array - { - return [StringType::class]; - } - - /** - * @param StringType $type - */ - public function mapToPHPStanPhpDocTypeNode(Type $type): TypeNode - { - return $type->toPhpDocNode(); - } -} diff --git a/src/PHPStanStaticTypeMapper/TypeMapper/TypeWithClassNameTypeMapper.php b/src/PHPStanStaticTypeMapper/TypeMapper/TypeWithClassNameTypeMapper.php deleted file mode 100644 index 452b11d7e1f..00000000000 --- a/src/PHPStanStaticTypeMapper/TypeMapper/TypeWithClassNameTypeMapper.php +++ /dev/null @@ -1,32 +0,0 @@ - - */ -final readonly class TypeWithClassNameTypeMapper implements TypeMapperInterface -{ - /** - * @return array> - */ - public function getNodeClasses(): array - { - return [TypeWithClassName::class]; - } - - /** - * @param TypeWithClassName $type - */ - public function mapToPHPStanPhpDocTypeNode(Type $type): TypeNode - { - return $type->toPhpDocNode(); - } -} diff --git a/src/PHPStanStaticTypeMapper/TypeMapper/UnionTypeMapper.php b/src/PHPStanStaticTypeMapper/TypeMapper/UnionTypeMapper.php deleted file mode 100644 index 485a997cc34..00000000000 --- a/src/PHPStanStaticTypeMapper/TypeMapper/UnionTypeMapper.php +++ /dev/null @@ -1,61 +0,0 @@ - - */ -final class UnionTypeMapper implements TypeMapperInterface -{ - private PHPStanStaticTypeMapper $phpStanStaticTypeMapper; - - public function autowire(PHPStanStaticTypeMapper $phpStanStaticTypeMapper): void - { - $this->phpStanStaticTypeMapper = $phpStanStaticTypeMapper; - } - - /** - * @return array> - */ - public function getNodeClasses(): array - { - return [UnionType::class]; - } - - /** - * @param UnionType $type - */ - public function mapToPHPStanPhpDocTypeNode(Type $type): BracketsAwareUnionTypeNode - { - $unionTypesNodes = []; - - foreach ($type->getTypes() as $unionedType) { - if ($unionedType instanceof ArrayType && $unionedType->getItemType() instanceof NeverType) { - $unionedType = new ArrayType($unionedType->getKeyType(), new MixedType()); - } - - $unionedTypeNode = $this->phpStanStaticTypeMapper->mapToPHPStanPhpDocTypeNode($unionedType); - - // an array of union item type is mapped to "A[]|B[]", merge it into this union - $typeNodes = $unionedTypeNode instanceof UnionTypeNode ? $unionedTypeNode->types : [$unionedTypeNode]; - - // remove duplicates, e.g. "int[]|int[]" - foreach ($typeNodes as $typeNode) { - $unionTypesNodes[(string) $typeNode] = $typeNode; - } - } - - return new UnionTypeNode(array_values($unionTypesNodes)); - } -} diff --git a/src/PHPStanStaticTypeMapper/TypeMapper/VoidTypeMapper.php b/src/PHPStanStaticTypeMapper/TypeMapper/VoidTypeMapper.php deleted file mode 100644 index 4b4687569ee..00000000000 --- a/src/PHPStanStaticTypeMapper/TypeMapper/VoidTypeMapper.php +++ /dev/null @@ -1,32 +0,0 @@ - - */ -final readonly class VoidTypeMapper implements TypeMapperInterface -{ - /** - * @return array> - */ - public function getNodeClasses(): array - { - return [VoidType::class]; - } - - /** - * @param VoidType $type - */ - public function mapToPHPStanPhpDocTypeNode(Type $type): TypeNode - { - return $type->toPhpDocNode(); - } -} diff --git a/src/StaticTypeMapper/StaticTypeMapper.php b/src/StaticTypeMapper/StaticTypeMapper.php index 73b19b2222e..ebfb4b7dd35 100644 --- a/src/StaticTypeMapper/StaticTypeMapper.php +++ b/src/StaticTypeMapper/StaticTypeMapper.php @@ -15,16 +15,23 @@ use PHPStan\PhpDocParser\Ast\PhpDoc\TemplateTagValueNode; use PHPStan\PhpDocParser\Ast\PhpDoc\ThrowsTagValueNode; use PHPStan\PhpDocParser\Ast\PhpDoc\VarTagValueNode; +use PHPStan\PhpDocParser\Ast\Type\ArrayTypeNode; +use PHPStan\PhpDocParser\Ast\Type\GenericTypeNode; +use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode; +use PHPStan\PhpDocParser\Ast\Type\IntersectionTypeNode; use PHPStan\PhpDocParser\Ast\Type\TypeNode; +use PHPStan\PhpDocParser\Ast\Type\UnionTypeNode; +use PHPStan\Type\ArrayType; use PHPStan\Type\BooleanType; +use PHPStan\Type\IntegerType; use PHPStan\Type\MixedType; use PHPStan\Type\NativeTypePosition; use PHPStan\Type\Type; use PHPStan\Type\TypeTraverser; +use PHPStan\Type\UnionType; use Rector\Exception\NotImplementedYetException; use Rector\Php\PhpVersionProvider; use Rector\PHPStanStaticTypeMapper\Enum\TypeKind; -use Rector\PHPStanStaticTypeMapper\PHPStanStaticTypeMapper; use Rector\StaticTypeMapper\Mapper\PhpParserNodeMapper; use Rector\StaticTypeMapper\Naming\NameScopeFactory; use Rector\StaticTypeMapper\PhpDoc\PhpDocTypeMapper; @@ -37,7 +44,6 @@ { public function __construct( private NameScopeFactory $nameScopeFactory, - private PHPStanStaticTypeMapper $phpStanStaticTypeMapper, private PhpDocTypeMapper $phpDocTypeMapper, private PhpParserNodeMapper $phpParserNodeMapper, private PhpVersionProvider $phpVersionProvider @@ -46,7 +52,20 @@ public function __construct( public function mapPHPStanTypeToPHPStanPhpDocTypeNode(Type $phpStanType): TypeNode { - return $this->phpStanStaticTypeMapper->mapToPHPStanPhpDocTypeNode($phpStanType); + // explicit int values and ranges are too detailed for a docblock + $phpStanType = TypeTraverser::map($phpStanType, static function (Type $type, callable $traverse): Type { + if ($type instanceof IntegerType) { + return new IntegerType(); + } + + if ($type instanceof UnionType || $type instanceof ArrayType) { + return $traverse($type); + } + + return $type; + }); + + return $this->styleTypeNode($phpStanType->toPhpDocNode()); } /** @@ -108,6 +127,82 @@ public function mapPHPStanPhpDocTypeNodeToPHPStanType(TypeNode $typeNode, Node $ return $this->phpDocTypeMapper->mapToPHPStanType($typeNode, $node, $nameScope); } + /** + * Rector prints "A[]" instead of "array" or "array" + */ + private function styleTypeNode(TypeNode $typeNode): TypeNode + { + if ($typeNode instanceof UnionTypeNode) { + $unionedTypeNodes = []; + foreach ($typeNode->types as $unionedTypeNode) { + $unionedTypeNode = $this->styleTypeNode($unionedTypeNode); + + // "A[]|B[]" from an array of a union is merged into this union + foreach ($unionedTypeNode instanceof UnionTypeNode ? $unionedTypeNode->types : [$unionedTypeNode] as $singleTypeNode) { + $unionedTypeNodes[(string) $singleTypeNode] = $singleTypeNode; + } + } + + return new UnionTypeNode(array_values($unionedTypeNodes)); + } + + if ($typeNode instanceof IntersectionTypeNode) { + return new IntersectionTypeNode(array_map($this->styleTypeNode(...), $typeNode->types)); + } + + if ($typeNode instanceof IdentifierTypeNode && $typeNode->name === 'array') { + return new ArrayTypeNode(new IdentifierTypeNode('mixed')); + } + + if (! $typeNode instanceof GenericTypeNode) { + return $typeNode; + } + + $genericTypeNodes = array_map($this->styleTypeNode(...), $typeNode->genericTypes); + if ($typeNode->type instanceof IdentifierTypeNode && $typeNode->type->name === 'array' && $this->isArrayOfItemsOnly($genericTypeNodes)) { + $itemTypeNode = $genericTypeNodes[array_key_last($genericTypeNodes)]; + if (! $itemTypeNode instanceof UnionTypeNode) { + return new ArrayTypeNode($itemTypeNode); + } + + return new UnionTypeNode(array_map( + static fn (TypeNode $unionedTypeNode): ArrayTypeNode => new ArrayTypeNode($unionedTypeNode), + $itemTypeNode->types + )); + } + + $typeNode->genericTypes = $genericTypeNodes; + return $typeNode; + } + + /** + * "array" or "array" can be printed as "A[]", unless that would lose the int key of nested arrays, + * or turn "array|A>" into "A[]|A[]" + * + * @param TypeNode[] $genericTypeNodes + */ + private function isArrayOfItemsOnly(array $genericTypeNodes): bool + { + if (count($genericTypeNodes) === 2 && (string) $genericTypeNodes[0] !== 'int') { + return false; + } + + $itemTypeNode = $genericTypeNodes[array_key_last($genericTypeNodes)]; + $itemTypeNodes = $itemTypeNode instanceof UnionTypeNode ? $itemTypeNode->types : [$itemTypeNode]; + + foreach ($itemTypeNodes as $singleItemTypeNode) { + if ($singleItemTypeNode instanceof GenericTypeNode && count($itemTypeNodes) > 1) { + return false; + } + + if (count($genericTypeNodes) === 2 && ($singleItemTypeNode instanceof ArrayTypeNode || $singleItemTypeNode instanceof GenericTypeNode)) { + return false; + } + } + + return true; + } + private function getPhpVersion(): PhpVersion { return new PhpVersion($this->phpVersionProvider->provide()); diff --git a/tests/Issues/ImportFullyQualifiedIdentifierDocblock/Source/AddFullyQualifiedIdentifierDocblockRector.php b/tests/Issues/ImportFullyQualifiedIdentifierDocblock/Source/AddFullyQualifiedIdentifierDocblockRector.php index 0f040cb9e73..a91ca996e74 100644 --- a/tests/Issues/ImportFullyQualifiedIdentifierDocblock/Source/AddFullyQualifiedIdentifierDocblockRector.php +++ b/tests/Issues/ImportFullyQualifiedIdentifierDocblock/Source/AddFullyQualifiedIdentifierDocblockRector.php @@ -8,7 +8,7 @@ use PhpParser\Node\Stmt\Property; use PHPStan\PhpDocParser\Ast\PhpDoc\VarTagValueNode; use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfoFactory; -use Rector\BetterPhpDocParser\ValueObject\Type\FullyQualifiedIdentifierTypeNode; +use PHPStan\PhpDocParser\Ast\Type\FullyQualifiedNameNode; use Rector\Comments\NodeDocBlock\DocBlockUpdater; use Rector\Rector\AbstractRector; use Rector\RuleDoc\RuleDefinition; @@ -42,7 +42,7 @@ public function refactor(Node $node) return null; } - $varTagValueNode = new VarTagValueNode(new FullyQualifiedIdentifierTypeNode('DateTime'), '', ''); + $varTagValueNode = new VarTagValueNode(new FullyQualifiedNameNode('DateTime'), '', ''); $phpDocInfo->addTagValueNode($varTagValueNode); $this->docBlockUpdater->updateRefactoredNodeWithPhpDocInfo($node); diff --git a/tests/PHPStanStaticTypeMapper/TypeMapper/ArrayTypeMapperTest.php b/tests/PHPStanStaticTypeMapper/TypeMapper/ArrayTypeMapperTest.php deleted file mode 100644 index 47d3e5ff592..00000000000 --- a/tests/PHPStanStaticTypeMapper/TypeMapper/ArrayTypeMapperTest.php +++ /dev/null @@ -1,94 +0,0 @@ -arrayTypeMapper = $this->make(ArrayTypeMapper::class); - } - - #[DataProvider('provideDataWithoutKeys')] - #[DataProvider('provideDataUnionedWithoutKeys')] - public function testWithoutKeys(ArrayType $arrayType, string $expectedResult): void - { - $actualTypeNode = $this->arrayTypeMapper->mapToPHPStanPhpDocTypeNode($arrayType); - $this->assertSame($expectedResult, new Printer()->print($actualTypeNode)); - } - - #[DataProvider('provideDataWithKeys')] - public function testWithKeys(ArrayType $arrayType, string $expectedResult): void - { - $actualTypeNode = $this->arrayTypeMapper->mapToPHPStanPhpDocTypeNode($arrayType); - $this->assertSame($expectedResult, new Printer()->print($actualTypeNode)); - } - - /** - * @return Iterator - */ - public static function provideDataWithoutKeys(): Iterator - { - $arrayType = new ArrayType(new MixedType(), new StringType()); - yield [$arrayType, 'string[]']; - - $stringStringUnionType = new UnionType([new StringType(), new StringType()]); - $arrayType = new ArrayType(new MixedType(), $stringStringUnionType); - yield [$arrayType, 'string[]']; - } - - /** - * @return Iterator> - */ - public static function provideDataUnionedWithoutKeys(): Iterator - { - $stringAndIntegerUnionType = new UnionType([new StringType(), new IntegerType()]); - $unionArrayType = new ArrayType(new MixedType(), $stringAndIntegerUnionType); - yield [$unionArrayType, 'string[]|int[]']; - - $moreNestedUnionArrayType = new ArrayType(new MixedType(), $unionArrayType); - yield [$moreNestedUnionArrayType, 'string[][]|int[][]']; - - $evenMoreNestedUnionArrayType = new ArrayType(new MixedType(), $moreNestedUnionArrayType); - yield [$evenMoreNestedUnionArrayType, 'string[][][]|int[][][]']; - } - - /** - * @return Iterator> - */ - public static function provideDataWithKeys(): Iterator - { - $arrayMixedToStringType = new ArrayType(new MixedType(), new StringType()); - $arrayType = new ArrayType(new StringType(), $arrayMixedToStringType); - yield [$arrayType, 'array']; - - $stringAndIntegerUnionType = new UnionType([new StringType(), new IntegerType()]); - - $stringAndIntegerUnionArrayType = new ArrayType(new MixedType(), $stringAndIntegerUnionType); - $arrayType = new ArrayType(new StringType(), $stringAndIntegerUnionArrayType); - yield [$arrayType, 'array>']; - - $arrayType = new ArrayType(new StringType(), new IntegerType()); - yield [$arrayType, 'array']; - - $arrayType = new ArrayType(new StringType(), $stringAndIntegerUnionType); - yield [$arrayType, 'array']; - } -} diff --git a/tests/PHPStanStaticTypeMapper/TypeMapper/NonexistentParentClassTypeMapperTest.php b/tests/PHPStanStaticTypeMapper/TypeMapper/NonexistentParentClassTypeMapperTest.php deleted file mode 100644 index 91f45df83fc..00000000000 --- a/tests/PHPStanStaticTypeMapper/TypeMapper/NonexistentParentClassTypeMapperTest.php +++ /dev/null @@ -1,27 +0,0 @@ -phpStanStaticTypeMapper = $this->make(PHPStanStaticTypeMapper::class); - } - - public function testMapToPHPStanPhpDocTypeNode(): void - { - $typeNode = $this->phpStanStaticTypeMapper->mapToPHPStanPhpDocTypeNode(new NonexistentParentClassType()); - $this->assertSame('parent', (string) $typeNode); - } -} diff --git a/tests/PHPStanStaticTypeMapper/TypeMapperOrderTest.php b/tests/PHPStanStaticTypeMapper/TypeMapperOrderTest.php deleted file mode 100644 index 3a357eec35a..00000000000 --- a/tests/PHPStanStaticTypeMapper/TypeMapperOrderTest.php +++ /dev/null @@ -1,38 +0,0 @@ -phpStanStaticTypeMapper = $this->make(PHPStanStaticTypeMapper::class); - } - - /** - * The most specific mapper wins regardless of registration order: ClassStringType extends - * StringType, so the ClassStringType mapper must match it over the StringType one. - */ - public function testMostSpecificMapperWinsOverParent(): void - { - $typeNode = $this->phpStanStaticTypeMapper->mapToPHPStanPhpDocTypeNode(new ClassStringType()); - $this->assertSame('class-string', (string) $typeNode); - } - - public function testParentMapperStillMatchesParentType(): void - { - $typeNode = $this->phpStanStaticTypeMapper->mapToPHPStanPhpDocTypeNode(new StringType()); - $this->assertSame('string', (string) $typeNode); - } -}