3 use ide_db::helpers::for_each_tail_expr;
5 ast::{self, make, Expr},
9 use crate::{AssistContext, AssistId, AssistKind, Assists};
11 // Assist: wrap_return_type_in_result
13 // Wrap the function's return type into Result.
16 // fn foo() -> i32$0 { 42i32 }
20 // fn foo() -> Result<i32, ${0:_}> { Ok(42i32) }
22 pub(crate) fn wrap_return_type_in_result(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
23 let ret_type = ctx.find_node_at_offset::<ast::RetType>()?;
24 let parent = ret_type.syntax().parent()?;
25 let body = match_ast! {
27 ast::Fn(func) => func.body()?,
28 ast::ClosureExpr(closure) => match closure.body()? {
29 Expr::BlockExpr(block) => block,
30 // closures require a block when a return type is specified
36 let body = ast::Expr::BlockExpr(body);
38 let type_ref = &ret_type.ty()?;
39 let ret_type_str = type_ref.syntax().text().to_string();
40 let first_part_ret_type = ret_type_str.splitn(2, '<').next();
41 if let Some(ret_type_first_part) = first_part_ret_type {
42 if ret_type_first_part.ends_with("Result") {
43 cov_mark::hit!(wrap_return_type_in_result_simple_return_type_already_result);
49 AssistId("wrap_return_type_in_result", AssistKind::RefactorRewrite),
50 "Wrap return type in Result",
51 type_ref.syntax().text_range(),
53 let mut exprs_to_wrap = Vec::new();
54 let tail_cb = &mut |e: &_| tail_cb_impl(&mut exprs_to_wrap, e);
55 body.walk(&mut |expr| {
56 if let Expr::ReturnExpr(ret_expr) = expr {
57 if let Some(ret_expr_arg) = &ret_expr.expr() {
58 for_each_tail_expr(ret_expr_arg, tail_cb);
62 for_each_tail_expr(&body, tail_cb);
64 for ret_expr_arg in exprs_to_wrap {
65 let ok_wrapped = make::expr_call(
66 make::expr_path(make::ext::ident_path("Ok")),
67 make::arg_list(iter::once(ret_expr_arg.clone())),
69 builder.replace_ast(ret_expr_arg, ok_wrapped);
72 match ctx.config.snippet_cap {
74 let snippet = format!("Result<{}, ${{0:_}}>", type_ref);
75 builder.replace_snippet(cap, type_ref.syntax().text_range(), snippet)
78 .replace(type_ref.syntax().text_range(), format!("Result<{}, _>", type_ref)),
84 fn tail_cb_impl(acc: &mut Vec<ast::Expr>, e: &ast::Expr) {
86 Expr::BreakExpr(break_expr) => {
87 if let Some(break_expr_arg) = break_expr.expr() {
88 for_each_tail_expr(&break_expr_arg, &mut |e| tail_cb_impl(acc, e))
91 e => acc.push(e.clone()),
97 use crate::tests::{check_assist, check_assist_not_applicable};
102 fn wrap_return_type_in_result_simple() {
104 wrap_return_type_in_result,
112 fn foo() -> Result<i32, ${0:_}> {
121 fn wrap_return_type_break_split_tail() {
123 wrap_return_type_in_result,
136 fn foo() -> Result<i32, ${0:_}> {
150 fn wrap_return_type_in_result_simple_closure() {
152 wrap_return_type_in_result,
163 || -> Result<i32, ${0:_}> {
173 fn wrap_return_type_in_result_simple_return_type_bad_cursor() {
174 check_assist_not_applicable(
175 wrap_return_type_in_result,
186 fn wrap_return_type_in_result_simple_return_type_bad_cursor_closure() {
187 check_assist_not_applicable(
188 wrap_return_type_in_result,
201 fn wrap_return_type_in_result_closure_non_block() {
202 check_assist_not_applicable(wrap_return_type_in_result, r#"fn foo() { || -> i$032 3; }"#);
206 fn wrap_return_type_in_result_simple_return_type_already_result_std() {
207 check_assist_not_applicable(
208 wrap_return_type_in_result,
210 fn foo() -> std::result::Result<i32$0, String> {
219 fn wrap_return_type_in_result_simple_return_type_already_result() {
220 cov_mark::check!(wrap_return_type_in_result_simple_return_type_already_result);
221 check_assist_not_applicable(
222 wrap_return_type_in_result,
224 fn foo() -> Result<i32$0, String> {
233 fn wrap_return_type_in_result_simple_return_type_already_result_closure() {
234 check_assist_not_applicable(
235 wrap_return_type_in_result,
238 || -> Result<i32$0, String> {
248 fn wrap_return_type_in_result_simple_with_cursor() {
250 wrap_return_type_in_result,
258 fn foo() -> Result<i32, ${0:_}> {
267 fn wrap_return_type_in_result_simple_with_tail() {
269 wrap_return_type_in_result,
277 fn foo() -> Result<i32, ${0:_}> {
286 fn wrap_return_type_in_result_simple_with_tail_closure() {
288 wrap_return_type_in_result,
299 || -> Result<i32, ${0:_}> {
309 fn wrap_return_type_in_result_simple_with_tail_only() {
311 wrap_return_type_in_result,
312 r#"fn foo() -> i32$0 { 42i32 }"#,
313 r#"fn foo() -> Result<i32, ${0:_}> { Ok(42i32) }"#,
318 fn wrap_return_type_in_result_simple_with_tail_block_like() {
320 wrap_return_type_in_result,
331 fn foo() -> Result<i32, ${0:_}> {
343 fn wrap_return_type_in_result_simple_without_block_closure() {
345 wrap_return_type_in_result,
359 || -> Result<i32, ${0:_}> {
372 fn wrap_return_type_in_result_simple_with_nested_if() {
374 wrap_return_type_in_result,
389 fn foo() -> Result<i32, ${0:_}> {
405 fn wrap_return_type_in_result_simple_with_await() {
407 wrap_return_type_in_result,
409 async fn foo() -> i$032 {
422 async fn foo() -> Result<i32, ${0:_}> {
438 fn wrap_return_type_in_result_simple_with_array() {
440 wrap_return_type_in_result,
441 r#"fn foo() -> [i32;$0 3] { [1, 2, 3] }"#,
442 r#"fn foo() -> Result<[i32; 3], ${0:_}> { Ok([1, 2, 3]) }"#,
447 fn wrap_return_type_in_result_simple_with_cast() {
449 wrap_return_type_in_result,
464 fn foo() -> Result<i32, ${0:_}> {
480 fn wrap_return_type_in_result_simple_with_tail_block_like_match() {
482 wrap_return_type_in_result,
493 fn foo() -> Result<i32, ${0:_}> {
505 fn wrap_return_type_in_result_simple_with_loop_with_tail() {
507 wrap_return_type_in_result,
519 fn foo() -> Result<i32, ${0:_}> {
532 fn wrap_return_type_in_result_simple_with_loop_in_let_stmt() {
534 wrap_return_type_in_result,
537 let my_var = let x = loop {
544 fn foo() -> Result<i32, ${0:_}> {
545 let my_var = let x = loop {
555 fn wrap_return_type_in_result_simple_with_tail_block_like_match_return_expr() {
557 wrap_return_type_in_result,
561 let res = match my_var {
569 fn foo() -> Result<i32, ${0:_}> {
571 let res = match my_var {
573 _ => return Ok(24i32),
581 wrap_return_type_in_result,
585 let res = if my_var == 5 {
594 fn foo() -> Result<i32, ${0:_}> {
596 let res = if my_var == 5 {
608 fn wrap_return_type_in_result_simple_with_tail_block_like_match_deeper() {
610 wrap_return_type_in_result,
633 fn foo() -> Result<i32, ${0:_}> {
657 fn wrap_return_type_in_result_simple_with_tail_block_like_early_return() {
659 wrap_return_type_in_result,
670 fn foo() -> Result<i32, ${0:_}> {
682 fn wrap_return_type_in_result_simple_with_closure() {
684 wrap_return_type_in_result,
686 fn foo(the_field: u32) ->$0 u32 {
687 let true_closure = || { return true; };
700 fn foo(the_field: u32) -> Result<u32, ${0:_}> {
701 let true_closure = || { return true; };
716 wrap_return_type_in_result,
718 fn foo(the_field: u32) -> u32$0 {
719 let true_closure = || {
734 t.unwrap_or_else(|| the_field)
738 fn foo(the_field: u32) -> Result<u32, ${0:_}> {
739 let true_closure = || {
754 Ok(t.unwrap_or_else(|| the_field))
761 fn wrap_return_type_in_result_simple_with_weird_forms() {
763 wrap_return_type_in_result,
780 fn foo() -> Result<i32, ${0:_}> {
797 wrap_return_type_in_result,
799 fn foo(the_field: u32) -> u32$0 {
817 fn foo(the_field: u32) -> Result<u32, ${0:_}> {
837 wrap_return_type_in_result,
839 fn foo(the_field: u32) -> u3$02 {
851 fn foo(the_field: u32) -> Result<u32, ${0:_}> {
865 wrap_return_type_in_result,
867 fn foo(the_field: u32) -> u32$0 {
880 fn foo(the_field: u32) -> Result<u32, ${0:_}> {
895 wrap_return_type_in_result,
897 fn foo(the_field: u32) -> $0u32 {
910 fn foo(the_field: u32) -> Result<u32, ${0:_}> {