From 0ece3b878d31b00fc3fe00d990b0cd6caa4cb6e4 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Wed, 26 Feb 2025 10:55:20 +0100 Subject: [PATCH 1/3] Implement FinalPrivateConstantRule --- conf/config.level0.neon | 1 + .../Constants/FinalPrivateConstantRule.php | 49 +++++++++++++++++++ .../FinalPrivateConstantRuleTest.php | 27 ++++++++++ .../Constants/data/final-private-const.php | 11 +++++ 4 files changed, 88 insertions(+) create mode 100644 src/Rules/Constants/FinalPrivateConstantRule.php create mode 100644 tests/PHPStan/Rules/Constants/FinalPrivateConstantRuleTest.php create mode 100644 tests/PHPStan/Rules/Constants/data/final-private-const.php diff --git a/conf/config.level0.neon b/conf/config.level0.neon index 9160281651..b5b1f2f793 100644 --- a/conf/config.level0.neon +++ b/conf/config.level0.neon @@ -46,6 +46,7 @@ rules: - PHPStan\Rules\Constants\FinalConstantRule - PHPStan\Rules\Constants\MagicConstantContextRule - PHPStan\Rules\Constants\NativeTypedClassConstantRule + - PHPStan\Rules\Constants\FinalPrivateConstantRule - PHPStan\Rules\EnumCases\EnumCaseAttributesRule - PHPStan\Rules\Exceptions\NoncapturingCatchRule - PHPStan\Rules\Exceptions\ThrowExpressionRule diff --git a/src/Rules/Constants/FinalPrivateConstantRule.php b/src/Rules/Constants/FinalPrivateConstantRule.php new file mode 100644 index 0000000000..e8b29362c5 --- /dev/null +++ b/src/Rules/Constants/FinalPrivateConstantRule.php @@ -0,0 +1,49 @@ + */ +final class FinalPrivateConstantRule implements Rule +{ + + public function getNodeType(): string + { + return ClassConst::class; + } + + public function processNode(Node $node, Scope $scope): array + { + if (!$scope->isInClass()) { + throw new ShouldNotHappenException(); + } + $classReflection = $scope->getClassReflection(); + + if (!$node->isFinal()) { + return []; + } + + if (!$node->isPrivate()) { + return []; + } + + $errors = []; + foreach ($node->consts as $classConstNode) { + $errors[] = RuleErrorBuilder::message(sprintf( + 'Private constant %s::%s() cannot be final as it is not visible to other classes.', + $classReflection->getDisplayName(), + $classConstNode->name->name, + ))->identifier('classConstant.finalPrivate')->build(); + } + + return $errors; + } + +} diff --git a/tests/PHPStan/Rules/Constants/FinalPrivateConstantRuleTest.php b/tests/PHPStan/Rules/Constants/FinalPrivateConstantRuleTest.php new file mode 100644 index 0000000000..6e8e74969b --- /dev/null +++ b/tests/PHPStan/Rules/Constants/FinalPrivateConstantRuleTest.php @@ -0,0 +1,27 @@ + */ +class FinalPrivateConstantRuleTest extends RuleTestCase +{ + + protected function getRule(): Rule + { + return new FinalPrivateConstantRule(); + } + + public function testRule(): void + { + $this->analyse([__DIR__ . '/data/final-private-const.php'], [ + [ + 'Private constant FinalPrivateConstants\User::FINAL_PRIVATE() cannot be final as it is not visible to other classes.', + 8, + ], + ]); + } + +} diff --git a/tests/PHPStan/Rules/Constants/data/final-private-const.php b/tests/PHPStan/Rules/Constants/data/final-private-const.php new file mode 100644 index 0000000000..23c21b1271 --- /dev/null +++ b/tests/PHPStan/Rules/Constants/data/final-private-const.php @@ -0,0 +1,11 @@ + Date: Wed, 26 Feb 2025 17:07:56 +0100 Subject: [PATCH 2/3] fix message --- Makefile | 1 + src/Rules/Constants/FinalPrivateConstantRule.php | 2 +- tests/PHPStan/Rules/Constants/FinalPrivateConstantRuleTest.php | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 1122b4ab0f..11f34d26cd 100644 --- a/Makefile +++ b/Makefile @@ -107,6 +107,7 @@ lint: --exclude tests/PHPStan/Rules/Properties/data/final-property-hooks.php \ --exclude tests/PHPStan/Rules/Properties/data/final-properties.php \ --exclude tests/PHPStan/Rules/Properties/data/property-in-interface-explicit-abstract.php \ + --exclude tests/PHPStan/Rules/Constants/data/final-private-const.php \ src tests cs: diff --git a/src/Rules/Constants/FinalPrivateConstantRule.php b/src/Rules/Constants/FinalPrivateConstantRule.php index e8b29362c5..6856df4af6 100644 --- a/src/Rules/Constants/FinalPrivateConstantRule.php +++ b/src/Rules/Constants/FinalPrivateConstantRule.php @@ -37,7 +37,7 @@ public function processNode(Node $node, Scope $scope): array $errors = []; foreach ($node->consts as $classConstNode) { $errors[] = RuleErrorBuilder::message(sprintf( - 'Private constant %s::%s() cannot be final as it is not visible to other classes.', + 'Private constant %s::%s() cannot be final as it is never overridden by other classes.', $classReflection->getDisplayName(), $classConstNode->name->name, ))->identifier('classConstant.finalPrivate')->build(); diff --git a/tests/PHPStan/Rules/Constants/FinalPrivateConstantRuleTest.php b/tests/PHPStan/Rules/Constants/FinalPrivateConstantRuleTest.php index 6e8e74969b..8e98e04565 100644 --- a/tests/PHPStan/Rules/Constants/FinalPrivateConstantRuleTest.php +++ b/tests/PHPStan/Rules/Constants/FinalPrivateConstantRuleTest.php @@ -18,7 +18,7 @@ public function testRule(): void { $this->analyse([__DIR__ . '/data/final-private-const.php'], [ [ - 'Private constant FinalPrivateConstants\User::FINAL_PRIVATE() cannot be final as it is not visible to other classes.', + 'Private constant FinalPrivateConstants\User::FINAL_PRIVATE() cannot be final as it is never overridden by other classes.', 8, ], ]); From c650a3c5f20449c3ee548aedb30fa8b56c2bd9d8 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Wed, 26 Feb 2025 17:22:06 +0100 Subject: [PATCH 3/3] Update FinalPrivateConstantRule.php --- src/Rules/Constants/FinalPrivateConstantRule.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Rules/Constants/FinalPrivateConstantRule.php b/src/Rules/Constants/FinalPrivateConstantRule.php index 6856df4af6..2be7d51165 100644 --- a/src/Rules/Constants/FinalPrivateConstantRule.php +++ b/src/Rules/Constants/FinalPrivateConstantRule.php @@ -40,7 +40,7 @@ public function processNode(Node $node, Scope $scope): array 'Private constant %s::%s() cannot be final as it is never overridden by other classes.', $classReflection->getDisplayName(), $classConstNode->name->name, - ))->identifier('classConstant.finalPrivate')->build(); + ))->identifier('classConstant.finalPrivate')->nonIgnorable()->build(); } return $errors;