| 1780 | // --- Process a single function body --- |
| 1781 | |
| 1782 | static void process_function(GoLSPContext* ctx, TSNode func_node) { |
| 1783 | // Set enclosing function QN |
| 1784 | TSNode name_node = ts_node_child_by_field_name(func_node, "name", 4); |
| 1785 | if (ts_node_is_null(name_node)) return; |
| 1786 | |
| 1787 | char* func_name = lsp_node_text(ctx, name_node); |
| 1788 | if (!func_name || !func_name[0]) return; |
| 1789 | |
| 1790 | // For methods, the enclosing-function QN must include the receiver type |
| 1791 | // (package.Type.Method), matching how the textual extractor and the |
| 1792 | // registry qualify the method. Building it as package.Method (no receiver) |
| 1793 | // here made the LSP-resolved call's caller_qn disagree with the textual |
| 1794 | // call's enclosing_func_qn, so cbm_pipeline_find_lsp_resolution never |
| 1795 | // joined them — every call inside a method body silently lost its |
| 1796 | // type-aware LSP strategy. Derive the bare receiver type name the same way |
| 1797 | // the receiver binding below does. |
| 1798 | char* recv_type_name = NULL; |
| 1799 | { |
| 1800 | TSNode recv0 = ts_node_child_by_field_name(func_node, "receiver", 8); |
| 1801 | if (!ts_node_is_null(recv0)) { |
| 1802 | uint32_t rnc0 = ts_node_child_count(recv0); |
| 1803 | for (uint32_t i = 0; i < rnc0 && !recv_type_name; i++) { |
| 1804 | TSNode rp = ts_node_child(recv0, i); |
| 1805 | if (ts_node_is_null(rp) || !ts_node_is_named(rp)) continue; |
| 1806 | if (strcmp(ts_node_type(rp), "parameter_declaration") != 0) continue; |
| 1807 | TSNode rtype = ts_node_child_by_field_name(rp, "type", 4); |
| 1808 | if (ts_node_is_null(rtype)) continue; |
| 1809 | // Unwrap a pointer receiver (*Type) to the bare type identifier. |
| 1810 | const char* rtk = ts_node_type(rtype); |
| 1811 | if (strcmp(rtk, "pointer_type") == 0 && ts_node_named_child_count(rtype) > 0) { |
| 1812 | rtype = ts_node_named_child(rtype, 0); |
| 1813 | } |
| 1814 | char* tn = lsp_node_text(ctx, rtype); |
| 1815 | if (tn && tn[0]) recv_type_name = tn; |
| 1816 | } |
| 1817 | } |
| 1818 | } |
| 1819 | |
| 1820 | if (recv_type_name) { |
| 1821 | ctx->enclosing_func_qn = |
| 1822 | cbm_arena_sprintf(ctx->arena, "%s.%s.%s", ctx->package_qn, recv_type_name, func_name); |
| 1823 | } else { |
| 1824 | ctx->enclosing_func_qn = cbm_arena_sprintf(ctx->arena, "%s.%s", ctx->package_qn, func_name); |
| 1825 | } |
| 1826 | |
| 1827 | // Push function scope |
| 1828 | CBMScope* saved_scope = ctx->current_scope; |
| 1829 | ctx->current_scope = cbm_scope_push(ctx->arena, ctx->current_scope); |
| 1830 | |
| 1831 | // Bind parameters into scope (including variadic) |
| 1832 | TSNode params = ts_node_child_by_field_name(func_node, "parameters", 10); |
| 1833 | if (!ts_node_is_null(params)) { |
| 1834 | uint32_t nc = ts_node_child_count(params); |
| 1835 | for (uint32_t i = 0; i < nc; i++) { |
| 1836 | TSNode param = ts_node_child(params, i); |
| 1837 | if (ts_node_is_null(param) || !ts_node_is_named(param)) continue; |
| 1838 | const char* pk = ts_node_type(param); |
| 1839 |
no test coverage detected