From fd7236c7917c81f19b1e2f859b15e9d30bab7e3c Mon Sep 17 00:00:00 2001
From: Yoshua Wuyts <yoshuawuyts@gmail.com>
Date: Sun, 8 Aug 2021 13:50:49 +0200
Subject: [PATCH] debug for record field structs

---
 .../replace_derive_with_manual_impl.rs        | 44 ++++++++++++-------
 crates/ide_assists/src/tests/generated.rs     |  2 +-
 crates/syntax/src/ast/make.rs                 |  3 ++
 3 files changed, 32 insertions(+), 17 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 887fa34c781..8b82cbf5e05 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
@@ -36,7 +36,7 @@ use crate::{
 //
 // impl Debug for S {
 //     $0fn fmt(&self, f: &mut Formatter) -> Result<()> {
-//         f.debug_struct(S)
+//         f.debug_struct("S").finish()
 //     }
 // }
 // ```
@@ -183,25 +183,37 @@ fn gen_debug_impl(adt: &ast::Adt, fn_: &ast::Fn, annotated_name: &ast::Name) {
     match adt {
         ast::Adt::Union(_) => {} // `Debug` cannot be derived for unions, so no default impl can be provided.
         ast::Adt::Enum(_) => {}  // TODO
-        ast::Adt::Struct(strukt) => {
-            match strukt.field_list() {
-                Some(ast::FieldList::RecordFieldList(field_list)) => {
-                    let name = format!("\"{}\"", annotated_name);
-                    let args = make::arg_list(Some(make::expr_literal(&name).into()));
-                    let target = make::expr_path(make::ext::ident_path("f"));
-                    let mut expr = make::expr_method_call(target, "debug_struct", args);
-                    for field in field_list.fields() {
-                        let args = make::arg_list(Some(make::expr_path(&name).into()));
+        ast::Adt::Struct(strukt) => match strukt.field_list() {
+            Some(ast::FieldList::RecordFieldList(field_list)) => {
+                let name = format!("\"{}\"", annotated_name);
+                let args = make::arg_list(Some(make::expr_literal(&name).into()));
+                let target = make::expr_path(make::ext::ident_path("f"));
+                let mut expr = make::expr_method_call(target, "debug_struct", args);
+                for field in field_list.fields() {
+                    if let Some(name) = field.name() {
+                        let f_name = make::expr_literal(&(format!("\"{}\"", name))).into();
+                        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]);
                         expr = make::expr_method_call(expr, "field", args);
                     }
-                    let expr = make::expr_method_call(expr, "finish", make::arg_list(None));
-                    let body = make::block_expr(None, Some(expr)).indent(ast::edit::IndentLevel(1));
-                    ted::replace(fn_.body().unwrap().syntax(), body.clone_for_update().syntax());
                 }
-                Some(ast::FieldList::TupleFieldList(field_list)) => {}
-                None => {} // `Debug` cannot be implemented for an incomplete struct.
+                let expr = make::expr_method_call(expr, "finish", make::arg_list(None));
+                let body = make::block_expr(None, Some(expr)).indent(ast::edit::IndentLevel(1));
+                ted::replace(fn_.body().unwrap().syntax(), body.clone_for_update().syntax());
             }
-        }
+            Some(ast::FieldList::TupleFieldList(field_list)) => {}
+            None => {
+                let name = format!("\"{}\"", annotated_name);
+                let args = make::arg_list(Some(make::expr_literal(&name).into()));
+                let target = make::expr_path(make::ext::ident_path("f"));
+                let expr = make::expr_method_call(target, "debug_struct", args);
+                let expr = make::expr_method_call(expr, "finish", make::arg_list(None));
+                let body = make::block_expr(None, Some(expr)).indent(ast::edit::IndentLevel(1));
+                ted::replace(fn_.body().unwrap().syntax(), body.clone_for_update().syntax());
+            }
+        },
     }
 }
 
diff --git a/crates/ide_assists/src/tests/generated.rs b/crates/ide_assists/src/tests/generated.rs
index 54dde4767c3..195f958208e 100644
--- a/crates/ide_assists/src/tests/generated.rs
+++ b/crates/ide_assists/src/tests/generated.rs
@@ -1364,7 +1364,7 @@ struct S;
 
 impl Debug for S {
     $0fn fmt(&self, f: &mut Formatter) -> Result<()> {
-        f.debug_struct(S)
+        f.debug_struct("S").finish()
     }
 }
 "#####,
diff --git a/crates/syntax/src/ast/make.rs b/crates/syntax/src/ast/make.rs
index e5fff983d0c..71254f08543 100644
--- a/crates/syntax/src/ast/make.rs
+++ b/crates/syntax/src/ast/make.rs
@@ -318,6 +318,9 @@ pub fn expr_closure(pats: impl IntoIterator<Item = ast::Param>, expr: ast::Expr)
     let params = pats.into_iter().join(", ");
     expr_from_text(&format!("|{}| {}", params, expr))
 }
+pub fn expr_field(receiver: ast::Expr, field: &str) -> ast::Expr {
+    expr_from_text(&format!("{}.{}", receiver, field))
+}
 pub fn expr_paren(expr: ast::Expr) -> ast::Expr {
     expr_from_text(&format!("({})", expr))
 }