| 2605 | } |
| 2606 | |
| 2607 | void php_lsp_process_file(PHPLSPContext *ctx, TSNode root) { |
| 2608 | if (ts_node_is_null(root)) |
| 2609 | return; |
| 2610 | |
| 2611 | /* Pass 1: namespace + use declarations. */ |
| 2612 | // Collect top-level children once (O(n)); ts_node_child(root,i) is O(i) → O(n²). |
| 2613 | uint32_t kn = 0; |
| 2614 | TSNode *kids = cbm_lsp_collect_children(ctx->arena, root, &kn); |
| 2615 | for (uint32_t i = 0; i < kn; i++) { |
| 2616 | TSNode c = kids[i]; |
| 2617 | const char *k = ts_node_type(c); |
| 2618 | if (strcmp(k, "namespace_definition") == 0) { |
| 2619 | set_namespace_from_decl(ctx, c); |
| 2620 | } else if (strcmp(k, "namespace_use_declaration") == 0) { |
| 2621 | collect_use_declaration(ctx, c); |
| 2622 | } |
| 2623 | } |
| 2624 | |
| 2625 | /* Pass 2: process classes and top-level functions. */ |
| 2626 | for (uint32_t i = 0; i < kn; i++) { |
| 2627 | TSNode c = kids[i]; |
| 2628 | const char *k = ts_node_type(c); |
| 2629 | if (strcmp(k, "class_declaration") == 0 || strcmp(k, "trait_declaration") == 0 || |
| 2630 | strcmp(k, "interface_declaration") == 0 || strcmp(k, "enum_declaration") == 0) { |
| 2631 | process_class_decl(ctx, c); |
| 2632 | } else if (strcmp(k, "function_definition") == 0 || |
| 2633 | strcmp(k, "function_static_declaration") == 0) { |
| 2634 | process_function_like(ctx, c); |
| 2635 | } else if (strcmp(k, "namespace_definition") == 0) { |
| 2636 | /* Body-style: namespace App { ... }. Set namespace + collect |
| 2637 | * use clauses inside the block, then walk children. */ |
| 2638 | set_namespace_from_decl(ctx, c); |
| 2639 | /* Collect any namespace_use_declaration inside the block. */ |
| 2640 | uint32_t nc2 = ts_node_child_count(c); |
| 2641 | for (uint32_t i2 = 0; i2 < nc2; i2++) { |
| 2642 | TSNode ch = ts_node_child(c, i2); |
| 2643 | if (ts_node_is_null(ch) || !ts_node_is_named(ch)) |
| 2644 | continue; |
| 2645 | if (strcmp(ts_node_type(ch), "namespace_use_declaration") == 0) { |
| 2646 | collect_use_declaration(ctx, ch); |
| 2647 | } else if (strcmp(ts_node_type(ch), "declaration_list") == 0) { |
| 2648 | /* use clauses can also appear inside the declaration_list. */ |
| 2649 | uint32_t ncc = ts_node_child_count(ch); |
| 2650 | for (uint32_t k3 = 0; k3 < ncc; k3++) { |
| 2651 | TSNode cch = ts_node_child(ch, k3); |
| 2652 | if (ts_node_is_null(cch) || !ts_node_is_named(cch)) |
| 2653 | continue; |
| 2654 | if (strcmp(ts_node_type(cch), "namespace_use_declaration") == 0) { |
| 2655 | collect_use_declaration(ctx, cch); |
| 2656 | } |
| 2657 | } |
| 2658 | } |
| 2659 | } |
| 2660 | /* The body of `namespace App { ... }` may be a `declaration_list` |
| 2661 | * or a `compound_statement` depending on tree-sitter-php |
| 2662 | * version. Iterate ALL named children of the namespace and |
| 2663 | * dispatch any class/function/etc. seen at any depth. */ |
| 2664 | for (uint32_t j = 0; j < nc2; j++) { |
no test coverage detected