diff --git a/src/Analyser/MutatingScope.php b/src/Analyser/MutatingScope.php index 933b44ddbc..d5acdcf93a 100644 --- a/src/Analyser/MutatingScope.php +++ b/src/Analyser/MutatingScope.php @@ -44,6 +44,7 @@ use PHPStan\Node\InvalidateExprNode; use PHPStan\Node\IssetExpr; use PHPStan\Node\Printer\ExprPrinter; +use PHPStan\Node\PropertyAssignNode; use PHPStan\Parser\ArrayMapArgVisitor; use PHPStan\Parser\NewAssignedToPropertyVisitor; use PHPStan\Parser\Parser; @@ -1287,8 +1288,9 @@ static function (): void { $closureReturnStatements = []; $closureYieldStatements = []; $closureExecutionEnds = []; + $closureImpurePoints = []; $invalidateExpressions = []; - $closureStatementResult = $this->nodeScopeResolver->processStmtNodes($node, $node->stmts, $closureScope, static function (Node $node, Scope $scope) use ($closureScope, &$closureReturnStatements, &$closureYieldStatements, &$closureExecutionEnds, &$invalidateExpressions): void { + $closureStatementResult = $this->nodeScopeResolver->processStmtNodes($node, $node->stmts, $closureScope, static function (Node $node, Scope $scope) use ($closureScope, &$closureReturnStatements, &$closureYieldStatements, &$closureExecutionEnds, &$closureImpurePoints, &$invalidateExpressions): void { if ($scope->getAnonymousFunctionReflection() !== $closureScope->getAnonymousFunctionReflection()) { return; } @@ -1298,6 +1300,17 @@ static function (): void { return; } + if ($node instanceof PropertyAssignNode) { + $closureImpurePoints[] = new ImpurePoint( + $scope, + $node, + 'propertyAssign', + 'property assignment', + true, + ); + return; + } + if ($node instanceof ExecutionEndNode) { if ($node->getStatementResult()->isAlwaysTerminating()) { foreach ($node->getStatementResult()->getExitPoints() as $exitPoint) { @@ -1329,7 +1342,7 @@ static function (): void { }, StatementContext::createTopLevel()); $throwPoints = $closureStatementResult->getThrowPoints(); - $impurePoints = $closureStatementResult->getImpurePoints(); + $impurePoints = array_merge($closureImpurePoints, $closureStatementResult->getImpurePoints()); $returnTypes = []; $hasNull = false; diff --git a/tests/PHPStan/Rules/DeadCode/BetterNoopRuleTest.php b/tests/PHPStan/Rules/DeadCode/BetterNoopRuleTest.php index 9a147c1a18..05ebdeabed 100644 --- a/tests/PHPStan/Rules/DeadCode/BetterNoopRuleTest.php +++ b/tests/PHPStan/Rules/DeadCode/BetterNoopRuleTest.php @@ -126,11 +126,11 @@ public function testRuleImpurePoints(): void $this->analyse([__DIR__ . '/data/noop-impure-points.php'], [ [ 'Unused result of "&&" operator.', - 10, + 12, ], [ 'Expression "$b()" on a separate line does not do anything.', - 57, + 59, ], ]); } diff --git a/tests/PHPStan/Rules/DeadCode/data/noop-impure-points.php b/tests/PHPStan/Rules/DeadCode/data/noop-impure-points.php index 550c9bfc22..a2cac1b9af 100644 --- a/tests/PHPStan/Rules/DeadCode/data/noop-impure-points.php +++ b/tests/PHPStan/Rules/DeadCode/data/noop-impure-points.php @@ -5,6 +5,8 @@ class Foo { + private static $staticProp = 1; + public function doFoo(bool $b): void { $b && $this->doBar(); @@ -61,6 +63,16 @@ public function doClosures(): void $ref++; }; $c(); + + $d = function () { + self::$foo = 1; + }; + $d(); + + $e = function () { + self::$staticProp = 1; + }; + $e(); } }