]> git.lizzy.rs Git - rust.git/blob - crates/assists/src/handlers/auto_import.rs
Share import_assets and related entities
[rust.git] / crates / assists / src / handlers / auto_import.rs
1 use ide_db::helpers::{
2     import_assets::{ImportAssets, ImportCandidate},
3     insert_use::{insert_use, ImportScope},
4     mod_path_to_ast,
5 };
6 use syntax::ast;
7
8 use crate::{AssistContext, AssistId, AssistKind, Assists, GroupLabel};
9
10 // Feature: Auto Import
11 //
12 // Using the `auto-import` assist it is possible to insert missing imports for unresolved items.
13 // When inserting an import it will do so in a structured manner by keeping imports grouped,
14 // separated by a newline in the following order:
15 //
16 // - `std` and `core`
17 // - External Crates
18 // - Current Crate, paths prefixed by `crate`
19 // - Current Module, paths prefixed by `self`
20 // - Super Module, paths prefixed by `super`
21 //
22 // Example:
23 // ```rust
24 // use std::fs::File;
25 //
26 // use itertools::Itertools;
27 // use syntax::ast;
28 //
29 // use crate::utils::insert_use;
30 //
31 // use self::auto_import;
32 //
33 // use super::AssistContext;
34 // ```
35 //
36 // .Merge Behaviour
37 //
38 // It is possible to configure how use-trees are merged with the `importMergeBehaviour` setting.
39 // It has the following configurations:
40 //
41 // - `full`: This setting will cause auto-import to always completely merge use-trees that share the
42 //  same path prefix while also merging inner trees that share the same path-prefix. This kind of
43 //  nesting is only supported in Rust versions later than 1.24.
44 // - `last`: This setting will cause auto-import to merge use-trees as long as the resulting tree
45 //  will only contain a nesting of single segment paths at the very end.
46 // - `none`: This setting will cause auto-import to never merge use-trees keeping them as simple
47 //  paths.
48 //
49 // In `VS Code` the configuration for this is `rust-analyzer.assist.importMergeBehaviour`.
50 //
51 // .Import Prefix
52 //
53 // The style of imports in the same crate is configurable through the `importPrefix` setting.
54 // It has the following configurations:
55 //
56 // - `by_crate`: This setting will force paths to be always absolute, starting with the `crate`
57 //  prefix, unless the item is defined outside of the current crate.
58 // - `by_self`: This setting will force paths that are relative to the current module to always
59 //  start with `self`. This will result in paths that always start with either `crate`, `self`,
60 //  `super` or an extern crate identifier.
61 // - `plain`: This setting does not impose any restrictions in imports.
62 //
63 // In `VS Code` the configuration for this is `rust-analyzer.assist.importPrefix`.
64
65 // Assist: auto_import
66 //
67 // If the name is unresolved, provides all possible imports for it.
68 //
69 // ```
70 // fn main() {
71 //     let map = HashMap$0::new();
72 // }
73 // # pub mod std { pub mod collections { pub struct HashMap { } } }
74 // ```
75 // ->
76 // ```
77 // use std::collections::HashMap;
78 //
79 // fn main() {
80 //     let map = HashMap::new();
81 // }
82 // # pub mod std { pub mod collections { pub struct HashMap { } } }
83 // ```
84 pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
85     let import_assets =
86         if let Some(path_under_caret) = ctx.find_node_at_offset_with_descend::<ast::Path>() {
87             ImportAssets::for_regular_path(path_under_caret, &ctx.sema)
88         } else if let Some(method_under_caret) =
89             ctx.find_node_at_offset_with_descend::<ast::MethodCallExpr>()
90         {
91             ImportAssets::for_method_call(method_under_caret, &ctx.sema)
92         } else {
93             None
94         }?;
95     let proposed_imports = import_assets.search_for_imports(&ctx.sema, &ctx.config.insert_use);
96     if proposed_imports.is_empty() {
97         return None;
98     }
99
100     let range = ctx.sema.original_range(import_assets.syntax_under_caret()).range;
101     let group = import_group_message(import_assets.import_candidate());
102     let scope =
103         ImportScope::find_insert_use_container(import_assets.syntax_under_caret(), &ctx.sema)?;
104     for (import, _) in proposed_imports {
105         acc.add_group(
106             &group,
107             AssistId("auto_import", AssistKind::QuickFix),
108             format!("Import `{}`", &import),
109             range,
110             |builder| {
111                 let rewriter =
112                     insert_use(&scope, mod_path_to_ast(&import), ctx.config.insert_use.merge);
113                 builder.rewrite(rewriter);
114             },
115         );
116     }
117     Some(())
118 }
119
120 fn import_group_message(import_candidate: &ImportCandidate) -> GroupLabel {
121     let name = match import_candidate {
122         ImportCandidate::Path(candidate) => format!("Import {}", &candidate.name),
123         ImportCandidate::TraitAssocItem(candidate) => {
124             format!("Import a trait for item {}", &candidate.name)
125         }
126         ImportCandidate::TraitMethod(candidate) => {
127             format!("Import a trait for method {}", &candidate.name)
128         }
129     };
130     GroupLabel(name)
131 }
132
133 #[cfg(test)]
134 mod tests {
135     use super::*;
136     use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target};
137
138     #[test]
139     fn applicable_when_found_an_import_partial() {
140         check_assist(
141             auto_import,
142             r"
143             mod std {
144                 pub mod fmt {
145                     pub struct Formatter;
146                 }
147             }
148
149             use std::fmt;
150
151             $0Formatter
152             ",
153             r"
154             mod std {
155                 pub mod fmt {
156                     pub struct Formatter;
157                 }
158             }
159
160             use std::fmt::{self, Formatter};
161
162             Formatter
163             ",
164         );
165     }
166
167     #[test]
168     fn applicable_when_found_an_import() {
169         check_assist(
170             auto_import,
171             r"
172             $0PubStruct
173
174             pub mod PubMod {
175                 pub struct PubStruct;
176             }
177             ",
178             r"
179             use PubMod::PubStruct;
180
181             PubStruct
182
183             pub mod PubMod {
184                 pub struct PubStruct;
185             }
186             ",
187         );
188     }
189
190     #[test]
191     fn applicable_when_found_an_import_in_macros() {
192         check_assist(
193             auto_import,
194             r"
195             macro_rules! foo {
196                 ($i:ident) => { fn foo(a: $i) {} }
197             }
198             foo!(Pub$0Struct);
199
200             pub mod PubMod {
201                 pub struct PubStruct;
202             }
203             ",
204             r"
205             use PubMod::PubStruct;
206
207             macro_rules! foo {
208                 ($i:ident) => { fn foo(a: $i) {} }
209             }
210             foo!(PubStruct);
211
212             pub mod PubMod {
213                 pub struct PubStruct;
214             }
215             ",
216         );
217     }
218
219     #[test]
220     fn auto_imports_are_merged() {
221         check_assist(
222             auto_import,
223             r"
224             use PubMod::PubStruct1;
225
226             struct Test {
227                 test: Pub$0Struct2<u8>,
228             }
229
230             pub mod PubMod {
231                 pub struct PubStruct1;
232                 pub struct PubStruct2<T> {
233                     _t: T,
234                 }
235             }
236             ",
237             r"
238             use PubMod::{PubStruct1, PubStruct2};
239
240             struct Test {
241                 test: PubStruct2<u8>,
242             }
243
244             pub mod PubMod {
245                 pub struct PubStruct1;
246                 pub struct PubStruct2<T> {
247                     _t: T,
248                 }
249             }
250             ",
251         );
252     }
253
254     #[test]
255     fn applicable_when_found_multiple_imports() {
256         check_assist(
257             auto_import,
258             r"
259             PubSt$0ruct
260
261             pub mod PubMod1 {
262                 pub struct PubStruct;
263             }
264             pub mod PubMod2 {
265                 pub struct PubStruct;
266             }
267             pub mod PubMod3 {
268                 pub struct PubStruct;
269             }
270             ",
271             r"
272             use PubMod3::PubStruct;
273
274             PubStruct
275
276             pub mod PubMod1 {
277                 pub struct PubStruct;
278             }
279             pub mod PubMod2 {
280                 pub struct PubStruct;
281             }
282             pub mod PubMod3 {
283                 pub struct PubStruct;
284             }
285             ",
286         );
287     }
288
289     #[test]
290     fn not_applicable_for_already_imported_types() {
291         check_assist_not_applicable(
292             auto_import,
293             r"
294             use PubMod::PubStruct;
295
296             PubStruct$0
297
298             pub mod PubMod {
299                 pub struct PubStruct;
300             }
301             ",
302         );
303     }
304
305     #[test]
306     fn not_applicable_for_types_with_private_paths() {
307         check_assist_not_applicable(
308             auto_import,
309             r"
310             PrivateStruct$0
311
312             pub mod PubMod {
313                 struct PrivateStruct;
314             }
315             ",
316         );
317     }
318
319     #[test]
320     fn not_applicable_when_no_imports_found() {
321         check_assist_not_applicable(
322             auto_import,
323             "
324             PubStruct$0",
325         );
326     }
327
328     #[test]
329     fn not_applicable_in_import_statements() {
330         check_assist_not_applicable(
331             auto_import,
332             r"
333             use PubStruct$0;
334
335             pub mod PubMod {
336                 pub struct PubStruct;
337             }",
338         );
339     }
340
341     #[test]
342     fn function_import() {
343         check_assist(
344             auto_import,
345             r"
346             test_function$0
347
348             pub mod PubMod {
349                 pub fn test_function() {};
350             }
351             ",
352             r"
353             use PubMod::test_function;
354
355             test_function
356
357             pub mod PubMod {
358                 pub fn test_function() {};
359             }
360             ",
361         );
362     }
363
364     #[test]
365     fn macro_import() {
366         check_assist(
367             auto_import,
368             r"
369 //- /lib.rs crate:crate_with_macro
370 #[macro_export]
371 macro_rules! foo {
372     () => ()
373 }
374
375 //- /main.rs crate:main deps:crate_with_macro
376 fn main() {
377     foo$0
378 }
379 ",
380             r"use crate_with_macro::foo;
381
382 fn main() {
383     foo
384 }
385 ",
386         );
387     }
388
389     #[test]
390     fn auto_import_target() {
391         check_assist_target(
392             auto_import,
393             r"
394             struct AssistInfo {
395                 group_label: Option<$0GroupLabel>,
396             }
397
398             mod m { pub struct GroupLabel; }
399             ",
400             "GroupLabel",
401         )
402     }
403
404     #[test]
405     fn not_applicable_when_path_start_is_imported() {
406         check_assist_not_applicable(
407             auto_import,
408             r"
409             pub mod mod1 {
410                 pub mod mod2 {
411                     pub mod mod3 {
412                         pub struct TestStruct;
413                     }
414                 }
415             }
416
417             use mod1::mod2;
418             fn main() {
419                 mod2::mod3::TestStruct$0
420             }
421             ",
422         );
423     }
424
425     #[test]
426     fn not_applicable_for_imported_function() {
427         check_assist_not_applicable(
428             auto_import,
429             r"
430             pub mod test_mod {
431                 pub fn test_function() {}
432             }
433
434             use test_mod::test_function;
435             fn main() {
436                 test_function$0
437             }
438             ",
439         );
440     }
441
442     #[test]
443     fn associated_struct_function() {
444         check_assist(
445             auto_import,
446             r"
447             mod test_mod {
448                 pub struct TestStruct {}
449                 impl TestStruct {
450                     pub fn test_function() {}
451                 }
452             }
453
454             fn main() {
455                 TestStruct::test_function$0
456             }
457             ",
458             r"
459             use test_mod::TestStruct;
460
461             mod test_mod {
462                 pub struct TestStruct {}
463                 impl TestStruct {
464                     pub fn test_function() {}
465                 }
466             }
467
468             fn main() {
469                 TestStruct::test_function
470             }
471             ",
472         );
473     }
474
475     #[test]
476     fn associated_struct_const() {
477         check_assist(
478             auto_import,
479             r"
480             mod test_mod {
481                 pub struct TestStruct {}
482                 impl TestStruct {
483                     const TEST_CONST: u8 = 42;
484                 }
485             }
486
487             fn main() {
488                 TestStruct::TEST_CONST$0
489             }
490             ",
491             r"
492             use test_mod::TestStruct;
493
494             mod test_mod {
495                 pub struct TestStruct {}
496                 impl TestStruct {
497                     const TEST_CONST: u8 = 42;
498                 }
499             }
500
501             fn main() {
502                 TestStruct::TEST_CONST
503             }
504             ",
505         );
506     }
507
508     #[test]
509     fn associated_trait_function() {
510         check_assist(
511             auto_import,
512             r"
513             mod test_mod {
514                 pub trait TestTrait {
515                     fn test_function();
516                 }
517                 pub struct TestStruct {}
518                 impl TestTrait for TestStruct {
519                     fn test_function() {}
520                 }
521             }
522
523             fn main() {
524                 test_mod::TestStruct::test_function$0
525             }
526             ",
527             r"
528             use test_mod::TestTrait;
529
530             mod test_mod {
531                 pub trait TestTrait {
532                     fn test_function();
533                 }
534                 pub struct TestStruct {}
535                 impl TestTrait for TestStruct {
536                     fn test_function() {}
537                 }
538             }
539
540             fn main() {
541                 test_mod::TestStruct::test_function
542             }
543             ",
544         );
545     }
546
547     #[test]
548     fn not_applicable_for_imported_trait_for_function() {
549         check_assist_not_applicable(
550             auto_import,
551             r"
552             mod test_mod {
553                 pub trait TestTrait {
554                     fn test_function();
555                 }
556                 pub trait TestTrait2 {
557                     fn test_function();
558                 }
559                 pub enum TestEnum {
560                     One,
561                     Two,
562                 }
563                 impl TestTrait2 for TestEnum {
564                     fn test_function() {}
565                 }
566                 impl TestTrait for TestEnum {
567                     fn test_function() {}
568                 }
569             }
570
571             use test_mod::TestTrait2;
572             fn main() {
573                 test_mod::TestEnum::test_function$0;
574             }
575             ",
576         )
577     }
578
579     #[test]
580     fn associated_trait_const() {
581         check_assist(
582             auto_import,
583             r"
584             mod test_mod {
585                 pub trait TestTrait {
586                     const TEST_CONST: u8;
587                 }
588                 pub struct TestStruct {}
589                 impl TestTrait for TestStruct {
590                     const TEST_CONST: u8 = 42;
591                 }
592             }
593
594             fn main() {
595                 test_mod::TestStruct::TEST_CONST$0
596             }
597             ",
598             r"
599             use test_mod::TestTrait;
600
601             mod test_mod {
602                 pub trait TestTrait {
603                     const TEST_CONST: u8;
604                 }
605                 pub struct TestStruct {}
606                 impl TestTrait for TestStruct {
607                     const TEST_CONST: u8 = 42;
608                 }
609             }
610
611             fn main() {
612                 test_mod::TestStruct::TEST_CONST
613             }
614             ",
615         );
616     }
617
618     #[test]
619     fn not_applicable_for_imported_trait_for_const() {
620         check_assist_not_applicable(
621             auto_import,
622             r"
623             mod test_mod {
624                 pub trait TestTrait {
625                     const TEST_CONST: u8;
626                 }
627                 pub trait TestTrait2 {
628                     const TEST_CONST: f64;
629                 }
630                 pub enum TestEnum {
631                     One,
632                     Two,
633                 }
634                 impl TestTrait2 for TestEnum {
635                     const TEST_CONST: f64 = 42.0;
636                 }
637                 impl TestTrait for TestEnum {
638                     const TEST_CONST: u8 = 42;
639                 }
640             }
641
642             use test_mod::TestTrait2;
643             fn main() {
644                 test_mod::TestEnum::TEST_CONST$0;
645             }
646             ",
647         )
648     }
649
650     #[test]
651     fn trait_method() {
652         check_assist(
653             auto_import,
654             r"
655             mod test_mod {
656                 pub trait TestTrait {
657                     fn test_method(&self);
658                 }
659                 pub struct TestStruct {}
660                 impl TestTrait for TestStruct {
661                     fn test_method(&self) {}
662                 }
663             }
664
665             fn main() {
666                 let test_struct = test_mod::TestStruct {};
667                 test_struct.test_meth$0od()
668             }
669             ",
670             r"
671             use test_mod::TestTrait;
672
673             mod test_mod {
674                 pub trait TestTrait {
675                     fn test_method(&self);
676                 }
677                 pub struct TestStruct {}
678                 impl TestTrait for TestStruct {
679                     fn test_method(&self) {}
680                 }
681             }
682
683             fn main() {
684                 let test_struct = test_mod::TestStruct {};
685                 test_struct.test_method()
686             }
687             ",
688         );
689     }
690
691     #[test]
692     fn trait_method_cross_crate() {
693         check_assist(
694             auto_import,
695             r"
696             //- /main.rs crate:main deps:dep
697             fn main() {
698                 let test_struct = dep::test_mod::TestStruct {};
699                 test_struct.test_meth$0od()
700             }
701             //- /dep.rs crate:dep
702             pub mod test_mod {
703                 pub trait TestTrait {
704                     fn test_method(&self);
705                 }
706                 pub struct TestStruct {}
707                 impl TestTrait for TestStruct {
708                     fn test_method(&self) {}
709                 }
710             }
711             ",
712             r"
713             use dep::test_mod::TestTrait;
714
715             fn main() {
716                 let test_struct = dep::test_mod::TestStruct {};
717                 test_struct.test_method()
718             }
719             ",
720         );
721     }
722
723     #[test]
724     fn assoc_fn_cross_crate() {
725         check_assist(
726             auto_import,
727             r"
728             //- /main.rs crate:main deps:dep
729             fn main() {
730                 dep::test_mod::TestStruct::test_func$0tion
731             }
732             //- /dep.rs crate:dep
733             pub mod test_mod {
734                 pub trait TestTrait {
735                     fn test_function();
736                 }
737                 pub struct TestStruct {}
738                 impl TestTrait for TestStruct {
739                     fn test_function() {}
740                 }
741             }
742             ",
743             r"
744             use dep::test_mod::TestTrait;
745
746             fn main() {
747                 dep::test_mod::TestStruct::test_function
748             }
749             ",
750         );
751     }
752
753     #[test]
754     fn assoc_const_cross_crate() {
755         check_assist(
756             auto_import,
757             r"
758             //- /main.rs crate:main deps:dep
759             fn main() {
760                 dep::test_mod::TestStruct::CONST$0
761             }
762             //- /dep.rs crate:dep
763             pub mod test_mod {
764                 pub trait TestTrait {
765                     const CONST: bool;
766                 }
767                 pub struct TestStruct {}
768                 impl TestTrait for TestStruct {
769                     const CONST: bool = true;
770                 }
771             }
772             ",
773             r"
774             use dep::test_mod::TestTrait;
775
776             fn main() {
777                 dep::test_mod::TestStruct::CONST
778             }
779             ",
780         );
781     }
782
783     #[test]
784     fn assoc_fn_as_method_cross_crate() {
785         check_assist_not_applicable(
786             auto_import,
787             r"
788             //- /main.rs crate:main deps:dep
789             fn main() {
790                 let test_struct = dep::test_mod::TestStruct {};
791                 test_struct.test_func$0tion()
792             }
793             //- /dep.rs crate:dep
794             pub mod test_mod {
795                 pub trait TestTrait {
796                     fn test_function();
797                 }
798                 pub struct TestStruct {}
799                 impl TestTrait for TestStruct {
800                     fn test_function() {}
801                 }
802             }
803             ",
804         );
805     }
806
807     #[test]
808     fn private_trait_cross_crate() {
809         check_assist_not_applicable(
810             auto_import,
811             r"
812             //- /main.rs crate:main deps:dep
813             fn main() {
814                 let test_struct = dep::test_mod::TestStruct {};
815                 test_struct.test_meth$0od()
816             }
817             //- /dep.rs crate:dep
818             pub mod test_mod {
819                 trait TestTrait {
820                     fn test_method(&self);
821                 }
822                 pub struct TestStruct {}
823                 impl TestTrait for TestStruct {
824                     fn test_method(&self) {}
825                 }
826             }
827             ",
828         );
829     }
830
831     #[test]
832     fn not_applicable_for_imported_trait_for_method() {
833         check_assist_not_applicable(
834             auto_import,
835             r"
836             mod test_mod {
837                 pub trait TestTrait {
838                     fn test_method(&self);
839                 }
840                 pub trait TestTrait2 {
841                     fn test_method(&self);
842                 }
843                 pub enum TestEnum {
844                     One,
845                     Two,
846                 }
847                 impl TestTrait2 for TestEnum {
848                     fn test_method(&self) {}
849                 }
850                 impl TestTrait for TestEnum {
851                     fn test_method(&self) {}
852                 }
853             }
854
855             use test_mod::TestTrait2;
856             fn main() {
857                 let one = test_mod::TestEnum::One;
858                 one.test$0_method();
859             }
860             ",
861         )
862     }
863
864     #[test]
865     fn dep_import() {
866         check_assist(
867             auto_import,
868             r"
869 //- /lib.rs crate:dep
870 pub struct Struct;
871
872 //- /main.rs crate:main deps:dep
873 fn main() {
874     Struct$0
875 }
876 ",
877             r"use dep::Struct;
878
879 fn main() {
880     Struct
881 }
882 ",
883         );
884     }
885
886     #[test]
887     fn whole_segment() {
888         // Tests that only imports whose last segment matches the identifier get suggested.
889         check_assist(
890             auto_import,
891             r"
892 //- /lib.rs crate:dep
893 pub mod fmt {
894     pub trait Display {}
895 }
896
897 pub fn panic_fmt() {}
898
899 //- /main.rs crate:main deps:dep
900 struct S;
901
902 impl f$0mt::Display for S {}
903 ",
904             r"use dep::fmt;
905
906 struct S;
907
908 impl fmt::Display for S {}
909 ",
910         );
911     }
912
913     #[test]
914     fn macro_generated() {
915         // Tests that macro-generated items are suggested from external crates.
916         check_assist(
917             auto_import,
918             r"
919 //- /lib.rs crate:dep
920 macro_rules! mac {
921     () => {
922         pub struct Cheese;
923     };
924 }
925
926 mac!();
927
928 //- /main.rs crate:main deps:dep
929 fn main() {
930     Cheese$0;
931 }
932 ",
933             r"use dep::Cheese;
934
935 fn main() {
936     Cheese;
937 }
938 ",
939         );
940     }
941
942     #[test]
943     fn casing() {
944         // Tests that differently cased names don't interfere and we only suggest the matching one.
945         check_assist(
946             auto_import,
947             r"
948 //- /lib.rs crate:dep
949 pub struct FMT;
950 pub struct fmt;
951
952 //- /main.rs crate:main deps:dep
953 fn main() {
954     FMT$0;
955 }
956 ",
957             r"use dep::FMT;
958
959 fn main() {
960     FMT;
961 }
962 ",
963         );
964     }
965 }