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