1 use ra_fmt::unwrap_trivial_block;
3 ast::{self, edit::IndentLevel, make},
7 use crate::{utils::TryEnum, Assist, AssistCtx, AssistId};
9 // Assist: replace_if_let_with_match
11 // Replaces `if let` with an else branch with a `match` expression.
14 // enum Action { Move { distance: u32 }, Stop }
16 // fn handle(action: Action) {
17 // <|>if let Action::Move { distance } = action {
26 // enum Action { Move { distance: u32 }, Stop }
28 // fn handle(action: Action) {
30 // Action::Move { distance } => foo(distance),
35 pub(crate) fn replace_if_let_with_match(ctx: AssistCtx) -> Option<Assist> {
36 let if_expr: ast::IfExpr = ctx.find_node_at_offset()?;
37 let cond = if_expr.condition()?;
38 let pat = cond.pat()?;
39 let expr = cond.expr()?;
40 let then_block = if_expr.then_branch()?;
41 let else_block = match if_expr.else_branch()? {
42 ast::ElseBranch::Block(it) => it,
43 ast::ElseBranch::IfExpr(_) => return None,
47 ctx.add_assist(AssistId("replace_if_let_with_match"), "Replace with match", move |edit| {
50 let then_expr = unwrap_trivial_block(then_block);
51 make::match_arm(vec![pat.clone()], then_expr)
56 .and_then(|ty| TryEnum::from_ty(sema, &ty))
57 .map(|it| it.sad_pattern())
58 .unwrap_or_else(|| make::placeholder_pat().into());
59 let else_expr = unwrap_trivial_block(else_block);
60 make::match_arm(vec![pattern], else_expr)
62 make::expr_match(expr, make::match_arm_list(vec![then_arm, else_arm]))
65 let match_expr = IndentLevel::from_node(if_expr.syntax()).increase_indent(match_expr);
67 edit.target(if_expr.syntax().text_range());
68 edit.set_cursor(if_expr.syntax().text_range().start());
69 edit.replace_ast::<ast::Expr>(if_expr.into(), match_expr);
77 use crate::tests::{check_assist, check_assist_target};
80 fn test_replace_if_let_with_match_unwraps_simple_expressions() {
82 replace_if_let_with_match,
85 pub fn is_struct(&self) -> bool {
86 if <|>let VariantData::Struct(..) = *self {
95 pub fn is_struct(&self) -> bool {
97 VariantData::Struct(..) => true,
106 fn test_replace_if_let_with_match_doesnt_unwrap_multiline_expressions() {
108 replace_if_let_with_match,
111 if <|>let VariantData::Struct(..) = a {
122 VariantData::Struct(..) => {
134 fn replace_if_let_with_match_target() {
136 replace_if_let_with_match,
139 pub fn is_struct(&self) -> bool {
140 if <|>let VariantData::Struct(..) = *self {
147 "if let VariantData::Struct(..) = *self {
156 fn special_case_option() {
158 replace_if_let_with_match,
160 enum Option<T> { Some(T), None }
163 fn foo(x: Option<i32>) {
164 <|>if let Some(x) = x {
172 enum Option<T> { Some(T), None }
175 fn foo(x: Option<i32>) {
177 Some(x) => println!("{}", x),
178 None => println!("none"),
186 fn special_case_result() {
188 replace_if_let_with_match,
190 enum Result<T, E> { Ok(T), Err(E) }
193 fn foo(x: Result<i32, ()>) {
194 <|>if let Ok(x) = x {
202 enum Result<T, E> { Ok(T), Err(E) }
205 fn foo(x: Result<i32, ()>) {
207 Ok(x) => println!("{}", x),
208 Err(_) => println!("none"),