• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use hir::{InFile, ModuleDef};
2 use ide_db::{helpers::mod_path_to_ast, imports::import_assets::NameToImport, items_locator};
3 use itertools::Itertools;
4 use syntax::{
5     ast::{self, AstNode, HasName},
6     SyntaxKind::WHITESPACE,
7 };
8 
9 use crate::{
10     assist_context::{AssistContext, Assists, SourceChangeBuilder},
11     utils::{
12         add_trait_assoc_items_to_impl, filter_assoc_items, gen_trait_fn_body,
13         generate_trait_impl_text, render_snippet, Cursor, DefaultMethods,
14     },
15     AssistId, AssistKind,
16 };
17 
18 // Assist: replace_derive_with_manual_impl
19 //
20 // Converts a `derive` impl into a manual one.
21 //
22 // ```
23 // # //- minicore: derive
24 // # trait Debug { fn fmt(&self, f: &mut Formatter) -> Result<()>; }
25 // #[derive(Deb$0ug, Display)]
26 // struct S;
27 // ```
28 // ->
29 // ```
30 // # trait Debug { fn fmt(&self, f: &mut Formatter) -> Result<()>; }
31 // #[derive(Display)]
32 // struct S;
33 //
34 // impl Debug for S {
35 //     $0fn fmt(&self, f: &mut Formatter) -> Result<()> {
36 //         f.debug_struct("S").finish()
37 //     }
38 // }
39 // ```
replace_derive_with_manual_impl( acc: &mut Assists, ctx: &AssistContext<'_>, ) -> Option<()>40 pub(crate) fn replace_derive_with_manual_impl(
41     acc: &mut Assists,
42     ctx: &AssistContext<'_>,
43 ) -> Option<()> {
44     let attr = ctx.find_node_at_offset_with_descend::<ast::Attr>()?;
45     let path = attr.path()?;
46     let hir_file = ctx.sema.hir_file_for(attr.syntax());
47     if !hir_file.is_derive_attr_pseudo_expansion(ctx.db()) {
48         return None;
49     }
50 
51     let InFile { file_id, value } = hir_file.call_node(ctx.db())?;
52     if file_id.is_macro() {
53         // FIXME: make this work in macro files
54         return None;
55     }
56     // collect the derive paths from the #[derive] expansion
57     let current_derives = ctx
58         .sema
59         .parse_or_expand(hir_file)
60         .descendants()
61         .filter_map(ast::Attr::cast)
62         .filter_map(|attr| attr.path())
63         .collect::<Vec<_>>();
64 
65     let adt = value.parent().and_then(ast::Adt::cast)?;
66     let attr = ast::Attr::cast(value)?;
67     let args = attr.token_tree()?;
68 
69     let current_module = ctx.sema.scope(adt.syntax())?.module();
70     let current_crate = current_module.krate();
71 
72     let found_traits = items_locator::items_with_name(
73         &ctx.sema,
74         current_crate,
75         NameToImport::exact_case_sensitive(path.segments().last()?.to_string()),
76         items_locator::AssocItemSearch::Exclude,
77         Some(items_locator::DEFAULT_QUERY_SEARCH_LIMIT.inner()),
78     )
79     .filter_map(|item| match item.as_module_def()? {
80         ModuleDef::Trait(trait_) => Some(trait_),
81         _ => None,
82     })
83     .flat_map(|trait_| {
84         current_module
85             .find_use_path(ctx.sema.db, hir::ModuleDef::Trait(trait_), ctx.config.prefer_no_std)
86             .as_ref()
87             .map(mod_path_to_ast)
88             .zip(Some(trait_))
89     });
90 
91     let mut no_traits_found = true;
92     for (replace_trait_path, trait_) in found_traits.inspect(|_| no_traits_found = false) {
93         add_assist(
94             acc,
95             ctx,
96             &attr,
97             &current_derives,
98             &args,
99             &path,
100             &replace_trait_path,
101             Some(trait_),
102             &adt,
103         )?;
104     }
105     if no_traits_found {
106         add_assist(acc, ctx, &attr, &current_derives, &args, &path, &path, None, &adt)?;
107     }
108     Some(())
109 }
110 
add_assist( acc: &mut Assists, ctx: &AssistContext<'_>, attr: &ast::Attr, old_derives: &[ast::Path], old_tree: &ast::TokenTree, old_trait_path: &ast::Path, replace_trait_path: &ast::Path, trait_: Option<hir::Trait>, adt: &ast::Adt, ) -> Option<()>111 fn add_assist(
112     acc: &mut Assists,
113     ctx: &AssistContext<'_>,
114     attr: &ast::Attr,
115     old_derives: &[ast::Path],
116     old_tree: &ast::TokenTree,
117     old_trait_path: &ast::Path,
118     replace_trait_path: &ast::Path,
119     trait_: Option<hir::Trait>,
120     adt: &ast::Adt,
121 ) -> Option<()> {
122     let target = attr.syntax().text_range();
123     let annotated_name = adt.name()?;
124     let label = format!("Convert to manual `impl {replace_trait_path} for {annotated_name}`");
125 
126     acc.add(
127         AssistId("replace_derive_with_manual_impl", AssistKind::Refactor),
128         label,
129         target,
130         |builder| {
131             let insert_pos = adt.syntax().text_range().end();
132             let impl_def_with_items =
133                 impl_def_from_trait(&ctx.sema, adt, &annotated_name, trait_, replace_trait_path);
134             update_attribute(builder, old_derives, old_tree, old_trait_path, attr);
135             let trait_path = replace_trait_path.to_string();
136             match (ctx.config.snippet_cap, impl_def_with_items) {
137                 (None, _) => {
138                     builder.insert(insert_pos, generate_trait_impl_text(adt, &trait_path, ""))
139                 }
140                 (Some(cap), None) => builder.insert_snippet(
141                     cap,
142                     insert_pos,
143                     generate_trait_impl_text(adt, &trait_path, "    $0"),
144                 ),
145                 (Some(cap), Some((impl_def, first_assoc_item))) => {
146                     let mut cursor = Cursor::Before(first_assoc_item.syntax());
147                     let placeholder;
148                     if let ast::AssocItem::Fn(ref func) = first_assoc_item {
149                         if let Some(m) = func.syntax().descendants().find_map(ast::MacroCall::cast)
150                         {
151                             if m.syntax().text() == "todo!()" {
152                                 placeholder = m;
153                                 cursor = Cursor::Replace(placeholder.syntax());
154                             }
155                         }
156                     }
157 
158                     let rendered = render_snippet(cap, impl_def.syntax(), cursor);
159                     builder.insert_snippet(cap, insert_pos, format!("\n\n{rendered}"))
160                 }
161             };
162         },
163     )
164 }
165 
impl_def_from_trait( sema: &hir::Semantics<'_, ide_db::RootDatabase>, adt: &ast::Adt, annotated_name: &ast::Name, trait_: Option<hir::Trait>, trait_path: &ast::Path, ) -> Option<(ast::Impl, ast::AssocItem)>166 fn impl_def_from_trait(
167     sema: &hir::Semantics<'_, ide_db::RootDatabase>,
168     adt: &ast::Adt,
169     annotated_name: &ast::Name,
170     trait_: Option<hir::Trait>,
171     trait_path: &ast::Path,
172 ) -> Option<(ast::Impl, ast::AssocItem)> {
173     let trait_ = trait_?;
174     let target_scope = sema.scope(annotated_name.syntax())?;
175     let trait_items = filter_assoc_items(sema, &trait_.items(sema.db), DefaultMethods::No);
176     if trait_items.is_empty() {
177         return None;
178     }
179     let impl_def = {
180         use syntax::ast::Impl;
181         let text = generate_trait_impl_text(adt, trait_path.to_string().as_str(), "");
182         // FIXME: `generate_trait_impl_text` currently generates two newlines
183         // at the front, but these leading newlines should really instead be
184         // inserted at the same time the impl is inserted
185         assert_eq!(&text[..2], "\n\n", "`generate_trait_impl_text` output changed");
186         let parse = syntax::SourceFile::parse(&text[2..]);
187         let node = match parse.tree().syntax().descendants().find_map(Impl::cast) {
188             Some(it) => it,
189             None => {
190                 panic!(
191                     "Failed to make ast node `{}` from text {}",
192                     std::any::type_name::<Impl>(),
193                     text
194                 )
195             }
196         };
197         let node = node.clone_for_update();
198         assert_eq!(node.syntax().text_range().start(), 0.into());
199         node
200     };
201 
202     let first_assoc_item =
203         add_trait_assoc_items_to_impl(sema, &trait_items, trait_, &impl_def, target_scope);
204 
205     // Generate a default `impl` function body for the derived trait.
206     if let ast::AssocItem::Fn(ref func) = first_assoc_item {
207         let _ = gen_trait_fn_body(func, trait_path, adt, None);
208     };
209 
210     Some((impl_def, first_assoc_item))
211 }
212 
update_attribute( builder: &mut SourceChangeBuilder, old_derives: &[ast::Path], old_tree: &ast::TokenTree, old_trait_path: &ast::Path, attr: &ast::Attr, )213 fn update_attribute(
214     builder: &mut SourceChangeBuilder,
215     old_derives: &[ast::Path],
216     old_tree: &ast::TokenTree,
217     old_trait_path: &ast::Path,
218     attr: &ast::Attr,
219 ) {
220     let new_derives = old_derives
221         .iter()
222         .filter(|t| t.to_string() != old_trait_path.to_string())
223         .collect::<Vec<_>>();
224     let has_more_derives = !new_derives.is_empty();
225 
226     if has_more_derives {
227         let new_derives = format!("({})", new_derives.iter().format(", "));
228         builder.replace(old_tree.syntax().text_range(), new_derives);
229     } else {
230         let attr_range = attr.syntax().text_range();
231         builder.delete(attr_range);
232 
233         if let Some(line_break_range) = attr
234             .syntax()
235             .next_sibling_or_token()
236             .filter(|t| t.kind() == WHITESPACE)
237             .map(|t| t.text_range())
238         {
239             builder.delete(line_break_range);
240         }
241     }
242 }
243 
244 #[cfg(test)]
245 mod tests {
246     use crate::tests::{check_assist, check_assist_not_applicable};
247 
248     use super::*;
249 
250     #[test]
add_custom_impl_debug_record_struct()251     fn add_custom_impl_debug_record_struct() {
252         check_assist(
253             replace_derive_with_manual_impl,
254             r#"
255 //- minicore: fmt, derive
256 #[derive(Debu$0g)]
257 struct Foo {
258     bar: String,
259 }
260 "#,
261             r#"
262 struct Foo {
263     bar: String,
264 }
265 
266 impl core::fmt::Debug for Foo {
267     $0fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
268         f.debug_struct("Foo").field("bar", &self.bar).finish()
269     }
270 }
271 "#,
272         )
273     }
274     #[test]
add_custom_impl_debug_tuple_struct()275     fn add_custom_impl_debug_tuple_struct() {
276         check_assist(
277             replace_derive_with_manual_impl,
278             r#"
279 //- minicore: fmt, derive
280 #[derive(Debu$0g)]
281 struct Foo(String, usize);
282 "#,
283             r#"struct Foo(String, usize);
284 
285 impl core::fmt::Debug for Foo {
286     $0fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
287         f.debug_tuple("Foo").field(&self.0).field(&self.1).finish()
288     }
289 }
290 "#,
291         )
292     }
293     #[test]
add_custom_impl_debug_empty_struct()294     fn add_custom_impl_debug_empty_struct() {
295         check_assist(
296             replace_derive_with_manual_impl,
297             r#"
298 //- minicore: fmt, derive
299 #[derive(Debu$0g)]
300 struct Foo;
301 "#,
302             r#"
303 struct Foo;
304 
305 impl core::fmt::Debug for Foo {
306     $0fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
307         f.debug_struct("Foo").finish()
308     }
309 }
310 "#,
311         )
312     }
313     #[test]
add_custom_impl_debug_enum()314     fn add_custom_impl_debug_enum() {
315         check_assist(
316             replace_derive_with_manual_impl,
317             r#"
318 //- minicore: fmt, derive
319 #[derive(Debu$0g)]
320 enum Foo {
321     Bar,
322     Baz,
323 }
324 "#,
325             r#"
326 enum Foo {
327     Bar,
328     Baz,
329 }
330 
331 impl core::fmt::Debug for Foo {
332     $0fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
333         match self {
334             Self::Bar => write!(f, "Bar"),
335             Self::Baz => write!(f, "Baz"),
336         }
337     }
338 }
339 "#,
340         )
341     }
342 
343     #[test]
add_custom_impl_debug_tuple_enum()344     fn add_custom_impl_debug_tuple_enum() {
345         check_assist(
346             replace_derive_with_manual_impl,
347             r#"
348 //- minicore: fmt, derive
349 #[derive(Debu$0g)]
350 enum Foo {
351     Bar(usize, usize),
352     Baz,
353 }
354 "#,
355             r#"
356 enum Foo {
357     Bar(usize, usize),
358     Baz,
359 }
360 
361 impl core::fmt::Debug for Foo {
362     $0fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
363         match self {
364             Self::Bar(arg0, arg1) => f.debug_tuple("Bar").field(arg0).field(arg1).finish(),
365             Self::Baz => write!(f, "Baz"),
366         }
367     }
368 }
369 "#,
370         )
371     }
372     #[test]
add_custom_impl_debug_record_enum()373     fn add_custom_impl_debug_record_enum() {
374         check_assist(
375             replace_derive_with_manual_impl,
376             r#"
377 //- minicore: fmt, derive
378 #[derive(Debu$0g)]
379 enum Foo {
380     Bar {
381         baz: usize,
382         qux: usize,
383     },
384     Baz,
385 }
386 "#,
387             r#"
388 enum Foo {
389     Bar {
390         baz: usize,
391         qux: usize,
392     },
393     Baz,
394 }
395 
396 impl core::fmt::Debug for Foo {
397     $0fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
398         match self {
399             Self::Bar { baz, qux } => f.debug_struct("Bar").field("baz", baz).field("qux", qux).finish(),
400             Self::Baz => write!(f, "Baz"),
401         }
402     }
403 }
404 "#,
405         )
406     }
407     #[test]
add_custom_impl_default_record_struct()408     fn add_custom_impl_default_record_struct() {
409         check_assist(
410             replace_derive_with_manual_impl,
411             r#"
412 //- minicore: default, derive
413 #[derive(Defau$0lt)]
414 struct Foo {
415     foo: usize,
416 }
417 "#,
418             r#"
419 struct Foo {
420     foo: usize,
421 }
422 
423 impl Default for Foo {
424     $0fn default() -> Self {
425         Self { foo: Default::default() }
426     }
427 }
428 "#,
429         )
430     }
431     #[test]
add_custom_impl_default_tuple_struct()432     fn add_custom_impl_default_tuple_struct() {
433         check_assist(
434             replace_derive_with_manual_impl,
435             r#"
436 //- minicore: default, derive
437 #[derive(Defau$0lt)]
438 struct Foo(usize);
439 "#,
440             r#"
441 struct Foo(usize);
442 
443 impl Default for Foo {
444     $0fn default() -> Self {
445         Self(Default::default())
446     }
447 }
448 "#,
449         )
450     }
451     #[test]
add_custom_impl_default_empty_struct()452     fn add_custom_impl_default_empty_struct() {
453         check_assist(
454             replace_derive_with_manual_impl,
455             r#"
456 //- minicore: default, derive
457 #[derive(Defau$0lt)]
458 struct Foo;
459 "#,
460             r#"
461 struct Foo;
462 
463 impl Default for Foo {
464     $0fn default() -> Self {
465         Self {  }
466     }
467 }
468 "#,
469         )
470     }
471 
472     #[test]
add_custom_impl_hash_record_struct()473     fn add_custom_impl_hash_record_struct() {
474         check_assist(
475             replace_derive_with_manual_impl,
476             r#"
477 //- minicore: hash, derive
478 #[derive(Has$0h)]
479 struct Foo {
480     bin: usize,
481     bar: usize,
482 }
483 "#,
484             r#"
485 struct Foo {
486     bin: usize,
487     bar: usize,
488 }
489 
490 impl core::hash::Hash for Foo {
491     $0fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
492         self.bin.hash(state);
493         self.bar.hash(state);
494     }
495 }
496 "#,
497         )
498     }
499 
500     #[test]
add_custom_impl_hash_tuple_struct()501     fn add_custom_impl_hash_tuple_struct() {
502         check_assist(
503             replace_derive_with_manual_impl,
504             r#"
505 //- minicore: hash, derive
506 #[derive(Has$0h)]
507 struct Foo(usize, usize);
508 "#,
509             r#"
510 struct Foo(usize, usize);
511 
512 impl core::hash::Hash for Foo {
513     $0fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
514         self.0.hash(state);
515         self.1.hash(state);
516     }
517 }
518 "#,
519         )
520     }
521 
522     #[test]
add_custom_impl_hash_enum()523     fn add_custom_impl_hash_enum() {
524         check_assist(
525             replace_derive_with_manual_impl,
526             r#"
527 //- minicore: hash, derive
528 #[derive(Has$0h)]
529 enum Foo {
530     Bar,
531     Baz,
532 }
533 "#,
534             r#"
535 enum Foo {
536     Bar,
537     Baz,
538 }
539 
540 impl core::hash::Hash for Foo {
541     $0fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
542         core::mem::discriminant(self).hash(state);
543     }
544 }
545 "#,
546         )
547     }
548 
549     #[test]
add_custom_impl_clone_record_struct()550     fn add_custom_impl_clone_record_struct() {
551         check_assist(
552             replace_derive_with_manual_impl,
553             r#"
554 //- minicore: clone, derive
555 #[derive(Clo$0ne)]
556 struct Foo {
557     bin: usize,
558     bar: usize,
559 }
560 "#,
561             r#"
562 struct Foo {
563     bin: usize,
564     bar: usize,
565 }
566 
567 impl Clone for Foo {
568     $0fn clone(&self) -> Self {
569         Self { bin: self.bin.clone(), bar: self.bar.clone() }
570     }
571 }
572 "#,
573         )
574     }
575 
576     #[test]
add_custom_impl_clone_tuple_struct()577     fn add_custom_impl_clone_tuple_struct() {
578         check_assist(
579             replace_derive_with_manual_impl,
580             r#"
581 //- minicore: clone, derive
582 #[derive(Clo$0ne)]
583 struct Foo(usize, usize);
584 "#,
585             r#"
586 struct Foo(usize, usize);
587 
588 impl Clone for Foo {
589     $0fn clone(&self) -> Self {
590         Self(self.0.clone(), self.1.clone())
591     }
592 }
593 "#,
594         )
595     }
596 
597     #[test]
add_custom_impl_clone_empty_struct()598     fn add_custom_impl_clone_empty_struct() {
599         check_assist(
600             replace_derive_with_manual_impl,
601             r#"
602 //- minicore: clone, derive
603 #[derive(Clo$0ne)]
604 struct Foo;
605 "#,
606             r#"
607 struct Foo;
608 
609 impl Clone for Foo {
610     $0fn clone(&self) -> Self {
611         Self {  }
612     }
613 }
614 "#,
615         )
616     }
617 
618     #[test]
add_custom_impl_clone_enum()619     fn add_custom_impl_clone_enum() {
620         check_assist(
621             replace_derive_with_manual_impl,
622             r#"
623 //- minicore: clone, derive
624 #[derive(Clo$0ne)]
625 enum Foo {
626     Bar,
627     Baz,
628 }
629 "#,
630             r#"
631 enum Foo {
632     Bar,
633     Baz,
634 }
635 
636 impl Clone for Foo {
637     $0fn clone(&self) -> Self {
638         match self {
639             Self::Bar => Self::Bar,
640             Self::Baz => Self::Baz,
641         }
642     }
643 }
644 "#,
645         )
646     }
647 
648     #[test]
add_custom_impl_clone_tuple_enum()649     fn add_custom_impl_clone_tuple_enum() {
650         check_assist(
651             replace_derive_with_manual_impl,
652             r#"
653 //- minicore: clone, derive
654 #[derive(Clo$0ne)]
655 enum Foo {
656     Bar(String),
657     Baz,
658 }
659 "#,
660             r#"
661 enum Foo {
662     Bar(String),
663     Baz,
664 }
665 
666 impl Clone for Foo {
667     $0fn clone(&self) -> Self {
668         match self {
669             Self::Bar(arg0) => Self::Bar(arg0.clone()),
670             Self::Baz => Self::Baz,
671         }
672     }
673 }
674 "#,
675         )
676     }
677 
678     #[test]
add_custom_impl_clone_record_enum()679     fn add_custom_impl_clone_record_enum() {
680         check_assist(
681             replace_derive_with_manual_impl,
682             r#"
683 //- minicore: clone, derive
684 #[derive(Clo$0ne)]
685 enum Foo {
686     Bar {
687         bin: String,
688     },
689     Baz,
690 }
691 "#,
692             r#"
693 enum Foo {
694     Bar {
695         bin: String,
696     },
697     Baz,
698 }
699 
700 impl Clone for Foo {
701     $0fn clone(&self) -> Self {
702         match self {
703             Self::Bar { bin } => Self::Bar { bin: bin.clone() },
704             Self::Baz => Self::Baz,
705         }
706     }
707 }
708 "#,
709         )
710     }
711 
712     #[test]
add_custom_impl_partial_ord_record_struct()713     fn add_custom_impl_partial_ord_record_struct() {
714         check_assist(
715             replace_derive_with_manual_impl,
716             r#"
717 //- minicore: ord, derive
718 #[derive(Partial$0Ord)]
719 struct Foo {
720     bin: usize,
721 }
722 "#,
723             r#"
724 struct Foo {
725     bin: usize,
726 }
727 
728 impl PartialOrd for Foo {
729     $0fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
730         self.bin.partial_cmp(&other.bin)
731     }
732 }
733 "#,
734         )
735     }
736 
737     #[test]
add_custom_impl_partial_ord_record_struct_multi_field()738     fn add_custom_impl_partial_ord_record_struct_multi_field() {
739         check_assist(
740             replace_derive_with_manual_impl,
741             r#"
742 //- minicore: ord, derive
743 #[derive(Partial$0Ord)]
744 struct Foo {
745     bin: usize,
746     bar: usize,
747     baz: usize,
748 }
749 "#,
750             r#"
751 struct Foo {
752     bin: usize,
753     bar: usize,
754     baz: usize,
755 }
756 
757 impl PartialOrd for Foo {
758     $0fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
759         match self.bin.partial_cmp(&other.bin) {
760             Some(core::cmp::Ordering::Equal) => {}
761             ord => return ord,
762         }
763         match self.bar.partial_cmp(&other.bar) {
764             Some(core::cmp::Ordering::Equal) => {}
765             ord => return ord,
766         }
767         self.baz.partial_cmp(&other.baz)
768     }
769 }
770 "#,
771         )
772     }
773 
774     #[test]
add_custom_impl_partial_ord_tuple_struct()775     fn add_custom_impl_partial_ord_tuple_struct() {
776         check_assist(
777             replace_derive_with_manual_impl,
778             r#"
779 //- minicore: ord, derive
780 #[derive(Partial$0Ord)]
781 struct Foo(usize, usize, usize);
782 "#,
783             r#"
784 struct Foo(usize, usize, usize);
785 
786 impl PartialOrd for Foo {
787     $0fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
788         match self.0.partial_cmp(&other.0) {
789             Some(core::cmp::Ordering::Equal) => {}
790             ord => return ord,
791         }
792         match self.1.partial_cmp(&other.1) {
793             Some(core::cmp::Ordering::Equal) => {}
794             ord => return ord,
795         }
796         self.2.partial_cmp(&other.2)
797     }
798 }
799 "#,
800         )
801     }
802 
803     #[test]
add_custom_impl_partial_eq_record_struct()804     fn add_custom_impl_partial_eq_record_struct() {
805         check_assist(
806             replace_derive_with_manual_impl,
807             r#"
808 //- minicore: eq, derive
809 #[derive(Partial$0Eq)]
810 struct Foo {
811     bin: usize,
812     bar: usize,
813 }
814 "#,
815             r#"
816 struct Foo {
817     bin: usize,
818     bar: usize,
819 }
820 
821 impl PartialEq for Foo {
822     $0fn eq(&self, other: &Self) -> bool {
823         self.bin == other.bin && self.bar == other.bar
824     }
825 }
826 "#,
827         )
828     }
829 
830     #[test]
add_custom_impl_partial_eq_tuple_struct()831     fn add_custom_impl_partial_eq_tuple_struct() {
832         check_assist(
833             replace_derive_with_manual_impl,
834             r#"
835 //- minicore: eq, derive
836 #[derive(Partial$0Eq)]
837 struct Foo(usize, usize);
838 "#,
839             r#"
840 struct Foo(usize, usize);
841 
842 impl PartialEq for Foo {
843     $0fn eq(&self, other: &Self) -> bool {
844         self.0 == other.0 && self.1 == other.1
845     }
846 }
847 "#,
848         )
849     }
850 
851     #[test]
add_custom_impl_partial_eq_empty_struct()852     fn add_custom_impl_partial_eq_empty_struct() {
853         check_assist(
854             replace_derive_with_manual_impl,
855             r#"
856 //- minicore: eq, derive
857 #[derive(Partial$0Eq)]
858 struct Foo;
859 "#,
860             r#"
861 struct Foo;
862 
863 impl PartialEq for Foo {
864     $0fn eq(&self, other: &Self) -> bool {
865         true
866     }
867 }
868 "#,
869         )
870     }
871 
872     #[test]
add_custom_impl_partial_eq_enum()873     fn add_custom_impl_partial_eq_enum() {
874         check_assist(
875             replace_derive_with_manual_impl,
876             r#"
877 //- minicore: eq, derive
878 #[derive(Partial$0Eq)]
879 enum Foo {
880     Bar,
881     Baz,
882 }
883 "#,
884             r#"
885 enum Foo {
886     Bar,
887     Baz,
888 }
889 
890 impl PartialEq for Foo {
891     $0fn eq(&self, other: &Self) -> bool {
892         core::mem::discriminant(self) == core::mem::discriminant(other)
893     }
894 }
895 "#,
896         )
897     }
898 
899     #[test]
add_custom_impl_partial_eq_single_variant_tuple_enum()900     fn add_custom_impl_partial_eq_single_variant_tuple_enum() {
901         check_assist(
902             replace_derive_with_manual_impl,
903             r#"
904 //- minicore: eq, derive
905 #[derive(Partial$0Eq)]
906 enum Foo {
907     Bar(String),
908 }
909 "#,
910             r#"
911 enum Foo {
912     Bar(String),
913 }
914 
915 impl PartialEq for Foo {
916     $0fn eq(&self, other: &Self) -> bool {
917         match (self, other) {
918             (Self::Bar(l0), Self::Bar(r0)) => l0 == r0,
919         }
920     }
921 }
922 "#,
923         )
924     }
925 
926     #[test]
add_custom_impl_partial_eq_partial_tuple_enum()927     fn add_custom_impl_partial_eq_partial_tuple_enum() {
928         check_assist(
929             replace_derive_with_manual_impl,
930             r#"
931 //- minicore: eq, derive
932 #[derive(Partial$0Eq)]
933 enum Foo {
934     Bar(String),
935     Baz,
936 }
937 "#,
938             r#"
939 enum Foo {
940     Bar(String),
941     Baz,
942 }
943 
944 impl PartialEq for Foo {
945     $0fn eq(&self, other: &Self) -> bool {
946         match (self, other) {
947             (Self::Bar(l0), Self::Bar(r0)) => l0 == r0,
948             _ => core::mem::discriminant(self) == core::mem::discriminant(other),
949         }
950     }
951 }
952 "#,
953         )
954     }
955 
956     #[test]
add_custom_impl_partial_eq_tuple_enum()957     fn add_custom_impl_partial_eq_tuple_enum() {
958         check_assist(
959             replace_derive_with_manual_impl,
960             r#"
961 //- minicore: eq, derive
962 #[derive(Partial$0Eq)]
963 enum Foo {
964     Bar(String),
965     Baz(i32),
966 }
967 "#,
968             r#"
969 enum Foo {
970     Bar(String),
971     Baz(i32),
972 }
973 
974 impl PartialEq for Foo {
975     $0fn eq(&self, other: &Self) -> bool {
976         match (self, other) {
977             (Self::Bar(l0), Self::Bar(r0)) => l0 == r0,
978             (Self::Baz(l0), Self::Baz(r0)) => l0 == r0,
979             _ => false,
980         }
981     }
982 }
983 "#,
984         )
985     }
986 
987     #[test]
add_custom_impl_partial_eq_tuple_enum_generic()988     fn add_custom_impl_partial_eq_tuple_enum_generic() {
989         check_assist(
990             replace_derive_with_manual_impl,
991             r#"
992 //- minicore: eq, derive
993 #[derive(Partial$0Eq)]
994 enum Either<T, U> {
995     Left(T),
996     Right(U),
997 }
998 "#,
999             r#"
1000 enum Either<T, U> {
1001     Left(T),
1002     Right(U),
1003 }
1004 
1005 impl<T: PartialEq, U: PartialEq> PartialEq for Either<T, U> {
1006     $0fn eq(&self, other: &Self) -> bool {
1007         match (self, other) {
1008             (Self::Left(l0), Self::Left(r0)) => l0 == r0,
1009             (Self::Right(l0), Self::Right(r0)) => l0 == r0,
1010             _ => false,
1011         }
1012     }
1013 }
1014 "#,
1015         )
1016     }
1017 
1018     #[test]
add_custom_impl_partial_eq_tuple_enum_generic_existing_bounds()1019     fn add_custom_impl_partial_eq_tuple_enum_generic_existing_bounds() {
1020         check_assist(
1021             replace_derive_with_manual_impl,
1022             r#"
1023 //- minicore: eq, derive
1024 #[derive(Partial$0Eq)]
1025 enum Either<T: PartialEq + Error, U: Clone> {
1026     Left(T),
1027     Right(U),
1028 }
1029 "#,
1030             r#"
1031 enum Either<T: PartialEq + Error, U: Clone> {
1032     Left(T),
1033     Right(U),
1034 }
1035 
1036 impl<T: PartialEq + Error, U: Clone + PartialEq> PartialEq for Either<T, U> {
1037     $0fn eq(&self, other: &Self) -> bool {
1038         match (self, other) {
1039             (Self::Left(l0), Self::Left(r0)) => l0 == r0,
1040             (Self::Right(l0), Self::Right(r0)) => l0 == r0,
1041             _ => false,
1042         }
1043     }
1044 }
1045 "#,
1046         )
1047     }
1048 
1049     #[test]
add_custom_impl_partial_eq_record_enum()1050     fn add_custom_impl_partial_eq_record_enum() {
1051         check_assist(
1052             replace_derive_with_manual_impl,
1053             r#"
1054 //- minicore: eq, derive
1055 #[derive(Partial$0Eq)]
1056 enum Foo {
1057     Bar {
1058         bin: String,
1059     },
1060     Baz {
1061         qux: String,
1062         fez: String,
1063     },
1064     Qux {},
1065     Bin,
1066 }
1067 "#,
1068             r#"
1069 enum Foo {
1070     Bar {
1071         bin: String,
1072     },
1073     Baz {
1074         qux: String,
1075         fez: String,
1076     },
1077     Qux {},
1078     Bin,
1079 }
1080 
1081 impl PartialEq for Foo {
1082     $0fn eq(&self, other: &Self) -> bool {
1083         match (self, other) {
1084             (Self::Bar { bin: l_bin }, Self::Bar { bin: r_bin }) => l_bin == r_bin,
1085             (Self::Baz { qux: l_qux, fez: l_fez }, Self::Baz { qux: r_qux, fez: r_fez }) => l_qux == r_qux && l_fez == r_fez,
1086             _ => core::mem::discriminant(self) == core::mem::discriminant(other),
1087         }
1088     }
1089 }
1090 "#,
1091         )
1092     }
1093     #[test]
add_custom_impl_all()1094     fn add_custom_impl_all() {
1095         check_assist(
1096             replace_derive_with_manual_impl,
1097             r#"
1098 //- minicore: derive
1099 mod foo {
1100     pub trait Bar {
1101         type Qux;
1102         const Baz: usize = 42;
1103         const Fez: usize;
1104         fn foo();
1105         fn bar() {}
1106     }
1107 }
1108 
1109 #[derive($0Bar)]
1110 struct Foo {
1111     bar: String,
1112 }
1113 "#,
1114             r#"
1115 mod foo {
1116     pub trait Bar {
1117         type Qux;
1118         const Baz: usize = 42;
1119         const Fez: usize;
1120         fn foo();
1121         fn bar() {}
1122     }
1123 }
1124 
1125 struct Foo {
1126     bar: String,
1127 }
1128 
1129 impl foo::Bar for Foo {
1130     $0type Qux;
1131 
1132     const Fez: usize;
1133 
1134     fn foo() {
1135         todo!()
1136     }
1137 }
1138 "#,
1139         )
1140     }
1141     #[test]
add_custom_impl_for_unique_input_unknown()1142     fn add_custom_impl_for_unique_input_unknown() {
1143         check_assist(
1144             replace_derive_with_manual_impl,
1145             r#"
1146 //- minicore: derive
1147 #[derive(Debu$0g)]
1148 struct Foo {
1149     bar: String,
1150 }
1151             "#,
1152             r#"
1153 struct Foo {
1154     bar: String,
1155 }
1156 
1157 impl Debug for Foo {
1158     $0
1159 }
1160             "#,
1161         )
1162     }
1163 
1164     #[test]
add_custom_impl_for_with_visibility_modifier()1165     fn add_custom_impl_for_with_visibility_modifier() {
1166         check_assist(
1167             replace_derive_with_manual_impl,
1168             r#"
1169 //- minicore: derive
1170 #[derive(Debug$0)]
1171 pub struct Foo {
1172     bar: String,
1173 }
1174             "#,
1175             r#"
1176 pub struct Foo {
1177     bar: String,
1178 }
1179 
1180 impl Debug for Foo {
1181     $0
1182 }
1183             "#,
1184         )
1185     }
1186 
1187     #[test]
add_custom_impl_when_multiple_inputs()1188     fn add_custom_impl_when_multiple_inputs() {
1189         check_assist(
1190             replace_derive_with_manual_impl,
1191             r#"
1192 //- minicore: derive
1193 #[derive(Display, Debug$0, Serialize)]
1194 struct Foo {}
1195             "#,
1196             r#"
1197 #[derive(Display, Serialize)]
1198 struct Foo {}
1199 
1200 impl Debug for Foo {
1201     $0
1202 }
1203             "#,
1204         )
1205     }
1206 
1207     #[test]
add_custom_impl_default_generic_record_struct()1208     fn add_custom_impl_default_generic_record_struct() {
1209         check_assist(
1210             replace_derive_with_manual_impl,
1211             r#"
1212 //- minicore: default, derive
1213 #[derive(Defau$0lt)]
1214 struct Foo<T, U> {
1215     foo: T,
1216     bar: U,
1217 }
1218 "#,
1219             r#"
1220 struct Foo<T, U> {
1221     foo: T,
1222     bar: U,
1223 }
1224 
1225 impl<T: Default, U: Default> Default for Foo<T, U> {
1226     $0fn default() -> Self {
1227         Self { foo: Default::default(), bar: Default::default() }
1228     }
1229 }
1230 "#,
1231         )
1232     }
1233 
1234     #[test]
add_custom_impl_clone_generic_tuple_struct_with_bounds()1235     fn add_custom_impl_clone_generic_tuple_struct_with_bounds() {
1236         check_assist(
1237             replace_derive_with_manual_impl,
1238             r#"
1239 //- minicore: clone, derive
1240 #[derive(Clo$0ne)]
1241 struct Foo<T: Clone>(T, usize);
1242 "#,
1243             r#"
1244 struct Foo<T: Clone>(T, usize);
1245 
1246 impl<T: Clone> Clone for Foo<T> {
1247     $0fn clone(&self) -> Self {
1248         Self(self.0.clone(), self.1.clone())
1249     }
1250 }
1251 "#,
1252         )
1253     }
1254 
1255     #[test]
test_ignore_derive_macro_without_input()1256     fn test_ignore_derive_macro_without_input() {
1257         check_assist_not_applicable(
1258             replace_derive_with_manual_impl,
1259             r#"
1260 //- minicore: derive
1261 #[derive($0)]
1262 struct Foo {}
1263             "#,
1264         )
1265     }
1266 
1267     #[test]
test_ignore_if_cursor_on_param()1268     fn test_ignore_if_cursor_on_param() {
1269         check_assist_not_applicable(
1270             replace_derive_with_manual_impl,
1271             r#"
1272 //- minicore: derive, fmt
1273 #[derive$0(Debug)]
1274 struct Foo {}
1275             "#,
1276         );
1277 
1278         check_assist_not_applicable(
1279             replace_derive_with_manual_impl,
1280             r#"
1281 //- minicore: derive, fmt
1282 #[derive(Debug)$0]
1283 struct Foo {}
1284             "#,
1285         )
1286     }
1287 
1288     #[test]
test_ignore_if_not_derive()1289     fn test_ignore_if_not_derive() {
1290         check_assist_not_applicable(
1291             replace_derive_with_manual_impl,
1292             r#"
1293 //- minicore: derive
1294 #[allow(non_camel_$0case_types)]
1295 struct Foo {}
1296             "#,
1297         )
1298     }
1299 
1300     #[test]
works_at_start_of_file()1301     fn works_at_start_of_file() {
1302         check_assist_not_applicable(
1303             replace_derive_with_manual_impl,
1304             r#"
1305 //- minicore: derive, fmt
1306 $0#[derive(Debug)]
1307 struct S;
1308             "#,
1309         );
1310     }
1311 
1312     #[test]
add_custom_impl_keep_path()1313     fn add_custom_impl_keep_path() {
1314         check_assist(
1315             replace_derive_with_manual_impl,
1316             r#"
1317 //- minicore: clone, derive
1318 #[derive(std::fmt::Debug, Clo$0ne)]
1319 pub struct Foo;
1320 "#,
1321             r#"
1322 #[derive(std::fmt::Debug)]
1323 pub struct Foo;
1324 
1325 impl Clone for Foo {
1326     $0fn clone(&self) -> Self {
1327         Self {  }
1328     }
1329 }
1330 "#,
1331         )
1332     }
1333 
1334     #[test]
add_custom_impl_replace_path()1335     fn add_custom_impl_replace_path() {
1336         check_assist(
1337             replace_derive_with_manual_impl,
1338             r#"
1339 //- minicore: fmt, derive
1340 #[derive(core::fmt::Deb$0ug, Clone)]
1341 pub struct Foo;
1342 "#,
1343             r#"
1344 #[derive(Clone)]
1345 pub struct Foo;
1346 
1347 impl core::fmt::Debug for Foo {
1348     $0fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1349         f.debug_struct("Foo").finish()
1350     }
1351 }
1352 "#,
1353         )
1354     }
1355 }
1356