Process a single function: bind parameters / `self`, then walk body. */
| 4984 | |
| 4985 | /* Process a single function: bind parameters / `self`, then walk body. */ |
| 4986 | static void rust_process_function(RustLSPContext *ctx, TSNode func_node, const char *parent_qn) { |
| 4987 | TSNode name_node = ts_node_child_by_field_name(func_node, "name", 4); |
| 4988 | if (ts_node_is_null(name_node)) |
| 4989 | return; |
| 4990 | char *name = rust_node_text(ctx, name_node); |
| 4991 | if (!name || !name[0]) |
| 4992 | return; |
| 4993 | |
| 4994 | const char *prefix = parent_qn ? parent_qn : ctx->module_qn; |
| 4995 | ctx->enclosing_func_qn = cbm_arena_sprintf(ctx->arena, "%s.%s", prefix, name); |
| 4996 | |
| 4997 | CBMScope *saved = ctx->current_scope; |
| 4998 | ctx->current_scope = cbm_scope_push(ctx->arena, ctx->current_scope); |
| 4999 | |
| 5000 | /* Chalk-lite: capture the active function's type-parameter bounds |
| 5001 | * and where-clause bounds into ctx so dispatch through generic |
| 5002 | * receivers can route via the bound trait. */ |
| 5003 | int saved_bound_count = ctx->type_param_bound_count; |
| 5004 | TSNode tp_list = ts_node_child_by_field_name(func_node, "type_parameters", 15); |
| 5005 | if (!ts_node_is_null(tp_list)) { |
| 5006 | char *tp_text = rust_node_text(ctx, tp_list); |
| 5007 | if (tp_text) |
| 5008 | rust_collect_bounds_from_text(ctx, tp_text); |
| 5009 | } |
| 5010 | TSNode where_clause = ts_node_child_by_field_name(func_node, "where_clause", 12); |
| 5011 | if (!ts_node_is_null(where_clause)) { |
| 5012 | char *wt = rust_node_text(ctx, where_clause); |
| 5013 | if (wt) |
| 5014 | rust_collect_bounds_from_text(ctx, wt); |
| 5015 | } |
| 5016 | |
| 5017 | /* Bind self for impl/trait methods. */ |
| 5018 | TSNode params = ts_node_child_by_field_name(func_node, "parameters", 10); |
| 5019 | if (!ts_node_is_null(params)) { |
| 5020 | uint32_t pc = ts_node_named_child_count(params); |
| 5021 | for (uint32_t i = 0; i < pc; i++) { |
| 5022 | TSNode p = ts_node_named_child(params, i); |
| 5023 | const char *pk = ts_node_type(p); |
| 5024 | if (strcmp(pk, "self_parameter") == 0) { |
| 5025 | if (ctx->self_type_qn) { |
| 5026 | /* Determine if &self / &mut self / self by reference. */ |
| 5027 | char *text = rust_node_text(ctx, p); |
| 5028 | const CBMType *self_t = cbm_type_named(ctx->arena, ctx->self_type_qn); |
| 5029 | if (text && strchr(text, '&')) { |
| 5030 | self_t = cbm_type_reference(ctx->arena, self_t); |
| 5031 | } |
| 5032 | cbm_scope_bind(ctx->current_scope, "self", self_t); |
| 5033 | } |
| 5034 | continue; |
| 5035 | } |
| 5036 | if (strcmp(pk, "parameter") == 0) { |
| 5037 | TSNode pat = ts_node_child_by_field_name(p, "pattern", 7); |
| 5038 | TSNode tn = ts_node_child_by_field_name(p, "type", 4); |
| 5039 | const CBMType *pt = |
| 5040 | ts_node_is_null(tn) ? cbm_type_unknown() : rust_parse_type_node(ctx, tn); |
| 5041 | if (!ts_node_is_null(pat)) |
| 5042 | rust_bind_pattern(ctx, pat, pt); |
| 5043 | } |
no test coverage detected