Skip to content

Commit 6779b98

Browse files
committed
Try to support all the for end loop scenarios :)
1 parent 367cf00 commit 6779b98

File tree

4 files changed

+32
-6
lines changed

4 files changed

+32
-6
lines changed

src/Analyser/NodeScopeResolver.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1314,7 +1314,6 @@ private function processStmtNode(
13141314
}
13151315

13161316
$bodyScope = $initScope;
1317-
$alwaysIterates = $stmt->cond === [] && $context->isTopLevel();
13181317
$isIterableAtLeastOnce = TrinaryLogic::createYes();
13191318
$lastCondExpr = $stmt->cond[count($stmt->cond) - 1] ?? null;
13201319
foreach ($stmt->cond as $condExpr) {
@@ -1385,7 +1384,10 @@ private function processStmtNode(
13851384
$loopScope = $this->processExprNode($stmt, $loopExpr, $loopScope, $nodeCallback, ExpressionContext::createTopLevel())->getScope();
13861385
}
13871386
$finalScope = $finalScope->generalizeWith($loopScope);
1387+
1388+
$alwaysIterates = TrinaryLogic::createFromBoolean($context->isTopLevel());
13881389
if ($lastCondExpr !== null) {
1390+
$alwaysIterates = $alwaysIterates->and($finalScope->getType($lastCondExpr)->toBoolean()->isTrue());
13891391
$finalScope = $finalScope->filterByFalseyValue($lastCondExpr);
13901392
}
13911393

@@ -1412,7 +1414,7 @@ private function processStmtNode(
14121414
}
14131415
}
14141416

1415-
if ($alwaysIterates) {
1417+
if ($alwaysIterates->yes()) {
14161418
$isAlwaysTerminating = count($finalScopeResult->getExitPointsByType(Break_::class)) === 0;
14171419
} elseif ($isIterableAtLeastOnce->yes()) {
14181420
$isAlwaysTerminating = $finalScopeResult->isAlwaysTerminating();

tests/PHPStan/Analyser/StatementResultTest.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,30 @@ public function dataIsAlwaysTerminating(): array
273273
'for (;;) { for ($i = 0; $i< 5; $i++) { break 2; } }',
274274
false,
275275
],
276+
[
277+
'for ($i = 0; $i < 5;) { }',
278+
true,
279+
],
280+
[
281+
'for ($i = 0; $i < 5; $i--) { }',
282+
true,
283+
],
284+
[
285+
'for (; 0, 1;) { }',
286+
true,
287+
],
288+
[
289+
'for (; 1, 0;) { }',
290+
false,
291+
],
292+
[
293+
'for (; "", "a";) { }',
294+
true,
295+
],
296+
[
297+
'for (; "a", "";) { }',
298+
false,
299+
],
276300
[
277301
'do { } while (doFoo());',
278302
false,

tests/PHPStan/Rules/Variables/data/defined-variables-anonymous-function-use.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ function () use (&$errorHandler) {
1414
$onlyInIf = 1;
1515
}
1616

17-
for ($forI = 0; $forI < 10, $anotherVariableFromForCond = 1; $forI++, $forJ = $forI) {
17+
for ($forI = 0; $anotherVariableFromForCond = 1, $forI < 10; $forI++, $forJ = $forI) {
1818

1919
}
2020

tests/PHPStan/Rules/Variables/data/defined-variables.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ function () {
243243

244244
}
245245

246-
for ($forI = 0; $forI < 10, $forK = 5; $forI++, $forK++, $forJ = $forI) {
246+
for ($forI = 0; $forK = 5, $forI < 10; $forI++, $forK++, $forJ = $forI) {
247247
echo $forI;
248248
}
249249

@@ -322,7 +322,7 @@ function () {
322322
include($fileB='includeB.php');
323323
echo $fileB;
324324

325-
for ($forLoopVariableInit = 0; $forLoopVariableInit < 5; $forLoopVariableInit = $forLoopVariable, $anotherForLoopVariable = 1) {
325+
for ($forLoopVariableInit = 0; $forLoopVariableInit < 5 && rand(0, 1); $forLoopVariableInit = $forLoopVariable, $anotherForLoopVariable = 1) {
326326
$forLoopVariable = 2;
327327
}
328328
echo $anotherForLoopVariable;
@@ -357,7 +357,7 @@ function () {
357357

358358
}
359359

360-
for (; $forVariableUsedAndThenDefined && $forVariableUsedAndThenDefined = 1;) {
360+
for (; $forVariableUsedAndThenDefined && $forVariableUsedAndThenDefined = 1 && rand(0, 1);) {
361361

362362
}
363363

0 commit comments

Comments
 (0)