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(&syntax_under_caret, &ctx.sema)?;
97 for import in proposed_imports {
100 AssistId("auto_import", AssistKind::QuickFix),
101 format!("Import `{}`", import.import_path),
105 insert_use(&scope, mod_path_to_ast(&import.import_path), ctx.config.insert_use);
106 builder.rewrite(rewriter);
113 pub(super) fn find_importable_node(ctx: &AssistContext) -> Option<(ImportAssets, SyntaxNode)> {
114 if let Some(path_under_caret) = ctx.find_node_at_offset_with_descend::<ast::Path>() {
115 ImportAssets::for_exact_path(&path_under_caret, &ctx.sema)
116 .zip(Some(path_under_caret.syntax().clone()))
117 } else if let Some(method_under_caret) =
118 ctx.find_node_at_offset_with_descend::<ast::MethodCallExpr>()
120 ImportAssets::for_method_call(&method_under_caret, &ctx.sema)
121 .zip(Some(method_under_caret.syntax().clone()))
127 fn group_label(import_candidate: &ImportCandidate) -> GroupLabel {
128 let name = match import_candidate {
129 ImportCandidate::Path(candidate) => format!("Import {}", candidate.name.text()),
130 ImportCandidate::TraitAssocItem(candidate) => {
131 format!("Import a trait for item {}", candidate.assoc_item_name.text())
133 ImportCandidate::TraitMethod(candidate) => {
134 format!("Import a trait for method {}", candidate.assoc_item_name.text())
143 use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target};
146 fn applicable_when_found_an_import_partial() {
152 pub struct Formatter;
163 pub struct Formatter;
167 use std::fmt::{self, Formatter};
175 fn applicable_when_found_an_import() {
182 pub struct PubStruct;
186 use PubMod::PubStruct;
191 pub struct PubStruct;
198 fn applicable_when_found_an_import_in_macros() {
203 ($i:ident) => { fn foo(a: $i) {} }
208 pub struct PubStruct;
212 use PubMod::PubStruct;
215 ($i:ident) => { fn foo(a: $i) {} }
220 pub struct PubStruct;
227 fn applicable_when_found_multiple_imports() {
234 pub struct PubStruct;
237 pub struct PubStruct;
240 pub struct PubStruct;
244 use PubMod3::PubStruct;
249 pub struct PubStruct;
252 pub struct PubStruct;
255 pub struct PubStruct;
262 fn not_applicable_for_already_imported_types() {
263 check_assist_not_applicable(
266 use PubMod::PubStruct;
271 pub struct PubStruct;
278 fn not_applicable_for_types_with_private_paths() {
279 check_assist_not_applicable(
285 struct PrivateStruct;
292 fn not_applicable_when_no_imports_found() {
293 check_assist_not_applicable(
301 fn not_applicable_in_import_statements() {
302 check_assist_not_applicable(
308 pub struct PubStruct;
314 fn function_import() {
321 pub fn test_function() {};
325 use PubMod::test_function;
330 pub fn test_function() {};
341 //- /lib.rs crate:crate_with_macro
347 //- /main.rs crate:main deps:crate_with_macro
352 r"use crate_with_macro::foo;
362 fn auto_import_target() {
367 group_label: Option<$0GroupLabel>,
370 mod m { pub struct GroupLabel; }
377 fn not_applicable_when_path_start_is_imported() {
378 check_assist_not_applicable(
384 pub struct TestStruct;
391 mod2::mod3::TestStruct$0
398 fn not_applicable_for_imported_function() {
399 check_assist_not_applicable(
403 pub fn test_function() {}
406 use test_mod::test_function;
415 fn associated_struct_function() {
420 pub struct TestStruct {}
422 pub fn test_function() {}
427 TestStruct::test_function$0
431 use test_mod::TestStruct;
434 pub struct TestStruct {}
436 pub fn test_function() {}
441 TestStruct::test_function
448 fn associated_struct_const() {
453 pub struct TestStruct {}
455 const TEST_CONST: u8 = 42;
460 TestStruct::TEST_CONST$0
464 use test_mod::TestStruct;
467 pub struct TestStruct {}
469 const TEST_CONST: u8 = 42;
474 TestStruct::TEST_CONST
481 fn associated_trait_function() {
486 pub trait TestTrait {
489 pub struct TestStruct {}
490 impl TestTrait for TestStruct {
491 fn test_function() {}
496 test_mod::TestStruct::test_function$0
500 use test_mod::TestTrait;
503 pub trait TestTrait {
506 pub struct TestStruct {}
507 impl TestTrait for TestStruct {
508 fn test_function() {}
513 test_mod::TestStruct::test_function
520 fn not_applicable_for_imported_trait_for_function() {
521 check_assist_not_applicable(
525 pub trait TestTrait {
528 pub trait TestTrait2 {
535 impl TestTrait2 for TestEnum {
536 fn test_function() {}
538 impl TestTrait for TestEnum {
539 fn test_function() {}
543 use test_mod::TestTrait2;
545 test_mod::TestEnum::test_function$0;
552 fn associated_trait_const() {
557 pub trait TestTrait {
558 const TEST_CONST: u8;
560 pub struct TestStruct {}
561 impl TestTrait for TestStruct {
562 const TEST_CONST: u8 = 42;
567 test_mod::TestStruct::TEST_CONST$0
571 use test_mod::TestTrait;
574 pub trait TestTrait {
575 const TEST_CONST: u8;
577 pub struct TestStruct {}
578 impl TestTrait for TestStruct {
579 const TEST_CONST: u8 = 42;
584 test_mod::TestStruct::TEST_CONST
591 fn not_applicable_for_imported_trait_for_const() {
592 check_assist_not_applicable(
596 pub trait TestTrait {
597 const TEST_CONST: u8;
599 pub trait TestTrait2 {
600 const TEST_CONST: f64;
606 impl TestTrait2 for TestEnum {
607 const TEST_CONST: f64 = 42.0;
609 impl TestTrait for TestEnum {
610 const TEST_CONST: u8 = 42;
614 use test_mod::TestTrait2;
616 test_mod::TestEnum::TEST_CONST$0;
628 pub trait TestTrait {
629 fn test_method(&self);
631 pub struct TestStruct {}
632 impl TestTrait for TestStruct {
633 fn test_method(&self) {}
638 let test_struct = test_mod::TestStruct {};
639 test_struct.test_meth$0od()
643 use test_mod::TestTrait;
646 pub trait TestTrait {
647 fn test_method(&self);
649 pub struct TestStruct {}
650 impl TestTrait for TestStruct {
651 fn test_method(&self) {}
656 let test_struct = test_mod::TestStruct {};
657 test_struct.test_method()
664 fn trait_method_cross_crate() {
668 //- /main.rs crate:main deps:dep
670 let test_struct = dep::test_mod::TestStruct {};
671 test_struct.test_meth$0od()
673 //- /dep.rs crate:dep
675 pub trait TestTrait {
676 fn test_method(&self);
678 pub struct TestStruct {}
679 impl TestTrait for TestStruct {
680 fn test_method(&self) {}
685 use dep::test_mod::TestTrait;
688 let test_struct = dep::test_mod::TestStruct {};
689 test_struct.test_method()
696 fn assoc_fn_cross_crate() {
700 //- /main.rs crate:main deps:dep
702 dep::test_mod::TestStruct::test_func$0tion
704 //- /dep.rs crate:dep
706 pub trait TestTrait {
709 pub struct TestStruct {}
710 impl TestTrait for TestStruct {
711 fn test_function() {}
716 use dep::test_mod::TestTrait;
719 dep::test_mod::TestStruct::test_function
726 fn assoc_const_cross_crate() {
730 //- /main.rs crate:main deps:dep
732 dep::test_mod::TestStruct::CONST$0
734 //- /dep.rs crate:dep
736 pub trait TestTrait {
739 pub struct TestStruct {}
740 impl TestTrait for TestStruct {
741 const CONST: bool = true;
746 use dep::test_mod::TestTrait;
749 dep::test_mod::TestStruct::CONST
756 fn assoc_fn_as_method_cross_crate() {
757 check_assist_not_applicable(
760 //- /main.rs crate:main deps:dep
762 let test_struct = dep::test_mod::TestStruct {};
763 test_struct.test_func$0tion()
765 //- /dep.rs crate:dep
767 pub trait TestTrait {
770 pub struct TestStruct {}
771 impl TestTrait for TestStruct {
772 fn test_function() {}
780 fn private_trait_cross_crate() {
781 check_assist_not_applicable(
784 //- /main.rs crate:main deps:dep
786 let test_struct = dep::test_mod::TestStruct {};
787 test_struct.test_meth$0od()
789 //- /dep.rs crate:dep
792 fn test_method(&self);
794 pub struct TestStruct {}
795 impl TestTrait for TestStruct {
796 fn test_method(&self) {}
804 fn not_applicable_for_imported_trait_for_method() {
805 check_assist_not_applicable(
809 pub trait TestTrait {
810 fn test_method(&self);
812 pub trait TestTrait2 {
813 fn test_method(&self);
819 impl TestTrait2 for TestEnum {
820 fn test_method(&self) {}
822 impl TestTrait for TestEnum {
823 fn test_method(&self) {}
827 use test_mod::TestTrait2;
829 let one = test_mod::TestEnum::One;
841 //- /lib.rs crate:dep
844 //- /main.rs crate:main deps:dep
860 // Tests that only imports whose last segment matches the identifier get suggested.
864 //- /lib.rs crate:dep
869 pub fn panic_fmt() {}
871 //- /main.rs crate:main deps:dep
874 impl f$0mt::Display for S {}
880 impl fmt::Display for S {}
886 fn macro_generated() {
887 // Tests that macro-generated items are suggested from external crates.
891 //- /lib.rs crate:dep
900 //- /main.rs crate:main deps:dep
916 // Tests that differently cased names don't interfere and we only suggest the matching one.
920 //- /lib.rs crate:dep
924 //- /main.rs crate:main deps:dep