| 2811 | } |
| 2812 | |
| 2813 | void php_lsp_process_file(PHPLSPContext *ctx, TSNode root) { |
| 2814 | if (ts_node_is_null(root)) |
| 2815 | return; |
| 2816 | |
| 2817 | /* Pass 1: namespace + use declarations. */ |
| 2818 | // Collect top-level children once (O(n)); ts_node_child(root,i) is O(i) → O(n²). |
| 2819 | uint32_t kn = 0; |
| 2820 | TSNode *kids = cbm_lsp_collect_children(ctx->arena, root, &kn); |
| 2821 | for (uint32_t i = 0; i < kn; i++) { |
| 2822 | TSNode c = kids[i]; |
| 2823 | const char *k = ts_node_type(c); |
| 2824 | if (strcmp(k, "namespace_definition") == 0) { |
| 2825 | set_namespace_from_decl(ctx, c); |
| 2826 | } else if (strcmp(k, "namespace_use_declaration") == 0) { |
| 2827 | collect_use_declaration(ctx, c); |
| 2828 | } |
| 2829 | } |
| 2830 | |
| 2831 | /* Pass 2: process classes and top-level functions. */ |
| 2832 | for (uint32_t i = 0; i < kn; i++) { |
| 2833 | TSNode c = kids[i]; |
| 2834 | const char *k = ts_node_type(c); |
| 2835 | if (strcmp(k, "class_declaration") == 0 || strcmp(k, "trait_declaration") == 0 || |
| 2836 | strcmp(k, "interface_declaration") == 0 || strcmp(k, "enum_declaration") == 0) { |
| 2837 | process_class_decl(ctx, c); |
| 2838 | } else if (strcmp(k, "function_definition") == 0 || |
| 2839 | strcmp(k, "function_static_declaration") == 0) { |
| 2840 | process_function_like(ctx, c); |
| 2841 | } else if (strcmp(k, "namespace_definition") == 0) { |
| 2842 | /* Body-style: namespace App { ... }. Set namespace + collect |
| 2843 | * use clauses inside the block, then walk children. */ |
| 2844 | set_namespace_from_decl(ctx, c); |
| 2845 | /* Collect any namespace_use_declaration inside the block. */ |
| 2846 | uint32_t nc2 = ts_node_child_count(c); |
| 2847 | for (uint32_t i2 = 0; i2 < nc2; i2++) { |
| 2848 | TSNode ch = ts_node_child(c, i2); |
| 2849 | if (ts_node_is_null(ch) || !ts_node_is_named(ch)) |
| 2850 | continue; |
| 2851 | if (strcmp(ts_node_type(ch), "namespace_use_declaration") == 0) { |
| 2852 | collect_use_declaration(ctx, ch); |
| 2853 | } else if (strcmp(ts_node_type(ch), "declaration_list") == 0) { |
| 2854 | /* use clauses can also appear inside the declaration_list. */ |
| 2855 | uint32_t ncc = ts_node_child_count(ch); |
| 2856 | for (uint32_t k3 = 0; k3 < ncc; k3++) { |
| 2857 | TSNode cch = ts_node_child(ch, k3); |
| 2858 | if (ts_node_is_null(cch) || !ts_node_is_named(cch)) |
| 2859 | continue; |
| 2860 | if (strcmp(ts_node_type(cch), "namespace_use_declaration") == 0) { |
| 2861 | collect_use_declaration(ctx, cch); |
| 2862 | } |
| 2863 | } |
| 2864 | } |
| 2865 | } |
| 2866 | /* The body of `namespace App { ... }` may be a `declaration_list` |
| 2867 | * or a `compound_statement` depending on tree-sitter-php |
| 2868 | * version. Iterate ALL named children of the namespace and |
| 2869 | * dispatch any class/function/etc. seen at any depth. */ |
| 2870 | for (uint32_t j = 0; j < nc2; j++) { |
no test coverage detected