Conditions | 92 |
Paths | > 20000 |
Total Lines | 558 |
Lines | 71 |
Ratio | 12.72 % |
Changes | 0 |
Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.
For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.
Commonly applied refactorings include:
If many parameters/temporary variables are present:
Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.
There are several approaches to avoid long parameter lists:
1 | <?php |
||
40 | public static function analyze( |
||
41 | StatementsAnalyzer $statements_analyzer, |
||
42 | array $stmts, |
||
43 | array $pre_conditions, |
||
44 | array $post_expressions, |
||
45 | LoopScope $loop_scope, |
||
46 | Context &$inner_context = null, |
||
47 | bool $is_do = false, |
||
48 | bool $always_enters_loop = false |
||
49 | ) { |
||
50 | $traverser = new PhpParser\NodeTraverser; |
||
51 | |||
52 | $assignment_mapper = new \Psalm\Internal\PhpVisitor\AssignmentMapVisitor($loop_scope->loop_context->self); |
||
53 | $traverser->addVisitor($assignment_mapper); |
||
54 | |||
55 | $traverser->traverse(array_merge($stmts, $post_expressions)); |
||
56 | |||
57 | $assignment_map = $assignment_mapper->getAssignmentMap(); |
||
58 | |||
59 | $assignment_depth = 0; |
||
60 | |||
61 | $asserted_var_ids = []; |
||
62 | |||
63 | $pre_condition_clauses = []; |
||
64 | |||
65 | $original_protected_var_ids = $loop_scope->loop_parent_context->protected_var_ids; |
||
66 | |||
67 | $codebase = $statements_analyzer->getCodebase(); |
||
68 | |||
69 | $inner_do_context = null; |
||
70 | |||
71 | if ($pre_conditions) { |
||
72 | foreach ($pre_conditions as $i => $pre_condition) { |
||
73 | $pre_condition_clauses[$i] = Algebra::getFormula( |
||
74 | \spl_object_id($pre_condition), |
||
75 | $pre_condition, |
||
76 | $loop_scope->loop_context->self, |
||
77 | $statements_analyzer, |
||
78 | $codebase |
||
79 | ); |
||
80 | } |
||
81 | } else { |
||
82 | $asserted_var_ids = Context::getNewOrUpdatedVarIds( |
||
83 | $loop_scope->loop_parent_context, |
||
84 | $loop_scope->loop_context |
||
85 | ); |
||
86 | } |
||
87 | |||
88 | $final_actions = ScopeAnalyzer::getFinalControlActions( |
||
89 | $stmts, |
||
90 | $statements_analyzer->node_data, |
||
91 | Config::getInstance()->exit_functions, |
||
92 | $loop_scope->loop_context->break_types |
||
93 | ); |
||
94 | |||
95 | $does_always_break = $final_actions === [ScopeAnalyzer::ACTION_BREAK]; |
||
96 | |||
97 | if ($assignment_map) { |
||
98 | $first_var_id = array_keys($assignment_map)[0]; |
||
99 | |||
100 | $assignment_depth = self::getAssignmentMapDepth($first_var_id, $assignment_map); |
||
101 | } |
||
102 | |||
103 | $loop_scope->loop_context->parent_context = $loop_scope->loop_parent_context; |
||
104 | |||
105 | $pre_outer_context = $loop_scope->loop_parent_context; |
||
106 | |||
107 | if ($assignment_depth === 0 || $does_always_break) { |
||
108 | $inner_context = clone $loop_scope->loop_context; |
||
109 | |||
110 | foreach ($inner_context->vars_in_scope as $context_var_id => $context_type) { |
||
111 | $inner_context->vars_in_scope[$context_var_id] = clone $context_type; |
||
112 | } |
||
113 | |||
114 | $inner_context->loop_scope = $loop_scope; |
||
115 | |||
116 | $inner_context->parent_context = $loop_scope->loop_context; |
||
117 | $old_referenced_var_ids = $inner_context->referenced_var_ids; |
||
118 | $inner_context->referenced_var_ids = []; |
||
119 | |||
120 | foreach ($pre_conditions as $condition_offset => $pre_condition) { |
||
121 | self::applyPreConditionToLoopContext( |
||
122 | $statements_analyzer, |
||
123 | $pre_condition, |
||
124 | $pre_condition_clauses[$condition_offset], |
||
125 | $inner_context, |
||
126 | $loop_scope->loop_parent_context, |
||
127 | $is_do |
||
128 | ); |
||
129 | } |
||
130 | |||
131 | $inner_context->protected_var_ids = $loop_scope->protected_var_ids; |
||
132 | |||
133 | $statements_analyzer->analyze($stmts, $inner_context); |
||
134 | self::updateLoopScopeContexts($loop_scope, $loop_scope->loop_parent_context); |
||
135 | |||
136 | foreach ($post_expressions as $post_expression) { |
||
137 | if (ExpressionAnalyzer::analyze( |
||
138 | $statements_analyzer, |
||
139 | $post_expression, |
||
140 | $loop_scope->loop_context |
||
141 | ) === false |
||
142 | ) { |
||
143 | return false; |
||
144 | } |
||
145 | } |
||
146 | |||
147 | $new_referenced_var_ids = $inner_context->referenced_var_ids; |
||
148 | $inner_context->referenced_var_ids = $old_referenced_var_ids + $inner_context->referenced_var_ids; |
||
149 | |||
150 | $loop_scope->loop_parent_context->vars_possibly_in_scope = array_merge( |
||
151 | $inner_context->vars_possibly_in_scope, |
||
152 | $loop_scope->loop_parent_context->vars_possibly_in_scope |
||
153 | ); |
||
154 | } else { |
||
155 | $pre_outer_context = clone $loop_scope->loop_parent_context; |
||
156 | |||
157 | $analyzer = $statements_analyzer->getCodebase()->analyzer; |
||
158 | |||
159 | $original_mixed_counts = $analyzer->getMixedCountsForFile($statements_analyzer->getFilePath()); |
||
160 | |||
161 | $pre_condition_vars_in_scope = $loop_scope->loop_context->vars_in_scope; |
||
162 | |||
163 | IssueBuffer::startRecording(); |
||
164 | |||
165 | View Code Duplication | if (!$is_do) { |
|
166 | foreach ($pre_conditions as $condition_offset => $pre_condition) { |
||
167 | $asserted_var_ids = array_merge( |
||
168 | self::applyPreConditionToLoopContext( |
||
169 | $statements_analyzer, |
||
170 | $pre_condition, |
||
171 | $pre_condition_clauses[$condition_offset], |
||
172 | $loop_scope->loop_context, |
||
173 | $loop_scope->loop_parent_context, |
||
174 | $is_do |
||
175 | ), |
||
176 | $asserted_var_ids |
||
177 | ); |
||
178 | } |
||
179 | } |
||
180 | |||
181 | // record all the vars that existed before we did the first pass through the loop |
||
182 | $pre_loop_context = clone $loop_scope->loop_context; |
||
183 | |||
184 | $inner_context = clone $loop_scope->loop_context; |
||
185 | |||
186 | foreach ($inner_context->vars_in_scope as $context_var_id => $context_type) { |
||
187 | $inner_context->vars_in_scope[$context_var_id] = clone $context_type; |
||
188 | } |
||
189 | |||
190 | $inner_context->parent_context = $loop_scope->loop_context; |
||
191 | $inner_context->loop_scope = $loop_scope; |
||
192 | |||
193 | $old_referenced_var_ids = $inner_context->referenced_var_ids; |
||
194 | $inner_context->referenced_var_ids = []; |
||
195 | |||
196 | $inner_context->protected_var_ids = $loop_scope->protected_var_ids; |
||
197 | |||
198 | $statements_analyzer->analyze($stmts, $inner_context); |
||
199 | |||
200 | self::updateLoopScopeContexts($loop_scope, $pre_outer_context); |
||
201 | |||
202 | $inner_context->protected_var_ids = $original_protected_var_ids; |
||
203 | |||
204 | View Code Duplication | if ($is_do) { |
|
205 | $inner_do_context = clone $inner_context; |
||
206 | |||
207 | foreach ($pre_conditions as $condition_offset => $pre_condition) { |
||
208 | $asserted_var_ids = array_merge( |
||
209 | self::applyPreConditionToLoopContext( |
||
210 | $statements_analyzer, |
||
211 | $pre_condition, |
||
212 | $pre_condition_clauses[$condition_offset], |
||
213 | $inner_context, |
||
214 | $loop_scope->loop_parent_context, |
||
215 | $is_do |
||
216 | ), |
||
217 | $asserted_var_ids |
||
218 | ); |
||
219 | } |
||
220 | } |
||
221 | |||
222 | $asserted_var_ids = array_unique($asserted_var_ids); |
||
223 | |||
224 | foreach ($post_expressions as $post_expression) { |
||
225 | if (ExpressionAnalyzer::analyze($statements_analyzer, $post_expression, $inner_context) === false) { |
||
226 | return false; |
||
227 | } |
||
228 | } |
||
229 | |||
230 | /** |
||
231 | * @var array<string, bool> |
||
232 | */ |
||
233 | $new_referenced_var_ids = $inner_context->referenced_var_ids; |
||
234 | $inner_context->referenced_var_ids = array_intersect_key( |
||
235 | $old_referenced_var_ids, |
||
236 | $inner_context->referenced_var_ids |
||
237 | ); |
||
238 | |||
239 | $recorded_issues = IssueBuffer::clearRecordingLevel(); |
||
240 | IssueBuffer::stopRecording(); |
||
241 | |||
242 | for ($i = 0; $i < $assignment_depth; ++$i) { |
||
243 | $vars_to_remove = []; |
||
244 | |||
245 | $loop_scope->iteration_count++; |
||
246 | |||
247 | $has_changes = false; |
||
248 | |||
249 | // reset the $inner_context to what it was before we started the analysis, |
||
250 | // but union the types with what's in the loop scope |
||
251 | |||
252 | foreach ($inner_context->vars_in_scope as $var_id => $type) { |
||
253 | if (in_array($var_id, $asserted_var_ids, true)) { |
||
254 | // set the vars to whatever the while/foreach loop expects them to be |
||
255 | if (!isset($pre_loop_context->vars_in_scope[$var_id]) |
||
256 | || !$type->equals($pre_loop_context->vars_in_scope[$var_id]) |
||
257 | ) { |
||
258 | $has_changes = true; |
||
259 | } |
||
260 | } elseif (isset($pre_outer_context->vars_in_scope[$var_id])) { |
||
261 | if (!$type->equals($pre_outer_context->vars_in_scope[$var_id])) { |
||
262 | $has_changes = true; |
||
263 | |||
264 | // widen the foreach context type with the initial context type |
||
265 | $inner_context->vars_in_scope[$var_id] = Type::combineUnionTypes( |
||
266 | $inner_context->vars_in_scope[$var_id], |
||
267 | $pre_outer_context->vars_in_scope[$var_id] |
||
268 | ); |
||
269 | |||
270 | // if there's a change, invalidate related clauses |
||
271 | $pre_loop_context->removeVarFromConflictingClauses($var_id); |
||
272 | } |
||
273 | |||
274 | if (isset($loop_scope->loop_context->vars_in_scope[$var_id]) |
||
275 | && !$type->equals($loop_scope->loop_context->vars_in_scope[$var_id]) |
||
276 | ) { |
||
277 | $has_changes = true; |
||
278 | |||
279 | // widen the foreach context type with the initial context type |
||
280 | $inner_context->vars_in_scope[$var_id] = Type::combineUnionTypes( |
||
281 | $inner_context->vars_in_scope[$var_id], |
||
282 | $loop_scope->loop_context->vars_in_scope[$var_id] |
||
283 | ); |
||
284 | |||
285 | // if there's a change, invalidate related clauses |
||
286 | $pre_loop_context->removeVarFromConflictingClauses($var_id); |
||
287 | } |
||
288 | } else { |
||
289 | // give an opportunity to redeemed UndefinedVariable issues |
||
290 | if ($recorded_issues) { |
||
291 | $has_changes = true; |
||
292 | } |
||
293 | |||
294 | // if we're in a do block we don't want to remove vars before evaluating |
||
295 | // the where conditional |
||
296 | if (!$is_do) { |
||
297 | $vars_to_remove[] = $var_id; |
||
298 | } |
||
299 | } |
||
300 | } |
||
301 | |||
302 | $inner_context->has_returned = false; |
||
303 | |||
304 | if ($codebase->find_unused_variables) { |
||
305 | foreach ($inner_context->unreferenced_vars as $var_id => $locations) { |
||
306 | if (!isset($pre_outer_context->vars_in_scope[$var_id])) { |
||
307 | $loop_scope->unreferenced_vars[$var_id] = $locations; |
||
308 | unset($inner_context->unreferenced_vars[$var_id]); |
||
309 | } |
||
310 | } |
||
311 | } |
||
312 | |||
313 | $loop_scope->loop_parent_context->vars_possibly_in_scope = array_merge( |
||
314 | $inner_context->vars_possibly_in_scope, |
||
315 | $loop_scope->loop_parent_context->vars_possibly_in_scope |
||
316 | ); |
||
317 | |||
318 | // if there are no changes to the types, no need to re-examine |
||
319 | if (!$has_changes) { |
||
320 | break; |
||
321 | } |
||
322 | |||
323 | if ($codebase->find_unused_variables) { |
||
324 | foreach ($loop_scope->possibly_unreferenced_vars as $var_id => $locations) { |
||
325 | if (isset($inner_context->unreferenced_vars[$var_id])) { |
||
326 | $inner_context->unreferenced_vars[$var_id] += $locations; |
||
327 | } else { |
||
328 | $inner_context->unreferenced_vars[$var_id] = $locations; |
||
329 | } |
||
330 | } |
||
331 | } |
||
332 | |||
333 | // remove vars that were defined in the foreach |
||
334 | foreach ($vars_to_remove as $var_id) { |
||
335 | unset($inner_context->vars_in_scope[$var_id]); |
||
336 | } |
||
337 | |||
338 | $inner_context->clauses = $pre_loop_context->clauses; |
||
339 | |||
340 | $analyzer->setMixedCountsForFile($statements_analyzer->getFilePath(), $original_mixed_counts); |
||
341 | IssueBuffer::startRecording(); |
||
342 | |||
343 | foreach ($pre_loop_context->vars_in_scope as $var_id => $_) { |
||
344 | if (!isset($pre_condition_vars_in_scope[$var_id]) |
||
345 | && isset($inner_context->vars_in_scope[$var_id]) |
||
346 | && \strpos($var_id, '->') === false |
||
347 | && \strpos($var_id, '[') === false |
||
348 | ) { |
||
349 | $inner_context->vars_in_scope[$var_id]->possibly_undefined = true; |
||
350 | } |
||
351 | } |
||
352 | |||
353 | if (!$is_do) { |
||
354 | foreach ($pre_conditions as $condition_offset => $pre_condition) { |
||
355 | self::applyPreConditionToLoopContext( |
||
356 | $statements_analyzer, |
||
357 | $pre_condition, |
||
358 | $pre_condition_clauses[$condition_offset], |
||
359 | $inner_context, |
||
360 | $loop_scope->loop_parent_context, |
||
361 | false |
||
362 | ); |
||
363 | } |
||
364 | } |
||
365 | |||
366 | foreach ($asserted_var_ids as $var_id) { |
||
367 | if (!isset($inner_context->vars_in_scope[$var_id]) |
||
368 | || $inner_context->vars_in_scope[$var_id]->getId() |
||
369 | !== $pre_loop_context->vars_in_scope[$var_id]->getId() |
||
370 | || $inner_context->vars_in_scope[$var_id]->from_docblock |
||
371 | !== $pre_loop_context->vars_in_scope[$var_id]->from_docblock |
||
372 | ) { |
||
373 | $inner_context->vars_in_scope[$var_id] = clone $pre_loop_context->vars_in_scope[$var_id]; |
||
374 | } |
||
375 | } |
||
376 | |||
377 | $inner_context->clauses = $pre_loop_context->clauses; |
||
378 | |||
379 | $inner_context->protected_var_ids = $loop_scope->protected_var_ids; |
||
380 | |||
381 | $traverser = new PhpParser\NodeTraverser; |
||
382 | |||
383 | $traverser->addVisitor( |
||
384 | new \Psalm\Internal\PhpVisitor\NodeCleanerVisitor( |
||
385 | $statements_analyzer->node_data |
||
386 | ) |
||
387 | ); |
||
388 | $traverser->traverse($stmts); |
||
389 | |||
390 | $statements_analyzer->analyze($stmts, $inner_context); |
||
391 | |||
392 | self::updateLoopScopeContexts($loop_scope, $pre_outer_context); |
||
393 | |||
394 | $inner_context->protected_var_ids = $original_protected_var_ids; |
||
395 | |||
396 | View Code Duplication | if ($is_do) { |
|
397 | $inner_do_context = clone $inner_context; |
||
398 | |||
399 | foreach ($pre_conditions as $condition_offset => $pre_condition) { |
||
400 | self::applyPreConditionToLoopContext( |
||
401 | $statements_analyzer, |
||
402 | $pre_condition, |
||
403 | $pre_condition_clauses[$condition_offset], |
||
404 | $inner_context, |
||
405 | $loop_scope->loop_parent_context, |
||
406 | $is_do |
||
407 | ); |
||
408 | } |
||
409 | } |
||
410 | |||
411 | foreach ($post_expressions as $post_expression) { |
||
412 | if (ExpressionAnalyzer::analyze($statements_analyzer, $post_expression, $inner_context) === false) { |
||
413 | return false; |
||
414 | } |
||
415 | } |
||
416 | |||
417 | $recorded_issues = IssueBuffer::clearRecordingLevel(); |
||
418 | |||
419 | IssueBuffer::stopRecording(); |
||
420 | } |
||
421 | |||
422 | if ($recorded_issues) { |
||
423 | foreach ($recorded_issues as $recorded_issue) { |
||
424 | // if we're not in any loops then this will just result in the issue being emitted |
||
425 | IssueBuffer::bubbleUp($recorded_issue); |
||
426 | } |
||
427 | } |
||
428 | } |
||
429 | |||
430 | $does_sometimes_break = in_array(ScopeAnalyzer::ACTION_BREAK, $loop_scope->final_actions, true); |
||
431 | $does_always_break = $loop_scope->final_actions === [ScopeAnalyzer::ACTION_BREAK]; |
||
432 | |||
433 | if ($does_sometimes_break) { |
||
434 | if ($loop_scope->possibly_redefined_loop_parent_vars !== null) { |
||
435 | foreach ($loop_scope->possibly_redefined_loop_parent_vars as $var => $type) { |
||
436 | $loop_scope->loop_parent_context->vars_in_scope[$var] = Type::combineUnionTypes( |
||
437 | $type, |
||
438 | $loop_scope->loop_parent_context->vars_in_scope[$var] |
||
439 | ); |
||
440 | } |
||
441 | } |
||
442 | } |
||
443 | |||
444 | foreach ($loop_scope->loop_parent_context->vars_in_scope as $var_id => $type) { |
||
445 | if (!isset($loop_scope->loop_context->vars_in_scope[$var_id])) { |
||
446 | continue; |
||
447 | } |
||
448 | |||
449 | View Code Duplication | if ($loop_scope->loop_context->vars_in_scope[$var_id]->getId() !== $type->getId()) { |
|
450 | $loop_scope->loop_parent_context->vars_in_scope[$var_id] = Type::combineUnionTypes( |
||
451 | $loop_scope->loop_parent_context->vars_in_scope[$var_id], |
||
452 | $loop_scope->loop_context->vars_in_scope[$var_id] |
||
453 | ); |
||
454 | |||
455 | $loop_scope->loop_parent_context->removeVarFromConflictingClauses($var_id); |
||
456 | } |
||
457 | } |
||
458 | |||
459 | if (!$does_always_break) { |
||
460 | foreach ($loop_scope->loop_parent_context->vars_in_scope as $var_id => $type) { |
||
461 | if (!isset($inner_context->vars_in_scope[$var_id])) { |
||
462 | unset($loop_scope->loop_parent_context->vars_in_scope[$var_id]); |
||
463 | continue; |
||
464 | } |
||
465 | |||
466 | if ($inner_context->vars_in_scope[$var_id]->hasMixed()) { |
||
467 | $loop_scope->loop_parent_context->vars_in_scope[$var_id] = |
||
468 | $inner_context->vars_in_scope[$var_id]; |
||
469 | $loop_scope->loop_parent_context->removeVarFromConflictingClauses($var_id); |
||
470 | continue; |
||
471 | } |
||
472 | |||
473 | View Code Duplication | if ($inner_context->vars_in_scope[$var_id]->getId() !== $type->getId()) { |
|
474 | $loop_scope->loop_parent_context->vars_in_scope[$var_id] = Type::combineUnionTypes( |
||
475 | $loop_scope->loop_parent_context->vars_in_scope[$var_id], |
||
476 | $inner_context->vars_in_scope[$var_id] |
||
477 | ); |
||
478 | |||
479 | $loop_scope->loop_parent_context->removeVarFromConflictingClauses($var_id); |
||
480 | } |
||
481 | } |
||
482 | } |
||
483 | |||
484 | if ($pre_conditions && $pre_condition_clauses && !ScopeAnalyzer::doesEverBreak($stmts)) { |
||
485 | // if the loop contains an assertion and there are no break statements, we can negate that assertion |
||
486 | // and apply it to the current context |
||
487 | |||
488 | try { |
||
489 | $negated_pre_condition_clauses = Algebra::negateFormula(array_merge(...$pre_condition_clauses)); |
||
490 | } catch (\Psalm\Exception\ComplicatedExpressionException $e) { |
||
491 | $negated_pre_condition_clauses = []; |
||
492 | } |
||
493 | |||
494 | $negated_pre_condition_types = Algebra::getTruthsFromFormula($negated_pre_condition_clauses); |
||
495 | |||
496 | if ($negated_pre_condition_types) { |
||
497 | $changed_var_ids = []; |
||
498 | |||
499 | $vars_in_scope_reconciled = Reconciler::reconcileKeyedTypes( |
||
500 | $negated_pre_condition_types, |
||
501 | [], |
||
502 | $inner_context->vars_in_scope, |
||
503 | $changed_var_ids, |
||
504 | [], |
||
505 | $statements_analyzer, |
||
506 | [], |
||
507 | true, |
||
508 | new CodeLocation($statements_analyzer->getSource(), $pre_conditions[0]) |
||
509 | ); |
||
510 | |||
511 | foreach ($changed_var_ids as $var_id => $_) { |
||
512 | if (isset($vars_in_scope_reconciled[$var_id]) |
||
513 | && isset($loop_scope->loop_parent_context->vars_in_scope[$var_id]) |
||
514 | ) { |
||
515 | $loop_scope->loop_parent_context->vars_in_scope[$var_id] = $vars_in_scope_reconciled[$var_id]; |
||
516 | } |
||
517 | |||
518 | $loop_scope->loop_parent_context->removeVarFromConflictingClauses($var_id); |
||
519 | } |
||
520 | } |
||
521 | } |
||
522 | |||
523 | $loop_scope->loop_context->referenced_var_ids = array_merge( |
||
524 | array_intersect_key( |
||
525 | $inner_context->referenced_var_ids, |
||
526 | $pre_outer_context->vars_in_scope |
||
527 | ), |
||
528 | $loop_scope->loop_context->referenced_var_ids |
||
529 | ); |
||
530 | |||
531 | if ($codebase->find_unused_variables) { |
||
532 | foreach ($loop_scope->possibly_unreferenced_vars as $var_id => $locations) { |
||
533 | if (isset($inner_context->unreferenced_vars[$var_id])) { |
||
534 | $inner_context->unreferenced_vars[$var_id] += $locations; |
||
535 | } |
||
536 | } |
||
537 | |||
538 | foreach ($inner_context->unreferenced_vars as $var_id => $locations) { |
||
539 | if (!isset($new_referenced_var_ids[$var_id]) |
||
540 | || !isset($pre_outer_context->vars_in_scope[$var_id]) |
||
541 | || $does_always_break |
||
542 | ) { |
||
543 | if (!isset($loop_scope->loop_context->unreferenced_vars[$var_id])) { |
||
544 | $loop_scope->loop_context->unreferenced_vars[$var_id] = $locations; |
||
545 | } else { |
||
546 | $loop_scope->loop_context->unreferenced_vars[$var_id] += $locations; |
||
547 | } |
||
548 | } else { |
||
549 | $statements_analyzer->registerVariableUses($locations); |
||
550 | } |
||
551 | } |
||
552 | |||
553 | foreach ($loop_scope->unreferenced_vars as $var_id => $locations) { |
||
554 | View Code Duplication | if (isset($loop_scope->referenced_var_ids[$var_id])) { |
|
555 | $statements_analyzer->registerVariableUses($locations); |
||
556 | } else { |
||
557 | if (!isset($loop_scope->loop_context->unreferenced_vars[$var_id])) { |
||
558 | $loop_scope->loop_context->unreferenced_vars[$var_id] = $locations; |
||
559 | } else { |
||
560 | $loop_scope->loop_context->unreferenced_vars[$var_id] += $locations; |
||
561 | } |
||
562 | } |
||
563 | } |
||
564 | } |
||
565 | |||
566 | if ($always_enters_loop) { |
||
567 | foreach ($inner_context->vars_in_scope as $var_id => $type) { |
||
568 | // if there are break statements in the loop it's not certain |
||
569 | // that the loop has finished executing, so the assertions at the end |
||
570 | // the loop in the while conditional may not hold |
||
571 | if (in_array(ScopeAnalyzer::ACTION_BREAK, $loop_scope->final_actions, true) |
||
572 | || in_array(ScopeAnalyzer::ACTION_CONTINUE, $loop_scope->final_actions, true) |
||
573 | ) { |
||
574 | if (isset($loop_scope->possibly_defined_loop_parent_vars[$var_id])) { |
||
575 | $loop_scope->loop_parent_context->vars_in_scope[$var_id] = Type::combineUnionTypes( |
||
576 | $type, |
||
577 | $loop_scope->possibly_defined_loop_parent_vars[$var_id] |
||
578 | ); |
||
579 | } |
||
580 | } else { |
||
581 | if ($codebase->find_unused_variables |
||
582 | && !isset($loop_scope->loop_parent_context->vars_in_scope[$var_id]) |
||
583 | && isset($inner_context->unreferenced_vars[$var_id]) |
||
584 | ) { |
||
585 | $loop_scope->loop_parent_context->unreferenced_vars[$var_id] |
||
586 | = $inner_context->unreferenced_vars[$var_id]; |
||
587 | } |
||
588 | |||
589 | $loop_scope->loop_parent_context->vars_in_scope[$var_id] = $type; |
||
590 | } |
||
591 | } |
||
592 | } |
||
593 | |||
594 | if ($inner_do_context) { |
||
595 | $inner_context = $inner_do_context; |
||
596 | } |
||
597 | } |
||
598 | |||
774 |
This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.
Consider the following example. The parameter
$ireland
is not defined by the methodfinale(...)
.The most likely cause is that the parameter was changed, but the annotation was not.