diff options
author | Kevin DeLorey <[email protected]> | 2020-02-09 16:25:47 +0000 |
---|---|---|
committer | Kevin DeLorey <[email protected]> | 2020-02-09 16:37:43 +0000 |
commit | a957c473fdb79880c39b73dc9e0c923093cf16ac (patch) | |
tree | f998b548f530ce604651e0e6af314ed2ec74b3b5 /crates/ra_assists/src/handlers/replace_if_let_with_match.rs | |
parent | 22caf982b99c54058e2e9200aeea0e61cada284a (diff) | |
parent | 1b9b13b4b4a75b5531c3f046ce6bf72d681f2732 (diff) |
Merge branch 'master' into kdelorey/complete-trait-impl
Diffstat (limited to 'crates/ra_assists/src/handlers/replace_if_let_with_match.rs')
-rw-r--r-- | crates/ra_assists/src/handlers/replace_if_let_with_match.rs | 148 |
1 files changed, 148 insertions, 0 deletions
diff --git a/crates/ra_assists/src/handlers/replace_if_let_with_match.rs b/crates/ra_assists/src/handlers/replace_if_let_with_match.rs new file mode 100644 index 000000000..e6cd50bc1 --- /dev/null +++ b/crates/ra_assists/src/handlers/replace_if_let_with_match.rs | |||
@@ -0,0 +1,148 @@ | |||
1 | use ra_fmt::unwrap_trivial_block; | ||
2 | use ra_syntax::{ | ||
3 | ast::{self, make}, | ||
4 | AstNode, | ||
5 | }; | ||
6 | |||
7 | use crate::{Assist, AssistCtx, AssistId}; | ||
8 | use ast::edit::IndentLevel; | ||
9 | |||
10 | // Assist: replace_if_let_with_match | ||
11 | // | ||
12 | // Replaces `if let` with an else branch with a `match` expression. | ||
13 | // | ||
14 | // ``` | ||
15 | // enum Action { Move { distance: u32 }, Stop } | ||
16 | // | ||
17 | // fn handle(action: Action) { | ||
18 | // <|>if let Action::Move { distance } = action { | ||
19 | // foo(distance) | ||
20 | // } else { | ||
21 | // bar() | ||
22 | // } | ||
23 | // } | ||
24 | // ``` | ||
25 | // -> | ||
26 | // ``` | ||
27 | // enum Action { Move { distance: u32 }, Stop } | ||
28 | // | ||
29 | // fn handle(action: Action) { | ||
30 | // match action { | ||
31 | // Action::Move { distance } => foo(distance), | ||
32 | // _ => bar(), | ||
33 | // } | ||
34 | // } | ||
35 | // ``` | ||
36 | pub(crate) fn replace_if_let_with_match(ctx: AssistCtx) -> Option<Assist> { | ||
37 | let if_expr: ast::IfExpr = ctx.find_node_at_offset()?; | ||
38 | let cond = if_expr.condition()?; | ||
39 | let pat = cond.pat()?; | ||
40 | let expr = cond.expr()?; | ||
41 | let then_block = if_expr.then_branch()?; | ||
42 | let else_block = match if_expr.else_branch()? { | ||
43 | ast::ElseBranch::Block(it) => it, | ||
44 | ast::ElseBranch::IfExpr(_) => return None, | ||
45 | }; | ||
46 | |||
47 | ctx.add_assist(AssistId("replace_if_let_with_match"), "Replace with match", |edit| { | ||
48 | let match_expr = { | ||
49 | let then_arm = { | ||
50 | let then_expr = unwrap_trivial_block(then_block); | ||
51 | make::match_arm(vec![pat], then_expr) | ||
52 | }; | ||
53 | let else_arm = { | ||
54 | let else_expr = unwrap_trivial_block(else_block); | ||
55 | make::match_arm(vec![make::placeholder_pat().into()], else_expr) | ||
56 | }; | ||
57 | make::expr_match(expr, make::match_arm_list(vec![then_arm, else_arm])) | ||
58 | }; | ||
59 | |||
60 | let match_expr = IndentLevel::from_node(if_expr.syntax()).increase_indent(match_expr); | ||
61 | |||
62 | edit.target(if_expr.syntax().text_range()); | ||
63 | edit.set_cursor(if_expr.syntax().text_range().start()); | ||
64 | edit.replace_ast::<ast::Expr>(if_expr.into(), match_expr.into()); | ||
65 | }) | ||
66 | } | ||
67 | |||
68 | #[cfg(test)] | ||
69 | mod tests { | ||
70 | use super::*; | ||
71 | use crate::helpers::{check_assist, check_assist_target}; | ||
72 | |||
73 | #[test] | ||
74 | fn test_replace_if_let_with_match_unwraps_simple_expressions() { | ||
75 | check_assist( | ||
76 | replace_if_let_with_match, | ||
77 | " | ||
78 | impl VariantData { | ||
79 | pub fn is_struct(&self) -> bool { | ||
80 | if <|>let VariantData::Struct(..) = *self { | ||
81 | true | ||
82 | } else { | ||
83 | false | ||
84 | } | ||
85 | } | ||
86 | } ", | ||
87 | " | ||
88 | impl VariantData { | ||
89 | pub fn is_struct(&self) -> bool { | ||
90 | <|>match *self { | ||
91 | VariantData::Struct(..) => true, | ||
92 | _ => false, | ||
93 | } | ||
94 | } | ||
95 | } ", | ||
96 | ) | ||
97 | } | ||
98 | |||
99 | #[test] | ||
100 | fn test_replace_if_let_with_match_doesnt_unwrap_multiline_expressions() { | ||
101 | check_assist( | ||
102 | replace_if_let_with_match, | ||
103 | " | ||
104 | fn foo() { | ||
105 | if <|>let VariantData::Struct(..) = a { | ||
106 | bar( | ||
107 | 123 | ||
108 | ) | ||
109 | } else { | ||
110 | false | ||
111 | } | ||
112 | } ", | ||
113 | " | ||
114 | fn foo() { | ||
115 | <|>match a { | ||
116 | VariantData::Struct(..) => { | ||
117 | bar( | ||
118 | 123 | ||
119 | ) | ||
120 | } | ||
121 | _ => false, | ||
122 | } | ||
123 | } ", | ||
124 | ) | ||
125 | } | ||
126 | |||
127 | #[test] | ||
128 | fn replace_if_let_with_match_target() { | ||
129 | check_assist_target( | ||
130 | replace_if_let_with_match, | ||
131 | " | ||
132 | impl VariantData { | ||
133 | pub fn is_struct(&self) -> bool { | ||
134 | if <|>let VariantData::Struct(..) = *self { | ||
135 | true | ||
136 | } else { | ||
137 | false | ||
138 | } | ||
139 | } | ||
140 | } ", | ||
141 | "if let VariantData::Struct(..) = *self { | ||
142 | true | ||
143 | } else { | ||
144 | false | ||
145 | }", | ||
146 | ); | ||
147 | } | ||
148 | } | ||