Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--crates/ide-completion/src/completions/keyword.rs140
-rw-r--r--crates/ide-completion/src/context/analysis.rs21
2 files changed, 160 insertions, 1 deletions
diff --git a/crates/ide-completion/src/completions/keyword.rs b/crates/ide-completion/src/completions/keyword.rs
index 6162d98372..eab2b9063f 100644
--- a/crates/ide-completion/src/completions/keyword.rs
+++ b/crates/ide-completion/src/completions/keyword.rs
@@ -532,6 +532,146 @@ fn main() {
}
#[test]
+ fn if_completion_in_format() {
+ check_edit(
+ "if",
+ r#"
+//- minicore: fmt
+fn main() {
+ format_args!("{}", $0);
+}
+"#,
+ r#"
+fn main() {
+ format_args!("{}", if $1 {
+ $2
+} else {
+ $0
+});
+}
+"#,
+ );
+
+ check_edit(
+ "if",
+ r#"
+//- minicore: fmt
+fn main() {
+ format_args!("{}", if$0);
+}
+"#,
+ r#"
+fn main() {
+ format_args!("{}", if $1 {
+ $2
+} else {
+ $0
+});
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn if_completion_in_value_expected_expressions() {
+ check_edit(
+ "if",
+ r#"
+fn main() {
+ 2 + $0;
+}
+"#,
+ r#"
+fn main() {
+ 2 + if $1 {
+ $2
+} else {
+ $0
+};
+}
+"#,
+ );
+
+ check_edit(
+ "if",
+ r#"
+fn main() {
+ -$0;
+}
+"#,
+ r#"
+fn main() {
+ -if $1 {
+ $2
+} else {
+ $0
+};
+}
+"#,
+ );
+
+ check_edit(
+ "if",
+ r#"
+fn main() {
+ return $0;
+}
+"#,
+ r#"
+fn main() {
+ return if $1 {
+ $2
+} else {
+ $0
+};
+}
+"#,
+ );
+
+ check_edit(
+ "if",
+ r#"
+fn main() {
+ loop {
+ break $0;
+ }
+}
+"#,
+ r#"
+fn main() {
+ loop {
+ break if $1 {
+ $2
+} else {
+ $0
+};
+ }
+}
+"#,
+ );
+
+ check_edit(
+ "if",
+ r#"
+struct Foo { x: i32 }
+fn main() {
+ Foo { x: $0 }
+}
+"#,
+ r#"
+struct Foo { x: i32 }
+fn main() {
+ Foo { x: if $1 {
+ $2
+} else {
+ $0
+} }
+}
+"#,
+ );
+ }
+
+ #[test]
fn completes_let_in_block() {
check_edit(
"let",
diff --git a/crates/ide-completion/src/context/analysis.rs b/crates/ide-completion/src/context/analysis.rs
index b3d9ff0046..d6d3978385 100644
--- a/crates/ide-completion/src/context/analysis.rs
+++ b/crates/ide-completion/src/context/analysis.rs
@@ -1012,6 +1012,25 @@ fn classify_name_ref<'db>(
.and_then(|next| next.first_token())
.is_some_and(|token| token.kind() == SyntaxKind::ELSE_KW)
};
+ let is_in_value = |it: &SyntaxNode| {
+ let Some(node) = it.parent() else { return false };
+ let kind = node.kind();
+ ast::LetStmt::can_cast(kind)
+ || ast::ArgList::can_cast(kind)
+ || ast::ArrayExpr::can_cast(kind)
+ || ast::ParenExpr::can_cast(kind)
+ || ast::BreakExpr::can_cast(kind)
+ || ast::ReturnExpr::can_cast(kind)
+ || ast::PrefixExpr::can_cast(kind)
+ || ast::FormatArgsArg::can_cast(kind)
+ || ast::RecordExprField::can_cast(kind)
+ || ast::BinExpr::cast(node.clone())
+ .and_then(|expr| expr.rhs())
+ .is_some_and(|expr| expr.syntax() == it)
+ || ast::IndexExpr::cast(node)
+ .and_then(|expr| expr.index())
+ .is_some_and(|expr| expr.syntax() == it)
+ };
// We do not want to generate path completions when we are sandwiched between an item decl signature and its body.
// ex. trait Foo $0 {}
@@ -1307,7 +1326,7 @@ fn classify_name_ref<'db>(
.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;
- let in_value = it.parent().and_then(Either::<ast::LetStmt, ast::ArgList>::cast).is_some();
+ let in_value = is_in_value(it);
let impl_ = fetch_immediate_impl_or_trait(sema, original_file, expr.syntax())
.and_then(Either::left);