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 mut proposed_imports =
88 import_assets.search_for_imports(&ctx.sema, ctx.config.insert_use.prefix_kind);
89 if proposed_imports.is_empty() {
92 // we aren't interested in different namespaces
93 proposed_imports.dedup_by(|a, b| a.import_path == b.import_path);
95 let range = ctx.sema.original_range(&syntax_under_caret).range;
96 let group_label = group_label(import_assets.import_candidate());
97 let scope = ImportScope::find_insert_use_container_with_macros(&syntax_under_caret, &ctx.sema)?;
98 for import in proposed_imports {
101 AssistId("auto_import", AssistKind::QuickFix),
102 format!("Import `{}`", import.import_path),
105 let scope = match scope.clone() {
106 ImportScope::File(it) => ImportScope::File(builder.make_mut(it)),
107 ImportScope::Module(it) => ImportScope::Module(builder.make_mut(it)),
108 ImportScope::Block(it) => ImportScope::Block(builder.make_mut(it)),
110 insert_use(&scope, mod_path_to_ast(&import.import_path), &ctx.config.insert_use);
117 pub(super) fn find_importable_node(ctx: &AssistContext) -> Option<(ImportAssets, SyntaxNode)> {
118 if let Some(path_under_caret) = ctx.find_node_at_offset_with_descend::<ast::Path>() {
119 ImportAssets::for_exact_path(&path_under_caret, &ctx.sema)
120 .zip(Some(path_under_caret.syntax().clone()))
121 } else if let Some(method_under_caret) =
122 ctx.find_node_at_offset_with_descend::<ast::MethodCallExpr>()
124 ImportAssets::for_method_call(&method_under_caret, &ctx.sema)
125 .zip(Some(method_under_caret.syntax().clone()))
126 } else if let Some(pat) = ctx
127 .find_node_at_offset_with_descend::<ast::IdentPat>()
128 .filter(ast::IdentPat::is_simple_ident)
130 ImportAssets::for_ident_pat(&pat, &ctx.sema).zip(Some(pat.syntax().clone()))
136 fn group_label(import_candidate: &ImportCandidate) -> GroupLabel {
137 let name = match import_candidate {
138 ImportCandidate::Path(candidate) => format!("Import {}", candidate.name.text()),
139 ImportCandidate::TraitAssocItem(candidate) => {
140 format!("Import a trait for item {}", candidate.assoc_item_name.text())
142 ImportCandidate::TraitMethod(candidate) => {
143 format!("Import a trait for method {}", candidate.assoc_item_name.text())
153 use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target};
156 fn applicable_when_found_an_import_partial() {
162 pub struct Formatter;
173 pub struct Formatter;
177 use std::fmt::{self, Formatter};
185 fn applicable_when_found_an_import() {
192 pub struct PubStruct;
196 use PubMod::PubStruct;
201 pub struct PubStruct;
208 fn applicable_when_found_an_import_in_macros() {
213 ($i:ident) => { fn foo(a: $i) {} }
218 pub struct PubStruct;
222 use PubMod::PubStruct;
225 ($i:ident) => { fn foo(a: $i) {} }
230 pub struct PubStruct;
237 fn applicable_when_found_multiple_imports() {
244 pub struct PubStruct;
247 pub struct PubStruct;
250 pub struct PubStruct;
254 use PubMod3::PubStruct;
259 pub struct PubStruct;
262 pub struct PubStruct;
265 pub struct PubStruct;
272 fn not_applicable_for_already_imported_types() {
273 check_assist_not_applicable(
276 use PubMod::PubStruct;
281 pub struct PubStruct;
288 fn not_applicable_for_types_with_private_paths() {
289 check_assist_not_applicable(
295 struct PrivateStruct;
302 fn not_applicable_when_no_imports_found() {
303 check_assist_not_applicable(
311 fn not_applicable_in_import_statements() {
312 check_assist_not_applicable(
318 pub struct PubStruct;
324 fn function_import() {
331 pub fn test_function() {};
335 use PubMod::test_function;
340 pub fn test_function() {};
351 //- /lib.rs crate:crate_with_macro
357 //- /main.rs crate:main deps:crate_with_macro
362 r"use crate_with_macro::foo;
372 fn auto_import_target() {
377 group_label: Option<$0GroupLabel>,
380 mod m { pub struct GroupLabel; }
387 fn not_applicable_when_path_start_is_imported() {
388 check_assist_not_applicable(
394 pub struct TestStruct;
401 mod2::mod3::TestStruct$0
408 fn not_applicable_for_imported_function() {
409 check_assist_not_applicable(
413 pub fn test_function() {}
416 use test_mod::test_function;
425 fn associated_struct_function() {
430 pub struct TestStruct {}
432 pub fn test_function() {}
437 TestStruct::test_function$0
441 use test_mod::TestStruct;
444 pub struct TestStruct {}
446 pub fn test_function() {}
451 TestStruct::test_function
458 fn associated_struct_const() {
463 pub struct TestStruct {}
465 const TEST_CONST: u8 = 42;
470 TestStruct::TEST_CONST$0
474 use test_mod::TestStruct;
477 pub struct TestStruct {}
479 const TEST_CONST: u8 = 42;
484 TestStruct::TEST_CONST
491 fn associated_trait_function() {
496 pub trait TestTrait {
499 pub struct TestStruct {}
500 impl TestTrait for TestStruct {
501 fn test_function() {}
506 test_mod::TestStruct::test_function$0
510 use test_mod::TestTrait;
513 pub trait TestTrait {
516 pub struct TestStruct {}
517 impl TestTrait for TestStruct {
518 fn test_function() {}
523 test_mod::TestStruct::test_function
530 fn not_applicable_for_imported_trait_for_function() {
531 check_assist_not_applicable(
535 pub trait TestTrait {
538 pub trait TestTrait2 {
545 impl TestTrait2 for TestEnum {
546 fn test_function() {}
548 impl TestTrait for TestEnum {
549 fn test_function() {}
553 use test_mod::TestTrait2;
555 test_mod::TestEnum::test_function$0;
562 fn associated_trait_const() {
567 pub trait TestTrait {
568 const TEST_CONST: u8;
570 pub struct TestStruct {}
571 impl TestTrait for TestStruct {
572 const TEST_CONST: u8 = 42;
577 test_mod::TestStruct::TEST_CONST$0
581 use test_mod::TestTrait;
584 pub trait TestTrait {
585 const TEST_CONST: u8;
587 pub struct TestStruct {}
588 impl TestTrait for TestStruct {
589 const TEST_CONST: u8 = 42;
594 test_mod::TestStruct::TEST_CONST
601 fn not_applicable_for_imported_trait_for_const() {
602 check_assist_not_applicable(
606 pub trait TestTrait {
607 const TEST_CONST: u8;
609 pub trait TestTrait2 {
610 const TEST_CONST: f64;
616 impl TestTrait2 for TestEnum {
617 const TEST_CONST: f64 = 42.0;
619 impl TestTrait for TestEnum {
620 const TEST_CONST: u8 = 42;
624 use test_mod::TestTrait2;
626 test_mod::TestEnum::TEST_CONST$0;
638 pub trait TestTrait {
639 fn test_method(&self);
641 pub struct TestStruct {}
642 impl TestTrait for TestStruct {
643 fn test_method(&self) {}
648 let test_struct = test_mod::TestStruct {};
649 test_struct.test_meth$0od()
653 use test_mod::TestTrait;
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_method()
674 fn trait_method_cross_crate() {
678 //- /main.rs crate:main deps:dep
680 let test_struct = dep::test_mod::TestStruct {};
681 test_struct.test_meth$0od()
683 //- /dep.rs crate:dep
685 pub trait TestTrait {
686 fn test_method(&self);
688 pub struct TestStruct {}
689 impl TestTrait for TestStruct {
690 fn test_method(&self) {}
695 use dep::test_mod::TestTrait;
698 let test_struct = dep::test_mod::TestStruct {};
699 test_struct.test_method()
706 fn assoc_fn_cross_crate() {
710 //- /main.rs crate:main deps:dep
712 dep::test_mod::TestStruct::test_func$0tion
714 //- /dep.rs crate:dep
716 pub trait TestTrait {
719 pub struct TestStruct {}
720 impl TestTrait for TestStruct {
721 fn test_function() {}
726 use dep::test_mod::TestTrait;
729 dep::test_mod::TestStruct::test_function
736 fn assoc_const_cross_crate() {
740 //- /main.rs crate:main deps:dep
742 dep::test_mod::TestStruct::CONST$0
744 //- /dep.rs crate:dep
746 pub trait TestTrait {
749 pub struct TestStruct {}
750 impl TestTrait for TestStruct {
751 const CONST: bool = true;
756 use dep::test_mod::TestTrait;
759 dep::test_mod::TestStruct::CONST
766 fn assoc_fn_as_method_cross_crate() {
767 check_assist_not_applicable(
770 //- /main.rs crate:main deps:dep
772 let test_struct = dep::test_mod::TestStruct {};
773 test_struct.test_func$0tion()
775 //- /dep.rs crate:dep
777 pub trait TestTrait {
780 pub struct TestStruct {}
781 impl TestTrait for TestStruct {
782 fn test_function() {}
790 fn private_trait_cross_crate() {
791 check_assist_not_applicable(
794 //- /main.rs crate:main deps:dep
796 let test_struct = dep::test_mod::TestStruct {};
797 test_struct.test_meth$0od()
799 //- /dep.rs crate:dep
802 fn test_method(&self);
804 pub struct TestStruct {}
805 impl TestTrait for TestStruct {
806 fn test_method(&self) {}
814 fn not_applicable_for_imported_trait_for_method() {
815 check_assist_not_applicable(
819 pub trait TestTrait {
820 fn test_method(&self);
822 pub trait TestTrait2 {
823 fn test_method(&self);
829 impl TestTrait2 for TestEnum {
830 fn test_method(&self) {}
832 impl TestTrait for TestEnum {
833 fn test_method(&self) {}
837 use test_mod::TestTrait2;
839 let one = test_mod::TestEnum::One;
851 //- /lib.rs crate:dep
854 //- /main.rs crate:main deps:dep
870 // Tests that only imports whose last segment matches the identifier get suggested.
874 //- /lib.rs crate:dep
879 pub fn panic_fmt() {}
881 //- /main.rs crate:main deps:dep
884 impl f$0mt::Display for S {}
890 impl fmt::Display for S {}
896 fn macro_generated() {
897 // Tests that macro-generated items are suggested from external crates.
901 //- /lib.rs crate:dep
910 //- /main.rs crate:main deps:dep
926 // Tests that differently cased names don't interfere and we only suggest the matching one.
930 //- /lib.rs crate:dep
934 //- /main.rs crate:main deps:dep
982 fn uses_abs_path_with_extern_crate_clash() {
986 //- /main.rs crate:main deps:foo
992 //- /foo.rs crate:foo
1008 fn works_on_ident_patterns() {