MCPcopy Create free account
hub / github.com/PHPantom-dev/phpantom_lsp / process_for

Function process_for

src/completion/variable/forward_walk.rs:7048–7142  ·  view source on GitHub ↗

Process a `for` loop. Uses the same assignment-depth-bounded iteration as `process_foreach`: a cheap AST walk determines the dependency chain depth, then the body is re-walked up to that many times with fixed-point early exit.

(for_stmt: &'b For<'b>, scope: &mut ScopeState, ctx: &ForwardWalkCtx<'_>)

Source from the content-addressed store, hash-verified

7046/// a cheap AST walk determines the dependency chain depth, then the body
7047/// is re-walked up to that many times with fixed-point early exit.
7048fn process_for<'b>(for_stmt: &'b For<'b>, scope: &mut ScopeState, ctx: &ForwardWalkCtx<'_>) {
7049 let loop_depth = enter_loop();
7050
7051 // Hard limit: skip the body entirely at excessive nesting depth.
7052 if loop_depth > MAX_LOOP_DEPTH {
7053 leave_loop(loop_depth);
7054 return;
7055 }
7056
7057 // Process initializer expressions (e.g. `$i = 0`).
7058 for init_expr in for_stmt.initializations.iter() {
7059 process_assignment_expr(init_expr, scope, ctx);
7060 }
7061
7062 // Process condition assignments (e.g. `for (; $x = nextItem(); )`)
7063 // and pass-by-ref in conditions (e.g. `for (; preg_match(..., $m); )`).
7064 for cond_expr in for_stmt.conditions.iter() {
7065 process_condition_assignment(cond_expr, scope, ctx);
7066 seed_pass_by_ref_in_condition(cond_expr, scope, ctx);
7067 }
7068
7069 let pre_loop_scope = scope.clone();
7070
7071 // When the cursor is inside the loop body (completion path), discovery
7072 // passes must walk the ENTIRE body; the final pass uses the real
7073 // cursor_offset so it stops at the cursor as usual.
7074 let body_span = match &for_stmt.body {
7075 ForBody::Statement(inner) => inner.span(),
7076 ForBody::ColonDelimited(body) => body.span(),
7077 };
7078 let cursor_in_body =
7079 ctx.cursor_offset >= body_span.start.offset && ctx.cursor_offset <= body_span.end.offset;
7080 let discovery_ctx = if cursor_in_body && !is_diagnostic_scope_active() {
7081 ctx.with_cursor_offset(u32::MAX)
7082 } else {
7083 ctx.with_cursor_offset(ctx.cursor_offset)
7084 };
7085
7086 // ── Assignment-depth-bounded loop iteration ─────────────────
7087 let body_stmts: Vec<&Statement<'b>> = match &for_stmt.body {
7088 ForBody::Statement(inner) => vec![*inner],
7089 ForBody::ColonDelimited(body) => body.statements.iter().collect(),
7090 };
7091 let assignment_depth =
7092 clamp_iterations_for_depth(assignment_map_depth(&body_stmts), loop_depth);
7093
7094 // ── Initial walk (always performed) ─────────────────────────
7095 let initial_ctx = if assignment_depth > 1 {
7096 &discovery_ctx
7097 } else {
7098 ctx
7099 };
7100 match &for_stmt.body {
7101 ForBody::Statement(inner) => {
7102 walk_body_forward(std::iter::once(*inner), scope, initial_ctx);
7103 }
7104 ForBody::ColonDelimited(body) => {
7105 walk_body_forward(body.statements.iter(), scope, initial_ctx);

Callers 1

process_statementFunction · 0.85

Calls 14

enter_loopFunction · 0.85
leave_loopFunction · 0.85
process_assignment_exprFunction · 0.85
assignment_map_depthFunction · 0.85
walk_body_forwardFunction · 0.85
scope_has_changesFunction · 0.85
iterMethod · 0.80
cloneMethod · 0.80

Tested by

no test coverage detected