[TypeDeclaration] Use @return type on Generator on ReturnTypeDeclarationRector (#1794)

* Add failing test fixture for ReturnTypeDeclarationRector

# Failing Test for ReturnTypeDeclarationRector

Based on https://getrector.org/demo/1ec89bdc-a24f-68ce-b1af-894c7ad7ac39

* Closes #1792

* phpstan

* wrong type generator

* return Generator when no return type definition

* yield generator

* Fixed 🎉

* [ci-review] Rector Rectify

* final touch: add Generator example

Co-authored-by: Yann Eugoné <eugone.yann@gmail.com>
Co-authored-by: GitHub Action <action@github.com>
This commit is contained in:
Abdul Malik Ikhsan 2022-02-12 19:07:12 +07:00 committed by GitHub
parent 916adb2637
commit 3720a55f51
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 153 additions and 9 deletions

View File

@ -2,7 +2,7 @@
namespace Rector\Tests\TypeDeclaration\Rector\ClassMethod\AddArrayReturnDocTypeRector\Fixture;
final class ReturnYieldIterator
final class ReturnYieldGenerator
{
public function someMethod()
{
@ -16,10 +16,10 @@ final class ReturnYieldIterator
namespace Rector\Tests\TypeDeclaration\Rector\ClassMethod\AddArrayReturnDocTypeRector\Fixture;
final class ReturnYieldIterator
final class ReturnYieldGenerator
{
/**
* @return \Iterator<string[]>
* @return \Generator<string[]>
*/
public function someMethod()
{

View File

@ -0,0 +1,72 @@
<?php
namespace Rector\Tests\TypeDeclaration\Rector\ClassMethod\AddArrayReturnDocTypeRector\Fixture;
use Generator;
use Rector\FileSystemRector\ValueObject\AddedFileWithContent;
use Symplify\SmartFileSystem\SmartFileInfo;
use Symplify\SmartFileSystem\SmartFileSystem;
final class UniqueReturnGenerator
{
public function provideData(): Generator
{
$smartFileSystem = new SmartFileSystem();
yield [
new SmartFileInfo(__DIR__ . '/Source/Entity/RandomInterface.php'),
new AddedFileWithContent(
'/Source/Contract/RandomInterface.php',
$smartFileSystem->readFile(__DIR__ . '/Expected/ExpectedRandomInterface.php')
)
];
yield [
new SmartFileInfo(__DIR__ . '/Source/Control/ControlFactory.php'),
new AddedFileWithContent(
'/Source/Control/ControlFactory.php',
$smartFileSystem->readFile(__DIR__ . '/Source/Control/ControlFactory.php')
),
];
}
}
?>
-----
<?php
namespace Rector\Tests\TypeDeclaration\Rector\ClassMethod\AddArrayReturnDocTypeRector\Fixture;
use Generator;
use Rector\FileSystemRector\ValueObject\AddedFileWithContent;
use Symplify\SmartFileSystem\SmartFileInfo;
use Symplify\SmartFileSystem\SmartFileSystem;
final class UniqueReturnGenerator
{
/**
* @return \Generator<\Rector\FileSystemRector\ValueObject\AddedFileWithContent[]|\Symplify\SmartFileSystem\SmartFileInfo[]>
*/
public function provideData(): Generator
{
$smartFileSystem = new SmartFileSystem();
yield [
new SmartFileInfo(__DIR__ . '/Source/Entity/RandomInterface.php'),
new AddedFileWithContent(
'/Source/Contract/RandomInterface.php',
$smartFileSystem->readFile(__DIR__ . '/Expected/ExpectedRandomInterface.php')
)
];
yield [
new SmartFileInfo(__DIR__ . '/Source/Control/ControlFactory.php'),
new AddedFileWithContent(
'/Source/Control/ControlFactory.php',
$smartFileSystem->readFile(__DIR__ . '/Source/Control/ControlFactory.php')
),
];
}
}
?>

View File

@ -20,7 +20,7 @@ namespace Rector\Tests\TypeDeclaration\Rector\ClassMethod\AddArrayReturnDocTypeR
class YieldStrings
{
/**
* @return \Iterator<string>
* @return \Generator<string>
*/
public function getValues(): iterable
{

View File

@ -14,7 +14,7 @@ function iterableFunction($value)
namespace Rector\Tests\TypeDeclaration\Rector\FunctionLike\ReturnTypeDeclarationRector\Fixture\IterableFunction;
function iterableFunction($value): \Iterator
function iterableFunction($value): \Generator
{
yield 1;
yield 2;

View File

@ -0,0 +1,31 @@
<?php
namespace Rector\Tests\TypeDeclaration\Rector\FunctionLike\ReturnTypeDeclarationRector\Fixture;
final class DemoFile
{
/**
* @return \Generator<int>
**/
public function generator()
{
yield 5;
}
}
?>
-----
<?php
namespace Rector\Tests\TypeDeclaration\Rector\FunctionLike\ReturnTypeDeclarationRector\Fixture;
final class DemoFile
{
/**
* @return \Generator<int>
**/
public function generator(): \Generator
{
yield 5;
}
}
?>

View File

@ -0,0 +1,31 @@
<?php
namespace Rector\Tests\TypeDeclaration\Rector\FunctionLike\ReturnTypeDeclarationRector\Fixture;
final class WrongTypeGenerator
{
/**
* @return \wrong
**/
public function generator()
{
yield 5;
}
}
?>
-----
<?php
namespace Rector\Tests\TypeDeclaration\Rector\FunctionLike\ReturnTypeDeclarationRector\Fixture;
final class WrongTypeGenerator
{
/**
* @return \wrong
**/
public function generator(): \Generator
{
yield 5;
}
}
?>

View File

@ -214,7 +214,7 @@ CODE_SAMPLE
return false;
}
return ! $this->isNames($classMethod->returnType, ['array', 'iterable', 'Iterator']);
return ! $this->isNames($classMethod->returnType, ['array', 'iterable', 'Iterator', 'Generator']);
}
private function hasArrayShapeNode(ClassMethod $classMethod): bool

View File

@ -9,9 +9,11 @@ use PhpParser\Node\Expr;
use PhpParser\Node\Expr\Yield_;
use PhpParser\Node\Expr\YieldFrom;
use PhpParser\Node\FunctionLike;
use PhpParser\Node\Name;
use PhpParser\NodeTraverser;
use PHPStan\Type\MixedType;
use PHPStan\Type\Type;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\NodeTypeResolver\NodeTypeResolver;
use Rector\NodeTypeResolver\PHPStan\Type\TypeFactory;
use Rector\StaticTypeMapper\ValueObject\Type\FullyQualifiedGenericObjectType;
@ -24,7 +26,8 @@ final class YieldNodesReturnTypeInfererTypeInferer implements ReturnTypeInfererI
public function __construct(
private readonly NodeTypeResolver $nodeTypeResolver,
private readonly TypeFactory $typeFactory,
private readonly SimpleCallableNodeTraverser $simpleCallableNodeTraverser
private readonly SimpleCallableNodeTraverser $simpleCallableNodeTraverser,
private readonly NodeNameResolver $nodeNameResolver
) {
}
@ -51,12 +54,19 @@ final class YieldNodesReturnTypeInfererTypeInferer implements ReturnTypeInfererI
$types[] = $resolvedType;
}
$returnType = $functionLike->getReturnType();
$className = 'Generator';
if ($returnType instanceof Name && ! $this->nodeNameResolver->isName($returnType, 'Generator')) {
$className = $this->nodeNameResolver->getName($returnType);
}
if ($types === []) {
return new FullyQualifiedObjectType('Iterator');
return new FullyQualifiedObjectType($className);
}
$types = $this->typeFactory->createMixedPassedOrUnionType($types);
return new FullyQualifiedGenericObjectType('Iterator', [$types]);
return new FullyQualifiedGenericObjectType($className, [$types]);
}
public function getPriority(): int