1 use ide_db::helpers::{for_each_tail_expr, node_ext::walk_expr, FamousDefs};
7 use crate::{AssistContext, AssistId, AssistKind, Assists};
9 // Assist: unwrap_result_return_type
11 // Unwrap the function's return type.
14 // # //- minicore: result
15 // fn foo() -> Result<i32>$0 { Ok(42i32) }
19 // fn foo() -> i32 { 42i32 }
21 pub(crate) fn unwrap_result_return_type(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
22 let ret_type = ctx.find_node_at_offset::<ast::RetType>()?;
23 let parent = ret_type.syntax().parent()?;
24 let body = match_ast! {
26 ast::Fn(func) => func.body()?,
27 ast::ClosureExpr(closure) => match closure.body()? {
28 Expr::BlockExpr(block) => block,
29 // closures require a block when a return type is specified
36 let type_ref = &ret_type.ty()?;
37 let ty = ctx.sema.resolve_type(type_ref).and_then(|ty| ty.as_adt());
39 FamousDefs(&ctx.sema, ctx.sema.scope(type_ref.syntax()).krate()).core_result_Result()?;
41 if !matches!(ty, Some(hir::Adt::Enum(ret_type)) if ret_type == result_enum) {
46 AssistId("unwrap_result_return_type", AssistKind::RefactorRewrite),
47 "Unwrap Result return type",
48 type_ref.syntax().text_range(),
50 let body = ast::Expr::BlockExpr(body);
52 let mut exprs_to_unwrap = Vec::new();
53 let tail_cb = &mut |e: &_| tail_cb_impl(&mut exprs_to_unwrap, e);
54 walk_expr(&body, &mut |expr| {
55 if let Expr::ReturnExpr(ret_expr) = expr {
56 if let Some(ret_expr_arg) = &ret_expr.expr() {
57 for_each_tail_expr(ret_expr_arg, tail_cb);
61 for_each_tail_expr(&body, tail_cb);
63 for ret_expr_arg in exprs_to_unwrap {
64 let new_ret_expr = ret_expr_arg.to_string();
66 new_ret_expr.trim_start_matches("Ok(").trim_start_matches("Err(");
68 ret_expr_arg.syntax().text_range(),
69 new_ret_expr.strip_suffix(')').unwrap_or(new_ret_expr),
73 if let Some((_, inner_type)) = type_ref.to_string().split_once('<') {
74 let inner_type = match inner_type.split_once(',') {
75 Some((success_inner_type, _)) => success_inner_type,
79 type_ref.syntax().text_range(),
80 inner_type.strip_suffix('>').unwrap_or(inner_type),
87 fn tail_cb_impl(acc: &mut Vec<ast::Expr>, e: &ast::Expr) {
89 Expr::BreakExpr(break_expr) => {
90 if let Some(break_expr_arg) = break_expr.expr() {
91 for_each_tail_expr(&break_expr_arg, &mut |e| tail_cb_impl(acc, e))
94 Expr::ReturnExpr(ret_expr) => {
95 if let Some(ret_expr_arg) = &ret_expr.expr() {
96 for_each_tail_expr(ret_expr_arg, &mut |e| tail_cb_impl(acc, e));
99 e => acc.push(e.clone()),
105 use crate::tests::{check_assist, check_assist_not_applicable};
110 fn unwrap_result_return_type_simple() {
112 unwrap_result_return_type,
115 fn foo() -> Result<i3$02> {
130 fn unwrap_return_type_break_split_tail() {
132 unwrap_result_return_type,
135 fn foo() -> Result<i3$02, String> {
160 fn unwrap_result_return_type_simple_closure() {
162 unwrap_result_return_type,
166 || -> Result<i32$0> {
184 fn unwrap_result_return_type_simple_return_type_bad_cursor() {
185 check_assist_not_applicable(
186 unwrap_result_return_type,
198 fn unwrap_result_return_type_simple_return_type_bad_cursor_closure() {
199 check_assist_not_applicable(
200 unwrap_result_return_type,
214 fn unwrap_result_return_type_closure_non_block() {
215 check_assist_not_applicable(
216 unwrap_result_return_type,
219 fn foo() { || -> i$032 3; }
225 fn unwrap_result_return_type_simple_return_type_already_not_result_std() {
226 check_assist_not_applicable(
227 unwrap_result_return_type,
239 fn unwrap_result_return_type_simple_return_type_already_not_result_closure() {
240 check_assist_not_applicable(
241 unwrap_result_return_type,
255 fn unwrap_result_return_type_simple_with_tail() {
257 unwrap_result_return_type,
260 fn foo() ->$0 Result<i32> {
275 fn unwrap_result_return_type_simple_with_tail_closure() {
277 unwrap_result_return_type,
281 || ->$0 Result<i32, String> {
299 fn unwrap_result_return_type_simple_with_tail_only() {
301 unwrap_result_return_type,
304 fn foo() -> Result<i32$0> { Ok(42i32) }
307 fn foo() -> i32 { 42i32 }
313 fn unwrap_result_return_type_simple_with_tail_block_like() {
315 unwrap_result_return_type,
318 fn foo() -> Result<i32>$0 {
339 fn unwrap_result_return_type_simple_without_block_closure() {
341 unwrap_result_return_type,
345 || -> Result<i32, String>$0 {
369 fn unwrap_result_return_type_simple_with_nested_if() {
371 unwrap_result_return_type,
374 fn foo() -> Result<i32>$0 {
403 fn unwrap_result_return_type_simple_with_await() {
405 unwrap_result_return_type,
408 async fn foo() -> Result<i$032> {
421 async fn foo() -> i32 {
437 fn unwrap_result_return_type_simple_with_array() {
439 unwrap_result_return_type,
442 fn foo() -> Result<[i32; 3]$0> { Ok([1, 2, 3]) }
445 fn foo() -> [i32; 3] { [1, 2, 3] }
451 fn unwrap_result_return_type_simple_with_cast() {
453 unwrap_result_return_type,
456 fn foo() -$0> Result<i32> {
485 fn unwrap_result_return_type_simple_with_tail_block_like_match() {
487 unwrap_result_return_type,
490 fn foo() -> Result<i32$0> {
511 fn unwrap_result_return_type_simple_with_loop_with_tail() {
513 unwrap_result_return_type,
516 fn foo() -> Result<i32$0> {
539 fn unwrap_result_return_type_simple_with_loop_in_let_stmt() {
541 unwrap_result_return_type,
544 fn foo() -> Result<i32$0> {
545 let my_var = let x = loop {
553 let my_var = let x = loop {
563 fn unwrap_result_return_type_simple_with_tail_block_like_match_return_expr() {
565 unwrap_result_return_type,
568 fn foo() -> Result<i32>$0 {
570 let res = match my_var {
572 _ => return Ok(24i32),
580 let res = match my_var {
590 unwrap_result_return_type,
593 fn foo() -> Result<i32$0> {
595 let res = if my_var == 5 {
606 let res = if my_var == 5 {
618 fn unwrap_result_return_type_simple_with_tail_block_like_match_deeper() {
620 unwrap_result_return_type,
623 fn foo() -> Result<i32$0> {
668 fn unwrap_result_return_type_simple_with_tail_block_like_early_return() {
670 unwrap_result_return_type,
673 fn foo() -> Result<i32$0> {
694 fn unwrap_result_return_type_simple_with_closure() {
696 unwrap_result_return_type,
699 fn foo(the_field: u32) -> Result<u32$0> {
700 let true_closure = || { return true; };
713 fn foo(the_field: u32) -> u32 {
714 let true_closure = || { return true; };
729 unwrap_result_return_type,
732 fn foo(the_field: u32) -> Result<u32$0> {
733 let true_closure = || {
748 Ok(t.unwrap_or_else(|| the_field))
752 fn foo(the_field: u32) -> u32 {
753 let true_closure = || {
768 t.unwrap_or_else(|| the_field)
775 fn unwrap_result_return_type_simple_with_weird_forms() {
777 unwrap_result_return_type,
780 fn foo() -> Result<i32$0> {
812 unwrap_result_return_type,
815 fn foo(the_field: u32) -> Result<u32$0> {
833 fn foo(the_field: u32) -> u32 {
853 unwrap_result_return_type,
856 fn foo(the_field: u32) -> Result<u32$0> {
868 fn foo(the_field: u32) -> u32 {
882 unwrap_result_return_type,
885 fn foo(the_field: u32) -> Result<u32$0> {
898 fn foo(the_field: u32) -> u32 {
913 unwrap_result_return_type,
916 fn foo(the_field: u32) -> Result<u3$02> {
929 fn foo(the_field: u32) -> u32 {