1 use hir::{InFile, ModuleDef};
3 helpers::mod_path_to_ast, imports::import_assets::NameToImport, items_locator,
4 syntax_helpers::insert_whitespace_into_node::insert_ws_into,
6 use itertools::Itertools;
8 ast::{self, AstNode, HasName},
9 SyntaxKind::WHITESPACE,
13 assist_context::{AssistContext, Assists, SourceChangeBuilder},
15 add_trait_assoc_items_to_impl, filter_assoc_items, gen_trait_fn_body,
16 generate_trait_impl_text, render_snippet, Cursor, DefaultMethods,
21 // Assist: replace_derive_with_manual_impl
23 // Converts a `derive` impl into a manual one.
26 // # //- minicore: derive
27 // # trait Debug { fn fmt(&self, f: &mut Formatter) -> Result<()>; }
28 // #[derive(Deb$0ug, Display)]
33 // # trait Debug { fn fmt(&self, f: &mut Formatter) -> Result<()>; }
38 // $0fn fmt(&self, f: &mut Formatter) -> Result<()> {
39 // f.debug_struct("S").finish()
43 pub(crate) fn replace_derive_with_manual_impl(
45 ctx: &AssistContext<'_>,
47 let attr = ctx.find_node_at_offset_with_descend::<ast::Attr>()?;
48 let path = attr.path()?;
49 let hir_file = ctx.sema.hir_file_for(attr.syntax());
50 if !hir_file.is_derive_attr_pseudo_expansion(ctx.db()) {
54 let InFile { file_id, value } = hir_file.call_node(ctx.db())?;
55 if file_id.is_macro() {
56 // FIXME: make this work in macro files
59 // collect the derive paths from the #[derive] expansion
60 let current_derives = ctx
62 .parse_or_expand(hir_file)?
64 .filter_map(ast::Attr::cast)
65 .filter_map(|attr| attr.path())
68 let adt = value.parent().and_then(ast::Adt::cast)?;
69 let attr = ast::Attr::cast(value)?;
70 let args = attr.token_tree()?;
72 let current_module = ctx.sema.scope(adt.syntax())?.module();
73 let current_crate = current_module.krate();
75 let found_traits = items_locator::items_with_name(
78 NameToImport::exact_case_sensitive(path.segments().last()?.to_string()),
79 items_locator::AssocItemSearch::Exclude,
80 Some(items_locator::DEFAULT_QUERY_SEARCH_LIMIT.inner()),
82 .filter_map(|item| match item.as_module_def()? {
83 ModuleDef::Trait(trait_) => Some(trait_),
88 .find_use_path(ctx.sema.db, hir::ModuleDef::Trait(trait_), ctx.config.prefer_no_std)
94 let mut no_traits_found = true;
95 for (replace_trait_path, trait_) in found_traits.inspect(|_| no_traits_found = false) {
109 add_assist(acc, ctx, &attr, ¤t_derives, &args, &path, &path, None, &adt)?;
116 ctx: &AssistContext<'_>,
118 old_derives: &[ast::Path],
119 old_tree: &ast::TokenTree,
120 old_trait_path: &ast::Path,
121 replace_trait_path: &ast::Path,
122 trait_: Option<hir::Trait>,
125 let target = attr.syntax().text_range();
126 let annotated_name = adt.name()?;
127 let label = format!("Convert to manual `impl {replace_trait_path} for {annotated_name}`");
130 AssistId("replace_derive_with_manual_impl", AssistKind::Refactor),
134 let insert_pos = adt.syntax().text_range().end();
135 let impl_def_with_items =
136 impl_def_from_trait(&ctx.sema, adt, &annotated_name, trait_, replace_trait_path);
137 update_attribute(builder, old_derives, old_tree, old_trait_path, attr);
138 let trait_path = replace_trait_path.to_string();
139 match (ctx.config.snippet_cap, impl_def_with_items) {
141 builder.insert(insert_pos, generate_trait_impl_text(adt, &trait_path, ""))
143 (Some(cap), None) => builder.insert_snippet(
146 generate_trait_impl_text(adt, &trait_path, " $0"),
148 (Some(cap), Some((impl_def, first_assoc_item))) => {
149 let mut cursor = Cursor::Before(first_assoc_item.syntax());
151 if let ast::AssocItem::Fn(ref func) = first_assoc_item {
152 if let Some(m) = func.syntax().descendants().find_map(ast::MacroCall::cast)
154 if m.syntax().text() == "todo!()" {
156 cursor = Cursor::Replace(placeholder.syntax());
161 let rendered = render_snippet(cap, impl_def.syntax(), cursor);
162 builder.insert_snippet(cap, insert_pos, format!("\n\n{rendered}"))
169 fn impl_def_from_trait(
170 sema: &hir::Semantics<'_, ide_db::RootDatabase>,
172 annotated_name: &ast::Name,
173 trait_: Option<hir::Trait>,
174 trait_path: &ast::Path,
175 ) -> Option<(ast::Impl, ast::AssocItem)> {
176 let trait_ = trait_?;
177 let target_scope = sema.scope(annotated_name.syntax())?;
178 let trait_items = filter_assoc_items(sema, &trait_.items(sema.db), DefaultMethods::No);
179 if trait_items.is_empty() {
183 use syntax::ast::Impl;
184 let text = generate_trait_impl_text(adt, trait_path.to_string().as_str(), "");
185 let parse = syntax::SourceFile::parse(&text);
186 let node = match parse.tree().syntax().descendants().find_map(Impl::cast) {
190 "Failed to make ast node `{}` from text {}",
191 std::any::type_name::<Impl>(),
196 let node = node.clone_subtree();
197 assert_eq!(node.syntax().text_range().start(), 0.into());
201 let trait_items = trait_items
204 if sema.hir_file_for(it.syntax()).is_macro() {
205 if let Some(it) = ast::AssocItem::cast(insert_ws_into(it.syntax().clone())) {
209 it.clone_for_update()
212 let (impl_def, first_assoc_item) =
213 add_trait_assoc_items_to_impl(sema, trait_items, trait_, impl_def, target_scope);
215 // Generate a default `impl` function body for the derived trait.
216 if let ast::AssocItem::Fn(ref func) = first_assoc_item {
217 let _ = gen_trait_fn_body(func, trait_path, adt);
220 Some((impl_def, first_assoc_item))
224 builder: &mut SourceChangeBuilder,
225 old_derives: &[ast::Path],
226 old_tree: &ast::TokenTree,
227 old_trait_path: &ast::Path,
230 let new_derives = old_derives
232 .filter(|t| t.to_string() != old_trait_path.to_string())
233 .collect::<Vec<_>>();
234 let has_more_derives = !new_derives.is_empty();
236 if has_more_derives {
237 let new_derives = format!("({})", new_derives.iter().format(", "));
238 builder.replace(old_tree.syntax().text_range(), new_derives);
240 let attr_range = attr.syntax().text_range();
241 builder.delete(attr_range);
243 if let Some(line_break_range) = attr
245 .next_sibling_or_token()
246 .filter(|t| t.kind() == WHITESPACE)
247 .map(|t| t.text_range())
249 builder.delete(line_break_range);
256 use crate::tests::{check_assist, check_assist_not_applicable};
261 fn add_custom_impl_debug_record_struct() {
263 replace_derive_with_manual_impl,
265 //- minicore: fmt, derive
276 impl core::fmt::Debug for Foo {
277 $0fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
278 f.debug_struct("Foo").field("bar", &self.bar).finish()
285 fn add_custom_impl_debug_tuple_struct() {
287 replace_derive_with_manual_impl,
289 //- minicore: fmt, derive
291 struct Foo(String, usize);
293 r#"struct Foo(String, usize);
295 impl core::fmt::Debug for Foo {
296 $0fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
297 f.debug_tuple("Foo").field(&self.0).field(&self.1).finish()
304 fn add_custom_impl_debug_empty_struct() {
306 replace_derive_with_manual_impl,
308 //- minicore: fmt, derive
315 impl core::fmt::Debug for Foo {
316 $0fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
317 f.debug_struct("Foo").finish()
324 fn add_custom_impl_debug_enum() {
326 replace_derive_with_manual_impl,
328 //- minicore: fmt, derive
341 impl core::fmt::Debug for Foo {
342 $0fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
344 Self::Bar => write!(f, "Bar"),
345 Self::Baz => write!(f, "Baz"),
354 fn add_custom_impl_debug_tuple_enum() {
356 replace_derive_with_manual_impl,
358 //- minicore: fmt, derive
371 impl core::fmt::Debug for Foo {
372 $0fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
374 Self::Bar(arg0, arg1) => f.debug_tuple("Bar").field(arg0).field(arg1).finish(),
375 Self::Baz => write!(f, "Baz"),
383 fn add_custom_impl_debug_record_enum() {
385 replace_derive_with_manual_impl,
387 //- minicore: fmt, derive
406 impl core::fmt::Debug for Foo {
407 $0fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
409 Self::Bar { baz, qux } => f.debug_struct("Bar").field("baz", baz).field("qux", qux).finish(),
410 Self::Baz => write!(f, "Baz"),
418 fn add_custom_impl_default_record_struct() {
420 replace_derive_with_manual_impl,
422 //- minicore: default, derive
433 impl Default for Foo {
434 $0fn default() -> Self {
435 Self { foo: Default::default() }
442 fn add_custom_impl_default_tuple_struct() {
444 replace_derive_with_manual_impl,
446 //- minicore: default, derive
453 impl Default for Foo {
454 $0fn default() -> Self {
455 Self(Default::default())
462 fn add_custom_impl_default_empty_struct() {
464 replace_derive_with_manual_impl,
466 //- minicore: default, derive
473 impl Default for Foo {
474 $0fn default() -> Self {
483 fn add_custom_impl_hash_record_struct() {
485 replace_derive_with_manual_impl,
487 //- minicore: hash, derive
500 impl core::hash::Hash for Foo {
501 $0fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
502 self.bin.hash(state);
503 self.bar.hash(state);
511 fn add_custom_impl_hash_tuple_struct() {
513 replace_derive_with_manual_impl,
515 //- minicore: hash, derive
517 struct Foo(usize, usize);
520 struct Foo(usize, usize);
522 impl core::hash::Hash for Foo {
523 $0fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
533 fn add_custom_impl_hash_enum() {
535 replace_derive_with_manual_impl,
537 //- minicore: hash, derive
550 impl core::hash::Hash for Foo {
551 $0fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
552 core::mem::discriminant(self).hash(state);
560 fn add_custom_impl_clone_record_struct() {
562 replace_derive_with_manual_impl,
564 //- minicore: clone, derive
578 $0fn clone(&self) -> Self {
579 Self { bin: self.bin.clone(), bar: self.bar.clone() }
587 fn add_custom_impl_clone_tuple_struct() {
589 replace_derive_with_manual_impl,
591 //- minicore: clone, derive
593 struct Foo(usize, usize);
596 struct Foo(usize, usize);
599 $0fn clone(&self) -> Self {
600 Self(self.0.clone(), self.1.clone())
608 fn add_custom_impl_clone_empty_struct() {
610 replace_derive_with_manual_impl,
612 //- minicore: clone, derive
620 $0fn clone(&self) -> Self {
629 fn add_custom_impl_clone_enum() {
631 replace_derive_with_manual_impl,
633 //- minicore: clone, derive
647 $0fn clone(&self) -> Self {
649 Self::Bar => Self::Bar,
650 Self::Baz => Self::Baz,
659 fn add_custom_impl_clone_tuple_enum() {
661 replace_derive_with_manual_impl,
663 //- minicore: clone, derive
677 $0fn clone(&self) -> Self {
679 Self::Bar(arg0) => Self::Bar(arg0.clone()),
680 Self::Baz => Self::Baz,
689 fn add_custom_impl_clone_record_enum() {
691 replace_derive_with_manual_impl,
693 //- minicore: clone, derive
711 $0fn clone(&self) -> Self {
713 Self::Bar { bin } => Self::Bar { bin: bin.clone() },
714 Self::Baz => Self::Baz,
723 fn add_custom_impl_partial_ord_record_struct() {
725 replace_derive_with_manual_impl,
727 //- minicore: ord, derive
728 #[derive(Partial$0Ord)]
738 impl PartialOrd for Foo {
739 $0fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
740 self.bin.partial_cmp(&other.bin)
748 fn add_custom_impl_partial_ord_record_struct_multi_field() {
750 replace_derive_with_manual_impl,
752 //- minicore: ord, derive
753 #[derive(Partial$0Ord)]
767 impl PartialOrd for Foo {
768 $0fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
769 match self.bin.partial_cmp(&other.bin) {
770 Some(core::cmp::Ordering::Equal) => {}
773 match self.bar.partial_cmp(&other.bar) {
774 Some(core::cmp::Ordering::Equal) => {}
777 self.baz.partial_cmp(&other.baz)
785 fn add_custom_impl_partial_ord_tuple_struct() {
787 replace_derive_with_manual_impl,
789 //- minicore: ord, derive
790 #[derive(Partial$0Ord)]
791 struct Foo(usize, usize, usize);
794 struct Foo(usize, usize, usize);
796 impl PartialOrd for Foo {
797 $0fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
798 match self.0.partial_cmp(&other.0) {
799 Some(core::cmp::Ordering::Equal) => {}
802 match self.1.partial_cmp(&other.1) {
803 Some(core::cmp::Ordering::Equal) => {}
806 self.2.partial_cmp(&other.2)
814 fn add_custom_impl_partial_eq_record_struct() {
816 replace_derive_with_manual_impl,
818 //- minicore: eq, derive
819 #[derive(Partial$0Eq)]
831 impl PartialEq for Foo {
832 $0fn eq(&self, other: &Self) -> bool {
833 self.bin == other.bin && self.bar == other.bar
841 fn add_custom_impl_partial_eq_tuple_struct() {
843 replace_derive_with_manual_impl,
845 //- minicore: eq, derive
846 #[derive(Partial$0Eq)]
847 struct Foo(usize, usize);
850 struct Foo(usize, usize);
852 impl PartialEq for Foo {
853 $0fn eq(&self, other: &Self) -> bool {
854 self.0 == other.0 && self.1 == other.1
862 fn add_custom_impl_partial_eq_empty_struct() {
864 replace_derive_with_manual_impl,
866 //- minicore: eq, derive
867 #[derive(Partial$0Eq)]
873 impl PartialEq for Foo {
874 $0fn eq(&self, other: &Self) -> bool {
883 fn add_custom_impl_partial_eq_enum() {
885 replace_derive_with_manual_impl,
887 //- minicore: eq, derive
888 #[derive(Partial$0Eq)]
900 impl PartialEq for Foo {
901 $0fn eq(&self, other: &Self) -> bool {
902 core::mem::discriminant(self) == core::mem::discriminant(other)
910 fn add_custom_impl_partial_eq_tuple_enum() {
912 replace_derive_with_manual_impl,
914 //- minicore: eq, derive
915 #[derive(Partial$0Eq)]
927 impl PartialEq for Foo {
928 $0fn eq(&self, other: &Self) -> bool {
929 match (self, other) {
930 (Self::Bar(l0), Self::Bar(r0)) => l0 == r0,
931 _ => core::mem::discriminant(self) == core::mem::discriminant(other),
940 fn add_custom_impl_partial_eq_record_enum() {
942 replace_derive_with_manual_impl,
944 //- minicore: eq, derive
945 #[derive(Partial$0Eq)]
971 impl PartialEq for Foo {
972 $0fn eq(&self, other: &Self) -> bool {
973 match (self, other) {
974 (Self::Bar { bin: l_bin }, Self::Bar { bin: r_bin }) => l_bin == r_bin,
975 (Self::Baz { qux: l_qux, fez: l_fez }, Self::Baz { qux: r_qux, fez: r_fez }) => l_qux == r_qux && l_fez == r_fez,
976 _ => core::mem::discriminant(self) == core::mem::discriminant(other),
984 fn add_custom_impl_all() {
986 replace_derive_with_manual_impl,
992 const Baz: usize = 42;
1008 const Baz: usize = 42;
1019 impl foo::Bar for Foo {
1032 fn add_custom_impl_for_unique_input_unknown() {
1034 replace_derive_with_manual_impl,
1036 //- minicore: derive
1047 impl Debug for Foo {
1055 fn add_custom_impl_for_with_visibility_modifier() {
1057 replace_derive_with_manual_impl,
1059 //- minicore: derive
1070 impl Debug for Foo {
1078 fn add_custom_impl_when_multiple_inputs() {
1080 replace_derive_with_manual_impl,
1082 //- minicore: derive
1083 #[derive(Display, Debug$0, Serialize)]
1087 #[derive(Display, Serialize)]
1090 impl Debug for Foo {
1098 fn add_custom_impl_default_generic_record_struct() {
1100 replace_derive_with_manual_impl,
1102 //- minicore: default, derive
1103 #[derive(Defau$0lt)]
1115 impl<T, U> Default for Foo<T, U> {
1116 $0fn default() -> Self {
1117 Self { foo: Default::default(), bar: Default::default() }
1125 fn add_custom_impl_clone_generic_tuple_struct_with_bounds() {
1127 replace_derive_with_manual_impl,
1129 //- minicore: clone, derive
1131 struct Foo<T: Clone>(T, usize);
1134 struct Foo<T: Clone>(T, usize);
1136 impl<T: Clone> Clone for Foo<T> {
1137 $0fn clone(&self) -> Self {
1138 Self(self.0.clone(), self.1.clone())
1146 fn test_ignore_derive_macro_without_input() {
1147 check_assist_not_applicable(
1148 replace_derive_with_manual_impl,
1150 //- minicore: derive
1158 fn test_ignore_if_cursor_on_param() {
1159 check_assist_not_applicable(
1160 replace_derive_with_manual_impl,
1162 //- minicore: derive, fmt
1168 check_assist_not_applicable(
1169 replace_derive_with_manual_impl,
1171 //- minicore: derive, fmt
1179 fn test_ignore_if_not_derive() {
1180 check_assist_not_applicable(
1181 replace_derive_with_manual_impl,
1183 //- minicore: derive
1184 #[allow(non_camel_$0case_types)]
1191 fn works_at_start_of_file() {
1192 check_assist_not_applicable(
1193 replace_derive_with_manual_impl,
1195 //- minicore: derive, fmt
1203 fn add_custom_impl_keep_path() {
1205 replace_derive_with_manual_impl,
1207 //- minicore: clone, derive
1208 #[derive(std::fmt::Debug, Clo$0ne)]
1212 #[derive(std::fmt::Debug)]
1215 impl Clone for Foo {
1216 $0fn clone(&self) -> Self {
1225 fn add_custom_impl_replace_path() {
1227 replace_derive_with_manual_impl,
1229 //- minicore: fmt, derive
1230 #[derive(core::fmt::Deb$0ug, Clone)]
1237 impl core::fmt::Debug for Foo {
1238 $0fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1239 f.debug_struct("Foo").finish()