Skip to content

Commit 7a3cfd0

Browse files
committed
Implement Scope->getPhpVersion()
1 parent 65ddbcb commit 7a3cfd0

File tree

5 files changed

+96
-15
lines changed

5 files changed

+96
-15
lines changed

src/Analyser/MutatingScope.php

Lines changed: 30 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,32 @@ 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+
return new PhpVersions([$versionId->getMax()]);
5737+
}
5738+
5739+
$scalars = $versionId->getConstantScalarValues();
5740+
if ($scalars !== []) {
5741+
$ints = [];
5742+
foreach ($scalars as $scalar) {
5743+
if (!is_int($scalar)) {
5744+
throw new ShouldNotHappenException();
5745+
}
5746+
$ints[] = $scalar;
5747+
}
5748+
return new PhpVersions($ints);
5749+
}
5750+
5751+
return new PhpVersions([$this->phpVersion->getVersionId()]);
5752+
}
5753+
57245754
}

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: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,9 @@
99
/** @extends RuleTestCase<FinalPrivateMethodRule> */
1010
class FinalPrivateMethodRuleTest extends RuleTestCase
1111
{
12-
13-
private int $phpVersionId;
14-
1512
protected function getRule(): Rule
1613
{
17-
return new FinalPrivateMethodRule(
18-
new PhpVersion($this->phpVersionId),
19-
);
14+
return new FinalPrivateMethodRule();
2015
}
2116

2217
public function dataRule(): array
@@ -44,7 +39,9 @@ public function dataRule(): array
4439
*/
4540
public function testRule(int $phpVersion, array $errors): void
4641
{
47-
$this->phpVersionId = $phpVersion;
42+
if (PHP_VERSION_ID < $phpVersion) {
43+
$this->markTestSkipped('Test requires PHP ' . $phpVersion);
44+
}
4845
$this->analyse([__DIR__ . '/data/final-private-method.php'], $errors);
4946
}
5047

0 commit comments

Comments
 (0)