diff options
author | Lukas Wirth <[email protected]> | 2021-05-28 21:18:52 +0100 |
---|---|---|
committer | Lukas Wirth <[email protected]> | 2021-05-28 21:19:52 +0100 |
commit | e42c448077ca2b7675320da3c5294bf4bebaedeb (patch) | |
tree | e6d76df5212db7589ef8dc6583b32d6c64871a33 /crates/ide_completion | |
parent | 47ad752e6cca5eb5499168ec7f859879e384a5ab (diff) |
More completion pattern tests
Diffstat (limited to 'crates/ide_completion')
-rw-r--r-- | crates/ide_completion/src/completions/keyword.rs | 2 | ||||
-rw-r--r-- | crates/ide_completion/src/patterns.rs | 193 |
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 | ||
42 | trait Foo {} | ||
43 | |||
44 | pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionContext) { | 42 | pub(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)] | ||
153 | fn 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] | ||
162 | fn test_has_trait_parent() { | ||
163 | check_location(r"trait A { f$0 }", ImmediateLocation::Trait); | ||
164 | } | ||
165 | |||
166 | #[test] | ||
167 | fn test_has_use_parent() { | ||
168 | check_location(r"use f$0", ImmediateLocation::Use); | ||
169 | } | ||
170 | |||
171 | #[test] | ||
172 | fn test_has_impl_parent() { | ||
173 | check_location(r"impl A { f$0 }", ImmediateLocation::Impl); | ||
174 | } | ||
175 | #[test] | ||
176 | fn 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] | ||
182 | fn test_has_block_expr_parent() { | ||
183 | check_location(r"fn my_fn() { let a = 2; f$0 }", ImmediateLocation::BlockExpr); | ||
184 | } | ||
185 | |||
186 | #[test] | ||
187 | fn 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] | ||
195 | fn test_has_ref_expr_parent() { | ||
196 | check_location(r"fn my_fn() { let x = &m$0 foo; }", ImmediateLocation::RefExpr); | ||
197 | } | ||
198 | |||
199 | #[test] | ||
200 | fn 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 | |||
205 | pub(crate) fn inside_impl_trait_block(element: SyntaxElement) -> bool { | 152 | pub(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)] | ||
255 | fn 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] | ||
264 | fn 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] | ||
274 | fn 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] | ||
280 | fn test_has_if_expr_as_prev_sibling() { | ||
281 | check_prev_sibling(r"fn foo() { if true {} w$0", ImmediatePrevSibling::IfExpr); | ||
282 | } | ||
283 | |||
284 | pub(crate) fn is_in_loop_body(element: SyntaxElement) -> bool { | 201 | pub(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)] | ||
251 | mod 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 | } | ||