fix union type on ReturnTypeDeclarationRector

This commit is contained in:
TomasVotruba 2020-03-23 19:30:43 +01:00
parent 2c3f676191
commit 070c41d7c9
2 changed files with 63 additions and 6 deletions

View File

@ -6,12 +6,17 @@ namespace Rector\TypeDeclaration\TypeAlreadyAddedChecker;
use Iterator;
use PhpParser\Node;
use PhpParser\Node\Identifier;
use PhpParser\Node\Name;
use PhpParser\Node\NullableType;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Function_;
use PhpParser\Node\UnionType as PhpParserUnionType;
use PHPStan\Type\ArrayType;
use PHPStan\Type\Generic\GenericObjectType;
use PHPStan\Type\IntersectionType;
use PHPStan\Type\IterableType;
use PHPStan\Type\NullType;
use PHPStan\Type\ObjectType;
use PHPStan\Type\Type;
use PHPStan\Type\UnionType;
@ -57,17 +62,24 @@ final class ReturnTypeAlreadyAddedChecker
*/
public function isReturnTypeAlreadyAdded(Node $node, Type $returnType): bool
{
$returnNode = $this->staticTypeMapper->mapPHPStanTypeToPhpParserNode($returnType);
if ($node->returnType === null) {
$nodeReturnType = $node->returnType;
/** @param Identifier|Name|NullableType|PhpParserUnionType|null $returnTypeNode */
if ($nodeReturnType === null) {
return false;
}
if ($this->betterStandardPrinter->areNodesEqual($node->returnType, $returnNode)) {
$returnNode = $this->staticTypeMapper->mapPHPStanTypeToPhpParserNode($returnType);
if ($this->betterStandardPrinter->areNodesEqual($nodeReturnType, $returnNode)) {
return true;
}
// is array <=> iterable <=> Iterator co-type? → skip
if ($this->isArrayIterableIteratorCoType($node, $returnType)) {
if ($this->isArrayIterableIteratorCoType($nodeReturnType, $returnType)) {
return true;
}
if ($this->isUnionCoType($nodeReturnType, $returnType)) {
return true;
}
@ -87,9 +99,12 @@ final class ReturnTypeAlreadyAddedChecker
return false;
}
private function isArrayIterableIteratorCoType(Node $node, Type $returnType): bool
/**
* @param Identifier|Name|NullableType|PhpParserUnionType $returnTypeNode
*/
private function isArrayIterableIteratorCoType(Node $returnTypeNode, Type $returnType): bool
{
if (! $this->nodeNameResolver->isNames($node->returnType, self::FOREACHABLE_TYPES)) {
if (! $this->nodeNameResolver->isNames($returnTypeNode, self::FOREACHABLE_TYPES)) {
return false;
}
@ -127,4 +142,23 @@ final class ReturnTypeAlreadyAddedChecker
return $type instanceof ObjectType && $type->getClassName() === Iterator::class;
}
/**
* @param Identifier|Name|NullableType|PhpParserUnionType $returnTypeNode
*/
private function isUnionCoType(Node $returnTypeNode, Type $type): bool
{
if (! $type instanceof UnionType) {
return false;
}
// skip nullable type
$nullType = new NullType();
if ($type->isSuperTypeOf($nullType)->yes()) {
return false;
}
$classMethodReturnType = $this->staticTypeMapper->mapPhpParserNodePHPStanType($returnTypeNode);
return $type->isSuperTypeOf($classMethodReturnType)->yes();
}
}

View File

@ -0,0 +1,23 @@
<?php
namespace Rector\TypeDeclaration\Tests\Rector\ClassMethod\ReturnTypeDeclarationRector\Fixture;
class Response
{
}
final class RedirectResponse extends Response
{
}
final class SkipParentAndChild
{
public function run(bool $response): Response
{
if ($response) {
return new RedirectResponse;
}
return new Response;
}
}