diff --git a/packages/PHPStanStaticTypeMapper/src/PHPStanStaticTypeMapper.php b/packages/PHPStanStaticTypeMapper/src/PHPStanStaticTypeMapper.php index d8ca4c7e8ed7..83fc115ec8d4 100644 --- a/packages/PHPStanStaticTypeMapper/src/PHPStanStaticTypeMapper.php +++ b/packages/PHPStanStaticTypeMapper/src/PHPStanStaticTypeMapper.php @@ -37,7 +37,6 @@ use PHPStan\Type\VoidType; use Rector\AttributeAwarePhpDoc\Ast\Type\AttributeAwareUnionTypeNode; use Rector\Exception\NotImplementedException; -use Rector\Exception\ShouldNotHappenException; use Rector\NodeTypeResolver\ClassExistenceStaticHelper; use Rector\Php\PhpVersionProvider; use Rector\PHPStan\Type\AliasedObjectType; @@ -47,7 +46,6 @@ use Rector\PHPStanStaticTypeMapper\Contract\PHPStanStaticTypeMapperAwareInterface; use Rector\PHPStanStaticTypeMapper\Contract\TypeMapperInterface; use Rector\ValueObject\PhpVersionFeature; -use Traversable; final class PHPStanStaticTypeMapper { @@ -103,19 +101,6 @@ public function mapToPHPStanPhpDocTypeNode(Type $type): TypeNode */ public function mapToPhpParserNode(Type $phpStanType, ?string $kind = null): ?Node { - if ($phpStanType instanceof VoidType) { - if ($this->phpVersionProvider->isAtLeast(PhpVersionFeature::VOID_TYPE)) { - if (in_array($kind, ['param', 'property'], true)) { - // param cannot be void - return null; - } - - return new Identifier('void'); - } - - return null; - } - if ($phpStanType instanceof SelfObjectType) { return new Identifier('self'); } @@ -126,7 +111,7 @@ public function mapToPhpParserNode(Type $phpStanType, ?string $kind = null): ?No continue; } - return $typeMapper->mapToPhpParserNode($phpStanType); + return $typeMapper->mapToPhpParserNode($phpStanType, $kind); } if ($phpStanType instanceof ArrayType) { @@ -137,14 +122,6 @@ public function mapToPhpParserNode(Type $phpStanType, ?string $kind = null): ?No return null; } - if ($phpStanType instanceof CallableType || $phpStanType instanceof ClosureType) { - if ($kind === 'property') { - return null; - } - - return new Identifier('callable'); - } - if ($phpStanType instanceof TypeWithClassName) { $lowerCasedClassName = strtolower($phpStanType->getClassName()); if ($lowerCasedClassName === 'callable') { @@ -166,50 +143,6 @@ public function mapToPhpParserNode(Type $phpStanType, ?string $kind = null): ?No return new FullyQualified($phpStanType->getClassName()); } - if ($phpStanType instanceof UnionType) { - // match array types - $arrayNode = $this->matchArrayTypes($phpStanType); - if ($arrayNode !== null) { - return $arrayNode; - } - - // special case for nullable - $nullabledType = $this->matchTypeForNullableUnionType($phpStanType); - if ($nullabledType === null) { - // use first unioned type in case of unioned object types - return $this->matchTypeForUnionedObjectTypes($phpStanType); - } - - $nullabledTypeNode = $this->mapToPhpParserNode($nullabledType); - if ($nullabledTypeNode === null) { - return null; - } - - if ($nullabledTypeNode instanceof NullableType) { - return $nullabledTypeNode; - } - - if ($nullabledTypeNode instanceof PhpParserUnionType) { - throw new ShouldNotHappenException(); - } - - return new NullableType($nullabledTypeNode); - } - - if ($phpStanType instanceof VoidType || - $phpStanType instanceof ResourceType - ) { - return null; - } - - if ($phpStanType instanceof ObjectWithoutClassType) { - if ($this->phpVersionProvider->isAtLeast(PhpVersionFeature::OBJECT_TYPE)) { - return new Identifier('object'); - } - - return null; - } - throw new NotImplementedException(__METHOD__ . ' for ' . get_class($phpStanType)); } @@ -340,123 +273,4 @@ private function convertUnionArrayTypeNodesToArrayTypeOfUnionTypeNodes( return new AttributeAwareUnionTypeNode($unionedArrayType); } - - private function matchTypeForNullableUnionType(UnionType $unionType): ?Type - { - if (count($unionType->getTypes()) !== 2) { - return null; - } - - $firstType = $unionType->getTypes()[0]; - $secondType = $unionType->getTypes()[1]; - - if ($firstType instanceof NullType) { - return $secondType; - } - - if ($secondType instanceof NullType) { - return $firstType; - } - - return null; - } - - /** - * @return Name|FullyQualified|PhpParserUnionType|null - */ - private function matchTypeForUnionedObjectTypes(UnionType $unionType): ?Node - { - $phpParserUnionType = $this->matchPhpParserUnionType($unionType); - if ($phpParserUnionType !== null) { - return $phpParserUnionType; - } - - // do the type should be compatible with all other types, e.g. A extends B, B - foreach ($unionType->getTypes() as $unionedType) { - if (! $unionedType instanceof TypeWithClassName) { - return null; - } - - foreach ($unionType->getTypes() as $nestedUnionedType) { - if (! $nestedUnionedType instanceof TypeWithClassName) { - return null; - } - - if (! $this->areTypeWithClassNamesRelated($unionedType, $nestedUnionedType)) { - continue 2; - } - } - - return new FullyQualified($unionedType->getClassName()); - } - - return null; - } - - private function areTypeWithClassNamesRelated(TypeWithClassName $firstType, TypeWithClassName $secondType): bool - { - if (is_a($firstType->getClassName(), $secondType->getClassName(), true)) { - return true; - } - - return is_a($secondType->getClassName(), $firstType->getClassName(), true); - } - - private function matchArrayTypes(UnionType $unionType): ?Identifier - { - $isNullableType = false; - $hasIterable = false; - - foreach ($unionType->getTypes() as $unionedType) { - if ($unionedType instanceof IterableType) { - $hasIterable = true; - continue; - } - - if ($unionedType instanceof ArrayType) { - continue; - } - - if ($unionedType instanceof NullType) { - $isNullableType = true; - continue; - } - - if ($unionedType instanceof ObjectType) { - if ($unionedType->getClassName() === Traversable::class) { - $hasIterable = true; - continue; - } - } - - return null; - } - - $type = $hasIterable ? 'iterable' : 'array'; - if ($isNullableType) { - return new Identifier('?' . $type); - } - - return new Identifier($type); - } - - private function matchPhpParserUnionType(UnionType $unionType): ?PhpParserUnionType - { - if (! $this->phpVersionProvider->isAtLeast(PhpVersionFeature::UNION_TYPES)) { - return null; - } - - $phpParserUnionedTypes = []; - foreach ($unionType->getTypes() as $unionedType) { - /** @var Identifier|Name|null $phpParserNode */ - $phpParserNode = $this->mapToPhpParserNode($unionedType); - if ($phpParserNode === null) { - return null; - } - - $phpParserUnionedTypes[] = $phpParserNode; - } - - return new PhpParserUnionType($phpParserUnionedTypes); - } } diff --git a/packages/PHPStanStaticTypeMapper/src/TypeMapper/CallableTypeMapper.php b/packages/PHPStanStaticTypeMapper/src/TypeMapper/CallableTypeMapper.php new file mode 100644 index 000000000000..7f64a40d1829 --- /dev/null +++ b/packages/PHPStanStaticTypeMapper/src/TypeMapper/CallableTypeMapper.php @@ -0,0 +1,41 @@ +phpVersionProvider = $phpVersionProvider; + } + + public function getNodeClass(): string + { + return ObjectWithoutClassType::class; + } + + /** + * @param ObjectWithoutClassType $type + */ + public function mapToPHPStanPhpDocTypeNode(Type $type): TypeNode + { + return new IdentifierTypeNode('object'); + } + + /** + * @param ObjectWithoutClassType $type + */ + public function mapToPhpParserNode(Type $type, ?string $kind = null): ?Node + { + if (! $this->phpVersionProvider->isAtLeast(PhpVersionFeature::OBJECT_TYPE)) { + return null; + } + + return new Identifier('object'); + } +} diff --git a/packages/PHPStanStaticTypeMapper/src/TypeMapper/ResourceTypeMapper.php b/packages/PHPStanStaticTypeMapper/src/TypeMapper/ResourceTypeMapper.php new file mode 100644 index 000000000000..67c46764c4c7 --- /dev/null +++ b/packages/PHPStanStaticTypeMapper/src/TypeMapper/ResourceTypeMapper.php @@ -0,0 +1,36 @@ +phpVersionProvider = $phpVersionProvider; + } + + public function getNodeClass(): string + { + return VoidType::class; + } + + /** + * @param VoidType $type + */ + public function mapToPHPStanPhpDocTypeNode(Type $type): TypeNode + { + return new IdentifierTypeNode('void'); + } + + /** + * @param VoidType $type + */ + public function mapToPhpParserNode(Type $type, ?string $kind = null): ?Node + { + if (! $this->phpVersionProvider->isAtLeast(PhpVersionFeature::VOID_TYPE)) { + return null; + } + + if (in_array($kind, ['param', 'property'], true)) { + return null; + } + + return new Identifier('void'); + } +}