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 `importMergeBehaviour` 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.importMergeBehaviour`.
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 // Assist: auto_import
67 // If the name is unresolved, provides all possible imports for it.
71 // let map = HashMap$0::new();
73 // # pub mod std { pub mod collections { pub struct HashMap { } } }
77 // use std::collections::HashMap;
80 // let map = HashMap::new();
82 // # pub mod std { pub mod collections { pub struct HashMap { } } }
84 pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
85 let (import_assets, syntax_under_caret) = find_importable_node(ctx)?;
86 let proposed_imports =
87 import_assets.search_for_imports(&ctx.sema, ctx.config.insert_use.prefix_kind);
88 if proposed_imports.is_empty() {
92 let range = ctx.sema.original_range(&syntax_under_caret).range;
93 let group = import_group_message(import_assets.import_candidate());
94 let scope = ImportScope::find_insert_use_container(&syntax_under_caret, &ctx.sema)?;
95 for (import, _) in proposed_imports {
98 AssistId("auto_import", AssistKind::QuickFix),
99 format!("Import `{}`", &import),
103 insert_use(&scope, mod_path_to_ast(&import), ctx.config.insert_use.merge);
104 builder.rewrite(rewriter);
111 pub(super) fn find_importable_node(ctx: &AssistContext) -> Option<(ImportAssets, SyntaxNode)> {
112 if let Some(path_under_caret) = ctx.find_node_at_offset_with_descend::<ast::Path>() {
113 ImportAssets::for_exact_path(&path_under_caret, &ctx.sema)
114 .zip(Some(path_under_caret.syntax().clone()))
115 } else if let Some(method_under_caret) =
116 ctx.find_node_at_offset_with_descend::<ast::MethodCallExpr>()
118 ImportAssets::for_method_call(&method_under_caret, &ctx.sema)
119 .zip(Some(method_under_caret.syntax().clone()))
125 fn import_group_message(import_candidate: &ImportCandidate) -> GroupLabel {
126 let name = match import_candidate {
127 ImportCandidate::Path(candidate) => format!("Import {}", candidate.name.text()),
128 ImportCandidate::TraitAssocItem(candidate) => {
129 format!("Import a trait for item {}", candidate.name.text())
131 ImportCandidate::TraitMethod(candidate) => {
132 format!("Import a trait for method {}", candidate.name.text())
141 use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target};
144 fn applicable_when_found_an_import_partial() {
150 pub struct Formatter;
161 pub struct Formatter;
165 use std::fmt::{self, Formatter};
173 fn applicable_when_found_an_import() {
180 pub struct PubStruct;
184 use PubMod::PubStruct;
189 pub struct PubStruct;
196 fn applicable_when_found_an_import_in_macros() {
201 ($i:ident) => { fn foo(a: $i) {} }
206 pub struct PubStruct;
210 use PubMod::PubStruct;
213 ($i:ident) => { fn foo(a: $i) {} }
218 pub struct PubStruct;
225 fn auto_imports_are_merged() {
229 use PubMod::PubStruct1;
232 test: Pub$0Struct2<u8>,
236 pub struct PubStruct1;
237 pub struct PubStruct2<T> {
243 use PubMod::{PubStruct1, PubStruct2};
246 test: PubStruct2<u8>,
250 pub struct PubStruct1;
251 pub struct PubStruct2<T> {
260 fn applicable_when_found_multiple_imports() {
267 pub struct PubStruct;
270 pub struct PubStruct;
273 pub struct PubStruct;
277 use PubMod3::PubStruct;
282 pub struct PubStruct;
285 pub struct PubStruct;
288 pub struct PubStruct;
295 fn not_applicable_for_already_imported_types() {
296 check_assist_not_applicable(
299 use PubMod::PubStruct;
304 pub struct PubStruct;
311 fn not_applicable_for_types_with_private_paths() {
312 check_assist_not_applicable(
318 struct PrivateStruct;
325 fn not_applicable_when_no_imports_found() {
326 check_assist_not_applicable(
334 fn not_applicable_in_import_statements() {
335 check_assist_not_applicable(
341 pub struct PubStruct;
347 fn function_import() {
354 pub fn test_function() {};
358 use PubMod::test_function;
363 pub fn test_function() {};
374 //- /lib.rs crate:crate_with_macro
380 //- /main.rs crate:main deps:crate_with_macro
385 r"use crate_with_macro::foo;
395 fn auto_import_target() {
400 group_label: Option<$0GroupLabel>,
403 mod m { pub struct GroupLabel; }
410 fn not_applicable_when_path_start_is_imported() {
411 check_assist_not_applicable(
417 pub struct TestStruct;
424 mod2::mod3::TestStruct$0
431 fn not_applicable_for_imported_function() {
432 check_assist_not_applicable(
436 pub fn test_function() {}
439 use test_mod::test_function;
448 fn associated_struct_function() {
453 pub struct TestStruct {}
455 pub fn test_function() {}
460 TestStruct::test_function$0
464 use test_mod::TestStruct;
467 pub struct TestStruct {}
469 pub fn test_function() {}
474 TestStruct::test_function
481 fn associated_struct_const() {
486 pub struct TestStruct {}
488 const TEST_CONST: u8 = 42;
493 TestStruct::TEST_CONST$0
497 use test_mod::TestStruct;
500 pub struct TestStruct {}
502 const TEST_CONST: u8 = 42;
507 TestStruct::TEST_CONST
514 fn associated_trait_function() {
519 pub trait TestTrait {
522 pub struct TestStruct {}
523 impl TestTrait for TestStruct {
524 fn test_function() {}
529 test_mod::TestStruct::test_function$0
533 use test_mod::TestTrait;
536 pub trait TestTrait {
539 pub struct TestStruct {}
540 impl TestTrait for TestStruct {
541 fn test_function() {}
546 test_mod::TestStruct::test_function
553 fn not_applicable_for_imported_trait_for_function() {
554 check_assist_not_applicable(
558 pub trait TestTrait {
561 pub trait TestTrait2 {
568 impl TestTrait2 for TestEnum {
569 fn test_function() {}
571 impl TestTrait for TestEnum {
572 fn test_function() {}
576 use test_mod::TestTrait2;
578 test_mod::TestEnum::test_function$0;
585 fn associated_trait_const() {
590 pub trait TestTrait {
591 const TEST_CONST: u8;
593 pub struct TestStruct {}
594 impl TestTrait for TestStruct {
595 const TEST_CONST: u8 = 42;
600 test_mod::TestStruct::TEST_CONST$0
604 use test_mod::TestTrait;
607 pub trait TestTrait {
608 const TEST_CONST: u8;
610 pub struct TestStruct {}
611 impl TestTrait for TestStruct {
612 const TEST_CONST: u8 = 42;
617 test_mod::TestStruct::TEST_CONST
624 fn not_applicable_for_imported_trait_for_const() {
625 check_assist_not_applicable(
629 pub trait TestTrait {
630 const TEST_CONST: u8;
632 pub trait TestTrait2 {
633 const TEST_CONST: f64;
639 impl TestTrait2 for TestEnum {
640 const TEST_CONST: f64 = 42.0;
642 impl TestTrait for TestEnum {
643 const TEST_CONST: u8 = 42;
647 use test_mod::TestTrait2;
649 test_mod::TestEnum::TEST_CONST$0;
661 pub trait TestTrait {
662 fn test_method(&self);
664 pub struct TestStruct {}
665 impl TestTrait for TestStruct {
666 fn test_method(&self) {}
671 let test_struct = test_mod::TestStruct {};
672 test_struct.test_meth$0od()
676 use test_mod::TestTrait;
679 pub trait TestTrait {
680 fn test_method(&self);
682 pub struct TestStruct {}
683 impl TestTrait for TestStruct {
684 fn test_method(&self) {}
689 let test_struct = test_mod::TestStruct {};
690 test_struct.test_method()
697 fn trait_method_cross_crate() {
701 //- /main.rs crate:main deps:dep
703 let test_struct = dep::test_mod::TestStruct {};
704 test_struct.test_meth$0od()
706 //- /dep.rs crate:dep
708 pub trait TestTrait {
709 fn test_method(&self);
711 pub struct TestStruct {}
712 impl TestTrait for TestStruct {
713 fn test_method(&self) {}
718 use dep::test_mod::TestTrait;
721 let test_struct = dep::test_mod::TestStruct {};
722 test_struct.test_method()
729 fn assoc_fn_cross_crate() {
733 //- /main.rs crate:main deps:dep
735 dep::test_mod::TestStruct::test_func$0tion
737 //- /dep.rs crate:dep
739 pub trait TestTrait {
742 pub struct TestStruct {}
743 impl TestTrait for TestStruct {
744 fn test_function() {}
749 use dep::test_mod::TestTrait;
752 dep::test_mod::TestStruct::test_function
759 fn assoc_const_cross_crate() {
763 //- /main.rs crate:main deps:dep
765 dep::test_mod::TestStruct::CONST$0
767 //- /dep.rs crate:dep
769 pub trait TestTrait {
772 pub struct TestStruct {}
773 impl TestTrait for TestStruct {
774 const CONST: bool = true;
779 use dep::test_mod::TestTrait;
782 dep::test_mod::TestStruct::CONST
789 fn assoc_fn_as_method_cross_crate() {
790 check_assist_not_applicable(
793 //- /main.rs crate:main deps:dep
795 let test_struct = dep::test_mod::TestStruct {};
796 test_struct.test_func$0tion()
798 //- /dep.rs crate:dep
800 pub trait TestTrait {
803 pub struct TestStruct {}
804 impl TestTrait for TestStruct {
805 fn test_function() {}
813 fn private_trait_cross_crate() {
814 check_assist_not_applicable(
817 //- /main.rs crate:main deps:dep
819 let test_struct = dep::test_mod::TestStruct {};
820 test_struct.test_meth$0od()
822 //- /dep.rs crate:dep
825 fn test_method(&self);
827 pub struct TestStruct {}
828 impl TestTrait for TestStruct {
829 fn test_method(&self) {}
837 fn not_applicable_for_imported_trait_for_method() {
838 check_assist_not_applicable(
842 pub trait TestTrait {
843 fn test_method(&self);
845 pub trait TestTrait2 {
846 fn test_method(&self);
852 impl TestTrait2 for TestEnum {
853 fn test_method(&self) {}
855 impl TestTrait for TestEnum {
856 fn test_method(&self) {}
860 use test_mod::TestTrait2;
862 let one = test_mod::TestEnum::One;
874 //- /lib.rs crate:dep
877 //- /main.rs crate:main deps:dep
893 // Tests that only imports whose last segment matches the identifier get suggested.
897 //- /lib.rs crate:dep
902 pub fn panic_fmt() {}
904 //- /main.rs crate:main deps:dep
907 impl f$0mt::Display for S {}
913 impl fmt::Display for S {}
919 fn macro_generated() {
920 // Tests that macro-generated items are suggested from external crates.
924 //- /lib.rs crate:dep
933 //- /main.rs crate:main deps:dep
949 // Tests that differently cased names don't interfere and we only suggest the matching one.
953 //- /lib.rs crate:dep
957 //- /main.rs crate:main deps:dep