1
1
//! FIXME: write short doc here
2
2
3
- use ra_syntax:: { ast:: AstNode , TextRange , TextUnit } ;
3
+ use ra_syntax:: {
4
+ ast:: { self , AstNode } ,
5
+ TextRange , TextUnit ,
6
+ } ;
4
7
use ra_text_edit:: TextEdit ;
5
8
6
9
use crate :: {
@@ -21,53 +24,97 @@ pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) {
21
24
None => return ,
22
25
} ;
23
26
24
- let receiver_text = if ctx. dot_receiver_is_ambiguous_float_literal {
25
- let text = dot_receiver. syntax ( ) . text ( ) ;
26
- let without_dot = ..text. len ( ) - TextUnit :: of_char ( '.' ) ;
27
- text. slice ( without_dot) . to_string ( )
28
- } else {
29
- dot_receiver. syntax ( ) . text ( ) . to_string ( )
30
- } ;
27
+ let receiver_text =
28
+ get_receiver_text ( dot_receiver, ctx. dot_receiver_is_ambiguous_float_literal ) ;
31
29
32
30
let receiver_ty = match ctx. sema . type_of_expr ( & dot_receiver) {
33
31
Some ( it) => it,
34
32
None => return ,
35
33
} ;
36
34
37
35
if receiver_ty. is_bool ( ) || receiver_ty. is_unknown ( ) {
38
- postfix_snippet ( ctx, "if" , "if expr {}" , & format ! ( "if {} {{$0}}" , receiver_text) )
39
- . add_to ( acc) ;
40
36
postfix_snippet (
41
37
ctx,
38
+ & dot_receiver,
39
+ "if" ,
40
+ "if expr {}" ,
41
+ & format ! ( "if {} {{$0}}" , receiver_text) ,
42
+ )
43
+ . add_to ( acc) ;
44
+ postfix_snippet (
45
+ ctx,
46
+ & dot_receiver,
42
47
"while" ,
43
48
"while expr {}" ,
44
49
& format ! ( "while {} {{\n $0\n }}" , receiver_text) ,
45
50
)
46
51
. add_to ( acc) ;
47
52
}
48
53
49
- postfix_snippet ( ctx, "not" , "!expr" , & format ! ( "!{}" , receiver_text) ) . add_to ( acc) ;
54
+ // !&&&42 is a compiler error, ergo process it before considering the references
55
+ postfix_snippet ( ctx, & dot_receiver, "not" , "!expr" , & format ! ( "!{}" , receiver_text) ) . add_to ( acc) ;
50
56
51
- postfix_snippet ( ctx, "ref" , "&expr" , & format ! ( "&{}" , receiver_text) ) . add_to ( acc) ;
52
- postfix_snippet ( ctx, "refm" , "&mut expr" , & format ! ( "&mut {}" , receiver_text) ) . add_to ( acc) ;
57
+ postfix_snippet ( ctx, & dot_receiver, "ref" , "&expr" , & format ! ( "&{}" , receiver_text) ) . add_to ( acc) ;
58
+ postfix_snippet ( ctx, & dot_receiver, "refm" , "&mut expr" , & format ! ( "&mut {}" , receiver_text) )
59
+ . add_to ( acc) ;
60
+
61
+ // The rest of the postfix completions create an expression that moves an argument,
62
+ // so it's better to consider references now to avoid breaking the compilation
63
+ let dot_receiver = include_references ( dot_receiver) ;
64
+ let receiver_text =
65
+ get_receiver_text ( & dot_receiver, ctx. dot_receiver_is_ambiguous_float_literal ) ;
53
66
54
67
postfix_snippet (
55
68
ctx,
69
+ & dot_receiver,
56
70
"match" ,
57
71
"match expr {}" ,
58
72
& format ! ( "match {} {{\n ${{1:_}} => {{$0\\ }},\n }}" , receiver_text) ,
59
73
)
60
74
. add_to ( acc) ;
61
75
62
- postfix_snippet ( ctx, "dbg" , "dbg!(expr)" , & format ! ( "dbg!({})" , receiver_text) ) . add_to ( acc) ;
76
+ postfix_snippet (
77
+ ctx,
78
+ & dot_receiver,
79
+ "box" ,
80
+ "Box::new(expr)" ,
81
+ & format ! ( "Box::new({})" , receiver_text) ,
82
+ )
83
+ . add_to ( acc) ;
63
84
64
- postfix_snippet ( ctx, "box ", "Box::new (expr)" , & format ! ( "Box::new ({})" , receiver_text) )
85
+ postfix_snippet ( ctx, & dot_receiver , "dbg ", "dbg! (expr)" , & format ! ( "dbg! ({})" , receiver_text) )
65
86
. add_to ( acc) ;
66
87
}
67
88
68
- fn postfix_snippet ( ctx : & CompletionContext , label : & str , detail : & str , snippet : & str ) -> Builder {
89
+ fn get_receiver_text ( receiver : & ast:: Expr , receiver_is_ambiguous_float_literal : bool ) -> String {
90
+ if receiver_is_ambiguous_float_literal {
91
+ let text = receiver. syntax ( ) . text ( ) ;
92
+ let without_dot = ..text. len ( ) - TextUnit :: of_char ( '.' ) ;
93
+ text. slice ( without_dot) . to_string ( )
94
+ } else {
95
+ receiver. to_string ( )
96
+ }
97
+ }
98
+
99
+ fn include_references ( initial_element : & ast:: Expr ) -> ast:: Expr {
100
+ let mut resulting_element = initial_element. clone ( ) ;
101
+ while let Some ( parent_ref_element) =
102
+ resulting_element. syntax ( ) . parent ( ) . and_then ( ast:: RefExpr :: cast)
103
+ {
104
+ resulting_element = ast:: Expr :: from ( parent_ref_element) ;
105
+ }
106
+ resulting_element
107
+ }
108
+
109
+ fn postfix_snippet (
110
+ ctx : & CompletionContext ,
111
+ receiver : & ast:: Expr ,
112
+ label : & str ,
113
+ detail : & str ,
114
+ snippet : & str ,
115
+ ) -> Builder {
69
116
let edit = {
70
- let receiver_syntax = ctx . dot_receiver . as_ref ( ) . expect ( "no receiver available" ) . syntax ( ) ;
117
+ let receiver_syntax = receiver. syntax ( ) ;
71
118
let receiver_range = ctx. sema . original_range ( receiver_syntax) . range ;
72
119
let delete_range = TextRange :: from_to ( receiver_range. start ( ) , ctx. source_range ( ) . end ( ) ) ;
73
120
TextEdit :: replace ( delete_range, snippet. to_string ( ) )
@@ -340,4 +387,63 @@ mod tests {
340
387
"###
341
388
) ;
342
389
}
390
+
391
+ #[ test]
392
+ fn postfix_completion_for_references ( ) {
393
+ assert_debug_snapshot ! (
394
+ do_postfix_completion(
395
+ r#"
396
+ fn main() {
397
+ &&&&42.<|>
398
+ }
399
+ "# ,
400
+ ) ,
401
+ @r###"
402
+ [
403
+ CompletionItem {
404
+ label: "box",
405
+ source_range: [56; 56),
406
+ delete: [49; 56),
407
+ insert: "Box::new(&&&&42)",
408
+ detail: "Box::new(expr)",
409
+ },
410
+ CompletionItem {
411
+ label: "dbg",
412
+ source_range: [56; 56),
413
+ delete: [49; 56),
414
+ insert: "dbg!(&&&&42)",
415
+ detail: "dbg!(expr)",
416
+ },
417
+ CompletionItem {
418
+ label: "match",
419
+ source_range: [56; 56),
420
+ delete: [49; 56),
421
+ insert: "match &&&&42 {\n ${1:_} => {$0\\},\n}",
422
+ detail: "match expr {}",
423
+ },
424
+ CompletionItem {
425
+ label: "not",
426
+ source_range: [56; 56),
427
+ delete: [53; 56),
428
+ insert: "!42",
429
+ detail: "!expr",
430
+ },
431
+ CompletionItem {
432
+ label: "ref",
433
+ source_range: [56; 56),
434
+ delete: [53; 56),
435
+ insert: "&42",
436
+ detail: "&expr",
437
+ },
438
+ CompletionItem {
439
+ label: "refm",
440
+ source_range: [56; 56),
441
+ delete: [53; 56),
442
+ insert: "&mut 42",
443
+ detail: "&mut expr",
444
+ },
445
+ ]
446
+ "###
447
+ ) ;
448
+ }
343
449
}
0 commit comments