*/ final class IntersectionTypeMapper implements TypeMapperInterface { /** * @var \Rector\PHPStanStaticTypeMapper\PHPStanStaticTypeMapper */ private $phpStanStaticTypeMapper; /** * @readonly * @var \Rector\Core\Php\PhpVersionProvider */ private $phpVersionProvider; /** * @readonly * @var \PHPStan\Reflection\ReflectionProvider */ private $reflectionProvider; public function __construct(PhpVersionProvider $phpVersionProvider, ReflectionProvider $reflectionProvider) { $this->phpVersionProvider = $phpVersionProvider; $this->reflectionProvider = $reflectionProvider; } /** * @required */ public function autowire(PHPStanStaticTypeMapper $phpStanStaticTypeMapper) : void { $this->phpStanStaticTypeMapper = $phpStanStaticTypeMapper; } /** * @return class-string */ public function getNodeClass() : string { return IntersectionType::class; } /** * @param IntersectionType $type */ public function mapToPHPStanPhpDocTypeNode(Type $type, string $typeKind) : TypeNode { $intersectionTypesNodes = []; foreach ($type->getTypes() as $intersectionedType) { $intersectionTypesNodes[] = $this->phpStanStaticTypeMapper->mapToPHPStanPhpDocTypeNode($intersectionedType, $typeKind); } $intersectionTypesNodes = \array_unique($intersectionTypesNodes); if (\count($intersectionTypesNodes) === 1) { return $intersectionTypesNodes[0]; } return new BracketsAwareIntersectionTypeNode($intersectionTypesNodes); } /** * @param IntersectionType $type */ public function mapToPhpParserNode(Type $type, string $typeKind) : ?Node { if (!$this->phpVersionProvider->isAtLeastPhpVersion(PhpVersionFeature::INTERSECTION_TYPES)) { return null; } $intersectionedTypeNodes = []; foreach ($type->getTypes() as $intersectionedType) { $resolvedType = $this->phpStanStaticTypeMapper->mapToPhpParserNode($intersectionedType, $typeKind); if (!$resolvedType instanceof Name && !$resolvedType instanceof Identifier) { return null; } $resolvedTypeName = (string) $resolvedType; /** * ObjectWithoutClassType can happen when use along with \PHPStan\Type\Accessory\HasMethodType * Use "object" as returned type */ if ($intersectionedType instanceof ObjectWithoutClassType) { return $resolvedType; } if (!$intersectionedType instanceof ObjectType) { return null; } if (!$this->reflectionProvider->hasClass($resolvedTypeName)) { return null; } $intersectionedTypeNodes[] = $resolvedType; } if ($intersectionedTypeNodes === []) { return null; } if (\count($intersectionedTypeNodes) === 1) { return \current($intersectionedTypeNodes); } return new Node\IntersectionType($intersectionedTypeNodes); } }