From 3266a0e98e75a8faba7ed82fa40a6c1329bf73f0 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Tue, 11 Mar 2025 12:10:05 +0100 Subject: [PATCH 1/3] Fix false positives on non-existing-offsets of super-globals --- src/Analyser/MutatingScope.php | 6 +++++- tests/PHPStan/Analyser/NodeScopeResolverTest.php | 1 + .../NonexistentOffsetInArrayDimFetchRuleTest.php | 7 +++++++ .../Rules/Arrays/data/narrow-superglobal.php | 16 ++++++++++++++++ 4 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 tests/PHPStan/Rules/Arrays/data/narrow-superglobal.php diff --git a/src/Analyser/MutatingScope.php b/src/Analyser/MutatingScope.php index 45e956408f..a6655dae52 100644 --- a/src/Analyser/MutatingScope.php +++ b/src/Analyser/MutatingScope.php @@ -548,7 +548,12 @@ public function getVariableType(string $variableName): Type } } + $varExprString = '$' . $variableName; if ($this->isGlobalVariable($variableName)) { + if (array_key_exists($varExprString, $this->expressionTypes)) { + return TypeUtils::resolveLateResolvableTypes($this->expressionTypes[$varExprString]->getType()); + } + return new ArrayType(new BenevolentUnionType([new IntegerType(), new StringType()]), new MixedType(true)); } @@ -556,7 +561,6 @@ public function getVariableType(string $variableName): Type throw new UndefinedVariableException($this, $variableName); } - $varExprString = '$' . $variableName; if (!array_key_exists($varExprString, $this->expressionTypes)) { return new MixedType(); } diff --git a/tests/PHPStan/Analyser/NodeScopeResolverTest.php b/tests/PHPStan/Analyser/NodeScopeResolverTest.php index 9dd8161487..a2e9ef0619 100644 --- a/tests/PHPStan/Analyser/NodeScopeResolverTest.php +++ b/tests/PHPStan/Analyser/NodeScopeResolverTest.php @@ -210,6 +210,7 @@ private static function findTestFiles(): iterable yield __DIR__ . '/../Rules/Arrays/data/bug-11679.php'; yield __DIR__ . '/../Rules/Methods/data/bug-4801.php'; + yield __DIR__ . '/../Rules/Arrays/data/narrow-superglobal.php'; } /** diff --git a/tests/PHPStan/Rules/Arrays/NonexistentOffsetInArrayDimFetchRuleTest.php b/tests/PHPStan/Rules/Arrays/NonexistentOffsetInArrayDimFetchRuleTest.php index 6557f97ed3..a1e7fbd212 100644 --- a/tests/PHPStan/Rules/Arrays/NonexistentOffsetInArrayDimFetchRuleTest.php +++ b/tests/PHPStan/Rules/Arrays/NonexistentOffsetInArrayDimFetchRuleTest.php @@ -870,4 +870,11 @@ public function testBug8649(): void $this->analyse([__DIR__ . '/data/bug-8649.php'], []); } + public function testNarrowSuperglobals(): void + { + $this->reportPossiblyNonexistentGeneralArrayOffset = true; + + $this->analyse([__DIR__ . '/data/narrow-superglobal.php'], []); + } + } diff --git a/tests/PHPStan/Rules/Arrays/data/narrow-superglobal.php b/tests/PHPStan/Rules/Arrays/data/narrow-superglobal.php new file mode 100644 index 0000000000..83edeb9fd5 --- /dev/null +++ b/tests/PHPStan/Rules/Arrays/data/narrow-superglobal.php @@ -0,0 +1,16 @@ + Date: Tue, 11 Mar 2025 12:20:41 +0100 Subject: [PATCH 2/3] de-duplicate --- src/Analyser/MutatingScope.php | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/src/Analyser/MutatingScope.php b/src/Analyser/MutatingScope.php index a6655dae52..5df8353a90 100644 --- a/src/Analyser/MutatingScope.php +++ b/src/Analyser/MutatingScope.php @@ -548,21 +548,18 @@ public function getVariableType(string $variableName): Type } } - $varExprString = '$' . $variableName; - if ($this->isGlobalVariable($variableName)) { - if (array_key_exists($varExprString, $this->expressionTypes)) { - return TypeUtils::resolveLateResolvableTypes($this->expressionTypes[$varExprString]->getType()); - } - - return new ArrayType(new BenevolentUnionType([new IntegerType(), new StringType()]), new MixedType(true)); - } - if ($this->hasVariableType($variableName)->no()) { throw new UndefinedVariableException($this, $variableName); } + $defaultType = new MixedType(); + if ($this->isGlobalVariable($variableName)) { + $defaultType = new ArrayType(new BenevolentUnionType([new IntegerType(), new StringType()]), new MixedType(true)); + } + + $varExprString = '$' . $variableName; if (!array_key_exists($varExprString, $this->expressionTypes)) { - return new MixedType(); + return $defaultType; } return TypeUtils::resolveLateResolvableTypes($this->expressionTypes[$varExprString]->getType()); From 271382ef7abce9eb0e457eb7764484a0d92ba27d Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Tue, 11 Mar 2025 12:21:51 +0100 Subject: [PATCH 3/3] simplify --- src/Analyser/MutatingScope.php | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/Analyser/MutatingScope.php b/src/Analyser/MutatingScope.php index 5df8353a90..8116216499 100644 --- a/src/Analyser/MutatingScope.php +++ b/src/Analyser/MutatingScope.php @@ -552,14 +552,12 @@ public function getVariableType(string $variableName): Type throw new UndefinedVariableException($this, $variableName); } - $defaultType = new MixedType(); - if ($this->isGlobalVariable($variableName)) { - $defaultType = new ArrayType(new BenevolentUnionType([new IntegerType(), new StringType()]), new MixedType(true)); - } - $varExprString = '$' . $variableName; if (!array_key_exists($varExprString, $this->expressionTypes)) { - return $defaultType; + if ($this->isGlobalVariable($variableName)) { + return new ArrayType(new BenevolentUnionType([new IntegerType(), new StringType()]), new MixedType(true)); + } + return new MixedType(); } return TypeUtils::resolveLateResolvableTypes($this->expressionTypes[$varExprString]->getType());