[Php74] Handle Generic Type on TypedPropertyRector (#6378)

Co-authored-by: Ruud Kamphuis <ruudk@users.noreply.github.com>
Co-authored-by: kaizen-ci <info@kaizen-ci.org>
This commit is contained in:
Abdul Malik Ikhsan 2021-05-07 08:01:46 +07:00 committed by GitHub
parent 85c87561aa
commit 6bae0256e3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 86 additions and 15 deletions

View File

@ -0,0 +1,47 @@
<?php
namespace Rector\Php74\Tests\Rector\Property\TypedPropertyRector\Fixture;
/**
* @template T of object
*/
final class GenericObjectType
{
/**
* @var T
*/
private $command;
/**
* @param T $command
*/
public function __construct(object $command)
{
$this->command = $command;
}
}
?>
-----
<?php
namespace Rector\Php74\Tests\Rector\Property\TypedPropertyRector\Fixture;
/**
* @template T of object
*/
final class GenericObjectType
{
/**
* @var T
*/
private object $command;
/**
* @param T $command
*/
public function __construct(object $command)
{
$this->command = $command;
}
}
?>

View File

@ -10,6 +10,7 @@ use PhpParser\Node\NullableType;
use PhpParser\Node\Stmt\Property;
use PhpParser\Node\UnionType as PhpParserUnionType;
use PHPStan\Reflection\ReflectionProvider;
use PHPStan\Type\Generic\TemplateType;
use PHPStan\Type\MixedType;
use PHPStan\Type\NullType;
use PHPStan\Type\Type;
@ -149,26 +150,23 @@ CODE_SAMPLE
return null;
}
if ($varType instanceof UnionType) {
$types = $varType->getTypes();
if (count($types) === 2 && $types[0] instanceof TemplateType) {
$node->type = $this->staticTypeMapper->mapPHPStanTypeToPhpParserNode(
$types[0]->getBound(),
TypeKind::KIND_PROPERTY
);
return $node;
}
}
$propertyTypeNode = $this->staticTypeMapper->mapPHPStanTypeToPhpParserNode(
$varType,
TypeKind::KIND_PROPERTY
);
if (! $propertyTypeNode instanceof Node) {
return null;
}
// is not class-type and should be skipped
if ($this->shouldSkipNonClassLikeType($propertyTypeNode)) {
return null;
}
// false positive
if ($propertyTypeNode instanceof Name && $this->isName($propertyTypeNode, 'mixed')) {
return null;
}
if ($this->vendorLockResolver->isPropertyTypeChangeVendorLockedIn($node)) {
if ($this->isNullOrNonClassLikeTypeOrMixedOrVendorLockedIn($propertyTypeNode, $node)) {
return null;
}
@ -186,6 +184,32 @@ CODE_SAMPLE
$this->classLikeTypeOnly = $configuration[self::CLASS_LIKE_TYPE_ONLY] ?? false;
}
/**
* @param Name|NullableType|PhpParserUnionType|null $node
*/
private function isNullOrNonClassLikeTypeOrMixedOrVendorLockedIn(?Node $node, Property $property): bool
{
if (! $node instanceof Node) {
return true;
}
// is not class-type and should be skipped
if ($this->shouldSkipNonClassLikeType($node)) {
return true;
}
// false positive
if (! $node instanceof Name) {
return $this->vendorLockResolver->isPropertyTypeChangeVendorLockedIn($property);
}
if (! $this->isName($node, 'mixed')) {
return $this->vendorLockResolver->isPropertyTypeChangeVendorLockedIn($property);
}
return true;
}
/**
* @param Name|NullableType|PhpParserUnionType $node
*/