Skip to main content

ide_assists/handlers/
replace_derive_with_manual_impl.rs

1use hir::{InFile, ModuleDef};
2use ide_db::{
3    helpers::mod_path_to_ast_with_factory, imports::import_assets::NameToImport, items_locator,
4};
5use itertools::Itertools;
6use syntax::{
7    Edition,
8    SyntaxKind::WHITESPACE,
9    T,
10    ast::{self, AstNode, HasName, syntax_factory::SyntaxFactory},
11    syntax_editor::{Position, SyntaxEditor},
12};
13
14use crate::{
15    AssistConfig, AssistId,
16    assist_context::{AssistContext, Assists},
17    utils::{
18        DefaultMethods, IgnoreAssocItems, add_trait_assoc_items_to_impl, filter_assoc_items,
19        gen_trait_fn_body, generate_trait_impl, generate_trait_impl_with_item,
20    },
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// ```
45pub(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 macro_file = ctx.sema.hir_file_for(attr.syntax()).macro_file()?;
52    if !macro_file.is_derive_attr_pseudo_expansion(ctx.db()) {
53        return None;
54    }
55
56    let InFile { file_id, value } = macro_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(macro_file.into())
65        .descendants()
66        .filter_map(ast::Attr::cast)
67        .filter_map(|attr| attr.path())
68        .collect::<Vec<_>>();
69
70    let attr = ast::Meta::cast(value)?.parent_attr()?;
71    let adt = attr.syntax().parent().and_then(ast::Adt::cast)?;
72    let ast::Meta::TokenTreeMeta(meta) = attr.meta()? else { return None };
73    let args = meta.token_tree()?;
74
75    let current_module = ctx.sema.scope(adt.syntax())?.module();
76    let current_crate = current_module.krate(ctx.db());
77    let current_edition = current_crate.edition(ctx.db());
78    let cfg = ctx.config.find_path_config(ctx.sema.is_nightly(current_crate));
79
80    let found_traits = items_locator::items_with_name(
81        ctx.db(),
82        current_crate,
83        NameToImport::exact_case_sensitive(path.segments().last()?.to_string()),
84        items_locator::AssocSearchMode::Exclude,
85    )
86    .filter_map(|(item, _)| match item.into_module_def() {
87        ModuleDef::Trait(trait_) => Some(trait_),
88        _ => None,
89    })
90    .flat_map(|trait_| {
91        current_module
92            .find_path(ctx.sema.db, hir::ModuleDef::Trait(trait_), cfg)
93            .map(|path| (path, trait_))
94    });
95
96    let found_traits = found_traits.collect::<Vec<_>>();
97    let no_traits_found = found_traits.is_empty();
98    for (replace_trait_mod_path, trait_) in found_traits {
99        add_assist(
100            acc,
101            ctx,
102            &attr,
103            &current_derives,
104            &args,
105            &path,
106            Some(replace_trait_mod_path),
107            Some(trait_),
108            &adt,
109            current_edition,
110        )?;
111    }
112    if no_traits_found {
113        add_assist(
114            acc,
115            ctx,
116            &attr,
117            &current_derives,
118            &args,
119            &path,
120            None,
121            None,
122            &adt,
123            current_edition,
124        )?;
125    }
126    Some(())
127}
128
129fn add_assist(
130    acc: &mut Assists,
131    ctx: &AssistContext<'_, '_>,
132    attr: &ast::Attr,
133    old_derives: &[ast::Path],
134    old_tree: &ast::TokenTree,
135    old_trait_path: &ast::Path,
136    replace_trait_mod_path: Option<hir::ModPath>,
137    trait_: Option<hir::Trait>,
138    adt: &ast::Adt,
139    current_edition: Edition,
140) -> Option<()> {
141    let target = attr.syntax().text_range();
142    let annotated_name = adt.name()?;
143    let label_trait_path = match replace_trait_mod_path.as_ref() {
144        Some(path) => {
145            mod_path_to_ast_with_factory(&SyntaxFactory::without_mappings(), path, current_edition)
146        }
147        None => old_trait_path.clone(),
148    };
149    let label = format!("Convert to manual `impl {label_trait_path} for {annotated_name}`");
150
151    acc.add(AssistId::refactor("replace_derive_with_manual_impl"), label, target, |builder| {
152        let editor = builder.make_editor(attr.syntax());
153        let make = editor.make();
154        let replace_trait_path = match replace_trait_mod_path.as_ref() {
155            Some(path) => mod_path_to_ast_with_factory(make, path, current_edition),
156            None => old_trait_path.clone(),
157        };
158        let insert_after = Position::after(adt.syntax());
159        let impl_is_unsafe = trait_.map(|s| s.is_unsafe(ctx.db())).unwrap_or(false);
160        let impl_def = impl_def_from_trait(
161            &editor,
162            &ctx.sema,
163            ctx.config,
164            adt,
165            &annotated_name,
166            trait_,
167            &replace_trait_path,
168            impl_is_unsafe,
169        );
170        update_attribute(&editor, old_derives, old_tree, old_trait_path, attr);
171
172        let trait_path = make.ty_path(replace_trait_path.clone()).into();
173
174        let (impl_def, first_assoc_item) = if let Some(impl_def) = impl_def {
175            (
176                impl_def.clone(),
177                impl_def.assoc_item_list().and_then(|list| list.assoc_items().next()),
178            )
179        } else {
180            (generate_trait_impl(make, impl_is_unsafe, adt, trait_path), None)
181        };
182
183        if let Some(cap) = ctx.config.snippet_cap {
184            if let Some(first_assoc_item) = first_assoc_item {
185                if let ast::AssocItem::Fn(ref func) = first_assoc_item
186                    && let Some(m) = func.syntax().descendants().find_map(ast::MacroCall::cast)
187                    && m.syntax().text() == "todo!()"
188                {
189                    // Make the `todo!()` a placeholder
190                    builder.add_placeholder_snippet(cap, m);
191                } else {
192                    // If we haven't already added a snippet, add a tabstop before the generated function
193                    builder.add_tabstop_before(cap, first_assoc_item);
194                }
195            } else if let Some(l_curly) =
196                impl_def.assoc_item_list().and_then(|it| it.l_curly_token())
197            {
198                builder.add_tabstop_after_token(cap, l_curly);
199            }
200        }
201
202        editor.insert_all(
203            insert_after,
204            vec![make.whitespace("\n\n").into(), impl_def.syntax().clone().into()],
205        );
206        builder.add_file_edits(ctx.vfs_file_id(), editor);
207    })
208}
209
210fn impl_def_from_trait(
211    editor: &SyntaxEditor,
212    sema: &hir::Semantics<'_, ide_db::RootDatabase>,
213    config: &AssistConfig,
214    adt: &ast::Adt,
215    annotated_name: &ast::Name,
216    trait_: Option<hir::Trait>,
217    trait_path: &ast::Path,
218    impl_is_unsafe: bool,
219) -> Option<ast::Impl> {
220    let make = editor.make();
221    let trait_ = trait_?;
222    let target_scope = sema.scope(annotated_name.syntax())?;
223
224    // Keep assoc items of local crates even if they have #[doc(hidden)] attr.
225    let ignore_items = if trait_.module(sema.db).krate(sema.db).origin(sema.db).is_local() {
226        IgnoreAssocItems::No
227    } else {
228        IgnoreAssocItems::DocHiddenAttrPresent
229    };
230
231    let trait_items =
232        filter_assoc_items(sema, &trait_.items(sema.db), DefaultMethods::No, ignore_items);
233
234    if trait_items.is_empty() {
235        return None;
236    }
237    let trait_ty: ast::Type = make.ty_path(trait_path.clone()).into();
238    let impl_def = generate_trait_impl(make, impl_is_unsafe, adt, trait_ty.clone());
239
240    let assoc_items = add_trait_assoc_items_to_impl(
241        make,
242        sema,
243        config,
244        &trait_items,
245        trait_,
246        &impl_def,
247        &target_scope,
248    );
249    let assoc_item_list = if let Some((first, other)) = assoc_items.split_first() {
250        let first_item = if let ast::AssocItem::Fn(func) = first
251            && let Some(body) = gen_trait_fn_body(make, func, trait_path, adt, None)
252            && let Some(func_body) = func.body()
253        {
254            let (editor, _) = SyntaxEditor::new(first.syntax().clone());
255            editor.replace(func_body.syntax(), body.syntax());
256            ast::AssocItem::cast(editor.finish().new_root().clone())
257        } else {
258            Some(first.clone())
259        };
260        let items: Vec<ast::AssocItem> =
261            first_item.into_iter().chain(other.iter().cloned()).collect();
262        make.assoc_item_list(items)
263    } else {
264        make.assoc_item_list_empty()
265    };
266
267    Some(generate_trait_impl_with_item(make, impl_is_unsafe, adt, trait_ty, assoc_item_list))
268}
269
270fn update_attribute(
271    editor: &SyntaxEditor,
272    old_derives: &[ast::Path],
273    old_tree: &ast::TokenTree,
274    old_trait_path: &ast::Path,
275    attr: &ast::Attr,
276) {
277    let make = editor.make();
278    let new_derives = old_derives
279        .iter()
280        .filter(|t| t.to_string() != old_trait_path.to_string())
281        .collect::<Vec<_>>();
282    let has_more_derives = !new_derives.is_empty();
283
284    if has_more_derives {
285        // Make the paths into flat lists of tokens in a vec
286        let tt = new_derives.iter().map(|path| path.syntax().clone()).map(|node| {
287            node.descendants_with_tokens()
288                .filter_map(|element| element.into_token())
289                .collect::<Vec<_>>()
290        });
291        // ...which are interspersed with ", "
292        let tt = Itertools::intersperse(tt, vec![make.token(T![,]), make.whitespace(" ")]);
293        // ...wrap them into the appropriate `NodeOrToken` variant
294        let tt = tt.flatten().map(syntax::NodeOrToken::Token);
295        // ...and make them into a flat list of tokens
296        let tt = tt.collect::<Vec<_>>();
297
298        let new_tree = make.token_tree(T!['('], tt);
299        editor.replace(old_tree.syntax(), new_tree.syntax());
300    } else {
301        // Remove the attr and any trailing whitespace
302
303        if let Some(line_break) =
304            attr.syntax().next_sibling_or_token().filter(|t| t.kind() == WHITESPACE)
305        {
306            editor.delete(line_break)
307        }
308
309        editor.delete(attr.syntax())
310    }
311}
312
313#[cfg(test)]
314mod tests {
315    use crate::tests::{check_assist, check_assist_no_snippet_cap, check_assist_not_applicable};
316
317    use super::*;
318
319    #[test]
320    fn add_custom_impl_debug_record_struct() {
321        check_assist(
322            replace_derive_with_manual_impl,
323            r#"
324//- minicore: fmt, derive
325#[derive(Debu$0g)]
326struct Foo {
327    bar: String,
328}
329"#,
330            r#"
331struct Foo {
332    bar: String,
333}
334
335impl core::fmt::Debug for Foo {
336    $0fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
337        f.debug_struct("Foo").field("bar", &self.bar).finish()
338    }
339}
340"#,
341        )
342    }
343    #[test]
344    fn add_custom_impl_without_snippet() {
345        check_assist_no_snippet_cap(
346            replace_derive_with_manual_impl,
347            r#"
348//- minicore: fmt, derive
349#[derive(Debu$0g)]
350struct Foo {
351    bar: String,
352}
353"#,
354            r#"
355struct Foo {
356    bar: String,
357}
358
359impl core::fmt::Debug for Foo {
360    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
361        f.debug_struct("Foo").field("bar", &self.bar).finish()
362    }
363}
364"#,
365        )
366    }
367    #[test]
368    fn add_custom_impl_debug_tuple_struct() {
369        check_assist(
370            replace_derive_with_manual_impl,
371            r#"
372//- minicore: fmt, derive
373#[derive(Debu$0g)]
374struct Foo(String, usize);
375"#,
376            r#"struct Foo(String, usize);
377
378impl core::fmt::Debug for Foo {
379    $0fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
380        f.debug_tuple("Foo").field(&self.0).field(&self.1).finish()
381    }
382}
383"#,
384        )
385    }
386    #[test]
387    fn add_custom_impl_debug_empty_struct() {
388        check_assist(
389            replace_derive_with_manual_impl,
390            r#"
391//- minicore: fmt, derive
392#[derive(Debu$0g)]
393struct Foo;
394"#,
395            r#"
396struct Foo;
397
398impl core::fmt::Debug for Foo {
399    $0fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
400        f.debug_struct("Foo").finish()
401    }
402}
403"#,
404        )
405    }
406    #[test]
407    fn add_custom_impl_debug_enum() {
408        check_assist(
409            replace_derive_with_manual_impl,
410            r#"
411//- minicore: fmt, derive
412#[derive(Debu$0g)]
413enum Foo {
414    Bar,
415    Baz,
416}
417"#,
418            r#"
419enum Foo {
420    Bar,
421    Baz,
422}
423
424impl core::fmt::Debug for Foo {
425    $0fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
426        match self {
427            Self::Bar => write!(f, "Bar"),
428            Self::Baz => write!(f, "Baz"),
429        }
430    }
431}
432"#,
433        )
434    }
435
436    #[test]
437    fn add_custom_impl_debug_tuple_enum() {
438        check_assist(
439            replace_derive_with_manual_impl,
440            r#"
441//- minicore: fmt, derive
442#[derive(Debu$0g)]
443enum Foo {
444    Bar(usize, usize),
445    Baz,
446}
447"#,
448            r#"
449enum Foo {
450    Bar(usize, usize),
451    Baz,
452}
453
454impl core::fmt::Debug for Foo {
455    $0fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
456        match self {
457            Self::Bar(arg0, arg1) => f.debug_tuple("Bar").field(arg0).field(arg1).finish(),
458            Self::Baz => write!(f, "Baz"),
459        }
460    }
461}
462"#,
463        )
464    }
465    #[test]
466    fn add_custom_impl_debug_record_enum() {
467        check_assist(
468            replace_derive_with_manual_impl,
469            r#"
470//- minicore: fmt, derive
471#[derive(Debu$0g)]
472enum Foo {
473    Bar {
474        baz: usize,
475        qux: usize,
476    },
477    Baz,
478}
479"#,
480            r#"
481enum Foo {
482    Bar {
483        baz: usize,
484        qux: usize,
485    },
486    Baz,
487}
488
489impl core::fmt::Debug for Foo {
490    $0fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
491        match self {
492            Self::Bar { baz, qux } => f.debug_struct("Bar").field("baz", baz).field("qux", qux).finish(),
493            Self::Baz => write!(f, "Baz"),
494        }
495    }
496}
497"#,
498        )
499    }
500    #[test]
501    fn add_custom_impl_default_record_struct() {
502        check_assist(
503            replace_derive_with_manual_impl,
504            r#"
505//- minicore: default, derive
506#[derive(Defau$0lt)]
507struct Foo {
508    foo: usize,
509}
510"#,
511            r#"
512struct Foo {
513    foo: usize,
514}
515
516impl Default for Foo {
517    $0fn default() -> Self {
518        Self { foo: Default::default() }
519    }
520}
521"#,
522        )
523    }
524    #[test]
525    fn add_custom_impl_default_tuple_struct() {
526        check_assist(
527            replace_derive_with_manual_impl,
528            r#"
529//- minicore: default, derive
530#[derive(Defau$0lt)]
531struct Foo(usize);
532"#,
533            r#"
534struct Foo(usize);
535
536impl Default for Foo {
537    $0fn default() -> Self {
538        Self(Default::default())
539    }
540}
541"#,
542        )
543    }
544    #[test]
545    fn add_custom_impl_default_empty_struct() {
546        check_assist(
547            replace_derive_with_manual_impl,
548            r#"
549//- minicore: default, derive
550#[derive(Defau$0lt)]
551struct Foo;
552"#,
553            r#"
554struct Foo;
555
556impl Default for Foo {
557    $0fn default() -> Self {
558        Self {  }
559    }
560}
561"#,
562        )
563    }
564
565    #[test]
566    fn add_custom_impl_hash_record_struct() {
567        check_assist(
568            replace_derive_with_manual_impl,
569            r#"
570//- minicore: hash, derive
571#[derive(Has$0h)]
572struct Foo {
573    bin: usize,
574    bar: usize,
575}
576"#,
577            r#"
578struct Foo {
579    bin: usize,
580    bar: usize,
581}
582
583impl core::hash::Hash for Foo {
584    $0fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
585        self.bin.hash(state);
586        self.bar.hash(state);
587    }
588}
589"#,
590        )
591    }
592
593    #[test]
594    fn add_custom_impl_hash_tuple_struct() {
595        check_assist(
596            replace_derive_with_manual_impl,
597            r#"
598//- minicore: hash, derive
599#[derive(Has$0h)]
600struct Foo(usize, usize);
601"#,
602            r#"
603struct Foo(usize, usize);
604
605impl core::hash::Hash for Foo {
606    $0fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
607        self.0.hash(state);
608        self.1.hash(state);
609    }
610}
611"#,
612        )
613    }
614
615    #[test]
616    fn add_custom_impl_hash_enum() {
617        check_assist(
618            replace_derive_with_manual_impl,
619            r#"
620//- minicore: hash, derive
621#[derive(Has$0h)]
622enum Foo {
623    Bar,
624    Baz,
625}
626"#,
627            r#"
628enum Foo {
629    Bar,
630    Baz,
631}
632
633impl core::hash::Hash for Foo {
634    $0fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
635        core::mem::discriminant(self).hash(state);
636    }
637}
638"#,
639        )
640    }
641
642    #[test]
643    fn add_custom_impl_clone_record_struct() {
644        check_assist(
645            replace_derive_with_manual_impl,
646            r#"
647//- minicore: clone, derive
648#[derive(Clo$0ne)]
649struct Foo {
650    bin: usize,
651    bar: usize,
652}
653"#,
654            r#"
655struct Foo {
656    bin: usize,
657    bar: usize,
658}
659
660impl Clone for Foo {
661    $0fn clone(&self) -> Self {
662        Self { bin: self.bin.clone(), bar: self.bar.clone() }
663    }
664}
665"#,
666        )
667    }
668
669    #[test]
670    fn add_custom_impl_clone_tuple_struct() {
671        check_assist(
672            replace_derive_with_manual_impl,
673            r#"
674//- minicore: clone, derive
675#[derive(Clo$0ne)]
676struct Foo(usize, usize);
677"#,
678            r#"
679struct Foo(usize, usize);
680
681impl Clone for Foo {
682    $0fn clone(&self) -> Self {
683        Self(self.0.clone(), self.1.clone())
684    }
685}
686"#,
687        )
688    }
689
690    #[test]
691    fn add_custom_impl_clone_empty_struct() {
692        check_assist(
693            replace_derive_with_manual_impl,
694            r#"
695//- minicore: clone, derive
696#[derive(Clo$0ne)]
697struct Foo;
698"#,
699            r#"
700struct Foo;
701
702impl Clone for Foo {
703    $0fn clone(&self) -> Self {
704        Self {  }
705    }
706}
707"#,
708        )
709    }
710
711    #[test]
712    fn add_custom_impl_clone_enum() {
713        check_assist(
714            replace_derive_with_manual_impl,
715            r#"
716//- minicore: clone, derive
717#[derive(Clo$0ne)]
718enum Foo {
719    Bar,
720    Baz,
721}
722"#,
723            r#"
724enum Foo {
725    Bar,
726    Baz,
727}
728
729impl Clone for Foo {
730    $0fn clone(&self) -> Self {
731        match self {
732            Self::Bar => Self::Bar,
733            Self::Baz => Self::Baz,
734        }
735    }
736}
737"#,
738        )
739    }
740
741    #[test]
742    fn add_custom_impl_clone_tuple_enum() {
743        check_assist(
744            replace_derive_with_manual_impl,
745            r#"
746//- minicore: clone, derive
747#[derive(Clo$0ne)]
748enum Foo {
749    Bar(String),
750    Baz,
751}
752"#,
753            r#"
754enum Foo {
755    Bar(String),
756    Baz,
757}
758
759impl Clone for Foo {
760    $0fn clone(&self) -> Self {
761        match self {
762            Self::Bar(arg0) => Self::Bar(arg0.clone()),
763            Self::Baz => Self::Baz,
764        }
765    }
766}
767"#,
768        )
769    }
770
771    #[test]
772    fn add_custom_impl_clone_record_enum() {
773        check_assist(
774            replace_derive_with_manual_impl,
775            r#"
776//- minicore: clone, derive
777#[derive(Clo$0ne)]
778enum Foo {
779    Bar {
780        bin: String,
781    },
782    Baz,
783}
784"#,
785            r#"
786enum Foo {
787    Bar {
788        bin: String,
789    },
790    Baz,
791}
792
793impl Clone for Foo {
794    $0fn clone(&self) -> Self {
795        match self {
796            Self::Bar { bin } => Self::Bar { bin: bin.clone() },
797            Self::Baz => Self::Baz,
798        }
799    }
800}
801"#,
802        )
803    }
804
805    #[test]
806    fn add_custom_impl_partial_ord_record_struct() {
807        check_assist(
808            replace_derive_with_manual_impl,
809            r#"
810//- minicore: ord, derive
811#[derive(Partial$0Ord)]
812struct Foo {
813    bin: usize,
814}
815"#,
816            r#"
817struct Foo {
818    bin: usize,
819}
820
821impl PartialOrd for Foo {
822    $0fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
823        self.bin.partial_cmp(&other.bin)
824    }
825}
826"#,
827        )
828    }
829
830    #[test]
831    fn add_custom_impl_partial_ord_record_struct_multi_field() {
832        check_assist(
833            replace_derive_with_manual_impl,
834            r#"
835//- minicore: ord, derive
836#[derive(Partial$0Ord)]
837struct Foo {
838    bin: usize,
839    bar: usize,
840    baz: usize,
841}
842"#,
843            r#"
844struct Foo {
845    bin: usize,
846    bar: usize,
847    baz: usize,
848}
849
850impl PartialOrd for Foo {
851    $0fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
852        match self.bin.partial_cmp(&other.bin) {
853            Some(core::cmp::Ordering::Equal) => {}
854            ord => return ord,
855        }
856        match self.bar.partial_cmp(&other.bar) {
857            Some(core::cmp::Ordering::Equal) => {}
858            ord => return ord,
859        }
860        self.baz.partial_cmp(&other.baz)
861    }
862}
863"#,
864        )
865    }
866
867    #[test]
868    fn add_custom_impl_partial_ord_tuple_struct() {
869        check_assist(
870            replace_derive_with_manual_impl,
871            r#"
872//- minicore: ord, derive
873#[derive(Partial$0Ord)]
874struct Foo(usize, usize, usize);
875"#,
876            r#"
877struct Foo(usize, usize, usize);
878
879impl PartialOrd for Foo {
880    $0fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
881        match self.0.partial_cmp(&other.0) {
882            Some(core::cmp::Ordering::Equal) => {}
883            ord => return ord,
884        }
885        match self.1.partial_cmp(&other.1) {
886            Some(core::cmp::Ordering::Equal) => {}
887            ord => return ord,
888        }
889        self.2.partial_cmp(&other.2)
890    }
891}
892"#,
893        )
894    }
895
896    #[test]
897    fn add_custom_impl_partial_eq_record_struct() {
898        check_assist(
899            replace_derive_with_manual_impl,
900            r#"
901//- minicore: eq, derive
902#[derive(Partial$0Eq)]
903struct Foo {
904    bin: usize,
905    bar: usize,
906}
907"#,
908            r#"
909struct Foo {
910    bin: usize,
911    bar: usize,
912}
913
914impl PartialEq for Foo {
915    $0fn eq(&self, other: &Self) -> bool {
916        self.bin == other.bin && self.bar == other.bar
917    }
918}
919"#,
920        )
921    }
922
923    #[test]
924    fn add_custom_impl_partial_eq_tuple_struct() {
925        check_assist(
926            replace_derive_with_manual_impl,
927            r#"
928//- minicore: eq, derive
929#[derive(Partial$0Eq)]
930struct Foo(usize, usize);
931"#,
932            r#"
933struct Foo(usize, usize);
934
935impl PartialEq for Foo {
936    $0fn eq(&self, other: &Self) -> bool {
937        self.0 == other.0 && self.1 == other.1
938    }
939}
940"#,
941        )
942    }
943
944    #[test]
945    fn add_custom_impl_partial_eq_empty_struct() {
946        check_assist(
947            replace_derive_with_manual_impl,
948            r#"
949//- minicore: eq, derive
950#[derive(Partial$0Eq)]
951struct Foo;
952"#,
953            r#"
954struct Foo;
955
956impl PartialEq for Foo {
957    $0fn eq(&self, other: &Self) -> bool {
958        true
959    }
960}
961"#,
962        )
963    }
964
965    #[test]
966    fn add_custom_impl_partial_eq_enum() {
967        check_assist(
968            replace_derive_with_manual_impl,
969            r#"
970//- minicore: eq, derive
971#[derive(Partial$0Eq)]
972enum Foo {
973    Bar,
974    Baz,
975}
976"#,
977            r#"
978enum Foo {
979    Bar,
980    Baz,
981}
982
983impl PartialEq for Foo {
984    $0fn eq(&self, other: &Self) -> bool {
985        core::mem::discriminant(self) == core::mem::discriminant(other)
986    }
987}
988"#,
989        )
990    }
991
992    #[test]
993    fn add_custom_impl_partial_eq_single_variant_tuple_enum() {
994        check_assist(
995            replace_derive_with_manual_impl,
996            r#"
997//- minicore: eq, derive
998#[derive(Partial$0Eq)]
999enum Foo {
1000    Bar(String),
1001}
1002"#,
1003            r#"
1004enum Foo {
1005    Bar(String),
1006}
1007
1008impl PartialEq for Foo {
1009    $0fn eq(&self, other: &Self) -> bool {
1010        match (self, other) {
1011            (Self::Bar(l0), Self::Bar(r0)) => l0 == r0,
1012        }
1013    }
1014}
1015"#,
1016        )
1017    }
1018
1019    #[test]
1020    fn add_custom_impl_partial_eq_partial_tuple_enum() {
1021        check_assist(
1022            replace_derive_with_manual_impl,
1023            r#"
1024//- minicore: eq, derive
1025#[derive(Partial$0Eq)]
1026enum Foo {
1027    Bar(String),
1028    Baz,
1029}
1030"#,
1031            r#"
1032enum Foo {
1033    Bar(String),
1034    Baz,
1035}
1036
1037impl PartialEq for Foo {
1038    $0fn eq(&self, other: &Self) -> bool {
1039        match (self, other) {
1040            (Self::Bar(l0), Self::Bar(r0)) => l0 == r0,
1041            _ => core::mem::discriminant(self) == core::mem::discriminant(other),
1042        }
1043    }
1044}
1045"#,
1046        )
1047    }
1048
1049    #[test]
1050    fn add_custom_impl_partial_eq_tuple_enum() {
1051        check_assist(
1052            replace_derive_with_manual_impl,
1053            r#"
1054//- minicore: eq, derive
1055#[derive(Partial$0Eq)]
1056enum Foo {
1057    Bar(String),
1058    Baz(i32),
1059}
1060"#,
1061            r#"
1062enum Foo {
1063    Bar(String),
1064    Baz(i32),
1065}
1066
1067impl PartialEq for Foo {
1068    $0fn eq(&self, other: &Self) -> bool {
1069        match (self, other) {
1070            (Self::Bar(l0), Self::Bar(r0)) => l0 == r0,
1071            (Self::Baz(l0), Self::Baz(r0)) => l0 == r0,
1072            _ => false,
1073        }
1074    }
1075}
1076"#,
1077        )
1078    }
1079
1080    #[test]
1081    fn add_custom_impl_partial_eq_tuple_enum_generic() {
1082        check_assist(
1083            replace_derive_with_manual_impl,
1084            r#"
1085//- minicore: eq, derive
1086#[derive(Partial$0Eq)]
1087enum Either<T, U> {
1088    Left(T),
1089    Right(U),
1090}
1091"#,
1092            r#"
1093enum Either<T, U> {
1094    Left(T),
1095    Right(U),
1096}
1097
1098impl<T: PartialEq, U: PartialEq> PartialEq for Either<T, U> {
1099    $0fn eq(&self, other: &Self) -> bool {
1100        match (self, other) {
1101            (Self::Left(l0), Self::Left(r0)) => l0 == r0,
1102            (Self::Right(l0), Self::Right(r0)) => l0 == r0,
1103            _ => false,
1104        }
1105    }
1106}
1107"#,
1108        )
1109    }
1110
1111    #[test]
1112    fn add_custom_impl_partial_eq_tuple_enum_generic_existing_bounds() {
1113        check_assist(
1114            replace_derive_with_manual_impl,
1115            r#"
1116//- minicore: eq, derive
1117#[derive(Partial$0Eq)]
1118enum Either<T: PartialEq + Error, U: Clone> {
1119    Left(T),
1120    Right(U),
1121}
1122"#,
1123            r#"
1124enum Either<T: PartialEq + Error, U: Clone> {
1125    Left(T),
1126    Right(U),
1127}
1128
1129impl<T: PartialEq + Error, U: Clone + PartialEq> PartialEq for Either<T, U> {
1130    $0fn eq(&self, other: &Self) -> bool {
1131        match (self, other) {
1132            (Self::Left(l0), Self::Left(r0)) => l0 == r0,
1133            (Self::Right(l0), Self::Right(r0)) => l0 == r0,
1134            _ => false,
1135        }
1136    }
1137}
1138"#,
1139        )
1140    }
1141
1142    #[test]
1143    fn add_custom_impl_partial_eq_record_enum() {
1144        check_assist(
1145            replace_derive_with_manual_impl,
1146            r#"
1147//- minicore: eq, derive
1148#[derive(Partial$0Eq)]
1149enum Foo {
1150    Bar {
1151        bin: String,
1152    },
1153    Baz {
1154        qux: String,
1155        fez: String,
1156    },
1157    Qux {},
1158    Bin,
1159}
1160"#,
1161            r#"
1162enum Foo {
1163    Bar {
1164        bin: String,
1165    },
1166    Baz {
1167        qux: String,
1168        fez: String,
1169    },
1170    Qux {},
1171    Bin,
1172}
1173
1174impl PartialEq for Foo {
1175    $0fn eq(&self, other: &Self) -> bool {
1176        match (self, other) {
1177            (Self::Bar { bin: l_bin }, Self::Bar { bin: r_bin }) => l_bin == r_bin,
1178            (Self::Baz { qux: l_qux, fez: l_fez }, Self::Baz { qux: r_qux, fez: r_fez }) => l_qux == r_qux && l_fez == r_fez,
1179            _ => core::mem::discriminant(self) == core::mem::discriminant(other),
1180        }
1181    }
1182}
1183"#,
1184        )
1185    }
1186    #[test]
1187    fn add_custom_impl_all() {
1188        check_assist(
1189            replace_derive_with_manual_impl,
1190            r#"
1191//- minicore: derive
1192mod foo {
1193    pub trait Bar {
1194        type Qux;
1195        const Baz: usize = 42;
1196        const Fez: usize;
1197        fn foo();
1198        fn bar() {}
1199    }
1200}
1201
1202#[derive($0Bar)]
1203struct Foo {
1204    bar: String,
1205}
1206"#,
1207            r#"
1208mod foo {
1209    pub trait Bar {
1210        type Qux;
1211        const Baz: usize = 42;
1212        const Fez: usize;
1213        fn foo();
1214        fn bar() {}
1215    }
1216}
1217
1218struct Foo {
1219    bar: String,
1220}
1221
1222impl foo::Bar for Foo {
1223    $0type Qux;
1224
1225    const Fez: usize;
1226
1227    fn foo() {
1228        todo!()
1229    }
1230}
1231"#,
1232        )
1233    }
1234    #[test]
1235    fn add_custom_impl_for_unique_input_unknown() {
1236        check_assist(
1237            replace_derive_with_manual_impl,
1238            r#"
1239//- minicore: derive
1240#[derive(Debu$0g)]
1241struct Foo {
1242    bar: String,
1243}
1244            "#,
1245            r#"
1246struct Foo {
1247    bar: String,
1248}
1249
1250impl Debug for Foo {$0}
1251            "#,
1252        )
1253    }
1254
1255    #[test]
1256    fn add_custom_impl_for_with_visibility_modifier() {
1257        check_assist(
1258            replace_derive_with_manual_impl,
1259            r#"
1260//- minicore: derive
1261#[derive(Debug$0)]
1262pub struct Foo {
1263    bar: String,
1264}
1265            "#,
1266            r#"
1267pub struct Foo {
1268    bar: String,
1269}
1270
1271impl Debug for Foo {$0}
1272            "#,
1273        )
1274    }
1275
1276    #[test]
1277    fn add_custom_impl_when_multiple_inputs() {
1278        check_assist(
1279            replace_derive_with_manual_impl,
1280            r#"
1281//- minicore: derive
1282#[derive(Display, Debug$0, Serialize)]
1283struct Foo {}
1284            "#,
1285            r#"
1286#[derive(Display, Serialize)]
1287struct Foo {}
1288
1289impl Debug for Foo {$0}
1290            "#,
1291        )
1292    }
1293
1294    #[test]
1295    fn add_custom_impl_default_generic_record_struct() {
1296        check_assist(
1297            replace_derive_with_manual_impl,
1298            r#"
1299//- minicore: default, derive
1300#[derive(Defau$0lt)]
1301struct Foo<T, U> {
1302    foo: T,
1303    bar: U,
1304}
1305"#,
1306            r#"
1307struct Foo<T, U> {
1308    foo: T,
1309    bar: U,
1310}
1311
1312impl<T: Default, U: Default> Default for Foo<T, U> {
1313    $0fn default() -> Self {
1314        Self { foo: Default::default(), bar: Default::default() }
1315    }
1316}
1317"#,
1318        )
1319    }
1320
1321    #[test]
1322    fn add_custom_impl_clone_generic_tuple_struct_with_bounds() {
1323        check_assist(
1324            replace_derive_with_manual_impl,
1325            r#"
1326//- minicore: clone, derive
1327#[derive(Clo$0ne)]
1328struct Foo<T: Clone>(T, usize);
1329"#,
1330            r#"
1331struct Foo<T: Clone>(T, usize);
1332
1333impl<T: Clone> Clone for Foo<T> {
1334    $0fn clone(&self) -> Self {
1335        Self(self.0.clone(), self.1.clone())
1336    }
1337}
1338"#,
1339        )
1340    }
1341
1342    #[test]
1343    fn add_custom_impl_clone_generic_tuple_struct_with_associated() {
1344        check_assist(
1345            replace_derive_with_manual_impl,
1346            r#"
1347//- minicore: clone, derive, deref
1348#[derive(Clo$0ne)]
1349struct Foo<T: core::ops::Deref>(T::Target);
1350"#,
1351            r#"
1352struct Foo<T: core::ops::Deref>(T::Target);
1353
1354impl<T: core::ops::Deref + Clone> Clone for Foo<T>
1355where T::Target: Clone
1356{
1357    $0fn clone(&self) -> Self {
1358        Self(self.0.clone())
1359    }
1360}
1361"#,
1362        )
1363    }
1364
1365    #[test]
1366    fn test_ignore_derive_macro_without_input() {
1367        check_assist_not_applicable(
1368            replace_derive_with_manual_impl,
1369            r#"
1370//- minicore: derive
1371#[derive($0)]
1372struct Foo {}
1373            "#,
1374        )
1375    }
1376
1377    #[test]
1378    fn test_ignore_if_cursor_on_param() {
1379        check_assist_not_applicable(
1380            replace_derive_with_manual_impl,
1381            r#"
1382//- minicore: derive, fmt
1383#[derive$0(Debug)]
1384struct Foo {}
1385            "#,
1386        );
1387
1388        check_assist_not_applicable(
1389            replace_derive_with_manual_impl,
1390            r#"
1391//- minicore: derive, fmt
1392#[derive(Debug)$0]
1393struct Foo {}
1394            "#,
1395        )
1396    }
1397
1398    #[test]
1399    fn test_ignore_if_not_derive() {
1400        check_assist_not_applicable(
1401            replace_derive_with_manual_impl,
1402            r#"
1403//- minicore: derive
1404#[allow(non_camel_$0case_types)]
1405struct Foo {}
1406            "#,
1407        )
1408    }
1409
1410    #[test]
1411    fn works_at_start_of_file() {
1412        check_assist_not_applicable(
1413            replace_derive_with_manual_impl,
1414            r#"
1415//- minicore: derive, fmt
1416$0#[derive(Debug)]
1417struct S;
1418            "#,
1419        );
1420    }
1421
1422    #[test]
1423    fn add_custom_impl_keep_path() {
1424        check_assist(
1425            replace_derive_with_manual_impl,
1426            r#"
1427//- minicore: clone, derive
1428#[derive(std::fmt::Debug, Clo$0ne)]
1429pub struct Foo;
1430"#,
1431            r#"
1432#[derive(std::fmt::Debug)]
1433pub struct Foo;
1434
1435impl Clone for Foo {
1436    $0fn clone(&self) -> Self {
1437        Self {  }
1438    }
1439}
1440"#,
1441        )
1442    }
1443
1444    #[test]
1445    fn add_custom_impl_replace_path() {
1446        check_assist(
1447            replace_derive_with_manual_impl,
1448            r#"
1449//- minicore: fmt, derive
1450#[derive(core::fmt::Deb$0ug, Clone)]
1451pub struct Foo;
1452"#,
1453            r#"
1454#[derive(Clone)]
1455pub struct Foo;
1456
1457impl core::fmt::Debug for Foo {
1458    $0fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1459        f.debug_struct("Foo").finish()
1460    }
1461}
1462"#,
1463        )
1464    }
1465
1466    #[test]
1467    fn unsafeness_of_a_trait_observed() {
1468        check_assist(
1469            replace_derive_with_manual_impl,
1470            r#"
1471//- minicore: send, derive
1472#[derive(Sen$0d)]
1473pub struct Foo;
1474"#,
1475            r#"
1476pub struct Foo;
1477
1478unsafe impl Send for Foo {$0}
1479"#,
1480        )
1481    }
1482}