| 3273 | } |
| 3274 | |
| 3275 | static void py_process_function(PyLSPContext *ctx, TSNode func_node, const char *container_qn) { |
| 3276 | TSNode name_node = ts_node_child_by_field_name(func_node, "name", 4); |
| 3277 | if (ts_node_is_null(name_node)) |
| 3278 | return; |
| 3279 | char *fname = py_node_text(ctx, name_node); |
| 3280 | if (!fname || !fname[0]) |
| 3281 | return; |
| 3282 | |
| 3283 | const char *prev_func = ctx->enclosing_func_qn; |
| 3284 | const char *base_qn = container_qn ? container_qn : ctx->module_qn; |
| 3285 | ctx->enclosing_func_qn = cbm_arena_sprintf(ctx->arena, "%s.%s", base_qn, fname); |
| 3286 | |
| 3287 | CBMScope *saved = ctx->current_scope; |
| 3288 | ctx->current_scope = cbm_scope_push(ctx->arena, ctx->current_scope); |
| 3289 | |
| 3290 | TSNode params = ts_node_child_by_field_name(func_node, "parameters", 10); |
| 3291 | py_bind_parameters(ctx, params); |
| 3292 | |
| 3293 | // For methods, bind `self`/`cls` AFTER param walk so the receiver type |
| 3294 | // wins over the unannotated `self` / `cls` parameter declaration. |
| 3295 | if (ctx->enclosing_class_qn) { |
| 3296 | py_scope_bind(ctx, "self", |
| 3297 | cbm_type_named(ctx->arena, ctx->enclosing_class_qn)); |
| 3298 | py_scope_bind(ctx, "cls", |
| 3299 | cbm_type_named(ctx->arena, ctx->enclosing_class_qn)); |
| 3300 | } |
| 3301 | |
| 3302 | TSNode body = ts_node_child_by_field_name(func_node, "body", 4); |
| 3303 | if (!ts_node_is_null(body)) { |
| 3304 | py_resolve_calls_in(ctx, body); |
| 3305 | // Also descend into nested function/class definitions in the body. |
| 3306 | uint32_t bnc = ts_node_named_child_count(body); |
| 3307 | for (uint32_t i = 0; i < bnc; i++) { |
| 3308 | TSNode c = ts_node_named_child(body, i); |
| 3309 | const char *ck = ts_node_type(c); |
| 3310 | if (strcmp(ck, "function_definition") == 0) { |
| 3311 | py_process_function(ctx, c, ctx->enclosing_func_qn); |
| 3312 | } else if (strcmp(ck, "decorated_definition") == 0) { |
| 3313 | TSNode def = ts_node_child_by_field_name(c, "definition", 10); |
| 3314 | if (!ts_node_is_null(def) && |
| 3315 | strcmp(ts_node_type(def), "function_definition") == 0) { |
| 3316 | py_process_function(ctx, def, ctx->enclosing_func_qn); |
| 3317 | } |
| 3318 | } |
| 3319 | } |
| 3320 | } |
| 3321 | |
| 3322 | py_scope_restore(ctx, saved); |
| 3323 | ctx->enclosing_func_qn = prev_func; |
| 3324 | } |
| 3325 | |
| 3326 | /* Return true iff func_node's name is __init__ or __post_init__. */ |
| 3327 | static bool py_is_init_method(PyLSPContext *ctx, TSNode func_node) { |
no test coverage detected