Process a single function: bind parameters / `self`, then walk body. */
| 4230 | |
| 4231 | /* Process a single function: bind parameters / `self`, then walk body. */ |
| 4232 | static void rust_process_function(RustLSPContext *ctx, TSNode func_node, const char *parent_qn) { |
| 4233 | TSNode name_node = ts_node_child_by_field_name(func_node, "name", 4); |
| 4234 | if (ts_node_is_null(name_node)) |
| 4235 | return; |
| 4236 | char *name = rust_node_text(ctx, name_node); |
| 4237 | if (!name || !name[0]) |
| 4238 | return; |
| 4239 | |
| 4240 | const char *prefix = parent_qn ? parent_qn : ctx->module_qn; |
| 4241 | ctx->enclosing_func_qn = cbm_arena_sprintf(ctx->arena, "%s.%s", prefix, name); |
| 4242 | |
| 4243 | CBMScope *saved = ctx->current_scope; |
| 4244 | ctx->current_scope = cbm_scope_push(ctx->arena, ctx->current_scope); |
| 4245 | |
| 4246 | /* Chalk-lite: capture the active function's type-parameter bounds |
| 4247 | * and where-clause bounds into ctx so dispatch through generic |
| 4248 | * receivers can route via the bound trait. */ |
| 4249 | int saved_bound_count = ctx->type_param_bound_count; |
| 4250 | TSNode tp_list = ts_node_child_by_field_name(func_node, "type_parameters", 15); |
| 4251 | if (!ts_node_is_null(tp_list)) { |
| 4252 | char *tp_text = rust_node_text(ctx, tp_list); |
| 4253 | if (tp_text) |
| 4254 | rust_collect_bounds_from_text(ctx, tp_text); |
| 4255 | } |
| 4256 | TSNode where_clause = ts_node_child_by_field_name(func_node, "where_clause", 12); |
| 4257 | if (!ts_node_is_null(where_clause)) { |
| 4258 | char *wt = rust_node_text(ctx, where_clause); |
| 4259 | if (wt) |
| 4260 | rust_collect_bounds_from_text(ctx, wt); |
| 4261 | } |
| 4262 | |
| 4263 | /* Bind self for impl/trait methods. */ |
| 4264 | TSNode params = ts_node_child_by_field_name(func_node, "parameters", 10); |
| 4265 | if (!ts_node_is_null(params)) { |
| 4266 | uint32_t pc = ts_node_named_child_count(params); |
| 4267 | for (uint32_t i = 0; i < pc; i++) { |
| 4268 | TSNode p = ts_node_named_child(params, i); |
| 4269 | const char *pk = ts_node_type(p); |
| 4270 | if (strcmp(pk, "self_parameter") == 0) { |
| 4271 | if (ctx->self_type_qn) { |
| 4272 | /* Determine if &self / &mut self / self by reference. */ |
| 4273 | char *text = rust_node_text(ctx, p); |
| 4274 | const CBMType *self_t = cbm_type_named(ctx->arena, ctx->self_type_qn); |
| 4275 | if (text && strchr(text, '&')) { |
| 4276 | self_t = cbm_type_reference(ctx->arena, self_t); |
| 4277 | } |
| 4278 | cbm_scope_bind(ctx->current_scope, "self", self_t); |
| 4279 | } |
| 4280 | continue; |
| 4281 | } |
| 4282 | if (strcmp(pk, "parameter") == 0) { |
| 4283 | TSNode pat = ts_node_child_by_field_name(p, "pattern", 7); |
| 4284 | TSNode tn = ts_node_child_by_field_name(p, "type", 4); |
| 4285 | const CBMType *pt = |
| 4286 | ts_node_is_null(tn) ? cbm_type_unknown() : rust_parse_type_node(ctx, tn); |
| 4287 | if (!ts_node_is_null(pat)) |
| 4288 | rust_bind_pattern(ctx, pat, pt); |
| 4289 | } |
no test coverage detected