From 7aa70a86d14f46dd18d43493728b2efa8a5076fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felici=C3=A1n=20N=C3=A9meth?= Date: Sat, 15 Mar 2025 08:14:20 +0100 Subject: [PATCH] Speed up resolving "Generate delegate method" assist (part 1) Fix #19322 Sometimes there are 185 "Generate delegate" assists with the same assist_id and asssist_kind. This commit introduces and additional differentiator: assist_subtype. Therefore, when the LSP client sends an assist resolve request, rust-analyzer only need to compute edits for a single assist instead of 185. --- .../src/handlers/generate_delegate_methods.rs | 5 ++--- .../src/handlers/generate_delegate_trait.rs | 8 ++++++-- crates/ide-db/src/assists.rs | 8 ++++++-- crates/rust-analyzer/src/handlers/request.rs | 12 ++++++++++-- crates/rust-analyzer/src/lsp/to_proto.rs | 7 ++++++- 5 files changed, 30 insertions(+), 10 deletions(-) diff --git a/crates/ide-assists/src/handlers/generate_delegate_methods.rs b/crates/ide-assists/src/handlers/generate_delegate_methods.rs index 750f160ec2..4794bf541f 100644 --- a/crates/ide-assists/src/handlers/generate_delegate_methods.rs +++ b/crates/ide-assists/src/handlers/generate_delegate_methods.rs @@ -92,19 +92,18 @@ pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<' }); } methods.sort_by(|(a, _), (b, _)| a.cmp(b)); - for (name, method) in methods { + for (index, (name, method)) in methods.into_iter().enumerate() { let adt = ast::Adt::Struct(strukt.clone()); let name = name.display(ctx.db(), current_edition).to_string(); // if `find_struct_impl` returns None, that means that a function named `name` already exists. let Some(impl_def) = find_struct_impl(ctx, &adt, std::slice::from_ref(&name)) else { continue; }; - let field = make::ext::field_from_idents(["self", &field_name])?; acc.add_group( &GroupLabel("Generate delegate methods…".to_owned()), - AssistId("generate_delegate_methods", AssistKind::Generate), + AssistId("generate_delegate_methods", AssistKind::Generate, Some(index)), format!("Generate delegate for `{field_name}.{name}()`",), target, |edit| { diff --git a/crates/ide-assists/src/handlers/generate_delegate_trait.rs b/crates/ide-assists/src/handlers/generate_delegate_trait.rs index 5c39214617..53a06ba1c6 100644 --- a/crates/ide-assists/src/handlers/generate_delegate_trait.rs +++ b/crates/ide-assists/src/handlers/generate_delegate_trait.rs @@ -201,7 +201,7 @@ impl Struct { pub(crate) fn delegate(&self, field: Field, acc: &mut Assists, ctx: &AssistContext<'_>) { let db = ctx.db(); - for delegee in &field.impls { + for (index, delegee) in field.impls.iter().enumerate() { let trait_ = match delegee { Delegee::Bound(b) => b, Delegee::Impls(i, _) => i, @@ -229,7 +229,11 @@ impl Struct { acc.add_group( &GroupLabel(format!("Generate delegate trait impls for field `{}`", field.name)), - AssistId("generate_delegate_trait", ide_db::assists::AssistKind::Generate), + AssistId( + "generate_delegate_trait", + ide_db::assists::AssistKind::Generate, + Some(index), + ), format!("Generate delegate trait impl `{}` for `{}`", signature, field.name), field.range, |builder| { diff --git a/crates/ide-db/src/assists.rs b/crates/ide-db/src/assists.rs index 1c40685ebb..7868f6148e 100644 --- a/crates/ide-db/src/assists.rs +++ b/crates/ide-db/src/assists.rs @@ -105,7 +105,7 @@ impl FromStr for AssistKind { /// Unique identifier of the assist, should not be shown to the user /// directly. #[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct AssistId(pub &'static str, pub AssistKind); +pub struct AssistId(pub &'static str, pub AssistKind, pub Option); /// A way to control how many assist to resolve during the assist resolution. /// When an assist is resolved, its edits are calculated that might be costly to always do by default. @@ -128,6 +128,8 @@ pub struct SingleResolve { pub assist_id: String, // The kind of the assist. pub assist_kind: AssistKind, + /// Subtype of the assist. When many assists have the same id, it differentiates among them. + pub assist_subtype: Option, } impl AssistResolveStrategy { @@ -136,7 +138,9 @@ impl AssistResolveStrategy { AssistResolveStrategy::None => false, AssistResolveStrategy::All => true, AssistResolveStrategy::Single(single_resolve) => { - single_resolve.assist_id == id.0 && single_resolve.assist_kind == id.1 + single_resolve.assist_id == id.0 + && single_resolve.assist_kind == id.1 + && single_resolve.assist_subtype == id.2 } } } diff --git a/crates/rust-analyzer/src/handlers/request.rs b/crates/rust-analyzer/src/handlers/request.rs index ef1cc28d15..ec8b324aac 100644 --- a/crates/rust-analyzer/src/handlers/request.rs +++ b/crates/rust-analyzer/src/handlers/request.rs @@ -1568,13 +1568,21 @@ pub(crate) fn handle_code_action_resolve( fn parse_action_id(action_id: &str) -> anyhow::Result<(usize, SingleResolve), String> { let id_parts = action_id.split(':').collect::>(); match id_parts.as_slice() { - [assist_id_string, assist_kind_string, index_string] => { + [assist_id_string, assist_kind_string, index_string, subtype_str] => { let assist_kind: AssistKind = assist_kind_string.parse()?; let index: usize = match index_string.parse() { Ok(index) => index, Err(e) => return Err(format!("Incorrect index string: {e}")), }; - Ok((index, SingleResolve { assist_id: assist_id_string.to_string(), assist_kind })) + let assist_subtype = subtype_str.parse::().ok(); + Ok(( + index, + SingleResolve { + assist_id: assist_id_string.to_string(), + assist_kind, + assist_subtype, + }, + )) } _ => Err("Action id contains incorrect number of segments".to_owned()), } diff --git a/crates/rust-analyzer/src/lsp/to_proto.rs b/crates/rust-analyzer/src/lsp/to_proto.rs index 8ea2d46797..c30ee0fee1 100644 --- a/crates/rust-analyzer/src/lsp/to_proto.rs +++ b/crates/rust-analyzer/src/lsp/to_proto.rs @@ -1514,7 +1514,12 @@ pub(crate) fn code_action( (Some(it), _) => res.edit = Some(snippet_workspace_edit(snap, it)?), (None, Some((index, code_action_params, version))) => { res.data = Some(lsp_ext::CodeActionData { - id: format!("{}:{}:{index}", assist.id.0, assist.id.1.name()), + id: format!( + "{}:{}:{index}:{}", + assist.id.0, + assist.id.1.name(), + assist.id.2.map(|x| x.to_string()).unwrap_or("".to_owned()) + ), code_action_params, version, });