From b67378f53e23cbecd77d775fa51e5c3a864379df Mon Sep 17 00:00:00 2001 From: Yoshua Wuyts Date: Mon, 16 Aug 2021 12:58:06 +0200 Subject: [PATCH 1/3] fix debug record structs --- .../replace_derive_with_manual_impl.rs | 65 +++++++++++++++++++ .../src/utils/gen_trait_fn_body.rs | 60 ++++++++++++++--- 2 files changed, 117 insertions(+), 8 deletions(-) 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 d29a312eba..813f662f10 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 5a8914b331..54060c02a3 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")); From 9374d526da82a74c5d5f7d7b8cef97feb3104274 Mon Sep 17 00:00:00 2001 From: Yoshua Wuyts Date: Mon, 16 Aug 2021 17:39:08 +0200 Subject: [PATCH 2/3] fix debug tuple structs --- .../replace_derive_with_manual_impl.rs | 2 +- .../src/utils/gen_trait_fn_body.rs | 39 +++++++++++++++++-- 2 files changed, 37 insertions(+), 4 deletions(-) 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 813f662f10..d6319ea5c1 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 @@ -327,7 +327,7 @@ enum Foo { 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::Bar(arg0, arg1) => f.debug_tuple("Bar").field(arg0).field(arg1).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 54060c02a3..1c94138273 100644 --- a/crates/ide_assists/src/utils/gen_trait_fn_body.rs +++ b/crates/ide_assists/src/utils/gen_trait_fn_body.rs @@ -166,7 +166,7 @@ fn gen_debug_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> { for field in list.fields() { let name = field.name()?; - // => MyStruct { field_name } + // create a field pattern for use in `MyStruct { fields.. }` let field_name = field.name()?; let pat = make::ident_pat(false, false, field_name.clone()); pats.push(pat.into()); @@ -184,11 +184,44 @@ fn gen_debug_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> { let method = make::name_ref("finish"); let expr = make::expr_method_call(expr, method, make::arg_list(None)); - // => MyStruct { fields.. } => f.debug_struct()...finish(), + // => MyStruct { fields.. } => f.debug_struct("MyStruct")...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!(), + Some(ast::FieldList::TupleFieldList(list)) => { + let mut pats = vec![]; + + // => f.debug_tuple(name) + let target = make::expr_path(make::ext::ident_path("f")); + let method = make::name_ref("debug_tuple"); + 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 (i, _) in list.fields().enumerate() { + let name = format!("arg{}", i); + + // create a field pattern for use in `MyStruct(fields..)` + let field_name = make::name(&name); + let pat = make::ident_pat(false, false, field_name.clone()); + pats.push(pat.into()); + + // => .field(field) + let method_name = make::name_ref("field"); + let field_path = &format!("{}", name); + let field_path = make::expr_path(make::ext::ident_path(field_path)); + let args = make::arg_list(vec![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_tuple("MyStruct")...finish(), + let pat = make::tuple_struct_pat(variant_name.clone(), pats.into_iter()); + arms.push(make::match_arm(Some(pat.into()), None, expr)); + } None => { let fmt_string = make::expr_literal(&(format!("\"{}\"", name))).into(); let args = make::arg_list(vec![target, fmt_string]); From 067dc660ae3eef47549fe2531054ba942ac3fc91 Mon Sep 17 00:00:00 2001 From: Yoshua Wuyts Date: Mon, 16 Aug 2021 18:23:51 +0200 Subject: [PATCH 3/3] implement feedback from review --- .../src/utils/gen_trait_fn_body.rs | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) 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 1c94138273..b9c7da71b5 100644 --- a/crates/ide_assists/src/utils/gen_trait_fn_body.rs +++ b/crates/ide_assists/src/utils/gen_trait_fn_body.rs @@ -154,8 +154,6 @@ fn gen_debug_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> { 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"); @@ -163,20 +161,20 @@ fn gen_debug_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> { let args = make::arg_list(Some(make::expr_literal(&struct_name).into())); let mut expr = make::expr_method_call(target, method, args); + let mut pats = vec![]; for field in list.fields() { - let name = field.name()?; + let field_name = field.name()?; // create a field pattern for use in `MyStruct { fields.. }` - 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]); + let name = make::expr_literal(&(format!("\"{}\"", field_name))).into(); + let path = &format!("{}", field_name); + let path = make::expr_path(make::ext::ident_path(path)); + let args = make::arg_list(vec![name, path]); expr = make::expr_method_call(expr, method_name, args); } @@ -189,8 +187,6 @@ fn gen_debug_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> { arms.push(make::match_arm(Some(pat.into()), None, expr)); } Some(ast::FieldList::TupleFieldList(list)) => { - let mut pats = vec![]; - // => f.debug_tuple(name) let target = make::expr_path(make::ext::ident_path("f")); let method = make::name_ref("debug_tuple"); @@ -198,6 +194,7 @@ fn gen_debug_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> { let args = make::arg_list(Some(make::expr_literal(&struct_name).into())); let mut expr = make::expr_method_call(target, method, args); + let mut pats = vec![]; for (i, _) in list.fields().enumerate() { let name = format!("arg{}", i); @@ -224,7 +221,7 @@ fn gen_debug_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> { } None => { let fmt_string = make::expr_literal(&(format!("\"{}\"", name))).into(); - let args = make::arg_list(vec![target, fmt_string]); + let args = make::arg_list([target, fmt_string]); let macro_name = make::expr_path(make::ext::ident_path("write")); let macro_call = make::expr_macro_call(macro_name, args); @@ -267,7 +264,7 @@ fn gen_debug_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> { let f_path = make::expr_path(make::ext::ident_path("self")); let f_path = make::expr_ref(f_path, false); let f_path = make::expr_field(f_path, &format!("{}", name)).into(); - let args = make::arg_list(vec![f_name, f_path]); + let args = make::arg_list([f_name, f_path]); expr = make::expr_method_call(expr, make::name_ref("field"), args); } expr