-
Notifications
You must be signed in to change notification settings - Fork 653
/
ContinueAnalyzer.php
103 lines (90 loc) · 3.66 KB
/
ContinueAnalyzer.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
<?php
namespace Psalm\Internal\Analyzer\Statements;
use PhpParser;
use Psalm\CodeLocation;
use Psalm\Context;
use Psalm\Internal\Analyzer\ScopeAnalyzer;
use Psalm\Internal\Analyzer\StatementsAnalyzer;
use Psalm\Issue\ContinueOutsideLoop;
use Psalm\IssueBuffer;
use Psalm\Type;
use function end;
/**
* @internal
*/
class ContinueAnalyzer
{
public static function analyze(
StatementsAnalyzer $statements_analyzer,
PhpParser\Node\Stmt\Continue_ $stmt,
Context $context
): void {
$count = $stmt->num instanceof PhpParser\Node\Scalar\LNumber? $stmt->num->value : 1;
$loop_scope = $context->loop_scope;
if ($count === 2 && isset($loop_scope->loop_parent_context->loop_scope)) {
$loop_scope = $loop_scope->loop_parent_context->loop_scope;
}
if ($count === 3 && isset($loop_scope->loop_parent_context->loop_scope)) {
$loop_scope = $loop_scope->loop_parent_context->loop_scope;
}
if ($loop_scope === null) {
if (!$context->break_types) {
if (IssueBuffer::accepts(
new ContinueOutsideLoop(
'Continue call outside loop context',
new CodeLocation($statements_analyzer, $stmt)
),
$statements_analyzer->getSource()->getSuppressedIssues()
)) {
return;
}
}
} else {
if ($context->break_types
&& end($context->break_types) === 'switch'
&& $count < 2
) {
$loop_scope->final_actions[] = ScopeAnalyzer::ACTION_LEAVE_SWITCH;
} else {
$loop_scope->final_actions[] = ScopeAnalyzer::ACTION_CONTINUE;
}
$redefined_vars = $context->getRedefinedVars($loop_scope->loop_parent_context->vars_in_scope);
if ($loop_scope->redefined_loop_vars === null) {
$loop_scope->redefined_loop_vars = $redefined_vars;
} else {
foreach ($loop_scope->redefined_loop_vars as $redefined_var => $type) {
if (!isset($redefined_vars[$redefined_var])) {
unset($loop_scope->redefined_loop_vars[$redefined_var]);
} else {
$loop_scope->redefined_loop_vars[$redefined_var] = Type::combineUnionTypes(
$redefined_vars[$redefined_var],
$type
);
}
}
}
foreach ($redefined_vars as $var => $type) {
$loop_scope->possibly_redefined_loop_vars[$var] = Type::combineUnionTypes(
$type,
$loop_scope->possibly_redefined_loop_vars[$var] ?? null
);
}
if ($context->finally_scope) {
foreach ($context->vars_in_scope as $var_id => $type) {
if (isset($context->finally_scope->vars_in_scope[$var_id])) {
$context->finally_scope->vars_in_scope[$var_id] = Type::combineUnionTypes(
$context->finally_scope->vars_in_scope[$var_id],
$type,
$statements_analyzer->getCodebase()
);
} else {
$context->finally_scope->vars_in_scope[$var_id] = $type;
$type->possibly_undefined = true;
$type->possibly_undefined_from_try = true;
}
}
}
}
$context->has_returned = true;
}
}