From 35ff6895f48b74e8bc0dda7ec94c40e73c84099b Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Wed, 15 May 2024 07:45:06 +0200 Subject: [PATCH] Fix property assign not being an impure point in arrow function --- src/Analyser/MutatingScope.php | 27 ++++++++++++++++--- .../Rules/DeadCode/BetterNoopRuleTest.php | 5 ++++ .../PHPStan/Rules/DeadCode/data/bug-11001.php | 15 +++++++++++ 3 files changed, 44 insertions(+), 3 deletions(-) diff --git a/src/Analyser/MutatingScope.php b/src/Analyser/MutatingScope.php index f374870b1b..6c707dbb52 100644 --- a/src/Analyser/MutatingScope.php +++ b/src/Analyser/MutatingScope.php @@ -1272,17 +1272,38 @@ private function resolveType(string $exprString, Expr $node): Type } } + $arrowFunctionImpurePoints = []; + $invalidateExpressions = []; $arrowFunctionExprResult = $this->nodeScopeResolver->processExprNode( new Node\Stmt\Expression($node->expr), $node->expr, $arrowScope, - static function (): void { + static function (Node $node, Scope $scope) use ($arrowScope, &$arrowFunctionImpurePoints, &$invalidateExpressions): void { + if ($scope->getAnonymousFunctionReflection() !== $arrowScope->getAnonymousFunctionReflection()) { + return; + } + + if ($node instanceof InvalidateExprNode) { + $invalidateExpressions[] = $node; + return; + } + + if (!$node instanceof PropertyAssignNode) { + return; + } + + $arrowFunctionImpurePoints[] = new ImpurePoint( + $scope, + $node, + 'propertyAssign', + 'property assignment', + true, + ); }, ExpressionContext::createDeep(), ); $throwPoints = $arrowFunctionExprResult->getThrowPoints(); - $impurePoints = $arrowFunctionExprResult->getImpurePoints(); - $invalidateExpressions = []; + $impurePoints = array_merge($arrowFunctionImpurePoints, $arrowFunctionExprResult->getImpurePoints()); $usedVariables = []; } else { $closureScope = $this->enterAnonymousFunctionWithoutReflection($node, $callableParameters); diff --git a/tests/PHPStan/Rules/DeadCode/BetterNoopRuleTest.php b/tests/PHPStan/Rules/DeadCode/BetterNoopRuleTest.php index 6a0780ad36..ddb2f1ab70 100644 --- a/tests/PHPStan/Rules/DeadCode/BetterNoopRuleTest.php +++ b/tests/PHPStan/Rules/DeadCode/BetterNoopRuleTest.php @@ -6,6 +6,7 @@ use PHPStan\Node\Printer\Printer; use PHPStan\Rules\Rule; use PHPStan\Testing\RuleTestCase; +use const PHP_VERSION_ID; /** * @extends RuleTestCase @@ -145,6 +146,10 @@ public function testRuleImpurePoints(): void public function testBug11001(): void { + if (PHP_VERSION_ID < 70400) { + self::markTestSkipped('Test requires PHP 7.4.'); + } + $this->analyse([__DIR__ . '/data/bug-11001.php'], []); } diff --git a/tests/PHPStan/Rules/DeadCode/data/bug-11001.php b/tests/PHPStan/Rules/DeadCode/data/bug-11001.php index a5b8182222..4b39b689c1 100644 --- a/tests/PHPStan/Rules/DeadCode/data/bug-11001.php +++ b/tests/PHPStan/Rules/DeadCode/data/bug-11001.php @@ -21,3 +21,18 @@ public function doFoo(): void } } + +class Foo2 +{ + public function test(): void + { + \Closure::bind(fn () => $this->status = 5, $this)(); + } + + public function test2(): void + { + \Closure::bind(function () { + $this->status = 5; + }, $this)(); + } +}