Skip to content

Commit 4cb271b

Browse files
committed
Implement Scope->getPhpVersion()
1 parent 65ddbcb commit 4cb271b

File tree

5 files changed

+99
-15
lines changed

5 files changed

+99
-15
lines changed

src/Analyser/MutatingScope.php

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
use PHPStan\Parser\NewAssignedToPropertyVisitor;
4848
use PHPStan\Parser\Parser;
4949
use PHPStan\Php\PhpVersion;
50+
use PHPStan\Php\PhpVersions;
5051
use PHPStan\PhpDoc\Tag\TemplateTag;
5152
use PHPStan\Reflection\Assertions;
5253
use PHPStan\Reflection\Callables\CallableParametersAcceptor;
@@ -144,6 +145,7 @@
144145
use function implode;
145146
use function in_array;
146147
use function is_bool;
148+
use function is_int;
147149
use function is_numeric;
148150
use function is_string;
149151
use function ltrim;
@@ -5721,4 +5723,34 @@ public function getIterableValueType(Type $iteratee): Type
57215723
return $iteratee->getIterableValueType();
57225724
}
57235725

5726+
public function getPhpVersions(): PhpVersions
5727+
{
5728+
$versionId = $this->getType(new ConstFetch(new Name('PHP_VERSION_ID')));
5729+
if ($versionId instanceof IntegerRangeType) {
5730+
if ($versionId->getMin() !== null && $versionId->getMax() !== null) {
5731+
return new PhpVersions([$versionId->getMin(), $versionId->getMax()]);
5732+
}
5733+
if ($versionId->getMin() !== null) {
5734+
return new PhpVersions([$versionId->getMin()]);
5735+
}
5736+
if ($versionId->getMax() !== null) {
5737+
return new PhpVersions([$versionId->getMax()]);
5738+
}
5739+
}
5740+
5741+
$scalars = $versionId->getConstantScalarValues();
5742+
if ($scalars !== []) {
5743+
$ints = [];
5744+
foreach ($scalars as $scalar) {
5745+
if (!is_int($scalar)) {
5746+
throw new ShouldNotHappenException();
5747+
}
5748+
$ints[] = $scalar;
5749+
}
5750+
return new PhpVersions($ints);
5751+
}
5752+
5753+
return new PhpVersions([$this->phpVersion->getVersionId()]);
5754+
}
5755+
57245756
}

src/Analyser/Scope.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
use PhpParser\Node\Expr;
77
use PhpParser\Node\Name;
88
use PhpParser\Node\Param;
9+
use PHPStan\Php\PhpVersions;
910
use PHPStan\Reflection\ClassConstantReflection;
1011
use PHPStan\Reflection\ClassMemberAccessAnswerer;
1112
use PHPStan\Reflection\ClassReflection;
@@ -136,4 +137,6 @@ public function filterByFalseyValue(Expr $expr): self;
136137

137138
public function isInFirstLevelStatement(): bool;
138139

140+
public function getPhpVersions(): PhpVersions;
141+
139142
}

src/Php/PhpVersions.php

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Php;
4+
5+
use PHPStan\ShouldNotHappenException;
6+
use PHPStan\TrinaryLogic;
7+
use function max;
8+
use function min;
9+
10+
/**
11+
* @api
12+
*/
13+
final class PhpVersions
14+
{
15+
16+
private int $minVersionId;
17+
18+
private int $maxVersionId;
19+
20+
/**
21+
* @api
22+
* @param list<int> $phpVersionIds
23+
*/
24+
public function __construct(
25+
array $phpVersionIds,
26+
)
27+
{
28+
if ($phpVersionIds === []) {
29+
throw new ShouldNotHappenException();
30+
}
31+
32+
$normalizedPhpVersionIds = [];
33+
foreach ($phpVersionIds as $versionId) {
34+
// drop patch version part and replace with 00
35+
$normalizedPhpVersionIds[] = ((int) ($versionId / 100)) * 100;
36+
}
37+
38+
$this->minVersionId = min($normalizedPhpVersionIds);
39+
$this->maxVersionId = max($normalizedPhpVersionIds);
40+
}
41+
42+
public function producesWarningForFinalPrivateMethods(): TrinaryLogic
43+
{
44+
return $this->minPhpVersion(80000);
45+
}
46+
47+
private function minPhpVersion(int $versionId): TrinaryLogic
48+
{
49+
if ($this->minVersionId >= $versionId) {
50+
return TrinaryLogic::createYes();
51+
}
52+
if ($this->maxVersionId >= $versionId) {
53+
return TrinaryLogic::createMaybe();
54+
}
55+
return TrinaryLogic::createNo();
56+
}
57+
58+
}

src/Rules/Methods/FinalPrivateMethodRule.php

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
use PhpParser\Node;
66
use PHPStan\Analyser\Scope;
77
use PHPStan\Node\InClassMethodNode;
8-
use PHPStan\Php\PhpVersion;
98
use PHPStan\Rules\Rule;
109
use PHPStan\Rules\RuleErrorBuilder;
1110
use function sprintf;
@@ -14,12 +13,6 @@
1413
final class FinalPrivateMethodRule implements Rule
1514
{
1615

17-
public function __construct(
18-
private PhpVersion $phpVersion,
19-
)
20-
{
21-
}
22-
2316
public function getNodeType(): string
2417
{
2518
return InClassMethodNode::class;
@@ -28,7 +21,7 @@ public function getNodeType(): string
2821
public function processNode(Node $node, Scope $scope): array
2922
{
3023
$method = $node->getMethodReflection();
31-
if (!$this->phpVersion->producesWarningForFinalPrivateMethods()) {
24+
if (!$scope->getPhpVersions()->producesWarningForFinalPrivateMethods()->yes()) {
3225
return [];
3326
}
3427

tests/PHPStan/Rules/Methods/FinalPrivateMethodRuleTest.php

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,17 @@
22

33
namespace PHPStan\Rules\Methods;
44

5-
use PHPStan\Php\PhpVersion;
65
use PHPStan\Rules\Rule;
76
use PHPStan\Testing\RuleTestCase;
7+
use const PHP_VERSION_ID;
88

99
/** @extends RuleTestCase<FinalPrivateMethodRule> */
1010
class FinalPrivateMethodRuleTest extends RuleTestCase
1111
{
1212

13-
private int $phpVersionId;
14-
1513
protected function getRule(): Rule
1614
{
17-
return new FinalPrivateMethodRule(
18-
new PhpVersion($this->phpVersionId),
19-
);
15+
return new FinalPrivateMethodRule();
2016
}
2117

2218
public function dataRule(): array
@@ -44,7 +40,9 @@ public function dataRule(): array
4440
*/
4541
public function testRule(int $phpVersion, array $errors): void
4642
{
47-
$this->phpVersionId = $phpVersion;
43+
if (PHP_VERSION_ID < $phpVersion) {
44+
$this->markTestSkipped('Test requires PHP ' . $phpVersion);
45+
}
4846
$this->analyse([__DIR__ . '/data/final-private-method.php'], $errors);
4947
}
5048

0 commit comments

Comments
 (0)