diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2020-03-26 15:38:03 +0000 |
---|---|---|
committer | GitHub <[email protected]> | 2020-03-26 15:38:03 +0000 |
commit | 20c110e57f24aa54154942ee40921e9129fbc595 (patch) | |
tree | a235a1338f590a243c3fd1302ac2e32ec4d24f05 /crates | |
parent | 0a8e65cf850ec3642fa51a3b71a4a7564c46a89b (diff) | |
parent | d9df0f43ac669a68dc76466a2f2c21885b5af2dd (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')
-rw-r--r-- | crates/ra_assists/src/doc_tests/generated.rs | 24 | ||||
-rw-r--r-- | crates/ra_assists/src/handlers/replace_unwrap_with_match.rs | 177 | ||||
-rw-r--r-- | crates/ra_assists/src/lib.rs | 2 | ||||
-rw-r--r-- | crates/ra_syntax/src/ast/make.rs | 4 |
4 files changed, 207 insertions, 0 deletions
diff --git a/crates/ra_assists/src/doc_tests/generated.rs b/crates/ra_assists/src/doc_tests/generated.rs index 62dcb3808..543224232 100644 --- a/crates/ra_assists/src/doc_tests/generated.rs +++ b/crates/ra_assists/src/doc_tests/generated.rs | |||
@@ -623,6 +623,30 @@ fn process(map: HashMap<String, String>) {} | |||
623 | } | 623 | } |
624 | 624 | ||
625 | #[test] | 625 | #[test] |
626 | fn doctest_replace_unwrap_with_match() { | ||
627 | check( | ||
628 | "replace_unwrap_with_match", | ||
629 | r#####" | ||
630 | enum Result<T, E> { Ok(T), Err(E) } | ||
631 | fn main() { | ||
632 | let x: Result<i32, i32> = Result::Ok(92); | ||
633 | let y = x.<|>unwrap(); | ||
634 | } | ||
635 | "#####, | ||
636 | r#####" | ||
637 | enum Result<T, E> { Ok(T), Err(E) } | ||
638 | fn main() { | ||
639 | let x: Result<i32, i32> = Result::Ok(92); | ||
640 | let y = match x { | ||
641 | Ok(a) => a, | ||
642 | _ => unreachable!(), | ||
643 | }; | ||
644 | } | ||
645 | "#####, | ||
646 | ) | ||
647 | } | ||
648 | |||
649 | #[test] | ||
626 | fn doctest_split_import() { | 650 | fn doctest_split_import() { |
627 | check( | 651 | check( |
628 | "split_import", | 652 | "split_import", |
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 @@ | |||
1 | use std::iter; | ||
2 | |||
3 | use ra_syntax::{ | ||
4 | ast::{self, make}, | ||
5 | AstNode, | ||
6 | }; | ||
7 | |||
8 | use crate::{Assist, AssistCtx, AssistId}; | ||
9 | use 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 | // ``` | ||
33 | pub(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)] | ||
80 | mod 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" | ||
89 | enum Result<T, E> { Ok(T), Err(E) } | ||
90 | fn i<T>(a: T) -> T { a } | ||
91 | fn main() { | ||
92 | let x: Result<i32, i32> = Result::Ok(92); | ||
93 | let y = i(x).<|>unwrap(); | ||
94 | } | ||
95 | ", | ||
96 | r" | ||
97 | enum Result<T, E> { Ok(T), Err(E) } | ||
98 | fn i<T>(a: T) -> T { a } | ||
99 | fn 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" | ||
115 | enum Option<T> { Some(T), None } | ||
116 | fn i<T>(a: T) -> T { a } | ||
117 | fn main() { | ||
118 | let x = Option::Some(92); | ||
119 | let y = i(x).<|>unwrap(); | ||
120 | } | ||
121 | ", | ||
122 | r" | ||
123 | enum Option<T> { Some(T), None } | ||
124 | fn i<T>(a: T) -> T { a } | ||
125 | fn 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" | ||
141 | enum Result<T, E> { Ok(T), Err(E) } | ||
142 | fn i<T>(a: T) -> T { a } | ||
143 | fn main() { | ||
144 | let x: Result<i32, i32> = Result::Ok(92); | ||
145 | let y = i(x).<|>unwrap().count_zeroes(); | ||
146 | } | ||
147 | ", | ||
148 | r" | ||
149 | enum Result<T, E> { Ok(T), Err(E) } | ||
150 | fn i<T>(a: T) -> T { a } | ||
151 | fn 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" | ||
167 | enum Option<T> { Some(T), None } | ||
168 | fn i<T>(a: T) -> T { a } | ||
169 | fn main() { | ||
170 | let x = Option::Some(92); | ||
171 | let y = i(x).<|>unwrap(); | ||
172 | } | ||
173 | ", | ||
174 | r"i(x).unwrap()", | ||
175 | ); | ||
176 | } | ||
177 | } | ||
diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs index bcc9b3f10..becd5e99d 100644 --- a/crates/ra_assists/src/lib.rs +++ b/crates/ra_assists/src/lib.rs | |||
@@ -119,6 +119,7 @@ mod handlers { | |||
119 | mod remove_mut; | 119 | mod remove_mut; |
120 | mod replace_if_let_with_match; | 120 | mod replace_if_let_with_match; |
121 | mod replace_qualified_name_with_use; | 121 | mod replace_qualified_name_with_use; |
122 | mod replace_unwrap_with_match; | ||
122 | mod split_import; | 123 | mod split_import; |
123 | 124 | ||
124 | pub(crate) fn all() -> &'static [AssistHandler] { | 125 | pub(crate) fn all() -> &'static [AssistHandler] { |
@@ -154,6 +155,7 @@ mod handlers { | |||
154 | remove_mut::remove_mut, | 155 | remove_mut::remove_mut, |
155 | replace_if_let_with_match::replace_if_let_with_match, | 156 | replace_if_let_with_match::replace_if_let_with_match, |
156 | replace_qualified_name_with_use::replace_qualified_name_with_use, | 157 | replace_qualified_name_with_use::replace_qualified_name_with_use, |
158 | replace_unwrap_with_match::replace_unwrap_with_match, | ||
157 | split_import::split_import, | 159 | split_import::split_import, |
158 | ] | 160 | ] |
159 | } | 161 | } |
diff --git a/crates/ra_syntax/src/ast/make.rs b/crates/ra_syntax/src/ast/make.rs index 1145b69e8..e29600439 100644 --- a/crates/ra_syntax/src/ast/make.rs +++ b/crates/ra_syntax/src/ast/make.rs | |||
@@ -250,6 +250,10 @@ pub fn token(kind: SyntaxKind) -> SyntaxToken { | |||
250 | .unwrap_or_else(|| panic!("unhandled token: {:?}", kind)) | 250 | .unwrap_or_else(|| panic!("unhandled token: {:?}", kind)) |
251 | } | 251 | } |
252 | 252 | ||
253 | pub fn unreachable_macro_call() -> ast::MacroCall { | ||
254 | ast_from_text(&format!("unreachable!()")) | ||
255 | } | ||
256 | |||
253 | fn ast_from_text<N: AstNode>(text: &str) -> N { | 257 | fn ast_from_text<N: AstNode>(text: &str) -> N { |
254 | let parse = SourceFile::parse(text); | 258 | let parse = SourceFile::parse(text); |
255 | let node = parse.tree().syntax().descendants().find_map(N::cast).unwrap(); | 259 | let node = parse.tree().syntax().descendants().find_map(N::cast).unwrap(); |