aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ide_completion/src/completions/keyword.rs2
-rw-r--r--crates/ide_completion/src/patterns.rs193
2 files changed, 109 insertions, 86 deletions
diff --git a/crates/ide_completion/src/completions/keyword.rs b/crates/ide_completion/src/completions/keyword.rs
index 06789b704..e71a04b6e 100644
--- a/crates/ide_completion/src/completions/keyword.rs
+++ b/crates/ide_completion/src/completions/keyword.rs
@@ -39,8 +39,6 @@ pub(crate) fn complete_use_tree_keyword(acc: &mut Completions, ctx: &CompletionC
39 } 39 }
40} 40}
41 41
42trait Foo {}
43
44pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionContext) { 42pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionContext) {
45 if ctx.token.kind() == SyntaxKind::COMMENT { 43 if ctx.token.kind() == SyntaxKind::COMMENT {
46 cov_mark::hit!(no_keyword_completion_in_comments); 44 cov_mark::hit!(no_keyword_completion_in_comments);
diff --git a/crates/ide_completion/src/patterns.rs b/crates/ide_completion/src/patterns.rs
index 8c4bdbed2..caf0ef39f 100644
--- a/crates/ide_completion/src/patterns.rs
+++ b/crates/ide_completion/src/patterns.rs
@@ -52,7 +52,7 @@ pub(crate) fn determine_prev_sibling(name_like: &ast::NameLike) -> Option<Immedi
52 let res = match_ast! { 52 let res = match_ast! {
53 match prev_sibling { 53 match prev_sibling {
54 ast::ExprStmt(it) => { 54 ast::ExprStmt(it) => {
55 let node = it.expr()?.syntax().clone(); 55 let node = it.expr().filter(|_| it.semicolon_token().is_none())?.syntax().clone();
56 match_ast! { 56 match_ast! {
57 match node { 57 match node {
58 ast::IfExpr(_it) => ImmediatePrevSibling::IfExpr, 58 ast::IfExpr(_it) => ImmediatePrevSibling::IfExpr,
@@ -149,59 +149,6 @@ fn maximize_name_ref(name_like: &ast::NameLike) -> Option<SyntaxNode> {
149 Some(node) 149 Some(node)
150} 150}
151 151
152#[cfg(test)]
153fn check_location(code: &str, loc: ImmediateLocation) {
154 check_pattern_is_applicable(code, |e| {
155 let name = &e.parent().and_then(ast::NameLike::cast).expect("Expected a namelike");
156 assert_eq!(determine_location(name), Some(loc));
157 true
158 });
159}
160
161#[test]
162fn test_has_trait_parent() {
163 check_location(r"trait A { f$0 }", ImmediateLocation::Trait);
164}
165
166#[test]
167fn test_has_use_parent() {
168 check_location(r"use f$0", ImmediateLocation::Use);
169}
170
171#[test]
172fn test_has_impl_parent() {
173 check_location(r"impl A { f$0 }", ImmediateLocation::Impl);
174}
175#[test]
176fn test_has_field_list_parent() {
177 check_location(r"struct Foo { f$0 }", ImmediateLocation::RecordField);
178 check_location(r"struct Foo { f$0 pub f: i32}", ImmediateLocation::RecordField);
179}
180
181#[test]
182fn test_has_block_expr_parent() {
183 check_location(r"fn my_fn() { let a = 2; f$0 }", ImmediateLocation::BlockExpr);
184}
185
186#[test]
187fn test_has_ident_pat_parent() {
188 check_location(r"fn my_fn(m$0) {}", ImmediateLocation::IdentPat);
189 check_location(r"fn my_fn() { let m$0 }", ImmediateLocation::IdentPat);
190 check_location(r"fn my_fn(&m$0) {}", ImmediateLocation::IdentPat);
191 check_location(r"fn my_fn() { let &m$0 }", ImmediateLocation::IdentPat);
192}
193
194#[test]
195fn test_has_ref_expr_parent() {
196 check_location(r"fn my_fn() { let x = &m$0 foo; }", ImmediateLocation::RefExpr);
197}
198
199#[test]
200fn test_has_item_list_or_source_file_parent() {
201 check_location(r"i$0", ImmediateLocation::ItemList);
202 check_location(r"mod foo { f$0 }", ImmediateLocation::ItemList);
203}
204
205pub(crate) fn inside_impl_trait_block(element: SyntaxElement) -> bool { 152pub(crate) fn inside_impl_trait_block(element: SyntaxElement) -> bool {
206 // Here we search `impl` keyword up through the all ancestors, unlike in `has_impl_parent`, 153 // Here we search `impl` keyword up through the all ancestors, unlike in `has_impl_parent`,
207 // where we only check the first parent with different text range. 154 // where we only check the first parent with different text range.
@@ -251,36 +198,6 @@ fn test_for_is_prev2() {
251 check_pattern_is_applicable(r"for i i$0", for_is_prev2); 198 check_pattern_is_applicable(r"for i i$0", for_is_prev2);
252} 199}
253 200
254#[cfg(test)]
255fn check_prev_sibling(code: &str, sibling: impl Into<Option<ImmediatePrevSibling>>) {
256 check_pattern_is_applicable(code, |e| {
257 let name = &e.parent().and_then(ast::NameLike::cast).expect("Expected a namelike");
258 assert_eq!(determine_prev_sibling(name), sibling.into());
259 true
260 });
261}
262
263#[test]
264fn test_has_impl_as_prev_sibling() {
265 check_prev_sibling(r"impl A w$0 ", ImmediatePrevSibling::ImplDefType);
266 check_prev_sibling(r"impl A w$0 {}", ImmediatePrevSibling::ImplDefType);
267 check_prev_sibling(r"impl A for A w$0 ", ImmediatePrevSibling::ImplDefType);
268 check_prev_sibling(r"impl A for A w$0 {}", ImmediatePrevSibling::ImplDefType);
269 check_prev_sibling(r"impl A for w$0 {}", None);
270 check_prev_sibling(r"impl A for w$0", None);
271}
272
273#[test]
274fn test_has_trait_as_prev_sibling() {
275 check_prev_sibling(r"trait A w$0 ", ImmediatePrevSibling::TraitDefName);
276 check_prev_sibling(r"trait A w$0 {}", ImmediatePrevSibling::TraitDefName);
277}
278
279#[test]
280fn test_has_if_expr_as_prev_sibling() {
281 check_prev_sibling(r"fn foo() { if true {} w$0", ImmediatePrevSibling::IfExpr);
282}
283
284pub(crate) fn is_in_loop_body(element: SyntaxElement) -> bool { 201pub(crate) fn is_in_loop_body(element: SyntaxElement) -> bool {
285 element 202 element
286 .ancestors() 203 .ancestors()
@@ -329,3 +246,111 @@ fn previous_sibling_or_ancestor_sibling(element: SyntaxElement) -> Option<Syntax
329 non_trivia_sibling(NodeOrToken::Node(prev_sibling_node), Direction::Prev) 246 non_trivia_sibling(NodeOrToken::Node(prev_sibling_node), Direction::Prev)
330 } 247 }
331} 248}
249
250#[cfg(test)]
251mod tests {
252 use super::*;
253
254 fn check_location(code: &str, loc: impl Into<Option<ImmediateLocation>>) {
255 check_pattern_is_applicable(code, |e| {
256 let name = &e.parent().and_then(ast::NameLike::cast).expect("Expected a namelike");
257 assert_eq!(determine_location(name), loc.into());
258 true
259 });
260 }
261
262 fn check_prev_sibling(code: &str, sibling: impl Into<Option<ImmediatePrevSibling>>) {
263 check_pattern_is_applicable(code, |e| {
264 let name = &e.parent().and_then(ast::NameLike::cast).expect("Expected a namelike");
265 assert_eq!(determine_prev_sibling(name), sibling.into());
266 true
267 });
268 }
269
270 #[test]
271 fn test_trait_loc() {
272 check_location(r"trait A { f$0 }", ImmediateLocation::Trait);
273 check_location(r"trait A { #[attr] f$0 }", ImmediateLocation::Trait);
274 check_location(r"trait A { f$0 fn f() {} }", ImmediateLocation::Trait);
275 check_location(r"trait A { fn f() {} f$0 }", ImmediateLocation::Trait);
276 check_location(r"trait A$0 {}", None);
277 check_location(r"trait A { fn f$0 }", None);
278 }
279
280 #[test]
281 fn test_impl_loc() {
282 check_location(r"impl A { f$0 }", ImmediateLocation::Impl);
283 check_location(r"impl A { #[attr] f$0 }", ImmediateLocation::Impl);
284 check_location(r"impl A { f$0 fn f() {} }", ImmediateLocation::Impl);
285 check_location(r"impl A { fn f() {} f$0 }", ImmediateLocation::Impl);
286 check_location(r"impl A$0 {}", None);
287 check_location(r"impl A { fn f$0 }", None);
288 }
289
290 #[test]
291 fn test_use_loc() {
292 check_location(r"use f$0", ImmediateLocation::Use);
293 check_location(r"use f$0;", ImmediateLocation::Use);
294 check_location(r"use f::{f$0}", None);
295 check_location(r"use {f$0}", None);
296 }
297
298 #[test]
299 fn test_record_field_loc() {
300 check_location(r"struct Foo { f$0 }", ImmediateLocation::RecordField);
301 check_location(r"struct Foo { f$0 pub f: i32}", ImmediateLocation::RecordField);
302 check_location(r"struct Foo { pub f: i32, f$0 }", ImmediateLocation::RecordField);
303 }
304
305 #[test]
306 fn test_block_expr_loc() {
307 check_location(r"fn my_fn() { let a = 2; f$0 }", ImmediateLocation::BlockExpr);
308 check_location(r"fn my_fn() { f$0 f }", ImmediateLocation::BlockExpr);
309 }
310
311 #[test]
312 fn test_ident_pat_loc() {
313 check_location(r"fn my_fn(m$0) {}", ImmediateLocation::IdentPat);
314 check_location(r"fn my_fn() { let m$0 }", ImmediateLocation::IdentPat);
315 check_location(r"fn my_fn(&m$0) {}", ImmediateLocation::IdentPat);
316 check_location(r"fn my_fn() { let &m$0 }", ImmediateLocation::IdentPat);
317 }
318
319 #[test]
320 fn test_ref_expr_loc() {
321 check_location(r"fn my_fn() { let x = &m$0 foo; }", ImmediateLocation::RefExpr);
322 }
323
324 #[test]
325 fn test_item_list_loc() {
326 check_location(r"i$0", ImmediateLocation::ItemList);
327 check_location(r"#[attr] i$0", ImmediateLocation::ItemList);
328 check_location(r"fn f() {} i$0", ImmediateLocation::ItemList);
329 check_location(r"mod foo { f$0 }", ImmediateLocation::ItemList);
330 check_location(r"mod foo { #[attr] f$0 }", ImmediateLocation::ItemList);
331 check_location(r"mod foo { fn f() {} f$0 }", ImmediateLocation::ItemList);
332 check_location(r"mod foo$0 {}", None);
333 }
334
335 #[test]
336 fn test_impl_prev_sibling() {
337 check_prev_sibling(r"impl A w$0 ", ImmediatePrevSibling::ImplDefType);
338 check_prev_sibling(r"impl A w$0 {}", ImmediatePrevSibling::ImplDefType);
339 check_prev_sibling(r"impl A for A w$0 ", ImmediatePrevSibling::ImplDefType);
340 check_prev_sibling(r"impl A for A w$0 {}", ImmediatePrevSibling::ImplDefType);
341 check_prev_sibling(r"impl A for w$0 {}", None);
342 check_prev_sibling(r"impl A for w$0", None);
343 }
344
345 #[test]
346 fn test_trait_prev_sibling() {
347 check_prev_sibling(r"trait A w$0 ", ImmediatePrevSibling::TraitDefName);
348 check_prev_sibling(r"trait A w$0 {}", ImmediatePrevSibling::TraitDefName);
349 }
350
351 #[test]
352 fn test_if_expr_prev_sibling() {
353 check_prev_sibling(r"fn foo() { if true {} w$0", ImmediatePrevSibling::IfExpr);
354 check_prev_sibling(r"fn foo() { if true {}; w$0", None);
355 }
356}