From eec834e7aca630307294a4416eb76f054380ee57 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Sat, 31 May 2025 10:05:27 +0200 Subject: [PATCH 01/10] Fixed false-positive with by-ref parameters and array-functions --- src/Analyser/NodeScopeResolver.php | 5 ++- .../ParameterOutAssignedTypeRuleTest.php | 5 +++ .../Rules/Variables/data/bug-13093.php | 40 +++++++++++++++++++ 3 files changed, 48 insertions(+), 2 deletions(-) create mode 100644 tests/PHPStan/Rules/Variables/data/bug-13093.php diff --git a/src/Analyser/NodeScopeResolver.php b/src/Analyser/NodeScopeResolver.php index 8c070bb040..ed976abef6 100644 --- a/src/Analyser/NodeScopeResolver.php +++ b/src/Analyser/NodeScopeResolver.php @@ -5487,6 +5487,7 @@ private function processAssignVar( $nativeValueToWrite = $scope->getNativeType($assignedExpr); $originalValueToWrite = $valueToWrite; $originalNativeValueToWrite = $nativeValueToWrite; + $scopeBeforeAssignEval = $scope; // 3. eval assigned expr $result = $processExprCallback($scope); @@ -5542,11 +5543,11 @@ private function processAssignVar( if ($varType->isArray()->yes() || !(new ObjectType(ArrayAccess::class))->isSuperTypeOf($varType)->yes()) { if ($var instanceof Variable && is_string($var->name)) { - $nodeCallback(new VariableAssignNode($var, $assignedPropertyExpr), $scope); + $nodeCallback(new VariableAssignNode($var, $assignedPropertyExpr), $scopeBeforeAssignEval); $scope = $scope->assignVariable($var->name, $valueToWrite, $nativeValueToWrite, TrinaryLogic::createYes()); } else { if ($var instanceof PropertyFetch || $var instanceof StaticPropertyFetch) { - $nodeCallback(new PropertyAssignNode($var, $assignedPropertyExpr, $isAssignOp), $scope); + $nodeCallback(new PropertyAssignNode($var, $assignedPropertyExpr, $isAssignOp), $scopeBeforeAssignEval); if ($var instanceof PropertyFetch && $var->name instanceof Node\Identifier && !$isAssignOp) { $scope = $scope->assignInitializedProperty($scope->getType($var->var), $var->name->toString()); } diff --git a/tests/PHPStan/Rules/Variables/ParameterOutAssignedTypeRuleTest.php b/tests/PHPStan/Rules/Variables/ParameterOutAssignedTypeRuleTest.php index f8268f8fcd..a8a9744819 100644 --- a/tests/PHPStan/Rules/Variables/ParameterOutAssignedTypeRuleTest.php +++ b/tests/PHPStan/Rules/Variables/ParameterOutAssignedTypeRuleTest.php @@ -64,4 +64,9 @@ public function testBenevolentArrayKey(): void $this->analyse([__DIR__ . '/data/benevolent-array-key.php'], []); } + public function testBug13093(): void + { + $this->analyse([__DIR__ . '/data/bug-13093.php'], []); + } + } diff --git a/tests/PHPStan/Rules/Variables/data/bug-13093.php b/tests/PHPStan/Rules/Variables/data/bug-13093.php new file mode 100644 index 0000000000..0d780ce1a0 --- /dev/null +++ b/tests/PHPStan/Rules/Variables/data/bug-13093.php @@ -0,0 +1,40 @@ + + */ + private array $nextMutantProcessKillerContainer = []; + + /** + * @param MutantProcessContainer[] $bucket + * @param Generator $input + */ + public function fillBucketOnce(array &$bucket, Generator $input, int $threadCount): int + { + if (count($bucket) >= $threadCount || !$input->valid()) { + if ($this->nextMutantProcessKillerContainer !== []) { + $bucket[] = array_shift($this->nextMutantProcessKillerContainer); + } + + return 0; + } + + return 1; + } + +} + From 214aa7bdec7e4a1c5e9f03f6a0621669a41990a9 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Sat, 31 May 2025 10:18:05 +0200 Subject: [PATCH 02/10] fix more variants --- src/Analyser/NodeScopeResolver.php | 7 ++--- .../ParameterOutAssignedTypeRuleTest.php | 5 ++++ .../Rules/Variables/data/bug-13093b.php | 26 +++++++++++++++++++ 3 files changed, 35 insertions(+), 3 deletions(-) create mode 100644 tests/PHPStan/Rules/Variables/data/bug-13093b.php diff --git a/src/Analyser/NodeScopeResolver.php b/src/Analyser/NodeScopeResolver.php index ed976abef6..ea762b721d 100644 --- a/src/Analyser/NodeScopeResolver.php +++ b/src/Analyser/NodeScopeResolver.php @@ -5392,6 +5392,7 @@ private function processAssignVar( } } + $scopeBeforeAssignEval = $scope; $scope = $result->getScope(); $truthySpecifiedTypes = $this->typeSpecifier->specifyTypesInCondition($scope, $assignedExpr, TypeSpecifierContext::createTruthy()); $falseySpecifiedTypes = $this->typeSpecifier->specifyTypesInCondition($scope, $assignedExpr, TypeSpecifierContext::createFalsey()); @@ -5404,7 +5405,7 @@ private function processAssignVar( $conditionalExpressions = $this->processSureTypesForConditionalExpressionsAfterAssign($scope, $var->name, $conditionalExpressions, $falseySpecifiedTypes, $falseyType); $conditionalExpressions = $this->processSureNotTypesForConditionalExpressionsAfterAssign($scope, $var->name, $conditionalExpressions, $falseySpecifiedTypes, $falseyType); - $nodeCallback(new VariableAssignNode($var, $assignedExpr), $result->getScope()); + $nodeCallback(new VariableAssignNode($var, $assignedExpr), $scopeBeforeAssignEval); $scope = $scope->assignVariable($var->name, $type, $scope->getNativeType($assignedExpr), TrinaryLogic::createYes()); foreach ($conditionalExpressions as $exprString => $holders) { $scope = $scope->addConditionalExpressions($exprString, $holders); @@ -5575,9 +5576,9 @@ private function processAssignVar( } } else { if ($var instanceof Variable) { - $nodeCallback(new VariableAssignNode($var, $assignedPropertyExpr), $scope); + $nodeCallback(new VariableAssignNode($var, $assignedPropertyExpr), $scopeBeforeAssignEval); } elseif ($var instanceof PropertyFetch || $var instanceof StaticPropertyFetch) { - $nodeCallback(new PropertyAssignNode($var, $assignedPropertyExpr, $isAssignOp), $scope); + $nodeCallback(new PropertyAssignNode($var, $assignedPropertyExpr, $isAssignOp), $scopeBeforeAssignEval); if ($var instanceof PropertyFetch && $var->name instanceof Node\Identifier && !$isAssignOp) { $scope = $scope->assignInitializedProperty($scope->getType($var->var), $var->name->toString()); } diff --git a/tests/PHPStan/Rules/Variables/ParameterOutAssignedTypeRuleTest.php b/tests/PHPStan/Rules/Variables/ParameterOutAssignedTypeRuleTest.php index a8a9744819..1e651b6b48 100644 --- a/tests/PHPStan/Rules/Variables/ParameterOutAssignedTypeRuleTest.php +++ b/tests/PHPStan/Rules/Variables/ParameterOutAssignedTypeRuleTest.php @@ -69,4 +69,9 @@ public function testBug13093(): void $this->analyse([__DIR__ . '/data/bug-13093.php'], []); } + public function testBug13093b(): void + { + $this->analyse([__DIR__ . '/data/bug-13093b.php'], []); + } + } diff --git a/tests/PHPStan/Rules/Variables/data/bug-13093b.php b/tests/PHPStan/Rules/Variables/data/bug-13093b.php new file mode 100644 index 0000000000..5e462a1cbe --- /dev/null +++ b/tests/PHPStan/Rules/Variables/data/bug-13093b.php @@ -0,0 +1,26 @@ + + */ + private array $nextMutantProcessKillerContainer = []; + + public function fillBucketOnce(string &$killer): int + { + if ($this->nextMutantProcessKillerContainer !== []) { + $killer = array_shift($this->nextMutantProcessKillerContainer); + } + + return 0; + } + +} + From d098ba80a3ddd5ad1bd768f86eeb5e06deef8714 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Sat, 31 May 2025 10:36:41 +0200 Subject: [PATCH 03/10] fix property variant --- src/Analyser/NodeScopeResolver.php | 3 +- .../TypesAssignedToPropertiesRuleTest.php | 5 ++++ .../Rules/Properties/data/bug-13093c.php | 28 +++++++++++++++++++ 3 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 tests/PHPStan/Rules/Properties/data/bug-13093c.php diff --git a/src/Analyser/NodeScopeResolver.php b/src/Analyser/NodeScopeResolver.php index ea762b721d..6607956a8d 100644 --- a/src/Analyser/NodeScopeResolver.php +++ b/src/Analyser/NodeScopeResolver.php @@ -5613,6 +5613,7 @@ static function (): void { $scope = $propertyNameResult->getScope(); } + $scopeBeforeAssignEval = $scope; $result = $processExprCallback($scope); $hasYield = $hasYield || $result->hasYield(); $throwPoints = array_merge($throwPoints, $result->getThrowPoints()); @@ -5627,7 +5628,7 @@ static function (): void { if ($propertyName !== null && $propertyHolderType->hasProperty($propertyName)->yes()) { $propertyReflection = $propertyHolderType->getProperty($propertyName, $scope); $assignedExprType = $scope->getType($assignedExpr); - $nodeCallback(new PropertyAssignNode($var, $assignedExpr, $isAssignOp), $scope); + $nodeCallback(new PropertyAssignNode($var, $assignedExpr, $isAssignOp), $scopeBeforeAssignEval); if ($propertyReflection->canChangeTypeAfterAssignment()) { if ($propertyReflection->hasNativeType()) { $propertyNativeType = $propertyReflection->getNativeType(); diff --git a/tests/PHPStan/Rules/Properties/TypesAssignedToPropertiesRuleTest.php b/tests/PHPStan/Rules/Properties/TypesAssignedToPropertiesRuleTest.php index 8d050e7636..1eb0653fbe 100644 --- a/tests/PHPStan/Rules/Properties/TypesAssignedToPropertiesRuleTest.php +++ b/tests/PHPStan/Rules/Properties/TypesAssignedToPropertiesRuleTest.php @@ -779,4 +779,9 @@ public function testPropertyHooks(): void ]); } + public function testBug13093c(): void + { + $this->analyse([__DIR__ . '/data/bug-13093c.php'], []); + } + } diff --git a/tests/PHPStan/Rules/Properties/data/bug-13093c.php b/tests/PHPStan/Rules/Properties/data/bug-13093c.php new file mode 100644 index 0000000000..b9123e6f3f --- /dev/null +++ b/tests/PHPStan/Rules/Properties/data/bug-13093c.php @@ -0,0 +1,28 @@ + + */ + private array $nextMutantProcessKillerContainer = []; + + private string $prop; + + public function fillBucketOnce(array &$killer): int + { + if ($this->nextMutantProcessKillerContainer !== []) { + $this->prop = array_shift($this->nextMutantProcessKillerContainer); + } + + return 0; + } + +} + From 2e751b72f9f92386aa94237b9eac763357f9a790 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Sat, 31 May 2025 10:40:49 +0200 Subject: [PATCH 04/10] fix static property variant --- src/Analyser/NodeScopeResolver.php | 3 +- .../TypesAssignedToPropertiesRuleTest.php | 5 ++++ .../Rules/Properties/data/bug-13093d.php | 28 +++++++++++++++++++ 3 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 tests/PHPStan/Rules/Properties/data/bug-13093d.php diff --git a/src/Analyser/NodeScopeResolver.php b/src/Analyser/NodeScopeResolver.php index 6607956a8d..add6bbc048 100644 --- a/src/Analyser/NodeScopeResolver.php +++ b/src/Analyser/NodeScopeResolver.php @@ -5708,6 +5708,7 @@ static function (): void { $scope = $propertyNameResult->getScope(); } + $scopeBeforeAssignEval = $scope; $result = $processExprCallback($scope); $hasYield = $hasYield || $result->hasYield(); $throwPoints = array_merge($throwPoints, $result->getThrowPoints()); @@ -5717,7 +5718,7 @@ static function (): void { if ($propertyName !== null) { $propertyReflection = $scope->getPropertyReflection($propertyHolderType, $propertyName); $assignedExprType = $scope->getType($assignedExpr); - $nodeCallback(new PropertyAssignNode($var, $assignedExpr, $isAssignOp), $scope); + $nodeCallback(new PropertyAssignNode($var, $assignedExpr, $isAssignOp), $scopeBeforeAssignEval); if ($propertyReflection !== null && $propertyReflection->canChangeTypeAfterAssignment()) { if ($propertyReflection->hasNativeType()) { $propertyNativeType = $propertyReflection->getNativeType(); diff --git a/tests/PHPStan/Rules/Properties/TypesAssignedToPropertiesRuleTest.php b/tests/PHPStan/Rules/Properties/TypesAssignedToPropertiesRuleTest.php index 1eb0653fbe..55061e27a5 100644 --- a/tests/PHPStan/Rules/Properties/TypesAssignedToPropertiesRuleTest.php +++ b/tests/PHPStan/Rules/Properties/TypesAssignedToPropertiesRuleTest.php @@ -784,4 +784,9 @@ public function testBug13093c(): void $this->analyse([__DIR__ . '/data/bug-13093c.php'], []); } + public function testBug13093d(): void + { + $this->analyse([__DIR__ . '/data/bug-13093d.php'], []); + } + } diff --git a/tests/PHPStan/Rules/Properties/data/bug-13093d.php b/tests/PHPStan/Rules/Properties/data/bug-13093d.php new file mode 100644 index 0000000000..26bb2f2f73 --- /dev/null +++ b/tests/PHPStan/Rules/Properties/data/bug-13093d.php @@ -0,0 +1,28 @@ + + */ + private array $nextMutantProcessKillerContainer = []; + + static private string $prop; + + public function fillBucketOnce(array &$killer): int + { + if ($this->nextMutantProcessKillerContainer !== []) { + self::$prop = array_shift($this->nextMutantProcessKillerContainer); + } + + return 0; + } + +} + From 228a0d137572e27de9ee3db492edfcdddb5fcc2a Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Sat, 31 May 2025 10:43:54 +0200 Subject: [PATCH 05/10] fix dynamic static variant --- src/Analyser/NodeScopeResolver.php | 2 +- .../Rules/Properties/data/bug-13093d.php | 22 +++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/Analyser/NodeScopeResolver.php b/src/Analyser/NodeScopeResolver.php index add6bbc048..53cc83ed86 100644 --- a/src/Analyser/NodeScopeResolver.php +++ b/src/Analyser/NodeScopeResolver.php @@ -5749,7 +5749,7 @@ static function (): void { } else { // fallback $assignedExprType = $scope->getType($assignedExpr); - $nodeCallback(new PropertyAssignNode($var, $assignedExpr, $isAssignOp), $scope); + $nodeCallback(new PropertyAssignNode($var, $assignedExpr, $isAssignOp), $scopeBeforeAssignEval); $scope = $scope->assignExpression($var, $assignedExprType, $scope->getNativeType($assignedExpr)); } } elseif ($var instanceof List_) { diff --git a/tests/PHPStan/Rules/Properties/data/bug-13093d.php b/tests/PHPStan/Rules/Properties/data/bug-13093d.php index 26bb2f2f73..966958e57e 100644 --- a/tests/PHPStan/Rules/Properties/data/bug-13093d.php +++ b/tests/PHPStan/Rules/Properties/data/bug-13093d.php @@ -26,3 +26,25 @@ public function fillBucketOnce(array &$killer): int } +final class ParallelProcessRunner +{ + /** + * @var array + */ + private array $nextMutantProcessKillerContainer = []; + + static private string $prop; + + public function fillBucketOnce(array &$killer): int + { + $name = 'prop'; + if ($this->nextMutantProcessKillerContainer !== []) { + self::${$name} = array_shift($this->nextMutantProcessKillerContainer); + } + + return 0; + } + +} + + From e1b12a1067b74e308b7f49ac1456925f13be9296 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Sat, 31 May 2025 10:45:13 +0200 Subject: [PATCH 06/10] fix dynamic property variant --- src/Analyser/NodeScopeResolver.php | 2 +- .../Rules/Properties/data/bug-13093c.php | 21 +++++++++++++++++++ .../Rules/Properties/data/bug-13093d.php | 2 +- 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/Analyser/NodeScopeResolver.php b/src/Analyser/NodeScopeResolver.php index 53cc83ed86..18ea0112e9 100644 --- a/src/Analyser/NodeScopeResolver.php +++ b/src/Analyser/NodeScopeResolver.php @@ -5674,7 +5674,7 @@ static function (): void { } else { // fallback $assignedExprType = $scope->getType($assignedExpr); - $nodeCallback(new PropertyAssignNode($var, $assignedExpr, $isAssignOp), $scope); + $nodeCallback(new PropertyAssignNode($var, $assignedExpr, $isAssignOp), $scopeBeforeAssignEval); $scope = $scope->assignExpression($var, $assignedExprType, $scope->getNativeType($assignedExpr)); // simulate dynamic property assign by __set to get throw points if (!$propertyHolderType->hasMethod('__set')->no()) { diff --git a/tests/PHPStan/Rules/Properties/data/bug-13093c.php b/tests/PHPStan/Rules/Properties/data/bug-13093c.php index b9123e6f3f..3fecc5f91d 100644 --- a/tests/PHPStan/Rules/Properties/data/bug-13093c.php +++ b/tests/PHPStan/Rules/Properties/data/bug-13093c.php @@ -26,3 +26,24 @@ public function fillBucketOnce(array &$killer): int } +final class ParallelProcessRunner2 +{ + /** + * @var array + */ + private array $nextMutantProcessKillerContainer = []; + + private string $prop; + + public function fillBucketOnce(array &$killer): int + { + $name = 'prop'; + if ($this->nextMutantProcessKillerContainer !== []) { + $this->{$name} = array_shift($this->nextMutantProcessKillerContainer); + } + + return 0; + } + +} + diff --git a/tests/PHPStan/Rules/Properties/data/bug-13093d.php b/tests/PHPStan/Rules/Properties/data/bug-13093d.php index 966958e57e..1682c7c22a 100644 --- a/tests/PHPStan/Rules/Properties/data/bug-13093d.php +++ b/tests/PHPStan/Rules/Properties/data/bug-13093d.php @@ -26,7 +26,7 @@ public function fillBucketOnce(array &$killer): int } -final class ParallelProcessRunner +final class ParallelProcessRunner2 { /** * @var array From ee73a0bbef732f5468899163e88ae8bb9a16773c Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Sat, 31 May 2025 11:09:02 +0200 Subject: [PATCH 07/10] regression test --- .../TypesAssignedToPropertiesRuleTest.php | 9 ++++++- .../Rules/Properties/data/bug-8825.php | 24 +++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 tests/PHPStan/Rules/Properties/data/bug-8825.php diff --git a/tests/PHPStan/Rules/Properties/TypesAssignedToPropertiesRuleTest.php b/tests/PHPStan/Rules/Properties/TypesAssignedToPropertiesRuleTest.php index 55061e27a5..71128cb7db 100644 --- a/tests/PHPStan/Rules/Properties/TypesAssignedToPropertiesRuleTest.php +++ b/tests/PHPStan/Rules/Properties/TypesAssignedToPropertiesRuleTest.php @@ -14,10 +14,11 @@ class TypesAssignedToPropertiesRuleTest extends RuleTestCase { private bool $checkExplicitMixed = false; + private bool $checkImplicitMixed = false; protected function getRule(): Rule { - return new TypesAssignedToPropertiesRule(new RuleLevelHelper($this->createReflectionProvider(), true, false, true, $this->checkExplicitMixed, false, false, true), new PropertyReflectionFinder()); + return new TypesAssignedToPropertiesRule(new RuleLevelHelper($this->createReflectionProvider(), true, false, true, $this->checkExplicitMixed, $this->checkImplicitMixed, false, true), new PropertyReflectionFinder()); } public function testTypesAssignedToProperties(): void @@ -789,4 +790,10 @@ public function testBug13093d(): void $this->analyse([__DIR__ . '/data/bug-13093d.php'], []); } + public function testBug8825(): void + { + $this->checkImplicitMixed = true; + $this->analyse([__DIR__ . '/data/bug-8825.php'], []); + } + } diff --git a/tests/PHPStan/Rules/Properties/data/bug-8825.php b/tests/PHPStan/Rules/Properties/data/bug-8825.php new file mode 100644 index 0000000000..e1aa5c372d --- /dev/null +++ b/tests/PHPStan/Rules/Properties/data/bug-8825.php @@ -0,0 +1,24 @@ +isBool = $actionParameters['my_key'] ?? false; + } + + public function use(): void + { + $this->isBool->someMethod(); + } +} From 933c2be25c82393e11c0ab7f4b88550a0011900b Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Sat, 31 May 2025 11:12:45 +0200 Subject: [PATCH 08/10] regression test --- .../Rules/Properties/data/bug-7844.php | 23 +++++++++++++++++++ .../ParameterOutAssignedTypeRuleTest.php | 5 ++++ 2 files changed, 28 insertions(+) create mode 100644 tests/PHPStan/Rules/Properties/data/bug-7844.php diff --git a/tests/PHPStan/Rules/Properties/data/bug-7844.php b/tests/PHPStan/Rules/Properties/data/bug-7844.php new file mode 100644 index 0000000000..40dd52d8cc --- /dev/null +++ b/tests/PHPStan/Rules/Properties/data/bug-7844.php @@ -0,0 +1,23 @@ + */ + public $data = array(); + + public function foo(): void + { + \PHPStan\dumpType($this->data); + if (count($this->data) > 0) { + \PHPStan\dumpType($this->data); + $this->val = array_shift($this->data); + \PHPStan\dumpType($this->val); + } + } +} + diff --git a/tests/PHPStan/Rules/Variables/ParameterOutAssignedTypeRuleTest.php b/tests/PHPStan/Rules/Variables/ParameterOutAssignedTypeRuleTest.php index 1e651b6b48..026a5d90a2 100644 --- a/tests/PHPStan/Rules/Variables/ParameterOutAssignedTypeRuleTest.php +++ b/tests/PHPStan/Rules/Variables/ParameterOutAssignedTypeRuleTest.php @@ -74,4 +74,9 @@ public function testBug13093b(): void $this->analyse([__DIR__ . '/data/bug-13093b.php'], []); } + public function testBug7844(): void + { + $this->analyse([__DIR__ . '/data/bug-7844.php'], []); + } + } From 7cc0b0d2265f42125290a495da9087b52055dcc0 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Sat, 31 May 2025 11:17:18 +0200 Subject: [PATCH 09/10] regression tests --- .../TypesAssignedToPropertiesRuleTest.php | 11 ++++++ .../Rules/Properties/data/bug-7844.php | 3 -- .../Rules/Properties/data/bug-7844b.php | 39 +++++++++++++++++++ .../ParameterOutAssignedTypeRuleTest.php | 5 --- 4 files changed, 50 insertions(+), 8 deletions(-) create mode 100644 tests/PHPStan/Rules/Properties/data/bug-7844b.php diff --git a/tests/PHPStan/Rules/Properties/TypesAssignedToPropertiesRuleTest.php b/tests/PHPStan/Rules/Properties/TypesAssignedToPropertiesRuleTest.php index 71128cb7db..e44cdde242 100644 --- a/tests/PHPStan/Rules/Properties/TypesAssignedToPropertiesRuleTest.php +++ b/tests/PHPStan/Rules/Properties/TypesAssignedToPropertiesRuleTest.php @@ -14,6 +14,7 @@ class TypesAssignedToPropertiesRuleTest extends RuleTestCase { private bool $checkExplicitMixed = false; + private bool $checkImplicitMixed = false; protected function getRule(): Rule @@ -796,4 +797,14 @@ public function testBug8825(): void $this->analyse([__DIR__ . '/data/bug-8825.php'], []); } + public function testBug7844(): void + { + $this->analyse([__DIR__ . '/data/bug-7844.php'], []); + } + + public function testBug7844b(): void + { + $this->analyse([__DIR__ . '/data/bug-7844b.php'], []); + } + } diff --git a/tests/PHPStan/Rules/Properties/data/bug-7844.php b/tests/PHPStan/Rules/Properties/data/bug-7844.php index 40dd52d8cc..b202edd3f2 100644 --- a/tests/PHPStan/Rules/Properties/data/bug-7844.php +++ b/tests/PHPStan/Rules/Properties/data/bug-7844.php @@ -12,11 +12,8 @@ class C public function foo(): void { - \PHPStan\dumpType($this->data); if (count($this->data) > 0) { - \PHPStan\dumpType($this->data); $this->val = array_shift($this->data); - \PHPStan\dumpType($this->val); } } } diff --git a/tests/PHPStan/Rules/Properties/data/bug-7844b.php b/tests/PHPStan/Rules/Properties/data/bug-7844b.php new file mode 100644 index 0000000000..c423628f8c --- /dev/null +++ b/tests/PHPStan/Rules/Properties/data/bug-7844b.php @@ -0,0 +1,39 @@ + $objs */ + public function __construct(array $objs) + { + \assert($objs !== []); + $this->p1 = $objs[0]; + + \assert($objs !== []); + $this->p2 = $objs[array_key_last($objs)]; + + \assert($objs !== []); + $this->p3 = \array_pop($objs); + + \assert($objs !== []); + $this->p4 = \array_shift($objs); + + \assert($objs !== []); + $p = \array_shift($objs); + $this->p5 = $p; + + \assert($objs !== []); + $this->doSomething(\array_pop($objs)); + } + + private function doSomething(Obj $obj): void {} +} diff --git a/tests/PHPStan/Rules/Variables/ParameterOutAssignedTypeRuleTest.php b/tests/PHPStan/Rules/Variables/ParameterOutAssignedTypeRuleTest.php index 026a5d90a2..1e651b6b48 100644 --- a/tests/PHPStan/Rules/Variables/ParameterOutAssignedTypeRuleTest.php +++ b/tests/PHPStan/Rules/Variables/ParameterOutAssignedTypeRuleTest.php @@ -74,9 +74,4 @@ public function testBug13093b(): void $this->analyse([__DIR__ . '/data/bug-13093b.php'], []); } - public function testBug7844(): void - { - $this->analyse([__DIR__ . '/data/bug-7844.php'], []); - } - } From c71567da8d97cd3cf6a660ede74a35d1f71f4454 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Sat, 31 May 2025 11:19:46 +0200 Subject: [PATCH 10/10] Add regression test --- .../TypesAssignedToPropertiesRuleTest.php | 5 +++ .../Rules/Properties/data/bug-12675.php | 37 +++++++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 tests/PHPStan/Rules/Properties/data/bug-12675.php diff --git a/tests/PHPStan/Rules/Properties/TypesAssignedToPropertiesRuleTest.php b/tests/PHPStan/Rules/Properties/TypesAssignedToPropertiesRuleTest.php index e44cdde242..4260da643c 100644 --- a/tests/PHPStan/Rules/Properties/TypesAssignedToPropertiesRuleTest.php +++ b/tests/PHPStan/Rules/Properties/TypesAssignedToPropertiesRuleTest.php @@ -807,4 +807,9 @@ public function testBug7844b(): void $this->analyse([__DIR__ . '/data/bug-7844b.php'], []); } + public function testBug12675(): void + { + $this->analyse([__DIR__ . '/data/bug-12675.php'], []); + } + } diff --git a/tests/PHPStan/Rules/Properties/data/bug-12675.php b/tests/PHPStan/Rules/Properties/data/bug-12675.php new file mode 100644 index 0000000000..ea4674dd3f --- /dev/null +++ b/tests/PHPStan/Rules/Properties/data/bug-12675.php @@ -0,0 +1,37 @@ +username = array_shift($pieces); + $this->domain = array_shift($pieces); + + echo "{$this->username}@{$this->domain}"; + } + + public function with_pop(string $email): void + { + $pieces = explode("@", $email); + if (2 !== count($pieces)) { + + throw new \Exception("Bad, very bad..."); + } + + $this->domain = array_pop($pieces); + $this->username = array_pop($pieces); + + echo "{$this->username}@{$this->domain}"; + } +}