Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/ide-assists/src/handlers/generate_trait_from_impl.rs')
| -rw-r--r-- | crates/ide-assists/src/handlers/generate_trait_from_impl.rs | 106 |
1 files changed, 95 insertions, 11 deletions
diff --git a/crates/ide-assists/src/handlers/generate_trait_from_impl.rs b/crates/ide-assists/src/handlers/generate_trait_from_impl.rs index 8bc4d50cf6..1286abe356 100644 --- a/crates/ide-assists/src/handlers/generate_trait_from_impl.rs +++ b/crates/ide-assists/src/handlers/generate_trait_from_impl.rs @@ -1,8 +1,10 @@ use crate::assist_context::{AssistContext, Assists}; use ide_db::assists::AssistId; use syntax::{ - AstNode, SyntaxKind, T, - ast::{self, HasGenericParams, HasName, HasVisibility, edit::AstNodeEdit, make}, + AstNode, AstToken, SyntaxKind, T, + ast::{ + self, HasDocComments, HasGenericParams, HasName, HasVisibility, edit::AstNodeEdit, make, + }, syntax_editor::{Position, SyntaxEditor}, }; @@ -45,7 +47,7 @@ use syntax::{ // }; // } // -// trait ${0:NewTrait}<const N: usize> { +// trait ${0:Create}<const N: usize> { // // Used as an associated constant. // const CONST_ASSOC: usize = N * 4; // @@ -54,7 +56,7 @@ use syntax::{ // const_maker! {i32, 7} // } // -// impl<const N: usize> ${0:NewTrait}<N> for Foo<N> { +// impl<const N: usize> ${0:Create}<N> for Foo<N> { // // Used as an associated constant. // const CONST_ASSOC: usize = N * 4; // @@ -107,7 +109,7 @@ pub(crate) fn generate_trait_from_impl(acc: &mut Assists, ctx: &AssistContext<'_ }; let trait_ast = make::trait_( false, - "NewTrait", + &trait_name(&impl_assoc_items).text(), impl_ast.generic_param_list(), impl_ast.where_clause(), trait_items, @@ -133,6 +135,7 @@ pub(crate) fn generate_trait_from_impl(acc: &mut Assists, ctx: &AssistContext<'_ let mut editor = builder.make_editor(impl_ast.syntax()); impl_assoc_items.assoc_items().for_each(|item| { remove_items_visibility(&mut editor, &item); + remove_doc_comments(&mut editor, &item); }); editor.insert_all(Position::before(impl_name.syntax()), elements); @@ -160,6 +163,18 @@ pub(crate) fn generate_trait_from_impl(acc: &mut Assists, ctx: &AssistContext<'_ Some(()) } +fn trait_name(items: &ast::AssocItemList) -> ast::Name { + let mut fn_names = items + .assoc_items() + .filter_map(|x| if let ast::AssocItem::Fn(f) = x { f.name() } else { None }); + fn_names + .next() + .and_then(|name| { + fn_names.next().is_none().then(|| make::name(&stdx::to_camel_case(&name.text()))) + }) + .unwrap_or_else(|| make::name("NewTrait")) +} + /// `E0449` Trait items always share the visibility of their trait fn remove_items_visibility(editor: &mut SyntaxEditor, item: &ast::AssocItem) { if let Some(has_vis) = ast::AnyHasVisibility::cast(item.syntax().clone()) { @@ -175,6 +190,17 @@ fn remove_items_visibility(editor: &mut SyntaxEditor, item: &ast::AssocItem) { } } +fn remove_doc_comments(editor: &mut SyntaxEditor, item: &ast::AssocItem) { + for doc in item.doc_comments() { + if let Some(next) = doc.syntax().next_token() + && next.kind() == SyntaxKind::WHITESPACE + { + editor.delete(next); + } + editor.delete(doc.syntax()); + } +} + fn strip_body(editor: &mut SyntaxEditor, item: &ast::AssocItem) { if let ast::AssocItem::Fn(f) = item && let Some(body) = f.body() @@ -226,11 +252,47 @@ impl F$0oo { r#" struct Foo(f64); -trait NewTrait { +trait Add { fn add(&mut self, x: f64); } -impl NewTrait for Foo { +impl Add for Foo { + fn add(&mut self, x: f64) { + self.0 += x; + } +}"#, + ) + } + + #[test] + fn test_remove_doc_comments() { + check_assist_no_snippet_cap( + generate_trait_from_impl, + r#" +struct Foo(f64); + +impl F$0oo { + /// Add `x` + /// + /// # Examples + #[cfg(true)] + fn add(&mut self, x: f64) { + self.0 += x; + } +}"#, + r#" +struct Foo(f64); + +trait Add { + /// Add `x` + /// + /// # Examples + #[cfg(true)] + fn add(&mut self, x: f64); +} + +impl Add for Foo { + #[cfg(true)] fn add(&mut self, x: f64) { self.0 += x; } @@ -339,11 +401,11 @@ impl F$0oo { r#" struct Foo; -trait NewTrait { +trait AFunc { fn a_func() -> Option<()>; } -impl NewTrait for Foo { +impl AFunc for Foo { fn a_func() -> Option<()> { Some(()) } @@ -373,11 +435,11 @@ mod a { }"#, r#" mod a { - trait NewTrait { + trait Foo { fn foo(); } - impl NewTrait for S { + impl Foo for S { fn foo() {} } }"#, @@ -385,6 +447,28 @@ mod a { } #[test] + fn test_multi_fn_impl_not_suggest_trait_name() { + check_assist_no_snippet_cap( + generate_trait_from_impl, + r#" +impl S$0 { + fn foo() {} + fn bar() {} +}"#, + r#" +trait NewTrait { + fn foo(); + fn bar(); +} + +impl NewTrait for S { + fn foo() {} + fn bar() {} +}"#, + ) + } + + #[test] fn test_snippet_cap_is_some() { check_assist( generate_trait_from_impl, |