From 40e9a205c35f13b354c2c30c1b5aa21e0460770c Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Thu, 21 Aug 2025 21:42:47 +0800 Subject: [PATCH] Add convert unwrap_or_else for convert_bool_then Example --- ```rust //- minicore:bool_impl fn main() { true.t$0hen(|| 3).unwrap_or_else(|| 4) } ``` Old output: ```rust //- minicore:bool_impl fn main() { if true { Some(3) } else { None }.unwrap_or_else(|| 4) } ``` This PR current output: ```rust //- minicore:bool_impl fn main() { if true { 3 } else { 4 } } ``` --- .../src/handlers/convert_bool_then.rs | 70 +++++++++++++++++-- 1 file changed, 63 insertions(+), 7 deletions(-) diff --git a/crates/ide-assists/src/handlers/convert_bool_then.rs b/crates/ide-assists/src/handlers/convert_bool_then.rs index 9d5d3f223707..206fcf2a996a 100644 --- a/crates/ide-assists/src/handlers/convert_bool_then.rs +++ b/crates/ide-assists/src/handlers/convert_bool_then.rs @@ -177,6 +177,7 @@ pub(crate) fn convert_bool_then_to_if(acc: &mut Assists, ctx: &AssistContext<'_> if !assoc.implementing_ty(ctx.sema.db)?.is_bool() { return None; } + let (else_mcall, else_body) = parent_has_unwrap_or_else(&mcall).unzip(); let target = mcall.syntax().text_range(); acc.add( @@ -201,7 +202,9 @@ pub(crate) fn convert_bool_then_to_if(acc: &mut Assists, ctx: &AssistContext<'_> ast::Expr::ReturnExpr(e) => e.expr(), _ => Some(e.clone()), }; - if let Some(expr) = e { + if let Some(expr) = e + && else_body.is_none() + { editor.replace( expr.syntax().clone(), mapless_make @@ -221,14 +224,15 @@ pub(crate) fn convert_bool_then_to_if(acc: &mut Assists, ctx: &AssistContext<'_> ast::Expr::ParenExpr(expr) => expr.expr().unwrap_or(receiver), _ => receiver, }; + let else_branch = match else_body { + Some(ast::Expr::BlockExpr(block)) if block.modifier().is_none() => block, + Some(expr) => mapless_make.block_expr(None, Some(expr)), + None => make.block_expr(None, Some(none_path)), + }; let if_expr = make - .expr_if( - cond, - closure_body, - Some(ast::ElseBranch::Block(make.block_expr(None, Some(none_path)))), - ) + .expr_if(cond, closure_body, Some(else_branch.reset_indent().into())) .indent(mcall.indent_level()); - editor.replace(mcall.syntax().clone(), if_expr.syntax().clone()); + editor.replace(else_mcall.unwrap_or(mcall).syntax().clone(), if_expr.syntax().clone()); editor.add_mappings(make.finish_with_mappings()); builder.add_file_edits(ctx.vfs_file_id(), editor); @@ -303,6 +307,21 @@ fn block_is_none_variant( }) == Some(none_variant) } +fn parent_has_unwrap_or_else(e: &ast::MethodCallExpr) -> Option<(ast::MethodCallExpr, ast::Expr)> { + let parent = e.syntax().parent()?; + let mcall = ast::MethodCallExpr::cast(parent)?; + let name = mcall.name_ref()?; + + if name.text() != "unwrap_or_else" { + return None; + } + + match mcall.arg_list()?.args().collect_array() { + Some([ast::Expr::ClosureExpr(closure)]) => Some((mcall, closure.body()?)), + _ => None, + } +} + #[cfg(test)] mod tests { use crate::tests::{check_assist, check_assist_not_applicable}; @@ -587,6 +606,43 @@ fn main() { None } } +", + ); + } + + #[test] + fn convert_bool_then_to_if_unwrap_or_else() { + check_assist( + convert_bool_then_to_if, + r" +//- minicore:bool_impl +fn main() { + true.t$0hen(|| { + loop { + if false { + break 0; + } + break 15; + } + }) + .unwrap_or_else(|| { + 8 + }) +} +", + r" +fn main() { + if true { + loop { + if false { + break 0; + } + break 15; + } + } else { + 8 + } +} ", ); }