1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
|
use ra_syntax::{
AstNode, SyntaxKind::{L_CURLY, R_CURLY, WHITESPACE},
ast,
};
use crate::assists::{AssistCtx, Assist};
pub fn replace_if_let_with_match(ctx: AssistCtx) -> Option<Assist> {
let if_expr: &ast::IfExpr = ctx.node_at_offset()?;
let cond = if_expr.condition()?;
let pat = cond.pat()?;
let expr = cond.expr()?;
let then_block = if_expr.then_branch()?;
let else_block = if_expr.else_branch()?;
ctx.build("replace with match", |edit| {
let match_expr = build_match_expr(expr, pat, then_block, else_block);
edit.replace_node_and_indent(if_expr.syntax(), match_expr);
edit.set_cursor(if_expr.syntax().range().start())
})
}
fn build_match_expr(
expr: &ast::Expr,
pat1: &ast::Pat,
arm1: &ast::Block,
arm2: &ast::Block,
) -> String {
let mut buf = String::new();
buf.push_str(&format!("match {} {{\n", expr.syntax().text()));
buf.push_str(&format!(
" {} => {}\n",
pat1.syntax().text(),
format_arm(arm1)
));
buf.push_str(&format!(" _ => {}\n", format_arm(arm2)));
buf.push_str("}");
buf
}
fn format_arm(block: &ast::Block) -> String {
match extract_expression(block) {
None => block.syntax().text().to_string(),
Some(e) => format!("{},", e.syntax().text()),
}
}
fn extract_expression(block: &ast::Block) -> Option<&ast::Expr> {
let expr = block.expr()?;
let non_trivial_children = block.syntax().children().filter(|it| {
!(it == &expr.syntax()
|| it.kind() == L_CURLY
|| it.kind() == R_CURLY
|| it.kind() == WHITESPACE)
});
if non_trivial_children.count() > 0 {
return None;
}
Some(expr)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::assists::check_assist;
#[test]
fn test_replace_if_let_with_match_unwraps_simple_expressions() {
check_assist(
replace_if_let_with_match,
"
impl VariantData {
pub fn is_struct(&self) -> bool {
if <|>let VariantData::Struct(..) = *self {
true
} else {
false
}
}
} ",
"
impl VariantData {
pub fn is_struct(&self) -> bool {
<|>match *self {
VariantData::Struct(..) => true,
_ => false,
}
}
} ",
)
}
}
|