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