From 0fffab29389e5be2816b8207fd37b25522c52789 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 30 Mar 2026 03:53:02 +0000 Subject: [PATCH] Fix phpstan/phpstan#12062: False positive "has no effect" on static:: call to overridable method - Skip collecting static:: calls in PossiblyPureStaticCallCollector when the method can be overridden - A subclass may override the method with side effects, so the call cannot be assumed pure - Updated existing test expectations for static:: calls in non-final classes - New regression test in tests/PHPStan/Rules/DeadCode/data/bug-12062.php --- .../PossiblyPureStaticCallCollector.php | 10 +++++ ...odStatementWithoutImpurePointsRuleTest.php | 9 +++-- .../PHPStan/Rules/DeadCode/data/bug-12062.php | 38 +++++++++++++++++++ 3 files changed, 53 insertions(+), 4 deletions(-) create mode 100644 tests/PHPStan/Rules/DeadCode/data/bug-12062.php diff --git a/src/Rules/DeadCode/PossiblyPureStaticCallCollector.php b/src/Rules/DeadCode/PossiblyPureStaticCallCollector.php index 782bf82cfdb..abfc2016c67 100644 --- a/src/Rules/DeadCode/PossiblyPureStaticCallCollector.php +++ b/src/Rules/DeadCode/PossiblyPureStaticCallCollector.php @@ -63,6 +63,16 @@ public function processNode(Node $node, Scope $scope) return null; } + if ( + $expr->class->toLowerString() === 'static' + && $scope->isInClass() + && !$scope->getClassReflection()->isFinal() + && !$methodReflection->isFinal()->yes() + && !$methodReflection->isPrivate() + ) { + return null; + } + return [$methodReflection->getDeclaringClass()->getName(), $methodReflection->getName(), $node->getStartLine()]; } diff --git a/tests/PHPStan/Rules/DeadCode/CallToStaticMethodStatementWithoutImpurePointsRuleTest.php b/tests/PHPStan/Rules/DeadCode/CallToStaticMethodStatementWithoutImpurePointsRuleTest.php index d068d0673bf..64cc826056b 100644 --- a/tests/PHPStan/Rules/DeadCode/CallToStaticMethodStatementWithoutImpurePointsRuleTest.php +++ b/tests/PHPStan/Rules/DeadCode/CallToStaticMethodStatementWithoutImpurePointsRuleTest.php @@ -44,10 +44,6 @@ public function testRule(): void 'Call to CallToStaticMethodWithoutImpurePoints\SubSubY::mySubSubFunc() on a separate line has no effect.', 21, ], - [ - 'Call to CallToStaticMethodWithoutImpurePoints\y::myFunc() on a separate line has no effect.', - 48, - ], [ 'Call to CallToStaticMethodWithoutImpurePoints\y::myFunc() on a separate line has no effect.', 53, @@ -59,6 +55,11 @@ public function testRule(): void ]); } + public function testBug12062(): void + { + $this->analyse([__DIR__ . '/data/bug-12062.php'], []); + } + #[RequiresPhp('>= 8.5')] public function testPipeOperator(): void { diff --git a/tests/PHPStan/Rules/DeadCode/data/bug-12062.php b/tests/PHPStan/Rules/DeadCode/data/bug-12062.php new file mode 100644 index 00000000000..2a7eb5e18fc --- /dev/null +++ b/tests/PHPStan/Rules/DeadCode/data/bug-12062.php @@ -0,0 +1,38 @@ +