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