Unnamed repository; edit this file 'description' to name the repository.
Merge pull request #20658 from A4-Tacks/more-expr-else-after-if
Fix else completion for more expressions
Shoyu Vanilla (Flint) 6 months ago
parent 5844df0 · parent b96babe · commit 30cd10a
-rw-r--r--crates/ide-completion/src/completions/pattern.rs5
-rw-r--r--crates/ide-completion/src/context.rs1
-rw-r--r--crates/ide-completion/src/context/analysis.rs19
-rw-r--r--crates/ide-completion/src/tests/expression.rs292
4 files changed, 312 insertions, 5 deletions
diff --git a/crates/ide-completion/src/completions/pattern.rs b/crates/ide-completion/src/completions/pattern.rs
index 0ce81d02b4..dcddc24890 100644
--- a/crates/ide-completion/src/completions/pattern.rs
+++ b/crates/ide-completion/src/completions/pattern.rs
@@ -42,6 +42,11 @@ pub(crate) fn complete_pattern(
}
}
+ if pattern_ctx.after_if_expr {
+ add_keyword("else", "else {\n $0\n}");
+ add_keyword("else if", "else if $1 {\n $0\n}");
+ }
+
if pattern_ctx.record_pat.is_some() {
return;
}
diff --git a/crates/ide-completion/src/context.rs b/crates/ide-completion/src/context.rs
index 91f19f6b43..2f166b7184 100644
--- a/crates/ide-completion/src/context.rs
+++ b/crates/ide-completion/src/context.rs
@@ -279,6 +279,7 @@ pub(crate) struct PatternContext {
pub(crate) param_ctx: Option<ParamContext>,
pub(crate) has_type_ascription: bool,
pub(crate) should_suggest_name: bool,
+ pub(crate) after_if_expr: bool,
pub(crate) parent_pat: Option<ast::Pat>,
pub(crate) ref_token: Option<SyntaxToken>,
pub(crate) mut_token: Option<SyntaxToken>,
diff --git a/crates/ide-completion/src/context/analysis.rs b/crates/ide-completion/src/context/analysis.rs
index d39bff1577..42772ef2d0 100644
--- a/crates/ide-completion/src/context/analysis.rs
+++ b/crates/ide-completion/src/context/analysis.rs
@@ -999,10 +999,6 @@ fn classify_name_ref<'db>(
}
}
};
- let after_if_expr = |node: SyntaxNode| {
- let prev_expr = prev_expr(node);
- matches!(prev_expr, Some(ast::Expr::IfExpr(_)))
- };
let after_incomplete_let = |node: SyntaxNode| {
prev_expr(node).and_then(|it| it.syntax().parent()).and_then(ast::LetStmt::cast)
};
@@ -1242,7 +1238,7 @@ fn classify_name_ref<'db>(
let it = expr.syntax();
let in_block_expr = is_in_block(it);
let (in_loop_body, innermost_breakable) = is_in_breakable(it).unzip();
- let after_if_expr = after_if_expr(it.clone());
+ let after_if_expr = is_after_if_expr(it.clone());
let ref_expr_parent =
path.as_single_name_ref().and_then(|_| it.parent()).and_then(ast::RefExpr::cast);
let after_amp = non_trivia_sibling(it.clone().into(), Direction::Prev)
@@ -1763,6 +1759,7 @@ fn pattern_context_for(
param_ctx,
has_type_ascription,
should_suggest_name,
+ after_if_expr: is_after_if_expr(pat.syntax().clone()),
parent_pat: pat.syntax().parent().and_then(ast::Pat::cast),
mut_token,
ref_token,
@@ -1933,6 +1930,18 @@ fn has_in_newline_expr_first(node: &SyntaxNode) -> bool {
}
}
+fn is_after_if_expr(node: SyntaxNode) -> bool {
+ let node = match node.parent().and_then(Either::<ast::ExprStmt, ast::MatchArm>::cast) {
+ Some(stmt) => stmt.syntax().clone(),
+ None => node,
+ };
+ let prev_sibling =
+ non_trivia_sibling(node.into(), Direction::Prev).and_then(NodeOrToken::into_node);
+ iter::successors(prev_sibling, |it| it.last_child_or_token()?.into_node())
+ .find_map(ast::IfExpr::cast)
+ .is_some()
+}
+
fn next_non_trivia_token(e: impl Into<SyntaxElement>) -> Option<SyntaxToken> {
let mut token = match e.into() {
SyntaxElement::Node(n) => n.last_token()?,
diff --git a/crates/ide-completion/src/tests/expression.rs b/crates/ide-completion/src/tests/expression.rs
index 09af635f01..67c84f42c1 100644
--- a/crates/ide-completion/src/tests/expression.rs
+++ b/crates/ide-completion/src/tests/expression.rs
@@ -1869,6 +1869,298 @@ fn foo() { let x = if foo {} $0 else if true {} else {}; }
sn ppd
"#]],
);
+ check(
+ r#"
+fn foo() { [if foo {} $0]}
+"#,
+ expect![[r#"
+ fn foo() fn()
+ bt u32 u32
+ 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() { [if foo {} el$0]}
+"#,
+ expect![[r#"
+ fn foo() fn()
+ bt u32 u32
+ 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() { 2 + if foo {} $0 }
+"#,
+ expect![[r#"
+ fn foo() fn()
+ bt u32 u32
+ 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() { -if foo {} $0 }
+"#,
+ expect![[r#"
+ fn foo() fn()
+ bt u32 u32
+ 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() { &mut if foo {} $0 }
+"#,
+ expect![[r#"
+ fn foo() fn()
+ bt u32 u32
+ 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() { return if foo {} $0 }
+"#,
+ expect![[r#"
+ fn foo() fn()
+ bt u32 u32
+ 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() { match () { () => if foo {} $0 } }
+"#,
+ expect![[r#"
+ kw else
+ kw else if
+ kw mut
+ kw ref
+ "#]],
+ );
+ check(
+ r#"
+fn foo() { match () { () => if foo {} $0, } }
+"#,
+ expect![[r#"
+ kw else
+ kw else if
+ kw mut
+ kw ref
+ "#]],
+ );
+ check(
+ r#"
+fn foo() { match () { () => if foo {} $0, _ => (), } }
+"#,
+ expect![[r#"
+ kw else
+ kw else if
+ kw mut
+ kw ref
+ "#]],
+ );
+ // FIXME: support else completion after ast::RecordExprField
}
#[test]