[Php80] Handle UnionTypesRector on object and specific class/type in union type (#6237)

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-04-26 16:08:56 +07:00 committed by GitHub
parent 5cda5de4ac
commit 70de3a01cc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 121 additions and 8 deletions

View File

@ -0,0 +1,45 @@
<?php
namespace Rector\Tests\Php80\Rector\FunctionLike\UnionTypesRector\Fixture;
use DateTime;
final class ObjectAndSpecificClass
{
/**
* @param object|DateTime $message
*/
private function getMessage($message)
{
if ($message instanceof \DateTime) {
// do something special
}
return $message;
}
}
?>
-----
<?php
namespace Rector\Tests\Php80\Rector\FunctionLike\UnionTypesRector\Fixture;
use DateTime;
final class ObjectAndSpecificClass
{
/**
* @param object|DateTime $message
*/
private function getMessage(object $message)
{
if ($message instanceof \DateTime) {
// do something special
}
return $message;
}
}
?>

View File

@ -0,0 +1,19 @@
<?php
namespace Rector\Tests\Php80\Rector\FunctionLike\UnionTypesRector\Fixture;
final class ObjectAndStringType
{
/**
* @param object|string $message
*/
private function getMessage($message)
{
if ($message instanceof \DateTime) {
// do something special
}
return $message;
}
}
?>

View File

@ -8,14 +8,18 @@ use PhpParser\Node;
use PhpParser\Node\Expr\ArrowFunction;
use PhpParser\Node\Expr\Closure;
use PhpParser\Node\FunctionLike;
use PhpParser\Node\Name;
use PhpParser\Node\Param;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Function_;
use PhpParser\Node\UnionType as PhpParserUnionType;
use PHPStan\Type\ObjectWithoutClassType;
use PHPStan\Type\UnionType;
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo;
use Rector\Core\Rector\AbstractRector;
use Rector\DeadCode\PhpDoc\TagRemover\ParamTagRemover;
use Rector\DeadCode\PhpDoc\TagRemover\ReturnTagRemover;
use Rector\StaticTypeMapper\ValueObject\Type\FullyQualifiedObjectType;
use Rector\VendorLocker\NodeVendorLocker\ClassMethodParamVendorLockResolver;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
@ -25,6 +29,11 @@ use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
*/
final class UnionTypesRector extends AbstractRector
{
/**
* @var ClassMethodParamVendorLockResolver
*/
private $classMethodParamVendorLockResolver;
/**
* @var ReturnTagRemover
*/
@ -35,11 +44,6 @@ final class UnionTypesRector extends AbstractRector
*/
private $paramTagRemover;
/**
* @var ClassMethodParamVendorLockResolver
*/
private $classMethodParamVendorLockResolver;
public function __construct(
ReturnTagRemover $returnTagRemover,
ParamTagRemover $paramTagRemover,
@ -106,14 +110,17 @@ CODE_SAMPLE
return $node;
}
private function isVendorLocked(ClassMethod $classMethod): bool
{
return $this->classMethodParamVendorLockResolver->isVendorLocked($classMethod);
}
/**
* @param ClassMethod|Function_|Closure|ArrowFunction $functionLike
*/
private function refactorParamTypes(FunctionLike $functionLike, PhpDocInfo $phpDocInfo): void
{
if ($functionLike instanceof ClassMethod && $this->classMethodParamVendorLockResolver->isVendorLocked(
$functionLike
)) {
if ($functionLike instanceof ClassMethod && $this->isVendorLocked($functionLike)) {
return;
}
@ -129,6 +136,11 @@ CODE_SAMPLE
continue;
}
if ($this->hasObjectWithoutClassType($paramType)) {
$this->changeObjectWithoutClassType($param, $paramType);
continue;
}
$phpParserUnionType = $this->staticTypeMapper->mapPHPStanTypeToPhpParserNode($paramType);
if (! $phpParserUnionType instanceof PhpParserUnionType) {
continue;
@ -138,6 +150,43 @@ CODE_SAMPLE
}
}
private function changeObjectWithoutClassType(Param $param, UnionType $unionType): void
{
if (! $this->hasObjectWithoutClassTypeWithOnlyFullyQualifiedObjectType($unionType)) {
return;
}
$param->type = new Name('object');
}
private function hasObjectWithoutClassType(UnionType $unionType): bool
{
$types = $unionType->getTypes();
foreach ($types as $type) {
if ($type instanceof ObjectWithoutClassType) {
return true;
}
}
return false;
}
private function hasObjectWithoutClassTypeWithOnlyFullyQualifiedObjectType(UnionType $unionType): bool
{
$types = $unionType->getTypes();
foreach ($types as $type) {
if ($type instanceof ObjectWithoutClassType) {
continue;
}
if (! $type instanceof FullyQualifiedObjectType) {
return false;
}
}
return true;
}
/**
* @param ClassMethod|Function_|Closure|ArrowFunction $functionLike
*/