-
-
Notifications
You must be signed in to change notification settings - Fork 335
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[DowngradePhp82] Add DowngradeReadonlyClassRector to downgrade readon…
…ly class (#2322) * [DowngradePhp82] Add DowngradeReadonlyClassRector to downgrade final readonly class * apply readonly property promotion * fixture * phpstan * [ci-review] Rector Rectify * add DowngradeLevelSetList::DOWN_TO_PHP_81 * add test to ensure no flip-flop between add and removing readonly when downgrade to php 8.0 * more test * more test * combination test * final touch: typo fix * not property promotion * static properties cannot be readonly * static properties cannot be readonly * note * note * note * test Co-authored-by: GitHub Action <action@github.com>
- Loading branch information
1 parent
f01725a
commit b48271e
Showing
19 changed files
with
441 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
use Rector\Config\RectorConfig; | ||
use Rector\Core\ValueObject\PhpVersion; | ||
use Rector\DowngradePhp82\Rector\Class_\DowngradeReadonlyClassRector; | ||
|
||
return static function (RectorConfig $rectorConfig): void { | ||
$rectorConfig->phpVersion(PhpVersion::PHP_81); | ||
$rectorConfig->rule(DowngradeReadonlyClassRector::class); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
use Rector\Config\RectorConfig; | ||
use Rector\Set\ValueObject\DowngradeSetList; | ||
|
||
return static function (RectorConfig $rectorConfig): void { | ||
$rectorConfig->sets([DowngradeSetList::PHP_82]); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
33 changes: 33 additions & 0 deletions
33
...radePhp82/Rector/Class_/DowngradeReadonlyClassRector/DowngradeReadonlyClassRectorTest.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Rector\Tests\DowngradePhp82\Rector\Class_\DowngradeReadonlyClassRector; | ||
|
||
use Iterator; | ||
use Rector\Testing\PHPUnit\AbstractRectorTestCase; | ||
use Symplify\SmartFileSystem\SmartFileInfo; | ||
|
||
final class DowngradeReadonlyClassRectorTest extends AbstractRectorTestCase | ||
{ | ||
/** | ||
* @dataProvider provideData() | ||
*/ | ||
public function test(SmartFileInfo $fileInfo): void | ||
{ | ||
$this->doTestFileInfo($fileInfo); | ||
} | ||
|
||
/** | ||
* @return Iterator<SmartFileInfo> | ||
*/ | ||
public function provideData(): Iterator | ||
{ | ||
return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture'); | ||
} | ||
|
||
public function provideConfigFilePath(): string | ||
{ | ||
return __DIR__ . '/config/configured_rule.php'; | ||
} | ||
} |
29 changes: 29 additions & 0 deletions
29
...ass_/DowngradeReadonlyClassRector/Fixture/combine_property_and_property_promotion.php.inc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
<?php | ||
|
||
namespace Rector\Tests\DowngradePhp82\Rector\Class_\DowngradeReadonlyClassRector\Fixture; | ||
|
||
final readonly class CombinePropertyAndPropertyPromotion | ||
{ | ||
private string $foo; | ||
|
||
public function __construct(private string $bar) | ||
{ | ||
} | ||
} | ||
|
||
?> | ||
----- | ||
<?php | ||
|
||
namespace Rector\Tests\DowngradePhp82\Rector\Class_\DowngradeReadonlyClassRector\Fixture; | ||
|
||
final class CombinePropertyAndPropertyPromotion | ||
{ | ||
private readonly string $foo; | ||
|
||
public function __construct(private readonly string $bar) | ||
{ | ||
} | ||
} | ||
|
||
?> |
25 changes: 25 additions & 0 deletions
25
...dePhp82/Rector/Class_/DowngradeReadonlyClassRector/Fixture/not_property_promotion.php.inc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
<?php | ||
|
||
namespace Rector\Tests\DowngradePhp82\Rector\Class_\DowngradeReadonlyClassRector\Fixture; | ||
|
||
final readonly class NotPropertyPromotion | ||
{ | ||
public function __construct(string $bar) | ||
{ | ||
} | ||
} | ||
|
||
?> | ||
----- | ||
<?php | ||
|
||
namespace Rector\Tests\DowngradePhp82\Rector\Class_\DowngradeReadonlyClassRector\Fixture; | ||
|
||
final class NotPropertyPromotion | ||
{ | ||
public function __construct(string $bar) | ||
{ | ||
} | ||
} | ||
|
||
?> |
21 changes: 21 additions & 0 deletions
21
.../DowngradePhp82/Rector/Class_/DowngradeReadonlyClassRector/Fixture/readonly_class.php.inc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
<?php | ||
|
||
namespace Rector\Tests\DowngradePhp82\Rector\Class_\DowngradeReadonlyClassRector\Fixture; | ||
|
||
final readonly class ReadonlyClass | ||
{ | ||
public string $foo; | ||
} | ||
|
||
?> | ||
----- | ||
<?php | ||
|
||
namespace Rector\Tests\DowngradePhp82\Rector\Class_\DowngradeReadonlyClassRector\Fixture; | ||
|
||
final class ReadonlyClass | ||
{ | ||
public readonly string $foo; | ||
} | ||
|
||
?> |
25 changes: 25 additions & 0 deletions
25
...lass_/DowngradeReadonlyClassRector/Fixture/readonly_class_with_property_promotion.php.inc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
<?php | ||
|
||
namespace Rector\Tests\DowngradePhp82\Rector\Class_\DowngradeReadonlyClassRector\Fixture; | ||
|
||
final readonly class ReadonlyClassWithPropertyPromotion | ||
{ | ||
public function __construct(private string $foo) | ||
{ | ||
} | ||
} | ||
|
||
?> | ||
----- | ||
<?php | ||
|
||
namespace Rector\Tests\DowngradePhp82\Rector\Class_\DowngradeReadonlyClassRector\Fixture; | ||
|
||
final class ReadonlyClassWithPropertyPromotion | ||
{ | ||
public function __construct(private readonly string $foo) | ||
{ | ||
} | ||
} | ||
|
||
?> |
8 changes: 8 additions & 0 deletions
8
...wngradePhp82/Rector/Class_/DowngradeReadonlyClassRector/Fixture/skip_not_readonly.php.inc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
<?php | ||
|
||
namespace Rector\Tests\DowngradePhp82\Rector\Class_\DowngradeReadonlyClassRector\Fixture; | ||
|
||
class SkipNotReadonly | ||
{ | ||
public readonly string $foo; | ||
} |
21 changes: 21 additions & 0 deletions
21
...DowngradePhp82/Rector/Class_/DowngradeReadonlyClassRector/Fixture/static_property.php.inc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
<?php | ||
|
||
namespace Rector\Tests\DowngradePhp82\Rector\Class_\DowngradeReadonlyClassRector\Fixture; | ||
|
||
final readonly class StaticProperty | ||
{ | ||
public static string $foo; | ||
} | ||
|
||
?> | ||
----- | ||
<?php | ||
|
||
namespace Rector\Tests\DowngradePhp82\Rector\Class_\DowngradeReadonlyClassRector\Fixture; | ||
|
||
final class StaticProperty | ||
{ | ||
public static string $foo; | ||
} | ||
|
||
?> |
10 changes: 10 additions & 0 deletions
10
...ests/DowngradePhp82/Rector/Class_/DowngradeReadonlyClassRector/config/configured_rule.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
use Rector\Config\RectorConfig; | ||
use Rector\DowngradePhp82\Rector\Class_\DowngradeReadonlyClassRector; | ||
|
||
return static function (RectorConfig $rectorConfig): void { | ||
$rectorConfig->rule(DowngradeReadonlyClassRector::class); | ||
}; |
141 changes: 141 additions & 0 deletions
141
rules/DowngradePhp82/Rector/Class_/DowngradeReadonlyClassRector.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,141 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Rector\DowngradePhp82\Rector\Class_; | ||
|
||
use PhpParser\Node; | ||
use PhpParser\Node\Stmt\Class_; | ||
use PhpParser\Node\Stmt\ClassMethod; | ||
use Rector\Core\Rector\AbstractRector; | ||
use Rector\Core\ValueObject\MethodName; | ||
use Rector\Privatization\NodeManipulator\VisibilityManipulator; | ||
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample; | ||
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition; | ||
|
||
/** | ||
* @changelog https://wiki.php.net/rfc/readonly_classes | ||
* | ||
* @see \Rector\Tests\DowngradePhp82\Rector\Class_\DowngradeReadonlyClassRector\DowngradeReadonlyClassRectorTest | ||
*/ | ||
final class DowngradeReadonlyClassRector extends AbstractRector | ||
{ | ||
public function __construct(private readonly VisibilityManipulator $visibilityManipulator) | ||
{ | ||
} | ||
|
||
/** | ||
* @return array<class-string<Node>> | ||
*/ | ||
public function getNodeTypes(): array | ||
{ | ||
return [Class_::class]; | ||
} | ||
|
||
public function getRuleDefinition(): RuleDefinition | ||
{ | ||
return new RuleDefinition( | ||
'Remove "readonly" class type, decorate all properties to "readonly"', | ||
[ | ||
new CodeSample( | ||
<<<'CODE_SAMPLE' | ||
final readonly class SomeClass | ||
{ | ||
public string $foo; | ||
public function __construct() | ||
{ | ||
$this->foo = 'foo'; | ||
} | ||
} | ||
CODE_SAMPLE | ||
, | ||
<<<'CODE_SAMPLE' | ||
final readonly class SomeClass | ||
{ | ||
public readonly string $foo; | ||
public function __construct() | ||
{ | ||
$this->foo = 'foo'; | ||
} | ||
} | ||
CODE_SAMPLE | ||
), | ||
] | ||
); | ||
} | ||
|
||
/** | ||
* @param Class_ $node | ||
*/ | ||
public function refactor(Node $node): ?Node | ||
{ | ||
if (! $this->visibilityManipulator->isReadonly($node)) { | ||
return null; | ||
} | ||
|
||
$this->visibilityManipulator->removeReadonly($node); | ||
$this->makePropertiesReadonly($node); | ||
$this->makePromotedPropertiesReadonly($node); | ||
|
||
return $node; | ||
} | ||
|
||
private function makePropertiesReadonly(Class_ $class): void | ||
{ | ||
foreach ($class->getProperties() as $property) { | ||
if ($property->isReadonly()) { | ||
continue; | ||
} | ||
|
||
/** | ||
* It technically impossible that readonly class has: | ||
* | ||
* - non-typed property | ||
* - static property | ||
* | ||
* but here to ensure no flip-flop when using direct rule for multiple rules applied | ||
*/ | ||
if ($property->type === null) { | ||
continue; | ||
} | ||
|
||
if ($property->isStatic()) { | ||
continue; | ||
} | ||
|
||
$this->visibilityManipulator->makeReadonly($property); | ||
} | ||
} | ||
|
||
private function makePromotedPropertiesReadonly(Class_ $class): void | ||
{ | ||
$classMethod = $class->getMethod(MethodName::CONSTRUCT); | ||
if (! $classMethod instanceof ClassMethod) { | ||
return; | ||
} | ||
|
||
foreach ($classMethod->getParams() as $param) { | ||
if ($this->visibilityManipulator->isReadonly($param)) { | ||
continue; | ||
} | ||
|
||
/** | ||
* not property promotion, just param | ||
*/ | ||
if ($param->flags === 0) { | ||
continue; | ||
} | ||
|
||
/** | ||
* also not typed, just param | ||
*/ | ||
if ($param->type === null) { | ||
continue; | ||
} | ||
|
||
$this->visibilityManipulator->makeReadonly($param); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.