Skip to content

Commit 27979ad

Browse files
committed
Auto merge of rust-lang#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 rust-lang#17787.
2 parents e77de38 + 9afdc3a commit 27979ad

File tree

2 files changed

+81
-5
lines changed

2 files changed

+81
-5
lines changed

src/tools/rust-analyzer/crates/ide-completion/src/completions/keyword.rs

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,68 @@ fn foo(a: A) { a.$0 }
150150
);
151151
}
152152

153+
#[test]
154+
fn for_in_impl() {
155+
check_edit(
156+
"for",
157+
r#"
158+
struct X;
159+
impl X $0 {}
160+
"#,
161+
r#"
162+
struct X;
163+
impl X for $0 {}
164+
"#,
165+
);
166+
check_edit(
167+
"for",
168+
r#"
169+
fn foo() {
170+
struct X;
171+
impl X $0 {}
172+
}
173+
"#,
174+
r#"
175+
fn foo() {
176+
struct X;
177+
impl X for $0 {}
178+
}
179+
"#,
180+
);
181+
check_edit(
182+
"for",
183+
r#"
184+
fn foo() {
185+
struct X;
186+
impl X $0
187+
}
188+
"#,
189+
r#"
190+
fn foo() {
191+
struct X;
192+
impl X for $0
193+
}
194+
"#,
195+
);
196+
check_edit(
197+
"for",
198+
r#"
199+
fn foo() {
200+
struct X;
201+
impl X { fn bar() { $0 } }
202+
}
203+
"#,
204+
r#"
205+
fn foo() {
206+
struct X;
207+
impl X { fn bar() { for $1 in $2 {
208+
$0
209+
} } }
210+
}
211+
"#,
212+
);
213+
}
214+
153215
#[test]
154216
fn let_semi() {
155217
cov_mark::check!(let_semi);

src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1132,10 +1132,18 @@ fn classify_name_ref(
11321132
ast::PathType(it) => make_path_kind_type(it.into()),
11331133
ast::PathExpr(it) => {
11341134
if let Some(p) = it.syntax().parent() {
1135-
if ast::ExprStmt::can_cast(p.kind()) {
1136-
if let Some(kind) = inbetween_body_and_decl_check(p) {
1137-
return Some(make_res(NameRefKind::Keyword(kind)));
1138-
}
1135+
let p_kind = p.kind();
1136+
// The syntax node of interest, for which we want to check whether
1137+
// it is sandwiched between an item decl signature and its body.
1138+
let probe = if ast::ExprStmt::can_cast(p_kind) {
1139+
Some(p)
1140+
} else if ast::StmtList::can_cast(p_kind) {
1141+
Some(it.syntax().clone())
1142+
} else {
1143+
None
1144+
};
1145+
if let Some(kind) = probe.and_then(inbetween_body_and_decl_check) {
1146+
return Some(make_res(NameRefKind::Keyword(kind)));
11391147
}
11401148
}
11411149

@@ -1199,7 +1207,13 @@ fn classify_name_ref(
11991207
}
12001208
}
12011209
},
1202-
ast::RecordExpr(it) => make_path_kind_expr(it.into()),
1210+
ast::RecordExpr(it) => {
1211+
// A record expression in this position is usually a result of parsing recovery, so check that
1212+
if let Some(kind) = inbetween_body_and_decl_check(it.syntax().clone()) {
1213+
return Some(make_res(NameRefKind::Keyword(kind)));
1214+
}
1215+
make_path_kind_expr(it.into())
1216+
},
12031217
_ => return None,
12041218
}
12051219
};

0 commit comments

Comments
 (0)