From ef333de3d58a4649558971b19f4814fd92823abe Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Wed, 3 Apr 2024 12:36:10 +0700 Subject: [PATCH] [DeadCode] Add RemoveUselessReadOnlyTagRector (#5790) * [DeadCode] Add RemoveUselessReadOnlyDocRector * roll * final touch: rename to RemoveUselessReadOnlyTagRector * final touch: doc --- .../docs/rector_rules_overview.md | 27 ++++- .../Fixture/remove_on_class.php.inc | 32 ++++++ .../Fixture/remove_on_param_construct.php.inc | 32 ++++++ .../Fixture/remove_on_property.php.inc | 34 ++++++ .../Fixture/skip_no_readonly_doc.php.inc | 13 +++ .../Fixture/skip_with_description.php.inc | 16 +++ .../RemoveUselessReadOnlyTagRectorTest.php | 28 +++++ .../config/configured_rule.php | 9 ++ .../RemoveUselessReadOnlyTagRector.php | 108 ++++++++++++++++++ src/Config/Level/DeadCodeLevel.php | 2 + 10 files changed, 299 insertions(+), 2 deletions(-) create mode 100644 rules-tests/DeadCode/Rector/Property/RemoveUselessReadOnlyTagRector/Fixture/remove_on_class.php.inc create mode 100644 rules-tests/DeadCode/Rector/Property/RemoveUselessReadOnlyTagRector/Fixture/remove_on_param_construct.php.inc create mode 100644 rules-tests/DeadCode/Rector/Property/RemoveUselessReadOnlyTagRector/Fixture/remove_on_property.php.inc create mode 100644 rules-tests/DeadCode/Rector/Property/RemoveUselessReadOnlyTagRector/Fixture/skip_no_readonly_doc.php.inc create mode 100644 rules-tests/DeadCode/Rector/Property/RemoveUselessReadOnlyTagRector/Fixture/skip_with_description.php.inc create mode 100644 rules-tests/DeadCode/Rector/Property/RemoveUselessReadOnlyTagRector/RemoveUselessReadOnlyTagRectorTest.php create mode 100644 rules-tests/DeadCode/Rector/Property/RemoveUselessReadOnlyTagRector/config/configured_rule.php create mode 100644 rules/DeadCode/Rector/Property/RemoveUselessReadOnlyTagRector.php diff --git a/build/target-repository/docs/rector_rules_overview.md b/build/target-repository/docs/rector_rules_overview.md index a39279ad1d8..fdacc54a1a0 100644 --- a/build/target-repository/docs/rector_rules_overview.md +++ b/build/target-repository/docs/rector_rules_overview.md @@ -1,4 +1,4 @@ -# 369 Rules Overview +# 370 Rules Overview
@@ -10,7 +10,7 @@ - [CodingStyle](#codingstyle) (28) -- [DeadCode](#deadcode) (43) +- [DeadCode](#deadcode) (44) - [EarlyReturn](#earlyreturn) (9) @@ -2886,6 +2886,29 @@ Remove `@param` docblock with same type as parameter type
+### RemoveUselessReadOnlyTagRector + +Remove useless `@readonly` annotation on native readonly type + +- class: [`Rector\DeadCode\Rector\Property\RemoveUselessReadOnlyTagRector`](../rules/DeadCode/Rector/Property/RemoveUselessReadOnlyTagRector.php) + +```diff + final class SomeClass + { +- /** +- * @readonly +- */ + private readonly string $name; + + public function __construct(string $name) + { + $this->name = $name; + } + } +``` + +
+ ### RemoveUselessReturnExprInConstructRector Remove useless return Expr in `__construct()` diff --git a/rules-tests/DeadCode/Rector/Property/RemoveUselessReadOnlyTagRector/Fixture/remove_on_class.php.inc b/rules-tests/DeadCode/Rector/Property/RemoveUselessReadOnlyTagRector/Fixture/remove_on_class.php.inc new file mode 100644 index 00000000000..df38cce3edb --- /dev/null +++ b/rules-tests/DeadCode/Rector/Property/RemoveUselessReadOnlyTagRector/Fixture/remove_on_class.php.inc @@ -0,0 +1,32 @@ + +----- + diff --git a/rules-tests/DeadCode/Rector/Property/RemoveUselessReadOnlyTagRector/Fixture/remove_on_param_construct.php.inc b/rules-tests/DeadCode/Rector/Property/RemoveUselessReadOnlyTagRector/Fixture/remove_on_param_construct.php.inc new file mode 100644 index 00000000000..1b9b8366114 --- /dev/null +++ b/rules-tests/DeadCode/Rector/Property/RemoveUselessReadOnlyTagRector/Fixture/remove_on_param_construct.php.inc @@ -0,0 +1,32 @@ + +----- + diff --git a/rules-tests/DeadCode/Rector/Property/RemoveUselessReadOnlyTagRector/Fixture/remove_on_property.php.inc b/rules-tests/DeadCode/Rector/Property/RemoveUselessReadOnlyTagRector/Fixture/remove_on_property.php.inc new file mode 100644 index 00000000000..6d7f7b3d7ab --- /dev/null +++ b/rules-tests/DeadCode/Rector/Property/RemoveUselessReadOnlyTagRector/Fixture/remove_on_property.php.inc @@ -0,0 +1,34 @@ +name = $name; + } +} + +?> +----- +name = $name; + } +} + +?> diff --git a/rules-tests/DeadCode/Rector/Property/RemoveUselessReadOnlyTagRector/Fixture/skip_no_readonly_doc.php.inc b/rules-tests/DeadCode/Rector/Property/RemoveUselessReadOnlyTagRector/Fixture/skip_no_readonly_doc.php.inc new file mode 100644 index 00000000000..f2047395390 --- /dev/null +++ b/rules-tests/DeadCode/Rector/Property/RemoveUselessReadOnlyTagRector/Fixture/skip_no_readonly_doc.php.inc @@ -0,0 +1,13 @@ +name = $name; + } +} diff --git a/rules-tests/DeadCode/Rector/Property/RemoveUselessReadOnlyTagRector/Fixture/skip_with_description.php.inc b/rules-tests/DeadCode/Rector/Property/RemoveUselessReadOnlyTagRector/Fixture/skip_with_description.php.inc new file mode 100644 index 00000000000..eb9dd784d86 --- /dev/null +++ b/rules-tests/DeadCode/Rector/Property/RemoveUselessReadOnlyTagRector/Fixture/skip_with_description.php.inc @@ -0,0 +1,16 @@ +name = $name; + } +} diff --git a/rules-tests/DeadCode/Rector/Property/RemoveUselessReadOnlyTagRector/RemoveUselessReadOnlyTagRectorTest.php b/rules-tests/DeadCode/Rector/Property/RemoveUselessReadOnlyTagRector/RemoveUselessReadOnlyTagRectorTest.php new file mode 100644 index 00000000000..90b3a2dc676 --- /dev/null +++ b/rules-tests/DeadCode/Rector/Property/RemoveUselessReadOnlyTagRector/RemoveUselessReadOnlyTagRectorTest.php @@ -0,0 +1,28 @@ +doTestFile($filePath); + } + + public static function provideData(): Iterator + { + return self::yieldFilesFromDirectory(__DIR__ . '/Fixture'); + } + + public function provideConfigFilePath(): string + { + return __DIR__ . '/config/configured_rule.php'; + } +} diff --git a/rules-tests/DeadCode/Rector/Property/RemoveUselessReadOnlyTagRector/config/configured_rule.php b/rules-tests/DeadCode/Rector/Property/RemoveUselessReadOnlyTagRector/config/configured_rule.php new file mode 100644 index 00000000000..862a435388c --- /dev/null +++ b/rules-tests/DeadCode/Rector/Property/RemoveUselessReadOnlyTagRector/config/configured_rule.php @@ -0,0 +1,9 @@ +withRules([RemoveUselessReadOnlyTagRector::class]); diff --git a/rules/DeadCode/Rector/Property/RemoveUselessReadOnlyTagRector.php b/rules/DeadCode/Rector/Property/RemoveUselessReadOnlyTagRector.php new file mode 100644 index 00000000000..664a30ea752 --- /dev/null +++ b/rules/DeadCode/Rector/Property/RemoveUselessReadOnlyTagRector.php @@ -0,0 +1,108 @@ +name = $name; + } +} +CODE_SAMPLE + + , + <<<'CODE_SAMPLE' +final class SomeClass +{ + private readonly string $name; + + public function __construct(string $name) + { + $this->name = $name; + } +} +CODE_SAMPLE + ), + ]); + } + + /** + * @return array> + */ + public function getNodeTypes(): array + { + return [Class_::class, Property::class, Param::class]; + } + + /** + * @param Class_|Property|Param $node + */ + public function refactor(Node $node): ?Node + { + // for param, only on property promotion + if ($node instanceof Param && $node->flags === 0) { + return null; + } + + if (! $this->visibilityManipulator->isReadonly($node)) { + return null; + } + + $phpDocInfo = $this->phpDocInfoFactory->createFromNodeOrEmpty($node); + $readonlyDoc = $phpDocInfo->getByName('readonly'); + if (! $readonlyDoc instanceof PhpDocTagNode) { + return null; + } + + if (! $readonlyDoc->value instanceof GenericTagValueNode) { + return null; + } + + if ($readonlyDoc->value->value !== '') { + return null; + } + + $phpDocInfo->removeByName('readonly'); + $this->docBlockUpdater->updateRefactoredNodeWithPhpDocInfo($node); + + return $node; + } +} diff --git a/src/Config/Level/DeadCodeLevel.php b/src/Config/Level/DeadCodeLevel.php index 7e3ca367ec2..7c92251f1ee 100644 --- a/src/Config/Level/DeadCodeLevel.php +++ b/src/Config/Level/DeadCodeLevel.php @@ -39,6 +39,7 @@ use Rector\DeadCode\Rector\Node\RemoveNonExistingVarAnnotationRector; use Rector\DeadCode\Rector\Plus\RemoveDeadZeroAndOneOperationRector; use Rector\DeadCode\Rector\Property\RemoveUnusedPrivatePropertyRector; +use Rector\DeadCode\Rector\Property\RemoveUselessReadOnlyTagRector; use Rector\DeadCode\Rector\Property\RemoveUselessVarTagRector; use Rector\DeadCode\Rector\PropertyProperty\RemoveNullPropertyInitializationRector; use Rector\DeadCode\Rector\Return_\RemoveDeadConditionAboveReturnRector; @@ -90,6 +91,7 @@ final class DeadCodeLevel // docblock RemoveUselessParamTagRector::class, RemoveUselessReturnTagRector::class, + RemoveUselessReadOnlyTagRector::class, RemoveNonExistingVarAnnotationRector::class, RemoveUselessVarTagRector::class, RemovePhpVersionIdCheckRector::class,