1
1
use hir:: HirDisplay ;
2
- use syntax:: { ast, AstNode , TextRange , TextSize } ;
2
+ use syntax:: { ast, AstNode , SyntaxKind , SyntaxToken , TextRange , TextSize } ;
3
3
4
4
use crate :: { AssistContext , AssistId , AssistKind , Assists } ;
5
5
@@ -33,8 +33,9 @@ pub(crate) fn add_return_type(acc: &mut Assists, ctx: &AssistContext) -> Option<
33
33
tail_expr. syntax ( ) . text_range ( ) ,
34
34
|builder| {
35
35
match builder_edit_pos {
36
- InsertOrReplace :: Insert ( insert_pos) => {
37
- builder. insert ( insert_pos, & format ! ( "-> {} " , ty) )
36
+ InsertOrReplace :: Insert ( insert_pos, needs_whitespace) => {
37
+ let preceeding_whitespace = if needs_whitespace { " " } else { "" } ;
38
+ builder. insert ( insert_pos, & format ! ( "{}-> {} " , preceeding_whitespace, ty) )
38
39
}
39
40
InsertOrReplace :: Replace ( text_range) => {
40
41
builder. replace ( text_range, & format ! ( "-> {}" , ty) )
@@ -50,13 +51,16 @@ pub(crate) fn add_return_type(acc: &mut Assists, ctx: &AssistContext) -> Option<
50
51
}
51
52
52
53
enum InsertOrReplace {
53
- Insert ( TextSize ) ,
54
+ Insert ( TextSize , bool ) ,
54
55
Replace ( TextRange ) ,
55
56
}
56
57
57
58
/// Check the potentially already specified return type and reject it or turn it into a builder command
58
59
/// if allowed.
59
- fn ret_ty_to_action ( ret_ty : Option < ast:: RetType > , insert_pos : TextSize ) -> Option < InsertOrReplace > {
60
+ fn ret_ty_to_action (
61
+ ret_ty : Option < ast:: RetType > ,
62
+ insert_after : SyntaxToken ,
63
+ ) -> Option < InsertOrReplace > {
60
64
match ret_ty {
61
65
Some ( ret_ty) => match ret_ty. ty ( ) {
62
66
Some ( ast:: Type :: InferType ( _) ) | None => {
@@ -70,7 +74,17 @@ fn ret_ty_to_action(ret_ty: Option<ast::RetType>, insert_pos: TextSize) -> Optio
70
74
None
71
75
}
72
76
} ,
73
- None => Some ( InsertOrReplace :: Insert ( insert_pos + TextSize :: from ( 1 ) ) ) ,
77
+ None => {
78
+ let insert_after_pos = insert_after. text_range ( ) . end ( ) ;
79
+ let ( insert_pos, needs_whitespace) = match insert_after. next_token ( ) {
80
+ Some ( it) if it. kind ( ) == SyntaxKind :: WHITESPACE => {
81
+ ( insert_after_pos + TextSize :: from ( 1 ) , false )
82
+ }
83
+ _ => ( insert_after_pos, true ) ,
84
+ } ;
85
+
86
+ Some ( InsertOrReplace :: Insert ( insert_pos, needs_whitespace) )
87
+ }
74
88
}
75
89
}
76
90
@@ -82,8 +96,10 @@ enum FnType {
82
96
fn extract_tail ( ctx : & AssistContext ) -> Option < ( FnType , ast:: Expr , InsertOrReplace ) > {
83
97
let ( fn_type, tail_expr, return_type_range, action) =
84
98
if let Some ( closure) = ctx. find_node_at_offset :: < ast:: ClosureExpr > ( ) {
85
- let rpipe_pos = closure. param_list ( ) ?. syntax ( ) . last_token ( ) ?. text_range ( ) . end ( ) ;
86
- let action = ret_ty_to_action ( closure. ret_type ( ) , rpipe_pos) ?;
99
+ let rpipe = closure. param_list ( ) ?. syntax ( ) . last_token ( ) ?;
100
+ let rpipe_pos = rpipe. text_range ( ) . end ( ) ;
101
+
102
+ let action = ret_ty_to_action ( closure. ret_type ( ) , rpipe) ?;
87
103
88
104
let body = closure. body ( ) ?;
89
105
let body_start = body. syntax ( ) . first_token ( ) ?. text_range ( ) . start ( ) ;
@@ -96,8 +112,10 @@ fn extract_tail(ctx: &AssistContext) -> Option<(FnType, ast::Expr, InsertOrRepla
96
112
( FnType :: Closure { wrap_expr } , tail_expr, ret_range, action)
97
113
} else {
98
114
let func = ctx. find_node_at_offset :: < ast:: Fn > ( ) ?;
99
- let rparen_pos = func. param_list ( ) ?. r_paren_token ( ) ?. text_range ( ) . end ( ) ;
100
- let action = ret_ty_to_action ( func. ret_type ( ) , rparen_pos) ?;
115
+
116
+ let rparen = func. param_list ( ) ?. r_paren_token ( ) ?;
117
+ let rparen_pos = rparen. text_range ( ) . end ( ) ;
118
+ let action = ret_ty_to_action ( func. ret_type ( ) , rparen) ?;
101
119
102
120
let body = func. body ( ) ?;
103
121
let stmt_list = body. stmt_list ( ) ?;
@@ -196,6 +214,19 @@ mod tests {
196
214
) ;
197
215
}
198
216
217
+ #[ test]
218
+ fn infer_return_type_no_whitespace ( ) {
219
+ check_assist (
220
+ add_return_type,
221
+ r#"fn foo(){
222
+ 45$0
223
+ }"# ,
224
+ r#"fn foo() -> i32 {
225
+ 45
226
+ }"# ,
227
+ ) ;
228
+ }
229
+
199
230
#[ test]
200
231
fn infer_return_type_nested ( ) {
201
232
check_assist (
@@ -280,6 +311,19 @@ mod tests {
280
311
) ;
281
312
}
282
313
314
+ #[ test]
315
+ fn infer_return_type_closure_no_whitespace ( ) {
316
+ check_assist (
317
+ add_return_type,
318
+ r#"fn foo() {
319
+ |x: i32|{ x$0 };
320
+ }"# ,
321
+ r#"fn foo() {
322
+ |x: i32| -> i32 { x };
323
+ }"# ,
324
+ ) ;
325
+ }
326
+
283
327
#[ test]
284
328
fn infer_return_type_closure_wrap ( ) {
285
329
cov_mark:: check!( wrap_closure_non_block_expr) ;
0 commit comments