use hir::{known, AsAssocItem, Semantics};
use ide_db::{
- helpers::{for_each_tail_expr, FamousDefs},
+ helpers::{
+ for_each_tail_expr,
+ node_ext::{block_as_lone_tail, is_pattern_cond, preorder_expr},
+ FamousDefs,
+ },
RootDatabase,
};
use itertools::Itertools;
use syntax::{
- ast::{self, edit::AstNodeEdit, make, ArgListOwner},
+ ast::{self, edit::AstNodeEdit, make, HasArgList},
ted, AstNode, SyntaxNode,
};
// }
// ```
pub(crate) fn convert_if_to_bool_then(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
- // todo, applies to match as well
+ // FIXME applies to match as well
let expr = ctx.find_node_at_offset::<ast::IfExpr>()?;
if !expr.if_token()?.text_range().contains_inclusive(ctx.offset()) {
return None;
}
- let cond = expr.condition().filter(|cond| !cond.is_pattern_cond())?;
- let cond = cond.expr()?;
+ let cond = expr.condition().filter(|cond| !is_pattern_cond(cond.clone()))?;
let then = expr.then_branch()?;
let else_ = match expr.else_branch()? {
ast::ElseBranch::Block(b) => b,
e => e,
};
+ let parenthesize = matches!(
+ cond,
+ ast::Expr::BinExpr(_)
+ | ast::Expr::BlockExpr(_)
+ | ast::Expr::BoxExpr(_)
+ | ast::Expr::BreakExpr(_)
+ | ast::Expr::CastExpr(_)
+ | ast::Expr::ClosureExpr(_)
+ | ast::Expr::ContinueExpr(_)
+ | ast::Expr::ForExpr(_)
+ | ast::Expr::IfExpr(_)
+ | ast::Expr::LoopExpr(_)
+ | ast::Expr::MacroCall(_)
+ | ast::Expr::MatchExpr(_)
+ | ast::Expr::PrefixExpr(_)
+ | ast::Expr::RangeExpr(_)
+ | ast::Expr::RefExpr(_)
+ | ast::Expr::ReturnExpr(_)
+ | ast::Expr::WhileExpr(_)
+ | ast::Expr::YieldExpr(_)
+ );
let cond = if invert_cond { invert_boolean_expression(cond) } else { cond };
+ let cond = if parenthesize { make::expr_paren(cond) } else { cond };
let arg_list = make::arg_list(Some(make::expr_closure(None, closure_body)));
let mcall = make::expr_method_call(cond, make::name_ref("then"), arg_list);
builder.replace(target, mcall.to_string());
_ => receiver,
};
let if_expr = make::expr_if(
- make::condition(cond, None),
+ cond,
closure_body.reset_indent(),
Some(ast::ElseBranch::Block(make::block_expr(None, Some(none_path)))),
)
sema: &Semantics<RootDatabase>,
expr: &SyntaxNode,
) -> Option<(hir::Variant, hir::Variant)> {
- let fam = FamousDefs(&sema, sema.scope(expr).krate());
+ let fam = FamousDefs(sema, sema.scope(expr).krate());
let option_variants = fam.core_option_Option()?.variants(sema.db);
match &*option_variants {
&[variant0, variant1] => Some(if variant0.name(sema.db) == known::None {
expr: &ast::Expr,
) -> bool {
let mut invalid = false;
- expr.preorder(&mut |e| {
+ preorder_expr(expr, &mut |e| {
invalid |=
matches!(e, syntax::WalkEvent::Enter(ast::Expr::TryExpr(_) | ast::Expr::ReturnExpr(_)));
invalid
});
if !invalid {
- for_each_tail_expr(&expr, &mut |e| {
+ for_each_tail_expr(expr, &mut |e| {
if invalid {
return;
}
block: &ast::BlockExpr,
none_variant: hir::Variant,
) -> bool {
- block.as_lone_tail().and_then(|e| match e {
+ block_as_lone_tail(block).and_then(|e| match e {
ast::Expr::PathExpr(pat) => match sema.resolve_path(&pat.path()?)? {
hir::PathResolution::Def(hir::ModuleDef::Variant(v)) => Some(v),
_ => None,