diff --git a/crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs b/crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs index d29a312eba5..813f662f10c 100644 --- a/crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs +++ b/crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs @@ -302,6 +302,71 @@ impl core::fmt::Debug for Foo { } } } +"#, + ) + } + + #[test] + fn add_custom_impl_debug_tuple_enum() { + check_assist( + replace_derive_with_manual_impl, + r#" +//- minicore: fmt +#[derive(Debu$0g)] +enum Foo { + Bar(usize, usize), + Baz, +} +"#, + r#" +enum Foo { + Bar(usize, usize), + Baz, +} + +impl core::fmt::Debug for Foo { + $0fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + Self::Bar(arg1, arg2) => f.debug_tuple("Bar").field(arg1).field(arg2).finish(), + Self::Baz => write!(f, "Baz"), + } + } +} +"#, + ) + } + #[test] + fn add_custom_impl_debug_record_enum() { + check_assist( + replace_derive_with_manual_impl, + r#" +//- minicore: fmt +#[derive(Debu$0g)] +enum Foo { + Bar { + baz: usize, + qux: usize, + }, + Baz, +} +"#, + r#" +enum Foo { + Bar { + baz: usize, + qux: usize, + }, + Baz, +} + +impl core::fmt::Debug for Foo { + $0fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + Self::Bar { baz, qux } => f.debug_struct("Bar").field("baz", baz).field("qux", qux).finish(), + Self::Baz => write!(f, "Baz"), + } + } +} "#, ) } diff --git a/crates/ide_assists/src/utils/gen_trait_fn_body.rs b/crates/ide_assists/src/utils/gen_trait_fn_body.rs index 5a8914b3316..54060c02a37 100644 --- a/crates/ide_assists/src/utils/gen_trait_fn_body.rs +++ b/crates/ide_assists/src/utils/gen_trait_fn_body.rs @@ -149,16 +149,60 @@ fn gen_debug_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> { let mut arms = vec![]; for variant in list.variants() { let name = variant.name()?; - let variant_name = - make::path_pat(make::ext::path_from_idents(["Self", &format!("{}", name)])?); - + let variant_name = make::ext::path_from_idents(["Self", &format!("{}", name)])?; let target = make::expr_path(make::ext::ident_path("f").into()); - let fmt_string = make::expr_literal(&(format!("\"{}\"", name))).into(); - let args = make::arg_list(vec![target, fmt_string]); - let macro_name = make::expr_path(make::ext::ident_path("write")); - let macro_call = make::expr_macro_call(macro_name, args); - arms.push(make::match_arm(Some(variant_name.into()), None, macro_call.into())); + match variant.field_list() { + Some(ast::FieldList::RecordFieldList(list)) => { + let mut pats = vec![]; + + // => f.debug_struct(name) + let target = make::expr_path(make::ext::ident_path("f")); + let method = make::name_ref("debug_struct"); + let struct_name = format!("\"{}\"", name); + let args = make::arg_list(Some(make::expr_literal(&struct_name).into())); + let mut expr = make::expr_method_call(target, method, args); + + for field in list.fields() { + let name = field.name()?; + + // => MyStruct { field_name } + let field_name = field.name()?; + let pat = make::ident_pat(false, false, field_name.clone()); + pats.push(pat.into()); + + // => .field("field_name", field) + let method_name = make::name_ref("field"); + let field_name = make::expr_literal(&(format!("\"{}\"", name))).into(); + let field_path = &format!("{}", name); + let field_path = make::expr_path(make::ext::ident_path(field_path)); + let args = make::arg_list(vec![field_name, field_path]); + expr = make::expr_method_call(expr, method_name, args); + } + + // => .finish() + let method = make::name_ref("finish"); + let expr = make::expr_method_call(expr, method, make::arg_list(None)); + + // => MyStruct { fields.. } => f.debug_struct()...finish(), + let pat = make::record_pat(variant_name.clone(), pats.into_iter()); + arms.push(make::match_arm(Some(pat.into()), None, expr)); + } + Some(ast::FieldList::TupleFieldList(_list)) => todo!(), + None => { + let fmt_string = make::expr_literal(&(format!("\"{}\"", name))).into(); + let args = make::arg_list(vec![target, fmt_string]); + let macro_name = make::expr_path(make::ext::ident_path("write")); + let macro_call = make::expr_macro_call(macro_name, args); + + let variant_name = make::path_pat(variant_name); + arms.push(make::match_arm( + Some(variant_name.into()), + None, + macro_call.into(), + )); + } + } } let match_target = make::expr_path(make::ext::ident_path("self"));