From 49f1092f14d7b2f096fa32d3e1d45c8844a22ee2 Mon Sep 17 00:00:00 2001
From: ponyii <ponyii@protonmail.com>
Date: Wed, 10 May 2023 22:27:05 +0400
Subject: [PATCH] `add_missing_impl_members` and `add_missing_default_members`
 break indentation no longer

---
 .../src/handlers/add_missing_impl_members.rs  | 134 +++++++++++++-----
 crates/ide-assists/src/utils.rs               |  10 +-
 2 files changed, 106 insertions(+), 38 deletions(-)

diff --git a/crates/ide-assists/src/handlers/add_missing_impl_members.rs b/crates/ide-assists/src/handlers/add_missing_impl_members.rs
index 4cc04fff633..89e03a98d6f 100644
--- a/crates/ide-assists/src/handlers/add_missing_impl_members.rs
+++ b/crates/ide-assists/src/handlers/add_missing_impl_members.rs
@@ -1346,8 +1346,8 @@ struct SomeStruct {
 }
 impl PartialEq for SomeStruct {
     $0fn ne(&self, other: &Self) -> bool {
-            !self.eq(other)
-        }
+        !self.eq(other)
+    }
 }
 "#,
         );
@@ -1520,48 +1520,47 @@ fn main() {
     }
 
     #[test]
-    fn test_add_missing_impl_members_indentation() {
-        // few trait members, no braces
+    fn test_add_missing_preserves_indentation() {
+        // in different modules
         check_assist(
             add_missing_impl_members,
             r#"
 mod m {
-    trait Foo { fn foo(&self); }
-    struct S;
-    impl Foo for S$0
-}"#,
+    pub trait Foo {
+        const CONST_MULTILINE: (
+            i32,
+            i32
+        );
+
+        fn foo(&self);
+    }
+}
+struct S;
+impl m::Foo for S { $0 }"#,
             r#"
 mod m {
-    trait Foo { fn foo(&self); }
-    struct S;
-    impl Foo for S {
-        fn foo(&self) {
-            ${0:todo!()}
-        }
+    pub trait Foo {
+        const CONST_MULTILINE: (
+            i32,
+            i32
+        );
+
+        fn foo(&self);
+    }
+}
+struct S;
+impl m::Foo for S {
+    $0const CONST_MULTILINE: (
+        i32,
+        i32
+    );
+
+    fn foo(&self) {
+        todo!()
     }
 }"#,
         );
-        // few trait members, empty impl def.
-        check_assist(
-            add_missing_impl_members,
-            r#"
-mod m {
-    trait Foo { fn foo(&self); }
-    struct S;
-    impl Foo for S { $0 }
-}"#,
-            r#"
-mod m {
-    trait Foo { fn foo(&self); }
-    struct S;
-    impl Foo for S {
-        fn foo(&self) {
-            ${0:todo!()}
-        }
-    }
-}"#,
-        );
-        // todo - in mod and outside
+        // in the same module
         check_assist(
             add_missing_impl_members,
             r#"
@@ -1571,6 +1570,10 @@ mod m {
 
         const CONST: usize = 42;
         const CONST_2: i32;
+        const CONST_MULTILINE: (
+            i32,
+            i32
+        );
 
         fn foo(&self);
         fn bar(&self);
@@ -1591,6 +1594,10 @@ mod m {
 
         const CONST: usize = 42;
         const CONST_2: i32;
+        const CONST_MULTILINE: (
+            i32,
+            i32
+        );
 
         fn foo(&self);
         fn bar(&self);
@@ -1606,6 +1613,11 @@ mod m {
 
         const CONST_2: i32;
 
+        const CONST_MULTILINE: (
+            i32,
+            i32
+        );
+
         fn foo(&self) {
             todo!()
         }
@@ -1618,4 +1630,56 @@ mod m {
 }"#,
         );
     }
+
+    #[test]
+    fn test_add_default_preserves_indentation() {
+        check_assist(
+            add_missing_default_members,
+            r#"
+mod m {
+    pub trait Foo {
+        type Output;
+
+        const CONST: usize = 42;
+        const CONST_2: i32;
+        const CONST_MULTILINE: = (
+            i32,
+            i32,
+        ) = (3, 14);
+
+        fn valid(some: u32) -> bool { false }
+        fn foo(some: u32) -> bool;
+    }
+}
+struct S;
+impl m::Foo for S { $0 }"#,
+            r#"
+mod m {
+    pub trait Foo {
+        type Output;
+
+        const CONST: usize = 42;
+        const CONST_2: i32;
+        const CONST_MULTILINE: = (
+            i32,
+            i32,
+        ) = (3, 14);
+
+        fn valid(some: u32) -> bool { false }
+        fn foo(some: u32) -> bool;
+    }
+}
+struct S;
+impl m::Foo for S {
+    $0const CONST: usize = 42;
+
+    const CONST_MULTILINE: = (
+        i32,
+        i32,
+    ) = (3, 14);
+
+    fn valid(some: u32) -> bool { false }
+}"#,
+        )
+    }
 }
diff --git a/crates/ide-assists/src/utils.rs b/crates/ide-assists/src/utils.rs
index 1c9d4157cd6..8f7ea26306c 100644
--- a/crates/ide-assists/src/utils.rs
+++ b/crates/ide-assists/src/utils.rs
@@ -10,7 +10,7 @@ use syntax::{
     ast::{
         self,
         edit::{AstNodeEdit, IndentLevel},
-        edit_in_place::{AttrsOwnerEdit, Removable},
+        edit_in_place::{AttrsOwnerEdit, Indent, Removable},
         make, HasArgList, HasAttrs, HasGenericParams, HasName, HasTypeBounds, Whitespace,
     },
     ted, AstNode, AstToken, Direction, SourceFile,
@@ -139,9 +139,11 @@ pub fn add_trait_assoc_items_to_impl(
 
     let transform = PathTransform::trait_impl(&target_scope, &source_scope, trait_, impl_.clone());
 
+    let new_indent_level = IndentLevel::from_node(impl_.syntax()) + 1;
     let items = items.into_iter().map(|assoc_item| {
         transform.apply(assoc_item.syntax());
         assoc_item.remove_attrs_and_docs();
+        assoc_item.reindent_to(new_indent_level);
         assoc_item
     });
 
@@ -153,8 +155,10 @@ pub fn add_trait_assoc_items_to_impl(
         first_item.get_or_insert_with(|| item.clone());
         match &item {
             ast::AssocItem::Fn(fn_) if fn_.body().is_none() => {
-                let body = make::block_expr(None, Some(make::ext::expr_todo()))
-                    .indent(IndentLevel::from_node(impl_.syntax()) + 1);
+                let body = AstNodeEdit::indent(
+                    &make::block_expr(None, Some(make::ext::expr_todo())),
+                    new_indent_level,
+                );
                 ted::replace(fn_.get_or_create_body().syntax(), body.clone_for_update().syntax())
             }
             ast::AssocItem::TypeAlias(type_alias) => {