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