| 5239 | } |
| 5240 | |
| 5241 | static void rust_process_impl(RustLSPContext *ctx, TSNode impl_node) { |
| 5242 | TSNode type_node = ts_node_child_by_field_name(impl_node, "type", 4); |
| 5243 | if (ts_node_is_null(type_node)) |
| 5244 | return; |
| 5245 | char *type_text = rust_node_text(ctx, type_node); |
| 5246 | if (!type_text) |
| 5247 | return; |
| 5248 | |
| 5249 | /* Detect blanket impl: `impl<T: Trait> ForeignTrait for T { ... }` |
| 5250 | * where type_text is a name that appears in the impl's type |
| 5251 | * parameters. In that case the receiver isn't a concrete type — it's |
| 5252 | * any T satisfying the bound. We register the methods on the trait |
| 5253 | * QN itself so dispatch through T: Trait finds them. */ |
| 5254 | TSNode trait_node = ts_node_child_by_field_name(impl_node, "trait", 5); |
| 5255 | bool is_blanket = |
| 5256 | !ts_node_is_null(trait_node) && rust_impl_has_type_param(ctx, impl_node, type_text); |
| 5257 | const char *effective_recv = NULL; |
| 5258 | |
| 5259 | if (is_blanket) { |
| 5260 | char *tt = rust_node_text(ctx, trait_node); |
| 5261 | if (tt) |
| 5262 | effective_recv = rust_resolve_path_expr(ctx, tt); |
| 5263 | } else { |
| 5264 | effective_recv = rust_resolve_path_expr(ctx, type_text); |
| 5265 | } |
| 5266 | if (!effective_recv) |
| 5267 | return; |
| 5268 | |
| 5269 | const char *saved_self = ctx->self_type_qn; |
| 5270 | const char *saved_trait = ctx->self_trait_qn; |
| 5271 | ctx->self_type_qn = effective_recv; |
| 5272 | ctx->self_trait_qn = NULL; |
| 5273 | |
| 5274 | if (!ts_node_is_null(trait_node) && !is_blanket) { |
| 5275 | char *tt = rust_node_text(ctx, trait_node); |
| 5276 | if (tt) |
| 5277 | ctx->self_trait_qn = rust_resolve_path_expr(ctx, tt); |
| 5278 | } |
| 5279 | |
| 5280 | TSNode body = ts_node_child_by_field_name(impl_node, "body", 4); |
| 5281 | if (!ts_node_is_null(body)) { |
| 5282 | uint32_t nc = ts_node_child_count(body); |
| 5283 | for (uint32_t i = 0; i < nc; i++) { |
| 5284 | TSNode c = ts_node_child(body, i); |
| 5285 | if (ts_node_is_null(c) || !ts_node_is_named(c)) |
| 5286 | continue; |
| 5287 | const char *ck = ts_node_type(c); |
| 5288 | if (strcmp(ck, "function_item") == 0) { |
| 5289 | rust_process_function(ctx, c, effective_recv); |
| 5290 | } |
| 5291 | } |
| 5292 | } |
| 5293 | |
| 5294 | ctx->self_type_qn = saved_self; |
| 5295 | ctx->self_trait_qn = saved_trait; |
| 5296 | } |
| 5297 | |
| 5298 | void rust_lsp_process_file(RustLSPContext *ctx, TSNode root) { |
no test coverage detected