mirror of
https://github.com/rectorphp/rector.git
synced 2025-04-20 15:31:58 +02:00
Merge pull request #2534 from rectorphp/generic
improve generic type conversion
This commit is contained in:
commit
24173b0290
@ -611,7 +611,6 @@ final class StaticTypeMapper
|
||||
}
|
||||
|
||||
// @todo improve - making many false positives now
|
||||
|
||||
$objectType = new ObjectType($typeNode->name);
|
||||
|
||||
return $this->objectTypeSpecifier->narrowToFullyQualifiedOrAlaisedObjectType($node, $objectType);
|
||||
@ -644,45 +643,33 @@ final class StaticTypeMapper
|
||||
}
|
||||
|
||||
if ($typeNode instanceof GenericTypeNode) {
|
||||
if ($typeNode->type instanceof IdentifierTypeNode) {
|
||||
$typeName = $typeNode->type->name;
|
||||
$genericMainType = $this->mapPHPStanPhpDocTypeNodeToPHPStanType($typeNode->type, $node);
|
||||
|
||||
// remove extra prefix
|
||||
$typeName = ltrim($typeName, '\\');
|
||||
if ($genericMainType instanceof TypeWithClassName) {
|
||||
$mainTypeAsString = $genericMainType->getClassName();
|
||||
} else {
|
||||
$mainTypeAsString = $typeNode->type->name;
|
||||
}
|
||||
|
||||
if (in_array($typeName, ['array', 'iterable', 'Traversable'], true)) {
|
||||
$genericTypes = [];
|
||||
foreach ($typeNode->genericTypes as $genericTypeNode) {
|
||||
$genericTypes[] = $this->mapPHPStanPhpDocTypeNodeToPHPStanType($genericTypeNode, $node);
|
||||
}
|
||||
$genericTypes = [];
|
||||
foreach ($typeNode->genericTypes as $genericTypeNode) {
|
||||
$genericTypes[] = $this->mapPHPStanPhpDocTypeNodeToPHPStanType($genericTypeNode, $node);
|
||||
}
|
||||
|
||||
$genericType = $this->typeFactory->createMixedPassedOrUnionType($genericTypes);
|
||||
// special use case for array
|
||||
if (in_array($mainTypeAsString, ['array', 'iterable'], true)) {
|
||||
$genericType = $this->typeFactory->createMixedPassedOrUnionType($genericTypes);
|
||||
|
||||
if ($typeName === 'array') {
|
||||
return new ArrayType(new MixedType(), $genericType);
|
||||
}
|
||||
|
||||
if ($typeName === 'Traversable') {
|
||||
return new ObjectType('Traversable');
|
||||
}
|
||||
if ($mainTypeAsString === 'array') {
|
||||
return new ArrayType(new MixedType(), $genericType);
|
||||
}
|
||||
|
||||
if ($mainTypeAsString === 'iterable') {
|
||||
return new IterableType(new MixedType(), $genericType);
|
||||
}
|
||||
}
|
||||
|
||||
$mainType = $this->mapPHPStanPhpDocTypeNodeToPHPStanType($typeNode->type, $node);
|
||||
if ($mainType instanceof TypeWithClassName) {
|
||||
$className = $mainType->getClassName();
|
||||
} else {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
$genericTypes = [];
|
||||
foreach ($typeNode->genericTypes as $genericType) {
|
||||
$genericTypes[] = $this->mapPHPStanPhpDocTypeNodeToPHPStanType($genericType, $node);
|
||||
}
|
||||
|
||||
return new GenericObjectType($className, $genericTypes);
|
||||
return new GenericObjectType($mainTypeAsString, $genericTypes);
|
||||
}
|
||||
|
||||
throw new NotImplementedException(__METHOD__ . ' for ' . get_class($typeNode));
|
||||
|
@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\NodeTypeResolver\Tests\StaticTypeMapper;
|
||||
|
||||
use Iterator;
|
||||
use PhpParser\Node\Scalar\String_;
|
||||
use PHPStan\PhpDocParser\Ast\Type\GenericTypeNode;
|
||||
use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
|
||||
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
|
||||
use PHPStan\Type\Generic\GenericObjectType;
|
||||
use PHPStan\Type\IterableType;
|
||||
use Rector\HttpKernel\RectorKernel;
|
||||
use Rector\NodeTypeResolver\StaticTypeMapper;
|
||||
use Symplify\PackageBuilder\Tests\AbstractKernelTestCase;
|
||||
|
||||
final class StaticTypeMapperTest extends AbstractKernelTestCase
|
||||
{
|
||||
/**
|
||||
* @var StaticTypeMapper
|
||||
*/
|
||||
private $staticTypeMapper;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->bootKernel(RectorKernel::class);
|
||||
|
||||
$this->staticTypeMapper = self::$container->get(StaticTypeMapper::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider provideDataForMapPHPStanPhpDocTypeNodeToPHPStanType()
|
||||
*/
|
||||
public function testMapPHPStanPhpDocTypeNodeToPHPStanType(TypeNode $typeNode, string $expectedType): void
|
||||
{
|
||||
$node = new String_('hey');
|
||||
|
||||
$phpStanType = $this->staticTypeMapper->mapPHPStanPhpDocTypeNodeToPHPStanType($typeNode, $node);
|
||||
|
||||
$this->assertInstanceOf($expectedType, $phpStanType);
|
||||
}
|
||||
|
||||
public function provideDataForMapPHPStanPhpDocTypeNodeToPHPStanType(): Iterator
|
||||
{
|
||||
$genericTypeNode = new GenericTypeNode(new IdentifierTypeNode('Traversable'), []);
|
||||
yield [$genericTypeNode, GenericObjectType::class];
|
||||
|
||||
$genericTypeNode = new GenericTypeNode(new IdentifierTypeNode('iterable'), []);
|
||||
yield [$genericTypeNode, IterableType::class];
|
||||
}
|
||||
}
|
@ -243,7 +243,7 @@ parameters:
|
||||
|
||||
- '#Method Rector\\BetterPhpDocParser\\PhpDocNodeFactory\\Gedmo\\(.*?)\:\:createFromNodeAndTokens\(\) should return Rector\\BetterPhpDocParser\\PhpDocNode\\Gedmo\\(.*?)\|null but returns PHPStan\\PhpDocParser\\Ast\\PhpDoc\\PhpDocTagValueNode\|null#'
|
||||
|
||||
|
||||
|
||||
- '#Access to an undefined property PhpParser\\Node\\Identifier\|PhpParser\\Node\\Name\|PhpParser\\Node\\NullableType\:\:\$type#'
|
||||
- '#Call to an undefined method PhpParser\\Node\\Identifier\|PhpParser\\Node\\Name\|PhpParser\\Node\\NullableType\:\:toString\(\)#'
|
||||
- '#Parameter \#1 \$expected of method PHPUnit\\Framework\\Assert\:\:assertInstanceOf\(\) expects class\-string<object\>, string given#'
|
||||
- '#Unable to resolve the template type ExpectedType in call to method PHPUnit\\Framework\\Assert\:\:assertInstanceOf\(\)#'
|
||||
|
Loading…
x
Reference in New Issue
Block a user