Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs')
-rw-r--r--crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs68
1 files changed, 51 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 11b3fd22fa..f54f7a02d2 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
@@ -4,7 +4,7 @@ use itertools::Itertools;
use syntax::{
SyntaxKind::WHITESPACE,
T,
- ast::{self, AstNode, HasName, make},
+ ast::{self, AstNode, HasName, syntax_factory::SyntaxFactory},
syntax_editor::{Position, SyntaxEditor},
};
@@ -12,8 +12,8 @@ use crate::{
AssistConfig, AssistId,
assist_context::{AssistContext, Assists},
utils::{
- DefaultMethods, IgnoreAssocItems, add_trait_assoc_items_to_impl, filter_assoc_items,
- gen_trait_fn_body, generate_trait_impl,
+ DefaultMethods, IgnoreAssocItems, add_trait_assoc_items_to_impl_with_factory,
+ filter_assoc_items, gen_trait_fn_body, generate_trait_impl,
},
};
@@ -127,6 +127,7 @@ fn add_assist(
let label = format!("Convert to manual `impl {replace_trait_path} for {annotated_name}`");
acc.add(AssistId::refactor("replace_derive_with_manual_impl"), label, target, |builder| {
+ let make = SyntaxFactory::without_mappings();
let insert_after = Position::after(adt.syntax());
let impl_is_unsafe = trait_.map(|s| s.is_unsafe(ctx.db())).unwrap_or(false);
let impl_def = impl_def_from_trait(
@@ -142,7 +143,7 @@ fn add_assist(
let mut editor = builder.make_editor(attr.syntax());
update_attribute(&mut editor, old_derives, old_tree, old_trait_path, attr);
- let trait_path = make::ty_path(replace_trait_path.clone());
+ let trait_path = make.ty_path(replace_trait_path.clone()).into();
let (impl_def, first_assoc_item) = if let Some(impl_def) = impl_def {
(
@@ -150,7 +151,7 @@ fn add_assist(
impl_def.assoc_item_list().and_then(|list| list.assoc_items().next()),
)
} else {
- (generate_trait_impl(impl_is_unsafe, adt, trait_path), None)
+ (generate_trait_impl(&make, impl_is_unsafe, adt, trait_path), None)
};
if let Some(cap) = ctx.config.snippet_cap {
@@ -174,7 +175,7 @@ fn add_assist(
editor.insert_all(
insert_after,
- vec![make::tokens::blank_line().into(), impl_def.syntax().clone().into()],
+ vec![make.whitespace("\n\n").into(), impl_def.syntax().clone().into()],
);
builder.add_file_edits(ctx.vfs_file_id(), editor);
})
@@ -205,10 +206,19 @@ fn impl_def_from_trait(
if trait_items.is_empty() {
return None;
}
- let impl_def = generate_trait_impl(impl_is_unsafe, adt, make::ty_path(trait_path.clone()));
-
- let assoc_items =
- add_trait_assoc_items_to_impl(sema, config, &trait_items, trait_, &impl_def, &target_scope);
+ let make = SyntaxFactory::without_mappings();
+ let trait_ty = make.ty_path(trait_path.clone()).into();
+ let impl_def = generate_trait_impl(&make, impl_is_unsafe, adt, trait_ty);
+
+ let assoc_items = add_trait_assoc_items_to_impl_with_factory(
+ &make,
+ sema,
+ config,
+ &trait_items,
+ trait_,
+ &impl_def,
+ &target_scope,
+ );
let assoc_item_list = if let Some((first, other)) =
assoc_items.split_first().map(|(first, other)| (first.clone_subtree(), other))
{
@@ -222,12 +232,12 @@ fn impl_def_from_trait(
} else {
Some(first.clone())
};
- let items = first_item.into_iter().chain(other.iter().cloned()).collect();
- make::assoc_item_list(Some(items))
+ let items: Vec<ast::AssocItem> =
+ first_item.into_iter().chain(other.iter().cloned()).collect();
+ make.assoc_item_list(items)
} else {
- make::assoc_item_list(None)
- }
- .clone_for_update();
+ make.assoc_item_list_empty()
+ };
let impl_def = impl_def.clone_subtree();
let mut editor = SyntaxEditor::new(impl_def.syntax().clone());
@@ -243,6 +253,7 @@ fn update_attribute(
old_trait_path: &ast::Path,
attr: &ast::Attr,
) {
+ let make = SyntaxFactory::without_mappings();
let new_derives = old_derives
.iter()
.filter(|t| t.to_string() != old_trait_path.to_string())
@@ -257,13 +268,13 @@ fn update_attribute(
.collect::<Vec<_>>()
});
// ...which are interspersed with ", "
- let tt = Itertools::intersperse(tt, vec![make::token(T![,]), make::tokens::single_space()]);
+ let tt = Itertools::intersperse(tt, vec![make.token(T![,]), make.whitespace(" ")]);
// ...wrap them into the appropriate `NodeOrToken` variant
let tt = tt.flatten().map(syntax::NodeOrToken::Token);
// ...and make them into a flat list of tokens
let tt = tt.collect::<Vec<_>>();
- let new_tree = make::token_tree(T!['('], tt).clone_for_update();
+ let new_tree = make.token_tree(T!['('], tt);
editor.replace(old_tree.syntax(), new_tree.syntax());
} else {
// Remove the attr and any trailing whitespace
@@ -1308,6 +1319,29 @@ impl<T: Clone> Clone for Foo<T> {
}
#[test]
+ fn add_custom_impl_clone_generic_tuple_struct_with_associated() {
+ check_assist(
+ replace_derive_with_manual_impl,
+ r#"
+//- minicore: clone, derive, deref
+#[derive(Clo$0ne)]
+struct Foo<T: core::ops::Deref>(T::Target);
+"#,
+ r#"
+struct Foo<T: core::ops::Deref>(T::Target);
+
+impl<T: core::ops::Deref + Clone> Clone for Foo<T>
+where T::Target: Clone
+{
+ $0fn clone(&self) -> Self {
+ Self(self.0.clone())
+ }
+}
+"#,
+ )
+ }
+
+ #[test]
fn test_ignore_derive_macro_without_input() {
check_assist_not_applicable(
replace_derive_with_manual_impl,