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