Skip to content

Commit d6a7d95

Browse files
takaramstaabm
authored andcommitted
Fix static method expression invalidation on "maybe pure" methods
1 parent 4c9cd90 commit d6a7d95

File tree

8 files changed

+61
-3
lines changed

8 files changed

+61
-3
lines changed

src/Analyser/NodeScopeResolver.php

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,8 @@ public function __construct(
291291
private readonly bool $implicitThrows,
292292
#[AutowiredParameter]
293293
private readonly bool $treatPhpDocTypesAsCertain,
294+
#[AutowiredParameter]
295+
private readonly bool $rememberPossiblyImpureFunctionValues,
294296
)
295297
{
296298
$earlyTerminatingMethodNames = [];
@@ -3215,11 +3217,13 @@ function (MutatingScope $scope) use ($stmt, $expr, $nodeCallback, $context, $sto
32153217
$scope = $result->getScope();
32163218

32173219
if ($methodReflection !== null) {
3218-
$hasSideEffects = $methodReflection->hasSideEffects()->yes();
3219-
if ($hasSideEffects || $methodReflection->getName() === '__construct') {
3220+
$shouldInvalidateExpr = $this->rememberPossiblyImpureFunctionValues
3221+
? $methodReflection->hasSideEffects()->yes()
3222+
: !$methodReflection->hasSideEffects()->no();
3223+
if ($shouldInvalidateExpr || $methodReflection->getName() === '__construct') {
32203224
$this->callNodeCallback($nodeCallback, new InvalidateExprNode($normalizedExpr->var), $scope, $storage);
32213225
$scope = $scope->invalidateExpression($normalizedExpr->var, true, $methodReflection->getDeclaringClass());
3222-
if ($hasSideEffects) {
3226+
if ($shouldInvalidateExpr) {
32233227
$scope = $scope->invalidateStaticMembers($normalizedExpr->var);
32243228
}
32253229
}

src/Testing/RuleTestCase.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ protected function createNodeScopeResolver(): NodeScopeResolver
119119
[],
120120
self::getContainer()->getParameter('exceptions')['implicitThrows'],
121121
$this->shouldTreatPhpDocTypesAsCertain(),
122+
self::getContainer()->getParameter('rememberPossiblyImpureFunctionValues'),
122123
);
123124
}
124125

src/Testing/TypeInferenceTestCase.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ protected static function createNodeScopeResolver(): NodeScopeResolver
9494
static::getEarlyTerminatingFunctionCalls(),
9595
$container->getParameter('exceptions')['implicitThrows'],
9696
$container->getParameter('treatPhpDocTypesAsCertain'),
97+
$container->getParameter('rememberPossiblyImpureFunctionValues'),
9798
);
9899
}
99100

tests/PHPStan/Analyser/AnalyserTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -835,6 +835,7 @@ private function createAnalyser(): Analyser
835835
[],
836836
true,
837837
$this->shouldTreatPhpDocTypesAsCertain(),
838+
true,
838839
);
839840
$lexer = new Lexer();
840841
$fileAnalyser = new FileAnalyser(

tests/PHPStan/Analyser/Fiber/FiberNodeScopeResolverRuleTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ protected function createNodeScopeResolver(): NodeScopeResolver
139139
[],
140140
self::getContainer()->getParameter('exceptions')['implicitThrows'],
141141
$this->shouldTreatPhpDocTypesAsCertain(),
142+
self::getContainer()->getParameter('rememberPossiblyImpureFunctionValues'),
142143
);
143144
}
144145

tests/PHPStan/Analyser/Fiber/FiberNodeScopeResolverTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ protected static function createNodeScopeResolver(): NodeScopeResolver
7272
static::getEarlyTerminatingFunctionCalls(),
7373
$container->getParameter('exceptions')['implicitThrows'],
7474
$container->getParameter('treatPhpDocTypesAsCertain'),
75+
$container->getParameter('rememberPossiblyImpureFunctionValues'),
7576
);
7677
}
7778

tests/PHPStan/Analyser/data/do-not-remember-possibly-impure-function-values.php

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
class Foo
88
{
9+
private static int $counter = 0;
910

1011
/** @phpstan-pure */
1112
public function pure(): int
@@ -24,6 +25,12 @@ public function impure(): int
2425
return rand(0, 1);
2526
}
2627

28+
/** @phpstan-pure */
29+
public static function getCounter(): int
30+
{
31+
return self::$counter;
32+
}
33+
2734
public function test(): void
2835
{
2936
if ($this->pure() === 1) {
@@ -39,6 +46,24 @@ public function test(): void
3946
}
4047
}
4148

49+
public function testStatic(): void
50+
{
51+
if (self::getCounter() === 1) {
52+
$this->pure();
53+
assertType('1', self::getCounter());
54+
}
55+
56+
if (self::getCounter() === 1) {
57+
$this->maybePure();
58+
assertType('int', self::getCounter());
59+
}
60+
61+
if (self::getCounter() === 1) {
62+
$this->impure();
63+
assertType('int', self::getCounter());
64+
}
65+
}
66+
4267
}
4368

4469
class FooStatic

tests/PHPStan/Analyser/nsrt/remember-possibly-impure-function-values.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
class Foo
88
{
9+
private static int $counter = 0;
910

1011
/** @phpstan-pure */
1112
public function pure(): int
@@ -24,6 +25,11 @@ public function impure(): int
2425
return rand(0, 1);
2526
}
2627

28+
public static function getCounter(): int
29+
{
30+
return self::$counter;
31+
}
32+
2733
public function test(): void
2834
{
2935
if ($this->pure() === 1) {
@@ -39,6 +45,24 @@ public function test(): void
3945
}
4046
}
4147

48+
public function testStatic(): void
49+
{
50+
if (self::getCounter() === 1) {
51+
$this->pure();
52+
assertType('1', self::getCounter());
53+
}
54+
55+
if (self::getCounter() === 1) {
56+
$this->maybePure();
57+
assertType('1', self::getCounter());
58+
}
59+
60+
if (self::getCounter() === 1) {
61+
$this->impure();
62+
assertType('int', self::getCounter());
63+
}
64+
}
65+
4266
}
4367

4468
class FooStatic

0 commit comments

Comments
 (0)