2 import_assets::{ImportAssets, ImportCandidate},
3 insert_use::{insert_use, ImportScope},
6 use syntax::{ast, AstNode, AstToken, NodeOrToken, SyntaxElement};
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 mut 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 = match &syntax_under_caret {
94 NodeOrToken::Node(node) => ctx.sema.original_range(node).range,
95 NodeOrToken::Token(token) => token.text_range(),
97 let group_label = group_label(import_assets.import_candidate());
98 let scope = ImportScope::find_insert_use_container(
99 &match syntax_under_caret {
100 NodeOrToken::Node(it) => it,
101 NodeOrToken::Token(it) => it.parent()?,
106 // we aren't interested in different namespaces
107 proposed_imports.dedup_by(|a, b| a.import_path == b.import_path);
108 for import in proposed_imports {
111 AssistId("auto_import", AssistKind::QuickFix),
112 format!("Import `{}`", import.import_path),
115 let scope = match scope.clone() {
116 ImportScope::File(it) => ImportScope::File(builder.make_mut(it)),
117 ImportScope::Module(it) => ImportScope::Module(builder.make_mut(it)),
118 ImportScope::Block(it) => ImportScope::Block(builder.make_mut(it)),
120 insert_use(&scope, mod_path_to_ast(&import.import_path), &ctx.config.insert_use);
127 pub(super) fn find_importable_node(ctx: &AssistContext) -> Option<(ImportAssets, SyntaxElement)> {
128 if let Some(path_under_caret) = ctx.find_node_at_offset_with_descend::<ast::Path>() {
129 ImportAssets::for_exact_path(&path_under_caret, &ctx.sema)
130 .zip(Some(path_under_caret.syntax().clone().into()))
131 } else if let Some(method_under_caret) =
132 ctx.find_node_at_offset_with_descend::<ast::MethodCallExpr>()
134 ImportAssets::for_method_call(&method_under_caret, &ctx.sema)
135 .zip(Some(method_under_caret.syntax().clone().into()))
136 } else if let Some(pat) = ctx
137 .find_node_at_offset_with_descend::<ast::IdentPat>()
138 .filter(ast::IdentPat::is_simple_ident)
140 ImportAssets::for_ident_pat(&ctx.sema, &pat).zip(Some(pat.syntax().clone().into()))
143 let ident = ctx.find_token_at_offset()?;
144 ImportAssets::for_derive_ident(&ctx.sema, &ident).zip(Some(ident.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 not_applicable_in_import_statements() {
378 check_assist_not_applicable(
384 pub struct PubStruct;
390 fn function_import() {
397 pub fn test_function() {};
401 use PubMod::test_function;
406 pub fn test_function() {};
417 //- /lib.rs crate:crate_with_macro
423 //- /main.rs crate:main deps:crate_with_macro
428 r"use crate_with_macro::foo;
438 fn auto_import_target() {
443 group_label: Option<$0GroupLabel>,
446 mod m { pub struct GroupLabel; }
453 fn not_applicable_when_path_start_is_imported() {
454 check_assist_not_applicable(
460 pub struct TestStruct;
467 mod2::mod3::TestStruct$0
474 fn not_applicable_for_imported_function() {
475 check_assist_not_applicable(
479 pub fn test_function() {}
482 use test_mod::test_function;
491 fn associated_struct_function() {
496 pub struct TestStruct {}
498 pub fn test_function() {}
503 TestStruct::test_function$0
507 use test_mod::TestStruct;
510 pub struct TestStruct {}
512 pub fn test_function() {}
517 TestStruct::test_function
524 fn associated_struct_const() {
529 pub struct TestStruct {}
531 const TEST_CONST: u8 = 42;
536 TestStruct::TEST_CONST$0
540 use test_mod::TestStruct;
543 pub struct TestStruct {}
545 const TEST_CONST: u8 = 42;
550 TestStruct::TEST_CONST
557 fn associated_trait_function() {
562 pub trait TestTrait {
565 pub struct TestStruct {}
566 impl TestTrait for TestStruct {
567 fn test_function() {}
572 test_mod::TestStruct::test_function$0
576 use test_mod::TestTrait;
579 pub trait TestTrait {
582 pub struct TestStruct {}
583 impl TestTrait for TestStruct {
584 fn test_function() {}
589 test_mod::TestStruct::test_function
596 fn not_applicable_for_imported_trait_for_function() {
597 check_assist_not_applicable(
601 pub trait TestTrait {
604 pub trait TestTrait2 {
611 impl TestTrait2 for TestEnum {
612 fn test_function() {}
614 impl TestTrait for TestEnum {
615 fn test_function() {}
619 use test_mod::TestTrait2;
621 test_mod::TestEnum::test_function$0;
628 fn associated_trait_const() {
633 pub trait TestTrait {
634 const TEST_CONST: u8;
636 pub struct TestStruct {}
637 impl TestTrait for TestStruct {
638 const TEST_CONST: u8 = 42;
643 test_mod::TestStruct::TEST_CONST$0
647 use test_mod::TestTrait;
650 pub trait TestTrait {
651 const TEST_CONST: u8;
653 pub struct TestStruct {}
654 impl TestTrait for TestStruct {
655 const TEST_CONST: u8 = 42;
660 test_mod::TestStruct::TEST_CONST
667 fn not_applicable_for_imported_trait_for_const() {
668 check_assist_not_applicable(
672 pub trait TestTrait {
673 const TEST_CONST: u8;
675 pub trait TestTrait2 {
676 const TEST_CONST: f64;
682 impl TestTrait2 for TestEnum {
683 const TEST_CONST: f64 = 42.0;
685 impl TestTrait for TestEnum {
686 const TEST_CONST: u8 = 42;
690 use test_mod::TestTrait2;
692 test_mod::TestEnum::TEST_CONST$0;
704 pub trait TestTrait {
705 fn test_method(&self);
707 pub struct TestStruct {}
708 impl TestTrait for TestStruct {
709 fn test_method(&self) {}
714 let test_struct = test_mod::TestStruct {};
715 test_struct.test_meth$0od()
719 use test_mod::TestTrait;
722 pub trait TestTrait {
723 fn test_method(&self);
725 pub struct TestStruct {}
726 impl TestTrait for TestStruct {
727 fn test_method(&self) {}
732 let test_struct = test_mod::TestStruct {};
733 test_struct.test_method()
740 fn trait_method_cross_crate() {
744 //- /main.rs crate:main deps:dep
746 let test_struct = dep::test_mod::TestStruct {};
747 test_struct.test_meth$0od()
749 //- /dep.rs crate:dep
751 pub trait TestTrait {
752 fn test_method(&self);
754 pub struct TestStruct {}
755 impl TestTrait for TestStruct {
756 fn test_method(&self) {}
761 use dep::test_mod::TestTrait;
764 let test_struct = dep::test_mod::TestStruct {};
765 test_struct.test_method()
772 fn assoc_fn_cross_crate() {
776 //- /main.rs crate:main deps:dep
778 dep::test_mod::TestStruct::test_func$0tion
780 //- /dep.rs crate:dep
782 pub trait TestTrait {
785 pub struct TestStruct {}
786 impl TestTrait for TestStruct {
787 fn test_function() {}
792 use dep::test_mod::TestTrait;
795 dep::test_mod::TestStruct::test_function
802 fn assoc_const_cross_crate() {
806 //- /main.rs crate:main deps:dep
808 dep::test_mod::TestStruct::CONST$0
810 //- /dep.rs crate:dep
812 pub trait TestTrait {
815 pub struct TestStruct {}
816 impl TestTrait for TestStruct {
817 const CONST: bool = true;
822 use dep::test_mod::TestTrait;
825 dep::test_mod::TestStruct::CONST
832 fn assoc_fn_as_method_cross_crate() {
833 check_assist_not_applicable(
836 //- /main.rs crate:main deps:dep
838 let test_struct = dep::test_mod::TestStruct {};
839 test_struct.test_func$0tion()
841 //- /dep.rs crate:dep
843 pub trait TestTrait {
846 pub struct TestStruct {}
847 impl TestTrait for TestStruct {
848 fn test_function() {}
856 fn private_trait_cross_crate() {
857 check_assist_not_applicable(
860 //- /main.rs crate:main deps:dep
862 let test_struct = dep::test_mod::TestStruct {};
863 test_struct.test_meth$0od()
865 //- /dep.rs crate:dep
868 fn test_method(&self);
870 pub struct TestStruct {}
871 impl TestTrait for TestStruct {
872 fn test_method(&self) {}
880 fn not_applicable_for_imported_trait_for_method() {
881 check_assist_not_applicable(
885 pub trait TestTrait {
886 fn test_method(&self);
888 pub trait TestTrait2 {
889 fn test_method(&self);
895 impl TestTrait2 for TestEnum {
896 fn test_method(&self) {}
898 impl TestTrait for TestEnum {
899 fn test_method(&self) {}
903 use test_mod::TestTrait2;
905 let one = test_mod::TestEnum::One;
917 //- /lib.rs crate:dep
920 //- /main.rs crate:main deps:dep
936 // Tests that only imports whose last segment matches the identifier get suggested.
940 //- /lib.rs crate:dep
945 pub fn panic_fmt() {}
947 //- /main.rs crate:main deps:dep
950 impl f$0mt::Display for S {}
956 impl fmt::Display for S {}
962 fn macro_generated() {
963 // Tests that macro-generated items are suggested from external crates.
967 //- /lib.rs crate:dep
976 //- /main.rs crate:main deps:dep
992 // Tests that differently cased names don't interfere and we only suggest the matching one.
996 //- /lib.rs crate:dep
1000 //- /main.rs crate:main deps:dep
1036 use crate::baz::Foo;
1048 fn uses_abs_path_with_extern_crate_clash() {
1049 cov_mark::check!(ambiguous_crate_start);
1053 //- /main.rs crate:main deps:foo
1059 //- /foo.rs crate:foo
1075 fn works_on_ident_patterns() {
1100 fn works_in_derives() {
1106 #[rustc_builtin_macro]
1116 #[rustc_builtin_macro]