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