Unnamed repository; edit this file 'description' to name the repository.
Add heuristic sensing `is_in_block`
Example --- ```rust fn foo() -> [i32; 2] { l$0 [0, n] } ``` **Before this PR**: ```text loop~ line!(…)~ macro_rules! line ``` **After this PR**: ```text let~ loop~ letm~ line!(…)~ macro_rules! line ```
A4-Tacks 6 months ago
parent 57875bd · commit 4c14c52
-rw-r--r--crates/ide-completion/src/context/analysis.rs26
-rw-r--r--crates/ide-completion/src/tests/expression.rs167
2 files changed, 193 insertions, 0 deletions
diff --git a/crates/ide-completion/src/context/analysis.rs b/crates/ide-completion/src/context/analysis.rs
index 873eceff5f..f0a03dedfe 100644
--- a/crates/ide-completion/src/context/analysis.rs
+++ b/crates/ide-completion/src/context/analysis.rs
@@ -1890,11 +1890,37 @@ fn is_in_breakable(node: &SyntaxNode) -> Option<(BreakableKind, SyntaxNode)> {
}
fn is_in_block(node: &SyntaxNode) -> bool {
+ if has_in_newline_expr_first(node) {
+ return true;
+ };
node.parent()
.map(|node| ast::ExprStmt::can_cast(node.kind()) || ast::StmtList::can_cast(node.kind()))
.unwrap_or(false)
}
+/// Similar to `has_parens`, heuristic sensing incomplete statement before ambigiguous `Expr`
+///
+/// Heuristic:
+///
+/// If the `PathExpr` is left part of the `Expr` and there is a newline after the `PathExpr`,
+/// it is considered that the `PathExpr` is not part of the `Expr`.
+fn has_in_newline_expr_first(node: &SyntaxNode) -> bool {
+ if ast::PathExpr::can_cast(node.kind())
+ && let Some(NodeOrToken::Token(next)) = node.next_sibling_or_token()
+ && next.kind() == SyntaxKind::WHITESPACE
+ && next.text().contains('\n')
+ && let Some(stmt_like) = node
+ .ancestors()
+ .take_while(|it| it.text_range().start() == node.text_range().start())
+ .filter_map(Either::<ast::ExprStmt, ast::Expr>::cast)
+ .last()
+ {
+ stmt_like.syntax().parent().and_then(ast::StmtList::cast).is_some()
+ } else {
+ false
+ }
+}
+
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 5363a68af7..f75fa7943b 100644
--- a/crates/ide-completion/src/tests/expression.rs
+++ b/crates/ide-completion/src/tests/expression.rs
@@ -2947,6 +2947,173 @@ fn let_in_let_chain() {
}
#[test]
+fn let_in_previous_line_of_ambiguous_expr() {
+ check_edit(
+ "let",
+ r#"
+ fn f() {
+ $0
+ (1, 2).foo();
+ }"#,
+ r#"
+ fn f() {
+ let $1 = $0;
+ (1, 2).foo();
+ }"#,
+ );
+
+ check_edit(
+ "let",
+ r#"
+ fn f() {
+ $0
+ (1, 2)
+ }"#,
+ r#"
+ fn f() {
+ let $1 = $0;
+ (1, 2)
+ }"#,
+ );
+
+ check_edit(
+ "let",
+ r#"
+ fn f() -> i32 {
+ $0
+ -2
+ }"#,
+ r#"
+ fn f() -> i32 {
+ let $1 = $0;
+ -2
+ }"#,
+ );
+
+ check_edit(
+ "let",
+ r#"
+ fn f() -> [i32; 2] {
+ $0
+ [1, 2]
+ }"#,
+ r#"
+ fn f() -> [i32; 2] {
+ let $1 = $0;
+ [1, 2]
+ }"#,
+ );
+
+ check_edit(
+ "let",
+ r#"
+ fn f() -> [u8; 2] {
+ $0
+ *b"01"
+ }"#,
+ r#"
+ fn f() -> [u8; 2] {
+ let $1 = $0;
+ *b"01"
+ }"#,
+ );
+
+ check(
+ r#"
+ fn foo() {
+ $0
+ *b"01"
+ }"#,
+ expect![[r#"
+ fn foo() fn()
+ bt u32 u32
+ kw async
+ kw const
+ kw crate::
+ 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 $0 {}
+ }"#,
+ expect![[r#"
+ fn foo() fn()
+ bt u32 u32
+ kw const
+ kw crate::
+ kw false
+ kw for
+ kw if
+ kw if let
+ kw loop
+ kw match
+ kw return
+ kw self::
+ kw true
+ kw unsafe
+ kw while
+ kw while let
+ "#]],
+ );
+
+ check(
+ r#"
+ fn foo() {
+ $0 *b"01"
+ }"#,
+ expect![[r#"
+ fn foo() fn()
+ bt u32 u32
+ kw const
+ kw crate::
+ kw false
+ kw for
+ kw if
+ kw if let
+ kw loop
+ kw match
+ kw return
+ kw self::
+ kw true
+ kw unsafe
+ kw while
+ kw while let
+ "#]],
+ );
+}
+
+#[test]
fn private_inherent_and_public_trait() {
check(
r#"