[TypeDeclaration] Prevent array-iterable-Iterator override in ReturnTypeDeclarationRector

This commit is contained in:
Tomas Votruba 2019-10-12 18:39:58 +02:00
parent 6c8f13a8b5
commit d6d337e85e
3 changed files with 65 additions and 1 deletions

View File

@ -2,12 +2,18 @@
namespace Rector\TypeDeclaration\Rector\FunctionLike;
use Iterator;
use PhpParser\Node;
use PhpParser\Node\Stmt\ClassLike;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Function_;
use PHPStan\Type\ArrayType;
use PHPStan\Type\IntersectionType;
use PHPStan\Type\IterableType;
use PHPStan\Type\MixedType;
use PHPStan\Type\ObjectType;
use PHPStan\Type\Type;
use PHPStan\Type\UnionType;
use Rector\Exception\ShouldNotHappenException;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\RectorDefinition\CodeSample;
@ -230,7 +236,12 @@ PHP
return false;
}
if ($this->print($node->returnType) === $this->print($returnNode)) {
if ($this->areNodesEqual($node->returnType, $returnNode)) {
return true;
}
// is array <=> iterable <=> Iterator co-type? → skip
if ($this->isArrayIterableIteratorCoType($node, $returnType)) {
return true;
}
@ -244,4 +255,42 @@ PHP
return false;
}
private function isStaticTypeIterable(Type $type): bool
{
if ($type instanceof ArrayType) {
return true;
}
if ($type instanceof IterableType) {
return true;
}
if ($type instanceof ObjectType) {
if ($type->getClassName() === Iterator::class) {
return true;
}
}
if ($type instanceof UnionType || $type instanceof IntersectionType) {
foreach ($type->getTypes() as $joinedType) {
if (! $this->isStaticTypeIterable($joinedType)) {
return false;
}
}
return true;
}
return false;
}
private function isArrayIterableIteratorCoType(Node $node, Type $returnType): bool
{
if (! $this->isNames($node->returnType, ['iterable', 'Iterator', 'array'])) {
return false;
}
return $this->isStaticTypeIterable($returnType);
}
}

View File

@ -0,0 +1,13 @@
<?php
namespace Rector\TypeDeclaration\Tests\Rector\ClassMethod\ReturnTypeDeclarationRector\Fixture;
use Iterator;
class SkipIterableArrayIteratorCoType
{
public function run(): Iterator
{
yield 5;
}
}

View File

@ -60,6 +60,8 @@ final class ReturnTypeDeclarationRectorTest extends AbstractRectorTestCase
yield [__DIR__ . '/Fixture/dunglas/nullable_types.php.inc'];
// anonymous class
yield [__DIR__ . '/Fixture/a_new_class.php.inc'];
yield [__DIR__ . '/Fixture/skip_iterable_array_iterator_co_type.php.inc'];
}
protected function getRectorClass(): string