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