diff --git a/src/Analyser/NodeScopeResolver.php b/src/Analyser/NodeScopeResolver.php index 8a807ea745..016f25763b 100644 --- a/src/Analyser/NodeScopeResolver.php +++ b/src/Analyser/NodeScopeResolver.php @@ -1517,8 +1517,16 @@ private function processStmtNode( } $breakExitPoints = $finalScopeResult->getExitPointsByType(Break_::class); - foreach ($breakExitPoints as $breakExitPoint) { - $finalScope = $finalScope->mergeWith($breakExitPoint->getScope()); + if ($alwaysIterates && count($breakExitPoints) > 0) { + $breakScope = null; + foreach ($breakExitPoints as $breakExitPoint) { + $breakScope = $breakScope === null ? $breakExitPoint->getScope() : $breakScope->mergeWith($breakExitPoint->getScope()); + } + $finalScope = $breakScope; + } else { + foreach ($breakExitPoints as $breakExitPoint) { + $finalScope = $finalScope->mergeWith($breakExitPoint->getScope()); + } } $isIterableAtLeastOnce = $beforeCondBooleanType->isTrue()->yes(); diff --git a/tests/PHPStan/Rules/Variables/DefinedVariableRuleTest.php b/tests/PHPStan/Rules/Variables/DefinedVariableRuleTest.php index 112a57d4cc..ccf3735539 100644 --- a/tests/PHPStan/Rules/Variables/DefinedVariableRuleTest.php +++ b/tests/PHPStan/Rules/Variables/DefinedVariableRuleTest.php @@ -1257,4 +1257,73 @@ public function testBug12944(): void $this->analyse([__DIR__ . '/data/bug-12944.php'], []); } + public function testBug9023(): void + { + $this->cliArgumentsVariablesRegistered = true; + $this->polluteScopeWithLoopInitialAssignments = false; + $this->checkMaybeUndefinedVariables = true; + $this->polluteScopeWithAlwaysIterableForeach = true; + + $this->analyse([__DIR__ . '/data/bug-9023.php'], []); + } + + public function testBug11984(): void + { + $this->cliArgumentsVariablesRegistered = true; + $this->polluteScopeWithLoopInitialAssignments = false; + $this->checkMaybeUndefinedVariables = true; + $this->polluteScopeWithAlwaysIterableForeach = true; + + $this->analyse([__DIR__ . '/data/bug-11984.php'], []); + } + + public function testBug11545(): void + { + $this->cliArgumentsVariablesRegistered = true; + $this->polluteScopeWithLoopInitialAssignments = false; + $this->checkMaybeUndefinedVariables = true; + $this->polluteScopeWithAlwaysIterableForeach = true; + + $this->analyse([__DIR__ . '/data/bug-11545.php'], [ + [ + 'Variable $result might not be defined.', + 24, + ], + [ + 'Variable $result might not be defined.', + 36, + ], + ]); + } + + public function testBug10245(): void + { + $this->cliArgumentsVariablesRegistered = true; + $this->polluteScopeWithLoopInitialAssignments = false; + $this->checkMaybeUndefinedVariables = true; + $this->polluteScopeWithAlwaysIterableForeach = true; + + $this->analyse([__DIR__ . '/data/bug-10245.php'], []); + } + + public function testBug5919(): void + { + $this->cliArgumentsVariablesRegistered = true; + $this->polluteScopeWithLoopInitialAssignments = false; + $this->checkMaybeUndefinedVariables = true; + $this->polluteScopeWithAlwaysIterableForeach = true; + + $this->analyse([__DIR__ . '/data/bug-5919.php'], []); + } + + public function testBug5477(): void + { + $this->cliArgumentsVariablesRegistered = true; + $this->polluteScopeWithLoopInitialAssignments = false; + $this->checkMaybeUndefinedVariables = true; + $this->polluteScopeWithAlwaysIterableForeach = true; + + $this->analyse([__DIR__ . '/data/bug-5477.php'], []); + } + } diff --git a/tests/PHPStan/Rules/Variables/data/bug-10245.php b/tests/PHPStan/Rules/Variables/data/bug-10245.php new file mode 100644 index 0000000000..f8c3e61156 --- /dev/null +++ b/tests/PHPStan/Rules/Variables/data/bug-10245.php @@ -0,0 +1,36 @@ += 8.0 + +namespace Bug10245; + +/** + * @throws \Exception + */ +function produceInt(): int +{ + return 1; +} + +function testTryCatchInWhileTrue(): void +{ + while (true) { + try { + $a = produceInt(); + break; + } catch (\Throwable) {} + } + + echo $a; +} + +function testIfBreakInWhileTrue(int $max): void +{ + $i = 0; + while (true) { + if ($i > $max) { + $result = 'done'; + break; + } + ++$i; + } + print $result; +} diff --git a/tests/PHPStan/Rules/Variables/data/bug-11545.php b/tests/PHPStan/Rules/Variables/data/bug-11545.php new file mode 100644 index 0000000000..8a118ce1e9 --- /dev/null +++ b/tests/PHPStan/Rules/Variables/data/bug-11545.php @@ -0,0 +1,45 @@ + $max) { + $result = 'done'; + break; + } + ++$i; + } + print $result; +} + +function foo_for(int $max): void { + for ($i = 0;; ++$i) { + if ($i > $max) { + $result = 'done'; + break; + } + } + print $result; +} + +function foo_do_while(int $max): void { + $i = 0; + do { + if ($i > $max) { + $result = 'done'; + break; + } + ++$i; + } while (true); + print $result; +} + +function bar(int $max): void { + while (true) { + $result = 'done'; + break; + } + print $result; +} diff --git a/tests/PHPStan/Rules/Variables/data/bug-11984.php b/tests/PHPStan/Rules/Variables/data/bug-11984.php new file mode 100644 index 0000000000..da45fb4f3c --- /dev/null +++ b/tests/PHPStan/Rules/Variables/data/bug-11984.php @@ -0,0 +1,31 @@ + + */ + public function loadFromFile(): array + { + return ['x' => 1]; + } + + /** + * @return array + */ + public function test(): array + { + while (true) { + try { + $data = $this->loadFromFile(); + + break; + } catch (\Exception $ex) { + } + } + + return $data; + } +} diff --git a/tests/PHPStan/Rules/Variables/data/bug-5477.php b/tests/PHPStan/Rules/Variables/data/bug-5477.php new file mode 100644 index 0000000000..ad2e35b043 --- /dev/null +++ b/tests/PHPStan/Rules/Variables/data/bug-5477.php @@ -0,0 +1,16 @@ +