Skip to main content

ide_assists/handlers/
generate_getter_or_setter.rs

1use ide_db::{famous_defs::FamousDefs, source_change::SourceChangeBuilder};
2use stdx::{format_to, to_lower_snake_case};
3use syntax::{
4    TextRange,
5    ast::{
6        self, AstNode, HasGenericParams, HasName, HasVisibility, edit::AstNodeEdit,
7        syntax_factory::SyntaxFactory,
8    },
9    syntax_editor::Position,
10};
11
12use crate::{
13    AssistContext, AssistId, Assists, GroupLabel,
14    utils::{convert_reference_type, find_struct_impl, is_selected},
15};
16
17// Assist: generate_setter
18//
19// Generate a setter method.
20//
21// ```
22// struct Person {
23//     nam$0e: String,
24// }
25// ```
26// ->
27// ```
28// struct Person {
29//     name: String,
30// }
31//
32// impl Person {
33//     fn $0set_name(&mut self, name: String) {
34//         self.name = name;
35//     }
36// }
37// ```
38pub(crate) fn generate_setter(acc: &mut Assists, ctx: &AssistContext<'_, '_>) -> Option<()> {
39    // This if condition denotes two modes this assist can work in:
40    // - First is acting upon selection of record fields
41    // - Next is acting upon a single record field
42    //
43    // This is the only part where implementation diverges a bit,
44    // subsequent code is generic for both of these modes
45
46    let (strukt, info_of_record_fields, mut fn_names) = extract_and_parse(ctx, AssistType::Set)?;
47
48    // No record fields to do work on :(
49    if info_of_record_fields.is_empty() {
50        return None;
51    }
52
53    // Prepend set_ to fn names.
54    fn_names.iter_mut().for_each(|name| *name = format!("set_{name}"));
55
56    // Return early if we've found an existing fn
57    let impl_def = find_struct_impl(ctx, &ast::Adt::Struct(strukt.clone()), &fn_names)?;
58
59    // Computing collective text range of all record fields in selected region
60    let target: TextRange = info_of_record_fields
61        .iter()
62        .map(|record_field_info| record_field_info.target)
63        .reduce(|acc, target| acc.cover(target))?;
64
65    let setter_info = AssistInfo { impl_def, strukt, assist_type: AssistType::Set };
66
67    acc.add_group(
68        &GroupLabel("Generate getter/setter".to_owned()),
69        AssistId::generate("generate_setter"),
70        "Generate a setter method",
71        target,
72        |builder| build_source_change(builder, ctx, info_of_record_fields, setter_info),
73    );
74    Some(())
75}
76
77// Assist: generate_getter
78//
79// Generate a getter method.
80//
81// ```
82// # //- minicore: as_ref, deref
83// # pub struct String;
84// # impl AsRef<str> for String {
85// #     fn as_ref(&self) -> &str {
86// #         ""
87// #     }
88// # }
89// #
90// # impl core::ops::Deref for String {
91// #     type Target = str;
92// #     fn deref(&self) -> &Self::Target {
93// #         ""
94// #     }
95// # }
96// #
97// struct Person {
98//     nam$0e: String,
99// }
100// ```
101// ->
102// ```
103// # pub struct String;
104// # impl AsRef<str> for String {
105// #     fn as_ref(&self) -> &str {
106// #         ""
107// #     }
108// # }
109// #
110// # impl core::ops::Deref for String {
111// #     type Target = str;
112// #     fn deref(&self) -> &Self::Target {
113// #         ""
114// #     }
115// # }
116// #
117// struct Person {
118//     name: String,
119// }
120//
121// impl Person {
122//     fn $0name(&self) -> &str {
123//         &self.name
124//     }
125// }
126// ```
127pub(crate) fn generate_getter(acc: &mut Assists, ctx: &AssistContext<'_, '_>) -> Option<()> {
128    generate_getter_impl(acc, ctx, false)
129}
130
131// Assist: generate_getter_mut
132//
133// Generate a mut getter method.
134//
135// ```
136// struct Person {
137//     nam$0e: String,
138// }
139// ```
140// ->
141// ```
142// struct Person {
143//     name: String,
144// }
145//
146// impl Person {
147//     fn $0name_mut(&mut self) -> &mut String {
148//         &mut self.name
149//     }
150// }
151// ```
152pub(crate) fn generate_getter_mut(acc: &mut Assists, ctx: &AssistContext<'_, '_>) -> Option<()> {
153    generate_getter_impl(acc, ctx, true)
154}
155
156#[derive(Clone, Debug)]
157struct RecordFieldInfo {
158    field_name: syntax::ast::Name,
159    field_ty: syntax::ast::Type,
160    fn_name: String,
161    target: TextRange,
162}
163
164struct AssistInfo {
165    impl_def: Option<ast::Impl>,
166    strukt: ast::Struct,
167    assist_type: AssistType,
168}
169
170enum AssistType {
171    Get,
172    MutGet,
173    Set,
174}
175
176pub(crate) fn generate_getter_impl(
177    acc: &mut Assists,
178    ctx: &AssistContext<'_, '_>,
179    mutable: bool,
180) -> Option<()> {
181    let (strukt, info_of_record_fields, fn_names) =
182        extract_and_parse(ctx, if mutable { AssistType::MutGet } else { AssistType::Get })?;
183    // No record fields to do work on :(
184    if info_of_record_fields.is_empty() {
185        return None;
186    }
187
188    let impl_def = find_struct_impl(ctx, &ast::Adt::Struct(strukt.clone()), &fn_names)?;
189
190    let (id, label) = if mutable {
191        ("generate_getter_mut", "Generate a mut getter method")
192    } else {
193        ("generate_getter", "Generate a getter method")
194    };
195
196    // Computing collective text range of all record fields in selected region
197    let target: TextRange = info_of_record_fields
198        .iter()
199        .map(|record_field_info| record_field_info.target)
200        .reduce(|acc, target| acc.cover(target))?;
201
202    let getter_info = AssistInfo {
203        impl_def,
204        strukt,
205        assist_type: if mutable { AssistType::MutGet } else { AssistType::Get },
206    };
207
208    acc.add_group(
209        &GroupLabel("Generate getter/setter".to_owned()),
210        AssistId::generate(id),
211        label,
212        target,
213        |builder| build_source_change(builder, ctx, info_of_record_fields, getter_info),
214    )
215}
216
217fn generate_getter_from_info(
218    ctx: &AssistContext<'_, '_>,
219    info: &AssistInfo,
220    record_field_info: &RecordFieldInfo,
221    make: &SyntaxFactory,
222) -> ast::Fn {
223    let (ty, body) = if matches!(info.assist_type, AssistType::MutGet) {
224        let self_expr = make.expr_path(make.ident_path("self"));
225        (
226            make.ty_ref(record_field_info.field_ty.clone(), true),
227            make.expr_ref(
228                make.expr_field(self_expr, &record_field_info.field_name.text()).into(),
229                true,
230            ),
231        )
232    } else {
233        (|| {
234            let module = ctx.sema.scope(record_field_info.field_ty.syntax())?.module();
235            let famous_defs = &FamousDefs(&ctx.sema, module.krate(ctx.db()));
236            ctx.sema
237                .resolve_type(&record_field_info.field_ty)
238                .and_then(|ty| convert_reference_type(ty, ctx.db(), famous_defs))
239                .map(|conversion| {
240                    cov_mark::hit!(convert_reference_type);
241                    (
242                        conversion.convert_type_with_factory(make, ctx.db(), module),
243                        conversion.getter(make, record_field_info.field_name.to_string()),
244                    )
245                })
246        })()
247        .unwrap_or_else(|| {
248            (
249                make.ty_ref(record_field_info.field_ty.clone(), false),
250                make.expr_ref(
251                    make.expr_field(
252                        make.expr_path(make.ident_path("self")),
253                        &record_field_info.field_name.text(),
254                    )
255                    .into(),
256                    false,
257                ),
258            )
259        })
260    };
261
262    let self_param = if matches!(info.assist_type, AssistType::MutGet) {
263        make.mut_self_param()
264    } else {
265        make.self_param()
266    };
267
268    let strukt = &info.strukt;
269    let fn_name = make.name(&record_field_info.fn_name);
270    let params = make.param_list(Some(self_param), []);
271    let ret_type = Some(make.ret_type(ty));
272    let body = make.block_expr([], Some(body));
273
274    make.fn_(
275        None,
276        strukt.visibility(),
277        fn_name,
278        None,
279        None,
280        params,
281        body,
282        ret_type,
283        false,
284        false,
285        false,
286        false,
287    )
288}
289
290fn generate_setter_from_info(
291    info: &AssistInfo,
292    record_field_info: &RecordFieldInfo,
293    make: &SyntaxFactory,
294) -> ast::Fn {
295    let strukt = &info.strukt;
296    let field_name = &record_field_info.fn_name;
297    let fn_name = make.name(&format!("set_{field_name}"));
298    let field_ty = &record_field_info.field_ty;
299
300    // Make the param list
301    // `(&mut self, $field_name: $field_ty)`
302    let field_param =
303        make.param(make.ident_pat(false, false, make.name(field_name)).into(), field_ty.clone());
304    let params = make.param_list(Some(make.mut_self_param()), [field_param]);
305
306    // Make the assignment body
307    // `self.$field_name = $field_name`
308    let self_expr = make.expr_path(make.ident_path("self"));
309    let lhs = make.expr_field(self_expr, field_name);
310    let rhs = make.expr_path(make.ident_path(field_name));
311    let assign_stmt = make.expr_stmt(make.expr_assignment(lhs.into(), rhs).into());
312    let body = make.block_expr([assign_stmt.into()], None);
313
314    // Make the setter fn
315    make.fn_(
316        None,
317        strukt.visibility(),
318        fn_name,
319        None,
320        None,
321        params,
322        body,
323        None,
324        false,
325        false,
326        false,
327        false,
328    )
329}
330
331fn extract_and_parse(
332    ctx: &AssistContext<'_, '_>,
333    assist_type: AssistType,
334) -> Option<(ast::Struct, Vec<RecordFieldInfo>, Vec<String>)> {
335    // This if condition denotes two modes assists can work in:
336    // - First is acting upon selection of record fields
337    // - Next is acting upon a single record field
338    if !ctx.has_empty_selection() {
339        // Selection Mode
340        let node = ctx.covering_element();
341
342        let node = match node {
343            syntax::NodeOrToken::Node(n) => n,
344            syntax::NodeOrToken::Token(t) => t.parent()?,
345        };
346
347        let parent_struct = node.ancestors().find_map(ast::Struct::cast)?;
348
349        let (info_of_record_fields, field_names) =
350            extract_and_parse_record_fields(&parent_struct, ctx.selection_trimmed(), &assist_type)?;
351
352        return Some((parent_struct, info_of_record_fields, field_names));
353    }
354
355    // Single Record Field mode
356    let strukt = ctx.find_node_at_offset::<ast::Struct>()?;
357    let field = ctx.find_node_at_offset::<ast::RecordField>()?;
358    let record_field_info = parse_record_field(field, &assist_type)?;
359    let fn_name = record_field_info.fn_name.clone();
360    Some((strukt, vec![record_field_info], vec![fn_name]))
361}
362
363fn extract_and_parse_record_fields(
364    node: &ast::Struct,
365    selection_range: TextRange,
366    assist_type: &AssistType,
367) -> Option<(Vec<RecordFieldInfo>, Vec<String>)> {
368    let mut field_names: Vec<String> = vec![];
369    let field_list = node.field_list()?;
370
371    match field_list {
372        ast::FieldList::RecordFieldList(ele) => {
373            let info_of_record_fields_in_selection = ele
374                .fields()
375                .filter_map(|record_field| {
376                    if is_selected(&record_field, selection_range, false) {
377                        let record_field_info = parse_record_field(record_field, assist_type)?;
378                        field_names.push(record_field_info.fn_name.clone());
379                        return Some(record_field_info);
380                    }
381
382                    None
383                })
384                .collect::<Vec<RecordFieldInfo>>();
385
386            if info_of_record_fields_in_selection.is_empty() {
387                return None;
388            }
389
390            Some((info_of_record_fields_in_selection, field_names))
391        }
392        ast::FieldList::TupleFieldList(_) => None,
393    }
394}
395
396fn parse_record_field(
397    record_field: ast::RecordField,
398    assist_type: &AssistType,
399) -> Option<RecordFieldInfo> {
400    let field_name = record_field.name()?;
401    let field_ty = record_field.ty()?;
402
403    let mut fn_name = to_lower_snake_case(&field_name.to_string());
404    if matches!(assist_type, AssistType::MutGet) {
405        format_to!(fn_name, "_mut");
406    }
407
408    let target = record_field.syntax().text_range();
409
410    Some(RecordFieldInfo { field_name, field_ty, fn_name, target })
411}
412
413fn items(
414    ctx: &AssistContext<'_, '_>,
415    info_of_record_fields: Vec<RecordFieldInfo>,
416    assist_info: &AssistInfo,
417    make: &SyntaxFactory,
418) -> Vec<ast::AssocItem> {
419    info_of_record_fields
420        .iter()
421        .map(|record_field_info| {
422            let method = match assist_info.assist_type {
423                AssistType::Set => generate_setter_from_info(assist_info, record_field_info, make),
424                _ => generate_getter_from_info(ctx, assist_info, record_field_info, make),
425            };
426            let new_fn = method;
427            let new_fn = new_fn.indent(1.into());
428            new_fn.into()
429        })
430        .collect()
431}
432
433fn build_source_change(
434    builder: &mut SourceChangeBuilder,
435    ctx: &AssistContext<'_, '_>,
436    info_of_record_fields: Vec<RecordFieldInfo>,
437    assist_info: AssistInfo,
438) {
439    if let Some(impl_def) = &assist_info.impl_def {
440        // We have an existing impl to add to
441        let editor = builder.make_editor(impl_def.syntax());
442        let items = items(ctx, info_of_record_fields, &assist_info, editor.make());
443        impl_def.assoc_item_list().unwrap().add_items(&editor, items.clone());
444
445        if let Some(cap) = ctx.config.snippet_cap
446            && let Some(ast::AssocItem::Fn(fn_)) = items.last()
447            && let Some(name) = fn_.name()
448        {
449            let tabstop = builder.make_tabstop_before(cap);
450            editor.add_annotation(name.syntax(), tabstop);
451        }
452
453        builder.add_file_edits(ctx.vfs_file_id(), editor);
454        return;
455    }
456
457    let editor = builder.make_editor(assist_info.strukt.syntax());
458    let make = editor.make();
459    let items = items(ctx, info_of_record_fields, &assist_info, make);
460    let ty_params = assist_info.strukt.generic_param_list();
461    let ty_args = ty_params.as_ref().map(|it| it.to_generic_args(make));
462    let impl_def = make.impl_(
463        None,
464        ty_params,
465        ty_args,
466        make.ty_path(make.ident_path(&assist_info.strukt.name().unwrap().to_string())).into(),
467        None,
468        Some(make.assoc_item_list(items)),
469    );
470    editor.insert_all(
471        Position::after(assist_info.strukt.syntax()),
472        vec![make.whitespace("\n\n").into(), impl_def.syntax().clone().into()],
473    );
474
475    if let Some(cap) = ctx.config.snippet_cap
476        && let Some(assoc_list) = impl_def.assoc_item_list()
477        && let Some(ast::AssocItem::Fn(fn_)) = assoc_list.assoc_items().last()
478        && let Some(name) = fn_.name()
479    {
480        let tabstop = builder.make_tabstop_before(cap);
481        editor.add_annotation(name.syntax().clone(), tabstop);
482    }
483
484    builder.add_file_edits(ctx.vfs_file_id(), editor);
485}
486
487#[cfg(test)]
488mod tests_getter {
489    use crate::tests::{check_assist, check_assist_no_snippet_cap, check_assist_not_applicable};
490
491    use super::*;
492
493    #[test]
494    fn test_generate_getter_from_field() {
495        check_assist(
496            generate_getter,
497            r#"
498struct Context {
499    dat$0a: Data,
500}
501"#,
502            r#"
503struct Context {
504    data: Data,
505}
506
507impl Context {
508    fn $0data(&self) -> &Data {
509        &self.data
510    }
511}
512"#,
513        );
514
515        check_assist(
516            generate_getter_mut,
517            r#"
518struct Context {
519    dat$0a: Data,
520}
521"#,
522            r#"
523struct Context {
524    data: Data,
525}
526
527impl Context {
528    fn $0data_mut(&mut self) -> &mut Data {
529        &mut self.data
530    }
531}
532"#,
533        );
534    }
535
536    #[test]
537    fn test_generate_getter_from_field_no_snippet_cap() {
538        check_assist_no_snippet_cap(
539            generate_getter,
540            r#"
541struct Context {
542    dat$0a: Data,
543}
544"#,
545            r#"
546struct Context {
547    data: Data,
548}
549
550impl Context {
551    fn data(&self) -> &Data {
552        &self.data
553    }
554}
555"#,
556        );
557
558        check_assist_no_snippet_cap(
559            generate_getter_mut,
560            r#"
561struct Context {
562    dat$0a: Data,
563}
564"#,
565            r#"
566struct Context {
567    data: Data,
568}
569
570impl Context {
571    fn data_mut(&mut self) -> &mut Data {
572        &mut self.data
573    }
574}
575"#,
576        );
577    }
578
579    #[test]
580    fn test_generate_getter_already_implemented() {
581        check_assist_not_applicable(
582            generate_getter,
583            r#"
584struct Context {
585    dat$0a: Data,
586}
587
588impl Context {
589    fn data(&self) -> &Data {
590        &self.data
591    }
592}
593"#,
594        );
595
596        check_assist_not_applicable(
597            generate_getter_mut,
598            r#"
599struct Context {
600    dat$0a: Data,
601}
602
603impl Context {
604    fn data_mut(&mut self) -> &mut Data {
605        &mut self.data
606    }
607}
608"#,
609        );
610    }
611
612    #[test]
613    fn test_generate_getter_from_field_with_visibility_marker() {
614        check_assist(
615            generate_getter,
616            r#"
617pub(crate) struct Context {
618    dat$0a: Data,
619}
620"#,
621            r#"
622pub(crate) struct Context {
623    data: Data,
624}
625
626impl Context {
627    pub(crate) fn $0data(&self) -> &Data {
628        &self.data
629    }
630}
631"#,
632        );
633    }
634
635    #[test]
636    fn test_generate_getter_from_field_with_visibility_marker_no_snippet_cap() {
637        check_assist_no_snippet_cap(
638            generate_getter,
639            r#"
640pub(crate) struct Context {
641    dat$0a: Data,
642}
643"#,
644            r#"
645pub(crate) struct Context {
646    data: Data,
647}
648
649impl Context {
650    pub(crate) fn data(&self) -> &Data {
651        &self.data
652    }
653}
654"#,
655        );
656    }
657
658    #[test]
659    fn test_multiple_generate_getter() {
660        check_assist(
661            generate_getter,
662            r#"
663struct Context {
664    data: Data,
665    cou$0nt: usize,
666}
667
668impl Context {
669    fn data(&self) -> &Data {
670        &self.data
671    }
672}
673"#,
674            r#"
675struct Context {
676    data: Data,
677    count: usize,
678}
679
680impl Context {
681    fn data(&self) -> &Data {
682        &self.data
683    }
684
685    fn $0count(&self) -> &usize {
686        &self.count
687    }
688}
689"#,
690        );
691    }
692
693    #[test]
694    fn test_multiple_generate_getter_no_snippet_cap() {
695        check_assist_no_snippet_cap(
696            generate_getter,
697            r#"
698struct Context {
699    data: Data,
700    cou$0nt: usize,
701}
702
703impl Context {
704    fn data(&self) -> &Data {
705        &self.data
706    }
707}
708"#,
709            r#"
710struct Context {
711    data: Data,
712    count: usize,
713}
714
715impl Context {
716    fn data(&self) -> &Data {
717        &self.data
718    }
719
720    fn count(&self) -> &usize {
721        &self.count
722    }
723}
724"#,
725        );
726    }
727
728    #[test]
729    fn test_not_a_special_case() {
730        cov_mark::check_count!(convert_reference_type, 0);
731        // Fake string which doesn't implement AsRef<str>
732        check_assist(
733            generate_getter,
734            r#"
735pub struct String;
736
737struct S { foo: $0String }
738"#,
739            r#"
740pub struct String;
741
742struct S { foo: String }
743
744impl S {
745    fn $0foo(&self) -> &String {
746        &self.foo
747    }
748}
749"#,
750        );
751    }
752
753    #[test]
754    fn test_convert_reference_type() {
755        cov_mark::check_count!(convert_reference_type, 6);
756
757        // Copy
758        check_assist(
759            generate_getter,
760            r#"
761//- minicore: copy
762struct S { foo: $0bool }
763"#,
764            r#"
765struct S { foo: bool }
766
767impl S {
768    fn $0foo(&self) -> bool {
769        self.foo
770    }
771}
772"#,
773        );
774
775        // AsRef<str>
776        check_assist(
777            generate_getter,
778            r#"
779//- minicore: as_ref
780pub struct String;
781impl AsRef<str> for String {
782    fn as_ref(&self) -> &str {
783        ""
784    }
785}
786
787struct S { foo: $0String }
788"#,
789            r#"
790pub struct String;
791impl AsRef<str> for String {
792    fn as_ref(&self) -> &str {
793        ""
794    }
795}
796
797struct S { foo: String }
798
799impl S {
800    fn $0foo(&self) -> &str {
801        self.foo.as_ref()
802    }
803}
804"#,
805        );
806
807        // AsRef<T>
808        check_assist(
809            generate_getter,
810            r#"
811//- minicore: as_ref
812struct Sweets;
813
814pub struct Box<T>(T);
815impl<T> AsRef<T> for Box<T> {
816    fn as_ref(&self) -> &T {
817        &self.0
818    }
819}
820
821struct S { foo: $0Box<Sweets> }
822"#,
823            r#"
824struct Sweets;
825
826pub struct Box<T>(T);
827impl<T> AsRef<T> for Box<T> {
828    fn as_ref(&self) -> &T {
829        &self.0
830    }
831}
832
833struct S { foo: Box<Sweets> }
834
835impl S {
836    fn $0foo(&self) -> &Sweets {
837        self.foo.as_ref()
838    }
839}
840"#,
841        );
842
843        // AsRef<[T]>
844        check_assist(
845            generate_getter,
846            r#"
847//- minicore: as_ref
848pub struct Vec<T>;
849impl<T> AsRef<[T]> for Vec<T> {
850    fn as_ref(&self) -> &[T] {
851        &[]
852    }
853}
854
855struct S { foo: $0Vec<()> }
856"#,
857            r#"
858pub struct Vec<T>;
859impl<T> AsRef<[T]> for Vec<T> {
860    fn as_ref(&self) -> &[T] {
861        &[]
862    }
863}
864
865struct S { foo: Vec<()> }
866
867impl S {
868    fn $0foo(&self) -> &[()] {
869        self.foo.as_ref()
870    }
871}
872"#,
873        );
874
875        // Option
876        check_assist(
877            generate_getter,
878            r#"
879//- minicore: option
880struct Failure;
881
882struct S { foo: $0Option<Failure> }
883"#,
884            r#"
885struct Failure;
886
887struct S { foo: Option<Failure> }
888
889impl S {
890    fn $0foo(&self) -> Option<&Failure> {
891        self.foo.as_ref()
892    }
893}
894"#,
895        );
896
897        // Result
898        check_assist(
899            generate_getter,
900            r#"
901//- minicore: result
902struct Context {
903    dat$0a: Result<bool, i32>,
904}
905"#,
906            r#"
907struct Context {
908    data: Result<bool, i32>,
909}
910
911impl Context {
912    fn $0data(&self) -> Result<&bool, &i32> {
913        self.data.as_ref()
914    }
915}
916"#,
917        );
918    }
919
920    #[test]
921    fn test_generate_multiple_getters_from_selection() {
922        check_assist(
923            generate_getter,
924            r#"
925struct Context {
926    $0data: Data,
927    count: usize,$0
928}
929    "#,
930            r#"
931struct Context {
932    data: Data,
933    count: usize,
934}
935
936impl Context {
937    fn data(&self) -> &Data {
938        &self.data
939    }
940
941    fn $0count(&self) -> &usize {
942        &self.count
943    }
944}
945    "#,
946        );
947    }
948
949    #[test]
950    fn test_generate_multiple_getters_from_partial_selection() {
951        check_assist(
952            generate_getter,
953            r#"
954struct Context {
955    data$0: Data,
956    count$0: usize,
957    other: usize,
958}
959    "#,
960            r#"
961struct Context {
962    data: Data,
963    count: usize,
964    other: usize,
965}
966
967impl Context {
968    fn data(&self) -> &Data {
969        &self.data
970    }
971
972    fn $0count(&self) -> &usize {
973        &self.count
974    }
975}
976    "#,
977        );
978    }
979
980    #[test]
981    fn test_generate_multiple_getters_from_selection_one_already_exists() {
982        // As impl for one of the fields already exist, skip it
983        check_assist_not_applicable(
984            generate_getter,
985            r#"
986struct Context {
987    $0data: Data,
988    count: usize,$0
989}
990
991impl Context {
992    fn data(&self) -> &Data {
993        &self.data
994    }
995}
996    "#,
997        );
998    }
999}
1000
1001#[cfg(test)]
1002mod tests_setter {
1003    use crate::tests::{check_assist, check_assist_not_applicable};
1004
1005    use super::*;
1006
1007    fn check_not_applicable(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
1008        check_assist_not_applicable(generate_setter, ra_fixture)
1009    }
1010
1011    #[test]
1012    fn test_generate_setter_from_field() {
1013        check_assist(
1014            generate_setter,
1015            r#"
1016struct Person<T: Clone> {
1017    dat$0a: T,
1018}"#,
1019            r#"
1020struct Person<T: Clone> {
1021    data: T,
1022}
1023
1024impl<T: Clone> Person<T> {
1025    fn $0set_data(&mut self, data: T) {
1026        self.data = data;
1027    }
1028}"#,
1029        );
1030    }
1031
1032    #[test]
1033    fn test_generate_setter_already_implemented() {
1034        check_not_applicable(
1035            r#"
1036struct Person<T: Clone> {
1037    dat$0a: T,
1038}
1039
1040impl<T: Clone> Person<T> {
1041    fn set_data(&mut self, data: T) {
1042        self.data = data;
1043    }
1044}"#,
1045        );
1046    }
1047
1048    #[test]
1049    fn test_generate_setter_from_field_with_visibility_marker() {
1050        check_assist(
1051            generate_setter,
1052            r#"
1053pub(crate) struct Person<T: Clone> {
1054    dat$0a: T,
1055}"#,
1056            r#"
1057pub(crate) struct Person<T: Clone> {
1058    data: T,
1059}
1060
1061impl<T: Clone> Person<T> {
1062    pub(crate) fn $0set_data(&mut self, data: T) {
1063        self.data = data;
1064    }
1065}"#,
1066        );
1067    }
1068
1069    #[test]
1070    fn test_multiple_generate_setter() {
1071        check_assist(
1072            generate_setter,
1073            r#"
1074struct Context<T: Clone> {
1075    data: T,
1076    cou$0nt: usize,
1077}
1078
1079impl<T: Clone> Context<T> {
1080    fn set_data(&mut self, data: T) {
1081        self.data = data;
1082    }
1083}"#,
1084            r#"
1085struct Context<T: Clone> {
1086    data: T,
1087    count: usize,
1088}
1089
1090impl<T: Clone> Context<T> {
1091    fn set_data(&mut self, data: T) {
1092        self.data = data;
1093    }
1094
1095    fn $0set_count(&mut self, count: usize) {
1096        self.count = count;
1097    }
1098}"#,
1099        );
1100    }
1101}