From d42c81e8d1c847d9006f104fac8d3548533e1d93 Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Fri, 12 Sep 2025 20:07:07 +0800 Subject: [PATCH] Fix extra semicolon before else in let-stmt Example --- ```rust fn main() { let x = if true { () } $0 else {}; } ``` **Before this PR**: ```rust fn main() { let x = if true { () } else if $1 { $0 }; else {}; } ``` **After this PR**: ```rust fn main() { let x = if true { () } else if $1 { $0 } else {}; } ``` --- .../ide-completion/src/completions/keyword.rs | 40 +++++++++++++++++++ crates/ide-completion/src/context/analysis.rs | 12 +++++- 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/crates/ide-completion/src/completions/keyword.rs b/crates/ide-completion/src/completions/keyword.rs index b3d770997a..6162d98372 100644 --- a/crates/ide-completion/src/completions/keyword.rs +++ b/crates/ide-completion/src/completions/keyword.rs @@ -269,6 +269,46 @@ fn main() { "#, ); + check_edit( + "else if", + r#" +fn main() { + let x = if true { + () + } $0 else {}; +} +"#, + r#" +fn main() { + let x = if true { + () + } else if $1 { + $0 +} else {}; +} +"#, + ); + + check_edit( + "else if", + r#" +fn main() { + let x = if true { + () + } $0 else if true {}; +} +"#, + r#" +fn main() { + let x = if true { + () + } else if $1 { + $0 +} else if true {}; +} +"#, + ); + check_edit( "else", r#" diff --git a/crates/ide-completion/src/context/analysis.rs b/crates/ide-completion/src/context/analysis.rs index 33b98a33ca..b33a547dee 100644 --- a/crates/ide-completion/src/context/analysis.rs +++ b/crates/ide-completion/src/context/analysis.rs @@ -970,6 +970,16 @@ fn classify_name_ref<'db>( let after_incomplete_let = |node: SyntaxNode| { prev_expr(node).and_then(|it| it.syntax().parent()).and_then(ast::LetStmt::cast) }; + let before_else_kw = |node: &SyntaxNode| { + node.parent() + .and_then(ast::ExprStmt::cast) + .filter(|stmt| stmt.semicolon_token().is_none()) + .and_then(|stmt| non_trivia_sibling(stmt.syntax().clone().into(), Direction::Next)) + .and_then(NodeOrToken::into_node) + .filter(|next| next.kind() == SyntaxKind::ERROR) + .and_then(|next| next.first_token()) + .is_some_and(|token| token.kind() == SyntaxKind::ELSE_KW) + }; // We do not want to generate path completions when we are sandwiched between an item decl signature and its body. // ex. trait Foo $0 {} @@ -1276,7 +1286,7 @@ fn classify_name_ref<'db>( .parent() .and_then(ast::LetStmt::cast) .is_some_and(|it| it.semicolon_token().is_none()) - || after_incomplete_let && incomplete_expr_stmt.unwrap_or(true); + || after_incomplete_let && incomplete_expr_stmt.unwrap_or(true) && !before_else_kw(it); let in_value = it.parent().and_then(Either::::cast).is_some(); let impl_ = fetch_immediate_impl(sema, original_file, expr.syntax());