mirror of
https://github.com/danog/psalm.git
synced 2025-01-22 05:41:20 +01:00
fix missing break handling in loop
This commit is contained in:
parent
4a77f24869
commit
2490230f1f
@ -23,6 +23,7 @@ class ScopeAnalyzer
|
|||||||
public const ACTION_BREAK = 'BREAK';
|
public const ACTION_BREAK = 'BREAK';
|
||||||
public const ACTION_CONTINUE = 'CONTINUE';
|
public const ACTION_CONTINUE = 'CONTINUE';
|
||||||
public const ACTION_LEAVE_SWITCH = 'LEAVE_SWITCH';
|
public const ACTION_LEAVE_SWITCH = 'LEAVE_SWITCH';
|
||||||
|
public const ACTION_LEAVE_LOOP = 'LEAVE_LOOP';
|
||||||
public const ACTION_NONE = 'NONE';
|
public const ACTION_NONE = 'NONE';
|
||||||
public const ACTION_RETURN = 'RETURN';
|
public const ACTION_RETURN = 'RETURN';
|
||||||
|
|
||||||
@ -107,6 +108,10 @@ class ScopeAnalyzer
|
|||||||
return [...$control_actions, ...[self::ACTION_LEAVE_SWITCH]];
|
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);
|
return array_values($control_actions);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -263,6 +268,7 @@ class ScopeAnalyzer
|
|||||||
&& $nodes
|
&& $nodes
|
||||||
&& ($stmt_expr_type = $nodes->getType($stmt->cond))
|
&& ($stmt_expr_type = $nodes->getType($stmt->cond))
|
||||||
&& $stmt_expr_type->isAlwaysTruthy()
|
&& $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
|
//infinite while loop that only return don't have an exit path
|
||||||
$have_exit_path = (bool)array_diff(
|
$have_exit_path = (bool)array_diff(
|
||||||
@ -277,6 +283,7 @@ class ScopeAnalyzer
|
|||||||
|
|
||||||
if ($stmt instanceof PhpParser\Node\Stmt\For_
|
if ($stmt instanceof PhpParser\Node\Stmt\For_
|
||||||
&& $nodes
|
&& $nodes
|
||||||
|
&& !in_array(self::ACTION_LEAVE_LOOP, $control_actions, true)
|
||||||
) {
|
) {
|
||||||
$is_infinite_loop = true;
|
$is_infinite_loop = true;
|
||||||
if ($stmt->cond) {
|
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) {
|
if ($stmt instanceof PhpParser\Node\Stmt\TryCatch) {
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
}'
|
||||||
|
],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user