aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_assists/src/handlers/replace_if_let_with_match.rs
diff options
context:
space:
mode:
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.rs148
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 @@
1use ra_fmt::unwrap_trivial_block;
2use ra_syntax::{
3 ast::{self, make},
4 AstNode,
5};
6
7use crate::{Assist, AssistCtx, AssistId};
8use 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// ```
36pub(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)]
69mod 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 "
78impl VariantData {
79 pub fn is_struct(&self) -> bool {
80 if <|>let VariantData::Struct(..) = *self {
81 true
82 } else {
83 false
84 }
85 }
86} ",
87 "
88impl 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 "
104fn foo() {
105 if <|>let VariantData::Struct(..) = a {
106 bar(
107 123
108 )
109 } else {
110 false
111 }
112} ",
113 "
114fn 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 "
132impl 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}