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