File tree Expand file tree Collapse file tree 5 files changed +96
-15
lines changed
tests/PHPStan/Rules/Methods Expand file tree Collapse file tree 5 files changed +96
-15
lines changed Original file line number Diff line number Diff line change 4747use PHPStan \Parser \NewAssignedToPropertyVisitor ;
4848use PHPStan \Parser \Parser ;
4949use PHPStan \Php \PhpVersion ;
50+ use PHPStan \Php \PhpVersions ;
5051use PHPStan \PhpDoc \Tag \TemplateTag ;
5152use PHPStan \Reflection \Assertions ;
5253use PHPStan \Reflection \Callables \CallableParametersAcceptor ;
144145use function implode ;
145146use function in_array ;
146147use function is_bool ;
148+ use function is_int ;
147149use function is_numeric ;
148150use function is_string ;
149151use 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}
Original file line number Diff line number Diff line change 66use PhpParser \Node \Expr ;
77use PhpParser \Node \Name ;
88use PhpParser \Node \Param ;
9+ use PHPStan \Php \PhpVersions ;
910use PHPStan \Reflection \ClassConstantReflection ;
1011use PHPStan \Reflection \ClassMemberAccessAnswerer ;
1112use 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}
Original file line number Diff line number Diff line change 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+ }
Original file line number Diff line number Diff line change 55use PhpParser \Node ;
66use PHPStan \Analyser \Scope ;
77use PHPStan \Node \InClassMethodNode ;
8- use PHPStan \Php \PhpVersion ;
98use PHPStan \Rules \Rule ;
109use PHPStan \Rules \RuleErrorBuilder ;
1110use function sprintf ;
1413final 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
Original file line number Diff line number Diff line change 99/** @extends RuleTestCase<FinalPrivateMethodRule> */
1010class 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
You can’t perform that action at this time.
0 commit comments