[Downgrade PHP 8.0] Add union types to doc types (#4082)

This commit is contained in:
Tomas Votruba 2020-09-08 12:00:38 +02:00 committed by GitHub
parent 46e2b450b3
commit 6508aedd13
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 465 additions and 69 deletions

View File

@ -11,7 +11,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
php: ['7.3', '7.4']
php: ['7.2', '7.3', '7.4']
name: PHP ${{ matrix.php }} tests
steps:

View File

@ -2,11 +2,11 @@
declare(strict_types=1);
use Rector\Architecture\Rector\Class_\MoveRepositoryFromParentToConstructorRector;
use Rector\Architecture\Rector\MethodCall\ReplaceParentRepositoryCallsByRepositoryPropertyRector;
use Rector\Architecture\Rector\MethodCall\ServiceLocatorToDIRector;
use Rector\Doctrine\Rector\Class_\RemoveRepositoryFromEntityAnnotationRector;
use Rector\Doctrine\Rector\ClassMethod\ServiceEntityRepositoryConstructorToDependencyInjectionWithRepositoryPropertyRector;
use Rector\DoctrineCodeQuality\Rector\Class_\MoveRepositoryFromParentToConstructorRector;
use Rector\Generic\Rector\Class_\AddPropertyByParentRector;
use Rector\Generic\Rector\Class_\RemoveParentRector;
use Rector\Generic\Rector\ClassLike\RemoveAnnotationRector;

View File

@ -7,18 +7,15 @@ use Rector\Downgrade\Rector\Coalesce\DowngradeNullCoalescingOperatorRector;
use Rector\Downgrade\Rector\FunctionLike\DowngradeParamObjectTypeDeclarationRector;
use Rector\Downgrade\Rector\FunctionLike\DowngradeReturnObjectTypeDeclarationRector;
use Rector\Downgrade\Rector\Property\DowngradeTypedPropertyRector;
use Rector\Downgrade\Rector\Property\DowngradeUnionTypeToDocBlockRector;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
return static function (ContainerConfigurator $containerConfigurator): void {
$services = $containerConfigurator->services();
$services->set(DowngradeParamObjectTypeDeclarationRector::class);
$services->set(DowngradeReturnObjectTypeDeclarationRector::class);
$services->set(DowngradeTypedPropertyRector::class);
$services->set(ArrowFunctionToAnonymousFunctionRector::class);
$services->set(DowngradeNullCoalescingOperatorRector::class);
$services->set(DowngradeUnionTypeToDocBlockRector::class);
};

View File

@ -1,11 +1,11 @@
# All 563 Rectors Overview
# All 568 Rectors Overview
- [Projects](#projects)
---
## Projects
- [Architecture](#architecture) (3)
- [Architecture](#architecture) (2)
- [Autodiscovery](#autodiscovery) (4)
- [CakePHP](#cakephp) (6)
- [CodeQuality](#codequality) (58)
@ -13,9 +13,9 @@
- [DeadCode](#deadcode) (40)
- [Decouple](#decouple) (1)
- [Doctrine](#doctrine) (17)
- [DoctrineCodeQuality](#doctrinecodequality) (7)
- [DoctrineCodeQuality](#doctrinecodequality) (8)
- [DoctrineGedmoToKnplabs](#doctrinegedmotoknplabs) (7)
- [Downgrade](#downgrade) (1)
- [Downgrade](#downgrade) (6)
- [DynamicTypeAnalysis](#dynamictypeanalysis) (3)
- [FileSystemRector](#filesystemrector) (1)
- [Generic](#generic) (38)
@ -73,34 +73,6 @@
## Architecture
### `MoveRepositoryFromParentToConstructorRector`
- class: [`Rector\Architecture\Rector\Class_\MoveRepositoryFromParentToConstructorRector`](/rules/architecture/src/Rector/Class_/MoveRepositoryFromParentToConstructorRector.php)
Turns parent EntityRepository class to constructor dependency
```diff
namespace App\Repository;
+use App\Entity\Post;
use Doctrine\ORM\EntityRepository;
-final class PostRepository extends EntityRepository
+final class PostRepository
{
+ /**
+ * @var \Doctrine\ORM\EntityRepository
+ */
+ private $repository;
+ public function __construct(\Doctrine\ORM\EntityManager $entityManager)
+ {
+ $this->repository = $entityManager->getRepository(\App\Entity\Post::class);
+ }
}
```
<br><br>
### `ReplaceParentRepositoryCallsByRepositoryPropertyRector`
- class: [`Rector\Architecture\Rector\MethodCall\ReplaceParentRepositoryCallsByRepositoryPropertyRector`](/rules/architecture/src/Rector/MethodCall/ReplaceParentRepositoryCallsByRepositoryPropertyRector.php)
@ -4132,6 +4104,34 @@ Move default value for entity property to constructor, the safest place
<br><br>
### `MoveRepositoryFromParentToConstructorRector`
- class: [`Rector\DoctrineCodeQuality\Rector\Class_\MoveRepositoryFromParentToConstructorRector`](/rules/doctrine-code-quality/src/Rector/Class_/MoveRepositoryFromParentToConstructorRector.php)
Turns parent EntityRepository class to constructor dependency
```diff
namespace App\Repository;
+use App\Entity\Post;
use Doctrine\ORM\EntityRepository;
-final class PostRepository extends EntityRepository
+final class PostRepository
{
+ /**
+ * @var \Doctrine\ORM\EntityRepository
+ */
+ private $repository;
+ public function __construct(\Doctrine\ORM\EntityManager $entityManager)
+ {
+ $this->repository = $entityManager->getRepository(\App\Entity\Post::class);
+ }
}
```
<br><br>
## DoctrineGedmoToKnplabs
### `BlameableBehaviorRector`
@ -4483,6 +4483,93 @@ Change Tree from gedmo/doctrine-extensions to knplabs/doctrine-behaviors
## Downgrade
### `ArrowFunctionToAnonymousFunctionRector`
- class: [`Rector\Downgrade\Rector\ArrowFunction\ArrowFunctionToAnonymousFunctionRector`](/rules/downgrade/src/Rector/ArrowFunction/ArrowFunctionToAnonymousFunctionRector.php)
- [test fixtures](/rules/downgrade/tests/Rector/ArrowFunction/ArrowFunctionToAnonymousFunctionRector/Fixture)
Replace arrow functions with anonymous functions
```diff
class SomeClass
{
public function run()
{
$delimiter = ",";
- $callable = fn($matches) => $delimiter . strtolower($matches[1]);
+ $callable = function ($matches) use ($delimiter) {
+ return $delimiter . strtolower($matches[1]);
+ };
}
}
```
<br><br>
### `DowngradeNullCoalescingOperatorRector`
- class: [`Rector\Downgrade\Rector\Coalesce\DowngradeNullCoalescingOperatorRector`](/rules/downgrade/src/Rector/Coalesce/DowngradeNullCoalescingOperatorRector.php)
- [test fixtures](/rules/downgrade/tests/Rector/Coalesce/DowngradeNullCoalescingOperatorRector/Fixture)
Remove null coalescing operator ??=
```diff
$array = [];
-$array['user_id'] ??= 'value';
+$array['user_id'] = $array['user_id'] ?? 'value';
```
<br><br>
### `DowngradeParamObjectTypeDeclarationRector`
- class: [`Rector\Downgrade\Rector\FunctionLike\DowngradeParamObjectTypeDeclarationRector`](/rules/downgrade/src/Rector/FunctionLike/DowngradeParamObjectTypeDeclarationRector.php)
- [test fixtures](/rules/downgrade/tests/Rector/FunctionLike/DowngradeParamObjectTypeDeclarationRector/Fixture)
Remove the 'object' param type, add a @param tag instead
```diff
<?php
class SomeClass
{
- public function someFunction(object $someObject)
+ /**
+ * @param object $someObject
+ */
+ public function someFunction($someObject)
{
}
}
```
<br><br>
### `DowngradeReturnObjectTypeDeclarationRector`
- class: [`Rector\Downgrade\Rector\FunctionLike\DowngradeReturnObjectTypeDeclarationRector`](/rules/downgrade/src/Rector/FunctionLike/DowngradeReturnObjectTypeDeclarationRector.php)
- [test fixtures](/rules/downgrade/tests/Rector/FunctionLike/DowngradeReturnObjectTypeDeclarationRector/Fixture)
Remove the 'object' function type, add a @return tag instead
```diff
<?php
class SomeClass
{
- public function getSomeObject(): object
+ /**
+ * @return object
+ */
+ public function getSomeObject()
{
return new SomeObject();
}
}
```
<br><br>
### `DowngradeTypedPropertyRector`
- class: [`Rector\Downgrade\Rector\Property\DowngradeTypedPropertyRector`](/rules/downgrade/src/Rector/Property/DowngradeTypedPropertyRector.php)
@ -4503,6 +4590,35 @@ Changes property type definition from type definitions to `@var` annotations.
<br><br>
### `DowngradeUnionTypeToDocBlockRector`
- class: [`Rector\Downgrade\Rector\Property\DowngradeUnionTypeToDocBlockRector`](/rules/downgrade/src/Rector/Property/DowngradeUnionTypeToDocBlockRector.php)
- [test fixtures](/rules/downgrade/tests/Rector/Property/DowngradeUnionTypeToDocBlockRector/Fixture)
Downgrade union types to doc block
```diff
class SomeClass
{
- public int|string $value;
+ /**
+ * @var int|string
+ */
+ public $value;
- public function run(): int|string
+ /**
+ * @return int|string
+ */
+ public function run()
{
$this->value;
}
}
```
<br><br>
## DynamicTypeAnalysis
### `AddArgumentTypeWithProbeDataRector`
@ -12831,7 +12947,7 @@ Turns `@Template` annotation to explicit method call in Controller of FrameworkE
- class: [`Rector\StrictCodeQuality\Rector\Stmt\VarInlineAnnotationToAssertRector`](/rules/strict-code-quality/src/Rector/Stmt/VarInlineAnnotationToAssertRector.php)
- [test fixtures](/rules/strict-code-quality/tests/Rector/Stmt/VarInlineAnnotationToAssertRector/Fixture)
Turn @var inline checks above code to `assert()` of hte type
Turn @var inline checks above code to `assert()` of the type
```diff
class SomeClass

View File

@ -109,6 +109,7 @@ final class PhpDocTypeChanger
$phpDocInfo->addTagValueNode($attributeAwareReturnTagValueNode);
}
// notify about node change
$this->notifyChange();
}
@ -121,13 +122,12 @@ final class PhpDocTypeChanger
// override existing type
if ($paramTagValueNode !== null) {
$paramTagValueNode->type = $phpDocType;
return;
} else {
$paramTagValueNode = $this->paramPhpDocNodeFactory->create($type, $param);
$phpDocInfo->addTagValueNode($paramTagValueNode);
}
$paramTagValueNode = $this->paramPhpDocNodeFactory->create($type, $param);
$phpDocInfo->addTagValueNode($paramTagValueNode);
// notify about node change
$this->notifyChange();
}

View File

@ -13,7 +13,7 @@ use Rector\Core\RectorDefinition\RectorDefinition;
use Rector\NodeTypeResolver\Node\AttributeKey;
/**
* @see \Rector\Architecture\Tests\Rector\DoctrineRepositoryAsService\DoctrineRepositoryAsServiceTest
* @see \Rector\DoctrineCodeQuality\Tests\Rector\DoctrineRepositoryAsService\DoctrineRepositoryAsServiceTest
*/
final class ReplaceParentRepositoryCallsByRepositoryPropertyRector extends AbstractRector
{

View File

@ -23,7 +23,7 @@ use Rector\Naming\Naming\PropertyNaming;
use Rector\NodeTypeResolver\Node\AttributeKey;
/**
* @see \Rector\Architecture\Tests\Rector\DoctrineRepositoryAsService\DoctrineRepositoryAsServiceTest
* @see \Rector\DoctrineCodeQuality\Tests\Rector\DoctrineRepositoryAsService\DoctrineRepositoryAsServiceTest
*/
final class ServiceLocatorToDIRector extends AbstractRector
{

View File

@ -3,7 +3,7 @@
namespace App\Repository;
use App\Entity\Post;
use Rector\Architecture\Tests\Rector\DoctrineRepositoryAsService\Source\RandomClass;
use Rector\DoctrineCodeQuality\Tests\Rector\DoctrineRepositoryAsService\Source\RandomClass;
final class SkipWithoutParentClass extends RandomClass
{

View File

@ -1,10 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Architecture\Tests\Rector\DoctrineRepositoryAsService\Source;
abstract class RandomClass
{
}

View File

@ -2,7 +2,7 @@
declare(strict_types=1);
namespace Rector\Architecture\Rector\Class_;
namespace Rector\DoctrineCodeQuality\Rector\Class_;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\EntityRepository;
@ -22,7 +22,7 @@ use Rector\Doctrine\Contract\Mapper\DoctrineEntityAndRepositoryMapperInterface;
use Rector\NodeTypeResolver\Node\AttributeKey;
/**
* @see \Rector\Architecture\Tests\Rector\DoctrineRepositoryAsService\DoctrineRepositoryAsServiceTest
* @see \Rector\DoctrineCodeQuality\Tests\Rector\DoctrineRepositoryAsService\DoctrineRepositoryAsServiceTest
*/
final class MoveRepositoryFromParentToConstructorRector extends AbstractRector
{

View File

@ -2,19 +2,19 @@
declare(strict_types=1);
namespace Rector\Architecture\Tests\Rector\DoctrineRepositoryAsService;
namespace Rector\DoctrineCodeQuality\Tests\Rector\DoctrineRepositoryAsService;
use Iterator;
use Rector\Architecture\Rector\Class_\MoveRepositoryFromParentToConstructorRector;
use Rector\Architecture\Rector\MethodCall\ReplaceParentRepositoryCallsByRepositoryPropertyRector;
use Rector\Architecture\Rector\MethodCall\ServiceLocatorToDIRector;
use Rector\Core\Testing\PHPUnit\AbstractRectorTestCase;
use Rector\Doctrine\Rector\Class_\RemoveRepositoryFromEntityAnnotationRector;
use Rector\DoctrineCodeQuality\Rector\Class_\MoveRepositoryFromParentToConstructorRector;
use Symplify\SmartFileSystem\SmartFileInfo;
/**
* @see \Rector\Architecture\Rector\MethodCall\ReplaceParentRepositoryCallsByRepositoryPropertyRector
* @see \Rector\Architecture\Rector\Class_\MoveRepositoryFromParentToConstructorRector
* @see \Rector\DoctrineCodeQuality\Rector\Class_\MoveRepositoryFromParentToConstructorRector
* @see \Rector\Architecture\Rector\MethodCall\ServiceLocatorToDIRector
*/
final class DoctrineRepositoryAsServiceTest extends AbstractRectorTestCase

View File

@ -1,6 +1,6 @@
<?php
namespace Rector\Architecture\Tests\Rector\DoctrineRepositoryAsService\Fixture;
namespace Rector\DoctrineCodeQuality\Tests\Rector\DoctrineRepositoryAsService\Fixture;
use Rector\Core\Tests\Rector\Architecture\DoctrineRepositoryAsService\Source\Entity\Post;
use Rector\Core\Tests\Rector\Architecture\DoctrineRepositoryAsService\Source\SymfonyController;
@ -21,7 +21,7 @@ final class PostController extends SymfonyController
-----
<?php
namespace Rector\Architecture\Tests\Rector\DoctrineRepositoryAsService\Fixture;
namespace Rector\DoctrineCodeQuality\Tests\Rector\DoctrineRepositoryAsService\Fixture;
use Rector\Core\Tests\Rector\Architecture\DoctrineRepositoryAsService\Source\Entity\Post;
use Rector\Core\Tests\Rector\Architecture\DoctrineRepositoryAsService\Source\SymfonyController;

View File

@ -1,6 +1,6 @@
<?php
namespace Rector\Architecture\Tests\Rector\DoctrineRepositoryAsService\Fixture;
namespace Rector\DoctrineCodeQuality\Tests\Rector\DoctrineRepositoryAsService\Fixture;
use Doctrine\ORM\EntityManagerInterface;
use PHPUnit\Framework\TestCase;

View File

@ -0,0 +1,10 @@
<?php
declare(strict_types=1);
namespace Rector\DoctrineCodeQuality\Tests\Rector\DoctrineRepositoryAsService\Source;
abstract class RandomClass
{
}

View File

@ -0,0 +1,160 @@
<?php
declare(strict_types=1);
namespace Rector\Downgrade\Rector\Property;
use PhpParser\Node;
use PhpParser\Node\Expr\ArrowFunction;
use PhpParser\Node\Expr\Closure;
use PhpParser\Node\FunctionLike;
use PhpParser\Node\Param;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Function_;
use PhpParser\Node\Stmt\Property;
use PhpParser\Node\UnionType;
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo;
use Rector\Core\Rector\AbstractRector;
use Rector\Core\RectorDefinition\CodeSample;
use Rector\Core\RectorDefinition\RectorDefinition;
use Rector\NodeTypeResolver\Node\AttributeKey;
/**
* @see \Rector\Downgrade\Tests\Rector\Property\DowngradeUnionTypeToDocBlockRector\DowngradeUnionTypeToDocBlockRectorTest
*/
final class DowngradeUnionTypeToDocBlockRector extends AbstractRector
{
public function getDefinition(): RectorDefinition
{
return new RectorDefinition('Downgrade union types to doc block', [
new CodeSample(
<<<'PHP'
class SomeClass
{
public int|string $value;
public function run(): int|string
{
$this->value;
}
}
PHP
,
<<<'PHP'
class SomeClass
{
/**
* @var int|string
*/
public $value;
/**
* @return int|string
*/
public function run()
{
$this->value;
}
}
PHP
),
]);
}
/**
* @return string[]
*/
public function getNodeTypes(): array
{
return [Property::class, ClassMethod::class];
}
/**
* @param Property|ClassMethod|Function_|Closure|ArrowFunction $node
*/
public function refactor(Node $node): ?Node
{
if ($node instanceof Property) {
return $this->refactorProperty($node);
}
if ($node instanceof FunctionLike) {
return $this->refactorClassMethod($node);
}
return null;
}
private function refactorProperty(Property $property): ?Property
{
if (! $property->type instanceof UnionType) {
return null;
}
/** @var PhpDocInfo|null $phpDocInfo */
$phpDocInfo = $property->getAttribute(AttributeKey::PHP_DOC_INFO);
if ($phpDocInfo === null) {
$phpDocInfo = $this->phpDocInfoFactory->createEmpty($property);
}
$phpStanType = $this->staticTypeMapper->mapPhpParserNodePHPStanType($property->type);
$phpDocInfo->changeVarType($phpStanType);
$property->type = null;
return $property;
}
/**
* @param ClassMethod|Function_|Closure|ArrowFunction $functionLike
*/
private function refactorClassMethod(FunctionLike $functionLike): FunctionLike
{
$this->processReturnType($functionLike);
$this->processParamTypes($functionLike);
return $functionLike;
}
/**
* @param ClassMethod|Function_|Closure|ArrowFunction $functionLike
*/
private function processReturnType(FunctionLike $functionLike): void
{
if (! $functionLike->returnType instanceof UnionType) {
return;
}
/** @var PhpDocInfo|null $phpDocInfo */
$phpDocInfo = $functionLike->getAttribute(AttributeKey::PHP_DOC_INFO);
if ($phpDocInfo === null) {
$phpDocInfo = $this->phpDocInfoFactory->createEmpty($functionLike);
}
$phpStanType = $this->staticTypeMapper->mapPhpParserNodePHPStanType($functionLike->returnType);
$phpDocInfo->changeReturnType($phpStanType);
}
/**
* @param ClassMethod|Function_|Closure|ArrowFunction $functionLike
*/
private function processParamTypes(FunctionLike $functionLike): void
{
foreach ($functionLike->getParams() as $param) {
if (! $param->type instanceof UnionType) {
continue;
}
/** @var PhpDocInfo|null $phpDocInfo */
$phpDocInfo = $param->getAttribute(AttributeKey::PHP_DOC_INFO);
if ($phpDocInfo === null) {
$phpDocInfo = $this->phpDocInfoFactory->createEmpty($functionLike);
}
$phpStanType = $this->staticTypeMapper->mapPhpParserNodePHPStanType($param->type);
$phpDocInfo->changeParamType($phpStanType, $param, $this->getName($param));
}
}
}

View File

@ -0,0 +1,34 @@
<?php
declare(strict_types=1);
namespace Rector\Downgrade\Tests\Rector\Property\DowngradeUnionTypeToDocBlockRector;
use Iterator;
use Rector\Core\Testing\PHPUnit\AbstractRectorTestCase;
use Rector\Downgrade\Rector\Property\DowngradeUnionTypeToDocBlockRector;
use Symplify\SmartFileSystem\SmartFileInfo;
/**
* @requires PHP >= 8.0
*/
final class DowngradeUnionTypeToDocBlockRectorTest extends AbstractRectorTestCase
{
/**
* @dataProvider provideData()
*/
public function test(SmartFileInfo $fileInfo): void
{
$this->doTestFileInfo($fileInfo);
}
public function provideData(): Iterator
{
return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture');
}
protected function getRectorClass(): string
{
return DowngradeUnionTypeToDocBlockRector::class;
}
}

View File

@ -0,0 +1,28 @@
<?php
namespace Rector\Downgrade\Tests\Rector\Property\DowngradeUnionTypeToDocBlockRector\Fixture;
class FunctionParam
{
public function run(int|string $value)
{
}
}
?>
-----
<?php
namespace Rector\Downgrade\Tests\Rector\Property\DowngradeUnionTypeToDocBlockRector\Fixture;
class FunctionParam
{
/**
* @param int|string $value
*/
public function run($value)
{
}
}
?>

View File

@ -0,0 +1,24 @@
<?php
namespace Rector\Downgrade\Tests\Rector\Property\DowngradeUnionTypeToDocBlockRector\Fixture;
class SomeClass
{
public int|string $value;
}
?>
-----
<?php
namespace Rector\Downgrade\Tests\Rector\Property\DowngradeUnionTypeToDocBlockRector\Fixture;
class SomeClass
{
/**
* @var int|string
*/
public $value;
}
?>

View File

@ -0,0 +1,38 @@
<?php
namespace Rector\Downgrade\Tests\Rector\Property\DowngradeUnionTypeToDocBlockRector\Fixture;
class ClassMethod
{
public function run(): int|string
{
if (mt_rand()) {
return 1;
}
return 'value';
}
}
?>
-----
<?php
namespace Rector\Downgrade\Tests\Rector\Property\DowngradeUnionTypeToDocBlockRector\Fixture;
class ClassMethod
{
/**
* @return int|string
*/
public function run()
{
if (mt_rand()) {
return 1;
}
return 'value';
}
}
?>

View File

@ -39,7 +39,7 @@ final class VarInlineAnnotationToAssertRector extends AbstractRector
public function getDefinition(): RectorDefinition
{
return new RectorDefinition('Turn @var inline checks above code to assert() of hte type', [
return new RectorDefinition('Turn @var inline checks above code to assert() of the type', [
new CodeSample(
<<<'PHP'
class SomeClass

View File

@ -105,9 +105,8 @@ PHP
$paramName = $this->getName($param);
$phpDocInfo->changeParamType($type, $param, $paramName);
return $node;
}
return $node;
}
private function shouldSkipParam(Param $param): bool