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.rs | 68 |
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, |