Skip to content

Commit

Permalink
fix missing break handling in loop
Browse files Browse the repository at this point in the history
  • Loading branch information
orklah committed Dec 4, 2022
1 parent 4a77f24 commit 2490230
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 0 deletions.
12 changes: 12 additions & 0 deletions src/Psalm/Internal/Analyzer/ScopeAnalyzer.php
Expand Up @@ -23,6 +23,7 @@ class ScopeAnalyzer
public const ACTION_BREAK = 'BREAK';
public const ACTION_CONTINUE = 'CONTINUE';
public const ACTION_LEAVE_SWITCH = 'LEAVE_SWITCH';
public const ACTION_LEAVE_LOOP = 'LEAVE_LOOP';
public const ACTION_NONE = 'NONE';
public const ACTION_RETURN = 'RETURN';

Expand Down Expand Up @@ -107,6 +108,10 @@ public static function getControlActions(
return [...$control_actions, ...[self::ACTION_LEAVE_SWITCH]];
}

if ($break_types[count($break_types) - $count] === 'loop') {
return [...$control_actions, ...[self::ACTION_LEAVE_LOOP]];
}

return array_values($control_actions);
}

Expand Down Expand Up @@ -263,6 +268,7 @@ public static function getControlActions(
&& $nodes
&& ($stmt_expr_type = $nodes->getType($stmt->cond))
&& $stmt_expr_type->isAlwaysTruthy()
&& !in_array(self::ACTION_LEAVE_LOOP, $control_actions, true)
) {
//infinite while loop that only return don't have an exit path
$have_exit_path = (bool)array_diff(
Expand All @@ -277,6 +283,7 @@ public static function getControlActions(

if ($stmt instanceof PhpParser\Node\Stmt\For_
&& $nodes
&& !in_array(self::ACTION_LEAVE_LOOP, $control_actions, true)
) {
$is_infinite_loop = true;
if ($stmt->cond) {
Expand All @@ -300,6 +307,11 @@ public static function getControlActions(
}
}
}

$control_actions = array_filter(
$control_actions,
static fn(string $action): bool => $action !== self::ACTION_LEAVE_LOOP
);
}

if ($stmt instanceof PhpParser\Node\Stmt\TryCatch) {
Expand Down
15 changes: 15 additions & 0 deletions tests/Loop/WhileTest.php
Expand Up @@ -676,6 +676,21 @@ function breakUpPathIntoParts(): void {
}
}'
],
'breakInWhileTrueIsNotInfiniteLoop' => [
'code' => '<?php
/** @return Generator<array-key, mixed> */
function f()
{
if (rand(0,1)) {
throw new Exception;
}
while (true) {
yield 1;
break;
}
}'
],
];
}

Expand Down

0 comments on commit 2490230

Please sign in to comment.