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