Skip to content

Commit 8dd06ec

Browse files
bors[bot]izik1
andauthored
Merge #10906
10906: [first contributation] fix: `add return type` assit works when there's missing whitespace r=Veykril a=izik1 I feel like the way I handled whitespace here isn't... Right? Maybe it should be folded into `InsertOrReplace::Insert` Also, sorry about the commit name, I am _not_ good at writing user facing commit messages Also sorry about the test names, could be clearer I feel Co-authored-by: Skyler Rain Ross <[email protected]>
2 parents 3b02aec + 5b59a5e commit 8dd06ec

File tree

1 file changed

+54
-10
lines changed

1 file changed

+54
-10
lines changed

crates/ide_assists/src/handlers/add_return_type.rs

Lines changed: 54 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use hir::HirDisplay;
2-
use syntax::{ast, AstNode, TextRange, TextSize};
2+
use syntax::{ast, AstNode, SyntaxKind, SyntaxToken, TextRange, TextSize};
33

44
use crate::{AssistContext, AssistId, AssistKind, Assists};
55

@@ -33,8 +33,9 @@ pub(crate) fn add_return_type(acc: &mut Assists, ctx: &AssistContext) -> Option<
3333
tail_expr.syntax().text_range(),
3434
|builder| {
3535
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))
3839
}
3940
InsertOrReplace::Replace(text_range) => {
4041
builder.replace(text_range, &format!("-> {}", ty))
@@ -50,13 +51,16 @@ pub(crate) fn add_return_type(acc: &mut Assists, ctx: &AssistContext) -> Option<
5051
}
5152

5253
enum InsertOrReplace {
53-
Insert(TextSize),
54+
Insert(TextSize, bool),
5455
Replace(TextRange),
5556
}
5657

5758
/// Check the potentially already specified return type and reject it or turn it into a builder command
5859
/// 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> {
6064
match ret_ty {
6165
Some(ret_ty) => match ret_ty.ty() {
6266
Some(ast::Type::InferType(_)) | None => {
@@ -70,7 +74,17 @@ fn ret_ty_to_action(ret_ty: Option<ast::RetType>, insert_pos: TextSize) -> Optio
7074
None
7175
}
7276
},
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+
}
7488
}
7589
}
7690

@@ -82,8 +96,10 @@ enum FnType {
8296
fn extract_tail(ctx: &AssistContext) -> Option<(FnType, ast::Expr, InsertOrReplace)> {
8397
let (fn_type, tail_expr, return_type_range, action) =
8498
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)?;
87103

88104
let body = closure.body()?;
89105
let body_start = body.syntax().first_token()?.text_range().start();
@@ -96,8 +112,10 @@ fn extract_tail(ctx: &AssistContext) -> Option<(FnType, ast::Expr, InsertOrRepla
96112
(FnType::Closure { wrap_expr }, tail_expr, ret_range, action)
97113
} else {
98114
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)?;
101119

102120
let body = func.body()?;
103121
let stmt_list = body.stmt_list()?;
@@ -196,6 +214,19 @@ mod tests {
196214
);
197215
}
198216

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+
199230
#[test]
200231
fn infer_return_type_nested() {
201232
check_assist(
@@ -280,6 +311,19 @@ mod tests {
280311
);
281312
}
282313

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+
283327
#[test]
284328
fn infer_return_type_closure_wrap() {
285329
cov_mark::check!(wrap_closure_non_block_expr);

0 commit comments

Comments
 (0)