From f1abacddb3787ce279e51b1f88f1543d52b9759c Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Fri, 19 Jul 2024 22:36:54 +0200 Subject: [PATCH] Closure with by-ref parameter is impure --- src/Analyser/MutatingScope.php | 14 ++++++++++++++ .../Rules/DeadCode/BetterNoopRuleTest.php | 5 +++++ tests/PHPStan/Rules/DeadCode/data/bug-11361.php | 12 ++++++++++++ .../PHPStan/Rules/Pure/PureFunctionRuleTest.php | 10 ++++++++++ .../PHPStan/Rules/Pure/data/bug-11361-pure.php | 17 +++++++++++++++++ 5 files changed, 58 insertions(+) create mode 100644 tests/PHPStan/Rules/DeadCode/data/bug-11361.php create mode 100644 tests/PHPStan/Rules/Pure/data/bug-11361-pure.php diff --git a/src/Analyser/MutatingScope.php b/src/Analyser/MutatingScope.php index 4d4933d7c5..e5b0758e90 100644 --- a/src/Analyser/MutatingScope.php +++ b/src/Analyser/MutatingScope.php @@ -1527,6 +1527,20 @@ static function (Node $node, Scope $scope) use ($arrowScope, &$arrowFunctionImpu } } + foreach ($parameters as $parameter) { + if ($parameter->passedByReference()->no()) { + continue; + } + + $impurePoints[] = new ImpurePoint( + $this, + $node, + 'functionCall', + 'call to a Closure with by-ref parameter', + true, + ); + } + $throwPointsForClosureType = array_map(static fn (ThrowPoint $throwPoint) => $throwPoint->isExplicit() ? SimpleThrowPoint::createExplicit($throwPoint->getType(), $throwPoint->canContainAnyThrowable()) : SimpleThrowPoint::createImplicit(), $throwPoints); $impurePointsForClosureType = array_map(static fn (ImpurePoint $impurePoint) => new SimpleImpurePoint($impurePoint->getIdentifier(), $impurePoint->getDescription(), $impurePoint->isCertain()), $impurePoints); diff --git a/tests/PHPStan/Rules/DeadCode/BetterNoopRuleTest.php b/tests/PHPStan/Rules/DeadCode/BetterNoopRuleTest.php index ddb2f1ab70..7519e3fc48 100644 --- a/tests/PHPStan/Rules/DeadCode/BetterNoopRuleTest.php +++ b/tests/PHPStan/Rules/DeadCode/BetterNoopRuleTest.php @@ -153,4 +153,9 @@ public function testBug11001(): void $this->analyse([__DIR__ . '/data/bug-11001.php'], []); } + public function testBug11361(): void + { + $this->analyse([__DIR__ . '/data/bug-11361.php'], []); + } + } diff --git a/tests/PHPStan/Rules/DeadCode/data/bug-11361.php b/tests/PHPStan/Rules/DeadCode/data/bug-11361.php new file mode 100644 index 0000000000..9e6b424daf --- /dev/null +++ b/tests/PHPStan/Rules/DeadCode/data/bug-11361.php @@ -0,0 +1,12 @@ +analyse([__DIR__ . '/data/bug-11361-pure.php'], [ + [ + 'Impure call to a Closure with by-ref parameter in pure function Bug11361Pure\foo().', + 14, + ], + ]); + } + } diff --git a/tests/PHPStan/Rules/Pure/data/bug-11361-pure.php b/tests/PHPStan/Rules/Pure/data/bug-11361-pure.php new file mode 100644 index 0000000000..f8a52fffe5 --- /dev/null +++ b/tests/PHPStan/Rules/Pure/data/bug-11361-pure.php @@ -0,0 +1,17 @@ +