6 edit::{AstNodeEdit, IndentLevel},
13 utils::{render_snippet, Cursor, TryEnum},
14 AssistContext, AssistId, Assists,
17 // Assist: replace_unwrap_with_match
19 // Replaces `unwrap` a `match` expression. Works for Result and Option.
22 // enum Result<T, E> { Ok(T), Err(E) }
24 // let x: Result<i32, i32> = Result::Ok(92);
25 // let y = x.<|>unwrap();
30 // enum Result<T, E> { Ok(T), Err(E) }
32 // let x: Result<i32, i32> = Result::Ok(92);
35 // $0_ => unreachable!(),
39 pub(crate) fn replace_unwrap_with_match(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
40 let method_call: ast::MethodCallExpr = ctx.find_node_at_offset()?;
41 let name = method_call.name_ref()?;
42 if name.text() != "unwrap" {
45 let caller = method_call.expr()?;
46 let ty = ctx.sema.type_of_expr(&caller)?;
47 let happy_variant = TryEnum::from_ty(&ctx.sema, &ty)?.happy_case();
48 let target = method_call.syntax().text_range();
49 acc.add(AssistId("replace_unwrap_with_match"), "Replace unwrap with match", target, |builder| {
50 let ok_path = make::path_unqualified(make::path_segment(make::name_ref(happy_variant)));
51 let it = make::bind_pat(make::name("a")).into();
52 let ok_tuple = make::tuple_struct_pat(ok_path, iter::once(it)).into();
54 let bind_path = make::path_unqualified(make::path_segment(make::name_ref("a")));
55 let ok_arm = make::match_arm(iter::once(ok_tuple), make::expr_path(bind_path));
57 let unreachable_call = make::expr_unreachable();
58 let err_arm = make::match_arm(iter::once(make::placeholder_pat().into()), unreachable_call);
60 let match_arm_list = make::match_arm_list(vec![ok_arm, err_arm]);
61 let match_expr = make::expr_match(caller.clone(), match_arm_list)
62 .indent(IndentLevel::from_node(method_call.syntax()));
64 let range = method_call.syntax().text_range();
65 match ctx.config.snippet_cap {
67 let err_arm = match_expr
70 .filter_map(ast::MatchArm::cast)
74 render_snippet(cap, match_expr.syntax(), Cursor::Before(err_arm.syntax()));
75 builder.replace_snippet(cap, range, snippet)
77 None => builder.replace(range, match_expr.to_string()),
84 use crate::tests::{check_assist, check_assist_target};
89 fn test_replace_result_unwrap_with_match() {
91 replace_unwrap_with_match,
93 enum Result<T, E> { Ok(T), Err(E) }
94 fn i<T>(a: T) -> T { a }
96 let x: Result<i32, i32> = Result::Ok(92);
97 let y = i(x).<|>unwrap();
101 enum Result<T, E> { Ok(T), Err(E) }
102 fn i<T>(a: T) -> T { a }
104 let x: Result<i32, i32> = Result::Ok(92);
107 $0_ => unreachable!(),
115 fn test_replace_option_unwrap_with_match() {
117 replace_unwrap_with_match,
119 enum Option<T> { Some(T), None }
120 fn i<T>(a: T) -> T { a }
122 let x = Option::Some(92);
123 let y = i(x).<|>unwrap();
127 enum Option<T> { Some(T), None }
128 fn i<T>(a: T) -> T { a }
130 let x = Option::Some(92);
133 $0_ => unreachable!(),
141 fn test_replace_result_unwrap_with_match_chaining() {
143 replace_unwrap_with_match,
145 enum Result<T, E> { Ok(T), Err(E) }
146 fn i<T>(a: T) -> T { a }
148 let x: Result<i32, i32> = Result::Ok(92);
149 let y = i(x).<|>unwrap().count_zeroes();
153 enum Result<T, E> { Ok(T), Err(E) }
154 fn i<T>(a: T) -> T { a }
156 let x: Result<i32, i32> = Result::Ok(92);
159 $0_ => unreachable!(),
167 fn replace_unwrap_with_match_target() {
169 replace_unwrap_with_match,
171 enum Option<T> { Some(T), None }
172 fn i<T>(a: T) -> T { a }
174 let x = Option::Some(92);
175 let y = i(x).<|>unwrap();