4 ast::{self, edit::IndentLevel, make},
8 use crate::{utils::TryEnum, AssistContext, AssistId, Assists};
10 // Assist: replace_unwrap_with_match
12 // Replaces `unwrap` a `match` expression. Works for Result and Option.
15 // enum Result<T, E> { Ok(T), Err(E) }
17 // let x: Result<i32, i32> = Result::Ok(92);
18 // let y = x.<|>unwrap();
23 // enum Result<T, E> { Ok(T), Err(E) }
25 // let x: Result<i32, i32> = Result::Ok(92);
28 // _ => unreachable!(),
32 pub(crate) fn replace_unwrap_with_match(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
33 let method_call: ast::MethodCallExpr = ctx.find_node_at_offset()?;
34 let name = method_call.name_ref()?;
35 if name.text() != "unwrap" {
38 let caller = method_call.expr()?;
39 let ty = ctx.sema.type_of_expr(&caller)?;
40 let happy_variant = TryEnum::from_ty(&ctx.sema, &ty)?.happy_case();
41 let target = method_call.syntax().text_range();
42 acc.add(AssistId("replace_unwrap_with_match"), "Replace unwrap with match", target, |edit| {
43 let ok_path = make::path_unqualified(make::path_segment(make::name_ref(happy_variant)));
44 let it = make::bind_pat(make::name("a")).into();
45 let ok_tuple = make::tuple_struct_pat(ok_path, iter::once(it)).into();
47 let bind_path = make::path_unqualified(make::path_segment(make::name_ref("a")));
48 let ok_arm = make::match_arm(iter::once(ok_tuple), make::expr_path(bind_path));
50 let unreachable_call = make::unreachable_macro_call().into();
51 let err_arm = make::match_arm(iter::once(make::placeholder_pat().into()), unreachable_call);
53 let match_arm_list = make::match_arm_list(vec![ok_arm, err_arm]);
54 let match_expr = make::expr_match(caller.clone(), match_arm_list);
55 let match_expr = IndentLevel::from_node(method_call.syntax()).increase_indent(match_expr);
57 edit.set_cursor(caller.syntax().text_range().start());
58 edit.replace_ast::<ast::Expr>(method_call.into(), match_expr);
65 use crate::tests::{check_assist, check_assist_target};
68 fn test_replace_result_unwrap_with_match() {
70 replace_unwrap_with_match,
72 enum Result<T, E> { Ok(T), Err(E) }
73 fn i<T>(a: T) -> T { a }
75 let x: Result<i32, i32> = Result::Ok(92);
76 let y = i(x).<|>unwrap();
80 enum Result<T, E> { Ok(T), Err(E) }
81 fn i<T>(a: T) -> T { a }
83 let x: Result<i32, i32> = Result::Ok(92);
84 let y = <|>match i(x) {
94 fn test_replace_option_unwrap_with_match() {
96 replace_unwrap_with_match,
98 enum Option<T> { Some(T), None }
99 fn i<T>(a: T) -> T { a }
101 let x = Option::Some(92);
102 let y = i(x).<|>unwrap();
106 enum Option<T> { Some(T), None }
107 fn i<T>(a: T) -> T { a }
109 let x = Option::Some(92);
110 let y = <|>match i(x) {
120 fn test_replace_result_unwrap_with_match_chaining() {
122 replace_unwrap_with_match,
124 enum Result<T, E> { Ok(T), Err(E) }
125 fn i<T>(a: T) -> T { a }
127 let x: Result<i32, i32> = Result::Ok(92);
128 let y = i(x).<|>unwrap().count_zeroes();
132 enum Result<T, E> { Ok(T), Err(E) }
133 fn i<T>(a: T) -> T { a }
135 let x: Result<i32, i32> = Result::Ok(92);
136 let y = <|>match i(x) {
146 fn replace_unwrap_with_match_target() {
148 replace_unwrap_with_match,
150 enum Option<T> { Some(T), None }
151 fn i<T>(a: T) -> T { a }
153 let x = Option::Some(92);
154 let y = i(x).<|>unwrap();