From 5418d4fdf1b772a0ed83d24745d56d59216a3660 Mon Sep 17 00:00:00 2001 From: phpstan-bot <79867460+phpstan-bot@users.noreply.github.com> Date: Fri, 27 Feb 2026 12:55:07 +0000 Subject: [PATCH 1/2] Fix "Cannot use [] for reading" false positive for by-reference args - Enter expression assign context for ArrayDimFetch with null dim when passed as a by-reference argument in NodeScopeResolver::processArgs() - Exit expression assign after processing to prevent scope leakage - Add regression test in tests/PHPStan/Rules/Arrays/data/bug-5290.php - Uncomment previously disabled test case for by-ref closure in existing test data Closes https://github.com/phpstan/phpstan/issues/5290 --- src/Analyser/NodeScopeResolver.php | 7 ++++++ ...fsetAccessWithoutDimForReadingRuleTest.php | 5 ++++ tests/PHPStan/Rules/Arrays/data/bug-5290.php | 24 +++++++++++++++++++ .../offset-access-without-dim-for-reading.php | 2 +- 4 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 tests/PHPStan/Rules/Arrays/data/bug-5290.php diff --git a/src/Analyser/NodeScopeResolver.php b/src/Analyser/NodeScopeResolver.php index ce853bd980..4b5c220c9a 100644 --- a/src/Analyser/NodeScopeResolver.php +++ b/src/Analyser/NodeScopeResolver.php @@ -3401,11 +3401,18 @@ public function processArgs( $this->storeBeforeScope($storage, $arg->value, $scopeToPass); } else { $exprType = $scope->getType($arg->value); + $enterExpressionAssignForByRef = $assignByReference && $arg->value instanceof ArrayDimFetch && $arg->value->dim === null; + if ($enterExpressionAssignForByRef) { + $scopeToPass = $scopeToPass->enterExpressionAssign($arg->value); + } $exprResult = $this->processExprNode($stmt, $arg->value, $scopeToPass, $storage, $nodeCallback, $context->enterDeep()); $throwPoints = array_merge($throwPoints, $exprResult->getThrowPoints()); $impurePoints = array_merge($impurePoints, $exprResult->getImpurePoints()); $isAlwaysTerminating = $isAlwaysTerminating || $exprResult->isAlwaysTerminating(); $scope = $exprResult->getScope(); + if ($enterExpressionAssignForByRef) { + $scope = $scope->exitExpressionAssign($arg->value); + } $hasYield = $hasYield || $exprResult->hasYield(); if ($exprType->isCallable()->yes()) { diff --git a/tests/PHPStan/Rules/Arrays/OffsetAccessWithoutDimForReadingRuleTest.php b/tests/PHPStan/Rules/Arrays/OffsetAccessWithoutDimForReadingRuleTest.php index db6846cfa0..6e109cc89b 100644 --- a/tests/PHPStan/Rules/Arrays/OffsetAccessWithoutDimForReadingRuleTest.php +++ b/tests/PHPStan/Rules/Arrays/OffsetAccessWithoutDimForReadingRuleTest.php @@ -16,6 +16,11 @@ protected function getRule(): Rule return new OffsetAccessWithoutDimForReadingRule(); } + public function testBug5290(): void + { + $this->analyse([__DIR__ . '/data/bug-5290.php'], []); + } + public function testOffsetAccessWithoutDimForReading(): void { $this->analyse( diff --git a/tests/PHPStan/Rules/Arrays/data/bug-5290.php b/tests/PHPStan/Rules/Arrays/data/bug-5290.php new file mode 100644 index 0000000000..17a28d9d31 --- /dev/null +++ b/tests/PHPStan/Rules/Arrays/data/bug-5290.php @@ -0,0 +1,24 @@ +bar($array[]); diff --git a/tests/PHPStan/Rules/Arrays/data/offset-access-without-dim-for-reading.php b/tests/PHPStan/Rules/Arrays/data/offset-access-without-dim-for-reading.php index 3ff679e20f..62910e04bc 100644 --- a/tests/PHPStan/Rules/Arrays/data/offset-access-without-dim-for-reading.php +++ b/tests/PHPStan/Rules/Arrays/data/offset-access-without-dim-for-reading.php @@ -15,7 +15,7 @@ $firstElement = &$array[]; (function ($ref) {})($array[]); -//(function (&$ref) {})($array[]); // Should work but doesn't +(function (&$ref) {})($array[]); // Technically works but makes no sense $array[] += 20; From 21e150e0a24efc85f68673790adcfb57831af350 Mon Sep 17 00:00:00 2001 From: phpstan-bot Date: Sun, 15 Mar 2026 22:24:45 +0000 Subject: [PATCH 2/2] Add test for nested array dim fetch with by-ref parameter Address review comment: test that `$array[1][]` passed to a by-reference parameter also does not produce a false positive. Co-Authored-By: Claude Opus 4.6 --- tests/PHPStan/Rules/Arrays/data/bug-5290.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/PHPStan/Rules/Arrays/data/bug-5290.php b/tests/PHPStan/Rules/Arrays/data/bug-5290.php index 17a28d9d31..9c57effc41 100644 --- a/tests/PHPStan/Rules/Arrays/data/bug-5290.php +++ b/tests/PHPStan/Rules/Arrays/data/bug-5290.php @@ -22,3 +22,6 @@ public function bar(?bool &$value): void { $foo = new Foo(); $foo->bar($array[]); + +// Nested array dim fetch with by-ref parameter +set($array[1][]);