Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 4 additions & 16 deletions src/DependencyInjection/LazyContainerFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -135,10 +135,8 @@
use Rector\PhpParser\NodeVisitor\SymfonyClosureNodeVisitor;
use Rector\PHPStanStaticTypeMapper\Contract\TypeMapperInterface;
use Rector\PHPStanStaticTypeMapper\PHPStanStaticTypeMapper;
use Rector\PHPStanStaticTypeMapper\TypeMapper\AccessoryLiteralStringTypeMapper;
use Rector\PHPStanStaticTypeMapper\TypeMapper\AccessoryNonEmptyStringTypeMapper;
use Rector\PHPStanStaticTypeMapper\TypeMapper\AccessoryNonFalsyStringTypeMapper;
use Rector\PHPStanStaticTypeMapper\TypeMapper\AccessoryNumericStringTypeMapper;
use Rector\PHPStanStaticTypeMapper\TypeMapper\AccessoryArrayTypeMapper;
use Rector\PHPStanStaticTypeMapper\TypeMapper\AccessoryStringTypeMapper;
use Rector\PHPStanStaticTypeMapper\TypeMapper\ArrayTypeMapper;
use Rector\PHPStanStaticTypeMapper\TypeMapper\BooleanTypeMapper;
use Rector\PHPStanStaticTypeMapper\TypeMapper\CallableTypeMapper;
Expand All @@ -149,19 +147,15 @@
use Rector\PHPStanStaticTypeMapper\TypeMapper\ConstantArrayTypeMapper;
use Rector\PHPStanStaticTypeMapper\TypeMapper\FloatTypeMapper;
use Rector\PHPStanStaticTypeMapper\TypeMapper\HasMethodTypeMapper;
use Rector\PHPStanStaticTypeMapper\TypeMapper\HasOffsetTypeMapper;
use Rector\PHPStanStaticTypeMapper\TypeMapper\HasOffsetValueTypeTypeMapper;
use Rector\PHPStanStaticTypeMapper\TypeMapper\HasPropertyTypeMapper;
use Rector\PHPStanStaticTypeMapper\TypeMapper\IntegerTypeMapper;
use Rector\PHPStanStaticTypeMapper\TypeMapper\IntersectionTypeMapper;
use Rector\PHPStanStaticTypeMapper\TypeMapper\IterableTypeMapper;
use Rector\PHPStanStaticTypeMapper\TypeMapper\MixedTypeMapper;
use Rector\PHPStanStaticTypeMapper\TypeMapper\NeverTypeMapper;
use Rector\PHPStanStaticTypeMapper\TypeMapper\NonEmptyArrayTypeMapper;
use Rector\PHPStanStaticTypeMapper\TypeMapper\NullTypeMapper;
use Rector\PHPStanStaticTypeMapper\TypeMapper\ObjectTypeMapper;
use Rector\PHPStanStaticTypeMapper\TypeMapper\ObjectWithoutClassTypeMapper;
use Rector\PHPStanStaticTypeMapper\TypeMapper\OversizedArrayTypeMapper;
use Rector\PHPStanStaticTypeMapper\TypeMapper\ParentStaticTypeMapper;
use Rector\PHPStanStaticTypeMapper\TypeMapper\ResourceTypeMapper;
use Rector\PHPStanStaticTypeMapper\TypeMapper\StaticTypeMapper;
Expand Down Expand Up @@ -287,10 +281,8 @@ final class LazyContainerFactory
* @var array<class-string<TypeMapperInterface>>
*/
private const array TYPE_MAPPER_CLASSES = [
AccessoryLiteralStringTypeMapper::class,
AccessoryNonEmptyStringTypeMapper::class,
AccessoryNonFalsyStringTypeMapper::class,
AccessoryNumericStringTypeMapper::class,
AccessoryArrayTypeMapper::class,
AccessoryStringTypeMapper::class,
ConstantArrayTypeMapper::class,
ArrayTypeMapper::class,
BooleanTypeMapper::class,
Expand All @@ -301,19 +293,15 @@ final class LazyContainerFactory
ConditionalTypeMapper::class,
FloatTypeMapper::class,
HasMethodTypeMapper::class,
HasOffsetTypeMapper::class,
HasOffsetValueTypeTypeMapper::class,
HasPropertyTypeMapper::class,
IntegerTypeMapper::class,
IntersectionTypeMapper::class,
IterableTypeMapper::class,
MixedTypeMapper::class,
NeverTypeMapper::class,
NonEmptyArrayTypeMapper::class,
NullTypeMapper::class,
ObjectTypeMapper::class,
ObjectWithoutClassTypeMapper::class,
OversizedArrayTypeMapper::class,
ParentStaticTypeMapper::class,
ResourceTypeMapper::class,
StaticTypeMapper::class,
Expand Down
7 changes: 5 additions & 2 deletions src/PHPStanStaticTypeMapper/Contract/TypeMapperInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,12 @@
interface TypeMapperInterface
{
/**
* @return class-string<TType>
* A mapper can cover several types at once, when they all map to the same output,
* e.g. every accessory string type maps to "string"
*
* @return array<class-string<TType>>
*/
public function getNodeClass(): string;
public function getNodeClasses(): array;

/**
* @param TType $type
Expand Down
12 changes: 10 additions & 2 deletions src/PHPStanStaticTypeMapper/PHPStanStaticTypeMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public function __construct(
public function mapToPHPStanPhpDocTypeNode(Type $type): TypeNode
{
foreach ($this->typeMappers as $typeMapper) {
if (! is_a($type, $typeMapper->getNodeClass(), true)) {
if (! $this->doesTypeMatch($type, $typeMapper)) {
continue;
}

Expand All @@ -44,7 +44,7 @@ public function mapToPHPStanPhpDocTypeNode(Type $type): TypeNode
public function mapToPhpParserNode(Type $type, string $typeKind): Name|ComplexType|Identifier|null
{
foreach ($this->typeMappers as $typeMapper) {
if (! is_a($type, $typeMapper->getNodeClass(), true)) {
if (! $this->doesTypeMatch($type, $typeMapper)) {
continue;
}

Expand All @@ -53,4 +53,12 @@ public function mapToPhpParserNode(Type $type, string $typeKind): Name|ComplexTy

throw new NotImplementedYetException(__METHOD__ . ' for ' . $type::class);
}

/**
* @param TypeMapperInterface<Type> $typeMapper
*/
private function doesTypeMatch(Type $type, TypeMapperInterface $typeMapper): bool
{
return array_any($typeMapper->getNodeClasses(), fn (string $nodeClass): bool => $type instanceof $nodeClass);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

declare(strict_types=1);

namespace Rector\PHPStanStaticTypeMapper\TypeMapper;

use PhpParser\Node\Identifier;
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
use PHPStan\Type\Accessory\HasOffsetType;
use PHPStan\Type\Accessory\HasOffsetValueType;
use PHPStan\Type\Accessory\NonEmptyArrayType;
use PHPStan\Type\Accessory\OversizedArrayType;
use PHPStan\Type\Type;
use Rector\PHPStanStaticTypeMapper\Contract\TypeMapperInterface;

/**
* Every accessory array type narrows "array" with an extra guarantee, so they all map back to "array"
*
* @implements TypeMapperInterface<HasOffsetType|HasOffsetValueType|NonEmptyArrayType|OversizedArrayType>
*/
final class AccessoryArrayTypeMapper implements TypeMapperInterface
{
/**
* @return array<class-string<Type>>
*/
public function getNodeClasses(): array
{
return [
HasOffsetType::class,
HasOffsetValueType::class,
NonEmptyArrayType::class,
OversizedArrayType::class,
];
}

public function mapToPHPStanPhpDocTypeNode(Type $type): TypeNode
{
return $type->toPhpDocNode();
}

public function mapToPhpParserNode(Type $type, string $typeKind): Identifier
{
return new Identifier('array');
}
}

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -7,38 +7,45 @@
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\PhpVersionFeature;

/**
* @implements TypeMapperInterface<AccessoryNonEmptyStringType>
* Every accessory string type narrows "string" with an extra guarantee, so they all map back to "string"
*
* @implements TypeMapperInterface<AccessoryLiteralStringType|AccessoryNonEmptyStringType|AccessoryNonFalsyStringType|AccessoryNumericStringType>
*/
final readonly class AccessoryNonEmptyStringTypeMapper implements TypeMapperInterface
final readonly class AccessoryStringTypeMapper implements TypeMapperInterface
{
public function __construct(
private PhpVersionProvider $phpVersionProvider
) {
}

public function getNodeClass(): string
/**
* @return array<class-string<Type>>
*/
public function getNodeClasses(): array
{
return AccessoryNonEmptyStringType::class;
return [
AccessoryLiteralStringType::class,
AccessoryNonEmptyStringType::class,
AccessoryNonFalsyStringType::class,
AccessoryNumericStringType::class,
];
}

/**
* @param AccessoryNonEmptyStringType $type
*/
public function mapToPHPStanPhpDocTypeNode(Type $type): TypeNode
{
return $type->toPhpDocNode();
}

/**
* @param AccessoryNonEmptyStringType $type
*/
public function mapToPhpParserNode(Type $type, string $typeKind): ?Node
{
if (! $this->phpVersionProvider->isAtLeastPhpVersion(PhpVersionFeature::SCALAR_TYPES)) {
Expand Down
7 changes: 5 additions & 2 deletions src/PHPStanStaticTypeMapper/TypeMapper/ArrayTypeMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,12 @@ public function autowire(PHPStanStaticTypeMapper $phpStanStaticTypeMapper): void
$this->phpStanStaticTypeMapper = $phpStanStaticTypeMapper;
}

public function getNodeClass(): string
/**
* @return array<class-string<Type>>
*/
public function getNodeClasses(): array
{
return ArrayType::class;
return [ArrayType::class];
}

/**
Expand Down
7 changes: 5 additions & 2 deletions src/PHPStanStaticTypeMapper/TypeMapper/BooleanTypeMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,12 @@ public function __construct(
) {
}

public function getNodeClass(): string
/**
* @return array<class-string<Type>>
*/
public function getNodeClasses(): array
{
return BooleanType::class;
return [BooleanType::class];
}

/**
Expand Down
Loading
Loading