Skip to content

Commit a4c6e8c

Browse files
committed
Refactor if-let -> match assist to use ast::make
1 parent 83dc22e commit a4c6e8c

File tree

4 files changed

+55
-32
lines changed

4 files changed

+55
-32
lines changed

crates/ra_assists/src/assists/replace_if_let_with_match.rs

Lines changed: 22 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
1-
use format_buf::format;
21
use hir::db::HirDatabase;
3-
use ra_fmt::extract_trivial_expression;
4-
use ra_syntax::{ast, AstNode};
2+
use ra_fmt::unwrap_trivial_block;
3+
use ra_syntax::{
4+
ast::{self, make},
5+
AstNode,
6+
};
57

68
use crate::{Assist, AssistCtx, AssistId};
9+
use ast::edit::IndentLevel;
710

811
// Assist: replace_if_let_with_match
912
//
@@ -43,32 +46,24 @@ pub(crate) fn replace_if_let_with_match(ctx: AssistCtx<impl HirDatabase>) -> Opt
4346
};
4447

4548
ctx.add_assist(AssistId("replace_if_let_with_match"), "Replace with match", |edit| {
46-
let match_expr = build_match_expr(expr, pat, then_block, else_block);
47-
edit.target(if_expr.syntax().text_range());
48-
edit.replace_node_and_indent(if_expr.syntax(), match_expr);
49-
edit.set_cursor(if_expr.syntax().text_range().start())
50-
})
51-
}
49+
let match_expr = {
50+
let then_arm = {
51+
let then_expr = unwrap_trivial_block(then_block);
52+
make::match_arm(vec![pat], then_expr)
53+
};
54+
let else_arm = {
55+
let else_expr = unwrap_trivial_block(else_block);
56+
make::match_arm(vec![make::placeholder_pat().into()], else_expr)
57+
};
58+
make::expr_match(expr, make::match_arm_list(vec![then_arm, else_arm]))
59+
};
5260

53-
fn build_match_expr(
54-
expr: ast::Expr,
55-
pat1: ast::Pat,
56-
arm1: ast::BlockExpr,
57-
arm2: ast::BlockExpr,
58-
) -> String {
59-
let mut buf = String::new();
60-
format!(buf, "match {} {{\n", expr.syntax().text());
61-
format!(buf, " {} => {}\n", pat1.syntax().text(), format_arm(&arm1));
62-
format!(buf, " _ => {}\n", format_arm(&arm2));
63-
buf.push_str("}");
64-
buf
65-
}
61+
let match_expr = IndentLevel::from_node(if_expr.syntax()).increase_indent(match_expr);
6662

67-
fn format_arm(block: &ast::BlockExpr) -> String {
68-
match extract_trivial_expression(block) {
69-
Some(e) if !e.syntax().text().contains_char('\n') => format!("{},", e.syntax().text()),
70-
_ => block.syntax().text().to_string(),
71-
}
63+
edit.target(if_expr.syntax().text_range());
64+
edit.set_cursor(if_expr.syntax().text_range().start());
65+
edit.replace_ast::<ast::Expr>(if_expr.into(), match_expr.into());
66+
})
7267
}
7368

7469
#[cfg(test)]

crates/ra_fmt/src/lib.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,14 @@ fn prev_tokens(token: SyntaxToken) -> impl Iterator<Item = SyntaxToken> {
3535
successors(token.prev_token(), |token| token.prev_token())
3636
}
3737

38-
pub fn extract_trivial_expression(expr: &ast::BlockExpr) -> Option<ast::Expr> {
39-
let block = expr.block()?;
38+
pub fn unwrap_trivial_block(block: ast::BlockExpr) -> ast::Expr {
39+
extract_trivial_expression(&block)
40+
.filter(|expr| !expr.syntax().text().contains_char('\n'))
41+
.unwrap_or_else(|| block.into())
42+
}
43+
44+
pub fn extract_trivial_expression(block: &ast::BlockExpr) -> Option<ast::Expr> {
45+
let block = block.block()?;
4046
let expr = block.expr()?;
4147
let non_trivial_children = block.syntax().children().filter(|it| match it.kind() {
4248
WHITESPACE | T!['{'] | T!['}'] => false,

crates/ra_syntax/src/ast/expr_extensions.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,21 @@ use crate::{
77
SyntaxToken, T,
88
};
99

10+
impl ast::Expr {
11+
pub fn is_block_like(&self) -> bool {
12+
match self {
13+
ast::Expr::IfExpr(_)
14+
| ast::Expr::LoopExpr(_)
15+
| ast::Expr::ForExpr(_)
16+
| ast::Expr::WhileExpr(_)
17+
| ast::Expr::BlockExpr(_)
18+
| ast::Expr::MatchExpr(_)
19+
| ast::Expr::TryBlockExpr(_) => true,
20+
_ => false,
21+
}
22+
}
23+
}
24+
1025
#[derive(Debug, Clone, PartialEq, Eq)]
1126
pub enum ElseBranch {
1227
Block(ast::BlockExpr),

crates/ra_syntax/src/ast/make.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -122,11 +122,18 @@ pub fn match_arm(pats: impl IntoIterator<Item = ast::Pat>, expr: ast::Expr) -> a
122122
}
123123

124124
pub fn match_arm_list(arms: impl IntoIterator<Item = ast::MatchArm>) -> ast::MatchArmList {
125-
let arms_str = arms.into_iter().map(|arm| format!("\n {}", arm.syntax())).join(",");
126-
return from_text(&format!("{},\n", arms_str));
125+
let arms_str = arms
126+
.into_iter()
127+
.map(|arm| {
128+
let needs_comma = arm.expr().map_or(true, |it| !it.is_block_like());
129+
let comma = if needs_comma { "," } else { "" };
130+
format!(" {}{}\n", arm.syntax(), comma)
131+
})
132+
.collect::<String>();
133+
return from_text(&format!("{}", arms_str));
127134

128135
fn from_text(text: &str) -> ast::MatchArmList {
129-
ast_from_text(&format!("fn f() {{ match () {{{}}} }}", text))
136+
ast_from_text(&format!("fn f() {{ match () {{\n{}}} }}", text))
130137
}
131138
}
132139

0 commit comments

Comments
 (0)