| 4485 | } |
| 4486 | |
| 4487 | static void rust_process_impl(RustLSPContext *ctx, TSNode impl_node) { |
| 4488 | TSNode type_node = ts_node_child_by_field_name(impl_node, "type", 4); |
| 4489 | if (ts_node_is_null(type_node)) |
| 4490 | return; |
| 4491 | char *type_text = rust_node_text(ctx, type_node); |
| 4492 | if (!type_text) |
| 4493 | return; |
| 4494 | |
| 4495 | /* Detect blanket impl: `impl<T: Trait> ForeignTrait for T { ... }` |
| 4496 | * where type_text is a name that appears in the impl's type |
| 4497 | * parameters. In that case the receiver isn't a concrete type — it's |
| 4498 | * any T satisfying the bound. We register the methods on the trait |
| 4499 | * QN itself so dispatch through T: Trait finds them. */ |
| 4500 | TSNode trait_node = ts_node_child_by_field_name(impl_node, "trait", 5); |
| 4501 | bool is_blanket = |
| 4502 | !ts_node_is_null(trait_node) && rust_impl_has_type_param(ctx, impl_node, type_text); |
| 4503 | const char *effective_recv = NULL; |
| 4504 | |
| 4505 | if (is_blanket) { |
| 4506 | char *tt = rust_node_text(ctx, trait_node); |
| 4507 | if (tt) |
| 4508 | effective_recv = rust_resolve_path_expr(ctx, tt); |
| 4509 | } else { |
| 4510 | effective_recv = rust_resolve_path_expr(ctx, type_text); |
| 4511 | } |
| 4512 | if (!effective_recv) |
| 4513 | return; |
| 4514 | |
| 4515 | const char *saved_self = ctx->self_type_qn; |
| 4516 | const char *saved_trait = ctx->self_trait_qn; |
| 4517 | ctx->self_type_qn = effective_recv; |
| 4518 | ctx->self_trait_qn = NULL; |
| 4519 | |
| 4520 | if (!ts_node_is_null(trait_node) && !is_blanket) { |
| 4521 | char *tt = rust_node_text(ctx, trait_node); |
| 4522 | if (tt) |
| 4523 | ctx->self_trait_qn = rust_resolve_path_expr(ctx, tt); |
| 4524 | } |
| 4525 | |
| 4526 | TSNode body = ts_node_child_by_field_name(impl_node, "body", 4); |
| 4527 | if (!ts_node_is_null(body)) { |
| 4528 | uint32_t nc = ts_node_child_count(body); |
| 4529 | for (uint32_t i = 0; i < nc; i++) { |
| 4530 | TSNode c = ts_node_child(body, i); |
| 4531 | if (ts_node_is_null(c) || !ts_node_is_named(c)) |
| 4532 | continue; |
| 4533 | const char *ck = ts_node_type(c); |
| 4534 | if (strcmp(ck, "function_item") == 0) { |
| 4535 | rust_process_function(ctx, c, effective_recv); |
| 4536 | } |
| 4537 | } |
| 4538 | } |
| 4539 | |
| 4540 | ctx->self_type_qn = saved_self; |
| 4541 | ctx->self_trait_qn = saved_trait; |
| 4542 | } |
| 4543 | |
| 4544 | void rust_lsp_process_file(RustLSPContext *ctx, TSNode root) { |
no test coverage detected