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;
38 // It is possible to configure how use-trees are merged with the `importMergeBehavior` setting.
39 // It has the following configurations:
41 // - `full`: This setting will cause auto-import to always completely merge use-trees that share the
42 // same path prefix while also merging inner trees that share the same path-prefix. This kind of
43 // nesting is only supported in Rust versions later than 1.24.
44 // - `last`: This setting will cause auto-import to merge use-trees as long as the resulting tree
45 // will only contain a nesting of single segment paths at the very end.
46 // - `none`: This setting will cause auto-import to never merge use-trees keeping them as simple
49 // In `VS Code` the configuration for this is `rust-analyzer.assist.importMergeBehavior`.
53 // The style of imports in the same crate is configurable through the `importPrefix` setting.
54 // It has the following configurations:
56 // - `by_crate`: This setting will force paths to be always absolute, starting with the `crate`
57 // prefix, unless the item is defined outside of the current crate.
58 // - `by_self`: This setting will force paths that are relative to the current module to always
59 // start with `self`. This will result in paths that always start with either `crate`, `self`,
60 // `super` or an extern crate identifier.
61 // - `plain`: This setting does not impose any restrictions in imports.
63 // In `VS Code` the configuration for this is `rust-analyzer.assist.importPrefix`.
65 // image::https://user-images.githubusercontent.com/48062697/113020673-b85be580-917a-11eb-9022-59585f35d4f8.gif[]
67 // Assist: auto_import
69 // If the name is unresolved, provides all possible imports for it.
73 // let map = HashMap$0::new();
75 // # pub mod std { pub mod collections { pub struct HashMap { } } }
79 // use std::collections::HashMap;
82 // let map = HashMap::new();
84 // # pub mod std { pub mod collections { pub struct HashMap { } } }
86 pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
87 let (import_assets, syntax_under_caret) = find_importable_node(ctx)?;
88 let proposed_imports =
89 import_assets.search_for_imports(&ctx.sema, ctx.config.insert_use.prefix_kind);
90 if proposed_imports.is_empty() {
94 let range = ctx.sema.original_range(&syntax_under_caret).range;
95 let group_label = group_label(import_assets.import_candidate());
96 let scope = ImportScope::find_insert_use_container_with_macros(&syntax_under_caret, &ctx.sema)?;
97 for import in proposed_imports {
100 AssistId("auto_import", AssistKind::QuickFix),
101 format!("Import `{}`", import.import_path),
104 let scope = match scope.clone() {
105 ImportScope::File(it) => ImportScope::File(builder.make_ast_mut(it)),
106 ImportScope::Module(it) => ImportScope::Module(builder.make_ast_mut(it)),
108 insert_use(&scope, mod_path_to_ast(&import.import_path), ctx.config.insert_use);
115 pub(super) fn find_importable_node(ctx: &AssistContext) -> Option<(ImportAssets, SyntaxNode)> {
116 if let Some(path_under_caret) = ctx.find_node_at_offset_with_descend::<ast::Path>() {
117 ImportAssets::for_exact_path(&path_under_caret, &ctx.sema)
118 .zip(Some(path_under_caret.syntax().clone()))
119 } else if let Some(method_under_caret) =
120 ctx.find_node_at_offset_with_descend::<ast::MethodCallExpr>()
122 ImportAssets::for_method_call(&method_under_caret, &ctx.sema)
123 .zip(Some(method_under_caret.syntax().clone()))
129 fn group_label(import_candidate: &ImportCandidate) -> GroupLabel {
130 let name = match import_candidate {
131 ImportCandidate::Path(candidate) => format!("Import {}", candidate.name.text()),
132 ImportCandidate::TraitAssocItem(candidate) => {
133 format!("Import a trait for item {}", candidate.assoc_item_name.text())
135 ImportCandidate::TraitMethod(candidate) => {
136 format!("Import a trait for method {}", candidate.assoc_item_name.text())
145 use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target};
148 fn applicable_when_found_an_import_partial() {
154 pub struct Formatter;
165 pub struct Formatter;
169 use std::fmt::{self, Formatter};
177 fn applicable_when_found_an_import() {
184 pub struct PubStruct;
188 use PubMod::PubStruct;
193 pub struct PubStruct;
200 fn applicable_when_found_an_import_in_macros() {
205 ($i:ident) => { fn foo(a: $i) {} }
210 pub struct PubStruct;
214 use PubMod::PubStruct;
217 ($i:ident) => { fn foo(a: $i) {} }
222 pub struct PubStruct;
229 fn applicable_when_found_multiple_imports() {
236 pub struct PubStruct;
239 pub struct PubStruct;
242 pub struct PubStruct;
246 use PubMod3::PubStruct;
251 pub struct PubStruct;
254 pub struct PubStruct;
257 pub struct PubStruct;
264 fn not_applicable_for_already_imported_types() {
265 check_assist_not_applicable(
268 use PubMod::PubStruct;
273 pub struct PubStruct;
280 fn not_applicable_for_types_with_private_paths() {
281 check_assist_not_applicable(
287 struct PrivateStruct;
294 fn not_applicable_when_no_imports_found() {
295 check_assist_not_applicable(
303 fn not_applicable_in_import_statements() {
304 check_assist_not_applicable(
310 pub struct PubStruct;
316 fn function_import() {
323 pub fn test_function() {};
327 use PubMod::test_function;
332 pub fn test_function() {};
343 //- /lib.rs crate:crate_with_macro
349 //- /main.rs crate:main deps:crate_with_macro
354 r"use crate_with_macro::foo;
364 fn auto_import_target() {
369 group_label: Option<$0GroupLabel>,
372 mod m { pub struct GroupLabel; }
379 fn not_applicable_when_path_start_is_imported() {
380 check_assist_not_applicable(
386 pub struct TestStruct;
393 mod2::mod3::TestStruct$0
400 fn not_applicable_for_imported_function() {
401 check_assist_not_applicable(
405 pub fn test_function() {}
408 use test_mod::test_function;
417 fn associated_struct_function() {
422 pub struct TestStruct {}
424 pub fn test_function() {}
429 TestStruct::test_function$0
433 use test_mod::TestStruct;
436 pub struct TestStruct {}
438 pub fn test_function() {}
443 TestStruct::test_function
450 fn associated_struct_const() {
455 pub struct TestStruct {}
457 const TEST_CONST: u8 = 42;
462 TestStruct::TEST_CONST$0
466 use test_mod::TestStruct;
469 pub struct TestStruct {}
471 const TEST_CONST: u8 = 42;
476 TestStruct::TEST_CONST
483 fn associated_trait_function() {
488 pub trait TestTrait {
491 pub struct TestStruct {}
492 impl TestTrait for TestStruct {
493 fn test_function() {}
498 test_mod::TestStruct::test_function$0
502 use test_mod::TestTrait;
505 pub trait TestTrait {
508 pub struct TestStruct {}
509 impl TestTrait for TestStruct {
510 fn test_function() {}
515 test_mod::TestStruct::test_function
522 fn not_applicable_for_imported_trait_for_function() {
523 check_assist_not_applicable(
527 pub trait TestTrait {
530 pub trait TestTrait2 {
537 impl TestTrait2 for TestEnum {
538 fn test_function() {}
540 impl TestTrait for TestEnum {
541 fn test_function() {}
545 use test_mod::TestTrait2;
547 test_mod::TestEnum::test_function$0;
554 fn associated_trait_const() {
559 pub trait TestTrait {
560 const TEST_CONST: u8;
562 pub struct TestStruct {}
563 impl TestTrait for TestStruct {
564 const TEST_CONST: u8 = 42;
569 test_mod::TestStruct::TEST_CONST$0
573 use test_mod::TestTrait;
576 pub trait TestTrait {
577 const TEST_CONST: u8;
579 pub struct TestStruct {}
580 impl TestTrait for TestStruct {
581 const TEST_CONST: u8 = 42;
586 test_mod::TestStruct::TEST_CONST
593 fn not_applicable_for_imported_trait_for_const() {
594 check_assist_not_applicable(
598 pub trait TestTrait {
599 const TEST_CONST: u8;
601 pub trait TestTrait2 {
602 const TEST_CONST: f64;
608 impl TestTrait2 for TestEnum {
609 const TEST_CONST: f64 = 42.0;
611 impl TestTrait for TestEnum {
612 const TEST_CONST: u8 = 42;
616 use test_mod::TestTrait2;
618 test_mod::TestEnum::TEST_CONST$0;
630 pub trait TestTrait {
631 fn test_method(&self);
633 pub struct TestStruct {}
634 impl TestTrait for TestStruct {
635 fn test_method(&self) {}
640 let test_struct = test_mod::TestStruct {};
641 test_struct.test_meth$0od()
645 use test_mod::TestTrait;
648 pub trait TestTrait {
649 fn test_method(&self);
651 pub struct TestStruct {}
652 impl TestTrait for TestStruct {
653 fn test_method(&self) {}
658 let test_struct = test_mod::TestStruct {};
659 test_struct.test_method()
666 fn trait_method_cross_crate() {
670 //- /main.rs crate:main deps:dep
672 let test_struct = dep::test_mod::TestStruct {};
673 test_struct.test_meth$0od()
675 //- /dep.rs crate:dep
677 pub trait TestTrait {
678 fn test_method(&self);
680 pub struct TestStruct {}
681 impl TestTrait for TestStruct {
682 fn test_method(&self) {}
687 use dep::test_mod::TestTrait;
690 let test_struct = dep::test_mod::TestStruct {};
691 test_struct.test_method()
698 fn assoc_fn_cross_crate() {
702 //- /main.rs crate:main deps:dep
704 dep::test_mod::TestStruct::test_func$0tion
706 //- /dep.rs crate:dep
708 pub trait TestTrait {
711 pub struct TestStruct {}
712 impl TestTrait for TestStruct {
713 fn test_function() {}
718 use dep::test_mod::TestTrait;
721 dep::test_mod::TestStruct::test_function
728 fn assoc_const_cross_crate() {
732 //- /main.rs crate:main deps:dep
734 dep::test_mod::TestStruct::CONST$0
736 //- /dep.rs crate:dep
738 pub trait TestTrait {
741 pub struct TestStruct {}
742 impl TestTrait for TestStruct {
743 const CONST: bool = true;
748 use dep::test_mod::TestTrait;
751 dep::test_mod::TestStruct::CONST
758 fn assoc_fn_as_method_cross_crate() {
759 check_assist_not_applicable(
762 //- /main.rs crate:main deps:dep
764 let test_struct = dep::test_mod::TestStruct {};
765 test_struct.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() {}
782 fn private_trait_cross_crate() {
783 check_assist_not_applicable(
786 //- /main.rs crate:main deps:dep
788 let test_struct = dep::test_mod::TestStruct {};
789 test_struct.test_meth$0od()
791 //- /dep.rs crate:dep
794 fn test_method(&self);
796 pub struct TestStruct {}
797 impl TestTrait for TestStruct {
798 fn test_method(&self) {}
806 fn not_applicable_for_imported_trait_for_method() {
807 check_assist_not_applicable(
811 pub trait TestTrait {
812 fn test_method(&self);
814 pub trait TestTrait2 {
815 fn test_method(&self);
821 impl TestTrait2 for TestEnum {
822 fn test_method(&self) {}
824 impl TestTrait for TestEnum {
825 fn test_method(&self) {}
829 use test_mod::TestTrait2;
831 let one = test_mod::TestEnum::One;
843 //- /lib.rs crate:dep
846 //- /main.rs crate:main deps:dep
862 // Tests that only imports whose last segment matches the identifier get suggested.
866 //- /lib.rs crate:dep
871 pub fn panic_fmt() {}
873 //- /main.rs crate:main deps:dep
876 impl f$0mt::Display for S {}
882 impl fmt::Display for S {}
888 fn macro_generated() {
889 // Tests that macro-generated items are suggested from external crates.
893 //- /lib.rs crate:dep
902 //- /main.rs crate:main deps:dep
918 // Tests that differently cased names don't interfere and we only suggest the matching one.
922 //- /lib.rs crate:dep
926 //- /main.rs crate:main deps:dep
974 fn uses_abs_path_with_extern_crate_clash() {
978 //- /main.rs crate:main deps:foo
984 //- /foo.rs crate:foo