Process an `if` statement with branch merging.
(
if_stmt: &'b If<'b>,
enclosing_stmt: &'b Statement<'b>,
scope: &mut ScopeState,
ctx: &ForwardWalkCtx<'_>,
)
| 5426 | |
| 5427 | /// Process an `if` statement with branch merging. |
| 5428 | fn process_if<'b>( |
| 5429 | if_stmt: &'b If<'b>, |
| 5430 | enclosing_stmt: &'b Statement<'b>, |
| 5431 | scope: &mut ScopeState, |
| 5432 | ctx: &ForwardWalkCtx<'_>, |
| 5433 | ) { |
| 5434 | // Record `&&` chain snapshots for the condition expression so that |
| 5435 | // member accesses after an instanceof/null guard within the condition |
| 5436 | // see the narrowed type. E.g. `if ($x !== null && $x->method())` |
| 5437 | // — the `$x->method()` span needs `$x` narrowed to non-null. |
| 5438 | record_and_chain_snapshots(if_stmt.condition, scope, ctx); |
| 5439 | |
| 5440 | // Check if the cursor is inside the condition expression. |
| 5441 | // If so, apply inline && narrowing. |
| 5442 | let cond_span = if_stmt.condition.span(); |
| 5443 | if ctx.cursor_offset >= cond_span.start.offset && ctx.cursor_offset <= cond_span.end.offset { |
| 5444 | // Cursor is in the condition — scope is already correct. |
| 5445 | return; |
| 5446 | } |
| 5447 | |
| 5448 | // Assignment in condition: `if ($x = expr())` |
| 5449 | process_condition_assignment(if_stmt.condition, scope, ctx); |
| 5450 | |
| 5451 | // Pass-by-reference in condition: `if (preg_match(..., $matches))` |
| 5452 | seed_pass_by_ref_in_condition(if_stmt.condition, scope, ctx); |
| 5453 | |
| 5454 | // Record a snapshot after condition processing so that variables |
| 5455 | // seeded by pass-by-reference (e.g. `$matches` from `preg_match`) |
| 5456 | // are visible in the then-body and elseif/else bodies. Without |
| 5457 | // this, the pre-statement snapshot (recorded by the outer |
| 5458 | // `walk_body_forward` before `process_if` runs) would be the |
| 5459 | // nearest floor entry, and it predates the seeding. |
| 5460 | if is_diagnostic_scope_active() { |
| 5461 | let body_start = match &if_stmt.body { |
| 5462 | IfBody::Statement(body) => body.statement.span().start.offset, |
| 5463 | IfBody::ColonDelimited(body) => body.colon.start.offset, |
| 5464 | }; |
| 5465 | record_scope_snapshot(body_start, scope); |
| 5466 | } |
| 5467 | |
| 5468 | match &if_stmt.body { |
| 5469 | IfBody::Statement(body) => { |
| 5470 | process_if_statement_body(if_stmt, body, enclosing_stmt, scope, ctx); |
| 5471 | } |
| 5472 | IfBody::ColonDelimited(body) => { |
| 5473 | process_if_colon_body(if_stmt, body, enclosing_stmt, scope, ctx); |
| 5474 | } |
| 5475 | } |
| 5476 | } |
| 5477 | |
| 5478 | /// Process if with statement body (brace-style). |
| 5479 | fn process_if_statement_body<'b>( |
no test coverage detected