diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2021-06-17 13:01:43 +0100 |
---|---|---|
committer | GitHub <[email protected]> | 2021-06-17 13:01:43 +0100 |
commit | c82a9141abe6b6cbf5b55710dc8a315a3839081b (patch) | |
tree | 1d130833fa51a6fd46e3ff61f3f68155e546c535 /crates/ide_completion | |
parent | 3b58d8f785917b4212cd917fced6c3006210e4d3 (diff) | |
parent | 9353f36516e5b4026ce3a181d578c3a63876a18f (diff) |
Merge #9310
9310: internal: Refine and test UseTree completions r=Veykril a=Veykril
bors r+
Co-authored-by: Lukas Wirth <[email protected]>
Diffstat (limited to 'crates/ide_completion')
-rw-r--r-- | crates/ide_completion/src/completions/flyimport.rs | 2 | ||||
-rw-r--r-- | crates/ide_completion/src/completions/keyword.rs | 64 | ||||
-rw-r--r-- | crates/ide_completion/src/completions/qualified_path.rs | 159 | ||||
-rw-r--r-- | crates/ide_completion/src/completions/unqualified_path.rs | 34 | ||||
-rw-r--r-- | crates/ide_completion/src/context.rs | 28 | ||||
-rw-r--r-- | crates/ide_completion/src/patterns.rs | 7 | ||||
-rw-r--r-- | crates/ide_completion/src/render/builder_ext.rs | 2 | ||||
-rw-r--r-- | crates/ide_completion/src/render/macro_.rs | 2 | ||||
-rw-r--r-- | crates/ide_completion/src/tests.rs | 1 | ||||
-rw-r--r-- | crates/ide_completion/src/tests/use_tree.rs | 255 |
10 files changed, 299 insertions, 255 deletions
diff --git a/crates/ide_completion/src/completions/flyimport.rs b/crates/ide_completion/src/completions/flyimport.rs index 4604feb5d..814c15653 100644 --- a/crates/ide_completion/src/completions/flyimport.rs +++ b/crates/ide_completion/src/completions/flyimport.rs | |||
@@ -109,7 +109,7 @@ pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext) | |||
109 | if !ctx.config.enable_imports_on_the_fly { | 109 | if !ctx.config.enable_imports_on_the_fly { |
110 | return None; | 110 | return None; |
111 | } | 111 | } |
112 | if ctx.use_item_syntax.is_some() | 112 | if ctx.in_use_tree() |
113 | || ctx.is_path_disallowed() | 113 | || ctx.is_path_disallowed() |
114 | || ctx.expects_item() | 114 | || ctx.expects_item() |
115 | || ctx.expects_assoc_item() | 115 | || ctx.expects_assoc_item() |
diff --git a/crates/ide_completion/src/completions/keyword.rs b/crates/ide_completion/src/completions/keyword.rs index 73bbc4345..9754122a0 100644 --- a/crates/ide_completion/src/completions/keyword.rs +++ b/crates/ide_completion/src/completions/keyword.rs | |||
@@ -18,17 +18,24 @@ pub(crate) fn complete_use_tree_keyword(acc: &mut Completions, ctx: &CompletionC | |||
18 | item | 18 | item |
19 | }; | 19 | }; |
20 | 20 | ||
21 | if ctx.use_item_syntax.is_some() { | 21 | if ctx.in_use_tree() { |
22 | let qual = ctx.path_qual(); | 22 | match &ctx.path_context { |
23 | if qual.is_none() { | 23 | Some(PathCompletionContext { qualifier: Some(qual), use_tree_parent, .. }) => { |
24 | kw_completion("crate::").add_to(acc); | 24 | if iter::successors(Some(qual.clone()), |p| p.qualifier()) |
25 | } | 25 | .all(|p| p.segment().and_then(|s| s.super_token()).is_some()) |
26 | kw_completion("self").add_to(acc); | 26 | { |
27 | if iter::successors(qual.cloned(), |p| p.qualifier()) | 27 | kw_completion("super::").add_to(acc); |
28 | .all(|p| p.segment().and_then(|s| s.super_token()).is_some()) | 28 | } |
29 | { | 29 | if *use_tree_parent { |
30 | kw_completion("super::").add_to(acc); | 30 | kw_completion("self").add_to(acc); |
31 | } | 31 | } |
32 | } | ||
33 | _ => { | ||
34 | kw_completion("crate::").add_to(acc); | ||
35 | kw_completion("self::").add_to(acc); | ||
36 | kw_completion("super::").add_to(acc); | ||
37 | } | ||
38 | }; | ||
32 | } | 39 | } |
33 | 40 | ||
34 | // Suggest .await syntax for types that implement Future trait | 41 | // Suggest .await syntax for types that implement Future trait |
@@ -200,41 +207,6 @@ mod tests { | |||
200 | } | 207 | } |
201 | 208 | ||
202 | #[test] | 209 | #[test] |
203 | fn test_keywords_in_use_stmt() { | ||
204 | check( | ||
205 | r"use $0", | ||
206 | expect![[r#" | ||
207 | kw crate:: | ||
208 | kw self | ||
209 | kw super:: | ||
210 | "#]], | ||
211 | ); | ||
212 | |||
213 | // FIXME: `self` shouldn't be shown here and the check below | ||
214 | check( | ||
215 | r"use a::$0", | ||
216 | expect![[r#" | ||
217 | kw self | ||
218 | "#]], | ||
219 | ); | ||
220 | |||
221 | check( | ||
222 | r"use super::$0", | ||
223 | expect![[r#" | ||
224 | kw self | ||
225 | kw super:: | ||
226 | "#]], | ||
227 | ); | ||
228 | |||
229 | check( | ||
230 | r"use a::{b, $0}", | ||
231 | expect![[r#" | ||
232 | kw self | ||
233 | "#]], | ||
234 | ); | ||
235 | } | ||
236 | |||
237 | #[test] | ||
238 | fn test_keywords_in_function() { | 210 | fn test_keywords_in_function() { |
239 | check( | 211 | check( |
240 | r"fn quux() { $0 }", | 212 | r"fn quux() { $0 }", |
diff --git a/crates/ide_completion/src/completions/qualified_path.rs b/crates/ide_completion/src/completions/qualified_path.rs index 9432caa22..0597879ac 100644 --- a/crates/ide_completion/src/completions/qualified_path.rs +++ b/crates/ide_completion/src/completions/qualified_path.rs | |||
@@ -49,7 +49,7 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon | |||
49 | hir::PathResolution::Def(hir::ModuleDef::Module(module)) => { | 49 | hir::PathResolution::Def(hir::ModuleDef::Module(module)) => { |
50 | let module_scope = module.scope(ctx.db, context_module); | 50 | let module_scope = module.scope(ctx.db, context_module); |
51 | for (name, def) in module_scope { | 51 | for (name, def) in module_scope { |
52 | if ctx.use_item_syntax.is_some() { | 52 | if ctx.in_use_tree() { |
53 | if let hir::ScopeDef::Unknown = def { | 53 | if let hir::ScopeDef::Unknown = def { |
54 | if let Some(name_ref) = ctx.name_ref_syntax.as_ref() { | 54 | if let Some(name_ref) = ctx.name_ref_syntax.as_ref() { |
55 | if name_ref.syntax().text() == name.to_string().as_str() { | 55 | if name_ref.syntax().text() == name.to_string().as_str() { |
@@ -213,12 +213,6 @@ mod tests { | |||
213 | } | 213 | } |
214 | 214 | ||
215 | #[test] | 215 | #[test] |
216 | fn dont_complete_current_use() { | ||
217 | cov_mark::check!(dont_complete_current_use); | ||
218 | check(r#"use self::foo$0;"#, expect![[""]]); | ||
219 | } | ||
220 | |||
221 | #[test] | ||
222 | fn dont_complete_values_in_type_pos() { | 216 | fn dont_complete_values_in_type_pos() { |
223 | check( | 217 | check( |
224 | r#" | 218 | r#" |
@@ -249,20 +243,6 @@ fn foo() { | |||
249 | } | 243 | } |
250 | 244 | ||
251 | #[test] | 245 | #[test] |
252 | fn dont_complete_current_use_in_braces_with_glob() { | ||
253 | check( | ||
254 | r#" | ||
255 | mod foo { pub struct S; } | ||
256 | use self::{foo::*, bar$0}; | ||
257 | "#, | ||
258 | expect![[r#" | ||
259 | st S | ||
260 | md foo | ||
261 | "#]], | ||
262 | ); | ||
263 | } | ||
264 | |||
265 | #[test] | ||
266 | fn dont_complete_primitive_in_use() { | 246 | fn dont_complete_primitive_in_use() { |
267 | check_builtin(r#"use self::$0;"#, expect![[""]]); | 247 | check_builtin(r#"use self::$0;"#, expect![[""]]); |
268 | } | 248 | } |
@@ -299,108 +279,6 @@ use self::{foo::*, bar$0}; | |||
299 | } | 279 | } |
300 | 280 | ||
301 | #[test] | 281 | #[test] |
302 | fn completes_mod_with_same_name_as_function() { | ||
303 | check( | ||
304 | r#" | ||
305 | use self::my::$0; | ||
306 | |||
307 | mod my { pub struct Bar; } | ||
308 | fn my() {} | ||
309 | "#, | ||
310 | expect![[r#" | ||
311 | st Bar | ||
312 | "#]], | ||
313 | ); | ||
314 | } | ||
315 | |||
316 | #[test] | ||
317 | fn filters_visibility() { | ||
318 | check( | ||
319 | r#" | ||
320 | use self::my::$0; | ||
321 | |||
322 | mod my { | ||
323 | struct Bar; | ||
324 | pub struct Foo; | ||
325 | pub use Bar as PublicBar; | ||
326 | } | ||
327 | "#, | ||
328 | expect![[r#" | ||
329 | st Foo | ||
330 | st PublicBar | ||
331 | "#]], | ||
332 | ); | ||
333 | } | ||
334 | |||
335 | #[test] | ||
336 | fn completes_use_item_starting_with_self() { | ||
337 | check( | ||
338 | r#" | ||
339 | use self::m::$0; | ||
340 | |||
341 | mod m { pub struct Bar; } | ||
342 | "#, | ||
343 | expect![[r#" | ||
344 | st Bar | ||
345 | "#]], | ||
346 | ); | ||
347 | } | ||
348 | |||
349 | #[test] | ||
350 | fn completes_use_item_starting_with_crate() { | ||
351 | check( | ||
352 | r#" | ||
353 | //- /lib.rs | ||
354 | mod foo; | ||
355 | struct Spam; | ||
356 | //- /foo.rs | ||
357 | use crate::Sp$0 | ||
358 | "#, | ||
359 | expect![[r#" | ||
360 | md foo | ||
361 | st Spam | ||
362 | "#]], | ||
363 | ); | ||
364 | } | ||
365 | |||
366 | #[test] | ||
367 | fn completes_nested_use_tree() { | ||
368 | check( | ||
369 | r#" | ||
370 | //- /lib.rs | ||
371 | mod foo; | ||
372 | struct Spam; | ||
373 | //- /foo.rs | ||
374 | use crate::{Sp$0}; | ||
375 | "#, | ||
376 | expect![[r#" | ||
377 | md foo | ||
378 | st Spam | ||
379 | "#]], | ||
380 | ); | ||
381 | } | ||
382 | |||
383 | #[test] | ||
384 | fn completes_deeply_nested_use_tree() { | ||
385 | check( | ||
386 | r#" | ||
387 | //- /lib.rs | ||
388 | mod foo; | ||
389 | pub mod bar { | ||
390 | pub mod baz { | ||
391 | pub struct Spam; | ||
392 | } | ||
393 | } | ||
394 | //- /foo.rs | ||
395 | use crate::{bar::{baz::Sp$0}}; | ||
396 | "#, | ||
397 | expect![[r#" | ||
398 | st Spam | ||
399 | "#]], | ||
400 | ); | ||
401 | } | ||
402 | |||
403 | #[test] | ||
404 | fn completes_enum_variant() { | 282 | fn completes_enum_variant() { |
405 | check( | 283 | check( |
406 | r#" | 284 | r#" |
@@ -497,22 +375,6 @@ fn foo() { let _ = U::$0 } | |||
497 | } | 375 | } |
498 | 376 | ||
499 | #[test] | 377 | #[test] |
500 | fn completes_use_paths_across_crates() { | ||
501 | check( | ||
502 | r#" | ||
503 | //- /main.rs crate:main deps:foo | ||
504 | use foo::$0; | ||
505 | |||
506 | //- /foo/lib.rs crate:foo | ||
507 | pub mod bar { pub struct S; } | ||
508 | "#, | ||
509 | expect![[r#" | ||
510 | md bar | ||
511 | "#]], | ||
512 | ); | ||
513 | } | ||
514 | |||
515 | #[test] | ||
516 | fn completes_trait_associated_method_1() { | 378 | fn completes_trait_associated_method_1() { |
517 | check( | 379 | check( |
518 | r#" | 380 | r#" |
@@ -714,25 +576,6 @@ impl MyStruct { | |||
714 | } | 576 | } |
715 | 577 | ||
716 | #[test] | 578 | #[test] |
717 | fn test_super_super_completion() { | ||
718 | check( | ||
719 | r#" | ||
720 | mod a { | ||
721 | const A: usize = 0; | ||
722 | mod b { | ||
723 | const B: usize = 0; | ||
724 | mod c { use super::super::$0 } | ||
725 | } | ||
726 | } | ||
727 | "#, | ||
728 | expect![[r#" | ||
729 | md b | ||
730 | ct A | ||
731 | "#]], | ||
732 | ); | ||
733 | } | ||
734 | |||
735 | #[test] | ||
736 | fn completes_reexported_items_under_correct_name() { | 579 | fn completes_reexported_items_under_correct_name() { |
737 | check( | 580 | check( |
738 | r#" | 581 | r#" |
diff --git a/crates/ide_completion/src/completions/unqualified_path.rs b/crates/ide_completion/src/completions/unqualified_path.rs index 2868d9b18..6f96eceb9 100644 --- a/crates/ide_completion/src/completions/unqualified_path.rs +++ b/crates/ide_completion/src/completions/unqualified_path.rs | |||
@@ -25,7 +25,7 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC | |||
25 | return; | 25 | return; |
26 | } | 26 | } |
27 | 27 | ||
28 | if ctx.expects_use_tree() { | 28 | if ctx.in_use_tree() { |
29 | // only show modules in a fresh UseTree | 29 | // only show modules in a fresh UseTree |
30 | cov_mark::hit!(only_completes_modules_in_import); | 30 | cov_mark::hit!(only_completes_modules_in_import); |
31 | ctx.scope.process_all_names(&mut |name, res| { | 31 | ctx.scope.process_all_names(&mut |name, res| { |
@@ -130,22 +130,6 @@ fn foo() { | |||
130 | } | 130 | } |
131 | 131 | ||
132 | #[test] | 132 | #[test] |
133 | fn only_completes_modules_in_import() { | ||
134 | cov_mark::check!(only_completes_modules_in_import); | ||
135 | check( | ||
136 | r#" | ||
137 | use f$0 | ||
138 | |||
139 | struct Foo; | ||
140 | mod foo {} | ||
141 | "#, | ||
142 | expect![[r#" | ||
143 | md foo | ||
144 | "#]], | ||
145 | ); | ||
146 | } | ||
147 | |||
148 | #[test] | ||
149 | fn bind_pat_and_path_ignore_at() { | 133 | fn bind_pat_and_path_ignore_at() { |
150 | check( | 134 | check( |
151 | r#" | 135 | r#" |
@@ -359,22 +343,6 @@ fn _alpha() {} | |||
359 | } | 343 | } |
360 | 344 | ||
361 | #[test] | 345 | #[test] |
362 | fn completes_extern_prelude() { | ||
363 | check( | ||
364 | r#" | ||
365 | //- /lib.rs crate:main deps:other_crate | ||
366 | use $0; | ||
367 | |||
368 | //- /other_crate/lib.rs crate:other_crate | ||
369 | // nothing here | ||
370 | "#, | ||
371 | expect![[r#" | ||
372 | md other_crate | ||
373 | "#]], | ||
374 | ); | ||
375 | } | ||
376 | |||
377 | #[test] | ||
378 | fn completes_module_items_in_nested_modules() { | 346 | fn completes_module_items_in_nested_modules() { |
379 | check( | 347 | check( |
380 | r#" | 348 | r#" |
diff --git a/crates/ide_completion/src/context.rs b/crates/ide_completion/src/context.rs index 121909857..240cac1de 100644 --- a/crates/ide_completion/src/context.rs +++ b/crates/ide_completion/src/context.rs | |||
@@ -43,6 +43,8 @@ pub(crate) struct PathCompletionContext { | |||
43 | pub(super) is_trivial_path: bool, | 43 | pub(super) is_trivial_path: bool, |
44 | /// If not a trivial path, the prefix (qualifier). | 44 | /// If not a trivial path, the prefix (qualifier). |
45 | pub(super) qualifier: Option<ast::Path>, | 45 | pub(super) qualifier: Option<ast::Path>, |
46 | /// Whether the qualifier comes from a use tree parent or not | ||
47 | pub(super) use_tree_parent: bool, | ||
46 | pub(super) kind: Option<PathKind>, | 48 | pub(super) kind: Option<PathKind>, |
47 | /// Whether the path segment has type args or not. | 49 | /// Whether the path segment has type args or not. |
48 | pub(super) has_type_args: bool, | 50 | pub(super) has_type_args: bool, |
@@ -79,7 +81,6 @@ pub(crate) struct CompletionContext<'a> { | |||
79 | /// The parent impl of the cursor position if it exists. | 81 | /// The parent impl of the cursor position if it exists. |
80 | pub(super) impl_def: Option<ast::Impl>, | 82 | pub(super) impl_def: Option<ast::Impl>, |
81 | pub(super) name_ref_syntax: Option<ast::NameRef>, | 83 | pub(super) name_ref_syntax: Option<ast::NameRef>, |
82 | pub(super) use_item_syntax: Option<ast::Use>, | ||
83 | 84 | ||
84 | // potentially set if we are completing a lifetime | 85 | // potentially set if we are completing a lifetime |
85 | pub(super) lifetime_syntax: Option<ast::Lifetime>, | 86 | pub(super) lifetime_syntax: Option<ast::Lifetime>, |
@@ -151,7 +152,6 @@ impl<'a> CompletionContext<'a> { | |||
151 | function_def: None, | 152 | function_def: None, |
152 | impl_def: None, | 153 | impl_def: None, |
153 | name_ref_syntax: None, | 154 | name_ref_syntax: None, |
154 | use_item_syntax: None, | ||
155 | lifetime_syntax: None, | 155 | lifetime_syntax: None, |
156 | lifetime_param_syntax: None, | 156 | lifetime_param_syntax: None, |
157 | lifetime_allowed: false, | 157 | lifetime_allowed: false, |
@@ -264,10 +264,6 @@ impl<'a> CompletionContext<'a> { | |||
264 | } | 264 | } |
265 | } | 265 | } |
266 | 266 | ||
267 | pub(crate) fn expects_use_tree(&self) -> bool { | ||
268 | matches!(self.completion_location, Some(ImmediateLocation::Use)) | ||
269 | } | ||
270 | |||
271 | pub(crate) fn expects_non_trait_assoc_item(&self) -> bool { | 267 | pub(crate) fn expects_non_trait_assoc_item(&self) -> bool { |
272 | matches!(self.completion_location, Some(ImmediateLocation::Impl)) | 268 | matches!(self.completion_location, Some(ImmediateLocation::Impl)) |
273 | } | 269 | } |
@@ -295,6 +291,13 @@ impl<'a> CompletionContext<'a> { | |||
295 | matches!(self.completion_location, Some(ImmediateLocation::RecordField)) | 291 | matches!(self.completion_location, Some(ImmediateLocation::RecordField)) |
296 | } | 292 | } |
297 | 293 | ||
294 | pub(crate) fn in_use_tree(&self) -> bool { | ||
295 | matches!( | ||
296 | self.completion_location, | ||
297 | Some(ImmediateLocation::Use) | Some(ImmediateLocation::UseTree) | ||
298 | ) | ||
299 | } | ||
300 | |||
298 | pub(crate) fn has_impl_or_trait_prev_sibling(&self) -> bool { | 301 | pub(crate) fn has_impl_or_trait_prev_sibling(&self) -> bool { |
299 | matches!( | 302 | matches!( |
300 | self.prev_sibling, | 303 | self.prev_sibling, |
@@ -578,9 +581,6 @@ impl<'a> CompletionContext<'a> { | |||
578 | self.name_ref_syntax = | 581 | self.name_ref_syntax = |
579 | find_node_at_offset(original_file, name_ref.syntax().text_range().start()); | 582 | find_node_at_offset(original_file, name_ref.syntax().text_range().start()); |
580 | 583 | ||
581 | self.use_item_syntax = | ||
582 | self.sema.token_ancestors_with_macros(self.token.clone()).find_map(ast::Use::cast); | ||
583 | |||
584 | self.function_def = self | 584 | self.function_def = self |
585 | .sema | 585 | .sema |
586 | .token_ancestors_with_macros(self.token.clone()) | 586 | .token_ancestors_with_macros(self.token.clone()) |
@@ -600,6 +600,7 @@ impl<'a> CompletionContext<'a> { | |||
600 | has_type_args: false, | 600 | has_type_args: false, |
601 | can_be_stmt: false, | 601 | can_be_stmt: false, |
602 | in_loop_body: false, | 602 | in_loop_body: false, |
603 | use_tree_parent: false, | ||
603 | kind: None, | 604 | kind: None, |
604 | }); | 605 | }); |
605 | path_ctx.in_loop_body = is_in_loop_body(name_ref.syntax()); | 606 | path_ctx.in_loop_body = is_in_loop_body(name_ref.syntax()); |
@@ -627,7 +628,8 @@ impl<'a> CompletionContext<'a> { | |||
627 | } | 628 | } |
628 | path_ctx.has_type_args = segment.generic_arg_list().is_some(); | 629 | path_ctx.has_type_args = segment.generic_arg_list().is_some(); |
629 | 630 | ||
630 | if let Some(path) = path_or_use_tree_qualifier(&path) { | 631 | if let Some((path, use_tree_parent)) = path_or_use_tree_qualifier(&path) { |
632 | path_ctx.use_tree_parent = use_tree_parent; | ||
631 | path_ctx.qualifier = path | 633 | path_ctx.qualifier = path |
632 | .segment() | 634 | .segment() |
633 | .and_then(|it| { | 635 | .and_then(|it| { |
@@ -681,13 +683,13 @@ fn is_node<N: AstNode>(node: &SyntaxNode) -> bool { | |||
681 | } | 683 | } |
682 | } | 684 | } |
683 | 685 | ||
684 | fn path_or_use_tree_qualifier(path: &ast::Path) -> Option<ast::Path> { | 686 | fn path_or_use_tree_qualifier(path: &ast::Path) -> Option<(ast::Path, bool)> { |
685 | if let Some(qual) = path.qualifier() { | 687 | if let Some(qual) = path.qualifier() { |
686 | return Some(qual); | 688 | return Some((qual, false)); |
687 | } | 689 | } |
688 | let use_tree_list = path.syntax().ancestors().find_map(ast::UseTreeList::cast)?; | 690 | let use_tree_list = path.syntax().ancestors().find_map(ast::UseTreeList::cast)?; |
689 | let use_tree = use_tree_list.syntax().parent().and_then(ast::UseTree::cast)?; | 691 | let use_tree = use_tree_list.syntax().parent().and_then(ast::UseTree::cast)?; |
690 | use_tree.path() | 692 | use_tree.path().zip(Some(true)) |
691 | } | 693 | } |
692 | 694 | ||
693 | #[cfg(test)] | 695 | #[cfg(test)] |
diff --git a/crates/ide_completion/src/patterns.rs b/crates/ide_completion/src/patterns.rs index 62e4334de..271409c38 100644 --- a/crates/ide_completion/src/patterns.rs +++ b/crates/ide_completion/src/patterns.rs | |||
@@ -27,6 +27,7 @@ pub(crate) enum ImmediatePrevSibling { | |||
27 | #[derive(Clone, Debug, PartialEq, Eq)] | 27 | #[derive(Clone, Debug, PartialEq, Eq)] |
28 | pub(crate) enum ImmediateLocation { | 28 | pub(crate) enum ImmediateLocation { |
29 | Use, | 29 | Use, |
30 | UseTree, | ||
30 | Impl, | 31 | Impl, |
31 | Trait, | 32 | Trait, |
32 | RecordField, | 33 | RecordField, |
@@ -180,6 +181,8 @@ pub(crate) fn determine_location( | |||
180 | match parent { | 181 | match parent { |
181 | ast::IdentPat(_it) => ImmediateLocation::IdentPat, | 182 | ast::IdentPat(_it) => ImmediateLocation::IdentPat, |
182 | ast::Use(_it) => ImmediateLocation::Use, | 183 | ast::Use(_it) => ImmediateLocation::Use, |
184 | ast::UseTree(_it) => ImmediateLocation::UseTree, | ||
185 | ast::UseTreeList(_it) => ImmediateLocation::UseTree, | ||
183 | ast::BlockExpr(_it) => ImmediateLocation::BlockExpr, | 186 | ast::BlockExpr(_it) => ImmediateLocation::BlockExpr, |
184 | ast::SourceFile(_it) => ImmediateLocation::ItemList, | 187 | ast::SourceFile(_it) => ImmediateLocation::ItemList, |
185 | ast::ItemList(_it) => ImmediateLocation::ItemList, | 188 | ast::ItemList(_it) => ImmediateLocation::ItemList, |
@@ -373,8 +376,8 @@ mod tests { | |||
373 | fn test_use_loc() { | 376 | fn test_use_loc() { |
374 | check_location(r"use f$0", ImmediateLocation::Use); | 377 | check_location(r"use f$0", ImmediateLocation::Use); |
375 | check_location(r"use f$0;", ImmediateLocation::Use); | 378 | check_location(r"use f$0;", ImmediateLocation::Use); |
376 | check_location(r"use f::{f$0}", None); | 379 | check_location(r"use f::{f$0}", ImmediateLocation::UseTree); |
377 | check_location(r"use {f$0}", None); | 380 | check_location(r"use {f$0}", ImmediateLocation::UseTree); |
378 | } | 381 | } |
379 | 382 | ||
380 | #[test] | 383 | #[test] |
diff --git a/crates/ide_completion/src/render/builder_ext.rs b/crates/ide_completion/src/render/builder_ext.rs index c54752d30..749dfc665 100644 --- a/crates/ide_completion/src/render/builder_ext.rs +++ b/crates/ide_completion/src/render/builder_ext.rs | |||
@@ -28,7 +28,7 @@ impl Builder { | |||
28 | if !ctx.config.add_call_parenthesis { | 28 | if !ctx.config.add_call_parenthesis { |
29 | return false; | 29 | return false; |
30 | } | 30 | } |
31 | if ctx.use_item_syntax.is_some() { | 31 | if ctx.in_use_tree() { |
32 | cov_mark::hit!(no_parens_in_use_item); | 32 | cov_mark::hit!(no_parens_in_use_item); |
33 | return false; | 33 | return false; |
34 | } | 34 | } |
diff --git a/crates/ide_completion/src/render/macro_.rs b/crates/ide_completion/src/render/macro_.rs index d5a1f45d3..4d5179c4f 100644 --- a/crates/ide_completion/src/render/macro_.rs +++ b/crates/ide_completion/src/render/macro_.rs | |||
@@ -69,7 +69,7 @@ impl<'a> MacroRender<'a> { | |||
69 | } | 69 | } |
70 | 70 | ||
71 | fn needs_bang(&self) -> bool { | 71 | fn needs_bang(&self) -> bool { |
72 | self.ctx.completion.use_item_syntax.is_none() | 72 | !self.ctx.completion.in_use_tree() |
73 | && !matches!(self.ctx.completion.path_call_kind(), Some(CallKind::Mac)) | 73 | && !matches!(self.ctx.completion.path_call_kind(), Some(CallKind::Mac)) |
74 | } | 74 | } |
75 | 75 | ||
diff --git a/crates/ide_completion/src/tests.rs b/crates/ide_completion/src/tests.rs index 1495924ea..89c7fb524 100644 --- a/crates/ide_completion/src/tests.rs +++ b/crates/ide_completion/src/tests.rs | |||
@@ -1,4 +1,5 @@ | |||
1 | mod item_list; | 1 | mod item_list; |
2 | mod use_tree; | ||
2 | 3 | ||
3 | use hir::{PrefixKind, Semantics}; | 4 | use hir::{PrefixKind, Semantics}; |
4 | use ide_db::{ | 5 | use ide_db::{ |
diff --git a/crates/ide_completion/src/tests/use_tree.rs b/crates/ide_completion/src/tests/use_tree.rs new file mode 100644 index 000000000..7e6748ccc --- /dev/null +++ b/crates/ide_completion/src/tests/use_tree.rs | |||
@@ -0,0 +1,255 @@ | |||
1 | use expect_test::{expect, Expect}; | ||
2 | |||
3 | use crate::tests::completion_list; | ||
4 | |||
5 | fn check(ra_fixture: &str, expect: Expect) { | ||
6 | let actual = completion_list(ra_fixture); | ||
7 | expect.assert_eq(&actual) | ||
8 | } | ||
9 | |||
10 | #[test] | ||
11 | fn use_tree_start() { | ||
12 | cov_mark::check!(only_completes_modules_in_import); | ||
13 | check( | ||
14 | r#" | ||
15 | //- /lib.rs crate:main deps:other_crate | ||
16 | use f$0 | ||
17 | |||
18 | struct Foo; | ||
19 | mod foo {} | ||
20 | //- /other_crate/lib.rs crate:other_crate | ||
21 | // nothing here | ||
22 | "#, | ||
23 | expect![[r#" | ||
24 | kw crate:: | ||
25 | kw self:: | ||
26 | kw super:: | ||
27 | md foo | ||
28 | md other_crate | ||
29 | "#]], | ||
30 | ); | ||
31 | } | ||
32 | |||
33 | #[test] | ||
34 | fn dont_complete_current_use() { | ||
35 | cov_mark::check!(dont_complete_current_use); | ||
36 | check(r#"use self::foo$0;"#, expect![[r#""#]]); | ||
37 | check( | ||
38 | r#" | ||
39 | mod foo { pub struct S; } | ||
40 | use self::{foo::*, bar$0}; | ||
41 | "#, | ||
42 | expect![[r#" | ||
43 | kw self | ||
44 | st S | ||
45 | md foo | ||
46 | "#]], | ||
47 | ); | ||
48 | } | ||
49 | |||
50 | #[test] | ||
51 | fn nested_use_tree() { | ||
52 | check( | ||
53 | r#" | ||
54 | mod foo { | ||
55 | pub mod bar { | ||
56 | pub struct FooBar; | ||
57 | } | ||
58 | } | ||
59 | use foo::{bar::$0} | ||
60 | "#, | ||
61 | expect![[r#" | ||
62 | st FooBar | ||
63 | "#]], | ||
64 | ); | ||
65 | check( | ||
66 | r#" | ||
67 | mod foo { | ||
68 | pub mod bar { | ||
69 | pub struct FooBar; | ||
70 | } | ||
71 | } | ||
72 | use foo::{$0} | ||
73 | "#, | ||
74 | expect![[r#" | ||
75 | kw self | ||
76 | md bar | ||
77 | "#]], | ||
78 | ); | ||
79 | } | ||
80 | |||
81 | #[test] | ||
82 | fn deeply_nested_use_tree() { | ||
83 | check( | ||
84 | r#" | ||
85 | mod foo { | ||
86 | pub mod bar { | ||
87 | pub mod baz { | ||
88 | pub struct FooBarBaz; | ||
89 | } | ||
90 | } | ||
91 | } | ||
92 | use foo::{bar::{baz::$0}} | ||
93 | "#, | ||
94 | expect![[r#" | ||
95 | st FooBarBaz | ||
96 | "#]], | ||
97 | ); | ||
98 | check( | ||
99 | r#" | ||
100 | mod foo { | ||
101 | pub mod bar { | ||
102 | pub mod baz { | ||
103 | pub struct FooBarBaz; | ||
104 | } | ||
105 | } | ||
106 | } | ||
107 | use foo::{bar::{$0}} | ||
108 | "#, | ||
109 | expect![[r#" | ||
110 | kw self | ||
111 | md baz | ||
112 | "#]], | ||
113 | ); | ||
114 | } | ||
115 | |||
116 | #[test] | ||
117 | fn plain_qualified_use_tree() { | ||
118 | check( | ||
119 | r#" | ||
120 | use foo::$0 | ||
121 | |||
122 | mod foo { | ||
123 | struct Private; | ||
124 | pub struct Foo; | ||
125 | } | ||
126 | struct Bar; | ||
127 | "#, | ||
128 | expect![[r#" | ||
129 | st Foo | ||
130 | "#]], | ||
131 | ); | ||
132 | } | ||
133 | |||
134 | #[test] | ||
135 | fn self_qualified_use_tree() { | ||
136 | check( | ||
137 | r#" | ||
138 | use self::$0 | ||
139 | |||
140 | mod foo {} | ||
141 | struct Bar; | ||
142 | "#, | ||
143 | expect![[r#" | ||
144 | md foo | ||
145 | st Bar | ||
146 | "#]], | ||
147 | ); | ||
148 | } | ||
149 | |||
150 | #[test] | ||
151 | fn super_qualified_use_tree() { | ||
152 | check( | ||
153 | r#" | ||
154 | mod bar { | ||
155 | use super::$0 | ||
156 | } | ||
157 | |||
158 | mod foo {} | ||
159 | struct Bar; | ||
160 | "#, | ||
161 | expect![[r#" | ||
162 | kw super:: | ||
163 | st Bar | ||
164 | md bar | ||
165 | md foo | ||
166 | "#]], | ||
167 | ); | ||
168 | } | ||
169 | |||
170 | #[test] | ||
171 | fn super_super_qualified_use_tree() { | ||
172 | check( | ||
173 | r#" | ||
174 | mod a { | ||
175 | const A: usize = 0; | ||
176 | mod b { | ||
177 | const B: usize = 0; | ||
178 | mod c { use super::super::$0 } | ||
179 | } | ||
180 | } | ||
181 | "#, | ||
182 | expect![[r#" | ||
183 | kw super:: | ||
184 | md b | ||
185 | ct A | ||
186 | "#]], | ||
187 | ); | ||
188 | } | ||
189 | |||
190 | #[test] | ||
191 | fn crate_qualified_use_tree() { | ||
192 | check( | ||
193 | r#" | ||
194 | use crate::$0 | ||
195 | |||
196 | mod foo {} | ||
197 | struct Bar; | ||
198 | "#, | ||
199 | expect![[r#" | ||
200 | md foo | ||
201 | st Bar | ||
202 | "#]], | ||
203 | ); | ||
204 | } | ||
205 | |||
206 | #[test] | ||
207 | fn extern_crate_qualified_use_tree() { | ||
208 | check( | ||
209 | r#" | ||
210 | //- /lib.rs crate:main deps:other_crate | ||
211 | use other_crate::$0 | ||
212 | //- /other_crate/lib.rs crate:other_crate | ||
213 | pub struct Foo; | ||
214 | pub mod foo {} | ||
215 | "#, | ||
216 | expect![[r#" | ||
217 | st Foo | ||
218 | md foo | ||
219 | "#]], | ||
220 | ); | ||
221 | } | ||
222 | |||
223 | #[test] | ||
224 | fn pub_use_tree() { | ||
225 | check( | ||
226 | r#" | ||
227 | pub struct X; | ||
228 | pub mod bar {} | ||
229 | pub use $0; | ||
230 | "#, | ||
231 | expect![[r#" | ||
232 | kw crate:: | ||
233 | kw self:: | ||
234 | kw super:: | ||
235 | md bar | ||
236 | "#]], | ||
237 | ); | ||
238 | } | ||
239 | |||
240 | #[test] | ||
241 | fn use_tree_braces_at_start() { | ||
242 | check( | ||
243 | r#" | ||
244 | struct X; | ||
245 | mod bar {} | ||
246 | use {$0}; | ||
247 | "#, | ||
248 | expect![[r#" | ||
249 | kw crate:: | ||
250 | kw self:: | ||
251 | kw super:: | ||
252 | md bar | ||
253 | "#]], | ||
254 | ); | ||
255 | } | ||