MCPcopy Create free account
hub / github.com/DeusData/codebase-memory-mcp / process_foreach

Function process_foreach

internal/cbm/lsp/php_lsp.c:1457–1553  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

1455}
1456
1457static void process_foreach(PHPLSPContext *ctx, TSNode node) {
1458 /* Try to extract the iterable expression's element type. tree-sitter-php
1459 * emits the iterable as the first sibling expression after `foreach (`,
1460 * and the loop var is the variable_name child after `as`.
1461 *
1462 * Element-type resolution rules:
1463 * - iterable is array<T> / list<T> / iterable<T> (TEMPLATE) → T
1464 * - iterable is array<K, V> (TEMPLATE arg_count=2) → V (value)
1465 * - iterable is a NAMED collection-like type whose `current()` method
1466 * has a known return type (e.g. Iterator) → that
1467 * - otherwise → UNKNOWN
1468 */
1469 TSNode iterable;
1470 memset(&iterable, 0, sizeof(iterable));
1471 TSNode loop_vars[4];
1472 int loop_var_count = 0;
1473 memset(loop_vars, 0, sizeof(loop_vars));
1474
1475 /* tree-sitter-php emits foreach_statement children in source order:
1476 * <iterable expression> ... `as` ... <loop var(s)> ... <body>
1477 * The iterable can be ANY expression: variable_name, member_call,
1478 * function_call_expression, member_access_expression, etc. The loop
1479 * vars are always variable_name. The body is compound_statement /
1480 * colon_block / a statement.
1481 *
1482 * We find the iterable as the first named child whose kind is an
1483 * expression-shape; subsequent variable_name children before the body
1484 * are the loop vars. */
1485 uint32_t nc = ts_node_child_count(node);
1486 for (uint32_t i = 0; i < nc; i++) {
1487 TSNode c = ts_node_child(node, i);
1488 if (ts_node_is_null(c) || !ts_node_is_named(c))
1489 continue;
1490 const char *k = ts_node_type(c);
1491 if (strcmp(k, "compound_statement") == 0 || strcmp(k, "colon_block") == 0 ||
1492 strcmp(k, "expression_statement") == 0 || strcmp(k, "echo_statement") == 0 ||
1493 strcmp(k, "return_statement") == 0 || strcmp(k, "if_statement") == 0 ||
1494 strcmp(k, "for_statement") == 0 || strcmp(k, "while_statement") == 0 ||
1495 strcmp(k, "switch_statement") == 0 || strcmp(k, "try_statement") == 0) {
1496 break; /* reached body */
1497 }
1498 if (ts_node_is_null(iterable)) {
1499 iterable = c;
1500 } else if (strcmp(k, "variable_name") == 0 && loop_var_count < 4) {
1501 loop_vars[loop_var_count++] = c;
1502 } else if (strcmp(k, "pair") == 0) {
1503 /* `$k => $v` — extract both variable_names; the second is the
1504 * value, gets the elem_type. */
1505 uint32_t pnc = ts_node_child_count(c);
1506 for (uint32_t j = 0; j < pnc; j++) {
1507 TSNode pc = ts_node_child(c, j);
1508 if (!ts_node_is_null(pc) && ts_node_is_named(pc) &&
1509 strcmp(ts_node_type(pc), "variable_name") == 0 && loop_var_count < 4) {
1510 loop_vars[loop_var_count++] = pc;
1511 }
1512 }
1513 }
1514 }

Callers 1

Calls 5

cbm_type_unknownFunction · 0.85
php_eval_expr_typeFunction · 0.85
php_lookup_methodFunction · 0.85
php_node_textFunction · 0.85
cbm_scope_bindFunction · 0.85

Tested by

no test coverage detected