2 import_assets::{ImportAssets, ImportCandidate},
3 insert_use::{insert_use, ImportScope},
6 use syntax::{ast, AstNode, SyntaxNode};
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;
36 // .Import Granularity
38 // It is possible to configure how use-trees are merged with the `importGranularity` setting.
39 // It has the following configurations:
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
48 // In `VS Code` the configuration for this is `rust-analyzer.assist.importGranularity`.
52 // The style of imports in the same crate is configurable through the `importPrefix` setting.
53 // It has the following configurations:
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.
62 // In `VS Code` the configuration for this is `rust-analyzer.assist.importPrefix`.
64 // image::https://user-images.githubusercontent.com/48062697/113020673-b85be580-917a-11eb-9022-59585f35d4f8.gif[]
66 // Assist: auto_import
68 // If the name is unresolved, provides all possible imports for it.
72 // let map = HashMap$0::new();
74 // # pub mod std { pub mod collections { pub struct HashMap { } } }
78 // use std::collections::HashMap;
81 // let map = HashMap::new();
83 // # pub mod std { pub mod collections { pub struct HashMap { } } }
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 proposed_imports =
88 import_assets.search_for_imports(&ctx.sema, ctx.config.insert_use.prefix_kind);
89 if proposed_imports.is_empty() {
93 let range = ctx.sema.original_range(&syntax_under_caret).range;
94 let group_label = group_label(import_assets.import_candidate());
95 let scope = ImportScope::find_insert_use_container_with_macros(&syntax_under_caret, &ctx.sema)?;
96 for import in proposed_imports {
99 AssistId("auto_import", AssistKind::QuickFix),
100 format!("Import `{}`", import.import_path),
103 let scope = match scope.clone() {
104 ImportScope::File(it) => ImportScope::File(builder.make_mut(it)),
105 ImportScope::Module(it) => ImportScope::Module(builder.make_mut(it)),
107 insert_use(&scope, mod_path_to_ast(&import.import_path), &ctx.config.insert_use);
114 pub(super) fn find_importable_node(ctx: &AssistContext) -> Option<(ImportAssets, SyntaxNode)> {
115 if let Some(path_under_caret) = ctx.find_node_at_offset_with_descend::<ast::Path>() {
116 ImportAssets::for_exact_path(&path_under_caret, &ctx.sema)
117 .zip(Some(path_under_caret.syntax().clone()))
118 } else if let Some(method_under_caret) =
119 ctx.find_node_at_offset_with_descend::<ast::MethodCallExpr>()
121 ImportAssets::for_method_call(&method_under_caret, &ctx.sema)
122 .zip(Some(method_under_caret.syntax().clone()))
128 fn group_label(import_candidate: &ImportCandidate) -> GroupLabel {
129 let name = match import_candidate {
130 ImportCandidate::Path(candidate) => format!("Import {}", candidate.name.text()),
131 ImportCandidate::TraitAssocItem(candidate) => {
132 format!("Import a trait for item {}", candidate.assoc_item_name.text())
134 ImportCandidate::TraitMethod(candidate) => {
135 format!("Import a trait for method {}", candidate.assoc_item_name.text())
144 use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target};
147 fn applicable_when_found_an_import_partial() {
153 pub struct Formatter;
164 pub struct Formatter;
168 use std::fmt::{self, Formatter};
176 fn applicable_when_found_an_import() {
183 pub struct PubStruct;
187 use PubMod::PubStruct;
192 pub struct PubStruct;
199 fn applicable_when_found_an_import_in_macros() {
204 ($i:ident) => { fn foo(a: $i) {} }
209 pub struct PubStruct;
213 use PubMod::PubStruct;
216 ($i:ident) => { fn foo(a: $i) {} }
221 pub struct PubStruct;
228 fn applicable_when_found_multiple_imports() {
235 pub struct PubStruct;
238 pub struct PubStruct;
241 pub struct PubStruct;
245 use PubMod3::PubStruct;
250 pub struct PubStruct;
253 pub struct PubStruct;
256 pub struct PubStruct;
263 fn not_applicable_for_already_imported_types() {
264 check_assist_not_applicable(
267 use PubMod::PubStruct;
272 pub struct PubStruct;
279 fn not_applicable_for_types_with_private_paths() {
280 check_assist_not_applicable(
286 struct PrivateStruct;
293 fn not_applicable_when_no_imports_found() {
294 check_assist_not_applicable(
302 fn not_applicable_in_import_statements() {
303 check_assist_not_applicable(
309 pub struct PubStruct;
315 fn function_import() {
322 pub fn test_function() {};
326 use PubMod::test_function;
331 pub fn test_function() {};
342 //- /lib.rs crate:crate_with_macro
348 //- /main.rs crate:main deps:crate_with_macro
353 r"use crate_with_macro::foo;
363 fn auto_import_target() {
368 group_label: Option<$0GroupLabel>,
371 mod m { pub struct GroupLabel; }
378 fn not_applicable_when_path_start_is_imported() {
379 check_assist_not_applicable(
385 pub struct TestStruct;
392 mod2::mod3::TestStruct$0
399 fn not_applicable_for_imported_function() {
400 check_assist_not_applicable(
404 pub fn test_function() {}
407 use test_mod::test_function;
416 fn associated_struct_function() {
421 pub struct TestStruct {}
423 pub fn test_function() {}
428 TestStruct::test_function$0
432 use test_mod::TestStruct;
435 pub struct TestStruct {}
437 pub fn test_function() {}
442 TestStruct::test_function
449 fn associated_struct_const() {
454 pub struct TestStruct {}
456 const TEST_CONST: u8 = 42;
461 TestStruct::TEST_CONST$0
465 use test_mod::TestStruct;
468 pub struct TestStruct {}
470 const TEST_CONST: u8 = 42;
475 TestStruct::TEST_CONST
482 fn associated_trait_function() {
487 pub trait TestTrait {
490 pub struct TestStruct {}
491 impl TestTrait for TestStruct {
492 fn test_function() {}
497 test_mod::TestStruct::test_function$0
501 use test_mod::TestTrait;
504 pub trait TestTrait {
507 pub struct TestStruct {}
508 impl TestTrait for TestStruct {
509 fn test_function() {}
514 test_mod::TestStruct::test_function
521 fn not_applicable_for_imported_trait_for_function() {
522 check_assist_not_applicable(
526 pub trait TestTrait {
529 pub trait TestTrait2 {
536 impl TestTrait2 for TestEnum {
537 fn test_function() {}
539 impl TestTrait for TestEnum {
540 fn test_function() {}
544 use test_mod::TestTrait2;
546 test_mod::TestEnum::test_function$0;
553 fn associated_trait_const() {
558 pub trait TestTrait {
559 const TEST_CONST: u8;
561 pub struct TestStruct {}
562 impl TestTrait for TestStruct {
563 const TEST_CONST: u8 = 42;
568 test_mod::TestStruct::TEST_CONST$0
572 use test_mod::TestTrait;
575 pub trait TestTrait {
576 const TEST_CONST: u8;
578 pub struct TestStruct {}
579 impl TestTrait for TestStruct {
580 const TEST_CONST: u8 = 42;
585 test_mod::TestStruct::TEST_CONST
592 fn not_applicable_for_imported_trait_for_const() {
593 check_assist_not_applicable(
597 pub trait TestTrait {
598 const TEST_CONST: u8;
600 pub trait TestTrait2 {
601 const TEST_CONST: f64;
607 impl TestTrait2 for TestEnum {
608 const TEST_CONST: f64 = 42.0;
610 impl TestTrait for TestEnum {
611 const TEST_CONST: u8 = 42;
615 use test_mod::TestTrait2;
617 test_mod::TestEnum::TEST_CONST$0;
629 pub trait TestTrait {
630 fn test_method(&self);
632 pub struct TestStruct {}
633 impl TestTrait for TestStruct {
634 fn test_method(&self) {}
639 let test_struct = test_mod::TestStruct {};
640 test_struct.test_meth$0od()
644 use test_mod::TestTrait;
647 pub trait TestTrait {
648 fn test_method(&self);
650 pub struct TestStruct {}
651 impl TestTrait for TestStruct {
652 fn test_method(&self) {}
657 let test_struct = test_mod::TestStruct {};
658 test_struct.test_method()
665 fn trait_method_cross_crate() {
669 //- /main.rs crate:main deps:dep
671 let test_struct = dep::test_mod::TestStruct {};
672 test_struct.test_meth$0od()
674 //- /dep.rs crate:dep
676 pub trait TestTrait {
677 fn test_method(&self);
679 pub struct TestStruct {}
680 impl TestTrait for TestStruct {
681 fn test_method(&self) {}
686 use dep::test_mod::TestTrait;
689 let test_struct = dep::test_mod::TestStruct {};
690 test_struct.test_method()
697 fn assoc_fn_cross_crate() {
701 //- /main.rs crate:main deps:dep
703 dep::test_mod::TestStruct::test_func$0tion
705 //- /dep.rs crate:dep
707 pub trait TestTrait {
710 pub struct TestStruct {}
711 impl TestTrait for TestStruct {
712 fn test_function() {}
717 use dep::test_mod::TestTrait;
720 dep::test_mod::TestStruct::test_function
727 fn assoc_const_cross_crate() {
731 //- /main.rs crate:main deps:dep
733 dep::test_mod::TestStruct::CONST$0
735 //- /dep.rs crate:dep
737 pub trait TestTrait {
740 pub struct TestStruct {}
741 impl TestTrait for TestStruct {
742 const CONST: bool = true;
747 use dep::test_mod::TestTrait;
750 dep::test_mod::TestStruct::CONST
757 fn assoc_fn_as_method_cross_crate() {
758 check_assist_not_applicable(
761 //- /main.rs crate:main deps:dep
763 let test_struct = dep::test_mod::TestStruct {};
764 test_struct.test_func$0tion()
766 //- /dep.rs crate:dep
768 pub trait TestTrait {
771 pub struct TestStruct {}
772 impl TestTrait for TestStruct {
773 fn test_function() {}
781 fn private_trait_cross_crate() {
782 check_assist_not_applicable(
785 //- /main.rs crate:main deps:dep
787 let test_struct = dep::test_mod::TestStruct {};
788 test_struct.test_meth$0od()
790 //- /dep.rs crate:dep
793 fn test_method(&self);
795 pub struct TestStruct {}
796 impl TestTrait for TestStruct {
797 fn test_method(&self) {}
805 fn not_applicable_for_imported_trait_for_method() {
806 check_assist_not_applicable(
810 pub trait TestTrait {
811 fn test_method(&self);
813 pub trait TestTrait2 {
814 fn test_method(&self);
820 impl TestTrait2 for TestEnum {
821 fn test_method(&self) {}
823 impl TestTrait for TestEnum {
824 fn test_method(&self) {}
828 use test_mod::TestTrait2;
830 let one = test_mod::TestEnum::One;
842 //- /lib.rs crate:dep
845 //- /main.rs crate:main deps:dep
861 // Tests that only imports whose last segment matches the identifier get suggested.
865 //- /lib.rs crate:dep
870 pub fn panic_fmt() {}
872 //- /main.rs crate:main deps:dep
875 impl f$0mt::Display for S {}
881 impl fmt::Display for S {}
887 fn macro_generated() {
888 // Tests that macro-generated items are suggested from external crates.
892 //- /lib.rs crate:dep
901 //- /main.rs crate:main deps:dep
917 // Tests that differently cased names don't interfere and we only suggest the matching one.
921 //- /lib.rs crate:dep
925 //- /main.rs crate:main deps:dep
973 fn uses_abs_path_with_extern_crate_clash() {
977 //- /main.rs crate:main deps:foo
983 //- /foo.rs crate:foo