| 3066 | } |
| 3067 | |
| 3068 | static void kt_process_statement(KotlinLSPContext *ctx, TSNode stmt) { |
| 3069 | if (ts_node_is_null(stmt)) { |
| 3070 | return; |
| 3071 | } |
| 3072 | const char *kind = ts_node_type(stmt); |
| 3073 | /* Newer tree-sitter-kotlin wraps a body's statements in a `statements` |
| 3074 | * node (where older grammars used `block`/bare children). Unwrap either so |
| 3075 | * each real statement is bound + resolved in order. */ |
| 3076 | if (strcmp(kind, "statements") == 0 || strcmp(kind, "block") == 0) { |
| 3077 | kt_process_block_stmts(ctx, stmt); |
| 3078 | return; |
| 3079 | } |
| 3080 | if (strcmp(kind, "property_declaration") == 0) { |
| 3081 | kt_bind_property_to_scope(ctx, stmt); |
| 3082 | /* Resolve calls within initializer */ |
| 3083 | kt_resolve_calls_in_node(ctx, stmt); |
| 3084 | return; |
| 3085 | } |
| 3086 | if (strcmp(kind, "function_declaration") == 0) { |
| 3087 | /* Local function — register and recurse */ |
| 3088 | TSNode name = kt_field_named(stmt, "name"); |
| 3089 | if (ts_node_is_null(name)) { |
| 3090 | name = kt_child_kind_named(stmt, "simple_identifier"); |
| 3091 | } |
| 3092 | if (ts_node_is_null(name)) { |
| 3093 | name = kt_name_child(stmt); |
| 3094 | } |
| 3095 | char *fname = kt_node_text(ctx, name); |
| 3096 | if (!fname) { |
| 3097 | return; |
| 3098 | } |
| 3099 | /* Register the local fn so call sites in the enclosing scope |
| 3100 | * can resolve it via kotlin_resolve_function_name. The QN is |
| 3101 | * "<enclosing_func_qn>.<fname>" so it's distinct from a top-level |
| 3102 | * function with the same short name. */ |
| 3103 | const char *prev_func = ctx->enclosing_func_qn; |
| 3104 | const char *new_qn = kt_join_dot(ctx->arena, prev_func ? prev_func : ctx->module_qn, fname); |
| 3105 | { |
| 3106 | CBMRegisteredFunc lrf = {0}; |
| 3107 | lrf.qualified_name = new_qn; |
| 3108 | lrf.short_name = fname; |
| 3109 | lrf.min_params = 0; |
| 3110 | cbm_registry_add_func((CBMTypeRegistry *)ctx->registry, lrf); |
| 3111 | /* Also register a same-package alias so bare `inner()` calls |
| 3112 | * succeed via the same-package fallback in |
| 3113 | * kotlin_resolve_function_name. */ |
| 3114 | if (ctx->package_qn && *ctx->package_qn) { |
| 3115 | CBMRegisteredFunc alias = lrf; |
| 3116 | alias.qualified_name = kt_join_dot(ctx->arena, ctx->package_qn, fname); |
| 3117 | cbm_registry_add_func((CBMTypeRegistry *)ctx->registry, alias); |
| 3118 | } else { |
| 3119 | /* No package — register at root. */ |
| 3120 | CBMRegisteredFunc alias = lrf; |
| 3121 | alias.qualified_name = cbm_arena_strdup(ctx->arena, fname); |
| 3122 | cbm_registry_add_func((CBMTypeRegistry *)ctx->registry, alias); |
| 3123 | } |
| 3124 | } |
| 3125 | ctx->enclosing_func_qn = new_qn; |
no test coverage detected