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