@@ -5,7 +5,8 @@ use hir::{Adt, HasSource, ModuleDef, Semantics};
5
5
use ide_db:: helpers:: { mod_path_to_ast, FamousDefs } ;
6
6
use ide_db:: RootDatabase ;
7
7
use itertools:: Itertools ;
8
- use syntax:: ast:: { self , make, AstNode , HasName , MatchArm , Pat } ;
8
+ use syntax:: ast:: { self , make, AstNode , HasName , MatchArm , MatchArmList , MatchExpr , Pat } ;
9
+ use syntax:: TextRange ;
9
10
10
11
use crate :: {
11
12
utils:: { self , render_snippet, Cursor } ,
@@ -39,6 +40,22 @@ use crate::{
39
40
pub ( crate ) fn add_missing_match_arms ( acc : & mut Assists , ctx : & AssistContext ) -> Option < ( ) > {
40
41
let match_expr = ctx. find_node_at_offset_with_descend :: < ast:: MatchExpr > ( ) ?;
41
42
let match_arm_list = match_expr. match_arm_list ( ) ?;
43
+ let target_range: TextRange ;
44
+
45
+ if let None = cursor_at_trivial_match_arm_list ( & ctx, & match_expr, & match_arm_list) {
46
+ target_range = TextRange :: new (
47
+ ctx. sema . original_range ( match_expr. syntax ( ) ) . range . start ( ) ,
48
+ ctx. sema . original_range ( match_arm_list. syntax ( ) ) . range . start ( ) ,
49
+ ) ;
50
+
51
+ let cursor_in_range = target_range. contains_range ( ctx. selection_trimmed ( ) ) ;
52
+ if !cursor_in_range {
53
+ cov_mark:: hit!( not_applicable_outside_of_range_right) ;
54
+ return None ;
55
+ }
56
+ } else {
57
+ target_range = ctx. sema . original_range ( match_expr. syntax ( ) ) . range ;
58
+ }
42
59
43
60
let expr = match_expr. expr ( ) ?;
44
61
@@ -121,11 +138,10 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext) ->
121
138
return None ;
122
139
}
123
140
124
- let target = ctx. sema . original_range ( match_expr. syntax ( ) ) . range ;
125
141
acc. add (
126
142
AssistId ( "add_missing_match_arms" , AssistKind :: QuickFix ) ,
127
143
"Fill match arms" ,
128
- target ,
144
+ target_range ,
129
145
|builder| {
130
146
let new_match_arm_list = match_arm_list. clone_for_update ( ) ;
131
147
let missing_arms = missing_pats
@@ -177,6 +193,29 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext) ->
177
193
)
178
194
}
179
195
196
+ fn cursor_at_trivial_match_arm_list (
197
+ ctx : & AssistContext ,
198
+ match_expr : & MatchExpr ,
199
+ match_arm_list : & MatchArmList ,
200
+ ) -> Option < ( ) > {
201
+ // match x { $0 }
202
+ if match_arm_list. arms ( ) . next ( ) == None {
203
+ cov_mark:: hit!( add_missing_match_arms_empty_body) ;
204
+ return Some ( ( ) ) ;
205
+ }
206
+
207
+ // match { _$0 => {...} }
208
+ let wild_pat = ctx. find_node_at_offset_with_descend :: < ast:: WildcardPat > ( ) ?;
209
+ let arm = wild_pat. syntax ( ) . parent ( ) . and_then ( ast:: MatchArm :: cast) ?;
210
+ let arm_match_expr = arm. syntax ( ) . ancestors ( ) . nth ( 2 ) . and_then ( ast:: MatchExpr :: cast) ?;
211
+ if arm_match_expr == * match_expr {
212
+ cov_mark:: hit!( add_missing_match_arms_trivial_arm) ;
213
+ return Some ( ( ) ) ;
214
+ }
215
+
216
+ None
217
+ }
218
+
180
219
fn is_variant_missing ( existing_pats : & [ Pat ] , var : & Pat ) -> bool {
181
220
!existing_pats. iter ( ) . any ( |pat| does_pat_match_variant ( pat, var) )
182
221
}
@@ -306,6 +345,39 @@ fn main() {
306
345
) ;
307
346
}
308
347
348
+ #[ test]
349
+ fn not_applicable_outside_of_range_left ( ) {
350
+ check_assist_not_applicable (
351
+ add_missing_match_arms,
352
+ r#"
353
+ enum A { X, Y }
354
+
355
+ fn foo(a: A) {
356
+ $0 match a {
357
+ A::X => { }
358
+ }
359
+ }
360
+ "# ,
361
+ ) ;
362
+ }
363
+
364
+ #[ test]
365
+ fn not_applicable_outside_of_range_right ( ) {
366
+ cov_mark:: check!( not_applicable_outside_of_range_right) ;
367
+ check_assist_not_applicable (
368
+ add_missing_match_arms,
369
+ r#"
370
+ enum A { X, Y }
371
+
372
+ fn foo(a: A) {
373
+ match a {$0
374
+ A::X => { }
375
+ }
376
+ }
377
+ "# ,
378
+ ) ;
379
+ }
380
+
309
381
#[ test]
310
382
fn all_boolean_match_arms_provided ( ) {
311
383
check_assist_not_applicable (
@@ -583,14 +655,15 @@ fn main() {
583
655
584
656
#[ test]
585
657
fn add_missing_match_arms_empty_body ( ) {
658
+ cov_mark:: check!( add_missing_match_arms_empty_body) ;
586
659
check_assist (
587
660
add_missing_match_arms,
588
661
r#"
589
662
enum A { As, Bs, Cs(String), Ds(String, String), Es { x: usize, y: usize } }
590
663
591
664
fn main() {
592
665
let a = A::As;
593
- match a$0 { }
666
+ match a {$0 }
594
667
}
595
668
"# ,
596
669
r#"
@@ -853,7 +926,7 @@ fn foo(a: &mut A) {
853
926
}
854
927
855
928
#[ test]
856
- fn add_missing_match_arms_target ( ) {
929
+ fn add_missing_match_arms_target_simple ( ) {
857
930
check_assist_target (
858
931
add_missing_match_arms,
859
932
r#"
@@ -867,8 +940,26 @@ fn main() {
867
940
) ;
868
941
}
869
942
943
+ #[ test]
944
+ fn add_missing_match_arms_target_complex ( ) {
945
+ check_assist_target (
946
+ add_missing_match_arms,
947
+ r#"
948
+ enum E { X, Y }
949
+
950
+ fn main() {
951
+ match E::X$0 {
952
+ E::X => {}
953
+ }
954
+ }
955
+ "# ,
956
+ "match E::X " ,
957
+ ) ;
958
+ }
959
+
870
960
#[ test]
871
961
fn add_missing_match_arms_trivial_arm ( ) {
962
+ cov_mark:: check!( add_missing_match_arms_trivial_arm) ;
872
963
check_assist (
873
964
add_missing_match_arms,
874
965
r#"
@@ -893,6 +984,25 @@ fn main() {
893
984
) ;
894
985
}
895
986
987
+ #[ test]
988
+ fn wildcard_inside_expression_not_applicable ( ) {
989
+ check_assist_not_applicable (
990
+ add_missing_match_arms,
991
+ r#"
992
+ enum E { X, Y }
993
+
994
+ fn foo(e : E) {
995
+ match e {
996
+ _ => {
997
+ println!("1");$0
998
+ println!("2");
999
+ }
1000
+ }
1001
+ }
1002
+ "# ,
1003
+ ) ;
1004
+ }
1005
+
896
1006
#[ test]
897
1007
fn add_missing_match_arms_qualifies_path ( ) {
898
1008
check_assist (
@@ -928,8 +1038,8 @@ fn main() {
928
1038
r#"
929
1039
enum A { One, Two }
930
1040
fn foo(a: A) {
931
- match a {
932
- // foo bar baz$0
1041
+ match a $0 {
1042
+ // foo bar baz
933
1043
A::One => {}
934
1044
// This is where the rest should be
935
1045
}
@@ -938,7 +1048,7 @@ fn foo(a: A) {
938
1048
r#"
939
1049
enum A { One, Two }
940
1050
fn foo(a: A) {
941
- match a {
1051
+ match a {
942
1052
// foo bar baz
943
1053
A::One => {}
944
1054
$0A::Two => todo!(),
0 commit comments