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