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.rs106
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,