2 import_assets::{ImportAssets, ImportCandidate},
3 insert_use::{insert_use, ImportScope},
8 use crate::{AssistContext, AssistId, AssistKind, Assists, GroupLabel};
10 // Feature: Auto Import
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:
18 // - Current Crate, paths prefixed by `crate`
19 // - Current Module, paths prefixed by `self`
20 // - Super Module, paths prefixed by `super`
26 // use itertools::Itertools;
29 // use crate::utils::insert_use;
31 // use self::auto_import;
33 // use super::AssistContext;
38 // It is possible to configure how use-trees are merged with the `importMergeBehaviour` setting.
39 // It has the following configurations:
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
49 // In `VS Code` the configuration for this is `rust-analyzer.assist.importMergeBehaviour`.
53 // The style of imports in the same crate is configurable through the `importPrefix` setting.
54 // It has the following configurations:
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.
63 // In `VS Code` the configuration for this is `rust-analyzer.assist.importPrefix`.
65 // Assist: auto_import
67 // If the name is unresolved, provides all possible imports for it.
71 // let map = HashMap$0::new();
73 // # pub mod std { pub mod collections { pub struct HashMap { } } }
77 // use std::collections::HashMap;
80 // let map = HashMap::new();
82 // # pub mod std { pub mod collections { pub struct HashMap { } } }
84 pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
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>()
91 ImportAssets::for_method_call(method_under_caret, &ctx.sema)
95 let proposed_imports = import_assets.search_for_imports(&ctx.sema, &ctx.config.insert_use);
96 if proposed_imports.is_empty() {
100 let range = ctx.sema.original_range(import_assets.syntax_under_caret()).range;
101 let group = import_group_message(import_assets.import_candidate());
103 ImportScope::find_insert_use_container(import_assets.syntax_under_caret(), &ctx.sema)?;
104 for (import, _) in proposed_imports {
107 AssistId("auto_import", AssistKind::QuickFix),
108 format!("Import `{}`", &import),
112 insert_use(&scope, mod_path_to_ast(&import), ctx.config.insert_use.merge);
113 builder.rewrite(rewriter);
120 fn 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)
126 ImportCandidate::TraitMethod(candidate) => {
127 format!("Import a trait for method {}", &candidate.name)
136 use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target};
139 fn applicable_when_found_an_import_partial() {
145 pub struct Formatter;
156 pub struct Formatter;
160 use std::fmt::{self, Formatter};
168 fn applicable_when_found_an_import() {
175 pub struct PubStruct;
179 use PubMod::PubStruct;
184 pub struct PubStruct;
191 fn applicable_when_found_an_import_in_macros() {
196 ($i:ident) => { fn foo(a: $i) {} }
201 pub struct PubStruct;
205 use PubMod::PubStruct;
208 ($i:ident) => { fn foo(a: $i) {} }
213 pub struct PubStruct;
220 fn auto_imports_are_merged() {
224 use PubMod::PubStruct1;
227 test: Pub$0Struct2<u8>,
231 pub struct PubStruct1;
232 pub struct PubStruct2<T> {
238 use PubMod::{PubStruct1, PubStruct2};
241 test: PubStruct2<u8>,
245 pub struct PubStruct1;
246 pub struct PubStruct2<T> {
255 fn applicable_when_found_multiple_imports() {
262 pub struct PubStruct;
265 pub struct PubStruct;
268 pub struct PubStruct;
272 use PubMod3::PubStruct;
277 pub struct PubStruct;
280 pub struct PubStruct;
283 pub struct PubStruct;
290 fn not_applicable_for_already_imported_types() {
291 check_assist_not_applicable(
294 use PubMod::PubStruct;
299 pub struct PubStruct;
306 fn not_applicable_for_types_with_private_paths() {
307 check_assist_not_applicable(
313 struct PrivateStruct;
320 fn not_applicable_when_no_imports_found() {
321 check_assist_not_applicable(
329 fn not_applicable_in_import_statements() {
330 check_assist_not_applicable(
336 pub struct PubStruct;
342 fn function_import() {
349 pub fn test_function() {};
353 use PubMod::test_function;
358 pub fn test_function() {};
369 //- /lib.rs crate:crate_with_macro
375 //- /main.rs crate:main deps:crate_with_macro
380 r"use crate_with_macro::foo;
390 fn auto_import_target() {
395 group_label: Option<$0GroupLabel>,
398 mod m { pub struct GroupLabel; }
405 fn not_applicable_when_path_start_is_imported() {
406 check_assist_not_applicable(
412 pub struct TestStruct;
419 mod2::mod3::TestStruct$0
426 fn not_applicable_for_imported_function() {
427 check_assist_not_applicable(
431 pub fn test_function() {}
434 use test_mod::test_function;
443 fn associated_struct_function() {
448 pub struct TestStruct {}
450 pub fn test_function() {}
455 TestStruct::test_function$0
459 use test_mod::TestStruct;
462 pub struct TestStruct {}
464 pub fn test_function() {}
469 TestStruct::test_function
476 fn associated_struct_const() {
481 pub struct TestStruct {}
483 const TEST_CONST: u8 = 42;
488 TestStruct::TEST_CONST$0
492 use test_mod::TestStruct;
495 pub struct TestStruct {}
497 const TEST_CONST: u8 = 42;
502 TestStruct::TEST_CONST
509 fn associated_trait_function() {
514 pub trait TestTrait {
517 pub struct TestStruct {}
518 impl TestTrait for TestStruct {
519 fn test_function() {}
524 test_mod::TestStruct::test_function$0
528 use test_mod::TestTrait;
531 pub trait TestTrait {
534 pub struct TestStruct {}
535 impl TestTrait for TestStruct {
536 fn test_function() {}
541 test_mod::TestStruct::test_function
548 fn not_applicable_for_imported_trait_for_function() {
549 check_assist_not_applicable(
553 pub trait TestTrait {
556 pub trait TestTrait2 {
563 impl TestTrait2 for TestEnum {
564 fn test_function() {}
566 impl TestTrait for TestEnum {
567 fn test_function() {}
571 use test_mod::TestTrait2;
573 test_mod::TestEnum::test_function$0;
580 fn associated_trait_const() {
585 pub trait TestTrait {
586 const TEST_CONST: u8;
588 pub struct TestStruct {}
589 impl TestTrait for TestStruct {
590 const TEST_CONST: u8 = 42;
595 test_mod::TestStruct::TEST_CONST$0
599 use test_mod::TestTrait;
602 pub trait TestTrait {
603 const TEST_CONST: u8;
605 pub struct TestStruct {}
606 impl TestTrait for TestStruct {
607 const TEST_CONST: u8 = 42;
612 test_mod::TestStruct::TEST_CONST
619 fn not_applicable_for_imported_trait_for_const() {
620 check_assist_not_applicable(
624 pub trait TestTrait {
625 const TEST_CONST: u8;
627 pub trait TestTrait2 {
628 const TEST_CONST: f64;
634 impl TestTrait2 for TestEnum {
635 const TEST_CONST: f64 = 42.0;
637 impl TestTrait for TestEnum {
638 const TEST_CONST: u8 = 42;
642 use test_mod::TestTrait2;
644 test_mod::TestEnum::TEST_CONST$0;
656 pub trait TestTrait {
657 fn test_method(&self);
659 pub struct TestStruct {}
660 impl TestTrait for TestStruct {
661 fn test_method(&self) {}
666 let test_struct = test_mod::TestStruct {};
667 test_struct.test_meth$0od()
671 use test_mod::TestTrait;
674 pub trait TestTrait {
675 fn test_method(&self);
677 pub struct TestStruct {}
678 impl TestTrait for TestStruct {
679 fn test_method(&self) {}
684 let test_struct = test_mod::TestStruct {};
685 test_struct.test_method()
692 fn trait_method_cross_crate() {
696 //- /main.rs crate:main deps:dep
698 let test_struct = dep::test_mod::TestStruct {};
699 test_struct.test_meth$0od()
701 //- /dep.rs crate:dep
703 pub trait TestTrait {
704 fn test_method(&self);
706 pub struct TestStruct {}
707 impl TestTrait for TestStruct {
708 fn test_method(&self) {}
713 use dep::test_mod::TestTrait;
716 let test_struct = dep::test_mod::TestStruct {};
717 test_struct.test_method()
724 fn assoc_fn_cross_crate() {
728 //- /main.rs crate:main deps:dep
730 dep::test_mod::TestStruct::test_func$0tion
732 //- /dep.rs crate:dep
734 pub trait TestTrait {
737 pub struct TestStruct {}
738 impl TestTrait for TestStruct {
739 fn test_function() {}
744 use dep::test_mod::TestTrait;
747 dep::test_mod::TestStruct::test_function
754 fn assoc_const_cross_crate() {
758 //- /main.rs crate:main deps:dep
760 dep::test_mod::TestStruct::CONST$0
762 //- /dep.rs crate:dep
764 pub trait TestTrait {
767 pub struct TestStruct {}
768 impl TestTrait for TestStruct {
769 const CONST: bool = true;
774 use dep::test_mod::TestTrait;
777 dep::test_mod::TestStruct::CONST
784 fn assoc_fn_as_method_cross_crate() {
785 check_assist_not_applicable(
788 //- /main.rs crate:main deps:dep
790 let test_struct = dep::test_mod::TestStruct {};
791 test_struct.test_func$0tion()
793 //- /dep.rs crate:dep
795 pub trait TestTrait {
798 pub struct TestStruct {}
799 impl TestTrait for TestStruct {
800 fn test_function() {}
808 fn private_trait_cross_crate() {
809 check_assist_not_applicable(
812 //- /main.rs crate:main deps:dep
814 let test_struct = dep::test_mod::TestStruct {};
815 test_struct.test_meth$0od()
817 //- /dep.rs crate:dep
820 fn test_method(&self);
822 pub struct TestStruct {}
823 impl TestTrait for TestStruct {
824 fn test_method(&self) {}
832 fn not_applicable_for_imported_trait_for_method() {
833 check_assist_not_applicable(
837 pub trait TestTrait {
838 fn test_method(&self);
840 pub trait TestTrait2 {
841 fn test_method(&self);
847 impl TestTrait2 for TestEnum {
848 fn test_method(&self) {}
850 impl TestTrait for TestEnum {
851 fn test_method(&self) {}
855 use test_mod::TestTrait2;
857 let one = test_mod::TestEnum::One;
869 //- /lib.rs crate:dep
872 //- /main.rs crate:main deps:dep
888 // Tests that only imports whose last segment matches the identifier get suggested.
892 //- /lib.rs crate:dep
897 pub fn panic_fmt() {}
899 //- /main.rs crate:main deps:dep
902 impl f$0mt::Display for S {}
908 impl fmt::Display for S {}
914 fn macro_generated() {
915 // Tests that macro-generated items are suggested from external crates.
919 //- /lib.rs crate:dep
928 //- /main.rs crate:main deps:dep
944 // Tests that differently cased names don't interfere and we only suggest the matching one.
948 //- /lib.rs crate:dep
952 //- /main.rs crate:main deps:dep