diff --git a/crates/assists/src/handlers/generate_from_impl_for_enum.rs b/crates/assists/src/handlers/generate_from_impl_for_enum.rs index f6febd3aaa..d9388a7378 100644 --- a/crates/assists/src/handlers/generate_from_impl_for_enum.rs +++ b/crates/assists/src/handlers/generate_from_impl_for_enum.rs @@ -1,15 +1,9 @@ -use ast::GenericParamsOwner; use ide_db::helpers::FamousDefs; use ide_db::RootDatabase; -use itertools::Itertools; -use stdx::format_to; -use syntax::{ - ast::{self, AstNode, NameOwner}, - SmolStr, -}; +use syntax::ast::{self, AstNode, NameOwner}; use test_utils::mark; -use crate::{AssistContext, AssistId, AssistKind, Assists}; +use crate::{utils::generate_trait_impl_text, AssistContext, AssistId, AssistKind, Assists}; // Assist: generate_from_impl_for_enum // @@ -31,8 +25,7 @@ use crate::{AssistContext, AssistId, AssistKind, Assists}; pub(crate) fn generate_from_impl_for_enum(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { let variant = ctx.find_node_at_offset::()?; let variant_name = variant.name()?; - let enum_name = variant.parent_enum().name()?; - let enum_type_params = variant.parent_enum().generic_param_list(); + let enum_ = ast::Adt::Enum(variant.parent_enum()); let (field_name, field_type) = match variant.kind() { ast::StructKind::Tuple(field_list) => { if field_list.fields().count() != 1 { @@ -62,49 +55,27 @@ pub(crate) fn generate_from_impl_for_enum(acc: &mut Assists, ctx: &AssistContext target, |edit| { let start_offset = variant.parent_enum().syntax().text_range().end(); - let mut buf = String::from("\n\nimpl"); - if let Some(type_params) = &enum_type_params { - format_to!(buf, "{}", type_params.syntax()); - } - format_to!(buf, " From<{}> for {}", field_type.syntax(), enum_name); - if let Some(type_params) = enum_type_params { - let lifetime_params = type_params - .lifetime_params() - .filter_map(|it| it.lifetime()) - .map(|it| SmolStr::from(it.text())); - let type_params = type_params - .type_params() - .filter_map(|it| it.name()) - .map(|it| SmolStr::from(it.text())); - - let generic_params = lifetime_params.chain(type_params).format(", "); - format_to!(buf, "<{}>", generic_params) - } - if let Some(name) = field_name { - format_to!( - buf, - r#" {{ - fn from({0}: {1}) -> Self {{ + let from_trait = format!("From<{}>", field_type.syntax()); + let impl_code = if let Some(name) = field_name { + format!( + r#" fn from({0}: {1}) -> Self {{ Self::{2} {{ {0} }} - }} -}}"#, + }}"#, name.text(), field_type.syntax(), variant_name, - ); + ) } else { - format_to!( - buf, - r#" {{ - fn from(v: {}) -> Self {{ + format!( + r#" fn from(v: {}) -> Self {{ Self::{}(v) - }} -}}"#, + }}"#, field_type.syntax(), variant_name, - ); - } - edit.insert(start_offset, buf); + ) + }; + let from_impl = generate_trait_impl_text(&enum_, &from_trait, &impl_code); + edit.insert(start_offset, from_impl); }, ) } diff --git a/crates/assists/src/handlers/generate_impl.rs b/crates/assists/src/handlers/generate_impl.rs index 61d1bd25c1..050bcd4e29 100644 --- a/crates/assists/src/handlers/generate_impl.rs +++ b/crates/assists/src/handlers/generate_impl.rs @@ -1,11 +1,6 @@ -use itertools::Itertools; -use stdx::format_to; -use syntax::{ - ast::{self, AstNode, AttrsOwner, GenericParamsOwner, NameOwner}, - SmolStr, -}; +use syntax::ast::{self, AstNode, NameOwner}; -use crate::{AssistContext, AssistId, AssistKind, Assists}; +use crate::{utils::generate_impl_text, AssistContext, AssistId, AssistKind, Assists}; // Assist: generate_impl // @@ -36,44 +31,15 @@ pub(crate) fn generate_impl(acc: &mut Assists, ctx: &AssistContext) -> Option<() format!("Generate impl for `{}`", name), target, |edit| { - let type_params = nominal.generic_param_list(); let start_offset = nominal.syntax().text_range().end(); - let mut buf = String::new(); - buf.push_str("\n\n"); - nominal - .attrs() - .filter(|attr| { - attr.as_simple_call().map(|(name, _arg)| name == "cfg").unwrap_or(false) - }) - .for_each(|attr| buf.push_str(format!("{}\n", attr.to_string()).as_str())); - - buf.push_str("impl"); - if let Some(type_params) = &type_params { - format_to!(buf, "{}", type_params.syntax()); - } - buf.push_str(" "); - buf.push_str(name.text()); - if let Some(type_params) = type_params { - let lifetime_params = type_params - .lifetime_params() - .filter_map(|it| it.lifetime()) - .map(|it| SmolStr::from(it.text())); - let type_params = type_params - .type_params() - .filter_map(|it| it.name()) - .map(|it| SmolStr::from(it.text())); - - let generic_params = lifetime_params.chain(type_params).format(", "); - format_to!(buf, "<{}>", generic_params) - } match ctx.config.snippet_cap { Some(cap) => { - buf.push_str(" {\n $0\n}"); - edit.insert_snippet(cap, start_offset, buf); + let snippet = generate_impl_text(&nominal, " $0"); + edit.insert_snippet(cap, start_offset, snippet); } None => { - buf.push_str(" {\n}"); - edit.insert(start_offset, buf); + let snippet = generate_impl_text(&nominal, ""); + edit.insert(start_offset, snippet); } } }, diff --git a/crates/assists/src/handlers/replace_derive_with_manual_impl.rs b/crates/assists/src/handlers/replace_derive_with_manual_impl.rs index 6aa9d2f2c9..c69bc5cacd 100644 --- a/crates/assists/src/handlers/replace_derive_with_manual_impl.rs +++ b/crates/assists/src/handlers/replace_derive_with_manual_impl.rs @@ -2,8 +2,7 @@ use ide_db::helpers::mod_path_to_ast; use ide_db::imports_locator; use itertools::Itertools; use syntax::{ - ast::{self, make, AstNode}, - Direction, + ast::{self, make, AstNode, NameOwner}, SyntaxKind::{IDENT, WHITESPACE}, TextSize, }; @@ -11,7 +10,8 @@ use syntax::{ use crate::{ assist_context::{AssistBuilder, AssistContext, Assists}, utils::{ - add_trait_assoc_items_to_impl, filter_assoc_items, render_snippet, Cursor, DefaultMethods, + add_trait_assoc_items_to_impl, filter_assoc_items, generate_trait_impl_text, + render_snippet, Cursor, DefaultMethods, }, AssistId, AssistKind, }; @@ -57,8 +57,9 @@ pub(crate) fn replace_derive_with_manual_impl( let trait_token = ctx.token_at_offset().find(|t| t.kind() == IDENT && t.text() != "derive")?; let trait_path = make::path_unqualified(make::path_segment(make::name_ref(trait_token.text()))); - let annotated_name = attr.syntax().siblings(Direction::Next).find_map(ast::Name::cast)?; - let insert_pos = annotated_name.syntax().parent()?.text_range().end(); + let adt = attr.syntax().parent().and_then(ast::Adt::cast)?; + let annotated_name = adt.name()?; + let insert_pos = adt.syntax().text_range().end(); let current_module = ctx.sema.scope(annotated_name.syntax()).module()?; let current_crate = current_module.krate(); @@ -82,10 +83,10 @@ pub(crate) fn replace_derive_with_manual_impl( let mut no_traits_found = true; for (trait_path, trait_) in found_traits.inspect(|_| no_traits_found = false) { - add_assist(acc, ctx, &attr, &trait_path, Some(trait_), &annotated_name, insert_pos)?; + add_assist(acc, ctx, &attr, &trait_path, Some(trait_), &adt, &annotated_name, insert_pos)?; } if no_traits_found { - add_assist(acc, ctx, &attr, &trait_path, None, &annotated_name, insert_pos)?; + add_assist(acc, ctx, &attr, &trait_path, None, &adt, &annotated_name, insert_pos)?; } Some(()) } @@ -96,6 +97,7 @@ fn add_assist( attr: &ast::Attr, trait_path: &ast::Path, trait_: Option, + adt: &ast::Adt, annotated_name: &ast::Name, insert_pos: TextSize, ) -> Option<()> { @@ -112,15 +114,15 @@ fn add_assist( let impl_def_with_items = impl_def_from_trait(&ctx.sema, annotated_name, trait_, trait_path); update_attribute(builder, &input, &trait_name, &attr); + let trait_path = format!("{}", trait_path); match (ctx.config.snippet_cap, impl_def_with_items) { - (None, _) => builder.insert( - insert_pos, - format!("\n\nimpl {} for {} {{\n\n}}", trait_path, annotated_name), - ), + (None, _) => { + builder.insert(insert_pos, generate_trait_impl_text(adt, &trait_path, "")) + } (Some(cap), None) => builder.insert_snippet( cap, insert_pos, - format!("\n\nimpl {} for {} {{\n $0\n}}", trait_path, annotated_name), + generate_trait_impl_text(adt, &trait_path, " $0"), ), (Some(cap), Some((impl_def, first_assoc_item))) => { let mut cursor = Cursor::Before(first_assoc_item.syntax()); diff --git a/crates/assists/src/utils.rs b/crates/assists/src/utils.rs index 5dd32aef10..98c4462bbc 100644 --- a/crates/assists/src/utils.rs +++ b/crates/assists/src/utils.rs @@ -367,13 +367,31 @@ pub(crate) fn find_impl_block_end(impl_def: ast::Impl, buf: &mut String) -> Opti // Generates the surrounding `impl Type { }` including type and lifetime // parameters pub(crate) fn generate_impl_text(adt: &ast::Adt, code: &str) -> String { + generate_impl_text_inner(adt, None, code) +} + +// Generates the surrounding `impl for Type { }` including type +// and lifetime parameters +pub(crate) fn generate_trait_impl_text(adt: &ast::Adt, trait_text: &str, code: &str) -> String { + generate_impl_text_inner(adt, Some(trait_text), code) +} + +fn generate_impl_text_inner(adt: &ast::Adt, trait_text: Option<&str>, code: &str) -> String { let type_params = adt.generic_param_list(); let mut buf = String::with_capacity(code.len()); - buf.push_str("\n\nimpl"); + buf.push_str("\n\n"); + adt.attrs() + .filter(|attr| attr.as_simple_call().map(|(name, _arg)| name == "cfg").unwrap_or(false)) + .for_each(|attr| buf.push_str(format!("{}\n", attr.to_string()).as_str())); + buf.push_str("impl"); if let Some(type_params) = &type_params { format_to!(buf, "{}", type_params.syntax()); } buf.push(' '); + if let Some(trait_text) = trait_text { + buf.push_str(trait_text); + buf.push_str(" for "); + } buf.push_str(adt.name().unwrap().text()); if let Some(type_params) = type_params { let lifetime_params = type_params