2 helpers::mod_path_to_ast,
4 import_assets::{ImportAssets, ImportCandidate},
5 insert_use::{insert_use, ImportScope},
8 use syntax::{ast, AstNode, NodeOrToken, SyntaxElement};
10 use crate::{AssistContext, AssistId, AssistKind, Assists, GroupLabel};
12 // Feature: Auto Import
14 // Using the `auto-import` assist it is possible to insert missing imports for unresolved items.
15 // When inserting an import it will do so in a structured manner by keeping imports grouped,
16 // separated by a newline in the following order:
20 // - Current Crate, paths prefixed by `crate`
21 // - Current Module, paths prefixed by `self`
22 // - Super Module, paths prefixed by `super`
28 // use itertools::Itertools;
31 // use crate::utils::insert_use;
33 // use self::auto_import;
35 // use super::AssistContext;
38 // .Import Granularity
40 // It is possible to configure how use-trees are merged with the `importGranularity` setting.
41 // It has the following configurations:
43 // - `crate`: Merge imports from the same crate into a single use statement. This kind of
44 // nesting is only supported in Rust versions later than 1.24.
45 // - `module`: Merge imports from the same module into a single use statement.
46 // - `item`: Don't merge imports at all, creating one import per item.
47 // - `preserve`: Do not change the granularity of any imports. For auto-import this has the same
50 // In `VS Code` the configuration for this is `rust-analyzer.assist.importGranularity`.
54 // The style of imports in the same crate is configurable through the `importPrefix` setting.
55 // It has the following configurations:
57 // - `crate`: This setting will force paths to be always absolute, starting with the `crate`
58 // prefix, unless the item is defined outside of the current crate.
59 // - `self`: This setting will force paths that are relative to the current module to always
60 // start with `self`. This will result in paths that always start with either `crate`, `self`,
61 // `super` or an extern crate identifier.
62 // - `plain`: This setting does not impose any restrictions in imports.
64 // In `VS Code` the configuration for this is `rust-analyzer.assist.importPrefix`.
66 // image::https://user-images.githubusercontent.com/48062697/113020673-b85be580-917a-11eb-9022-59585f35d4f8.gif[]
68 // Assist: auto_import
70 // If the name is unresolved, provides all possible imports for it.
74 // let map = HashMap$0::new();
76 // # pub mod std { pub mod collections { pub struct HashMap { } } }
80 // use std::collections::HashMap;
83 // let map = HashMap::new();
85 // # pub mod std { pub mod collections { pub struct HashMap { } } }
87 pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
88 let (import_assets, syntax_under_caret) = find_importable_node(ctx)?;
89 let mut proposed_imports =
90 import_assets.search_for_imports(&ctx.sema, ctx.config.insert_use.prefix_kind);
91 if proposed_imports.is_empty() {
95 let range = match &syntax_under_caret {
96 NodeOrToken::Node(node) => ctx.sema.original_range(node).range,
97 NodeOrToken::Token(token) => token.text_range(),
99 let group_label = group_label(import_assets.import_candidate());
100 let scope = ImportScope::find_insert_use_container(
101 &match syntax_under_caret {
102 NodeOrToken::Node(it) => it,
103 NodeOrToken::Token(it) => it.parent()?,
108 // we aren't interested in different namespaces
109 proposed_imports.dedup_by(|a, b| a.import_path == b.import_path);
110 for import in proposed_imports {
113 AssistId("auto_import", AssistKind::QuickFix),
114 format!("Import `{}`", import.import_path),
117 let scope = match scope.clone() {
118 ImportScope::File(it) => ImportScope::File(builder.make_mut(it)),
119 ImportScope::Module(it) => ImportScope::Module(builder.make_mut(it)),
120 ImportScope::Block(it) => ImportScope::Block(builder.make_mut(it)),
122 insert_use(&scope, mod_path_to_ast(&import.import_path), &ctx.config.insert_use);
129 pub(super) fn find_importable_node(ctx: &AssistContext) -> Option<(ImportAssets, SyntaxElement)> {
130 if let Some(path_under_caret) = ctx.find_node_at_offset_with_descend::<ast::Path>() {
131 ImportAssets::for_exact_path(&path_under_caret, &ctx.sema)
132 .zip(Some(path_under_caret.syntax().clone().into()))
133 } else if let Some(method_under_caret) =
134 ctx.find_node_at_offset_with_descend::<ast::MethodCallExpr>()
136 ImportAssets::for_method_call(&method_under_caret, &ctx.sema)
137 .zip(Some(method_under_caret.syntax().clone().into()))
138 } else if let Some(pat) = ctx
139 .find_node_at_offset_with_descend::<ast::IdentPat>()
140 .filter(ast::IdentPat::is_simple_ident)
142 ImportAssets::for_ident_pat(&ctx.sema, &pat).zip(Some(pat.syntax().clone().into()))
148 fn group_label(import_candidate: &ImportCandidate) -> GroupLabel {
149 let name = match import_candidate {
150 ImportCandidate::Path(candidate) => format!("Import {}", candidate.name.text()),
151 ImportCandidate::TraitAssocItem(candidate) => {
152 format!("Import a trait for item {}", candidate.assoc_item_name.text())
154 ImportCandidate::TraitMethod(candidate) => {
155 format!("Import a trait for method {}", candidate.assoc_item_name.text())
165 use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target};
168 fn not_applicable_if_scope_inside_macro() {
169 check_assist_not_applicable(
190 fn applicable_in_attributes() {
194 //- proc_macros: identity
195 #[proc_macros::identity]
206 #[proc_macros::identity]
222 fn applicable_when_found_an_import_partial() {
228 pub struct Formatter;
239 pub struct Formatter;
243 use std::fmt::{self, Formatter};
251 fn applicable_when_found_an_import() {
258 pub struct PubStruct;
262 use PubMod::PubStruct;
267 pub struct PubStruct;
274 fn applicable_when_found_an_import_in_macros() {
279 ($i:ident) => { fn foo(a: $i) {} }
284 pub struct PubStruct;
288 use PubMod::PubStruct;
291 ($i:ident) => { fn foo(a: $i) {} }
296 pub struct PubStruct;
303 fn applicable_when_found_multiple_imports() {
310 pub struct PubStruct;
313 pub struct PubStruct;
316 pub struct PubStruct;
320 use PubMod3::PubStruct;
325 pub struct PubStruct;
328 pub struct PubStruct;
331 pub struct PubStruct;
338 fn not_applicable_for_already_imported_types() {
339 check_assist_not_applicable(
342 use PubMod::PubStruct;
347 pub struct PubStruct;
354 fn not_applicable_for_types_with_private_paths() {
355 check_assist_not_applicable(
361 struct PrivateStruct;
368 fn not_applicable_when_no_imports_found() {
369 check_assist_not_applicable(
377 fn function_import() {
384 pub fn test_function() {};
388 use PubMod::test_function;
393 pub fn test_function() {};
404 //- /lib.rs crate:crate_with_macro
410 //- /main.rs crate:main deps:crate_with_macro
415 r"use crate_with_macro::foo;
425 fn auto_import_target() {
430 group_label: Option<$0GroupLabel>,
433 mod m { pub struct GroupLabel; }
440 fn not_applicable_when_path_start_is_imported() {
441 check_assist_not_applicable(
447 pub struct TestStruct;
454 mod2::mod3::TestStruct$0
461 fn not_applicable_for_imported_function() {
462 check_assist_not_applicable(
466 pub fn test_function() {}
469 use test_mod::test_function;
478 fn associated_struct_function() {
483 pub struct TestStruct {}
485 pub fn test_function() {}
490 TestStruct::test_function$0
494 use test_mod::TestStruct;
497 pub struct TestStruct {}
499 pub fn test_function() {}
504 TestStruct::test_function
511 fn associated_struct_const() {
516 pub struct TestStruct {}
518 const TEST_CONST: u8 = 42;
523 TestStruct::TEST_CONST$0
527 use test_mod::TestStruct;
530 pub struct TestStruct {}
532 const TEST_CONST: u8 = 42;
537 TestStruct::TEST_CONST
544 fn associated_trait_function() {
549 pub trait TestTrait {
552 pub struct TestStruct {}
553 impl TestTrait for TestStruct {
554 fn test_function() {}
559 test_mod::TestStruct::test_function$0
563 use test_mod::TestTrait;
566 pub trait TestTrait {
569 pub struct TestStruct {}
570 impl TestTrait for TestStruct {
571 fn test_function() {}
576 test_mod::TestStruct::test_function
583 fn not_applicable_for_imported_trait_for_function() {
584 check_assist_not_applicable(
588 pub trait TestTrait {
591 pub trait TestTrait2 {
598 impl TestTrait2 for TestEnum {
599 fn test_function() {}
601 impl TestTrait for TestEnum {
602 fn test_function() {}
606 use test_mod::TestTrait2;
608 test_mod::TestEnum::test_function$0;
615 fn associated_trait_const() {
620 pub trait TestTrait {
621 const TEST_CONST: u8;
623 pub struct TestStruct {}
624 impl TestTrait for TestStruct {
625 const TEST_CONST: u8 = 42;
630 test_mod::TestStruct::TEST_CONST$0
634 use test_mod::TestTrait;
637 pub trait TestTrait {
638 const TEST_CONST: u8;
640 pub struct TestStruct {}
641 impl TestTrait for TestStruct {
642 const TEST_CONST: u8 = 42;
647 test_mod::TestStruct::TEST_CONST
654 fn not_applicable_for_imported_trait_for_const() {
655 check_assist_not_applicable(
659 pub trait TestTrait {
660 const TEST_CONST: u8;
662 pub trait TestTrait2 {
663 const TEST_CONST: f64;
669 impl TestTrait2 for TestEnum {
670 const TEST_CONST: f64 = 42.0;
672 impl TestTrait for TestEnum {
673 const TEST_CONST: u8 = 42;
677 use test_mod::TestTrait2;
679 test_mod::TestEnum::TEST_CONST$0;
691 pub trait TestTrait {
692 fn test_method(&self);
694 pub struct TestStruct {}
695 impl TestTrait for TestStruct {
696 fn test_method(&self) {}
701 let test_struct = test_mod::TestStruct {};
702 test_struct.test_meth$0od()
706 use test_mod::TestTrait;
709 pub trait TestTrait {
710 fn test_method(&self);
712 pub struct TestStruct {}
713 impl TestTrait for TestStruct {
714 fn test_method(&self) {}
719 let test_struct = test_mod::TestStruct {};
720 test_struct.test_method()
727 fn trait_method_cross_crate() {
731 //- /main.rs crate:main deps:dep
733 let test_struct = dep::test_mod::TestStruct {};
734 test_struct.test_meth$0od()
736 //- /dep.rs crate:dep
738 pub trait TestTrait {
739 fn test_method(&self);
741 pub struct TestStruct {}
742 impl TestTrait for TestStruct {
743 fn test_method(&self) {}
748 use dep::test_mod::TestTrait;
751 let test_struct = dep::test_mod::TestStruct {};
752 test_struct.test_method()
759 fn assoc_fn_cross_crate() {
763 //- /main.rs crate:main deps:dep
765 dep::test_mod::TestStruct::test_func$0tion
767 //- /dep.rs crate:dep
769 pub trait TestTrait {
772 pub struct TestStruct {}
773 impl TestTrait for TestStruct {
774 fn test_function() {}
779 use dep::test_mod::TestTrait;
782 dep::test_mod::TestStruct::test_function
789 fn assoc_const_cross_crate() {
793 //- /main.rs crate:main deps:dep
795 dep::test_mod::TestStruct::CONST$0
797 //- /dep.rs crate:dep
799 pub trait TestTrait {
802 pub struct TestStruct {}
803 impl TestTrait for TestStruct {
804 const CONST: bool = true;
809 use dep::test_mod::TestTrait;
812 dep::test_mod::TestStruct::CONST
819 fn assoc_fn_as_method_cross_crate() {
820 check_assist_not_applicable(
823 //- /main.rs crate:main deps:dep
825 let test_struct = dep::test_mod::TestStruct {};
826 test_struct.test_func$0tion()
828 //- /dep.rs crate:dep
830 pub trait TestTrait {
833 pub struct TestStruct {}
834 impl TestTrait for TestStruct {
835 fn test_function() {}
843 fn private_trait_cross_crate() {
844 check_assist_not_applicable(
847 //- /main.rs crate:main deps:dep
849 let test_struct = dep::test_mod::TestStruct {};
850 test_struct.test_meth$0od()
852 //- /dep.rs crate:dep
855 fn test_method(&self);
857 pub struct TestStruct {}
858 impl TestTrait for TestStruct {
859 fn test_method(&self) {}
867 fn not_applicable_for_imported_trait_for_method() {
868 check_assist_not_applicable(
872 pub trait TestTrait {
873 fn test_method(&self);
875 pub trait TestTrait2 {
876 fn test_method(&self);
882 impl TestTrait2 for TestEnum {
883 fn test_method(&self) {}
885 impl TestTrait for TestEnum {
886 fn test_method(&self) {}
890 use test_mod::TestTrait2;
892 let one = test_mod::TestEnum::One;
904 //- /lib.rs crate:dep
907 //- /main.rs crate:main deps:dep
923 // Tests that only imports whose last segment matches the identifier get suggested.
927 //- /lib.rs crate:dep
932 pub fn panic_fmt() {}
934 //- /main.rs crate:main deps:dep
937 impl f$0mt::Display for S {}
943 impl fmt::Display for S {}
949 fn macro_generated() {
950 // Tests that macro-generated items are suggested from external crates.
954 //- /lib.rs crate:dep
963 //- /main.rs crate:main deps:dep
979 // Tests that differently cased names don't interfere and we only suggest the matching one.
983 //- /lib.rs crate:dep
987 //- /main.rs crate:main deps:dep
1023 use crate::baz::Foo;
1035 fn uses_abs_path_with_extern_crate_clash() {
1036 cov_mark::check!(ambiguous_crate_start);
1040 //- /main.rs crate:main deps:foo
1046 //- /foo.rs crate:foo
1062 fn works_on_ident_patterns() {
1087 fn works_in_derives() {
1093 #[rustc_builtin_macro]
1103 #[rustc_builtin_macro]
1113 fn works_in_use_start() {
1137 fn not_applicable_in_non_start_use() {
1138 check_assist_not_applicable(