| 2794 | } |
| 2795 | |
| 2796 | static void kt_process_when_expression(KotlinLSPContext *ctx, TSNode node) { |
| 2797 | /* when (subject) { entries } — bind subject type as `it`-like? Actually |
| 2798 | * Kotlin's `when (x) { is Foo -> ... }` creates smart-cast on x. */ |
| 2799 | TSNode subject = kt_child_kind(node, "when_subject"); |
| 2800 | char *subject_name = NULL; |
| 2801 | const CBMType *subject_type = NULL; |
| 2802 | if (!ts_node_is_null(subject)) { |
| 2803 | /* when_subject: '(' expression ')' or '(' val name = expr ')' */ |
| 2804 | TSNode inner = ts_node_named_child(subject, 0); |
| 2805 | if (!ts_node_is_null(inner)) { |
| 2806 | subject_type = kotlin_eval_expr_type(ctx, inner); |
| 2807 | if (kt_node_is(inner, "identifier") || kt_node_is(inner, "simple_identifier")) { |
| 2808 | subject_name = kt_node_text(ctx, inner); |
| 2809 | } |
| 2810 | } |
| 2811 | } |
| 2812 | uint32_t nc = ts_node_named_child_count(node); |
| 2813 | for (uint32_t i = 0; i < nc; i++) { |
| 2814 | TSNode c = ts_node_named_child(node, i); |
| 2815 | if (!kt_node_is(c, "when_entry")) { |
| 2816 | continue; |
| 2817 | } |
| 2818 | ctx->current_scope = cbm_scope_push(ctx->arena, ctx->current_scope); |
| 2819 | /* Look for `is Type` conditions */ |
| 2820 | uint32_t en = ts_node_named_child_count(c); |
| 2821 | for (uint32_t e = 0; e < en; e++) { |
| 2822 | TSNode ec = ts_node_named_child(c, e); |
| 2823 | if (kt_node_is(ec, "_when_condition") || kt_node_is(ec, "when_condition") || |
| 2824 | kt_node_is(ec, "type_test")) { |
| 2825 | /* Find a 'type' node and apply smart-cast on subject_name */ |
| 2826 | TSNode tt = kt_find_descendant_kind(ec, "type", 3); |
| 2827 | if (ts_node_is_null(tt)) { |
| 2828 | tt = kt_find_descendant_kind(ec, "user_type", 3); |
| 2829 | } |
| 2830 | if (!ts_node_is_null(tt) && subject_name) { |
| 2831 | const CBMType *narrow = kotlin_parse_type_node(ctx, tt); |
| 2832 | if (!cbm_type_is_unknown(narrow)) { |
| 2833 | cbm_scope_bind(ctx->current_scope, |
| 2834 | cbm_arena_strdup(ctx->arena, subject_name), narrow); |
| 2835 | } |
| 2836 | } |
| 2837 | } |
| 2838 | } |
| 2839 | /* Process entry body */ |
| 2840 | if (en > 0) { |
| 2841 | TSNode body = ts_node_named_child(c, en - 1); |
| 2842 | if (kt_node_is(body, "block")) { |
| 2843 | kt_process_block_stmts(ctx, body); |
| 2844 | } else { |
| 2845 | kt_resolve_calls_in_node(ctx, body); |
| 2846 | kotlin_eval_expr_type(ctx, body); |
| 2847 | } |
| 2848 | } |
| 2849 | ctx->current_scope = cbm_scope_pop(ctx->current_scope); |
| 2850 | } |
| 2851 | (void)subject_type; |
| 2852 | } |
| 2853 |
no test coverage detected