1 use hir::{InFile, ModuleDef};
4 import_assets::NameToImport, insert_whitespace_into_node::insert_ws_into, mod_path_to_ast,
8 use itertools::Itertools;
10 ast::{self, AstNode, HasName},
11 SyntaxKind::WHITESPACE,
15 assist_context::{AssistBuilder, AssistContext, Assists},
17 add_trait_assoc_items_to_impl, filter_assoc_items, gen_trait_fn_body,
18 generate_trait_impl_text, render_snippet, Cursor, DefaultMethods,
23 // Assist: replace_derive_with_manual_impl
25 // Converts a `derive` impl into a manual one.
28 // # //- minicore: derive
29 // # trait Debug { fn fmt(&self, f: &mut Formatter) -> Result<()>; }
30 // #[derive(Deb$0ug, Display)]
35 // # trait Debug { fn fmt(&self, f: &mut Formatter) -> Result<()>; }
40 // $0fn fmt(&self, f: &mut Formatter) -> Result<()> {
41 // f.debug_struct("S").finish()
45 pub(crate) fn replace_derive_with_manual_impl(
49 let attr = ctx.find_node_at_offset_with_descend::<ast::Attr>()?;
50 let path = attr.path()?;
51 let hir_file = ctx.sema.hir_file_for(attr.syntax());
52 if !hir_file.is_derive_attr_pseudo_expansion(ctx.db()) {
56 let InFile { file_id, value } = hir_file.call_node(ctx.db())?;
57 if file_id.is_macro() {
58 // FIXME: make this work in macro files
61 // collect the derive paths from the #[derive] expansion
62 let current_derives = ctx
64 .parse_or_expand(hir_file)?
66 .filter_map(ast::Attr::cast)
67 .filter_map(|attr| attr.path())
70 let adt = value.parent().and_then(ast::Adt::cast)?;
71 let attr = ast::Attr::cast(value)?;
72 let args = attr.token_tree()?;
74 let current_module = ctx.sema.scope(adt.syntax()).module()?;
75 let current_crate = current_module.krate();
77 let found_traits = items_locator::items_with_name(
80 NameToImport::exact_case_sensitive(path.segments().last()?.to_string()),
81 items_locator::AssocItemSearch::Exclude,
82 Some(items_locator::DEFAULT_QUERY_SEARCH_LIMIT.inner()),
84 .filter_map(|item| match item.as_module_def()? {
85 ModuleDef::Trait(trait_) => Some(trait_),
90 .find_use_path(ctx.sema.db, hir::ModuleDef::Trait(trait_))
96 let mut no_traits_found = true;
97 for (replace_trait_path, trait_) in found_traits.inspect(|_| no_traits_found = false) {
111 add_assist(acc, ctx, &attr, ¤t_derives, &args, &path, &path, None, &adt)?;
120 old_derives: &[ast::Path],
121 old_tree: &ast::TokenTree,
122 old_trait_path: &ast::Path,
123 replace_trait_path: &ast::Path,
124 trait_: Option<hir::Trait>,
127 let target = attr.syntax().text_range();
128 let annotated_name = adt.name()?;
129 let label = format!("Convert to manual `impl {} for {}`", replace_trait_path, annotated_name);
132 AssistId("replace_derive_with_manual_impl", AssistKind::Refactor),
136 let insert_pos = adt.syntax().text_range().end();
137 let impl_def_with_items =
138 impl_def_from_trait(&ctx.sema, adt, &annotated_name, trait_, replace_trait_path);
139 update_attribute(builder, old_derives, old_tree, old_trait_path, attr);
140 let trait_path = replace_trait_path.to_string();
141 match (ctx.config.snippet_cap, impl_def_with_items) {
143 builder.insert(insert_pos, generate_trait_impl_text(adt, &trait_path, ""))
145 (Some(cap), None) => builder.insert_snippet(
148 generate_trait_impl_text(adt, &trait_path, " $0"),
150 (Some(cap), Some((impl_def, first_assoc_item))) => {
151 let mut cursor = Cursor::Before(first_assoc_item.syntax());
153 if let ast::AssocItem::Fn(ref func) = first_assoc_item {
154 if let Some(m) = func.syntax().descendants().find_map(ast::MacroCall::cast)
156 if m.syntax().text() == "todo!()" {
158 cursor = Cursor::Replace(placeholder.syntax());
163 builder.insert_snippet(
166 format!("\n\n{}", render_snippet(cap, impl_def.syntax(), cursor)),
174 fn impl_def_from_trait(
175 sema: &hir::Semantics<ide_db::RootDatabase>,
177 annotated_name: &ast::Name,
178 trait_: Option<hir::Trait>,
179 trait_path: &ast::Path,
180 ) -> Option<(ast::Impl, ast::AssocItem)> {
181 let trait_ = trait_?;
182 let target_scope = sema.scope(annotated_name.syntax());
183 let trait_items = filter_assoc_items(sema, &trait_.items(sema.db), DefaultMethods::No);
184 if trait_items.is_empty() {
188 use syntax::ast::Impl;
189 let text = generate_trait_impl_text(adt, trait_path.to_string().as_str(), "");
190 let parse = syntax::SourceFile::parse(&text);
191 let node = match parse.tree().syntax().descendants().find_map(Impl::cast) {
195 "Failed to make ast node `{}` from text {}",
196 std::any::type_name::<Impl>(),
201 let node = node.clone_subtree();
202 assert_eq!(node.syntax().text_range().start(), 0.into());
206 let trait_items = trait_items
209 if sema.hir_file_for(it.syntax()).is_macro() {
210 if let Some(it) = ast::AssocItem::cast(insert_ws_into(it.syntax().clone())) {
214 it.clone_for_update()
217 let (impl_def, first_assoc_item) =
218 add_trait_assoc_items_to_impl(sema, trait_items, trait_, impl_def, target_scope);
220 // Generate a default `impl` function body for the derived trait.
221 if let ast::AssocItem::Fn(ref func) = first_assoc_item {
222 let _ = gen_trait_fn_body(func, trait_path, adt);
225 Some((impl_def, first_assoc_item))
229 builder: &mut AssistBuilder,
230 old_derives: &[ast::Path],
231 old_tree: &ast::TokenTree,
232 old_trait_path: &ast::Path,
235 let new_derives = old_derives
237 .filter(|t| t.to_string() != old_trait_path.to_string())
238 .collect::<Vec<_>>();
239 let has_more_derives = !new_derives.is_empty();
241 if has_more_derives {
242 let new_derives = format!("({})", new_derives.iter().format(", "));
243 builder.replace(old_tree.syntax().text_range(), new_derives);
245 let attr_range = attr.syntax().text_range();
246 builder.delete(attr_range);
248 if let Some(line_break_range) = attr
250 .next_sibling_or_token()
251 .filter(|t| t.kind() == WHITESPACE)
252 .map(|t| t.text_range())
254 builder.delete(line_break_range);
261 use crate::tests::{check_assist, check_assist_not_applicable};
266 fn add_custom_impl_debug_record_struct() {
268 replace_derive_with_manual_impl,
270 //- minicore: fmt, derive
281 impl core::fmt::Debug for Foo {
282 $0fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
283 f.debug_struct("Foo").field("bar", &self.bar).finish()
290 fn add_custom_impl_debug_tuple_struct() {
292 replace_derive_with_manual_impl,
294 //- minicore: fmt, derive
296 struct Foo(String, usize);
298 r#"struct Foo(String, usize);
300 impl core::fmt::Debug for Foo {
301 $0fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
302 f.debug_tuple("Foo").field(&self.0).field(&self.1).finish()
309 fn add_custom_impl_debug_empty_struct() {
311 replace_derive_with_manual_impl,
313 //- minicore: fmt, derive
320 impl core::fmt::Debug for Foo {
321 $0fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
322 f.debug_struct("Foo").finish()
329 fn add_custom_impl_debug_enum() {
331 replace_derive_with_manual_impl,
333 //- minicore: fmt, derive
346 impl core::fmt::Debug for Foo {
347 $0fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
349 Self::Bar => write!(f, "Bar"),
350 Self::Baz => write!(f, "Baz"),
359 fn add_custom_impl_debug_tuple_enum() {
361 replace_derive_with_manual_impl,
363 //- minicore: fmt, derive
376 impl core::fmt::Debug for Foo {
377 $0fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
379 Self::Bar(arg0, arg1) => f.debug_tuple("Bar").field(arg0).field(arg1).finish(),
380 Self::Baz => write!(f, "Baz"),
388 fn add_custom_impl_debug_record_enum() {
390 replace_derive_with_manual_impl,
392 //- minicore: fmt, derive
411 impl core::fmt::Debug for Foo {
412 $0fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
414 Self::Bar { baz, qux } => f.debug_struct("Bar").field("baz", baz).field("qux", qux).finish(),
415 Self::Baz => write!(f, "Baz"),
423 fn add_custom_impl_default_record_struct() {
425 replace_derive_with_manual_impl,
427 //- minicore: default, derive
438 impl Default for Foo {
439 $0fn default() -> Self {
440 Self { foo: Default::default() }
447 fn add_custom_impl_default_tuple_struct() {
449 replace_derive_with_manual_impl,
451 //- minicore: default, derive
458 impl Default for Foo {
459 $0fn default() -> Self {
460 Self(Default::default())
467 fn add_custom_impl_default_empty_struct() {
469 replace_derive_with_manual_impl,
471 //- minicore: default, derive
478 impl Default for Foo {
479 $0fn default() -> Self {
488 fn add_custom_impl_hash_record_struct() {
490 replace_derive_with_manual_impl,
492 //- minicore: hash, derive
505 impl core::hash::Hash for Foo {
506 $0fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
507 self.bin.hash(state);
508 self.bar.hash(state);
516 fn add_custom_impl_hash_tuple_struct() {
518 replace_derive_with_manual_impl,
520 //- minicore: hash, derive
522 struct Foo(usize, usize);
525 struct Foo(usize, usize);
527 impl core::hash::Hash for Foo {
528 $0fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
538 fn add_custom_impl_hash_enum() {
540 replace_derive_with_manual_impl,
542 //- minicore: hash, derive
555 impl core::hash::Hash for Foo {
556 $0fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
557 core::mem::discriminant(self).hash(state);
565 fn add_custom_impl_clone_record_struct() {
567 replace_derive_with_manual_impl,
569 //- minicore: clone, derive
583 $0fn clone(&self) -> Self {
584 Self { bin: self.bin.clone(), bar: self.bar.clone() }
592 fn add_custom_impl_clone_tuple_struct() {
594 replace_derive_with_manual_impl,
596 //- minicore: clone, derive
598 struct Foo(usize, usize);
601 struct Foo(usize, usize);
604 $0fn clone(&self) -> Self {
605 Self(self.0.clone(), self.1.clone())
613 fn add_custom_impl_clone_empty_struct() {
615 replace_derive_with_manual_impl,
617 //- minicore: clone, derive
625 $0fn clone(&self) -> Self {
634 fn add_custom_impl_clone_enum() {
636 replace_derive_with_manual_impl,
638 //- minicore: clone, derive
652 $0fn clone(&self) -> Self {
654 Self::Bar => Self::Bar,
655 Self::Baz => Self::Baz,
664 fn add_custom_impl_clone_tuple_enum() {
666 replace_derive_with_manual_impl,
668 //- minicore: clone, derive
682 $0fn clone(&self) -> Self {
684 Self::Bar(arg0) => Self::Bar(arg0.clone()),
685 Self::Baz => Self::Baz,
694 fn add_custom_impl_clone_record_enum() {
696 replace_derive_with_manual_impl,
698 //- minicore: clone, derive
716 $0fn clone(&self) -> Self {
718 Self::Bar { bin } => Self::Bar { bin: bin.clone() },
719 Self::Baz => Self::Baz,
728 fn add_custom_impl_partial_ord_record_struct() {
730 replace_derive_with_manual_impl,
732 //- minicore: ord, derive
733 #[derive(Partial$0Ord)]
743 impl PartialOrd for Foo {
744 $0fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
745 self.bin.partial_cmp(&other.bin)
753 fn add_custom_impl_partial_ord_record_struct_multi_field() {
755 replace_derive_with_manual_impl,
757 //- minicore: ord, derive
758 #[derive(Partial$0Ord)]
772 impl PartialOrd for Foo {
773 $0fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
774 match self.bin.partial_cmp(&other.bin) {
775 Some(core::cmp::Ordering::Equal) => {}
778 match self.bar.partial_cmp(&other.bar) {
779 Some(core::cmp::Ordering::Equal) => {}
782 self.baz.partial_cmp(&other.baz)
790 fn add_custom_impl_partial_ord_tuple_struct() {
792 replace_derive_with_manual_impl,
794 //- minicore: ord, derive
795 #[derive(Partial$0Ord)]
796 struct Foo(usize, usize, usize);
799 struct Foo(usize, usize, usize);
801 impl PartialOrd for Foo {
802 $0fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
803 match self.0.partial_cmp(&other.0) {
804 Some(core::cmp::Ordering::Equal) => {}
807 match self.1.partial_cmp(&other.1) {
808 Some(core::cmp::Ordering::Equal) => {}
811 self.2.partial_cmp(&other.2)
819 fn add_custom_impl_partial_eq_record_struct() {
821 replace_derive_with_manual_impl,
823 //- minicore: eq, derive
824 #[derive(Partial$0Eq)]
836 impl PartialEq for Foo {
837 $0fn eq(&self, other: &Self) -> bool {
838 self.bin == other.bin && self.bar == other.bar
846 fn add_custom_impl_partial_eq_tuple_struct() {
848 replace_derive_with_manual_impl,
850 //- minicore: eq, derive
851 #[derive(Partial$0Eq)]
852 struct Foo(usize, usize);
855 struct Foo(usize, usize);
857 impl PartialEq for Foo {
858 $0fn eq(&self, other: &Self) -> bool {
859 self.0 == other.0 && self.1 == other.1
867 fn add_custom_impl_partial_eq_empty_struct() {
869 replace_derive_with_manual_impl,
871 //- minicore: eq, derive
872 #[derive(Partial$0Eq)]
878 impl PartialEq for Foo {
879 $0fn eq(&self, other: &Self) -> bool {
888 fn add_custom_impl_partial_eq_enum() {
890 replace_derive_with_manual_impl,
892 //- minicore: eq, derive
893 #[derive(Partial$0Eq)]
905 impl PartialEq for Foo {
906 $0fn eq(&self, other: &Self) -> bool {
907 core::mem::discriminant(self) == core::mem::discriminant(other)
915 fn add_custom_impl_partial_eq_tuple_enum() {
917 replace_derive_with_manual_impl,
919 //- minicore: eq, derive
920 #[derive(Partial$0Eq)]
932 impl PartialEq for Foo {
933 $0fn eq(&self, other: &Self) -> bool {
934 match (self, other) {
935 (Self::Bar(l0), Self::Bar(r0)) => l0 == r0,
936 _ => core::mem::discriminant(self) == core::mem::discriminant(other),
945 fn add_custom_impl_partial_eq_record_enum() {
947 replace_derive_with_manual_impl,
949 //- minicore: eq, derive
950 #[derive(Partial$0Eq)]
976 impl PartialEq for Foo {
977 $0fn eq(&self, other: &Self) -> bool {
978 match (self, other) {
979 (Self::Bar { bin: l_bin }, Self::Bar { bin: r_bin }) => l_bin == r_bin,
980 (Self::Baz { qux: l_qux, fez: l_fez }, Self::Baz { qux: r_qux, fez: r_fez }) => l_qux == r_qux && l_fez == r_fez,
981 _ => core::mem::discriminant(self) == core::mem::discriminant(other),
989 fn add_custom_impl_all() {
991 replace_derive_with_manual_impl,
997 const Baz: usize = 42;
1013 const Baz: usize = 42;
1024 impl foo::Bar for Foo {
1027 const Baz: usize = 42;
1039 fn add_custom_impl_for_unique_input_unknown() {
1041 replace_derive_with_manual_impl,
1043 //- minicore: derive
1054 impl Debug for Foo {
1062 fn add_custom_impl_for_with_visibility_modifier() {
1064 replace_derive_with_manual_impl,
1066 //- minicore: derive
1077 impl Debug for Foo {
1085 fn add_custom_impl_when_multiple_inputs() {
1087 replace_derive_with_manual_impl,
1089 //- minicore: derive
1090 #[derive(Display, Debug$0, Serialize)]
1094 #[derive(Display, Serialize)]
1097 impl Debug for Foo {
1105 fn add_custom_impl_default_generic_record_struct() {
1107 replace_derive_with_manual_impl,
1109 //- minicore: default, derive
1110 #[derive(Defau$0lt)]
1122 impl<T, U> Default for Foo<T, U> {
1123 $0fn default() -> Self {
1124 Self { foo: Default::default(), bar: Default::default() }
1132 fn add_custom_impl_clone_generic_tuple_struct_with_bounds() {
1134 replace_derive_with_manual_impl,
1136 //- minicore: clone, derive
1138 struct Foo<T: Clone>(T, usize);
1141 struct Foo<T: Clone>(T, usize);
1143 impl<T: Clone> Clone for Foo<T> {
1144 $0fn clone(&self) -> Self {
1145 Self(self.0.clone(), self.1.clone())
1153 fn test_ignore_derive_macro_without_input() {
1154 check_assist_not_applicable(
1155 replace_derive_with_manual_impl,
1157 //- minicore: derive
1165 fn test_ignore_if_cursor_on_param() {
1166 check_assist_not_applicable(
1167 replace_derive_with_manual_impl,
1169 //- minicore: derive, fmt
1175 check_assist_not_applicable(
1176 replace_derive_with_manual_impl,
1178 //- minicore: derive, fmt
1186 fn test_ignore_if_not_derive() {
1187 check_assist_not_applicable(
1188 replace_derive_with_manual_impl,
1190 //- minicore: derive
1191 #[allow(non_camel_$0case_types)]
1198 fn works_at_start_of_file() {
1199 check_assist_not_applicable(
1200 replace_derive_with_manual_impl,
1202 //- minicore: derive, fmt
1210 fn add_custom_impl_keep_path() {
1212 replace_derive_with_manual_impl,
1214 //- minicore: clone, derive
1215 #[derive(std::fmt::Debug, Clo$0ne)]
1219 #[derive(std::fmt::Debug)]
1222 impl Clone for Foo {
1223 $0fn clone(&self) -> Self {
1232 fn add_custom_impl_replace_path() {
1234 replace_derive_with_manual_impl,
1236 //- minicore: fmt, derive
1237 #[derive(core::fmt::Deb$0ug, Clone)]
1244 impl core::fmt::Debug for Foo {
1245 $0fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1246 f.debug_struct("Foo").finish()