aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ide_completion/src/completions/flyimport.rs2
-rw-r--r--crates/ide_completion/src/completions/keyword.rs64
-rw-r--r--crates/ide_completion/src/completions/qualified_path.rs159
-rw-r--r--crates/ide_completion/src/completions/unqualified_path.rs34
-rw-r--r--crates/ide_completion/src/context.rs28
-rw-r--r--crates/ide_completion/src/patterns.rs7
-rw-r--r--crates/ide_completion/src/render/builder_ext.rs2
-rw-r--r--crates/ide_completion/src/render/macro_.rs2
-rw-r--r--crates/ide_completion/src/tests.rs1
-rw-r--r--crates/ide_completion/src/tests/use_tree.rs255
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#"
255mod foo { pub struct S; }
256use 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#"
305use self::my::$0;
306
307mod my { pub struct Bar; }
308fn my() {}
309"#,
310 expect![[r#"
311 st Bar
312 "#]],
313 );
314 }
315
316 #[test]
317 fn filters_visibility() {
318 check(
319 r#"
320use self::my::$0;
321
322mod 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#"
339use self::m::$0;
340
341mod 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
354mod foo;
355struct Spam;
356//- /foo.rs
357use 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
371mod foo;
372struct Spam;
373//- /foo.rs
374use 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
388mod foo;
389pub mod bar {
390 pub mod baz {
391 pub struct Spam;
392 }
393}
394//- /foo.rs
395use 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
504use foo::$0;
505
506//- /foo/lib.rs crate:foo
507pub 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#"
720mod 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#"
137use f$0
138
139struct Foo;
140mod 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
366use $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
684fn path_or_use_tree_qualifier(path: &ast::Path) -> Option<ast::Path> { 686fn 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)]
28pub(crate) enum ImmediateLocation { 28pub(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 @@
1mod item_list; 1mod item_list;
2mod use_tree;
2 3
3use hir::{PrefixKind, Semantics}; 4use hir::{PrefixKind, Semantics};
4use ide_db::{ 5use 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 @@
1use expect_test::{expect, Expect};
2
3use crate::tests::completion_list;
4
5fn check(ra_fixture: &str, expect: Expect) {
6 let actual = completion_list(ra_fixture);
7 expect.assert_eq(&actual)
8}
9
10#[test]
11fn use_tree_start() {
12 cov_mark::check!(only_completes_modules_in_import);
13 check(
14 r#"
15//- /lib.rs crate:main deps:other_crate
16use f$0
17
18struct Foo;
19mod 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]
34fn 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#"
39mod foo { pub struct S; }
40use self::{foo::*, bar$0};
41"#,
42 expect![[r#"
43 kw self
44 st S
45 md foo
46 "#]],
47 );
48}
49
50#[test]
51fn nested_use_tree() {
52 check(
53 r#"
54mod foo {
55 pub mod bar {
56 pub struct FooBar;
57 }
58}
59use foo::{bar::$0}
60"#,
61 expect![[r#"
62 st FooBar
63 "#]],
64 );
65 check(
66 r#"
67mod foo {
68 pub mod bar {
69 pub struct FooBar;
70 }
71}
72use foo::{$0}
73"#,
74 expect![[r#"
75 kw self
76 md bar
77 "#]],
78 );
79}
80
81#[test]
82fn deeply_nested_use_tree() {
83 check(
84 r#"
85mod foo {
86 pub mod bar {
87 pub mod baz {
88 pub struct FooBarBaz;
89 }
90 }
91}
92use foo::{bar::{baz::$0}}
93"#,
94 expect![[r#"
95 st FooBarBaz
96 "#]],
97 );
98 check(
99 r#"
100mod foo {
101 pub mod bar {
102 pub mod baz {
103 pub struct FooBarBaz;
104 }
105 }
106}
107use foo::{bar::{$0}}
108"#,
109 expect![[r#"
110 kw self
111 md baz
112 "#]],
113 );
114}
115
116#[test]
117fn plain_qualified_use_tree() {
118 check(
119 r#"
120use foo::$0
121
122mod foo {
123 struct Private;
124 pub struct Foo;
125}
126struct Bar;
127"#,
128 expect![[r#"
129 st Foo
130 "#]],
131 );
132}
133
134#[test]
135fn self_qualified_use_tree() {
136 check(
137 r#"
138use self::$0
139
140mod foo {}
141struct Bar;
142"#,
143 expect![[r#"
144 md foo
145 st Bar
146 "#]],
147 );
148}
149
150#[test]
151fn super_qualified_use_tree() {
152 check(
153 r#"
154mod bar {
155 use super::$0
156}
157
158mod foo {}
159struct Bar;
160"#,
161 expect![[r#"
162 kw super::
163 st Bar
164 md bar
165 md foo
166 "#]],
167 );
168}
169
170#[test]
171fn super_super_qualified_use_tree() {
172 check(
173 r#"
174mod 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]
191fn crate_qualified_use_tree() {
192 check(
193 r#"
194use crate::$0
195
196mod foo {}
197struct Bar;
198"#,
199 expect![[r#"
200 md foo
201 st Bar
202 "#]],
203 );
204}
205
206#[test]
207fn extern_crate_qualified_use_tree() {
208 check(
209 r#"
210//- /lib.rs crate:main deps:other_crate
211use other_crate::$0
212//- /other_crate/lib.rs crate:other_crate
213pub struct Foo;
214pub mod foo {}
215"#,
216 expect![[r#"
217 st Foo
218 md foo
219 "#]],
220 );
221}
222
223#[test]
224fn pub_use_tree() {
225 check(
226 r#"
227pub struct X;
228pub mod bar {}
229pub use $0;
230"#,
231 expect![[r#"
232 kw crate::
233 kw self::
234 kw super::
235 md bar
236 "#]],
237 );
238}
239
240#[test]
241fn use_tree_braces_at_start() {
242 check(
243 r#"
244struct X;
245mod bar {}
246use {$0};
247"#,
248 expect![[r#"
249 kw crate::
250 kw self::
251 kw super::
252 md bar
253 "#]],
254 );
255}