| 5135 | // ============================================================================ |
| 5136 | |
| 5137 | static void c_process_class(CLSPContext *ctx, TSNode class_node) { |
| 5138 | const char *saved_class = ctx->enclosing_class_qn; |
| 5139 | const char **saved_tpn = ctx->template_param_names; |
| 5140 | const CBMType **saved_tpd = ctx->template_param_defaults; |
| 5141 | int saved_tpc = ctx->template_param_count; |
| 5142 | |
| 5143 | char *class_name = NULL; |
| 5144 | TSNode name_node = ts_node_child_by_field_name(class_node, "name", 4); |
| 5145 | if (!ts_node_is_null(name_node)) { |
| 5146 | class_name = c_node_text(ctx, name_node); |
| 5147 | if (class_name) { |
| 5148 | const char *class_qn; |
| 5149 | if (ctx->current_namespace) { |
| 5150 | class_qn = |
| 5151 | cbm_arena_sprintf(ctx->arena, "%s.%s", ctx->current_namespace, class_name); |
| 5152 | } else if (ctx->module_qn) { |
| 5153 | class_qn = cbm_arena_sprintf(ctx->arena, "%s.%s", ctx->module_qn, class_name); |
| 5154 | } else { |
| 5155 | class_qn = class_name; |
| 5156 | } |
| 5157 | ctx->enclosing_class_qn = class_qn; |
| 5158 | |
| 5159 | // Store template param names on the registered type (for substitution) |
| 5160 | if (ctx->in_template && ctx->template_param_names && ctx->template_param_count > 0) { |
| 5161 | CBMRegisteredType *rt = NULL; |
| 5162 | for (int ri = 0; ri < ((CBMTypeRegistry *)ctx->registry)->type_count; ri++) { |
| 5163 | if (strcmp(((CBMTypeRegistry *)ctx->registry)->types[ri].qualified_name, |
| 5164 | class_qn) == 0) { |
| 5165 | rt = &((CBMTypeRegistry *)ctx->registry)->types[ri]; |
| 5166 | break; |
| 5167 | } |
| 5168 | } |
| 5169 | if (rt && !rt->type_param_names) { |
| 5170 | const char **tpn = (const char **)cbm_arena_alloc( |
| 5171 | ctx->arena, (ctx->template_param_count + 1) * sizeof(const char *)); |
| 5172 | for (int pi = 0; pi < ctx->template_param_count; pi++) |
| 5173 | tpn[pi] = ctx->template_param_names[pi]; |
| 5174 | tpn[ctx->template_param_count] = NULL; |
| 5175 | rt->type_param_names = tpn; |
| 5176 | } |
| 5177 | } |
| 5178 | } |
| 5179 | } |
| 5180 | |
| 5181 | // CRTP detection: class Derived : Base<Derived> |
| 5182 | // When a base class template argument matches the class name, |
| 5183 | // bind that template parameter to the derived class type. |
| 5184 | if (class_name && ctx->enclosing_class_qn) { |
| 5185 | // Walk base_class_clause children looking for template base classes |
| 5186 | uint32_t cnc = ts_node_named_child_count(class_node); |
| 5187 | for (uint32_t ci = 0; ci < cnc; ci++) { |
| 5188 | TSNode child = ts_node_named_child(class_node, ci); |
| 5189 | if (ts_node_is_null(child)) |
| 5190 | continue; |
| 5191 | const char *ck = ts_node_type(child); |
| 5192 | if (strcmp(ck, "base_class_clause") != 0) |
| 5193 | continue; |
| 5194 | // Iterate base specifiers |
no test coverage detected