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