From d58da3a0201c58b2647a65dc55199960f649df2c Mon Sep 17 00:00:00 2001 From: Martin Herndl Date: Thu, 2 Jun 2022 20:31:49 +0200 Subject: [PATCH 1/3] Add @readonly rule that disallows default values --- conf/config.level0.neon | 5 +++ .../ReadOnlyByPhpDocPropertyRule.php | 36 +++++++++++++++++++ .../ReadOnlyByPhpDocPropertyRuleTest.php | 29 +++++++++++++++ .../data/read-only-property-phpdoc.php | 23 ++++++++++++ 4 files changed, 93 insertions(+) create mode 100644 src/Rules/Properties/ReadOnlyByPhpDocPropertyRule.php create mode 100644 tests/PHPStan/Rules/Properties/ReadOnlyByPhpDocPropertyRuleTest.php create mode 100644 tests/PHPStan/Rules/Properties/data/read-only-property-phpdoc.php diff --git a/conf/config.level0.neon b/conf/config.level0.neon index 95f20d2528..482aae9d64 100644 --- a/conf/config.level0.neon +++ b/conf/config.level0.neon @@ -6,6 +6,8 @@ conditionalTags: phpstan.rules.rule: %featureToggles.nodeConnectingVisitorRule% PHPStan\Rules\Properties\MissingReadOnlyByPhpDocPropertyAssignRule: phpstan.rules.rule: %featureToggles.readOnlyByPhpDoc% + PHPStan\Rules\Properties\ReadOnlyByPhpDocPropertyRule: + phpstan.rules.rule: %featureToggles.readOnlyByPhpDoc% PHPStan\Rules\Properties\UninitializedPropertyRule: phpstan.rules.rule: %checkUninitializedProperties% PHPStan\Rules\Methods\ConsistentConstructorRule: @@ -188,6 +190,9 @@ services: tags: - phpstan.rules.rule + - + class: PHPStan\Rules\Properties\ReadOnlyByPhpDocPropertyRule + - class: PHPStan\Rules\Properties\UninitializedPropertyRule diff --git a/src/Rules/Properties/ReadOnlyByPhpDocPropertyRule.php b/src/Rules/Properties/ReadOnlyByPhpDocPropertyRule.php new file mode 100644 index 0000000000..e0f4b00532 --- /dev/null +++ b/src/Rules/Properties/ReadOnlyByPhpDocPropertyRule.php @@ -0,0 +1,36 @@ + + */ +class ReadOnlyByPhpDocPropertyRule implements Rule +{ + + public function getNodeType(): string + { + return ClassPropertyNode::class; + } + + public function processNode(Node $node, Scope $scope): array + { + if (!$node->isReadOnlyByPhpDoc()) { + return []; + } + + $errors = []; + if ($node->getDefault() !== null) { + $errors[] = RuleErrorBuilder::message('@readonly property cannot have a default value.')->nonIgnorable()->build(); + } + + return $errors; + } + +} diff --git a/tests/PHPStan/Rules/Properties/ReadOnlyByPhpDocPropertyRuleTest.php b/tests/PHPStan/Rules/Properties/ReadOnlyByPhpDocPropertyRuleTest.php new file mode 100644 index 0000000000..b13c566b4f --- /dev/null +++ b/tests/PHPStan/Rules/Properties/ReadOnlyByPhpDocPropertyRuleTest.php @@ -0,0 +1,29 @@ + + */ +class ReadOnlyByPhpDocPropertyRuleTest extends RuleTestCase +{ + + protected function getRule(): Rule + { + return new ReadOnlyByPhpDocPropertyRule(); + } + + public function testRule(): void + { + $this->analyse([__DIR__ . '/data/read-only-property-phpdoc.php'], [ + [ + '@readonly property cannot have a default value.', + 21, + ], + ]); + } + +} diff --git a/tests/PHPStan/Rules/Properties/data/read-only-property-phpdoc.php b/tests/PHPStan/Rules/Properties/data/read-only-property-phpdoc.php new file mode 100644 index 0000000000..6522f2668b --- /dev/null +++ b/tests/PHPStan/Rules/Properties/data/read-only-property-phpdoc.php @@ -0,0 +1,23 @@ + Date: Fri, 3 Jun 2022 20:56:55 +0200 Subject: [PATCH 2/3] make error ignorable --- src/Rules/Properties/ReadOnlyByPhpDocPropertyRule.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Rules/Properties/ReadOnlyByPhpDocPropertyRule.php b/src/Rules/Properties/ReadOnlyByPhpDocPropertyRule.php index e0f4b00532..96e793b776 100644 --- a/src/Rules/Properties/ReadOnlyByPhpDocPropertyRule.php +++ b/src/Rules/Properties/ReadOnlyByPhpDocPropertyRule.php @@ -27,7 +27,7 @@ public function processNode(Node $node, Scope $scope): array $errors = []; if ($node->getDefault() !== null) { - $errors[] = RuleErrorBuilder::message('@readonly property cannot have a default value.')->nonIgnorable()->build(); + $errors[] = RuleErrorBuilder::message('@readonly property cannot have a default value.')->build(); } return $errors; From 2e93957fa89329e172287fecd6d8a74c01f81394 Mon Sep 17 00:00:00 2001 From: Martin Herndl Date: Fri, 3 Jun 2022 21:55:04 +0200 Subject: [PATCH 3/3] Add a promoted property test --- .../Properties/ReadOnlyByPhpDocPropertyRuleTest.php | 5 +++++ .../Properties/data/read-only-property-phpdoc.php | 12 +++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/tests/PHPStan/Rules/Properties/ReadOnlyByPhpDocPropertyRuleTest.php b/tests/PHPStan/Rules/Properties/ReadOnlyByPhpDocPropertyRuleTest.php index b13c566b4f..94f906d60c 100644 --- a/tests/PHPStan/Rules/Properties/ReadOnlyByPhpDocPropertyRuleTest.php +++ b/tests/PHPStan/Rules/Properties/ReadOnlyByPhpDocPropertyRuleTest.php @@ -4,6 +4,7 @@ use PHPStan\Rules\Rule; use PHPStan\Testing\RuleTestCase; +use const PHP_VERSION_ID; /** * @extends RuleTestCase @@ -18,6 +19,10 @@ protected function getRule(): Rule public function testRule(): void { + if (PHP_VERSION_ID < 80100) { + $this->markTestSkipped('Test requires PHP 8.1.'); + } + $this->analyse([__DIR__ . '/data/read-only-property-phpdoc.php'], [ [ '@readonly property cannot have a default value.', diff --git a/tests/PHPStan/Rules/Properties/data/read-only-property-phpdoc.php b/tests/PHPStan/Rules/Properties/data/read-only-property-phpdoc.php index 6522f2668b..bb730d8e01 100644 --- a/tests/PHPStan/Rules/Properties/data/read-only-property-phpdoc.php +++ b/tests/PHPStan/Rules/Properties/data/read-only-property-phpdoc.php @@ -1,4 +1,4 @@ -= 8.1 namespace ReadOnlyPropertyPhpDoc; @@ -21,3 +21,13 @@ class Foo private $baz = 0; } + +final class ErrorResponse +{ + public function __construct( + /** @readonly */ + public string $message = '' + ) + { + } +}