1
0
mirror of https://github.com/danog/psalm.git synced 2024-11-27 12:55:26 +01:00

Merge pull request #8828 from orklah/generator

fix missing break handling in loop
This commit is contained in:
orklah 2022-12-04 16:38:37 +01:00 committed by GitHub
commit df4d3692ab
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 27 additions and 0 deletions

View File

@ -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';
@ -107,6 +108,10 @@ class ScopeAnalyzer
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);
}
@ -263,6 +268,7 @@ class ScopeAnalyzer
&& $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(
@ -277,6 +283,7 @@ class ScopeAnalyzer
if ($stmt instanceof PhpParser\Node\Stmt\For_
&& $nodes
&& !in_array(self::ACTION_LEAVE_LOOP, $control_actions, true)
) {
$is_infinite_loop = true;
if ($stmt->cond) {
@ -300,6 +307,11 @@ class ScopeAnalyzer
}
}
}
$control_actions = array_filter(
$control_actions,
static fn(string $action): bool => $action !== self::ACTION_LEAVE_LOOP
);
}
if ($stmt instanceof PhpParser\Node\Stmt\TryCatch) {

View File

@ -676,6 +676,21 @@ class WhileTest extends TestCase
}
}'
],
'breakInWhileTrueIsNotInfiniteLoop' => [
'code' => '<?php
/** @return Generator<array-key, mixed> */
function f()
{
if (rand(0,1)) {
throw new Exception;
}
while (true) {
yield 1;
break;
}
}'
],
];
}