Skip to content

Commit

Permalink
[Downgrade] [PHP 8.0] Add DowngradePropertyPromotionToConstructorProp…
Browse files Browse the repository at this point in the history
…ertyAssignRector (#4762)

* [Downgrade] [PHP 8.0] Add DowngradePropertyPromotionToConstructorPropertyAssignRector

* fix parent

* various fixes for PHP 8.0 tests

* [ci-review] Rector Rectify

* Update rules/downgrade-php80/tests/Rector/Class_/DowngradePropertyPromotionToConstructorPropertyAssignRector/DowngradePropertyPromotionToConstructorPropertyAssignRectorTest.php

Co-authored-by: rector-bot <tomas@getrector.org>
  • Loading branch information
TomasVotruba and rector-bot committed Dec 3, 2020
1 parent 1f5876e commit 09f17a7
Show file tree
Hide file tree
Showing 16 changed files with 286 additions and 14 deletions.
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
/vendor
composer.lock
stubs

# PHPStorm meta files
.idea/
Expand Down
9 changes: 5 additions & 4 deletions config/set/downgrade-php80.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
declare(strict_types=1);

use Rector\Downgrade\Rector\LNumber\ChangePhpVersionInPlatformCheckRector;
use Rector\DowngradePhp80\Rector\Class_\DowngradePropertyPromotionToConstructorPropertyAssignRector;
use Rector\DowngradePhp80\Rector\FunctionLike\DowngradeParamMixedTypeDeclarationRector;
use Rector\DowngradePhp80\Rector\FunctionLike\DowngradeReturnMixedTypeDeclarationRector;
use Rector\DowngradePhp80\Rector\FunctionLike\DowngradeReturnStaticTypeDeclarationRector;
Expand All @@ -19,8 +20,8 @@
$services->set(DowngradeParamMixedTypeDeclarationRector::class);
$services->set(DowngradeReturnMixedTypeDeclarationRector::class);
$services->set(DowngradeReturnStaticTypeDeclarationRector::class);
$services->set(ChangePhpVersionInPlatformCheckRector::class)
->call('configure', [[
ChangePhpVersionInPlatformCheckRector::TARGET_PHP_VERSION => 80000,
]]);
$services->set(ChangePhpVersionInPlatformCheckRector::class)->call('configure', [[
ChangePhpVersionInPlatformCheckRector::TARGET_PHP_VERSION => 80000,
]]);
$services->set(DowngradePropertyPromotionToConstructorPropertyAssignRector::class);
};
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

namespace Rector\CodeQuality\Tests\Rector\CombinedAssignRector\Fixture;

class Whatever
use Rector\CodeQuality\Tests\Rector\Assign\CombinedAssignRector\Source\AbstractSomeClassSoParentCanBeUsed;

class Whatever extends AbstractSomeClassSoParentCanBeUsed
{
public function __construct($parameter)
{
Expand Down Expand Up @@ -30,7 +32,9 @@ class Whatever

namespace Rector\CodeQuality\Tests\Rector\CombinedAssignRector\Fixture;

class Whatever
use Rector\CodeQuality\Tests\Rector\Assign\CombinedAssignRector\Source\AbstractSomeClassSoParentCanBeUsed;

class Whatever extends AbstractSomeClassSoParentCanBeUsed
{
public function __construct($parameter)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

declare(strict_types=1);

namespace Rector\CodeQuality\Tests\Rector\Assign\CombinedAssignRector\Source;

class AbstractSomeClassSoParentCanBeUsed
{

}
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,15 @@ class SkipNativePhpMethods
function __sleep(){}
function __wakeup(){}
function __serialize(){}
function __unserialize(){}
function __unserialize($content){}

function __toString()
{
return 'something to keep contract';
}

function __invoke(){}
function __set_state(){}
static function __set_state($state){}
function __clone(){}
function __debugInfo(){}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

namespace Rector\DeadCode\Tests\Rector\ClassMethod\RemoveDelegatingParentCallRector\Fixture;

class SkipChangedArguments
use PhpParser\PrettyPrinter\Standard;

class SkipChangedArguments extends Standard
{
public function prettyPrint(array $stmts): string
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

namespace Rector\DeadCode\Tests\Rector\ClassMethod\RemoveDelegatingParentCallRector\Fixture;

class SkipDifferentMethodName
use PhpParser\PrettyPrinter\Standard;

class SkipDifferentMethodName extends Standard
{
public function prettyPrint(array $stmts): string
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

namespace Rector\DeadCode\Tests\Rector\ClassMethod\RemoveDelegatingParentCallRector\Fixture;

class SkipExtraContent
use PhpParser\PrettyPrinter\Standard;

class SkipExtraContent extends Standard
{
public function prettyPrint(array $stmts): string
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
final class RemoveParentCallWithoutParentRectorTest extends AbstractRectorTestCase
{
/**
* @requires PHP < 8.0
* @dataProvider provideData()
*/
public function test(SmartFileInfo $fileInfo): void
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
<?php

declare(strict_types=1);

namespace Rector\DowngradePhp80\Rector\Class_;

use PhpParser\Node;
use PhpParser\Node\Param;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Expression;
use PhpParser\Node\Stmt\Property;
use Rector\Core\PhpParser\Node\Manipulator\ClassInsertManipulator;
use Rector\Core\Rector\AbstractRector;
use Rector\Core\ValueObject\MethodName;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;

/**
* @see https://wiki.php.net/rfc/constructor_promotion
*
* @see \Rector\DowngradePhp80\Tests\Rector\Class_\DowngradePropertyPromotionToConstructorPropertyAssignRector\DowngradePropertyPromotionToConstructorPropertyAssignRectorTest
*/
final class DowngradePropertyPromotionToConstructorPropertyAssignRector extends AbstractRector
{
/**
* @var ClassInsertManipulator
*/
private $classInsertManipulator;

public function __construct(ClassInsertManipulator $classInsertManipulator)
{
$this->classInsertManipulator = $classInsertManipulator;
}

public function getRuleDefinition(): RuleDefinition
{
return new RuleDefinition('Change constructor property promotion to property asssign', [
new CodeSample(
<<<'CODE_SAMPLE'
class SomeClass
{
public function __construct(public float $value = 0.0)
{
}
}
CODE_SAMPLE

,
<<<'CODE_SAMPLE'
class SomeClass
{
public float $value;
public function __construct(float $value = 0.0)
{
$this->value = $value;
}
}
CODE_SAMPLE

),
]);
}

/**
* @return string[]
*/
public function getNodeTypes(): array
{
return [Class_::class];
}

/**
* @param Class_ $node
*/
public function refactor(Node $node): ?Node
{
$promotedParams = $this->resolvePromotedParams($node);
if ($promotedParams === []) {
return null;
}

$properties = $this->addPropertiesFromParams($promotedParams, $node);

$this->addPropertyAssignsToConstructorClassMethod($properties, $node);

foreach ($promotedParams as $promotedParam) {
$promotedParam->flags = 0;
}

return $node;
}

/**
* @return Param[]
*/
private function resolvePromotedParams(Class_ $class): array
{
$constructorClassMethod = $class->getMethod(MethodName::CONSTRUCT);
if ($constructorClassMethod === null) {
return [];
}

$promotedParams = [];

foreach ($constructorClassMethod->params as $param) {
if ($param->flags === 0) {
continue;
}

$promotedParams[] = $param;
}

return $promotedParams;
}

/**
* @param Param[] $promotedParams
* @return Property[]
*/
private function addPropertiesFromParams(array $promotedParams, Class_ $class): array
{
$properties = $this->createPropertiesFromParams($promotedParams);
$this->classInsertManipulator->addPropertiesToClass($class, $properties);

return $properties;
}

/**
* @param Property[] $properties
*/
private function addPropertyAssignsToConstructorClassMethod(array $properties, Class_ $class): void
{
$assigns = [];

foreach ($properties as $property) {
$propertyName = $this->getName($property);
$assign = $this->nodeFactory->createPropertyAssignment($propertyName);
$assigns[] = new Expression($assign);
}

/** @var ClassMethod $constructorClassMethod */
$constructorClassMethod = $class->getMethod(MethodName::CONSTRUCT);
$constructorClassMethod->stmts = array_merge($assigns, (array) $constructorClassMethod->stmts);
}

/**
* @param Param[] $params
* @return Property[]
*/
private function createPropertiesFromParams(array $params): array
{
$properties = [];

foreach ($params as $param) {
/** @var string $name */
$name = $this->getName($param->var);

$property = $this->nodeFactory->createProperty($name);
$property->flags = $param->flags;
$property->type = $param->type;

$properties[] = $property;
}

return $properties;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

declare(strict_types=1);

namespace Rector\DowngradePhp80\Tests\Rector\Class_\DowngradePropertyPromotionToConstructorPropertyAssignRector;

use Iterator;
use Rector\DowngradePhp80\Rector\Class_\DowngradePropertyPromotionToConstructorPropertyAssignRector;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
use Symplify\SmartFileSystem\SmartFileInfo;

final class DowngradePropertyPromotionToConstructorPropertyAssignRectorTest extends AbstractRectorTestCase
{
/**
* @requires PHP 8.0
* @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 DowngradePropertyPromotionToConstructorPropertyAssignRector::class;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

namespace Rector\DowngradePhp80\Tests\Rector\Class_\DowngradePropertyPromotionToConstructorPropertyAssignRector\Fixture;

class SomeClass
{
public function __construct(public float $value = 0.0)
{
}
}

?>
-----
<?php

namespace Rector\DowngradePhp80\Tests\Rector\Class_\DowngradePropertyPromotionToConstructorPropertyAssignRector\Fixture;

class SomeClass
{
public float $value;
public function __construct(float $value = 0.0)
{
$this->value = $value;
}
}

?>
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
use Symplify\SmartFileSystem\SmartFileInfo;

/**
* @requires PHP >= 8.0
* @requires PHP 8.0
*/
final class DowngradeUnionTypeReturnDeclarationRectorTest extends AbstractRectorTestCase
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
final class OrderMethodsByVisibilityRectorTest extends AbstractRectorTestCase
{
/**
* Final + private method breaks :)
* @requires PHP < 8.0
* @dataProvider provideData()
*/
public function test(SmartFileInfo $fileInfo): void
Expand Down
10 changes: 10 additions & 0 deletions src/PhpParser/Node/Manipulator/ClassInsertManipulator.php
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,16 @@ public function addConstantToClass(Class_ $class, string $constantName, ClassCon
$this->addAsFirstMethod($class, $classConst);
}

/**
* @param Property[] $properties
*/
public function addPropertiesToClass(Class_ $class, array $properties): void
{
foreach ($properties as $property) {
$this->addAsFirstMethod($class, $property);
}
}

public function addPropertyToClass(Class_ $class, string $name, ?Type $type): void
{
if ($this->hasClassProperty($class, $name)) {
Expand Down

0 comments on commit 09f17a7

Please sign in to comment.