4 famous_defs::FamousDefs,
5 syntax_helpers::node_ext::{for_each_tail_expr, walk_expr},
8 ast::{self, make, Expr},
12 use crate::{AssistContext, AssistId, AssistKind, Assists};
14 // Assist: wrap_return_type_in_result
16 // Wrap the function's return type into Result.
19 // # //- minicore: result
20 // fn foo() -> i32$0 { 42i32 }
24 // fn foo() -> Result<i32, ${0:_}> { Ok(42i32) }
26 pub(crate) fn wrap_return_type_in_result(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
27 let ret_type = ctx.find_node_at_offset::<ast::RetType>()?;
28 let parent = ret_type.syntax().parent()?;
29 let body = match_ast! {
31 ast::Fn(func) => func.body()?,
32 ast::ClosureExpr(closure) => match closure.body()? {
33 Expr::BlockExpr(block) => block,
34 // closures require a block when a return type is specified
41 let type_ref = &ret_type.ty()?;
42 let ty = ctx.sema.resolve_type(type_ref)?.as_adt();
44 FamousDefs(&ctx.sema, ctx.sema.scope(type_ref.syntax())?.krate()).core_result_Result()?;
46 if matches!(ty, Some(hir::Adt::Enum(ret_type)) if ret_type == result_enum) {
47 cov_mark::hit!(wrap_return_type_in_result_simple_return_type_already_result);
52 AssistId("wrap_return_type_in_result", AssistKind::RefactorRewrite),
53 "Wrap return type in Result",
54 type_ref.syntax().text_range(),
56 let body = ast::Expr::BlockExpr(body);
58 let mut exprs_to_wrap = Vec::new();
59 let tail_cb = &mut |e: &_| tail_cb_impl(&mut exprs_to_wrap, e);
60 walk_expr(&body, &mut |expr| {
61 if let Expr::ReturnExpr(ret_expr) = expr {
62 if let Some(ret_expr_arg) = &ret_expr.expr() {
63 for_each_tail_expr(ret_expr_arg, tail_cb);
67 for_each_tail_expr(&body, tail_cb);
69 for ret_expr_arg in exprs_to_wrap {
70 let ok_wrapped = make::expr_call(
71 make::expr_path(make::ext::ident_path("Ok")),
72 make::arg_list(iter::once(ret_expr_arg.clone())),
74 builder.replace_ast(ret_expr_arg, ok_wrapped);
77 match ctx.config.snippet_cap {
79 let snippet = format!("Result<{}, ${{0:_}}>", type_ref);
80 builder.replace_snippet(cap, type_ref.syntax().text_range(), snippet)
83 .replace(type_ref.syntax().text_range(), format!("Result<{}, _>", type_ref)),
89 fn tail_cb_impl(acc: &mut Vec<ast::Expr>, e: &ast::Expr) {
91 Expr::BreakExpr(break_expr) => {
92 if let Some(break_expr_arg) = break_expr.expr() {
93 for_each_tail_expr(&break_expr_arg, &mut |e| tail_cb_impl(acc, e))
96 Expr::ReturnExpr(ret_expr) => {
97 if let Some(ret_expr_arg) = &ret_expr.expr() {
98 for_each_tail_expr(ret_expr_arg, &mut |e| tail_cb_impl(acc, e));
101 e => acc.push(e.clone()),
107 use crate::tests::{check_assist, check_assist_not_applicable};
112 fn wrap_return_type_in_result_simple() {
114 wrap_return_type_in_result,
123 fn foo() -> Result<i32, ${0:_}> {
132 fn wrap_return_type_break_split_tail() {
134 wrap_return_type_in_result,
148 fn foo() -> Result<i32, ${0:_}> {
162 fn wrap_return_type_in_result_simple_closure() {
164 wrap_return_type_in_result,
176 || -> Result<i32, ${0:_}> {
186 fn wrap_return_type_in_result_simple_return_type_bad_cursor() {
187 check_assist_not_applicable(
188 wrap_return_type_in_result,
200 fn wrap_return_type_in_result_simple_return_type_bad_cursor_closure() {
201 check_assist_not_applicable(
202 wrap_return_type_in_result,
216 fn wrap_return_type_in_result_closure_non_block() {
217 check_assist_not_applicable(
218 wrap_return_type_in_result,
221 fn foo() { || -> i$032 3; }
227 fn wrap_return_type_in_result_simple_return_type_already_result_std() {
228 check_assist_not_applicable(
229 wrap_return_type_in_result,
232 fn foo() -> core::result::Result<i32$0, String> {
241 fn wrap_return_type_in_result_simple_return_type_already_result() {
242 cov_mark::check!(wrap_return_type_in_result_simple_return_type_already_result);
243 check_assist_not_applicable(
244 wrap_return_type_in_result,
247 fn foo() -> Result<i32$0, String> {
256 fn wrap_return_type_in_result_simple_return_type_already_result_closure() {
257 check_assist_not_applicable(
258 wrap_return_type_in_result,
262 || -> Result<i32$0, String> {
272 fn wrap_return_type_in_result_simple_with_cursor() {
274 wrap_return_type_in_result,
283 fn foo() -> Result<i32, ${0:_}> {
292 fn wrap_return_type_in_result_simple_with_tail() {
294 wrap_return_type_in_result,
303 fn foo() -> Result<i32, ${0:_}> {
312 fn wrap_return_type_in_result_simple_with_tail_closure() {
314 wrap_return_type_in_result,
326 || -> Result<i32, ${0:_}> {
336 fn wrap_return_type_in_result_simple_with_tail_only() {
338 wrap_return_type_in_result,
341 fn foo() -> i32$0 { 42i32 }
344 fn foo() -> Result<i32, ${0:_}> { Ok(42i32) }
350 fn wrap_return_type_in_result_simple_with_tail_block_like() {
352 wrap_return_type_in_result,
364 fn foo() -> Result<i32, ${0:_}> {
376 fn wrap_return_type_in_result_simple_without_block_closure() {
378 wrap_return_type_in_result,
393 || -> Result<i32, ${0:_}> {
406 fn wrap_return_type_in_result_simple_with_nested_if() {
408 wrap_return_type_in_result,
424 fn foo() -> Result<i32, ${0:_}> {
440 fn wrap_return_type_in_result_simple_with_await() {
442 wrap_return_type_in_result,
445 async fn foo() -> i$032 {
458 async fn foo() -> Result<i32, ${0:_}> {
474 fn wrap_return_type_in_result_simple_with_array() {
476 wrap_return_type_in_result,
479 fn foo() -> [i32;$0 3] { [1, 2, 3] }
482 fn foo() -> Result<[i32; 3], ${0:_}> { Ok([1, 2, 3]) }
488 fn wrap_return_type_in_result_simple_with_cast() {
490 wrap_return_type_in_result,
506 fn foo() -> Result<i32, ${0:_}> {
522 fn wrap_return_type_in_result_simple_with_tail_block_like_match() {
524 wrap_return_type_in_result,
536 fn foo() -> Result<i32, ${0:_}> {
548 fn wrap_return_type_in_result_simple_with_loop_with_tail() {
550 wrap_return_type_in_result,
563 fn foo() -> Result<i32, ${0:_}> {
576 fn wrap_return_type_in_result_simple_with_loop_in_let_stmt() {
578 wrap_return_type_in_result,
582 let my_var = let x = loop {
589 fn foo() -> Result<i32, ${0:_}> {
590 let my_var = let x = loop {
600 fn wrap_return_type_in_result_simple_with_tail_block_like_match_return_expr() {
602 wrap_return_type_in_result,
607 let res = match my_var {
615 fn foo() -> Result<i32, ${0:_}> {
617 let res = match my_var {
619 _ => return Ok(24i32),
627 wrap_return_type_in_result,
632 let res = if my_var == 5 {
641 fn foo() -> Result<i32, ${0:_}> {
643 let res = if my_var == 5 {
655 fn wrap_return_type_in_result_simple_with_tail_block_like_match_deeper() {
657 wrap_return_type_in_result,
681 fn foo() -> Result<i32, ${0:_}> {
705 fn wrap_return_type_in_result_simple_with_tail_block_like_early_return() {
707 wrap_return_type_in_result,
719 fn foo() -> Result<i32, ${0:_}> {
731 fn wrap_return_type_in_result_simple_with_closure() {
733 wrap_return_type_in_result,
736 fn foo(the_field: u32) ->$0 u32 {
737 let true_closure = || { return true; };
750 fn foo(the_field: u32) -> Result<u32, ${0:_}> {
751 let true_closure = || { return true; };
766 wrap_return_type_in_result,
769 fn foo(the_field: u32) -> u32$0 {
770 let true_closure = || {
785 t.unwrap_or_else(|| the_field)
789 fn foo(the_field: u32) -> Result<u32, ${0:_}> {
790 let true_closure = || {
805 Ok(t.unwrap_or_else(|| the_field))
812 fn wrap_return_type_in_result_simple_with_weird_forms() {
814 wrap_return_type_in_result,
832 fn foo() -> Result<i32, ${0:_}> {
849 wrap_return_type_in_result,
852 fn foo(the_field: u32) -> u32$0 {
870 fn foo(the_field: u32) -> Result<u32, ${0:_}> {
890 wrap_return_type_in_result,
893 fn foo(the_field: u32) -> u3$02 {
905 fn foo(the_field: u32) -> Result<u32, ${0:_}> {
919 wrap_return_type_in_result,
922 fn foo(the_field: u32) -> u32$0 {
935 fn foo(the_field: u32) -> Result<u32, ${0:_}> {
950 wrap_return_type_in_result,
953 fn foo(the_field: u32) -> $0u32 {
966 fn foo(the_field: u32) -> Result<u32, ${0:_}> {