2 import_assets::{ImportAssets, ImportCandidate},
3 insert_use::{insert_use, ImportScope},
6 use syntax::{ast, AstNode, AstToken, 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() {
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)?;
97 // we aren't interested in different namespaces
98 proposed_imports.dedup_by(|a, b| a.import_path == b.import_path);
99 for import in proposed_imports {
102 AssistId("auto_import", AssistKind::QuickFix),
103 format!("Import `{}`", import.import_path),
106 let scope = match scope.clone() {
107 ImportScope::File(it) => ImportScope::File(builder.make_mut(it)),
108 ImportScope::Module(it) => ImportScope::Module(builder.make_mut(it)),
109 ImportScope::Block(it) => ImportScope::Block(builder.make_mut(it)),
111 insert_use(&scope, mod_path_to_ast(&import.import_path), &ctx.config.insert_use);
118 pub(super) fn find_importable_node(ctx: &AssistContext) -> Option<(ImportAssets, SyntaxNode)> {
119 if let Some(path_under_caret) = ctx.find_node_at_offset_with_descend::<ast::Path>() {
120 ImportAssets::for_exact_path(&path_under_caret, &ctx.sema)
121 .zip(Some(path_under_caret.syntax().clone()))
122 } else if let Some(method_under_caret) =
123 ctx.find_node_at_offset_with_descend::<ast::MethodCallExpr>()
125 ImportAssets::for_method_call(&method_under_caret, &ctx.sema)
126 .zip(Some(method_under_caret.syntax().clone()))
127 } else if let Some(pat) = ctx
128 .find_node_at_offset_with_descend::<ast::IdentPat>()
129 .filter(ast::IdentPat::is_simple_ident)
131 ImportAssets::for_ident_pat(&ctx.sema, &pat).zip(Some(pat.syntax().clone()))
133 let ident = ctx.find_token_at_offset()?;
134 ImportAssets::for_derive_ident(&ctx.sema, &ident).zip(ident.syntax().parent())
138 fn group_label(import_candidate: &ImportCandidate) -> GroupLabel {
139 let name = match import_candidate {
140 ImportCandidate::Path(candidate) => format!("Import {}", candidate.name.text()),
141 ImportCandidate::TraitAssocItem(candidate) => {
142 format!("Import a trait for item {}", candidate.assoc_item_name.text())
144 ImportCandidate::TraitMethod(candidate) => {
145 format!("Import a trait for method {}", candidate.assoc_item_name.text())
155 use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target};
158 fn applicable_when_found_an_import_partial() {
164 pub struct Formatter;
175 pub struct Formatter;
179 use std::fmt::{self, Formatter};
187 fn applicable_when_found_an_import() {
194 pub struct PubStruct;
198 use PubMod::PubStruct;
203 pub struct PubStruct;
210 fn applicable_when_found_an_import_in_macros() {
215 ($i:ident) => { fn foo(a: $i) {} }
220 pub struct PubStruct;
224 use PubMod::PubStruct;
227 ($i:ident) => { fn foo(a: $i) {} }
232 pub struct PubStruct;
239 fn applicable_when_found_multiple_imports() {
246 pub struct PubStruct;
249 pub struct PubStruct;
252 pub struct PubStruct;
256 use PubMod3::PubStruct;
261 pub struct PubStruct;
264 pub struct PubStruct;
267 pub struct PubStruct;
274 fn not_applicable_for_already_imported_types() {
275 check_assist_not_applicable(
278 use PubMod::PubStruct;
283 pub struct PubStruct;
290 fn not_applicable_for_types_with_private_paths() {
291 check_assist_not_applicable(
297 struct PrivateStruct;
304 fn not_applicable_when_no_imports_found() {
305 check_assist_not_applicable(
313 fn not_applicable_in_import_statements() {
314 check_assist_not_applicable(
320 pub struct PubStruct;
326 fn function_import() {
333 pub fn test_function() {};
337 use PubMod::test_function;
342 pub fn test_function() {};
353 //- /lib.rs crate:crate_with_macro
359 //- /main.rs crate:main deps:crate_with_macro
364 r"use crate_with_macro::foo;
374 fn auto_import_target() {
379 group_label: Option<$0GroupLabel>,
382 mod m { pub struct GroupLabel; }
389 fn not_applicable_when_path_start_is_imported() {
390 check_assist_not_applicable(
396 pub struct TestStruct;
403 mod2::mod3::TestStruct$0
410 fn not_applicable_for_imported_function() {
411 check_assist_not_applicable(
415 pub fn test_function() {}
418 use test_mod::test_function;
427 fn associated_struct_function() {
432 pub struct TestStruct {}
434 pub fn test_function() {}
439 TestStruct::test_function$0
443 use test_mod::TestStruct;
446 pub struct TestStruct {}
448 pub fn test_function() {}
453 TestStruct::test_function
460 fn associated_struct_const() {
465 pub struct TestStruct {}
467 const TEST_CONST: u8 = 42;
472 TestStruct::TEST_CONST$0
476 use test_mod::TestStruct;
479 pub struct TestStruct {}
481 const TEST_CONST: u8 = 42;
486 TestStruct::TEST_CONST
493 fn associated_trait_function() {
498 pub trait TestTrait {
501 pub struct TestStruct {}
502 impl TestTrait for TestStruct {
503 fn test_function() {}
508 test_mod::TestStruct::test_function$0
512 use test_mod::TestTrait;
515 pub trait TestTrait {
518 pub struct TestStruct {}
519 impl TestTrait for TestStruct {
520 fn test_function() {}
525 test_mod::TestStruct::test_function
532 fn not_applicable_for_imported_trait_for_function() {
533 check_assist_not_applicable(
537 pub trait TestTrait {
540 pub trait TestTrait2 {
547 impl TestTrait2 for TestEnum {
548 fn test_function() {}
550 impl TestTrait for TestEnum {
551 fn test_function() {}
555 use test_mod::TestTrait2;
557 test_mod::TestEnum::test_function$0;
564 fn associated_trait_const() {
569 pub trait TestTrait {
570 const TEST_CONST: u8;
572 pub struct TestStruct {}
573 impl TestTrait for TestStruct {
574 const TEST_CONST: u8 = 42;
579 test_mod::TestStruct::TEST_CONST$0
583 use test_mod::TestTrait;
586 pub trait TestTrait {
587 const TEST_CONST: u8;
589 pub struct TestStruct {}
590 impl TestTrait for TestStruct {
591 const TEST_CONST: u8 = 42;
596 test_mod::TestStruct::TEST_CONST
603 fn not_applicable_for_imported_trait_for_const() {
604 check_assist_not_applicable(
608 pub trait TestTrait {
609 const TEST_CONST: u8;
611 pub trait TestTrait2 {
612 const TEST_CONST: f64;
618 impl TestTrait2 for TestEnum {
619 const TEST_CONST: f64 = 42.0;
621 impl TestTrait for TestEnum {
622 const TEST_CONST: u8 = 42;
626 use test_mod::TestTrait2;
628 test_mod::TestEnum::TEST_CONST$0;
640 pub trait TestTrait {
641 fn test_method(&self);
643 pub struct TestStruct {}
644 impl TestTrait for TestStruct {
645 fn test_method(&self) {}
650 let test_struct = test_mod::TestStruct {};
651 test_struct.test_meth$0od()
655 use test_mod::TestTrait;
658 pub trait TestTrait {
659 fn test_method(&self);
661 pub struct TestStruct {}
662 impl TestTrait for TestStruct {
663 fn test_method(&self) {}
668 let test_struct = test_mod::TestStruct {};
669 test_struct.test_method()
676 fn trait_method_cross_crate() {
680 //- /main.rs crate:main deps:dep
682 let test_struct = dep::test_mod::TestStruct {};
683 test_struct.test_meth$0od()
685 //- /dep.rs crate:dep
687 pub trait TestTrait {
688 fn test_method(&self);
690 pub struct TestStruct {}
691 impl TestTrait for TestStruct {
692 fn test_method(&self) {}
697 use dep::test_mod::TestTrait;
700 let test_struct = dep::test_mod::TestStruct {};
701 test_struct.test_method()
708 fn assoc_fn_cross_crate() {
712 //- /main.rs crate:main deps:dep
714 dep::test_mod::TestStruct::test_func$0tion
716 //- /dep.rs crate:dep
718 pub trait TestTrait {
721 pub struct TestStruct {}
722 impl TestTrait for TestStruct {
723 fn test_function() {}
728 use dep::test_mod::TestTrait;
731 dep::test_mod::TestStruct::test_function
738 fn assoc_const_cross_crate() {
742 //- /main.rs crate:main deps:dep
744 dep::test_mod::TestStruct::CONST$0
746 //- /dep.rs crate:dep
748 pub trait TestTrait {
751 pub struct TestStruct {}
752 impl TestTrait for TestStruct {
753 const CONST: bool = true;
758 use dep::test_mod::TestTrait;
761 dep::test_mod::TestStruct::CONST
768 fn assoc_fn_as_method_cross_crate() {
769 check_assist_not_applicable(
772 //- /main.rs crate:main deps:dep
774 let test_struct = dep::test_mod::TestStruct {};
775 test_struct.test_func$0tion()
777 //- /dep.rs crate:dep
779 pub trait TestTrait {
782 pub struct TestStruct {}
783 impl TestTrait for TestStruct {
784 fn test_function() {}
792 fn private_trait_cross_crate() {
793 check_assist_not_applicable(
796 //- /main.rs crate:main deps:dep
798 let test_struct = dep::test_mod::TestStruct {};
799 test_struct.test_meth$0od()
801 //- /dep.rs crate:dep
804 fn test_method(&self);
806 pub struct TestStruct {}
807 impl TestTrait for TestStruct {
808 fn test_method(&self) {}
816 fn not_applicable_for_imported_trait_for_method() {
817 check_assist_not_applicable(
821 pub trait TestTrait {
822 fn test_method(&self);
824 pub trait TestTrait2 {
825 fn test_method(&self);
831 impl TestTrait2 for TestEnum {
832 fn test_method(&self) {}
834 impl TestTrait for TestEnum {
835 fn test_method(&self) {}
839 use test_mod::TestTrait2;
841 let one = test_mod::TestEnum::One;
853 //- /lib.rs crate:dep
856 //- /main.rs crate:main deps:dep
872 // Tests that only imports whose last segment matches the identifier get suggested.
876 //- /lib.rs crate:dep
881 pub fn panic_fmt() {}
883 //- /main.rs crate:main deps:dep
886 impl f$0mt::Display for S {}
892 impl fmt::Display for S {}
898 fn macro_generated() {
899 // Tests that macro-generated items are suggested from external crates.
903 //- /lib.rs crate:dep
912 //- /main.rs crate:main deps:dep
928 // Tests that differently cased names don't interfere and we only suggest the matching one.
932 //- /lib.rs crate:dep
936 //- /main.rs crate:main deps:dep
984 fn uses_abs_path_with_extern_crate_clash() {
985 cov_mark::check!(ambiguous_crate_start);
989 //- /main.rs crate:main deps:foo
995 //- /foo.rs crate:foo
1011 fn works_on_ident_patterns() {