From c976f9900dae277a2d8cdbbe8ba6ebbae931718f Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Fri, 19 Sep 2025 19:55:02 +0800 Subject: [PATCH] Fix `else` completion before else keyword Example --- ```rust fn foo() { let x = if true { 1 } el$0 else { 2 }; } ``` **Before this PR**: ```text else~ k [LS] else if~ k [LS] ``` **After this PR**: ```text else if~ k [LS] ``` --- crates/ide-completion/src/completions/expr.rs | 3 +- crates/ide-completion/src/context.rs | 1 + crates/ide-completion/src/context/analysis.rs | 4 +- crates/ide-completion/src/tests/expression.rs | 128 +++++++++++++++++- 4 files changed, 133 insertions(+), 3 deletions(-) diff --git a/crates/ide-completion/src/completions/expr.rs b/crates/ide-completion/src/completions/expr.rs index a7df0ab3863b..080875e01632 100644 --- a/crates/ide-completion/src/completions/expr.rs +++ b/crates/ide-completion/src/completions/expr.rs @@ -59,6 +59,7 @@ pub(crate) fn complete_expr_path( in_block_expr, in_breakable, after_if_expr, + before_else_kw, in_condition, incomplete_let, after_incomplete_let, @@ -386,7 +387,7 @@ pub(crate) fn complete_expr_path( add_keyword("let", "let $1 = $0;"); } - if after_if_expr || after_incomplete_let { + if !before_else_kw && (after_if_expr || after_incomplete_let) { add_keyword("else", "else {\n $0\n}"); } diff --git a/crates/ide-completion/src/context.rs b/crates/ide-completion/src/context.rs index 007475688d20..9deaaf663127 100644 --- a/crates/ide-completion/src/context.rs +++ b/crates/ide-completion/src/context.rs @@ -144,6 +144,7 @@ pub(crate) struct PathExprCtx<'db> { pub(crate) in_block_expr: bool, pub(crate) in_breakable: BreakableKind, pub(crate) after_if_expr: bool, + pub(crate) before_else_kw: bool, /// Whether this expression is the direct condition of an if or while expression pub(crate) in_condition: bool, pub(crate) incomplete_let: bool, diff --git a/crates/ide-completion/src/context/analysis.rs b/crates/ide-completion/src/context/analysis.rs index b33a547dee97..7b78a9700ec5 100644 --- a/crates/ide-completion/src/context/analysis.rs +++ b/crates/ide-completion/src/context/analysis.rs @@ -1282,11 +1282,12 @@ fn classify_name_ref<'db>( let after_incomplete_let = after_incomplete_let(it.clone()).is_some(); let incomplete_expr_stmt = it.parent().and_then(ast::ExprStmt::cast).map(|it| it.semicolon_token().is_none()); + let before_else_kw = before_else_kw(it); let incomplete_let = it .parent() .and_then(ast::LetStmt::cast) .is_some_and(|it| it.semicolon_token().is_none()) - || after_incomplete_let && incomplete_expr_stmt.unwrap_or(true) && !before_else_kw(it); + || after_incomplete_let && incomplete_expr_stmt.unwrap_or(true) && !before_else_kw; let in_value = it.parent().and_then(Either::::cast).is_some(); let impl_ = fetch_immediate_impl(sema, original_file, expr.syntax()); @@ -1302,6 +1303,7 @@ fn classify_name_ref<'db>( in_block_expr, in_breakable: in_loop_body, after_if_expr, + before_else_kw, in_condition, ref_expr_parent, after_amp, diff --git a/crates/ide-completion/src/tests/expression.rs b/crates/ide-completion/src/tests/expression.rs index 79137104b568..db9a7b2efe17 100644 --- a/crates/ide-completion/src/tests/expression.rs +++ b/crates/ide-completion/src/tests/expression.rs @@ -1673,7 +1673,133 @@ fn foo() { let x = if foo {} $0 else {}; } kw async kw const kw crate:: - kw else + kw else if + kw enum + kw extern + kw false + kw fn + kw for + kw if + kw if let + kw impl + kw impl for + kw let + kw letm + kw loop + kw match + kw mod + kw return + kw self:: + kw static + kw struct + kw trait + kw true + kw type + kw union + kw unsafe + kw use + kw while + kw while let + sn macro_rules + sn pd + sn ppd + "#]], + ); + check( + r#" +fn foo() { let x = if foo {} $0 else if true {}; } +"#, + expect![[r#" + fn foo fn() + bt u32 u32 + kw async + kw const + kw crate:: + kw else if + kw enum + kw extern + kw false + kw fn + kw for + kw if + kw if let + kw impl + kw impl for + kw let + kw letm + kw loop + kw match + kw mod + kw return + kw self:: + kw static + kw struct + kw trait + kw true + kw type + kw union + kw unsafe + kw use + kw while + kw while let + sn macro_rules + sn pd + sn ppd + "#]], + ); + check( + r#" +fn foo() { let x = if foo {} el$0 else if true {} else {}; } +"#, + expect![[r#" + fn foo() fn() + lc x () + bt u32 u32 + kw async + kw const + kw crate:: + kw else if + kw enum + kw extern + kw false + kw fn + kw for + kw if + kw if let + kw impl + kw impl for + kw let + kw letm + kw loop + kw match + kw mod + kw return + kw self:: + kw static + kw struct + kw trait + kw true + kw type + kw union + kw unsafe + kw use + kw while + kw while let + sn macro_rules + sn pd + sn ppd + "#]], + ); + check( + r#" +fn foo() { let x = if foo {} $0 else if true {} else {}; } +"#, + expect![[r#" + fn foo fn() + bt u32 u32 + kw async + kw const + kw crate:: kw else if kw enum kw extern