From e48811f723d94cc2b4ebfe4af86aa3ed2ce9d6e7 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Sat, 20 Jun 2026 19:46:57 +0200 Subject: [PATCH] Implement ClassAttributeRequiresPhpVersionRule --- rules.neon | 6 ++ .../ClassAttributeRequiresPhpVersionRule.php | 44 +++++++++++++ .../ClassAttributeRequiresPhpVersionRule.neon | 2 + ...assAttributeRequiresPhpVersionRuleTest.php | 63 +++++++++++++++++++ .../data/requires-php-version-on-class.php | 24 +++++++ 5 files changed, 139 insertions(+) create mode 100644 src/Rules/PHPUnit/ClassAttributeRequiresPhpVersionRule.php create mode 100644 tests/Rules/PHPUnit/ClassAttributeRequiresPhpVersionRule.neon create mode 100644 tests/Rules/PHPUnit/ClassAttributeRequiresPhpVersionRuleTest.php create mode 100644 tests/Rules/PHPUnit/data/requires-php-version-on-class.php diff --git a/rules.neon b/rules.neon index 7809d66..9d2d947 100644 --- a/rules.neon +++ b/rules.neon @@ -16,6 +16,9 @@ conditionalTags: PHPStan\Rules\PHPUnit\DataProviderDataRule: phpstan.rules.rule: %featureToggles.bleedingEdge% + PHPStan\Rules\PHPUnit\ClassAttributeRequiresPhpVersionRule: + phpstan.rules.rule: %featureToggles.bleedingEdge% + services: - class: PHPStan\Rules\PHPUnit\DataProviderDeclarationRule @@ -30,6 +33,9 @@ services: tags: - phpstan.rules.rule + - + class: PHPStan\Rules\PHPUnit\ClassAttributeRequiresPhpVersionRule + - class: PHPStan\Rules\PHPUnit\AssertEqualsIsDiscouragedRule diff --git a/src/Rules/PHPUnit/ClassAttributeRequiresPhpVersionRule.php b/src/Rules/PHPUnit/ClassAttributeRequiresPhpVersionRule.php new file mode 100644 index 0000000..74c1f43 --- /dev/null +++ b/src/Rules/PHPUnit/ClassAttributeRequiresPhpVersionRule.php @@ -0,0 +1,44 @@ + + */ +class ClassAttributeRequiresPhpVersionRule implements Rule +{ + + private AttributeVersionRequirementHelper $attributeVersionRequirementHelper; + + public function __construct( + AttributeVersionRequirementHelper $attributeVersionRequirementHelper + ) + { + $this->attributeVersionRequirementHelper = $attributeVersionRequirementHelper; + } + + public function getNodeType(): string + { + return InClassNode::class; + } + + public function processNode(Node $node, Scope $scope): array + { + $classReflection = $scope->getClassReflection(); + if ($classReflection === null || $classReflection->is(TestCase::class) === false) { + return []; + } + + return $this->attributeVersionRequirementHelper->checkRequiresPhpVersion( + $classReflection->getNativeReflection()->getBetterReflection()->getAttributesByName('PHPUnit\Framework\Attributes\RequiresPhp'), + $scope, + ); + } + +} diff --git a/tests/Rules/PHPUnit/ClassAttributeRequiresPhpVersionRule.neon b/tests/Rules/PHPUnit/ClassAttributeRequiresPhpVersionRule.neon new file mode 100644 index 0000000..72ae924 --- /dev/null +++ b/tests/Rules/PHPUnit/ClassAttributeRequiresPhpVersionRule.neon @@ -0,0 +1,2 @@ +parameters: + phpVersion: 80500 diff --git a/tests/Rules/PHPUnit/ClassAttributeRequiresPhpVersionRuleTest.php b/tests/Rules/PHPUnit/ClassAttributeRequiresPhpVersionRuleTest.php new file mode 100644 index 0000000..113187f --- /dev/null +++ b/tests/Rules/PHPUnit/ClassAttributeRequiresPhpVersionRuleTest.php @@ -0,0 +1,63 @@ + + */ +final class ClassAttributeRequiresPhpVersionRuleTest extends RuleTestCase +{ + + private int $phpVersion = 80500; + + private int $phpunitMajorVersion; + + private int $phpunitMinorVersion; + + private bool $warnAboutIncompleteVersion = false; + + public function testWarnAboutIncompleteVersion(): void + { + $this->phpunitMajorVersion = 12; + $this->phpunitMinorVersion = 5; + $this->warnAboutIncompleteVersion = true; + + $this->analyse([__DIR__ . '/data/requires-php-version-on-class.php'], [ + [ + 'Version requirement will always evaluate to false.', + 10, + ], + [ + 'Version requirement is incomplete.', + 10, + ], + ]); + } + + protected function getRule(): Rule + { + $phpunitVersion = new PHPUnitVersion($this->phpunitMajorVersion, $this->phpunitMinorVersion); + + return new ClassAttributeRequiresPhpVersionRule( + new AttributeVersionRequirementHelper( + $phpunitVersion, + false, + new PhpVersion($this->phpVersion), + true, + $this->warnAboutIncompleteVersion, + ), + ); + } + + public static function getAdditionalConfigFiles(): array + { + return [ + __DIR__ . '/ClassAttributeRequiresPhpVersionRule.neon', + ]; + } + +} diff --git a/tests/Rules/PHPUnit/data/requires-php-version-on-class.php b/tests/Rules/PHPUnit/data/requires-php-version-on-class.php new file mode 100644 index 0000000..00500d4 --- /dev/null +++ b/tests/Rules/PHPUnit/data/requires-php-version-on-class.php @@ -0,0 +1,24 @@ +=8.0.0')] +class CorrectRequirementOnClass extends TestCase +{ + public function testBar(): void { + + } +}