9924: Fix gen debug for enums r=yoshuawuyts a=yoshuawuyts

Closes https://github.com/rust-analyzer/rust-analyzer/issues/9914. Thanks!

r? `@Veykril` 

Co-authored-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
This commit is contained in:
bors[bot] 2021-08-16 16:25:57 +00:00 committed by GitHub
commit bae22f9507
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 148 additions and 9 deletions

View file

@ -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(arg0, arg1) => f.debug_tuple("Bar").field(arg0).field(arg1).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"),
}
}
}
"#, "#,
) )
} }

View file

@ -149,16 +149,90 @@ fn gen_debug_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
let mut arms = vec![]; let mut arms = vec![];
for variant in list.variants() { for variant in list.variants() {
let name = variant.name()?; let name = variant.name()?;
let variant_name = let variant_name = make::ext::path_from_idents(["Self", &format!("{}", name)])?;
make::path_pat(make::ext::path_from_idents(["Self", &format!("{}", name)])?);
let target = make::expr_path(make::ext::ident_path("f").into()); let target = make::expr_path(make::ext::ident_path("f").into());
match variant.field_list() {
Some(ast::FieldList::RecordFieldList(list)) => {
// => 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);
let mut pats = vec![];
for field in list.fields() {
let field_name = field.name()?;
// create a field pattern for use in `MyStruct { fields.. }`
let pat = make::ident_pat(false, false, field_name.clone());
pats.push(pat.into());
// => <expr>.field("field_name", field)
let method_name = make::name_ref("field");
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);
}
// => <expr>.finish()
let method = make::name_ref("finish");
let expr = make::expr_method_call(expr, method, make::arg_list(None));
// => 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)) => {
// => 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);
let mut pats = vec![];
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());
// => <expr>.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);
}
// => <expr>.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 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_name = make::expr_path(make::ext::ident_path("write"));
let macro_call = make::expr_macro_call(macro_name, args); let macro_call = make::expr_macro_call(macro_name, args);
arms.push(make::match_arm(Some(variant_name.into()), None, macro_call.into())); 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")); let match_target = make::expr_path(make::ext::ident_path("self"));
@ -190,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_path(make::ext::ident_path("self"));
let f_path = make::expr_ref(f_path, false); let f_path = make::expr_ref(f_path, false);
let f_path = make::expr_field(f_path, &format!("{}", name)).into(); 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 = make::expr_method_call(expr, make::name_ref("field"), args);
} }
expr expr