Unnamed repository; edit this file 'description' to name the repository.
Auto merge of #18005 - rami3l:fix/for-completion-in-impl, r=Veykril
fix(ide-completion): fix handling of `for` in `impl T for A` in function body Closes #17787.
bors 2024-08-30
parent 13ac53e · parent 0b28126 · commit 2890b10
-rw-r--r--crates/ide-completion/src/completions/keyword.rs62
-rw-r--r--crates/ide-completion/src/context/analysis.rs24
2 files changed, 81 insertions, 5 deletions
diff --git a/crates/ide-completion/src/completions/keyword.rs b/crates/ide-completion/src/completions/keyword.rs
index 3f50cd55cb..0acb87872f 100644
--- a/crates/ide-completion/src/completions/keyword.rs
+++ b/crates/ide-completion/src/completions/keyword.rs
@@ -151,6 +151,68 @@ fn foo(a: A) { a.$0 }
}
#[test]
+ fn for_in_impl() {
+ check_edit(
+ "for",
+ r#"
+struct X;
+impl X $0 {}
+"#,
+ r#"
+struct X;
+impl X for $0 {}
+"#,
+ );
+ check_edit(
+ "for",
+ r#"
+fn foo() {
+ struct X;
+ impl X $0 {}
+}
+"#,
+ r#"
+fn foo() {
+ struct X;
+ impl X for $0 {}
+}
+"#,
+ );
+ check_edit(
+ "for",
+ r#"
+fn foo() {
+ struct X;
+ impl X $0
+}
+"#,
+ r#"
+fn foo() {
+ struct X;
+ impl X for $0
+}
+"#,
+ );
+ check_edit(
+ "for",
+ r#"
+fn foo() {
+ struct X;
+ impl X { fn bar() { $0 } }
+}
+"#,
+ r#"
+fn foo() {
+ struct X;
+ impl X { fn bar() { for $1 in $2 {
+ $0
+} } }
+}
+"#,
+ );
+ }
+
+ #[test]
fn let_semi() {
cov_mark::check!(let_semi);
check_edit(
diff --git a/crates/ide-completion/src/context/analysis.rs b/crates/ide-completion/src/context/analysis.rs
index ed359394f1..292c419498 100644
--- a/crates/ide-completion/src/context/analysis.rs
+++ b/crates/ide-completion/src/context/analysis.rs
@@ -1132,10 +1132,18 @@ fn classify_name_ref(
ast::PathType(it) => make_path_kind_type(it.into()),
ast::PathExpr(it) => {
if let Some(p) = it.syntax().parent() {
- if ast::ExprStmt::can_cast(p.kind()) {
- if let Some(kind) = inbetween_body_and_decl_check(p) {
- return Some(make_res(NameRefKind::Keyword(kind)));
- }
+ let p_kind = p.kind();
+ // The syntax node of interest, for which we want to check whether
+ // it is sandwiched between an item decl signature and its body.
+ let probe = if ast::ExprStmt::can_cast(p_kind) {
+ Some(p)
+ } else if ast::StmtList::can_cast(p_kind) {
+ Some(it.syntax().clone())
+ } else {
+ None
+ };
+ if let Some(kind) = probe.and_then(inbetween_body_and_decl_check) {
+ return Some(make_res(NameRefKind::Keyword(kind)));
}
}
@@ -1199,7 +1207,13 @@ fn classify_name_ref(
}
}
},
- ast::RecordExpr(it) => make_path_kind_expr(it.into()),
+ ast::RecordExpr(it) => {
+ // A record expression in this position is usually a result of parsing recovery, so check that
+ if let Some(kind) = inbetween_body_and_decl_check(it.syntax().clone()) {
+ return Some(make_res(NameRefKind::Keyword(kind)));
+ }
+ make_path_kind_expr(it.into())
+ },
_ => return None,
}
};