aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_assists/src/handlers
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2020-03-26 15:38:03 +0000
committerGitHub <[email protected]>2020-03-26 15:38:03 +0000
commit20c110e57f24aa54154942ee40921e9129fbc595 (patch)
treea235a1338f590a243c3fd1302ac2e32ec4d24f05 /crates/ra_assists/src/handlers
parent0a8e65cf850ec3642fa51a3b71a4a7564c46a89b (diff)
parentd9df0f43ac669a68dc76466a2f2c21885b5af2dd (diff)
Merge #3732
3732: Assist: replace unwrap with match r=matklad a=unrealhoang attempt on #3669 Co-authored-by: Unreal Hoang <[email protected]>
Diffstat (limited to 'crates/ra_assists/src/handlers')
-rw-r--r--crates/ra_assists/src/handlers/replace_unwrap_with_match.rs177
1 files changed, 177 insertions, 0 deletions
diff --git a/crates/ra_assists/src/handlers/replace_unwrap_with_match.rs b/crates/ra_assists/src/handlers/replace_unwrap_with_match.rs
new file mode 100644
index 000000000..62cb7a763
--- /dev/null
+++ b/crates/ra_assists/src/handlers/replace_unwrap_with_match.rs
@@ -0,0 +1,177 @@
1use std::iter;
2
3use ra_syntax::{
4 ast::{self, make},
5 AstNode,
6};
7
8use crate::{Assist, AssistCtx, AssistId};
9use ast::edit::IndentLevel;
10
11// Assist: replace_unwrap_with_match
12//
13// Replaces `unwrap` a `match` expression. Works for Result and Option.
14//
15// ```
16// enum Result<T, E> { Ok(T), Err(E) }
17// fn main() {
18// let x: Result<i32, i32> = Result::Ok(92);
19// let y = x.<|>unwrap();
20// }
21// ```
22// ->
23// ```
24// enum Result<T, E> { Ok(T), Err(E) }
25// fn main() {
26// let x: Result<i32, i32> = Result::Ok(92);
27// let y = match x {
28// Ok(a) => a,
29// _ => unreachable!(),
30// };
31// }
32// ```
33pub(crate) fn replace_unwrap_with_match(ctx: AssistCtx) -> Option<Assist> {
34 let method_call: ast::MethodCallExpr = ctx.find_node_at_offset()?;
35 let name = method_call.name_ref()?;
36 if name.text() != "unwrap" {
37 return None;
38 }
39 let caller = method_call.expr()?;
40 let ty = ctx.sema.type_of_expr(&caller)?;
41
42 let type_name = ty.as_adt()?.name(ctx.sema.db).to_string();
43
44 for (unwrap_type, variant_name) in [("Result", "Ok"), ("Option", "Some")].iter() {
45 if &type_name == unwrap_type {
46 return ctx.add_assist(
47 AssistId("replace_unwrap_with_match"),
48 "Replace unwrap with match",
49 |edit| {
50 let ok_path =
51 make::path_unqualified(make::path_segment(make::name_ref(variant_name)));
52 let it = make::bind_pat(make::name("a")).into();
53 let ok_tuple = make::tuple_struct_pat(ok_path, iter::once(it)).into();
54
55 let bind_path = make::path_unqualified(make::path_segment(make::name_ref("a")));
56 let ok_arm = make::match_arm(iter::once(ok_tuple), make::expr_path(bind_path));
57
58 let unreachable_call = make::unreachable_macro_call().into();
59 let err_arm = make::match_arm(
60 iter::once(make::placeholder_pat().into()),
61 unreachable_call,
62 );
63
64 let match_arm_list = make::match_arm_list(vec![ok_arm, err_arm]);
65 let match_expr = make::expr_match(caller.clone(), match_arm_list);
66 let match_expr =
67 IndentLevel::from_node(method_call.syntax()).increase_indent(match_expr);
68
69 edit.target(method_call.syntax().text_range());
70 edit.set_cursor(caller.syntax().text_range().start());
71 edit.replace_ast::<ast::Expr>(method_call.into(), match_expr);
72 },
73 );
74 }
75 }
76 None
77}
78
79#[cfg(test)]
80mod tests {
81 use super::*;
82 use crate::helpers::{check_assist, check_assist_target};
83
84 #[test]
85 fn test_replace_result_unwrap_with_match() {
86 check_assist(
87 replace_unwrap_with_match,
88 r"
89enum Result<T, E> { Ok(T), Err(E) }
90fn i<T>(a: T) -> T { a }
91fn main() {
92 let x: Result<i32, i32> = Result::Ok(92);
93 let y = i(x).<|>unwrap();
94}
95 ",
96 r"
97enum Result<T, E> { Ok(T), Err(E) }
98fn i<T>(a: T) -> T { a }
99fn main() {
100 let x: Result<i32, i32> = Result::Ok(92);
101 let y = <|>match i(x) {
102 Ok(a) => a,
103 _ => unreachable!(),
104 };
105}
106 ",
107 )
108 }
109
110 #[test]
111 fn test_replace_option_unwrap_with_match() {
112 check_assist(
113 replace_unwrap_with_match,
114 r"
115enum Option<T> { Some(T), None }
116fn i<T>(a: T) -> T { a }
117fn main() {
118 let x = Option::Some(92);
119 let y = i(x).<|>unwrap();
120}
121 ",
122 r"
123enum Option<T> { Some(T), None }
124fn i<T>(a: T) -> T { a }
125fn main() {
126 let x = Option::Some(92);
127 let y = <|>match i(x) {
128 Some(a) => a,
129 _ => unreachable!(),
130 };
131}
132 ",
133 );
134 }
135
136 #[test]
137 fn test_replace_result_unwrap_with_match_chaining() {
138 check_assist(
139 replace_unwrap_with_match,
140 r"
141enum Result<T, E> { Ok(T), Err(E) }
142fn i<T>(a: T) -> T { a }
143fn main() {
144 let x: Result<i32, i32> = Result::Ok(92);
145 let y = i(x).<|>unwrap().count_zeroes();
146}
147 ",
148 r"
149enum Result<T, E> { Ok(T), Err(E) }
150fn i<T>(a: T) -> T { a }
151fn main() {
152 let x: Result<i32, i32> = Result::Ok(92);
153 let y = <|>match i(x) {
154 Ok(a) => a,
155 _ => unreachable!(),
156 }.count_zeroes();
157}
158 ",
159 )
160 }
161
162 #[test]
163 fn replace_unwrap_with_match_target() {
164 check_assist_target(
165 replace_unwrap_with_match,
166 r"
167enum Option<T> { Some(T), None }
168fn i<T>(a: T) -> T { a }
169fn main() {
170 let x = Option::Some(92);
171 let y = i(x).<|>unwrap();
172}
173 ",
174 r"i(x).unwrap()",
175 );
176 }
177}