]> git.lizzy.rs Git - rust.git/blob - crates/ide_completion/src/completions/flyimport.rs
Merge #6822
[rust.git] / crates / ide_completion / src / completions / flyimport.rs
1 //! Feature: completion with imports-on-the-fly
2 //!
3 //! When completing names in the current scope, proposes additional imports from other modules or crates,
4 //! if they can be qualified in the scope and their name contains all symbols from the completion input
5 //! (case-insensitive, in any order or places).
6 //!
7 //! ```
8 //! fn main() {
9 //!     pda$0
10 //! }
11 //! # pub mod std { pub mod marker { pub struct PhantomData { } } }
12 //! ```
13 //! ->
14 //! ```
15 //! use std::marker::PhantomData;
16 //!
17 //! fn main() {
18 //!     PhantomData
19 //! }
20 //! # pub mod std { pub mod marker { pub struct PhantomData { } } }
21 //! ```
22 //!
23 //! Also completes associated items, that require trait imports.
24 //! If any unresolved and/or partially-qualified path predeces the input, it will be taken into account.
25 //! Currently, only the imports with their import path ending with the whole qialifier will be proposed
26 //! (no fuzzy matching for qualifier).
27 //!
28 //! ```
29 //! mod foo {
30 //!     pub mod bar {
31 //!         pub struct Item;
32 //!
33 //!         impl Item {
34 //!             pub const TEST_ASSOC: usize = 3;
35 //!         }
36 //!     }
37 //! }
38 //!
39 //! fn main() {
40 //!     bar::Item::TEST_A$0
41 //! }
42 //! ```
43 //! ->
44 //! ```
45 //! use foo::bar;
46 //!
47 //! mod foo {
48 //!     pub mod bar {
49 //!         pub struct Item;
50 //!
51 //!         impl Item {
52 //!             pub const TEST_ASSOC: usize = 3;
53 //!         }
54 //!     }
55 //! }
56 //!
57 //! fn main() {
58 //!     bar::Item::TEST_ASSOC
59 //! }
60 //! ```
61 //!
62 //! NOTE: currently, if an assoc item comes from a trait that's not currently imported and it also has an unresolved and/or partially-qualified path,
63 //! no imports will be proposed.
64 //!
65 //! .Fuzzy search details
66 //!
67 //! To avoid an excessive amount of the results returned, completion input is checked for inclusion in the names only
68 //! (i.e. in `HashMap` in the `std::collections::HashMap` path).
69 //! For the same reasons, avoids searching for any path imports for inputs with their length less that 2 symbols
70 //! (but shows all associated items for any input length).
71 //!
72 //! .Import configuration
73 //!
74 //! It is possible to configure how use-trees are merged with the `importMergeBehavior` setting.
75 //! Mimics the corresponding behavior of the `Auto Import` feature.
76 //!
77 //! .LSP and performance implications
78 //!
79 //! The feature is enabled only if the LSP client supports LSP protocol version 3.16+ and reports the `additionalTextEdits`
80 //! (case sensitive) resolve client capability in its client capabilities.
81 //! This way the server is able to defer the costly computations, doing them for a selected completion item only.
82 //! For clients with no such support, all edits have to be calculated on the completion request, including the fuzzy search completion ones,
83 //! which might be slow ergo the feature is automatically disabled.
84 //!
85 //! .Feature toggle
86 //!
87 //! The feature can be forcefully turned off in the settings with the `rust-analyzer.completion.enableAutoimportCompletions` flag.
88 //! Note that having this flag set to `true` does not guarantee that the feature is enabled: your client needs to have the corredponding
89 //! capability enabled.
90
91 use hir::ModPath;
92 use ide_db::helpers::{
93     import_assets::{ImportAssets, ImportCandidate},
94     insert_use::ImportScope,
95 };
96 use itertools::Itertools;
97 use syntax::{AstNode, SyntaxNode, T};
98
99 use crate::{
100     context::CompletionContext,
101     render::{render_resolution_with_import, RenderContext},
102     ImportEdit,
103 };
104
105 use super::Completions;
106
107 pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
108     if !ctx.config.enable_imports_on_the_fly {
109         return None;
110     }
111     if ctx.use_item_syntax.is_some()
112         || ctx.attribute_under_caret.is_some()
113         || ctx.mod_declaration_under_caret.is_some()
114     {
115         return None;
116     }
117     let potential_import_name = {
118         let token_kind = ctx.token.kind();
119         if matches!(token_kind, T![.] | T![::]) {
120             String::new()
121         } else {
122             ctx.token.to_string()
123         }
124     };
125
126     let _p = profile::span("import_on_the_fly").detail(|| potential_import_name.to_string());
127
128     let user_input_lowercased = potential_import_name.to_lowercase();
129     let import_assets = import_assets(ctx, potential_import_name)?;
130     let import_scope = ImportScope::find_insert_use_container(
131         position_for_import(ctx, Some(import_assets.import_candidate()))?,
132         &ctx.sema,
133     )?;
134
135     acc.add_all(
136         import_assets
137             .search_for_imports(&ctx.sema, ctx.config.insert_use.prefix_kind)
138             .into_iter()
139             .sorted_by_key(|located_import| {
140                 compute_fuzzy_completion_order_key(
141                     &located_import.import_path,
142                     &user_input_lowercased,
143                 )
144             })
145             .filter_map(|import| {
146                 render_resolution_with_import(
147                     RenderContext::new(ctx),
148                     ImportEdit { import, scope: import_scope.clone() },
149                 )
150             }),
151     );
152     Some(())
153 }
154
155 pub(crate) fn position_for_import<'a>(
156     ctx: &'a CompletionContext,
157     import_candidate: Option<&ImportCandidate>,
158 ) -> Option<&'a SyntaxNode> {
159     Some(match import_candidate {
160         Some(ImportCandidate::Path(_)) => ctx.name_ref_syntax.as_ref()?.syntax(),
161         Some(ImportCandidate::TraitAssocItem(_)) => ctx.path_qual.as_ref()?.syntax(),
162         Some(ImportCandidate::TraitMethod(_)) => ctx.dot_receiver.as_ref()?.syntax(),
163         None => ctx
164             .name_ref_syntax
165             .as_ref()
166             .map(|name_ref| name_ref.syntax())
167             .or_else(|| ctx.path_qual.as_ref().map(|path| path.syntax()))
168             .or_else(|| ctx.dot_receiver.as_ref().map(|expr| expr.syntax()))?,
169     })
170 }
171
172 fn import_assets(ctx: &CompletionContext, fuzzy_name: String) -> Option<ImportAssets> {
173     let current_module = ctx.scope.module()?;
174     if let Some(dot_receiver) = &ctx.dot_receiver {
175         ImportAssets::for_fuzzy_method_call(
176             current_module,
177             ctx.sema.type_of_expr(dot_receiver)?,
178             fuzzy_name,
179             dot_receiver.syntax().clone(),
180         )
181     } else {
182         let fuzzy_name_length = fuzzy_name.len();
183         let approximate_node = match current_module.definition_source(ctx.db).value {
184             hir::ModuleSource::SourceFile(s) => s.syntax().clone(),
185             hir::ModuleSource::Module(m) => m.syntax().clone(),
186             hir::ModuleSource::BlockExpr(b) => b.syntax().clone(),
187         };
188         let assets_for_path = ImportAssets::for_fuzzy_path(
189             current_module,
190             ctx.path_qual.clone(),
191             fuzzy_name,
192             &ctx.sema,
193             approximate_node,
194         )?;
195
196         if matches!(assets_for_path.import_candidate(), ImportCandidate::Path(_))
197             && fuzzy_name_length < 2
198         {
199             cov_mark::hit!(ignore_short_input_for_path);
200             None
201         } else {
202             Some(assets_for_path)
203         }
204     }
205 }
206
207 fn compute_fuzzy_completion_order_key(
208     proposed_mod_path: &ModPath,
209     user_input_lowercased: &str,
210 ) -> usize {
211     cov_mark::hit!(certain_fuzzy_order_test);
212     let import_name = match proposed_mod_path.segments().last() {
213         Some(name) => name.to_string().to_lowercase(),
214         None => return usize::MAX,
215     };
216     match import_name.match_indices(user_input_lowercased).next() {
217         Some((first_matching_index, _)) => first_matching_index,
218         None => usize::MAX,
219     }
220 }
221
222 #[cfg(test)]
223 mod tests {
224     use expect_test::{expect, Expect};
225
226     use crate::{
227         item::CompletionKind,
228         test_utils::{check_edit, check_edit_with_config, completion_list, TEST_CONFIG},
229     };
230
231     fn check(ra_fixture: &str, expect: Expect) {
232         let actual = completion_list(ra_fixture, CompletionKind::Magic);
233         expect.assert_eq(&actual);
234     }
235
236     #[test]
237     fn function_fuzzy_completion() {
238         check_edit(
239             "stdin",
240             r#"
241 //- /lib.rs crate:dep
242 pub mod io {
243     pub fn stdin() {}
244 };
245
246 //- /main.rs crate:main deps:dep
247 fn main() {
248     stdi$0
249 }
250 "#,
251             r#"
252 use dep::io::stdin;
253
254 fn main() {
255     stdin()$0
256 }
257 "#,
258         );
259     }
260
261     #[test]
262     fn macro_fuzzy_completion() {
263         check_edit(
264             "macro_with_curlies!",
265             r#"
266 //- /lib.rs crate:dep
267 /// Please call me as macro_with_curlies! {}
268 #[macro_export]
269 macro_rules! macro_with_curlies {
270     () => {}
271 }
272
273 //- /main.rs crate:main deps:dep
274 fn main() {
275     curli$0
276 }
277 "#,
278             r#"
279 use dep::macro_with_curlies;
280
281 fn main() {
282     macro_with_curlies! {$0}
283 }
284 "#,
285         );
286     }
287
288     #[test]
289     fn struct_fuzzy_completion() {
290         check_edit(
291             "ThirdStruct",
292             r#"
293 //- /lib.rs crate:dep
294 pub struct FirstStruct;
295 pub mod some_module {
296     pub struct SecondStruct;
297     pub struct ThirdStruct;
298 }
299
300 //- /main.rs crate:main deps:dep
301 use dep::{FirstStruct, some_module::SecondStruct};
302
303 fn main() {
304     this$0
305 }
306 "#,
307             r#"
308 use dep::{FirstStruct, some_module::{SecondStruct, ThirdStruct}};
309
310 fn main() {
311     ThirdStruct
312 }
313 "#,
314         );
315     }
316
317     #[test]
318     fn short_paths_are_ignored() {
319         cov_mark::check!(ignore_short_input_for_path);
320
321         check(
322             r#"
323 //- /lib.rs crate:dep
324 pub struct FirstStruct;
325 pub mod some_module {
326     pub struct SecondStruct;
327     pub struct ThirdStruct;
328 }
329
330 //- /main.rs crate:main deps:dep
331 use dep::{FirstStruct, some_module::SecondStruct};
332
333 fn main() {
334     t$0
335 }
336 "#,
337             expect![[r#""#]],
338         );
339     }
340
341     #[test]
342     fn fuzzy_completions_come_in_specific_order() {
343         cov_mark::check!(certain_fuzzy_order_test);
344         check(
345             r#"
346 //- /lib.rs crate:dep
347 pub struct FirstStruct;
348 pub mod some_module {
349     // already imported, omitted
350     pub struct SecondStruct;
351     // does not contain all letters from the query, omitted
352     pub struct UnrelatedOne;
353     // contains all letters from the query, but not in sequence, displayed last
354     pub struct ThiiiiiirdStruct;
355     // contains all letters from the query, but not in the beginning, displayed second
356     pub struct AfterThirdStruct;
357     // contains all letters from the query in the begginning, displayed first
358     pub struct ThirdStruct;
359 }
360
361 //- /main.rs crate:main deps:dep
362 use dep::{FirstStruct, some_module::SecondStruct};
363
364 fn main() {
365     hir$0
366 }
367 "#,
368             expect![[r#"
369                 st dep::some_module::ThirdStruct
370                 st dep::some_module::AfterThirdStruct
371                 st dep::some_module::ThiiiiiirdStruct
372             "#]],
373         );
374     }
375
376     #[test]
377     fn trait_function_fuzzy_completion() {
378         let fixture = r#"
379         //- /lib.rs crate:dep
380         pub mod test_mod {
381             pub trait TestTrait {
382                 const SPECIAL_CONST: u8;
383                 type HumbleType;
384                 fn weird_function();
385                 fn random_method(&self);
386             }
387             pub struct TestStruct {}
388             impl TestTrait for TestStruct {
389                 const SPECIAL_CONST: u8 = 42;
390                 type HumbleType = ();
391                 fn weird_function() {}
392                 fn random_method(&self) {}
393             }
394         }
395
396         //- /main.rs crate:main deps:dep
397         fn main() {
398             dep::test_mod::TestStruct::wei$0
399         }
400         "#;
401
402         check(
403             fixture,
404             expect![[r#"
405                 fn weird_function() (dep::test_mod::TestTrait) -> ()
406             "#]],
407         );
408
409         check_edit(
410             "weird_function",
411             fixture,
412             r#"
413 use dep::test_mod::TestTrait;
414
415 fn main() {
416     dep::test_mod::TestStruct::weird_function()$0
417 }
418 "#,
419         );
420     }
421
422     #[test]
423     fn trait_const_fuzzy_completion() {
424         let fixture = r#"
425         //- /lib.rs crate:dep
426         pub mod test_mod {
427             pub trait TestTrait {
428                 const SPECIAL_CONST: u8;
429                 type HumbleType;
430                 fn weird_function();
431                 fn random_method(&self);
432             }
433             pub struct TestStruct {}
434             impl TestTrait for TestStruct {
435                 const SPECIAL_CONST: u8 = 42;
436                 type HumbleType = ();
437                 fn weird_function() {}
438                 fn random_method(&self) {}
439             }
440         }
441
442         //- /main.rs crate:main deps:dep
443         fn main() {
444             dep::test_mod::TestStruct::spe$0
445         }
446         "#;
447
448         check(
449             fixture,
450             expect![[r#"
451             ct SPECIAL_CONST (dep::test_mod::TestTrait)
452         "#]],
453         );
454
455         check_edit(
456             "SPECIAL_CONST",
457             fixture,
458             r#"
459 use dep::test_mod::TestTrait;
460
461 fn main() {
462     dep::test_mod::TestStruct::SPECIAL_CONST
463 }
464 "#,
465         );
466     }
467
468     #[test]
469     fn trait_method_fuzzy_completion() {
470         let fixture = r#"
471         //- /lib.rs crate:dep
472         pub mod test_mod {
473             pub trait TestTrait {
474                 const SPECIAL_CONST: u8;
475                 type HumbleType;
476                 fn weird_function();
477                 fn random_method(&self);
478             }
479             pub struct TestStruct {}
480             impl TestTrait for TestStruct {
481                 const SPECIAL_CONST: u8 = 42;
482                 type HumbleType = ();
483                 fn weird_function() {}
484                 fn random_method(&self) {}
485             }
486         }
487
488         //- /main.rs crate:main deps:dep
489         fn main() {
490             let test_struct = dep::test_mod::TestStruct {};
491             test_struct.ran$0
492         }
493         "#;
494
495         check(
496             fixture,
497             expect![[r#"
498                 me random_method() (dep::test_mod::TestTrait) -> ()
499             "#]],
500         );
501
502         check_edit(
503             "random_method",
504             fixture,
505             r#"
506 use dep::test_mod::TestTrait;
507
508 fn main() {
509     let test_struct = dep::test_mod::TestStruct {};
510     test_struct.random_method()$0
511 }
512 "#,
513         );
514     }
515
516     #[test]
517     fn no_trait_type_fuzzy_completion() {
518         check(
519             r#"
520 //- /lib.rs crate:dep
521 pub mod test_mod {
522     pub trait TestTrait {
523         const SPECIAL_CONST: u8;
524         type HumbleType;
525         fn weird_function();
526         fn random_method(&self);
527     }
528     pub struct TestStruct {}
529     impl TestTrait for TestStruct {
530         const SPECIAL_CONST: u8 = 42;
531         type HumbleType = ();
532         fn weird_function() {}
533         fn random_method(&self) {}
534     }
535 }
536
537 //- /main.rs crate:main deps:dep
538 fn main() {
539     dep::test_mod::TestStruct::hum$0
540 }
541 "#,
542             expect![[r#""#]],
543         );
544     }
545
546     #[test]
547     fn does_not_propose_names_in_scope() {
548         check(
549             r#"
550 //- /lib.rs crate:dep
551 pub mod test_mod {
552     pub trait TestTrait {
553         const SPECIAL_CONST: u8;
554         type HumbleType;
555         fn weird_function();
556         fn random_method(&self);
557     }
558     pub struct TestStruct {}
559     impl TestTrait for TestStruct {
560         const SPECIAL_CONST: u8 = 42;
561         type HumbleType = ();
562         fn weird_function() {}
563         fn random_method(&self) {}
564     }
565 }
566
567 //- /main.rs crate:main deps:dep
568 use dep::test_mod::TestStruct;
569 fn main() {
570     TestSt$0
571 }
572 "#,
573             expect![[r#""#]],
574         );
575     }
576
577     #[test]
578     fn does_not_propose_traits_in_scope() {
579         check(
580             r#"
581 //- /lib.rs crate:dep
582 pub mod test_mod {
583     pub trait TestTrait {
584         const SPECIAL_CONST: u8;
585         type HumbleType;
586         fn weird_function();
587         fn random_method(&self);
588     }
589     pub struct TestStruct {}
590     impl TestTrait for TestStruct {
591         const SPECIAL_CONST: u8 = 42;
592         type HumbleType = ();
593         fn weird_function() {}
594         fn random_method(&self) {}
595     }
596 }
597
598 //- /main.rs crate:main deps:dep
599 use dep::test_mod::{TestStruct, TestTrait};
600 fn main() {
601     dep::test_mod::TestStruct::hum$0
602 }
603 "#,
604             expect![[r#""#]],
605         );
606     }
607
608     #[test]
609     fn blanket_trait_impl_import() {
610         check_edit(
611             "another_function",
612             r#"
613 //- /lib.rs crate:dep
614 pub mod test_mod {
615     pub struct TestStruct {}
616     pub trait TestTrait {
617         fn another_function();
618     }
619     impl<T> TestTrait for T {
620         fn another_function() {}
621     }
622 }
623
624 //- /main.rs crate:main deps:dep
625 fn main() {
626     dep::test_mod::TestStruct::ano$0
627 }
628 "#,
629             r#"
630 use dep::test_mod::TestTrait;
631
632 fn main() {
633     dep::test_mod::TestStruct::another_function()$0
634 }
635 "#,
636         );
637     }
638
639     #[test]
640     fn zero_input_deprecated_assoc_item_completion() {
641         check(
642             r#"
643 //- /lib.rs crate:dep
644 pub mod test_mod {
645     #[deprecated]
646     pub trait TestTrait {
647         const SPECIAL_CONST: u8;
648         type HumbleType;
649         fn weird_function();
650         fn random_method(&self);
651     }
652     pub struct TestStruct {}
653     impl TestTrait for TestStruct {
654         const SPECIAL_CONST: u8 = 42;
655         type HumbleType = ();
656         fn weird_function() {}
657         fn random_method(&self) {}
658     }
659 }
660
661 //- /main.rs crate:main deps:dep
662 fn main() {
663     let test_struct = dep::test_mod::TestStruct {};
664     test_struct.$0
665 }
666         "#,
667             expect![[r#"
668                 me random_method() (dep::test_mod::TestTrait) -> () DEPRECATED
669             "#]],
670         );
671
672         check(
673             r#"
674 //- /lib.rs crate:dep
675 pub mod test_mod {
676     #[deprecated]
677     pub trait TestTrait {
678         const SPECIAL_CONST: u8;
679         type HumbleType;
680         fn weird_function();
681         fn random_method(&self);
682     }
683     pub struct TestStruct {}
684     impl TestTrait for TestStruct {
685         const SPECIAL_CONST: u8 = 42;
686         type HumbleType = ();
687         fn weird_function() {}
688         fn random_method(&self) {}
689     }
690 }
691
692 //- /main.rs crate:main deps:dep
693 fn main() {
694     dep::test_mod::TestStruct::$0
695 }
696 "#,
697             expect![[r#"
698                 ct SPECIAL_CONST (dep::test_mod::TestTrait) DEPRECATED
699                 fn weird_function() (dep::test_mod::TestTrait) -> () DEPRECATED
700             "#]],
701         );
702     }
703
704     #[test]
705     fn no_completions_in_use_statements() {
706         check(
707             r#"
708 //- /lib.rs crate:dep
709 pub mod io {
710     pub fn stdin() {}
711 };
712
713 //- /main.rs crate:main deps:dep
714 use stdi$0
715
716 fn main() {}
717 "#,
718             expect![[]],
719         );
720     }
721
722     #[test]
723     fn prefix_config_usage() {
724         let fixture = r#"
725 mod foo {
726     pub mod bar {
727         pub struct Item;
728     }
729 }
730
731 use crate::foo::bar;
732
733 fn main() {
734     Ite$0
735 }"#;
736         let mut config = TEST_CONFIG;
737
738         config.insert_use.prefix_kind = hir::PrefixKind::ByCrate;
739         check_edit_with_config(
740             config.clone(),
741             "Item",
742             fixture,
743             r#"
744 mod foo {
745     pub mod bar {
746         pub struct Item;
747     }
748 }
749
750 use crate::foo::bar::{self, Item};
751
752 fn main() {
753     Item
754 }"#,
755         );
756
757         config.insert_use.prefix_kind = hir::PrefixKind::BySelf;
758         check_edit_with_config(
759             config.clone(),
760             "Item",
761             fixture,
762             r#"
763 mod foo {
764     pub mod bar {
765         pub struct Item;
766     }
767 }
768
769 use crate::foo::bar;
770
771 use self::foo::bar::Item;
772
773 fn main() {
774     Item
775 }"#,
776         );
777
778         config.insert_use.prefix_kind = hir::PrefixKind::Plain;
779         check_edit_with_config(
780             config,
781             "Item",
782             fixture,
783             r#"
784 mod foo {
785     pub mod bar {
786         pub struct Item;
787     }
788 }
789
790 use foo::bar::Item;
791
792 use crate::foo::bar;
793
794 fn main() {
795     Item
796 }"#,
797         );
798     }
799
800     #[test]
801     fn unresolved_qualifier() {
802         let fixture = r#"
803 mod foo {
804     pub mod bar {
805         pub mod baz {
806             pub struct Item;
807         }
808     }
809 }
810
811 fn main() {
812     bar::baz::Ite$0
813 }"#;
814
815         check(
816             fixture,
817             expect![[r#"
818         st foo::bar::baz::Item
819         "#]],
820         );
821
822         check_edit(
823             "Item",
824             fixture,
825             r#"
826         use foo::bar;
827
828         mod foo {
829             pub mod bar {
830                 pub mod baz {
831                     pub struct Item;
832                 }
833             }
834         }
835
836         fn main() {
837             bar::baz::Item
838         }"#,
839         );
840     }
841
842     #[test]
843     fn unresolved_assoc_item_container() {
844         let fixture = r#"
845 mod foo {
846     pub struct Item;
847
848     impl Item {
849         pub const TEST_ASSOC: usize = 3;
850     }
851 }
852
853 fn main() {
854     Item::TEST_A$0
855 }"#;
856
857         check(
858             fixture,
859             expect![[r#"
860         ct TEST_ASSOC (foo::Item)
861         "#]],
862         );
863
864         check_edit(
865             "TEST_ASSOC",
866             fixture,
867             r#"
868 use foo::Item;
869
870 mod foo {
871     pub struct Item;
872
873     impl Item {
874         pub const TEST_ASSOC: usize = 3;
875     }
876 }
877
878 fn main() {
879     Item::TEST_ASSOC
880 }"#,
881         );
882     }
883
884     #[test]
885     fn unresolved_assoc_item_container_with_path() {
886         let fixture = r#"
887 mod foo {
888     pub mod bar {
889         pub struct Item;
890
891         impl Item {
892             pub const TEST_ASSOC: usize = 3;
893         }
894     }
895 }
896
897 fn main() {
898     bar::Item::TEST_A$0
899 }"#;
900
901         check(
902             fixture,
903             expect![[r#"
904         ct TEST_ASSOC (foo::bar::Item)
905     "#]],
906         );
907
908         check_edit(
909             "TEST_ASSOC",
910             fixture,
911             r#"
912 use foo::bar;
913
914 mod foo {
915     pub mod bar {
916         pub struct Item;
917
918         impl Item {
919             pub const TEST_ASSOC: usize = 3;
920         }
921     }
922 }
923
924 fn main() {
925     bar::Item::TEST_ASSOC
926 }"#,
927         );
928     }
929
930     #[test]
931     fn fuzzy_unresolved_path() {
932         check(
933             r#"
934 mod foo {
935     pub mod bar {
936         pub struct Item;
937
938         impl Item {
939             pub const TEST_ASSOC: usize = 3;
940         }
941     }
942 }
943
944 fn main() {
945     bar::Ass$0
946 }"#,
947             expect![[]],
948         )
949     }
950 }