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