diff options
Diffstat (limited to 'crates/ide_assists/src')
-rw-r--r-- | crates/ide_assists/src/handlers/fill_match_arms.rs | 148 | ||||
-rw-r--r-- | crates/ide_assists/src/handlers/fix_visibility.rs | 2 | ||||
-rw-r--r-- | crates/ide_assists/src/handlers/generate_getter.rs | 292 | ||||
-rw-r--r-- | crates/ide_assists/src/handlers/generate_getter_mut.rs | 195 | ||||
-rw-r--r-- | crates/ide_assists/src/lib.rs | 6 | ||||
-rw-r--r-- | crates/ide_assists/src/tests.rs | 2 | ||||
-rw-r--r-- | crates/ide_assists/src/tests/generated.rs | 10 |
7 files changed, 341 insertions, 314 deletions
diff --git a/crates/ide_assists/src/handlers/fill_match_arms.rs b/crates/ide_assists/src/handlers/fill_match_arms.rs index 97435f021..3d2cd739a 100644 --- a/crates/ide_assists/src/handlers/fill_match_arms.rs +++ b/crates/ide_assists/src/handlers/fill_match_arms.rs | |||
@@ -31,8 +31,8 @@ use crate::{ | |||
31 | // | 31 | // |
32 | // fn handle(action: Action) { | 32 | // fn handle(action: Action) { |
33 | // match action { | 33 | // match action { |
34 | // $0Action::Move { distance } => {} | 34 | // $0Action::Move { distance } => todo!(), |
35 | // Action::Stop => {} | 35 | // Action::Stop => todo!(), |
36 | // } | 36 | // } |
37 | // } | 37 | // } |
38 | // ``` | 38 | // ``` |
@@ -129,7 +129,7 @@ pub(crate) fn fill_match_arms(acc: &mut Assists, ctx: &AssistContext) -> Option< | |||
129 | |builder| { | 129 | |builder| { |
130 | let new_match_arm_list = match_arm_list.clone_for_update(); | 130 | let new_match_arm_list = match_arm_list.clone_for_update(); |
131 | let missing_arms = missing_pats | 131 | let missing_arms = missing_pats |
132 | .map(|pat| make::match_arm(iter::once(pat), make::expr_empty_block())) | 132 | .map(|pat| make::match_arm(iter::once(pat), make::ext::expr_todo())) |
133 | .map(|it| it.clone_for_update()); | 133 | .map(|it| it.clone_for_update()); |
134 | 134 | ||
135 | let catch_all_arm = new_match_arm_list | 135 | let catch_all_arm = new_match_arm_list |
@@ -350,8 +350,8 @@ fn foo(a: bool) { | |||
350 | r#" | 350 | r#" |
351 | fn foo(a: bool) { | 351 | fn foo(a: bool) { |
352 | match a { | 352 | match a { |
353 | $0true => {} | 353 | $0true => todo!(), |
354 | false => {} | 354 | false => todo!(), |
355 | } | 355 | } |
356 | } | 356 | } |
357 | "#, | 357 | "#, |
@@ -373,7 +373,7 @@ fn foo(a: bool) { | |||
373 | fn foo(a: bool) { | 373 | fn foo(a: bool) { |
374 | match a { | 374 | match a { |
375 | true => {} | 375 | true => {} |
376 | $0false => {} | 376 | $0false => todo!(), |
377 | } | 377 | } |
378 | } | 378 | } |
379 | "#, | 379 | "#, |
@@ -410,10 +410,10 @@ fn foo(a: bool) { | |||
410 | r#" | 410 | r#" |
411 | fn foo(a: bool) { | 411 | fn foo(a: bool) { |
412 | match (a, a) { | 412 | match (a, a) { |
413 | $0(true, true) => {} | 413 | $0(true, true) => todo!(), |
414 | (true, false) => {} | 414 | (true, false) => todo!(), |
415 | (false, true) => {} | 415 | (false, true) => todo!(), |
416 | (false, false) => {} | 416 | (false, false) => todo!(), |
417 | } | 417 | } |
418 | } | 418 | } |
419 | "#, | 419 | "#, |
@@ -435,9 +435,9 @@ fn foo(a: bool) { | |||
435 | fn foo(a: bool) { | 435 | fn foo(a: bool) { |
436 | match (a, a) { | 436 | match (a, a) { |
437 | (false, true) => {} | 437 | (false, true) => {} |
438 | $0(true, true) => {} | 438 | $0(true, true) => todo!(), |
439 | (true, false) => {} | 439 | (true, false) => todo!(), |
440 | (false, false) => {} | 440 | (false, false) => todo!(), |
441 | } | 441 | } |
442 | } | 442 | } |
443 | "#, | 443 | "#, |
@@ -471,7 +471,7 @@ fn main() { | |||
471 | match A::As { | 471 | match A::As { |
472 | A::Bs { x, y: Some(_) } => {} | 472 | A::Bs { x, y: Some(_) } => {} |
473 | A::Cs(_, Some(_)) => {} | 473 | A::Cs(_, Some(_)) => {} |
474 | $0A::As => {} | 474 | $0A::As => todo!(), |
475 | } | 475 | } |
476 | } | 476 | } |
477 | "#, | 477 | "#, |
@@ -499,7 +499,7 @@ use Option::*; | |||
499 | fn main() { | 499 | fn main() { |
500 | match None { | 500 | match None { |
501 | None => {} | 501 | None => {} |
502 | Some(${0:_}) => {} | 502 | Some(${0:_}) => todo!(), |
503 | } | 503 | } |
504 | } | 504 | } |
505 | "#, | 505 | "#, |
@@ -523,7 +523,7 @@ enum A { As, Bs, Cs(Option<i32>) } | |||
523 | fn main() { | 523 | fn main() { |
524 | match A::As { | 524 | match A::As { |
525 | A::Cs(_) | A::Bs => {} | 525 | A::Cs(_) | A::Bs => {} |
526 | $0A::As => {} | 526 | $0A::As => todo!(), |
527 | } | 527 | } |
528 | } | 528 | } |
529 | "#, | 529 | "#, |
@@ -553,8 +553,8 @@ fn main() { | |||
553 | A::Bs if 0 < 1 => {} | 553 | A::Bs if 0 < 1 => {} |
554 | A::Ds(_value) => { let x = 1; } | 554 | A::Ds(_value) => { let x = 1; } |
555 | A::Es(B::Xs) => (), | 555 | A::Es(B::Xs) => (), |
556 | $0A::As => {} | 556 | $0A::As => todo!(), |
557 | A::Cs => {} | 557 | A::Cs => todo!(), |
558 | } | 558 | } |
559 | } | 559 | } |
560 | "#, | 560 | "#, |
@@ -580,7 +580,7 @@ fn main() { | |||
580 | match A::As { | 580 | match A::As { |
581 | A::As(_) => {} | 581 | A::As(_) => {} |
582 | a @ A::Bs(_) => {} | 582 | a @ A::Bs(_) => {} |
583 | A::Cs(${0:_}) => {} | 583 | A::Cs(${0:_}) => todo!(), |
584 | } | 584 | } |
585 | } | 585 | } |
586 | "#, | 586 | "#, |
@@ -605,11 +605,11 @@ enum A { As, Bs, Cs(String), Ds(String, String), Es { x: usize, y: usize } } | |||
605 | fn main() { | 605 | fn main() { |
606 | let a = A::As; | 606 | let a = A::As; |
607 | match a { | 607 | match a { |
608 | $0A::As => {} | 608 | $0A::As => todo!(), |
609 | A::Bs => {} | 609 | A::Bs => todo!(), |
610 | A::Cs(_) => {} | 610 | A::Cs(_) => todo!(), |
611 | A::Ds(_, _) => {} | 611 | A::Ds(_, _) => todo!(), |
612 | A::Es { x, y } => {} | 612 | A::Es { x, y } => todo!(), |
613 | } | 613 | } |
614 | } | 614 | } |
615 | "#, | 615 | "#, |
@@ -638,10 +638,10 @@ fn main() { | |||
638 | let a = A::One; | 638 | let a = A::One; |
639 | let b = B::One; | 639 | let b = B::One; |
640 | match (a, b) { | 640 | match (a, b) { |
641 | $0(A::One, B::One) => {} | 641 | $0(A::One, B::One) => todo!(), |
642 | (A::One, B::Two) => {} | 642 | (A::One, B::Two) => todo!(), |
643 | (A::Two, B::One) => {} | 643 | (A::Two, B::One) => todo!(), |
644 | (A::Two, B::Two) => {} | 644 | (A::Two, B::Two) => todo!(), |
645 | } | 645 | } |
646 | } | 646 | } |
647 | "#, | 647 | "#, |
@@ -670,10 +670,10 @@ fn main() { | |||
670 | let a = A::One; | 670 | let a = A::One; |
671 | let b = B::One; | 671 | let b = B::One; |
672 | match (&a, &b) { | 672 | match (&a, &b) { |
673 | $0(A::One, B::One) => {} | 673 | $0(A::One, B::One) => todo!(), |
674 | (A::One, B::Two) => {} | 674 | (A::One, B::Two) => todo!(), |
675 | (A::Two, B::One) => {} | 675 | (A::Two, B::One) => todo!(), |
676 | (A::Two, B::Two) => {} | 676 | (A::Two, B::Two) => todo!(), |
677 | } | 677 | } |
678 | } | 678 | } |
679 | "#, | 679 | "#, |
@@ -705,9 +705,9 @@ fn main() { | |||
705 | let b = B::One; | 705 | let b = B::One; |
706 | match (a, b) { | 706 | match (a, b) { |
707 | (A::Two, B::One) => {} | 707 | (A::Two, B::One) => {} |
708 | $0(A::One, B::One) => {} | 708 | $0(A::One, B::One) => todo!(), |
709 | (A::One, B::Two) => {} | 709 | (A::One, B::Two) => todo!(), |
710 | (A::Two, B::Two) => {} | 710 | (A::Two, B::Two) => todo!(), |
711 | } | 711 | } |
712 | } | 712 | } |
713 | "#, | 713 | "#, |
@@ -736,7 +736,7 @@ fn main() { | |||
736 | match (a, b) { | 736 | match (a, b) { |
737 | (Some(_), _) => {} | 737 | (Some(_), _) => {} |
738 | (None, Some(_)) => {} | 738 | (None, Some(_)) => {} |
739 | $0(None, None) => {} | 739 | $0(None, None) => todo!(), |
740 | } | 740 | } |
741 | } | 741 | } |
742 | "#, | 742 | "#, |
@@ -801,8 +801,8 @@ enum A { One, Two } | |||
801 | fn main() { | 801 | fn main() { |
802 | let a = A::One; | 802 | let a = A::One; |
803 | match (a, ) { | 803 | match (a, ) { |
804 | $0(A::One,) => {} | 804 | $0(A::One,) => todo!(), |
805 | (A::Two,) => {} | 805 | (A::Two,) => todo!(), |
806 | } | 806 | } |
807 | } | 807 | } |
808 | "#, | 808 | "#, |
@@ -826,7 +826,7 @@ enum A { As } | |||
826 | 826 | ||
827 | fn foo(a: &A) { | 827 | fn foo(a: &A) { |
828 | match a { | 828 | match a { |
829 | $0A::As => {} | 829 | $0A::As => todo!(), |
830 | } | 830 | } |
831 | } | 831 | } |
832 | "#, | 832 | "#, |
@@ -851,7 +851,7 @@ enum A { | |||
851 | 851 | ||
852 | fn foo(a: &mut A) { | 852 | fn foo(a: &mut A) { |
853 | match a { | 853 | match a { |
854 | $0A::Es { x, y } => {} | 854 | $0A::Es { x, y } => todo!(), |
855 | } | 855 | } |
856 | } | 856 | } |
857 | "#, | 857 | "#, |
@@ -891,8 +891,8 @@ enum E { X, Y } | |||
891 | 891 | ||
892 | fn main() { | 892 | fn main() { |
893 | match E::X { | 893 | match E::X { |
894 | $0E::X => {} | 894 | $0E::X => todo!(), |
895 | E::Y => {} | 895 | E::Y => todo!(), |
896 | } | 896 | } |
897 | } | 897 | } |
898 | "#, | 898 | "#, |
@@ -919,8 +919,8 @@ use foo::E::X; | |||
919 | 919 | ||
920 | fn main() { | 920 | fn main() { |
921 | match X { | 921 | match X { |
922 | $0X => {} | 922 | $0X => todo!(), |
923 | foo::E::Y => {} | 923 | foo::E::Y => todo!(), |
924 | } | 924 | } |
925 | } | 925 | } |
926 | "#, | 926 | "#, |
@@ -947,7 +947,7 @@ fn foo(a: A) { | |||
947 | match a { | 947 | match a { |
948 | // foo bar baz | 948 | // foo bar baz |
949 | A::One => {} | 949 | A::One => {} |
950 | $0A::Two => {} | 950 | $0A::Two => todo!(), |
951 | // This is where the rest should be | 951 | // This is where the rest should be |
952 | } | 952 | } |
953 | } | 953 | } |
@@ -971,8 +971,8 @@ fn foo(a: A) { | |||
971 | enum A { One, Two } | 971 | enum A { One, Two } |
972 | fn foo(a: A) { | 972 | fn foo(a: A) { |
973 | match a { | 973 | match a { |
974 | $0A::One => {} | 974 | $0A::One => todo!(), |
975 | A::Two => {} | 975 | A::Two => todo!(), |
976 | // foo bar baz | 976 | // foo bar baz |
977 | } | 977 | } |
978 | } | 978 | } |
@@ -996,8 +996,8 @@ fn foo(a: A) { | |||
996 | enum A { One, Two, } | 996 | enum A { One, Two, } |
997 | fn foo(a: A) { | 997 | fn foo(a: A) { |
998 | match a { | 998 | match a { |
999 | $0A::One => {} | 999 | $0A::One => todo!(), |
1000 | A::Two => {} | 1000 | A::Two => todo!(), |
1001 | } | 1001 | } |
1002 | } | 1002 | } |
1003 | "#, | 1003 | "#, |
@@ -1021,8 +1021,8 @@ fn foo(opt: Option<i32>) { | |||
1021 | r#" | 1021 | r#" |
1022 | fn foo(opt: Option<i32>) { | 1022 | fn foo(opt: Option<i32>) { |
1023 | match opt { | 1023 | match opt { |
1024 | Some(${0:_}) => {} | 1024 | Some(${0:_}) => todo!(), |
1025 | None => {} | 1025 | None => todo!(), |
1026 | } | 1026 | } |
1027 | } | 1027 | } |
1028 | "#, | 1028 | "#, |
@@ -1054,9 +1054,9 @@ enum Test { | |||
1054 | 1054 | ||
1055 | fn foo(t: Test) { | 1055 | fn foo(t: Test) { |
1056 | m!(match t { | 1056 | m!(match t { |
1057 | $0Test::A => {} | 1057 | $0Test::A => todo!(), |
1058 | Test::B => {} | 1058 | Test::B => todo!(), |
1059 | Test::C => {} | 1059 | Test::C => todo!(), |
1060 | }); | 1060 | }); |
1061 | }"#, | 1061 | }"#, |
1062 | ); | 1062 | ); |
@@ -1076,4 +1076,44 @@ fn foo(tuple: (A, A)) { | |||
1076 | "#, | 1076 | "#, |
1077 | ); | 1077 | ); |
1078 | } | 1078 | } |
1079 | |||
1080 | #[test] | ||
1081 | fn adds_comma_before_new_arms() { | ||
1082 | check_assist( | ||
1083 | fill_match_arms, | ||
1084 | r#" | ||
1085 | fn foo(t: bool) { | ||
1086 | match $0t { | ||
1087 | true => 1 + 2 | ||
1088 | } | ||
1089 | }"#, | ||
1090 | r#" | ||
1091 | fn foo(t: bool) { | ||
1092 | match t { | ||
1093 | true => 1 + 2, | ||
1094 | $0false => todo!(), | ||
1095 | } | ||
1096 | }"#, | ||
1097 | ); | ||
1098 | } | ||
1099 | |||
1100 | #[test] | ||
1101 | fn does_not_add_extra_comma() { | ||
1102 | check_assist( | ||
1103 | fill_match_arms, | ||
1104 | r#" | ||
1105 | fn foo(t: bool) { | ||
1106 | match $0t { | ||
1107 | true => 1 + 2, | ||
1108 | } | ||
1109 | }"#, | ||
1110 | r#" | ||
1111 | fn foo(t: bool) { | ||
1112 | match t { | ||
1113 | true => 1 + 2, | ||
1114 | $0false => todo!(), | ||
1115 | } | ||
1116 | }"#, | ||
1117 | ); | ||
1118 | } | ||
1079 | } | 1119 | } |
diff --git a/crates/ide_assists/src/handlers/fix_visibility.rs b/crates/ide_assists/src/handlers/fix_visibility.rs index 6c7824e55..89f7b2c2c 100644 --- a/crates/ide_assists/src/handlers/fix_visibility.rs +++ b/crates/ide_assists/src/handlers/fix_visibility.rs | |||
@@ -85,7 +85,7 @@ fn add_vis_to_referenced_module_def(acc: &mut Assists, ctx: &AssistContext) -> O | |||
85 | 85 | ||
86 | fn add_vis_to_referenced_record_field(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | 86 | fn add_vis_to_referenced_record_field(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
87 | let record_field: ast::RecordExprField = ctx.find_node_at_offset()?; | 87 | let record_field: ast::RecordExprField = ctx.find_node_at_offset()?; |
88 | let (record_field_def, _) = ctx.sema.resolve_record_field(&record_field)?; | 88 | let (record_field_def, _, _) = ctx.sema.resolve_record_field(&record_field)?; |
89 | 89 | ||
90 | let current_module = ctx.sema.scope(record_field.syntax()).module()?; | 90 | let current_module = ctx.sema.scope(record_field.syntax()).module()?; |
91 | let visibility = record_field_def.visibility(ctx.db()); | 91 | let visibility = record_field_def.visibility(ctx.db()); |
diff --git a/crates/ide_assists/src/handlers/generate_getter.rs b/crates/ide_assists/src/handlers/generate_getter.rs index df7d1bb95..09971226e 100644 --- a/crates/ide_assists/src/handlers/generate_getter.rs +++ b/crates/ide_assists/src/handlers/generate_getter.rs | |||
@@ -23,12 +23,46 @@ use crate::{ | |||
23 | // | 23 | // |
24 | // impl Person { | 24 | // impl Person { |
25 | // /// Get a reference to the person's name. | 25 | // /// Get a reference to the person's name. |
26 | // fn name(&self) -> &String { | 26 | // fn $0name(&self) -> &str { |
27 | // &self.name | 27 | // self.name.as_str() |
28 | // } | 28 | // } |
29 | // } | 29 | // } |
30 | // ``` | 30 | // ``` |
31 | pub(crate) fn generate_getter(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | 31 | pub(crate) fn generate_getter(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
32 | generate_getter_impl(acc, ctx, false) | ||
33 | } | ||
34 | |||
35 | // Assist: generate_getter_mut | ||
36 | // | ||
37 | // Generate a mut getter method. | ||
38 | // | ||
39 | // ``` | ||
40 | // struct Person { | ||
41 | // nam$0e: String, | ||
42 | // } | ||
43 | // ``` | ||
44 | // -> | ||
45 | // ``` | ||
46 | // struct Person { | ||
47 | // name: String, | ||
48 | // } | ||
49 | // | ||
50 | // impl Person { | ||
51 | // /// Get a mutable reference to the person's name. | ||
52 | // fn $0name_mut(&mut self) -> &mut String { | ||
53 | // &mut self.name | ||
54 | // } | ||
55 | // } | ||
56 | // ``` | ||
57 | pub(crate) fn generate_getter_mut(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | ||
58 | generate_getter_impl(acc, ctx, true) | ||
59 | } | ||
60 | |||
61 | pub(crate) fn generate_getter_impl( | ||
62 | acc: &mut Assists, | ||
63 | ctx: &AssistContext, | ||
64 | mutable: bool, | ||
65 | ) -> Option<()> { | ||
32 | let strukt = ctx.find_node_at_offset::<ast::Struct>()?; | 66 | let strukt = ctx.find_node_at_offset::<ast::Struct>()?; |
33 | let field = ctx.find_node_at_offset::<ast::RecordField>()?; | 67 | let field = ctx.find_node_at_offset::<ast::RecordField>()?; |
34 | 68 | ||
@@ -37,39 +71,52 @@ pub(crate) fn generate_getter(acc: &mut Assists, ctx: &AssistContext) -> Option< | |||
37 | let field_ty = field.ty()?; | 71 | let field_ty = field.ty()?; |
38 | 72 | ||
39 | // Return early if we've found an existing fn | 73 | // Return early if we've found an existing fn |
40 | let fn_name = to_lower_snake_case(&field_name.to_string()); | 74 | let mut fn_name = to_lower_snake_case(&field_name.to_string()); |
75 | if mutable { | ||
76 | format_to!(fn_name, "_mut"); | ||
77 | } | ||
41 | let impl_def = find_struct_impl(&ctx, &ast::Adt::Struct(strukt.clone()), fn_name.as_str())?; | 78 | let impl_def = find_struct_impl(&ctx, &ast::Adt::Struct(strukt.clone()), fn_name.as_str())?; |
42 | 79 | ||
80 | let (id, label) = if mutable { | ||
81 | ("generate_getter_mut", "Generate a mut getter method") | ||
82 | } else { | ||
83 | ("generate_getter", "Generate a getter method") | ||
84 | }; | ||
43 | let target = field.syntax().text_range(); | 85 | let target = field.syntax().text_range(); |
44 | acc.add_group( | 86 | acc.add_group( |
45 | &GroupLabel("Generate getter/setter".to_owned()), | 87 | &GroupLabel("Generate getter/setter".to_owned()), |
46 | AssistId("generate_getter", AssistKind::Generate), | 88 | AssistId(id, AssistKind::Generate), |
47 | "Generate a getter method", | 89 | label, |
48 | target, | 90 | target, |
49 | |builder| { | 91 | |builder| { |
50 | let mut buf = String::with_capacity(512); | 92 | let mut buf = String::with_capacity(512); |
51 | 93 | ||
52 | let fn_name_spaced = fn_name.replace('_', " "); | ||
53 | let strukt_name_spaced = | ||
54 | to_lower_snake_case(&strukt_name.to_string()).replace('_', " "); | ||
55 | |||
56 | if impl_def.is_some() { | 94 | if impl_def.is_some() { |
57 | buf.push('\n'); | 95 | buf.push('\n'); |
58 | } | 96 | } |
59 | 97 | ||
60 | let vis = strukt.visibility().map_or(String::new(), |v| format!("{} ", v)); | 98 | let vis = strukt.visibility().map_or(String::new(), |v| format!("{} ", v)); |
99 | let (ty, body) = if mutable { | ||
100 | (format!("&mut {}", field_ty), format!("&mut self.{}", field_name)) | ||
101 | } else { | ||
102 | useless_type_special_case(&field_name.to_string(), &field_ty) | ||
103 | .unwrap_or_else(|| (format!("&{}", field_ty), format!("&self.{}", field_name))) | ||
104 | }; | ||
105 | |||
61 | format_to!( | 106 | format_to!( |
62 | buf, | 107 | buf, |
63 | " /// Get a reference to the {}'s {}. | 108 | " /// Get a {}reference to the {}'s {}. |
64 | {}fn {}(&self) -> &{} {{ | 109 | {}fn {}(&{}self) -> {} {{ |
65 | &self.{} | 110 | {} |
66 | }}", | 111 | }}", |
67 | strukt_name_spaced, | 112 | mutable.then(|| "mutable ").unwrap_or_default(), |
68 | fn_name_spaced, | 113 | to_lower_snake_case(&strukt_name.to_string()).replace('_', " "), |
114 | fn_name.trim_end_matches("_mut").replace('_', " "), | ||
69 | vis, | 115 | vis, |
70 | fn_name, | 116 | fn_name, |
71 | field_ty, | 117 | mutable.then(|| "mut ").unwrap_or_default(), |
72 | fn_name, | 118 | ty, |
119 | body, | ||
73 | ); | 120 | ); |
74 | 121 | ||
75 | let start_offset = impl_def | 122 | let start_offset = impl_def |
@@ -79,56 +126,120 @@ pub(crate) fn generate_getter(acc: &mut Assists, ctx: &AssistContext) -> Option< | |||
79 | strukt.syntax().text_range().end() | 126 | strukt.syntax().text_range().end() |
80 | }); | 127 | }); |
81 | 128 | ||
82 | builder.insert(start_offset, buf); | 129 | match ctx.config.snippet_cap { |
130 | Some(cap) => { | ||
131 | builder.insert_snippet(cap, start_offset, buf.replacen("fn ", "fn $0", 1)) | ||
132 | } | ||
133 | None => builder.insert(start_offset, buf), | ||
134 | } | ||
83 | }, | 135 | }, |
84 | ) | 136 | ) |
85 | } | 137 | } |
86 | 138 | ||
139 | fn useless_type_special_case(field_name: &str, field_ty: &ast::Type) -> Option<(String, String)> { | ||
140 | if field_ty.to_string() == "String" { | ||
141 | cov_mark::hit!(useless_type_special_case); | ||
142 | return Some(("&str".to_string(), format!("self.{}.as_str()", field_name))); | ||
143 | } | ||
144 | if let Some(arg) = ty_ctor(field_ty, "Vec") { | ||
145 | return Some((format!("&[{}]", arg), format!("self.{}.as_slice()", field_name))); | ||
146 | } | ||
147 | if let Some(arg) = ty_ctor(field_ty, "Box") { | ||
148 | return Some((format!("&{}", arg), format!("self.{}.as_ref()", field_name))); | ||
149 | } | ||
150 | if let Some(arg) = ty_ctor(field_ty, "Option") { | ||
151 | return Some((format!("Option<&{}>", arg), format!("self.{}.as_ref()", field_name))); | ||
152 | } | ||
153 | None | ||
154 | } | ||
155 | |||
156 | // FIXME: This should rely on semantic info. | ||
157 | fn ty_ctor(ty: &ast::Type, ctor: &str) -> Option<String> { | ||
158 | let res = ty.to_string().strip_prefix(ctor)?.strip_prefix('<')?.strip_suffix('>')?.to_string(); | ||
159 | Some(res) | ||
160 | } | ||
161 | |||
87 | #[cfg(test)] | 162 | #[cfg(test)] |
88 | mod tests { | 163 | mod tests { |
89 | use crate::tests::{check_assist, check_assist_not_applicable}; | 164 | use crate::tests::{check_assist, check_assist_not_applicable}; |
90 | 165 | ||
91 | use super::*; | 166 | use super::*; |
92 | 167 | ||
93 | fn check_not_applicable(ra_fixture: &str) { | ||
94 | check_assist_not_applicable(generate_getter, ra_fixture) | ||
95 | } | ||
96 | |||
97 | #[test] | 168 | #[test] |
98 | fn test_generate_getter_from_field() { | 169 | fn test_generate_getter_from_field() { |
99 | check_assist( | 170 | check_assist( |
100 | generate_getter, | 171 | generate_getter, |
101 | r#" | 172 | r#" |
102 | struct Context<T: Clone> { | 173 | struct Context { |
103 | dat$0a: T, | 174 | dat$0a: Data, |
104 | }"#, | 175 | } |
176 | "#, | ||
105 | r#" | 177 | r#" |
106 | struct Context<T: Clone> { | 178 | struct Context { |
107 | data: T, | 179 | data: Data, |
108 | } | 180 | } |
109 | 181 | ||
110 | impl<T: Clone> Context<T> { | 182 | impl Context { |
111 | /// Get a reference to the context's data. | 183 | /// Get a reference to the context's data. |
112 | fn data(&self) -> &T { | 184 | fn $0data(&self) -> &Data { |
113 | &self.data | 185 | &self.data |
114 | } | 186 | } |
115 | }"#, | 187 | } |
188 | "#, | ||
189 | ); | ||
190 | |||
191 | check_assist( | ||
192 | generate_getter_mut, | ||
193 | r#" | ||
194 | struct Context { | ||
195 | dat$0a: Data, | ||
196 | } | ||
197 | "#, | ||
198 | r#" | ||
199 | struct Context { | ||
200 | data: Data, | ||
201 | } | ||
202 | |||
203 | impl Context { | ||
204 | /// Get a mutable reference to the context's data. | ||
205 | fn $0data_mut(&mut self) -> &mut Data { | ||
206 | &mut self.data | ||
207 | } | ||
208 | } | ||
209 | "#, | ||
116 | ); | 210 | ); |
117 | } | 211 | } |
118 | 212 | ||
119 | #[test] | 213 | #[test] |
120 | fn test_generate_getter_already_implemented() { | 214 | fn test_generate_getter_already_implemented() { |
121 | check_not_applicable( | 215 | check_assist_not_applicable( |
216 | generate_getter, | ||
122 | r#" | 217 | r#" |
123 | struct Context<T: Clone> { | 218 | struct Context { |
124 | dat$0a: T, | 219 | dat$0a: Data, |
125 | } | 220 | } |
126 | 221 | ||
127 | impl<T: Clone> Context<T> { | 222 | impl Context { |
128 | fn data(&self) -> &T { | 223 | fn data(&self) -> &Data { |
129 | &self.data | 224 | &self.data |
130 | } | 225 | } |
131 | }"#, | 226 | } |
227 | "#, | ||
228 | ); | ||
229 | |||
230 | check_assist_not_applicable( | ||
231 | generate_getter_mut, | ||
232 | r#" | ||
233 | struct Context { | ||
234 | dat$0a: Data, | ||
235 | } | ||
236 | |||
237 | impl Context { | ||
238 | fn data_mut(&mut self) -> &mut Data { | ||
239 | &mut self.data | ||
240 | } | ||
241 | } | ||
242 | "#, | ||
132 | ); | 243 | ); |
133 | } | 244 | } |
134 | 245 | ||
@@ -137,20 +248,22 @@ impl<T: Clone> Context<T> { | |||
137 | check_assist( | 248 | check_assist( |
138 | generate_getter, | 249 | generate_getter, |
139 | r#" | 250 | r#" |
140 | pub(crate) struct Context<T: Clone> { | 251 | pub(crate) struct Context { |
141 | dat$0a: T, | 252 | dat$0a: Data, |
142 | }"#, | 253 | } |
254 | "#, | ||
143 | r#" | 255 | r#" |
144 | pub(crate) struct Context<T: Clone> { | 256 | pub(crate) struct Context { |
145 | data: T, | 257 | data: Data, |
146 | } | 258 | } |
147 | 259 | ||
148 | impl<T: Clone> Context<T> { | 260 | impl Context { |
149 | /// Get a reference to the context's data. | 261 | /// Get a reference to the context's data. |
150 | pub(crate) fn data(&self) -> &T { | 262 | pub(crate) fn $0data(&self) -> &Data { |
151 | &self.data | 263 | &self.data |
152 | } | 264 | } |
153 | }"#, | 265 | } |
266 | "#, | ||
154 | ); | 267 | ); |
155 | } | 268 | } |
156 | 269 | ||
@@ -159,34 +272,105 @@ impl<T: Clone> Context<T> { | |||
159 | check_assist( | 272 | check_assist( |
160 | generate_getter, | 273 | generate_getter, |
161 | r#" | 274 | r#" |
162 | struct Context<T: Clone> { | 275 | struct Context { |
163 | data: T, | 276 | data: Data, |
164 | cou$0nt: usize, | 277 | cou$0nt: usize, |
165 | } | 278 | } |
166 | 279 | ||
167 | impl<T: Clone> Context<T> { | 280 | impl Context { |
168 | /// Get a reference to the context's data. | 281 | /// Get a reference to the context's data. |
169 | fn data(&self) -> &T { | 282 | fn data(&self) -> &Data { |
170 | &self.data | 283 | &self.data |
171 | } | 284 | } |
172 | }"#, | 285 | } |
286 | "#, | ||
173 | r#" | 287 | r#" |
174 | struct Context<T: Clone> { | 288 | struct Context { |
175 | data: T, | 289 | data: Data, |
176 | count: usize, | 290 | count: usize, |
177 | } | 291 | } |
178 | 292 | ||
179 | impl<T: Clone> Context<T> { | 293 | impl Context { |
180 | /// Get a reference to the context's data. | 294 | /// Get a reference to the context's data. |
181 | fn data(&self) -> &T { | 295 | fn data(&self) -> &Data { |
182 | &self.data | 296 | &self.data |
183 | } | 297 | } |
184 | 298 | ||
185 | /// Get a reference to the context's count. | 299 | /// Get a reference to the context's count. |
186 | fn count(&self) -> &usize { | 300 | fn $0count(&self) -> &usize { |
187 | &self.count | 301 | &self.count |
188 | } | 302 | } |
189 | }"#, | 303 | } |
304 | "#, | ||
305 | ); | ||
306 | } | ||
307 | |||
308 | #[test] | ||
309 | fn test_special_cases() { | ||
310 | cov_mark::check!(useless_type_special_case); | ||
311 | check_assist( | ||
312 | generate_getter, | ||
313 | r#" | ||
314 | struct S { foo: $0String } | ||
315 | "#, | ||
316 | r#" | ||
317 | struct S { foo: String } | ||
318 | |||
319 | impl S { | ||
320 | /// Get a reference to the s's foo. | ||
321 | fn $0foo(&self) -> &str { | ||
322 | self.foo.as_str() | ||
323 | } | ||
324 | } | ||
325 | "#, | ||
326 | ); | ||
327 | check_assist( | ||
328 | generate_getter, | ||
329 | r#" | ||
330 | struct S { foo: $0Box<Sweets> } | ||
331 | "#, | ||
332 | r#" | ||
333 | struct S { foo: Box<Sweets> } | ||
334 | |||
335 | impl S { | ||
336 | /// Get a reference to the s's foo. | ||
337 | fn $0foo(&self) -> &Sweets { | ||
338 | self.foo.as_ref() | ||
339 | } | ||
340 | } | ||
341 | "#, | ||
342 | ); | ||
343 | check_assist( | ||
344 | generate_getter, | ||
345 | r#" | ||
346 | struct S { foo: $0Vec<()> } | ||
347 | "#, | ||
348 | r#" | ||
349 | struct S { foo: Vec<()> } | ||
350 | |||
351 | impl S { | ||
352 | /// Get a reference to the s's foo. | ||
353 | fn $0foo(&self) -> &[()] { | ||
354 | self.foo.as_slice() | ||
355 | } | ||
356 | } | ||
357 | "#, | ||
358 | ); | ||
359 | check_assist( | ||
360 | generate_getter, | ||
361 | r#" | ||
362 | struct S { foo: $0Option<Failure> } | ||
363 | "#, | ||
364 | r#" | ||
365 | struct S { foo: Option<Failure> } | ||
366 | |||
367 | impl S { | ||
368 | /// Get a reference to the s's foo. | ||
369 | fn $0foo(&self) -> Option<&Failure> { | ||
370 | self.foo.as_ref() | ||
371 | } | ||
372 | } | ||
373 | "#, | ||
190 | ); | 374 | ); |
191 | } | 375 | } |
192 | } | 376 | } |
diff --git a/crates/ide_assists/src/handlers/generate_getter_mut.rs b/crates/ide_assists/src/handlers/generate_getter_mut.rs deleted file mode 100644 index 821c2eed5..000000000 --- a/crates/ide_assists/src/handlers/generate_getter_mut.rs +++ /dev/null | |||
@@ -1,195 +0,0 @@ | |||
1 | use stdx::{format_to, to_lower_snake_case}; | ||
2 | use syntax::ast::{self, AstNode, NameOwner, VisibilityOwner}; | ||
3 | |||
4 | use crate::{ | ||
5 | utils::{find_impl_block_end, find_struct_impl, generate_impl_text}, | ||
6 | AssistContext, AssistId, AssistKind, Assists, GroupLabel, | ||
7 | }; | ||
8 | |||
9 | // Assist: generate_getter_mut | ||
10 | // | ||
11 | // Generate a mut getter method. | ||
12 | // | ||
13 | // ``` | ||
14 | // struct Person { | ||
15 | // nam$0e: String, | ||
16 | // } | ||
17 | // ``` | ||
18 | // -> | ||
19 | // ``` | ||
20 | // struct Person { | ||
21 | // name: String, | ||
22 | // } | ||
23 | // | ||
24 | // impl Person { | ||
25 | // /// Get a mutable reference to the person's name. | ||
26 | // fn name_mut(&mut self) -> &mut String { | ||
27 | // &mut self.name | ||
28 | // } | ||
29 | // } | ||
30 | // ``` | ||
31 | pub(crate) fn generate_getter_mut(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | ||
32 | let strukt = ctx.find_node_at_offset::<ast::Struct>()?; | ||
33 | let field = ctx.find_node_at_offset::<ast::RecordField>()?; | ||
34 | |||
35 | let strukt_name = strukt.name()?; | ||
36 | let field_name = field.name()?; | ||
37 | let field_ty = field.ty()?; | ||
38 | |||
39 | // Return early if we've found an existing fn | ||
40 | let fn_name = to_lower_snake_case(&field_name.to_string()); | ||
41 | let impl_def = find_struct_impl( | ||
42 | &ctx, | ||
43 | &ast::Adt::Struct(strukt.clone()), | ||
44 | format!("{}_mut", fn_name).as_str(), | ||
45 | )?; | ||
46 | |||
47 | let target = field.syntax().text_range(); | ||
48 | acc.add_group( | ||
49 | &GroupLabel("Generate getter/setter".to_owned()), | ||
50 | AssistId("generate_getter_mut", AssistKind::Generate), | ||
51 | "Generate a mut getter method", | ||
52 | target, | ||
53 | |builder| { | ||
54 | let mut buf = String::with_capacity(512); | ||
55 | let fn_name_spaced = fn_name.replace('_', " "); | ||
56 | let strukt_name_spaced = | ||
57 | to_lower_snake_case(&strukt_name.to_string()).replace('_', " "); | ||
58 | |||
59 | if impl_def.is_some() { | ||
60 | buf.push('\n'); | ||
61 | } | ||
62 | |||
63 | let vis = strukt.visibility().map_or(String::new(), |v| format!("{} ", v)); | ||
64 | format_to!( | ||
65 | buf, | ||
66 | " /// Get a mutable reference to the {}'s {}. | ||
67 | {}fn {}_mut(&mut self) -> &mut {} {{ | ||
68 | &mut self.{} | ||
69 | }}", | ||
70 | strukt_name_spaced, | ||
71 | fn_name_spaced, | ||
72 | vis, | ||
73 | fn_name, | ||
74 | field_ty, | ||
75 | fn_name, | ||
76 | ); | ||
77 | |||
78 | let start_offset = impl_def | ||
79 | .and_then(|impl_def| find_impl_block_end(impl_def, &mut buf)) | ||
80 | .unwrap_or_else(|| { | ||
81 | buf = generate_impl_text(&ast::Adt::Struct(strukt.clone()), &buf); | ||
82 | strukt.syntax().text_range().end() | ||
83 | }); | ||
84 | |||
85 | builder.insert(start_offset, buf); | ||
86 | }, | ||
87 | ) | ||
88 | } | ||
89 | |||
90 | #[cfg(test)] | ||
91 | mod tests { | ||
92 | use crate::tests::{check_assist, check_assist_not_applicable}; | ||
93 | |||
94 | use super::*; | ||
95 | |||
96 | fn check_not_applicable(ra_fixture: &str) { | ||
97 | check_assist_not_applicable(generate_getter_mut, ra_fixture) | ||
98 | } | ||
99 | |||
100 | #[test] | ||
101 | fn test_generate_getter_mut_from_field() { | ||
102 | check_assist( | ||
103 | generate_getter_mut, | ||
104 | r#" | ||
105 | struct Context<T: Clone> { | ||
106 | dat$0a: T, | ||
107 | }"#, | ||
108 | r#" | ||
109 | struct Context<T: Clone> { | ||
110 | data: T, | ||
111 | } | ||
112 | |||
113 | impl<T: Clone> Context<T> { | ||
114 | /// Get a mutable reference to the context's data. | ||
115 | fn data_mut(&mut self) -> &mut T { | ||
116 | &mut self.data | ||
117 | } | ||
118 | }"#, | ||
119 | ); | ||
120 | } | ||
121 | |||
122 | #[test] | ||
123 | fn test_generate_getter_mut_already_implemented() { | ||
124 | check_not_applicable( | ||
125 | r#" | ||
126 | struct Context<T: Clone> { | ||
127 | dat$0a: T, | ||
128 | } | ||
129 | |||
130 | impl<T: Clone> Context<T> { | ||
131 | fn data_mut(&mut self) -> &mut T { | ||
132 | &mut self.data | ||
133 | } | ||
134 | }"#, | ||
135 | ); | ||
136 | } | ||
137 | |||
138 | #[test] | ||
139 | fn test_generate_getter_mut_from_field_with_visibility_marker() { | ||
140 | check_assist( | ||
141 | generate_getter_mut, | ||
142 | r#" | ||
143 | pub(crate) struct Context<T: Clone> { | ||
144 | dat$0a: T, | ||
145 | }"#, | ||
146 | r#" | ||
147 | pub(crate) struct Context<T: Clone> { | ||
148 | data: T, | ||
149 | } | ||
150 | |||
151 | impl<T: Clone> Context<T> { | ||
152 | /// Get a mutable reference to the context's data. | ||
153 | pub(crate) fn data_mut(&mut self) -> &mut T { | ||
154 | &mut self.data | ||
155 | } | ||
156 | }"#, | ||
157 | ); | ||
158 | } | ||
159 | |||
160 | #[test] | ||
161 | fn test_multiple_generate_getter_mut() { | ||
162 | check_assist( | ||
163 | generate_getter_mut, | ||
164 | r#" | ||
165 | struct Context<T: Clone> { | ||
166 | data: T, | ||
167 | cou$0nt: usize, | ||
168 | } | ||
169 | |||
170 | impl<T: Clone> Context<T> { | ||
171 | /// Get a mutable reference to the context's data. | ||
172 | fn data_mut(&mut self) -> &mut T { | ||
173 | &mut self.data | ||
174 | } | ||
175 | }"#, | ||
176 | r#" | ||
177 | struct Context<T: Clone> { | ||
178 | data: T, | ||
179 | count: usize, | ||
180 | } | ||
181 | |||
182 | impl<T: Clone> Context<T> { | ||
183 | /// Get a mutable reference to the context's data. | ||
184 | fn data_mut(&mut self) -> &mut T { | ||
185 | &mut self.data | ||
186 | } | ||
187 | |||
188 | /// Get a mutable reference to the context's count. | ||
189 | fn count_mut(&mut self) -> &mut usize { | ||
190 | &mut self.count | ||
191 | } | ||
192 | }"#, | ||
193 | ); | ||
194 | } | ||
195 | } | ||
diff --git a/crates/ide_assists/src/lib.rs b/crates/ide_assists/src/lib.rs index 05644b6ff..16af72927 100644 --- a/crates/ide_assists/src/lib.rs +++ b/crates/ide_assists/src/lib.rs | |||
@@ -20,8 +20,7 @@ pub mod path_transform; | |||
20 | use std::str::FromStr; | 20 | use std::str::FromStr; |
21 | 21 | ||
22 | use hir::Semantics; | 22 | use hir::Semantics; |
23 | use ide_db::base_db::FileRange; | 23 | use ide_db::{base_db::FileRange, label::Label, source_change::SourceChange, RootDatabase}; |
24 | use ide_db::{label::Label, source_change::SourceChange, RootDatabase}; | ||
25 | use syntax::TextRange; | 24 | use syntax::TextRange; |
26 | 25 | ||
27 | pub(crate) use crate::assist_context::{AssistContext, Assists}; | 26 | pub(crate) use crate::assist_context::{AssistContext, Assists}; |
@@ -207,7 +206,6 @@ mod handlers { | |||
207 | mod generate_enum_projection_method; | 206 | mod generate_enum_projection_method; |
208 | mod generate_from_impl_for_enum; | 207 | mod generate_from_impl_for_enum; |
209 | mod generate_function; | 208 | mod generate_function; |
210 | mod generate_getter_mut; | ||
211 | mod generate_getter; | 209 | mod generate_getter; |
212 | mod generate_impl; | 210 | mod generate_impl; |
213 | mod generate_new; | 211 | mod generate_new; |
@@ -277,8 +275,8 @@ mod handlers { | |||
277 | generate_enum_projection_method::generate_enum_try_into_method, | 275 | generate_enum_projection_method::generate_enum_try_into_method, |
278 | generate_from_impl_for_enum::generate_from_impl_for_enum, | 276 | generate_from_impl_for_enum::generate_from_impl_for_enum, |
279 | generate_function::generate_function, | 277 | generate_function::generate_function, |
280 | generate_getter_mut::generate_getter_mut, | ||
281 | generate_getter::generate_getter, | 278 | generate_getter::generate_getter, |
279 | generate_getter::generate_getter_mut, | ||
282 | generate_impl::generate_impl, | 280 | generate_impl::generate_impl, |
283 | generate_new::generate_new, | 281 | generate_new::generate_new, |
284 | generate_setter::generate_setter, | 282 | generate_setter::generate_setter, |
diff --git a/crates/ide_assists/src/tests.rs b/crates/ide_assists/src/tests.rs index 6a9231e07..2b7c2d581 100644 --- a/crates/ide_assists/src/tests.rs +++ b/crates/ide_assists/src/tests.rs | |||
@@ -215,8 +215,8 @@ fn assist_order_field_struct() { | |||
215 | 215 | ||
216 | assert_eq!(assists.next().expect("expected assist").label, "Change visibility to pub(crate)"); | 216 | assert_eq!(assists.next().expect("expected assist").label, "Change visibility to pub(crate)"); |
217 | assert_eq!(assists.next().expect("expected assist").label, "Generate `Deref` impl using `bar`"); | 217 | assert_eq!(assists.next().expect("expected assist").label, "Generate `Deref` impl using `bar`"); |
218 | assert_eq!(assists.next().expect("expected assist").label, "Generate a mut getter method"); | ||
219 | assert_eq!(assists.next().expect("expected assist").label, "Generate a getter method"); | 218 | assert_eq!(assists.next().expect("expected assist").label, "Generate a getter method"); |
219 | assert_eq!(assists.next().expect("expected assist").label, "Generate a mut getter method"); | ||
220 | assert_eq!(assists.next().expect("expected assist").label, "Generate a setter method"); | 220 | assert_eq!(assists.next().expect("expected assist").label, "Generate a setter method"); |
221 | assert_eq!(assists.next().expect("expected assist").label, "Add `#[derive]`"); | 221 | assert_eq!(assists.next().expect("expected assist").label, "Add `#[derive]`"); |
222 | } | 222 | } |
diff --git a/crates/ide_assists/src/tests/generated.rs b/crates/ide_assists/src/tests/generated.rs index 4406406a2..de5d9e55a 100644 --- a/crates/ide_assists/src/tests/generated.rs +++ b/crates/ide_assists/src/tests/generated.rs | |||
@@ -455,8 +455,8 @@ enum Action { Move { distance: u32 }, Stop } | |||
455 | 455 | ||
456 | fn handle(action: Action) { | 456 | fn handle(action: Action) { |
457 | match action { | 457 | match action { |
458 | $0Action::Move { distance } => {} | 458 | $0Action::Move { distance } => todo!(), |
459 | Action::Stop => {} | 459 | Action::Stop => todo!(), |
460 | } | 460 | } |
461 | } | 461 | } |
462 | "#####, | 462 | "#####, |
@@ -786,8 +786,8 @@ struct Person { | |||
786 | 786 | ||
787 | impl Person { | 787 | impl Person { |
788 | /// Get a reference to the person's name. | 788 | /// Get a reference to the person's name. |
789 | fn name(&self) -> &String { | 789 | fn $0name(&self) -> &str { |
790 | &self.name | 790 | self.name.as_str() |
791 | } | 791 | } |
792 | } | 792 | } |
793 | "#####, | 793 | "#####, |
@@ -810,7 +810,7 @@ struct Person { | |||
810 | 810 | ||
811 | impl Person { | 811 | impl Person { |
812 | /// Get a mutable reference to the person's name. | 812 | /// Get a mutable reference to the person's name. |
813 | fn name_mut(&mut self) -> &mut String { | 813 | fn $0name_mut(&mut self) -> &mut String { |
814 | &mut self.name | 814 | &mut self.name |
815 | } | 815 | } |
816 | } | 816 | } |