4 ast::{self, edit::IndentLevel, make},
8 use crate::{utils::TryEnum, Assist, AssistCtx, AssistId};
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(ctx: AssistCtx) -> Option<Assist> {
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();
43 AssistId("replace_unwrap_with_match"),
44 "Replace unwrap with match",
47 let ok_path = make::path_unqualified(make::path_segment(make::name_ref(happy_variant)));
48 let it = make::bind_pat(make::name("a")).into();
49 let ok_tuple = make::tuple_struct_pat(ok_path, iter::once(it)).into();
51 let bind_path = make::path_unqualified(make::path_segment(make::name_ref("a")));
52 let ok_arm = make::match_arm(iter::once(ok_tuple), make::expr_path(bind_path));
54 let unreachable_call = make::unreachable_macro_call().into();
56 make::match_arm(iter::once(make::placeholder_pat().into()), unreachable_call);
58 let match_arm_list = make::match_arm_list(vec![ok_arm, err_arm]);
59 let match_expr = make::expr_match(caller.clone(), match_arm_list);
61 IndentLevel::from_node(method_call.syntax()).increase_indent(match_expr);
63 edit.set_cursor(caller.syntax().text_range().start());
64 edit.replace_ast::<ast::Expr>(method_call.into(), match_expr);
72 use crate::tests::{check_assist, check_assist_target};
75 fn test_replace_result_unwrap_with_match() {
77 replace_unwrap_with_match,
79 enum Result<T, E> { Ok(T), Err(E) }
80 fn i<T>(a: T) -> T { a }
82 let x: Result<i32, i32> = Result::Ok(92);
83 let y = i(x).<|>unwrap();
87 enum Result<T, E> { Ok(T), Err(E) }
88 fn i<T>(a: T) -> T { a }
90 let x: Result<i32, i32> = Result::Ok(92);
91 let y = <|>match i(x) {
101 fn test_replace_option_unwrap_with_match() {
103 replace_unwrap_with_match,
105 enum Option<T> { Some(T), None }
106 fn i<T>(a: T) -> T { a }
108 let x = Option::Some(92);
109 let y = i(x).<|>unwrap();
113 enum Option<T> { Some(T), None }
114 fn i<T>(a: T) -> T { a }
116 let x = Option::Some(92);
117 let y = <|>match i(x) {
127 fn test_replace_result_unwrap_with_match_chaining() {
129 replace_unwrap_with_match,
131 enum Result<T, E> { Ok(T), Err(E) }
132 fn i<T>(a: T) -> T { a }
134 let x: Result<i32, i32> = Result::Ok(92);
135 let y = i(x).<|>unwrap().count_zeroes();
139 enum Result<T, E> { Ok(T), Err(E) }
140 fn i<T>(a: T) -> T { a }
142 let x: Result<i32, i32> = Result::Ok(92);
143 let y = <|>match i(x) {
153 fn replace_unwrap_with_match_target() {
155 replace_unwrap_with_match,
157 enum Option<T> { Some(T), None }
158 fn i<T>(a: T) -> T { a }
160 let x = Option::Some(92);
161 let y = i(x).<|>unwrap();