[TypeDeclaration] Handle return self and static on ReturnTypeFromReturnNewRector (#603)

* Add failing test fixture for ReturnTypeFromReturnNewRector

# Failing Test for ReturnTypeFromReturnNewRector

Based on https://getrector.org/demo/1ebef269-093c-6afe-9c29-afdc8959befb

refs https://github.com/rectorphp/rector/issues/6595

* Closes #602 Fixes https://github.com/rectorphp/rector/issues/6595

* final touch

* centralize check in TypeFactory

* mixed

* clean up

Co-authored-by: Dominik Peters <kuhlesdominik@gmx.de>
This commit is contained in:
Abdul Malik Ikhsan 2021-08-06 04:29:21 +07:00 committed by GitHub
parent 7c937fa451
commit e740a93886
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 143 additions and 1 deletions

View File

@ -17,19 +17,24 @@ use PHPStan\Type\IntegerType;
use PHPStan\Type\MixedType;
use PHPStan\Type\ObjectType;
use PHPStan\Type\StringType;
use PHPStan\Type\ThisType;
use PHPStan\Type\Type;
use PHPStan\Type\TypeTraverser;
use PHPStan\Type\TypeUtils;
use PHPStan\Type\VerbosityLevel;
use Rector\Core\Php\PhpVersionProvider;
use Rector\Core\ValueObject\PhpVersionFeature;
use Rector\StaticTypeMapper\TypeFactory\UnionTypeFactory;
use Rector\StaticTypeMapper\ValueObject\Type\AliasedObjectType;
use Rector\StaticTypeMapper\ValueObject\Type\FullyQualifiedObjectType;
use Rector\StaticTypeMapper\ValueObject\Type\SelfObjectType;
use Rector\StaticTypeMapper\ValueObject\Type\ShortenedObjectType;
final class TypeFactory
{
public function __construct(
private UnionTypeFactory $unionTypeFactory
private UnionTypeFactory $unionTypeFactory,
private PhpVersionProvider $phpVersionProvider
) {
}
@ -165,6 +170,22 @@ final class TypeFactory
private function normalizeObjectTypes(Type $type): Type
{
return TypeTraverser::map($type, function (Type $traversedType, callable $traverseCallback): Type {
if ($this->isStatic($traversedType) && $this->phpVersionProvider->isAtLeastPhpVersion(
PhpVersionFeature::STATIC_RETURN_TYPE
)) {
/** @var ObjectType $traversedType */
return new ThisType($traversedType->getClassName());
}
if ($this->isStatic($traversedType)) {
return new MixedType();
}
if ($this->isSelf($traversedType)) {
/** @var ObjectType $traversedType */
return new SelfObjectType($traversedType->getClassName());
}
if ($traversedType instanceof ShortenedObjectType) {
return new FullyQualifiedObjectType($traversedType->getFullyQualifiedName());
}
@ -176,4 +197,14 @@ final class TypeFactory
return $traverseCallback($traversedType);
});
}
private function isStatic(Type $type): bool
{
return $type instanceof ObjectType && $type->getClassName() === 'static';
}
private function isSelf(Type $type): bool
{
return $type instanceof ObjectType && $type->getClassName() === 'self';
}
}

View File

@ -0,0 +1,25 @@
<?php
namespace Rector\Tests\TypeDeclaration\Rector\ClassMethod\ReturnTypeFromReturnNewRector\Fixture;
final class ReturnSelf
{
public function run()
{
return new self();
}
}
?>
-----
<?php
namespace Rector\Tests\TypeDeclaration\Rector\ClassMethod\ReturnTypeFromReturnNewRector\Fixture;
final class ReturnSelf
{
public function run(): self
{
return new self();
}
}
?>

View File

@ -0,0 +1,25 @@
<?php
namespace Rector\Tests\TypeDeclaration\Rector\ClassMethod\ReturnTypeFromReturnNewRector\Fixture;
final class ReturnStatic
{
public function run()
{
return new static();
}
}
?>
-----
<?php
namespace Rector\Tests\TypeDeclaration\Rector\ClassMethod\ReturnTypeFromReturnNewRector\Fixture;
final class ReturnStatic
{
public function run(): static
{
return new static();
}
}
?>

View File

@ -0,0 +1,12 @@
<?php
namespace Rector\Tests\TypeDeclaration\Rector\ClassMethod\ReturnTypeFromReturnNewRector\FixturePhp74;
final class SkipReturnStatic
{
public function run()
{
return new static();
}
}
?>

View File

@ -0,0 +1,33 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\TypeDeclaration\Rector\ClassMethod\ReturnTypeFromReturnNewRector;
use Iterator;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
use Symplify\SmartFileSystem\SmartFileInfo;
final class Php74Test extends AbstractRectorTestCase
{
/**
* @dataProvider provideData()
*/
public function test(SmartFileInfo $fileInfo): void
{
$this->doTestFileInfo($fileInfo);
}
/**
* @return Iterator<SmartFileInfo>
*/
public function provideData(): Iterator
{
return $this->yieldFilesFromDirectory(__DIR__ . '/FixturePhp74');
}
public function provideConfigFilePath(): string
{
return __DIR__ . '/config/php74.php';
}
}

View File

@ -0,0 +1,16 @@
<?php
declare(strict_types=1);
use Rector\Core\Configuration\Option;
use Rector\Core\ValueObject\PhpVersionFeature;
use Rector\TypeDeclaration\Rector\ClassMethod\ReturnTypeFromReturnNewRector;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
return static function (ContainerConfigurator $containerConfigurator): void {
$services = $containerConfigurator->services();
$services->set(ReturnTypeFromReturnNewRector::class);
$parameters = $containerConfigurator->parameters();
$parameters->set(Option::PHP_VERSION_FEATURES, PhpVersionFeature::STATIC_RETURN_TYPE - 1);
};