From 9bb325bbdb66754d269800b9b8be1b7ee2ff2624 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Thu, 14 Nov 2024 11:47:46 +0100 Subject: [PATCH 01/11] Implement Scope->getPhpVersion() --- src/Analyser/MutatingScope.php | 32 ++++++++++ src/Analyser/Scope.php | 3 + src/Php/PhpVersions.php | 58 +++++++++++++++++++ src/Rules/Methods/FinalPrivateMethodRule.php | 9 +-- .../Methods/FinalPrivateMethodRuleTest.php | 40 ++++--------- .../Methods/data/final-private-method.php | 30 ++++++++++ 6 files changed, 136 insertions(+), 36 deletions(-) create mode 100644 src/Php/PhpVersions.php diff --git a/src/Analyser/MutatingScope.php b/src/Analyser/MutatingScope.php index b8dcee4fd8..152a16f8da 100644 --- a/src/Analyser/MutatingScope.php +++ b/src/Analyser/MutatingScope.php @@ -47,6 +47,7 @@ use PHPStan\Parser\NewAssignedToPropertyVisitor; use PHPStan\Parser\Parser; use PHPStan\Php\PhpVersion; +use PHPStan\Php\PhpVersions; use PHPStan\PhpDoc\Tag\TemplateTag; use PHPStan\Reflection\Assertions; use PHPStan\Reflection\Callables\CallableParametersAcceptor; @@ -144,6 +145,7 @@ use function implode; use function in_array; use function is_bool; +use function is_int; use function is_numeric; use function is_string; use function ltrim; @@ -5721,4 +5723,34 @@ public function getIterableValueType(Type $iteratee): Type return $iteratee->getIterableValueType(); } + public function getPhpVersions(): PhpVersions + { + $versionId = $this->getType(new ConstFetch(new Name('PHP_VERSION_ID'))); + if ($versionId instanceof IntegerRangeType) { + if ($versionId->getMin() !== null && $versionId->getMax() !== null) { + return new PhpVersions([$versionId->getMin(), $versionId->getMax()]); + } + if ($versionId->getMin() !== null) { + return new PhpVersions([$versionId->getMin()]); + } + if ($versionId->getMax() !== null) { + return new PhpVersions([$versionId->getMax()]); + } + } + + $scalars = $versionId->getConstantScalarValues(); + if ($scalars !== []) { + $ints = []; + foreach ($scalars as $scalar) { + if (!is_int($scalar)) { + throw new ShouldNotHappenException(); + } + $ints[] = $scalar; + } + return new PhpVersions($ints); + } + + return new PhpVersions([$this->phpVersion->getVersionId()]); + } + } diff --git a/src/Analyser/Scope.php b/src/Analyser/Scope.php index a14c9d108d..64e83d87f7 100644 --- a/src/Analyser/Scope.php +++ b/src/Analyser/Scope.php @@ -6,6 +6,7 @@ use PhpParser\Node\Expr; use PhpParser\Node\Name; use PhpParser\Node\Param; +use PHPStan\Php\PhpVersions; use PHPStan\Reflection\ClassConstantReflection; use PHPStan\Reflection\ClassMemberAccessAnswerer; use PHPStan\Reflection\ClassReflection; @@ -136,4 +137,6 @@ public function filterByFalseyValue(Expr $expr): self; public function isInFirstLevelStatement(): bool; + public function getPhpVersions(): PhpVersions; + } diff --git a/src/Php/PhpVersions.php b/src/Php/PhpVersions.php new file mode 100644 index 0000000000..f92e025506 --- /dev/null +++ b/src/Php/PhpVersions.php @@ -0,0 +1,58 @@ + $phpVersionIds + */ + public function __construct( + array $phpVersionIds, + ) + { + if ($phpVersionIds === []) { + throw new ShouldNotHappenException(); + } + + $normalizedPhpVersionIds = []; + foreach ($phpVersionIds as $versionId) { + // drop patch version part and replace with 00 + $normalizedPhpVersionIds[] = ((int) ($versionId / 100)) * 100; + } + + $this->minVersionId = min($normalizedPhpVersionIds); + $this->maxVersionId = max($normalizedPhpVersionIds); + } + + public function producesWarningForFinalPrivateMethods(): TrinaryLogic + { + return $this->minPhpVersion(80000); + } + + private function minPhpVersion(int $versionId): TrinaryLogic + { + if ($this->minVersionId >= $versionId) { + return TrinaryLogic::createYes(); + } + if ($this->maxVersionId >= $versionId) { + return TrinaryLogic::createMaybe(); + } + return TrinaryLogic::createNo(); + } + +} diff --git a/src/Rules/Methods/FinalPrivateMethodRule.php b/src/Rules/Methods/FinalPrivateMethodRule.php index b205234dc2..16a2c0fde8 100644 --- a/src/Rules/Methods/FinalPrivateMethodRule.php +++ b/src/Rules/Methods/FinalPrivateMethodRule.php @@ -5,7 +5,6 @@ use PhpParser\Node; use PHPStan\Analyser\Scope; use PHPStan\Node\InClassMethodNode; -use PHPStan\Php\PhpVersion; use PHPStan\Rules\Rule; use PHPStan\Rules\RuleErrorBuilder; use function sprintf; @@ -14,12 +13,6 @@ final class FinalPrivateMethodRule implements Rule { - public function __construct( - private PhpVersion $phpVersion, - ) - { - } - public function getNodeType(): string { return InClassMethodNode::class; @@ -28,7 +21,7 @@ public function getNodeType(): string public function processNode(Node $node, Scope $scope): array { $method = $node->getMethodReflection(); - if (!$this->phpVersion->producesWarningForFinalPrivateMethods()) { + if ($scope->getPhpVersions()->producesWarningForFinalPrivateMethods()->no()) { return []; } diff --git a/tests/PHPStan/Rules/Methods/FinalPrivateMethodRuleTest.php b/tests/PHPStan/Rules/Methods/FinalPrivateMethodRuleTest.php index 64a4b89c0f..e15d33af06 100644 --- a/tests/PHPStan/Rules/Methods/FinalPrivateMethodRuleTest.php +++ b/tests/PHPStan/Rules/Methods/FinalPrivateMethodRuleTest.php @@ -2,7 +2,6 @@ namespace PHPStan\Rules\Methods; -use PHPStan\Php\PhpVersion; use PHPStan\Rules\Rule; use PHPStan\Testing\RuleTestCase; @@ -10,42 +9,27 @@ class FinalPrivateMethodRuleTest extends RuleTestCase { - private int $phpVersionId; - protected function getRule(): Rule { - return new FinalPrivateMethodRule( - new PhpVersion($this->phpVersionId), - ); + return new FinalPrivateMethodRule(); } - public function dataRule(): array + public function testRule(): void { - return [ + $this->analyse([__DIR__ . '/data/final-private-method.php'], [ [ - 70400, - [], + 'Private method FinalPrivateMethod\Foo::foo() cannot be final as it is never overridden by other classes.', + 8, ], [ - 80000, - [ - [ - 'Private method FinalPrivateMethod\Foo::foo() cannot be final as it is never overridden by other classes.', - 8, - ], - ], + 'Private method FinalPrivateMethod\FooBarPhp8orHigher::foo() cannot be final as it is never overridden by other classes.', + 39, ], - ]; - } - - /** - * @dataProvider dataRule - * @param list $errors - */ - public function testRule(int $phpVersion, array $errors): void - { - $this->phpVersionId = $phpVersion; - $this->analyse([__DIR__ . '/data/final-private-method.php'], $errors); + [ + 'Private method FinalPrivateMethod\FooBarPhp74OrHigher::foo() cannot be final as it is never overridden by other classes.', + 59, + ], + ]); } } diff --git a/tests/PHPStan/Rules/Methods/data/final-private-method.php b/tests/PHPStan/Rules/Methods/data/final-private-method.php index bb06450219..db770dd29a 100644 --- a/tests/PHPStan/Rules/Methods/data/final-private-method.php +++ b/tests/PHPStan/Rules/Methods/data/final-private-method.php @@ -31,3 +31,33 @@ final private function __construct() } } + +if (PHP_VERSION_ID >= 80000) { + class FooBarPhp8orHigher + { + + final private function foo(): void + { + } + } +} + +if (PHP_VERSION_ID < 80000) { + class FooBarPhp7 + { + + final private function foo(): void + { + } + } +} + +if (PHP_VERSION_ID > 70400) { + class FooBarPhp74OrHigher + { + + final private function foo(): void + { + } + } +} From 935b88b0dc12c7827e746aa4958428155d46d785 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Sun, 17 Nov 2024 18:21:48 +0100 Subject: [PATCH 02/11] deprecate old producesWarningForFinalPrivateMethods variant --- src/Php/PhpVersion.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Php/PhpVersion.php b/src/Php/PhpVersion.php index 8520f6488d..23c246641a 100644 --- a/src/Php/PhpVersion.php +++ b/src/Php/PhpVersion.php @@ -248,6 +248,9 @@ public function supportsPassNoneEncodings(): bool return $this->versionId < 70300; } + /** + * @deprecated use PhpVersions::producesWarningForFinalPrivateMethods() instead + */ public function producesWarningForFinalPrivateMethods(): bool { return $this->versionId >= 80000; From 6928a8879888e69a7dea4b49687fcf0b469eb5c6 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Tue, 19 Nov 2024 21:04:09 +0100 Subject: [PATCH 03/11] fix --- src/Analyser/MutatingScope.php | 9 +++++++-- src/Analyser/Scope.php | 2 +- src/Php/PhpVersion.php | 3 --- src/Php/PhpVersions.php | 1 - src/Rules/Methods/FinalPrivateMethodRule.php | 2 +- 5 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/Analyser/MutatingScope.php b/src/Analyser/MutatingScope.php index 152a16f8da..43fa6c540e 100644 --- a/src/Analyser/MutatingScope.php +++ b/src/Analyser/MutatingScope.php @@ -5723,9 +5723,14 @@ public function getIterableValueType(Type $iteratee): Type return $iteratee->getIterableValueType(); } - public function getPhpVersions(): PhpVersions + public function getPhpVersion(): PhpVersions { - $versionId = $this->getType(new ConstFetch(new Name('PHP_VERSION_ID'))); + $versionExpr = new ConstFetch(new Name('PHP_VERSION_ID')); + if (!$this->hasExpressionType($versionExpr)->yes()) { + return new PhpVersions([$this->phpVersion->getVersionId()]); + } + + $versionId = $this->getType($versionExpr); if ($versionId instanceof IntegerRangeType) { if ($versionId->getMin() !== null && $versionId->getMax() !== null) { return new PhpVersions([$versionId->getMin(), $versionId->getMax()]); diff --git a/src/Analyser/Scope.php b/src/Analyser/Scope.php index 64e83d87f7..bf89cbdf48 100644 --- a/src/Analyser/Scope.php +++ b/src/Analyser/Scope.php @@ -137,6 +137,6 @@ public function filterByFalseyValue(Expr $expr): self; public function isInFirstLevelStatement(): bool; - public function getPhpVersions(): PhpVersions; + public function getPhpVersion(): PhpVersions; } diff --git a/src/Php/PhpVersion.php b/src/Php/PhpVersion.php index 23c246641a..8520f6488d 100644 --- a/src/Php/PhpVersion.php +++ b/src/Php/PhpVersion.php @@ -248,9 +248,6 @@ public function supportsPassNoneEncodings(): bool return $this->versionId < 70300; } - /** - * @deprecated use PhpVersions::producesWarningForFinalPrivateMethods() instead - */ public function producesWarningForFinalPrivateMethods(): bool { return $this->versionId >= 80000; diff --git a/src/Php/PhpVersions.php b/src/Php/PhpVersions.php index f92e025506..0a02454165 100644 --- a/src/Php/PhpVersions.php +++ b/src/Php/PhpVersions.php @@ -18,7 +18,6 @@ final class PhpVersions private int $maxVersionId; /** - * @api * @param list $phpVersionIds */ public function __construct( diff --git a/src/Rules/Methods/FinalPrivateMethodRule.php b/src/Rules/Methods/FinalPrivateMethodRule.php index 16a2c0fde8..7331e21bc1 100644 --- a/src/Rules/Methods/FinalPrivateMethodRule.php +++ b/src/Rules/Methods/FinalPrivateMethodRule.php @@ -21,7 +21,7 @@ public function getNodeType(): string public function processNode(Node $node, Scope $scope): array { $method = $node->getMethodReflection(); - if ($scope->getPhpVersions()->producesWarningForFinalPrivateMethods()->no()) { + if ($scope->getPhpVersion()->producesWarningForFinalPrivateMethods()->no()) { return []; } From 3abd8121ea327b6b2685d8f2418fc08c568c3a5d Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Tue, 19 Nov 2024 21:56:49 +0100 Subject: [PATCH 04/11] fix --- src/Analyser/MutatingScope.php | 30 +------------- src/Php/PhpVersions.php | 39 ++----------------- .../Methods/FinalPrivateMethodRuleTest.php | 4 ++ .../Methods/data/final-private-method.php | 10 +++++ 4 files changed, 20 insertions(+), 63 deletions(-) diff --git a/src/Analyser/MutatingScope.php b/src/Analyser/MutatingScope.php index 43fa6c540e..61f16a5119 100644 --- a/src/Analyser/MutatingScope.php +++ b/src/Analyser/MutatingScope.php @@ -145,7 +145,6 @@ use function implode; use function in_array; use function is_bool; -use function is_int; use function is_numeric; use function is_string; use function ltrim; @@ -5727,35 +5726,10 @@ public function getPhpVersion(): PhpVersions { $versionExpr = new ConstFetch(new Name('PHP_VERSION_ID')); if (!$this->hasExpressionType($versionExpr)->yes()) { - return new PhpVersions([$this->phpVersion->getVersionId()]); + return new PhpVersions(new ConstantIntegerType($this->phpVersion->getVersionId())); } - $versionId = $this->getType($versionExpr); - if ($versionId instanceof IntegerRangeType) { - if ($versionId->getMin() !== null && $versionId->getMax() !== null) { - return new PhpVersions([$versionId->getMin(), $versionId->getMax()]); - } - if ($versionId->getMin() !== null) { - return new PhpVersions([$versionId->getMin()]); - } - if ($versionId->getMax() !== null) { - return new PhpVersions([$versionId->getMax()]); - } - } - - $scalars = $versionId->getConstantScalarValues(); - if ($scalars !== []) { - $ints = []; - foreach ($scalars as $scalar) { - if (!is_int($scalar)) { - throw new ShouldNotHappenException(); - } - $ints[] = $scalar; - } - return new PhpVersions($ints); - } - - return new PhpVersions([$this->phpVersion->getVersionId()]); + return new PhpVersions($this->getType($versionExpr)); } } diff --git a/src/Php/PhpVersions.php b/src/Php/PhpVersions.php index 0a02454165..e4b0c165f7 100644 --- a/src/Php/PhpVersions.php +++ b/src/Php/PhpVersions.php @@ -2,10 +2,9 @@ namespace PHPStan\Php; -use PHPStan\ShouldNotHappenException; use PHPStan\TrinaryLogic; -use function max; -use function min; +use PHPStan\Type\IntegerRangeType; +use PHPStan\Type\Type; /** * @api @@ -13,45 +12,15 @@ final class PhpVersions { - private int $minVersionId; - - private int $maxVersionId; - - /** - * @param list $phpVersionIds - */ public function __construct( - array $phpVersionIds, + private Type $phpVersions, ) { - if ($phpVersionIds === []) { - throw new ShouldNotHappenException(); - } - - $normalizedPhpVersionIds = []; - foreach ($phpVersionIds as $versionId) { - // drop patch version part and replace with 00 - $normalizedPhpVersionIds[] = ((int) ($versionId / 100)) * 100; - } - - $this->minVersionId = min($normalizedPhpVersionIds); - $this->maxVersionId = max($normalizedPhpVersionIds); } public function producesWarningForFinalPrivateMethods(): TrinaryLogic { - return $this->minPhpVersion(80000); - } - - private function minPhpVersion(int $versionId): TrinaryLogic - { - if ($this->minVersionId >= $versionId) { - return TrinaryLogic::createYes(); - } - if ($this->maxVersionId >= $versionId) { - return TrinaryLogic::createMaybe(); - } - return TrinaryLogic::createNo(); + return $this->phpVersions->isSuperTypeOf(IntegerRangeType::fromInterval(80000, null))->result; } } diff --git a/tests/PHPStan/Rules/Methods/FinalPrivateMethodRuleTest.php b/tests/PHPStan/Rules/Methods/FinalPrivateMethodRuleTest.php index e15d33af06..7da02182b5 100644 --- a/tests/PHPStan/Rules/Methods/FinalPrivateMethodRuleTest.php +++ b/tests/PHPStan/Rules/Methods/FinalPrivateMethodRuleTest.php @@ -29,6 +29,10 @@ public function testRule(): void 'Private method FinalPrivateMethod\FooBarPhp74OrHigher::foo() cannot be final as it is never overridden by other classes.', 59, ], + [ + 'Private method FinalPrivateMethod\FooBarPhp8orHigher::foo() cannot be final as it is never overridden by other classes.', + 69, + ], ]); } diff --git a/tests/PHPStan/Rules/Methods/data/final-private-method.php b/tests/PHPStan/Rules/Methods/data/final-private-method.php index db770dd29a..4a48b43683 100644 --- a/tests/PHPStan/Rules/Methods/data/final-private-method.php +++ b/tests/PHPStan/Rules/Methods/data/final-private-method.php @@ -61,3 +61,13 @@ final private function foo(): void } } } + +if (PHP_VERSION_ID < 70400 || PHP_VERSION_ID >= 80100) { + class FooBarPhp8orHigher + { + + final private function foo(): void + { + } + } +} From 0a602702fb7ed0b2aca045dfcb1c013f73cb6468 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Tue, 19 Nov 2024 22:00:02 +0100 Subject: [PATCH 05/11] Update final-private-method.php --- tests/PHPStan/Rules/Methods/data/final-private-method.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/PHPStan/Rules/Methods/data/final-private-method.php b/tests/PHPStan/Rules/Methods/data/final-private-method.php index 4a48b43683..eec2ff3095 100644 --- a/tests/PHPStan/Rules/Methods/data/final-private-method.php +++ b/tests/PHPStan/Rules/Methods/data/final-private-method.php @@ -63,7 +63,7 @@ final private function foo(): void } if (PHP_VERSION_ID < 70400 || PHP_VERSION_ID >= 80100) { - class FooBarPhp8orHigher + class FooBarBaz { final private function foo(): void From 7a0a78fa6e8fa864e7fc4b18580b83ead298e5d0 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Tue, 19 Nov 2024 22:04:09 +0100 Subject: [PATCH 06/11] Update FinalPrivateMethodRuleTest.php --- tests/PHPStan/Rules/Methods/FinalPrivateMethodRuleTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/PHPStan/Rules/Methods/FinalPrivateMethodRuleTest.php b/tests/PHPStan/Rules/Methods/FinalPrivateMethodRuleTest.php index 7da02182b5..c6d27d7584 100644 --- a/tests/PHPStan/Rules/Methods/FinalPrivateMethodRuleTest.php +++ b/tests/PHPStan/Rules/Methods/FinalPrivateMethodRuleTest.php @@ -30,7 +30,7 @@ public function testRule(): void 59, ], [ - 'Private method FinalPrivateMethod\FooBarPhp8orHigher::foo() cannot be final as it is never overridden by other classes.', + 'Private method FinalPrivateMethod\FooBarBaz::foo() cannot be final as it is never overridden by other classes.', 69, ], ]); From b4bbcee92ef1b5b77f5c0aac6958d7899efa7514 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Tue, 19 Nov 2024 22:10:14 +0100 Subject: [PATCH 07/11] fix test on php 7.4 --- .../Rules/Methods/FinalPrivateMethodRuleTest.php | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/tests/PHPStan/Rules/Methods/FinalPrivateMethodRuleTest.php b/tests/PHPStan/Rules/Methods/FinalPrivateMethodRuleTest.php index c6d27d7584..c815bd1d22 100644 --- a/tests/PHPStan/Rules/Methods/FinalPrivateMethodRuleTest.php +++ b/tests/PHPStan/Rules/Methods/FinalPrivateMethodRuleTest.php @@ -4,6 +4,7 @@ use PHPStan\Rules\Rule; use PHPStan\Testing\RuleTestCase; +use const PHP_VERSION_ID; /** @extends RuleTestCase */ class FinalPrivateMethodRuleTest extends RuleTestCase @@ -16,11 +17,16 @@ protected function getRule(): Rule public function testRule(): void { - $this->analyse([__DIR__ . '/data/final-private-method.php'], [ - [ + $error = []; + if (PHP_VERSION_ID >= 80000) { + $error = [ 'Private method FinalPrivateMethod\Foo::foo() cannot be final as it is never overridden by other classes.', 8, - ], + ]; + } + + $this->analyse([__DIR__ . '/data/final-private-method.php'], [ + $error, [ 'Private method FinalPrivateMethod\FooBarPhp8orHigher::foo() cannot be final as it is never overridden by other classes.', 39, From 45eb043216a644b1dd8631a6e19a0f404f5e3e72 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Tue, 19 Nov 2024 22:17:19 +0100 Subject: [PATCH 08/11] Update FinalPrivateMethodRuleTest.php --- .../Rules/Methods/FinalPrivateMethodRuleTest.php | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/tests/PHPStan/Rules/Methods/FinalPrivateMethodRuleTest.php b/tests/PHPStan/Rules/Methods/FinalPrivateMethodRuleTest.php index c815bd1d22..337d041eb7 100644 --- a/tests/PHPStan/Rules/Methods/FinalPrivateMethodRuleTest.php +++ b/tests/PHPStan/Rules/Methods/FinalPrivateMethodRuleTest.php @@ -4,6 +4,7 @@ use PHPStan\Rules\Rule; use PHPStan\Testing\RuleTestCase; +use function array_merge; use const PHP_VERSION_ID; /** @extends RuleTestCase */ @@ -17,16 +18,17 @@ protected function getRule(): Rule public function testRule(): void { - $error = []; + $errors = []; if (PHP_VERSION_ID >= 80000) { - $error = [ - 'Private method FinalPrivateMethod\Foo::foo() cannot be final as it is never overridden by other classes.', - 8, + $errors = [ + [ + 'Private method FinalPrivateMethod\Foo::foo() cannot be final as it is never overridden by other classes.', + 8, + ], ]; } - $this->analyse([__DIR__ . '/data/final-private-method.php'], [ - $error, + $errors = array_merge($errors, [ [ 'Private method FinalPrivateMethod\FooBarPhp8orHigher::foo() cannot be final as it is never overridden by other classes.', 39, @@ -40,6 +42,8 @@ public function testRule(): void 69, ], ]); + + $this->analyse([__DIR__ . '/data/final-private-method.php'], $errors); } } From e6c97d324ed2fb5f56c5aef450e37530ab4d908e Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Wed, 20 Nov 2024 17:18:34 +0100 Subject: [PATCH 09/11] added unit test --- src/Php/PhpVersions.php | 2 +- tests/PHPStan/Php/PhpVersionsTest.php | 64 +++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 tests/PHPStan/Php/PhpVersionsTest.php diff --git a/src/Php/PhpVersions.php b/src/Php/PhpVersions.php index e4b0c165f7..a85c6c4a42 100644 --- a/src/Php/PhpVersions.php +++ b/src/Php/PhpVersions.php @@ -20,7 +20,7 @@ public function __construct( public function producesWarningForFinalPrivateMethods(): TrinaryLogic { - return $this->phpVersions->isSuperTypeOf(IntegerRangeType::fromInterval(80000, null))->result; + return IntegerRangeType::fromInterval(80000, null)->isSuperTypeOf($this->phpVersions)->result; } } diff --git a/tests/PHPStan/Php/PhpVersionsTest.php b/tests/PHPStan/Php/PhpVersionsTest.php new file mode 100644 index 0000000000..bc091b431e --- /dev/null +++ b/tests/PHPStan/Php/PhpVersionsTest.php @@ -0,0 +1,64 @@ +assertSame( + $expected->describe(), + $phpVersions->producesWarningForFinalPrivateMethods()->describe() + ); + } + + public function dataProducesWarningForFinalPrivateMethods(): iterable { + yield [ + TrinaryLogic::createNo(), + new ConstantIntegerType(70400), + ]; + + yield [ + TrinaryLogic::createYes(), + new ConstantIntegerType(80000), + ]; + + yield [ + TrinaryLogic::createYes(), + new ConstantIntegerType(80100), + ]; + + yield [ + TrinaryLogic::createYes(), + IntegerRangeType::fromInterval(80000, null) + ]; + + yield [ + TrinaryLogic::createMaybe(), + IntegerRangeType::fromInterval(null, 80000) + ]; + + yield [ + TrinaryLogic::createNo(), + IntegerRangeType::fromInterval(70200, 70400) + ]; + + yield [ + TrinaryLogic::createMaybe(), + new UnionType([ + IntegerRangeType::fromInterval(70200, 70400), + IntegerRangeType::fromInterval(80200, 80400), + ]) + ]; + } +} From 7366fd24b7447092621fc44d13de1104e31b7fb7 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Wed, 20 Nov 2024 17:35:42 +0100 Subject: [PATCH 10/11] cleanup tests --- tests/PHPStan/Php/PhpVersionsTest.php | 20 ++++--- .../Methods/FinalPrivateMethodRuleTest.php | 60 +++++++++++++------ .../data/final-private-method-phpversions.php | 43 +++++++++++++ .../Methods/data/final-private-method.php | 40 ------------- 4 files changed, 98 insertions(+), 65 deletions(-) create mode 100644 tests/PHPStan/Rules/Methods/data/final-private-method-phpversions.php diff --git a/tests/PHPStan/Php/PhpVersionsTest.php b/tests/PHPStan/Php/PhpVersionsTest.php index bc091b431e..b1563e2eb1 100644 --- a/tests/PHPStan/Php/PhpVersionsTest.php +++ b/tests/PHPStan/Php/PhpVersionsTest.php @@ -3,26 +3,29 @@ namespace PHPStan\Php; use PHPStan\TrinaryLogic; +use PHPStan\Type\Constant\ConstantIntegerType; use PHPStan\Type\IntegerRangeType; use PHPStan\Type\Type; -use PHPStan\Type\Constant\ConstantIntegerType; use PHPStan\Type\UnionType; use PHPUnit\Framework\TestCase; class PhpVersionsTest extends TestCase { + /** * @dataProvider dataProducesWarningForFinalPrivateMethods */ - public function testProducesWarningForFinalPrivateMethods(TrinaryLogic $expected, Type $versionType ) { + public function testProducesWarningForFinalPrivateMethods(TrinaryLogic $expected, Type $versionType): void + { $phpVersions = new PhpVersions($versionType); $this->assertSame( $expected->describe(), - $phpVersions->producesWarningForFinalPrivateMethods()->describe() + $phpVersions->producesWarningForFinalPrivateMethods()->describe(), ); } - public function dataProducesWarningForFinalPrivateMethods(): iterable { + public function dataProducesWarningForFinalPrivateMethods(): iterable + { yield [ TrinaryLogic::createNo(), new ConstantIntegerType(70400), @@ -40,17 +43,17 @@ public function dataProducesWarningForFinalPrivateMethods(): iterable { yield [ TrinaryLogic::createYes(), - IntegerRangeType::fromInterval(80000, null) + IntegerRangeType::fromInterval(80000, null), ]; yield [ TrinaryLogic::createMaybe(), - IntegerRangeType::fromInterval(null, 80000) + IntegerRangeType::fromInterval(null, 80000), ]; yield [ TrinaryLogic::createNo(), - IntegerRangeType::fromInterval(70200, 70400) + IntegerRangeType::fromInterval(70200, 70400), ]; yield [ @@ -58,7 +61,8 @@ public function dataProducesWarningForFinalPrivateMethods(): iterable { new UnionType([ IntegerRangeType::fromInterval(70200, 70400), IntegerRangeType::fromInterval(80200, 80400), - ]) + ]), ]; } + } diff --git a/tests/PHPStan/Rules/Methods/FinalPrivateMethodRuleTest.php b/tests/PHPStan/Rules/Methods/FinalPrivateMethodRuleTest.php index 337d041eb7..8214f22044 100644 --- a/tests/PHPStan/Rules/Methods/FinalPrivateMethodRuleTest.php +++ b/tests/PHPStan/Rules/Methods/FinalPrivateMethodRuleTest.php @@ -2,9 +2,9 @@ namespace PHPStan\Rules\Methods; +use PHPStan\Php\PhpVersion; use PHPStan\Rules\Rule; use PHPStan\Testing\RuleTestCase; -use function array_merge; use const PHP_VERSION_ID; /** @extends RuleTestCase */ @@ -16,34 +16,60 @@ protected function getRule(): Rule return new FinalPrivateMethodRule(); } - public function testRule(): void + public function dataRule(): array { - $errors = []; - if (PHP_VERSION_ID >= 80000) { - $errors = [ + return [ + [ + 70400, + [], + ], + [ + 80000, [ - 'Private method FinalPrivateMethod\Foo::foo() cannot be final as it is never overridden by other classes.', - 8, + [ + 'Private method FinalPrivateMethod\Foo::foo() cannot be final as it is never overridden by other classes.', + 8, + ], ], - ]; + ], + ]; + } + + /** + * @dataProvider dataRule + * @param list $errors + */ + public function testRule(int $phpVersion, array $errors): void + { + $testVersion = new PhpVersion($phpVersion); + $runtimeVersion = new PhpVersion(PHP_VERSION_ID); + + if ( + $testVersion->getMajorVersionId() !== $runtimeVersion->getMajorVersionId() + || $testVersion->getMinorVersionId() !== $runtimeVersion->getMinorVersionId() + ) { + $this->markTestSkipped('Test requires PHP version ' . $phpVersion); } - $errors = array_merge($errors, [ + $this->analyse([__DIR__ . '/data/final-private-method.php'], $errors); + } + + public function testRulePhpVersions(): void + { + $this->analyse([__DIR__ . '/data/final-private-method-phpversions.php'], [ [ - 'Private method FinalPrivateMethod\FooBarPhp8orHigher::foo() cannot be final as it is never overridden by other classes.', - 39, + 'Private method FinalPrivateMethodPhpVersions\FooBarPhp8orHigher::foo() cannot be final as it is never overridden by other classes.', + 9, ], [ - 'Private method FinalPrivateMethod\FooBarPhp74OrHigher::foo() cannot be final as it is never overridden by other classes.', - 59, + 'Private method FinalPrivateMethodPhpVersions\FooBarPhp74OrHigher::foo() cannot be final as it is never overridden by other classes.', + 29, ], [ - 'Private method FinalPrivateMethod\FooBarBaz::foo() cannot be final as it is never overridden by other classes.', - 69, + 'Private method FinalPrivateMethodPhpVersions\FooBarBaz::foo() cannot be final as it is never overridden by other classes.', + 39, ], ]); - - $this->analyse([__DIR__ . '/data/final-private-method.php'], $errors); } } diff --git a/tests/PHPStan/Rules/Methods/data/final-private-method-phpversions.php b/tests/PHPStan/Rules/Methods/data/final-private-method-phpversions.php new file mode 100644 index 0000000000..c9424720d1 --- /dev/null +++ b/tests/PHPStan/Rules/Methods/data/final-private-method-phpversions.php @@ -0,0 +1,43 @@ += 80000) { + class FooBarPhp8orHigher + { + + final private function foo(): void + { + } + } +} + +if (PHP_VERSION_ID < 80000) { + class FooBarPhp7 + { + + final private function foo(): void + { + } + } +} + +if (PHP_VERSION_ID > 70400) { + class FooBarPhp74OrHigher + { + + final private function foo(): void + { + } + } +} + +if (PHP_VERSION_ID < 70400 || PHP_VERSION_ID >= 80100) { + class FooBarBaz + { + + final private function foo(): void + { + } + } +} diff --git a/tests/PHPStan/Rules/Methods/data/final-private-method.php b/tests/PHPStan/Rules/Methods/data/final-private-method.php index eec2ff3095..bb06450219 100644 --- a/tests/PHPStan/Rules/Methods/data/final-private-method.php +++ b/tests/PHPStan/Rules/Methods/data/final-private-method.php @@ -31,43 +31,3 @@ final private function __construct() } } - -if (PHP_VERSION_ID >= 80000) { - class FooBarPhp8orHigher - { - - final private function foo(): void - { - } - } -} - -if (PHP_VERSION_ID < 80000) { - class FooBarPhp7 - { - - final private function foo(): void - { - } - } -} - -if (PHP_VERSION_ID > 70400) { - class FooBarPhp74OrHigher - { - - final private function foo(): void - { - } - } -} - -if (PHP_VERSION_ID < 70400 || PHP_VERSION_ID >= 80100) { - class FooBarBaz - { - - final private function foo(): void - { - } - } -} From 6b0e6381068e1112e6b37d9fcf451575695baad9 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Wed, 20 Nov 2024 17:45:43 +0100 Subject: [PATCH 11/11] improved skip message --- tests/PHPStan/Rules/Methods/FinalPrivateMethodRuleTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/PHPStan/Rules/Methods/FinalPrivateMethodRuleTest.php b/tests/PHPStan/Rules/Methods/FinalPrivateMethodRuleTest.php index 8214f22044..05be45a380 100644 --- a/tests/PHPStan/Rules/Methods/FinalPrivateMethodRuleTest.php +++ b/tests/PHPStan/Rules/Methods/FinalPrivateMethodRuleTest.php @@ -48,7 +48,7 @@ public function testRule(int $phpVersion, array $errors): void $testVersion->getMajorVersionId() !== $runtimeVersion->getMajorVersionId() || $testVersion->getMinorVersionId() !== $runtimeVersion->getMinorVersionId() ) { - $this->markTestSkipped('Test requires PHP version ' . $phpVersion); + $this->markTestSkipped('Test requires PHP version ' . $testVersion->getMajorVersionId() . '.' . $testVersion->getMinorVersionId() . '.*'); } $this->analyse([__DIR__ . '/data/final-private-method.php'], $errors);