Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--crates/ide-assists/src/handlers/add_missing_impl_members.rs172
-rw-r--r--crates/ide-assists/src/handlers/generate_derive.rs41
-rw-r--r--crates/ide-assists/src/utils.rs12
-rw-r--r--crates/syntax/src/ast/edit_in_place.rs2
4 files changed, 217 insertions, 10 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 9e4e6c1daf..89e03a98d6 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)
+ }
}
"#,
);
@@ -1511,11 +1511,175 @@ fn main() {
struct S;
impl Tr for S {
fn method() {
- ${0:todo!()}
- }
+ ${0:todo!()}
+ }
}
}
"#,
);
}
+
+ #[test]
+ fn test_add_missing_preserves_indentation() {
+ // in different modules
+ check_assist(
+ add_missing_impl_members,
+ r#"
+mod m {
+ pub trait Foo {
+ const CONST_MULTILINE: (
+ i32,
+ i32
+ );
+
+ fn foo(&self);
+ }
+}
+struct S;
+impl m::Foo for S { $0 }"#,
+ r#"
+mod m {
+ 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!()
+ }
+}"#,
+ );
+ // in the same module
+ check_assist(
+ add_missing_impl_members,
+ r#"
+mod m {
+ trait Foo {
+ type Output;
+
+ const CONST: usize = 42;
+ const CONST_2: i32;
+ const CONST_MULTILINE: (
+ i32,
+ i32
+ );
+
+ fn foo(&self);
+ fn bar(&self);
+ fn baz(&self);
+ }
+
+ struct S;
+
+ impl Foo for S {
+ fn bar(&self) {}
+$0
+ }
+}"#,
+ r#"
+mod m {
+ trait Foo {
+ type Output;
+
+ const CONST: usize = 42;
+ const CONST_2: i32;
+ const CONST_MULTILINE: (
+ i32,
+ i32
+ );
+
+ fn foo(&self);
+ fn bar(&self);
+ fn baz(&self);
+ }
+
+ struct S;
+
+ impl Foo for S {
+ fn bar(&self) {}
+
+ $0type Output;
+
+ const CONST_2: i32;
+
+ const CONST_MULTILINE: (
+ i32,
+ i32
+ );
+
+ fn foo(&self) {
+ todo!()
+ }
+
+ fn baz(&self) {
+ todo!()
+ }
+
+ }
+}"#,
+ );
+ }
+
+ #[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/handlers/generate_derive.rs b/crates/ide-assists/src/handlers/generate_derive.rs
index 339245b94e..78ac2eb30e 100644
--- a/crates/ide-assists/src/handlers/generate_derive.rs
+++ b/crates/ide-assists/src/handlers/generate_derive.rs
@@ -1,5 +1,5 @@
use syntax::{
- ast::{self, AstNode, HasAttrs},
+ ast::{self, edit::IndentLevel, AstNode, HasAttrs},
SyntaxKind::{COMMENT, WHITESPACE},
TextSize,
};
@@ -42,7 +42,12 @@ pub(crate) fn generate_derive(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opt
.next();
match derive_attr {
None => {
- builder.insert_snippet(cap, node_start, "#[derive($0)]\n");
+ let indent_level = IndentLevel::from_node(nominal.syntax());
+ builder.insert_snippet(
+ cap,
+ node_start,
+ format!("#[derive($0)]\n{indent_level}"),
+ );
}
Some(tt) => {
// Just move the cursor.
@@ -84,6 +89,20 @@ mod tests {
"struct Foo { $0 a: i32, }",
"#[derive($0)]\nstruct Foo { a: i32, }",
);
+ check_assist(
+ generate_derive,
+ "
+mod m {
+ struct Foo { a: i32,$0 }
+}
+ ",
+ "
+mod m {
+ #[derive($0)]
+ struct Foo { a: i32, }
+}
+ ",
+ );
}
#[test]
@@ -111,6 +130,24 @@ struct Foo { a: i32$0, }
struct Foo { a: i32, }
",
);
+ check_assist(
+ generate_derive,
+ "
+mod m {
+ /// `Foo` is a pretty important struct.
+ /// It does stuff.
+ struct Foo { a: i32,$0 }
+}
+ ",
+ "
+mod m {
+ /// `Foo` is a pretty important struct.
+ /// It does stuff.
+ #[derive($0)]
+ struct Foo { a: i32, }
+}
+ ",
+ );
}
#[test]
diff --git a/crates/ide-assists/src/utils.rs b/crates/ide-assists/src/utils.rs
index 77f4b0e3e0..8f7ea26306 100644
--- a/crates/ide-assists/src/utils.rs
+++ b/crates/ide-assists/src/utils.rs
@@ -9,8 +9,8 @@ use stdx::format_to;
use syntax::{
ast::{
self,
- edit::{self, AstNodeEdit},
- edit_in_place::{AttrsOwnerEdit, Removable},
+ edit::{AstNodeEdit, IndentLevel},
+ 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(edit::IndentLevel(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) => {
diff --git a/crates/syntax/src/ast/edit_in_place.rs b/crates/syntax/src/ast/edit_in_place.rs
index a493c92e7d..995e8d8d15 100644
--- a/crates/syntax/src/ast/edit_in_place.rs
+++ b/crates/syntax/src/ast/edit_in_place.rs
@@ -465,6 +465,8 @@ impl ast::Impl {
}
impl ast::AssocItemList {
+ /// Attention! This function does align the first line of `item` with respect to `self`,
+ /// but it does _not_ change indentation of other lines (if any).
pub fn add_item(&self, item: ast::AssocItem) {
let (indent, position, whitespace) = match self.assoc_items().last() {
Some(last_item) => (