| 2727 | } |
| 2728 | |
| 2729 | static void process_node(TSLSPContext *ctx, TSNode node) { |
| 2730 | if (!ctx || ts_node_is_null(node)) |
| 2731 | return; |
| 2732 | const char *kind = ts_node_type(node); |
| 2733 | |
| 2734 | // Scope-affecting statements bind first, then we recurse. |
| 2735 | ts_process_statement(ctx, node); |
| 2736 | |
| 2737 | if (strcmp(kind, "call_expression") == 0) { |
| 2738 | resolve_call_at(ctx, node); |
| 2739 | |
| 2740 | // Contextual callback typing: when an arg is an arrow_function and the |
| 2741 | // corresponding param of the called function is itself a FUNC, propagate the |
| 2742 | // expected callback param types into the arrow's body before walking it. |
| 2743 | // Handle arg processing manually for this path to avoid double-walking via |
| 2744 | // default recurse below. |
| 2745 | do { |
| 2746 | TSNode fn_node = |
| 2747 | ts_node_child_by_field_name(node, "function", TS_LSP_FIELD_LEN("function")); |
| 2748 | if (ts_node_is_null(fn_node)) |
| 2749 | break; |
| 2750 | const CBMType *fn_type = ts_eval_expr_type(ctx, fn_node); |
| 2751 | if (!fn_type || fn_type->kind != CBM_TYPE_FUNC) |
| 2752 | break; |
| 2753 | if (!fn_type->data.func.param_types) |
| 2754 | break; |
| 2755 | TSNode args = |
| 2756 | ts_node_child_by_field_name(node, "arguments", TS_LSP_FIELD_LEN("arguments")); |
| 2757 | if (ts_node_is_null(args)) |
| 2758 | break; |
| 2759 | |
| 2760 | // Process the function child for nested call resolution. |
| 2761 | process_node(ctx, fn_node); |
| 2762 | |
| 2763 | // param_types is NULL-terminated (no count field). Measure its |
| 2764 | // length so we never index past the terminator: a call may pass |
| 2765 | // more args than the function declares params (e.g. excess/variadic |
| 2766 | // args), and the extra args simply have no expected type. Indexing |
| 2767 | // param_types[i] by the raw arg count read out of bounds → garbage |
| 2768 | // CBMType* → crash on expected->kind. |
| 2769 | uint32_t param_count = 0; |
| 2770 | while (fn_type->data.func.param_types[param_count]) |
| 2771 | param_count++; |
| 2772 | |
| 2773 | uint32_t argc = ts_node_named_child_count(args); |
| 2774 | for (uint32_t i = 0; i < argc; i++) { |
| 2775 | TSNode arg = ts_node_named_child(args, i); |
| 2776 | if (ts_node_is_null(arg)) |
| 2777 | continue; |
| 2778 | const char *ak = ts_node_type(arg); |
| 2779 | const CBMType *expected = |
| 2780 | (i < param_count) ? fn_type->data.func.param_types[i] : NULL; |
| 2781 | if ((strcmp(ak, "arrow_function") == 0 || strcmp(ak, "function_expression") == 0) && |
| 2782 | expected && expected->kind == CBM_TYPE_FUNC) { |
| 2783 | process_callback_arrow(ctx, arg, expected); |
| 2784 | } else { |
| 2785 | process_node(ctx, arg); |
| 2786 | } |
no test coverage detected