1use std::cmp::Reverse;
2
3use either::Either;
4use hir::{Module, Type, db::HirDatabase};
5use ide_db::{
6 active_parameter::ActiveParameter,
7 helpers::mod_path_to_ast,
8 imports::{
9 import_assets::{ImportAssets, ImportCandidate, LocatedImport, TraitImportCandidate},
10 insert_use::{ImportScope, insert_use_as_alias_with_editor, insert_use_with_editor},
11 },
12};
13use syntax::{AstNode, Edition, SyntaxNode, ast, match_ast};
14
15use crate::{AssistContext, AssistId, Assists, GroupLabel};
16
17pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext<'_, '_>) -> Option<()> {
95 let cfg = ctx.config.import_path_config();
96
97 let (import_assets, syntax_under_caret, expected) = find_importable_node(ctx)?;
98 let mut proposed_imports: Vec<_> = import_assets
99 .search_for_imports(&ctx.sema, cfg, ctx.config.insert_use.prefix_kind)
100 .collect();
101 if proposed_imports.is_empty() {
102 return None;
103 }
104
105 let range = ctx.sema.original_range(&syntax_under_caret).range;
106 let scope = ImportScope::find_insert_use_container(&syntax_under_caret, &ctx.sema)?;
107
108 proposed_imports.sort_by(|a, b| a.import_path.cmp(&b.import_path));
110 proposed_imports.dedup_by(|a, b| a.import_path == b.import_path);
111
112 let current_module = ctx.sema.scope(scope.as_syntax_node()).map(|scope| scope.module());
113 proposed_imports.sort_by_key(|import| {
115 Reverse(relevance_score(ctx, import, expected.as_ref(), current_module.as_ref()))
116 });
117 let edition =
118 current_module.map(|it| it.krate(ctx.db()).edition(ctx.db())).unwrap_or(Edition::CURRENT);
119
120 let group_label = group_label(import_assets.import_candidate());
121 for import in proposed_imports {
122 let import_path = import.import_path;
123
124 let (assist_id, import_name) =
125 (AssistId::quick_fix("auto_import"), import_path.display(ctx.db(), edition));
126 let add_normal_import = |acc: &mut Assists, label| {
127 acc.add_group(&group_label, assist_id, label, range, |builder| {
128 let editor = builder.make_editor(scope.as_syntax_node());
129 insert_use_with_editor(
130 &scope,
131 mod_path_to_ast(&import_path, edition),
132 &ctx.config.insert_use,
133 &editor,
134 );
135 builder.add_file_edits(ctx.vfs_file_id(), editor);
136 })
137 };
138 let add_underscore_import = |acc: &mut Assists, name: &TraitImportCandidate<'_>, label| {
139 let is_method =
140 matches!(import_assets.import_candidate(), ImportCandidate::TraitMethod(_));
141 let type_ = if is_method { "method" } else { "item" };
142 let group_label = GroupLabel(format!(
143 "Import a trait for {} {} by alias",
144 type_,
145 name.assoc_item_name.text()
146 ));
147 acc.add_group(&group_label, assist_id, label, range, |builder| {
148 let editor = builder.make_editor(scope.as_syntax_node());
149 insert_use_as_alias_with_editor(
150 &scope,
151 mod_path_to_ast(&import_path, edition),
152 &ctx.config.insert_use,
153 edition,
154 &editor,
155 );
156 builder.add_file_edits(ctx.vfs_file_id(), editor);
157 });
158 };
159
160 if let ImportCandidate::TraitAssocItem(name) | ImportCandidate::TraitMethod(name) =
161 import_assets.import_candidate()
162 {
163 if let hir::ItemInNs::Types(hir::ModuleDef::Trait(trait_to_import)) =
164 import.item_to_import
165 && trait_to_import.prefer_underscore_import(ctx.db())
166 {
167 add_underscore_import(acc, name, format!("Import `{import_name}`"));
169 add_normal_import(acc, format!("Import `{import_name}` without `as _`"));
170 } else {
171 add_normal_import(acc, format!("Import `{import_name}`"));
172 add_underscore_import(acc, name, format!("Import `{import_name} as _`"));
173 }
174 } else {
175 add_normal_import(acc, format!("Import `{import_name}`"));
176 }
177 }
178 Some(())
179}
180
181pub(super) fn find_importable_node<'db>(
182 ctx: &AssistContext<'_, 'db>,
183) -> Option<(ImportAssets<'db>, SyntaxNode, Option<Type<'db>>)> {
184 let expected = |expr_or_pat: Either<ast::Expr, ast::Pat>| match expr_or_pat {
186 Either::Left(expr) => {
187 let parent = expr.syntax().parent()?;
188 match_ast! {
190 match parent {
191 ast::ArgList(list) => {
192 ActiveParameter::at_arg(
193 &ctx.sema,
194 list,
195 expr.syntax().text_range().start(),
196 ).map(|ap| ap.ty)
197 },
198 ast::LetStmt(stmt) => {
199 ctx.sema.type_of_pat(&stmt.pat()?).map(|t| t.original)
200 },
201 _ => None,
202 }
203 }
204 }
205 Either::Right(pat) => {
206 let parent = pat.syntax().parent()?;
207 match_ast! {
209 match parent {
210 ast::LetStmt(stmt) => {
211 ctx.sema.type_of_expr(&stmt.initializer()?).map(|t| t.original)
212 },
213 _ => None,
214 }
215 }
216 }
217 };
218
219 if let Some(path_under_caret) = ctx.find_node_at_offset_with_descend::<ast::Path>() {
220 let expected =
221 path_under_caret.top_path().syntax().parent().and_then(Either::cast).and_then(expected);
222 ImportAssets::for_exact_path(&path_under_caret, &ctx.sema)
223 .map(|it| (it, path_under_caret.syntax().clone(), expected))
224 } else if let Some(method_under_caret) =
225 ctx.find_node_at_offset_with_descend::<ast::MethodCallExpr>()
226 {
227 let expected = expected(Either::Left(method_under_caret.clone().into()));
228 ImportAssets::for_method_call(&method_under_caret, &ctx.sema)
229 .map(|it| (it, method_under_caret.syntax().clone(), expected))
230 } else if ctx.find_node_at_offset_with_descend::<ast::Param>().is_some() {
231 None
232 } else if let Some(pat) = ctx
233 .find_node_at_offset_with_descend::<ast::IdentPat>()
234 .filter(ast::IdentPat::is_simple_ident)
235 {
236 let expected = expected(Either::Right(pat.clone().into()));
237 ImportAssets::for_ident_pat(&ctx.sema, &pat).map(|it| (it, pat.syntax().clone(), expected))
238 } else {
239 None
240 }
241}
242
243fn group_label(import_candidate: &ImportCandidate<'_>) -> GroupLabel {
244 let name = match import_candidate {
245 ImportCandidate::Path(candidate) => format!("Import {}", candidate.name.text()),
246 ImportCandidate::TraitAssocItem(candidate) => {
247 format!("Import a trait for item {}", candidate.assoc_item_name.text())
248 }
249 ImportCandidate::TraitMethod(candidate) => {
250 format!("Import a trait for method {}", candidate.assoc_item_name.text())
251 }
252 };
253 GroupLabel(name)
254}
255
256pub(crate) fn relevance_score(
259 ctx: &AssistContext<'_, '_>,
260 import: &LocatedImport,
261 expected: Option<&Type<'_>>,
262 current_module: Option<&Module>,
263) -> i32 {
264 let mut score = 0;
265
266 let db = ctx.db();
267
268 let item_module = match import.item_to_import {
269 hir::ItemInNs::Types(item) | hir::ItemInNs::Values(item) => item.module(db),
270 hir::ItemInNs::Macros(makro) => Some(makro.module(db)),
271 };
272
273 if let Some(expected) = expected {
274 let ty = match import.item_to_import {
275 hir::ItemInNs::Types(module_def) | hir::ItemInNs::Values(module_def) => {
276 match module_def {
277 hir::ModuleDef::Function(function) => Some(function.ret_type(ctx.db())),
278 hir::ModuleDef::Adt(adt) => Some(match adt {
279 hir::Adt::Struct(it) => it.ty(ctx.db()),
280 hir::Adt::Union(it) => it.ty(ctx.db()),
281 hir::Adt::Enum(it) => it.ty(ctx.db()),
282 }),
283 hir::ModuleDef::EnumVariant(variant) => Some(variant.constructor_ty(ctx.db())),
284 hir::ModuleDef::Const(it) => Some(it.ty(ctx.db())),
285 hir::ModuleDef::Static(it) => Some(it.ty(ctx.db())),
286 hir::ModuleDef::TypeAlias(it) => Some(it.ty(ctx.db())),
287 hir::ModuleDef::BuiltinType(it) => Some(it.ty(ctx.db())),
288 _ => None,
289 }
290 }
291 hir::ItemInNs::Macros(_) => None,
292 };
293 if let Some(ty) = ty {
294 if ty == *expected {
295 score = 100000;
296 } else if ty.could_unify_with(ctx.db(), expected) {
297 score = 10000;
298 }
299 }
300 }
301
302 match item_module.zip(current_module) {
303 Some((item_module, current_module)) => {
306 score -= module_distance_heuristic(db, current_module, &item_module) as i32;
307 }
308
309 None => return -(2 * import.import_path.len() as i32),
311 }
312
313 score
314}
315
316fn module_distance_heuristic(db: &dyn HirDatabase, current: &Module, item: &Module) -> usize {
318 let mut current_path = current.path_to_root(db);
320 let mut item_path = item.path_to_root(db);
321
322 current_path.reverse();
324 item_path.reverse();
325
326 let prefix_length = current_path.iter().zip(&item_path).take_while(|(a, b)| a == b).count();
328
329 let distinct_length = current_path.len() + item_path.len() - 2 * prefix_length;
331
332 let crate_boundary_cost = if current.krate(db) == item.krate(db) {
334 0
335 } else if item.krate(db).origin(db).is_local() {
336 2
337 } else if item.krate(db).is_builtin(db) {
338 3
339 } else {
340 4
341 };
342
343 distinct_length + crate_boundary_cost
344}
345
346#[cfg(test)]
347mod tests {
348 use super::*;
349
350 use hir::{FileRange, Semantics};
351 use ide_db::{RootDatabase, assists::AssistResolveStrategy};
352 use test_fixture::WithFixture;
353
354 use crate::tests::{
355 TEST_CONFIG, check_assist, check_assist_by_label, check_assist_not_applicable,
356 check_assist_target,
357 };
358
359 fn check_auto_import_order(before: &str, order: &[&str]) {
360 let (db, file_id, range_or_offset) = RootDatabase::with_range_or_offset(before);
361 let frange = FileRange { file_id, range: range_or_offset.into() };
362
363 let sema = Semantics::new(&db);
364 let config = TEST_CONFIG;
365 let ctx = AssistContext::new(sema, &config, frange);
366 let mut acc = Assists::new(&ctx, AssistResolveStrategy::All);
367 hir::attach_db(&db, || auto_import(&mut acc, &ctx));
368 let assists = acc.finish();
369
370 let labels = assists.iter().map(|assist| assist.label.to_string()).collect::<Vec<_>>();
371
372 assert_eq!(labels, order);
373 }
374
375 #[test]
376 fn ignore_parameter_name() {
377 check_assist_not_applicable(
378 auto_import,
379 r"
380 mod foo {
381 pub mod bar {}
382 }
383
384 fn foo(bar$0: &str) {}
385 ",
386 );
387 }
388
389 #[test]
390 fn prefer_shorter_paths() {
391 let before = r"
392//- /main.rs crate:main deps:foo,bar
393HashMap$0::new();
394
395//- /lib.rs crate:foo
396pub mod collections { pub struct HashMap; }
397
398//- /lib.rs crate:bar
399pub mod collections { pub mod hash_map { pub struct HashMap; } }
400 ";
401
402 check_auto_import_order(
403 before,
404 &["Import `foo::collections::HashMap`", "Import `bar::collections::hash_map::HashMap`"],
405 )
406 }
407
408 #[test]
409 fn prefer_same_crate() {
410 let before = r"
411//- /main.rs crate:main deps:foo
412HashMap$0::new();
413
414mod collections {
415 pub mod hash_map {
416 pub struct HashMap;
417 }
418}
419
420//- /lib.rs crate:foo
421pub struct HashMap;
422 ";
423
424 check_auto_import_order(
425 before,
426 &["Import `collections::hash_map::HashMap`", "Import `foo::HashMap`"],
427 )
428 }
429
430 #[test]
431 fn prefer_workspace() {
432 let before = r"
433//- /main.rs crate:main deps:foo,bar
434HashMap$0::new();
435
436//- /lib.rs crate:foo
437pub mod module {
438 pub struct HashMap;
439}
440
441//- /lib.rs crate:bar library
442pub struct HashMap;
443 ";
444
445 check_auto_import_order(before, &["Import `foo::module::HashMap`", "Import `bar::HashMap`"])
446 }
447
448 #[test]
449 fn prefer_non_local_over_long_path() {
450 let before = r"
451//- /main.rs crate:main deps:foo,bar
452HashMap$0::new();
453
454//- /lib.rs crate:foo
455pub mod deeply {
456 pub mod nested {
457 pub mod module {
458 pub struct HashMap;
459 }
460 }
461}
462
463//- /lib.rs crate:bar library
464pub struct HashMap;
465 ";
466
467 check_auto_import_order(
468 before,
469 &["Import `bar::HashMap`", "Import `foo::deeply::nested::module::HashMap`"],
470 )
471 }
472
473 #[test]
474 fn not_applicable_if_scope_inside_macro() {
475 check_assist_not_applicable(
476 auto_import,
477 r"
478mod bar {
479 pub struct Baz;
480}
481macro_rules! foo {
482 ($it:ident) => {
483 mod __ {
484 fn __(x: $it) {}
485 }
486 };
487}
488foo! {
489 Baz$0
490}
491",
492 );
493 }
494
495 #[test]
496 fn applicable_in_attributes() {
497 check_assist(
498 auto_import,
499 r"
500//- proc_macros: identity
501#[proc_macros::identity]
502mod foo {
503 mod bar {
504 const _: Baz$0 = ();
505 }
506}
507mod baz {
508 pub struct Baz;
509}
510",
511 r"
512#[proc_macros::identity]
513mod foo {
514 mod bar {
515 use crate::baz::Baz;
516
517 const _: Baz = ();
518 }
519}
520mod baz {
521 pub struct Baz;
522}
523",
524 );
525 }
526
527 #[test]
528 fn applicable_when_found_an_import_partial() {
529 check_assist(
530 auto_import,
531 r"
532 mod std {
533 pub mod fmt {
534 pub struct Formatter;
535 }
536 }
537
538 use std::fmt;
539
540 $0Formatter
541 ",
542 r"
543 mod std {
544 pub mod fmt {
545 pub struct Formatter;
546 }
547 }
548
549 use std::fmt::{self, Formatter};
550
551 Formatter
552 ",
553 );
554 }
555
556 #[test]
557 fn applicable_when_found_an_import() {
558 check_assist(
559 auto_import,
560 r"
561 $0PubStruct
562
563 pub mod PubMod {
564 pub struct PubStruct;
565 }
566 ",
567 r"
568 use PubMod::PubStruct;
569
570 PubStruct
571
572 pub mod PubMod {
573 pub struct PubStruct;
574 }
575 ",
576 );
577 }
578
579 #[test]
580 fn applicable_when_found_an_import_in_macros() {
581 check_assist(
582 auto_import,
583 r"
584 macro_rules! foo {
585 ($i:ident) => { fn foo(a: $i) {} }
586 }
587 foo!(Pub$0Struct);
588
589 pub mod PubMod {
590 pub struct PubStruct;
591 }
592 ",
593 r"
594 use PubMod::PubStruct;
595
596 macro_rules! foo {
597 ($i:ident) => { fn foo(a: $i) {} }
598 }
599 foo!(PubStruct);
600
601 pub mod PubMod {
602 pub struct PubStruct;
603 }
604 ",
605 );
606 }
607
608 #[test]
609 fn applicable_when_found_multiple_imports() {
610 check_assist(
611 auto_import,
612 r"
613 PubSt$0ruct
614
615 pub mod PubMod1 {
616 pub struct PubStruct;
617 }
618 pub mod PubMod2 {
619 pub struct PubStruct;
620 }
621 pub mod PubMod3 {
622 pub struct PubStruct;
623 }
624 ",
625 r"
626 use PubMod1::PubStruct;
627
628 PubStruct
629
630 pub mod PubMod1 {
631 pub struct PubStruct;
632 }
633 pub mod PubMod2 {
634 pub struct PubStruct;
635 }
636 pub mod PubMod3 {
637 pub struct PubStruct;
638 }
639 ",
640 );
641 }
642
643 #[test]
644 fn not_applicable_for_already_imported_types() {
645 check_assist_not_applicable(
646 auto_import,
647 r"
648 use PubMod::PubStruct;
649
650 PubStruct$0
651
652 pub mod PubMod {
653 pub struct PubStruct;
654 }
655 ",
656 );
657 }
658
659 #[test]
660 fn not_applicable_for_types_with_private_paths() {
661 check_assist_not_applicable(
662 auto_import,
663 r"
664 PrivateStruct$0
665
666 pub mod PubMod {
667 struct PrivateStruct;
668 }
669 ",
670 );
671 }
672
673 #[test]
674 fn not_applicable_when_no_imports_found() {
675 check_assist_not_applicable(
676 auto_import,
677 "
678 PubStruct$0",
679 );
680 }
681
682 #[test]
683 fn function_import() {
684 check_assist(
685 auto_import,
686 r"
687 test_function$0
688
689 pub mod PubMod {
690 pub fn test_function() {};
691 }
692 ",
693 r"
694 use PubMod::test_function;
695
696 test_function
697
698 pub mod PubMod {
699 pub fn test_function() {};
700 }
701 ",
702 );
703 }
704
705 #[test]
706 fn macro_import() {
707 check_assist(
708 auto_import,
709 r"
710//- /lib.rs crate:crate_with_macro
711#[macro_export]
712macro_rules! foo {
713 () => ()
714}
715
716//- /main.rs crate:main deps:crate_with_macro
717fn main() {
718 foo$0
719}
720",
721 r"use crate_with_macro::foo;
722
723fn main() {
724 foo
725}
726",
727 );
728 }
729
730 #[test]
731 fn auto_import_target() {
732 check_assist_target(
733 auto_import,
734 r"
735 struct AssistInfo {
736 group_label: Option<$0GroupLabel>,
737 }
738
739 mod m { pub struct GroupLabel; }
740 ",
741 "GroupLabel",
742 )
743 }
744
745 #[test]
746 fn not_applicable_when_path_start_is_imported() {
747 check_assist_not_applicable(
748 auto_import,
749 r"
750 pub mod mod1 {
751 pub mod mod2 {
752 pub mod mod3 {
753 pub struct TestStruct;
754 }
755 }
756 }
757
758 use mod1::mod2;
759 fn main() {
760 mod2::mod3::TestStruct$0
761 }
762 ",
763 );
764 }
765
766 #[test]
767 fn not_applicable_for_imported_function() {
768 check_assist_not_applicable(
769 auto_import,
770 r"
771 pub mod test_mod {
772 pub fn test_function() {}
773 }
774
775 use test_mod::test_function;
776 fn main() {
777 test_function$0
778 }
779 ",
780 );
781 }
782
783 #[test]
784 fn associated_struct_function() {
785 check_assist(
786 auto_import,
787 r"
788 mod test_mod {
789 pub struct TestStruct {}
790 impl TestStruct {
791 pub fn test_function() {}
792 }
793 }
794
795 fn main() {
796 TestStruct::test_function$0
797 }
798 ",
799 r"
800 use test_mod::TestStruct;
801
802 mod test_mod {
803 pub struct TestStruct {}
804 impl TestStruct {
805 pub fn test_function() {}
806 }
807 }
808
809 fn main() {
810 TestStruct::test_function
811 }
812 ",
813 );
814 }
815
816 #[test]
817 fn associated_struct_const() {
818 check_assist(
819 auto_import,
820 r"
821 mod test_mod {
822 pub struct TestStruct {}
823 impl TestStruct {
824 const TEST_CONST: u8 = 42;
825 }
826 }
827
828 fn main() {
829 TestStruct::TEST_CONST$0
830 }
831 ",
832 r"
833 use test_mod::TestStruct;
834
835 mod test_mod {
836 pub struct TestStruct {}
837 impl TestStruct {
838 const TEST_CONST: u8 = 42;
839 }
840 }
841
842 fn main() {
843 TestStruct::TEST_CONST
844 }
845 ",
846 );
847 }
848
849 #[test]
850 fn associated_trait_function() {
851 check_assist_by_label(
852 auto_import,
853 r"
854 mod test_mod {
855 pub trait TestTrait {
856 fn test_function();
857 }
858 pub struct TestStruct {}
859 impl TestTrait for TestStruct {
860 fn test_function() {}
861 }
862 }
863
864 fn main() {
865 test_mod::TestStruct::test_function$0
866 }
867 ",
868 r"
869 use test_mod::TestTrait;
870
871 mod test_mod {
872 pub trait TestTrait {
873 fn test_function();
874 }
875 pub struct TestStruct {}
876 impl TestTrait for TestStruct {
877 fn test_function() {}
878 }
879 }
880
881 fn main() {
882 test_mod::TestStruct::test_function
883 }
884 ",
885 "Import `test_mod::TestTrait`",
886 );
887
888 check_assist_by_label(
889 auto_import,
890 r"
891 mod test_mod {
892 pub trait TestTrait {
893 fn test_function();
894 }
895 pub struct TestStruct {}
896 impl TestTrait for TestStruct {
897 fn test_function() {}
898 }
899 }
900
901 fn main() {
902 test_mod::TestStruct::test_function$0
903 }
904 ",
905 r"
906 use test_mod::TestTrait as _;
907
908 mod test_mod {
909 pub trait TestTrait {
910 fn test_function();
911 }
912 pub struct TestStruct {}
913 impl TestTrait for TestStruct {
914 fn test_function() {}
915 }
916 }
917
918 fn main() {
919 test_mod::TestStruct::test_function
920 }
921 ",
922 "Import `test_mod::TestTrait as _`",
923 );
924 }
925
926 #[test]
927 fn not_applicable_for_imported_trait_for_function() {
928 check_assist_not_applicable(
929 auto_import,
930 r"
931 mod test_mod {
932 pub trait TestTrait {
933 fn test_function();
934 }
935 pub trait TestTrait2 {
936 fn test_function();
937 }
938 pub enum TestEnum {
939 One,
940 Two,
941 }
942 impl TestTrait2 for TestEnum {
943 fn test_function() {}
944 }
945 impl TestTrait for TestEnum {
946 fn test_function() {}
947 }
948 }
949
950 use test_mod::TestTrait2;
951 fn main() {
952 test_mod::TestEnum::test_function$0;
953 }
954 ",
955 )
956 }
957
958 #[test]
959 fn associated_trait_const() {
960 check_assist_by_label(
961 auto_import,
962 r"
963 mod test_mod {
964 pub trait TestTrait {
965 const TEST_CONST: u8;
966 }
967 pub struct TestStruct {}
968 impl TestTrait for TestStruct {
969 const TEST_CONST: u8 = 42;
970 }
971 }
972
973 fn main() {
974 test_mod::TestStruct::TEST_CONST$0
975 }
976 ",
977 r"
978 use test_mod::TestTrait as _;
979
980 mod test_mod {
981 pub trait TestTrait {
982 const TEST_CONST: u8;
983 }
984 pub struct TestStruct {}
985 impl TestTrait for TestStruct {
986 const TEST_CONST: u8 = 42;
987 }
988 }
989
990 fn main() {
991 test_mod::TestStruct::TEST_CONST
992 }
993 ",
994 "Import `test_mod::TestTrait as _`",
995 );
996
997 check_assist_by_label(
998 auto_import,
999 r"
1000 mod test_mod {
1001 pub trait TestTrait {
1002 const TEST_CONST: u8;
1003 }
1004 pub struct TestStruct {}
1005 impl TestTrait for TestStruct {
1006 const TEST_CONST: u8 = 42;
1007 }
1008 }
1009
1010 fn main() {
1011 test_mod::TestStruct::TEST_CONST$0
1012 }
1013 ",
1014 r"
1015 use test_mod::TestTrait;
1016
1017 mod test_mod {
1018 pub trait TestTrait {
1019 const TEST_CONST: u8;
1020 }
1021 pub struct TestStruct {}
1022 impl TestTrait for TestStruct {
1023 const TEST_CONST: u8 = 42;
1024 }
1025 }
1026
1027 fn main() {
1028 test_mod::TestStruct::TEST_CONST
1029 }
1030 ",
1031 "Import `test_mod::TestTrait`",
1032 );
1033 }
1034
1035 #[test]
1036 fn not_applicable_for_imported_trait_for_const() {
1037 check_assist_not_applicable(
1038 auto_import,
1039 r"
1040 mod test_mod {
1041 pub trait TestTrait {
1042 const TEST_CONST: u8;
1043 }
1044 pub trait TestTrait2 {
1045 const TEST_CONST: f64;
1046 }
1047 pub enum TestEnum {
1048 One,
1049 Two,
1050 }
1051 impl TestTrait2 for TestEnum {
1052 const TEST_CONST: f64 = 42.0;
1053 }
1054 impl TestTrait for TestEnum {
1055 const TEST_CONST: u8 = 42;
1056 }
1057 }
1058
1059 use test_mod::TestTrait2;
1060 fn main() {
1061 test_mod::TestEnum::TEST_CONST$0;
1062 }
1063 ",
1064 )
1065 }
1066
1067 #[test]
1068 fn trait_method() {
1069 check_assist_by_label(
1070 auto_import,
1071 r"
1072 mod test_mod {
1073 pub trait TestTrait {
1074 fn test_method(&self);
1075 }
1076 pub struct TestStruct {}
1077 impl TestTrait for TestStruct {
1078 fn test_method(&self) {}
1079 }
1080 }
1081
1082 fn main() {
1083 let test_struct = test_mod::TestStruct {};
1084 test_struct.test_meth$0od()
1085 }
1086 ",
1087 r"
1088 use test_mod::TestTrait as _;
1089
1090 mod test_mod {
1091 pub trait TestTrait {
1092 fn test_method(&self);
1093 }
1094 pub struct TestStruct {}
1095 impl TestTrait for TestStruct {
1096 fn test_method(&self) {}
1097 }
1098 }
1099
1100 fn main() {
1101 let test_struct = test_mod::TestStruct {};
1102 test_struct.test_method()
1103 }
1104 ",
1105 "Import `test_mod::TestTrait as _`",
1106 );
1107
1108 check_assist_by_label(
1109 auto_import,
1110 r"
1111 mod test_mod {
1112 pub trait TestTrait {
1113 fn test_method(&self);
1114 }
1115 pub struct TestStruct {}
1116 impl TestTrait for TestStruct {
1117 fn test_method(&self) {}
1118 }
1119 }
1120
1121 fn main() {
1122 let test_struct = test_mod::TestStruct {};
1123 test_struct.test_meth$0od()
1124 }
1125 ",
1126 r"
1127 use test_mod::TestTrait;
1128
1129 mod test_mod {
1130 pub trait TestTrait {
1131 fn test_method(&self);
1132 }
1133 pub struct TestStruct {}
1134 impl TestTrait for TestStruct {
1135 fn test_method(&self) {}
1136 }
1137 }
1138
1139 fn main() {
1140 let test_struct = test_mod::TestStruct {};
1141 test_struct.test_method()
1142 }
1143 ",
1144 "Import `test_mod::TestTrait`",
1145 );
1146 }
1147
1148 #[test]
1149 fn trait_method_cross_crate() {
1150 check_assist_by_label(
1151 auto_import,
1152 r"
1153 //- /main.rs crate:main deps:dep
1154 fn main() {
1155 let test_struct = dep::test_mod::TestStruct {};
1156 test_struct.test_meth$0od()
1157 }
1158 //- /dep.rs crate:dep
1159 pub mod test_mod {
1160 pub trait TestTrait {
1161 fn test_method(&self);
1162 }
1163 pub struct TestStruct {}
1164 impl TestTrait for TestStruct {
1165 fn test_method(&self) {}
1166 }
1167 }
1168 ",
1169 r"
1170 use dep::test_mod::TestTrait as _;
1171
1172 fn main() {
1173 let test_struct = dep::test_mod::TestStruct {};
1174 test_struct.test_method()
1175 }
1176 ",
1177 "Import `dep::test_mod::TestTrait as _`",
1178 );
1179
1180 check_assist_by_label(
1181 auto_import,
1182 r"
1183 //- /main.rs crate:main deps:dep
1184 fn main() {
1185 let test_struct = dep::test_mod::TestStruct {};
1186 test_struct.test_meth$0od()
1187 }
1188 //- /dep.rs crate:dep
1189 pub mod test_mod {
1190 pub trait TestTrait {
1191 fn test_method(&self);
1192 }
1193 pub struct TestStruct {}
1194 impl TestTrait for TestStruct {
1195 fn test_method(&self) {}
1196 }
1197 }
1198 ",
1199 r"
1200 use dep::test_mod::TestTrait;
1201
1202 fn main() {
1203 let test_struct = dep::test_mod::TestStruct {};
1204 test_struct.test_method()
1205 }
1206 ",
1207 "Import `dep::test_mod::TestTrait`",
1208 );
1209 }
1210
1211 #[test]
1212 fn assoc_fn_cross_crate() {
1213 check_assist_by_label(
1214 auto_import,
1215 r"
1216 //- /main.rs crate:main deps:dep
1217 fn main() {
1218 dep::test_mod::TestStruct::test_func$0tion
1219 }
1220 //- /dep.rs crate:dep
1221 pub mod test_mod {
1222 pub trait TestTrait {
1223 fn test_function();
1224 }
1225 pub struct TestStruct {}
1226 impl TestTrait for TestStruct {
1227 fn test_function() {}
1228 }
1229 }
1230 ",
1231 r"
1232 use dep::test_mod::TestTrait as _;
1233
1234 fn main() {
1235 dep::test_mod::TestStruct::test_function
1236 }
1237 ",
1238 "Import `dep::test_mod::TestTrait as _`",
1239 );
1240
1241 check_assist_by_label(
1242 auto_import,
1243 r"
1244 //- /main.rs crate:main deps:dep
1245 fn main() {
1246 dep::test_mod::TestStruct::test_func$0tion
1247 }
1248 //- /dep.rs crate:dep
1249 pub mod test_mod {
1250 pub trait TestTrait {
1251 fn test_function();
1252 }
1253 pub struct TestStruct {}
1254 impl TestTrait for TestStruct {
1255 fn test_function() {}
1256 }
1257 }
1258 ",
1259 r"
1260 use dep::test_mod::TestTrait;
1261
1262 fn main() {
1263 dep::test_mod::TestStruct::test_function
1264 }
1265 ",
1266 "Import `dep::test_mod::TestTrait`",
1267 );
1268 }
1269
1270 #[test]
1271 fn assoc_const_cross_crate() {
1272 check_assist_by_label(
1273 auto_import,
1274 r"
1275 //- /main.rs crate:main deps:dep
1276 fn main() {
1277 dep::test_mod::TestStruct::CONST$0
1278 }
1279 //- /dep.rs crate:dep
1280 pub mod test_mod {
1281 pub trait TestTrait {
1282 const CONST: bool;
1283 }
1284 pub struct TestStruct {}
1285 impl TestTrait for TestStruct {
1286 const CONST: bool = true;
1287 }
1288 }
1289 ",
1290 r"
1291 use dep::test_mod::TestTrait as _;
1292
1293 fn main() {
1294 dep::test_mod::TestStruct::CONST
1295 }
1296 ",
1297 "Import `dep::test_mod::TestTrait as _`",
1298 );
1299
1300 check_assist_by_label(
1301 auto_import,
1302 r"
1303 //- /main.rs crate:main deps:dep
1304 fn main() {
1305 dep::test_mod::TestStruct::CONST$0
1306 }
1307 //- /dep.rs crate:dep
1308 pub mod test_mod {
1309 pub trait TestTrait {
1310 const CONST: bool;
1311 }
1312 pub struct TestStruct {}
1313 impl TestTrait for TestStruct {
1314 const CONST: bool = true;
1315 }
1316 }
1317 ",
1318 r"
1319 use dep::test_mod::TestTrait;
1320
1321 fn main() {
1322 dep::test_mod::TestStruct::CONST
1323 }
1324 ",
1325 "Import `dep::test_mod::TestTrait`",
1326 );
1327 }
1328
1329 #[test]
1330 fn assoc_fn_as_method_cross_crate() {
1331 check_assist_not_applicable(
1332 auto_import,
1333 r"
1334 //- /main.rs crate:main deps:dep
1335 fn main() {
1336 let test_struct = dep::test_mod::TestStruct {};
1337 test_struct.test_func$0tion()
1338 }
1339 //- /dep.rs crate:dep
1340 pub mod test_mod {
1341 pub trait TestTrait {
1342 fn test_function();
1343 }
1344 pub struct TestStruct {}
1345 impl TestTrait for TestStruct {
1346 fn test_function() {}
1347 }
1348 }
1349 ",
1350 );
1351 }
1352
1353 #[test]
1354 fn private_trait_cross_crate() {
1355 check_assist_not_applicable(
1356 auto_import,
1357 r"
1358 //- /main.rs crate:main deps:dep
1359 fn main() {
1360 let test_struct = dep::test_mod::TestStruct {};
1361 test_struct.test_meth$0od()
1362 }
1363 //- /dep.rs crate:dep
1364 pub mod test_mod {
1365 trait TestTrait {
1366 fn test_method(&self);
1367 }
1368 pub struct TestStruct {}
1369 impl TestTrait for TestStruct {
1370 fn test_method(&self) {}
1371 }
1372 }
1373 ",
1374 );
1375 }
1376
1377 #[test]
1378 fn not_applicable_for_imported_trait_for_method() {
1379 check_assist_not_applicable(
1380 auto_import,
1381 r"
1382 mod test_mod {
1383 pub trait TestTrait {
1384 fn test_method(&self);
1385 }
1386 pub trait TestTrait2 {
1387 fn test_method(&self);
1388 }
1389 pub enum TestEnum {
1390 One,
1391 Two,
1392 }
1393 impl TestTrait2 for TestEnum {
1394 fn test_method(&self) {}
1395 }
1396 impl TestTrait for TestEnum {
1397 fn test_method(&self) {}
1398 }
1399 }
1400
1401 use test_mod::TestTrait2;
1402 fn main() {
1403 let one = test_mod::TestEnum::One;
1404 one.test$0_method();
1405 }
1406 ",
1407 )
1408 }
1409
1410 #[test]
1411 fn dep_import() {
1412 check_assist(
1413 auto_import,
1414 r"
1415//- /lib.rs crate:dep
1416pub struct Struct;
1417
1418//- /main.rs crate:main deps:dep
1419fn main() {
1420 Struct$0
1421}
1422",
1423 r"use dep::Struct;
1424
1425fn main() {
1426 Struct
1427}
1428",
1429 );
1430 }
1431
1432 #[test]
1433 fn whole_segment() {
1434 check_assist(
1436 auto_import,
1437 r"
1438//- /lib.rs crate:dep
1439pub mod fmt {
1440 pub trait Display {}
1441}
1442
1443pub fn panic_fmt() {}
1444
1445//- /main.rs crate:main deps:dep
1446struct S;
1447
1448impl f$0mt::Display for S {}
1449",
1450 r"use dep::fmt;
1451
1452struct S;
1453
1454impl fmt::Display for S {}
1455",
1456 );
1457 }
1458
1459 #[test]
1460 fn macro_generated() {
1461 check_assist(
1463 auto_import,
1464 r"
1465//- /lib.rs crate:dep
1466macro_rules! mac {
1467 () => {
1468 pub struct Cheese;
1469 };
1470}
1471
1472mac!();
1473
1474//- /main.rs crate:main deps:dep
1475fn main() {
1476 Cheese$0;
1477}
1478",
1479 r"use dep::Cheese;
1480
1481fn main() {
1482 Cheese;
1483}
1484",
1485 );
1486 }
1487
1488 #[test]
1489 fn casing() {
1490 check_assist(
1492 auto_import,
1493 r"
1494//- /lib.rs crate:dep
1495pub struct FMT;
1496pub struct fmt;
1497
1498//- /main.rs crate:main deps:dep
1499fn main() {
1500 FMT$0;
1501}
1502",
1503 r"use dep::FMT;
1504
1505fn main() {
1506 FMT;
1507}
1508",
1509 );
1510 }
1511
1512 #[test]
1513 fn inner_items() {
1514 check_assist(
1515 auto_import,
1516 r#"
1517mod baz {
1518 pub struct Foo {}
1519}
1520
1521mod bar {
1522 fn bar() {
1523 Foo$0;
1524 println!("Hallo");
1525 }
1526}
1527"#,
1528 r#"
1529mod baz {
1530 pub struct Foo {}
1531}
1532
1533mod bar {
1534 use crate::baz::Foo;
1535
1536 fn bar() {
1537 Foo;
1538 println!("Hallo");
1539 }
1540}
1541"#,
1542 );
1543 }
1544
1545 #[test]
1546 fn uses_abs_path_with_extern_crate_clash() {
1547 cov_mark::check!(ambiguous_crate_start);
1548 check_assist(
1549 auto_import,
1550 r#"
1551//- /main.rs crate:main deps:foo
1552mod foo {}
1553
1554const _: () = {
1555 Foo$0
1556};
1557//- /foo.rs crate:foo
1558pub struct Foo
1559"#,
1560 r#"
1561use ::foo::Foo;
1562
1563mod foo {}
1564
1565const _: () = {
1566 Foo
1567};
1568"#,
1569 );
1570 }
1571
1572 #[test]
1573 fn works_on_ident_patterns() {
1574 check_assist(
1575 auto_import,
1576 r#"
1577mod foo {
1578 pub struct Foo {}
1579}
1580fn foo() {
1581 let Foo$0;
1582}
1583"#,
1584 r#"
1585use foo::Foo;
1586
1587mod foo {
1588 pub struct Foo {}
1589}
1590fn foo() {
1591 let Foo;
1592}
1593"#,
1594 );
1595 }
1596
1597 #[test]
1598 fn works_in_derives() {
1599 check_assist(
1600 auto_import,
1601 r#"
1602//- minicore:derive
1603mod foo {
1604 #[rustc_builtin_macro]
1605 pub macro Copy {}
1606}
1607#[derive(Copy$0)]
1608struct Foo;
1609"#,
1610 r#"
1611use foo::Copy;
1612
1613mod foo {
1614 #[rustc_builtin_macro]
1615 pub macro Copy {}
1616}
1617#[derive(Copy)]
1618struct Foo;
1619"#,
1620 );
1621 }
1622
1623 #[test]
1624 fn works_in_use_start() {
1625 check_assist(
1626 auto_import,
1627 r#"
1628mod bar {
1629 pub mod foo {
1630 pub struct Foo;
1631 }
1632}
1633use foo$0::Foo;
1634"#,
1635 r#"
1636mod bar {
1637 pub mod foo {
1638 pub struct Foo;
1639 }
1640}
1641use bar::foo;
1642use foo::Foo;
1643"#,
1644 );
1645 }
1646
1647 #[test]
1648 fn not_applicable_in_non_start_use() {
1649 check_assist_not_applicable(
1650 auto_import,
1651 r"
1652mod bar {
1653 pub mod foo {
1654 pub struct Foo;
1655 }
1656}
1657use foo::Foo$0;
1658",
1659 );
1660 }
1661
1662 #[test]
1663 fn considers_pub_crate() {
1664 check_assist(
1665 auto_import,
1666 r#"
1667mod foo {
1668 pub struct Foo;
1669}
1670
1671pub(crate) use self::foo::*;
1672
1673mod bar {
1674 fn main() {
1675 Foo$0;
1676 }
1677}
1678"#,
1679 r#"
1680mod foo {
1681 pub struct Foo;
1682}
1683
1684pub(crate) use self::foo::*;
1685
1686mod bar {
1687 use crate::Foo;
1688
1689 fn main() {
1690 Foo;
1691 }
1692}
1693"#,
1694 );
1695 }
1696
1697 #[test]
1698 fn local_inline_import_has_alias() {
1699 check_assist(
1701 auto_import,
1702 r#"
1703struct S<T>(T);
1704use S as IoResult;
1705
1706mod foo {
1707 pub fn bar() -> S$0<()> {}
1708}
1709"#,
1710 r#"
1711struct S<T>(T);
1712use S as IoResult;
1713
1714mod foo {
1715 use crate::S;
1716
1717 pub fn bar() -> S<()> {}
1718}
1719"#,
1720 );
1721 }
1722
1723 #[test]
1724 fn alias_local() {
1725 check_assist(
1727 auto_import,
1728 r#"
1729struct S<T>(T);
1730use S as IoResult;
1731
1732mod foo {
1733 pub fn bar() -> IoResult$0<()> {}
1734}
1735"#,
1736 r#"
1737struct S<T>(T);
1738use S as IoResult;
1739
1740mod foo {
1741 use crate::S;
1742
1743 pub fn bar() -> IoResult<()> {}
1744}
1745"#,
1746 );
1747 }
1748
1749 #[test]
1750 fn preserve_raw_identifiers_strict() {
1751 check_assist(
1752 auto_import,
1753 r"
1754 r#as$0
1755
1756 pub mod ffi_mod {
1757 pub fn r#as() {};
1758 }
1759 ",
1760 r"
1761 use ffi_mod::r#as;
1762
1763 r#as
1764
1765 pub mod ffi_mod {
1766 pub fn r#as() {};
1767 }
1768 ",
1769 );
1770 }
1771
1772 #[test]
1773 fn preserve_raw_identifiers_reserved() {
1774 check_assist(
1775 auto_import,
1776 r"
1777 r#abstract$0
1778
1779 pub mod ffi_mod {
1780 pub fn r#abstract() {};
1781 }
1782 ",
1783 r"
1784 use ffi_mod::r#abstract;
1785
1786 r#abstract
1787
1788 pub mod ffi_mod {
1789 pub fn r#abstract() {};
1790 }
1791 ",
1792 );
1793 }
1794
1795 #[test]
1796 fn prefers_type_match() {
1797 check_assist(
1798 auto_import,
1799 r"
1800mod sync { pub mod atomic { pub enum Ordering { V } } }
1801mod cmp { pub enum Ordering { V } }
1802fn takes_ordering(_: sync::atomic::Ordering) {}
1803fn main() {
1804 takes_ordering(Ordering$0);
1805}
1806",
1807 r"
1808use sync::atomic::Ordering;
1809
1810mod sync { pub mod atomic { pub enum Ordering { V } } }
1811mod cmp { pub enum Ordering { V } }
1812fn takes_ordering(_: sync::atomic::Ordering) {}
1813fn main() {
1814 takes_ordering(Ordering);
1815}
1816",
1817 );
1818 check_assist(
1819 auto_import,
1820 r"
1821mod sync { pub mod atomic { pub enum Ordering { V } } }
1822mod cmp { pub enum Ordering { V } }
1823fn takes_ordering(_: cmp::Ordering) {}
1824fn main() {
1825 takes_ordering(Ordering$0);
1826}
1827",
1828 r"
1829use cmp::Ordering;
1830
1831mod sync { pub mod atomic { pub enum Ordering { V } } }
1832mod cmp { pub enum Ordering { V } }
1833fn takes_ordering(_: cmp::Ordering) {}
1834fn main() {
1835 takes_ordering(Ordering);
1836}
1837",
1838 );
1839 }
1840
1841 #[test]
1842 fn prefers_type_match2() {
1843 check_assist(
1844 auto_import,
1845 r"
1846mod sync { pub mod atomic { pub enum Ordering { V } } }
1847mod cmp { pub enum Ordering { V } }
1848fn takes_ordering(_: sync::atomic::Ordering) {}
1849fn main() {
1850 takes_ordering(Ordering$0::V);
1851}
1852",
1853 r"
1854use sync::atomic::Ordering;
1855
1856mod sync { pub mod atomic { pub enum Ordering { V } } }
1857mod cmp { pub enum Ordering { V } }
1858fn takes_ordering(_: sync::atomic::Ordering) {}
1859fn main() {
1860 takes_ordering(Ordering::V);
1861}
1862",
1863 );
1864 check_assist(
1865 auto_import,
1866 r"
1867mod sync { pub mod atomic { pub enum Ordering { V } } }
1868mod cmp { pub enum Ordering { V } }
1869fn takes_ordering(_: cmp::Ordering) {}
1870fn main() {
1871 takes_ordering(Ordering$0::V);
1872}
1873",
1874 r"
1875use cmp::Ordering;
1876
1877mod sync { pub mod atomic { pub enum Ordering { V } } }
1878mod cmp { pub enum Ordering { V } }
1879fn takes_ordering(_: cmp::Ordering) {}
1880fn main() {
1881 takes_ordering(Ordering::V);
1882}
1883",
1884 );
1885 }
1886
1887 #[test]
1888 fn carries_cfg_attr() {
1889 check_assist(
1890 auto_import,
1891 r#"
1892mod m {
1893 pub struct S;
1894}
1895
1896#[cfg(test)]
1897fn foo(_: S$0) {}
1898"#,
1899 r#"
1900#[cfg(test)]
1901use m::S;
1902
1903mod m {
1904 pub struct S;
1905}
1906
1907#[cfg(test)]
1908fn foo(_: S) {}
1909"#,
1910 );
1911 }
1912
1913 #[test]
1914 fn with_after_segments() {
1915 let before = r#"
1916mod foo {
1917 pub mod wanted {
1918 pub fn abc() {}
1919 }
1920}
1921
1922mod bar {
1923 pub mod wanted {}
1924}
1925
1926mod baz {
1927 pub fn wanted() {}
1928}
1929
1930mod quux {
1931 pub struct wanted;
1932}
1933impl quux::wanted {
1934 fn abc() {}
1935}
1936
1937fn f() {
1938 wanted$0::abc;
1939}
1940 "#;
1941 check_auto_import_order(before, &["Import `foo::wanted`", "Import `quux::wanted`"]);
1942 }
1943
1944 #[test]
1945 fn consider_definition_kind() {
1946 check_assist(
1947 auto_import,
1948 r#"
1949//- /eyre.rs crate:eyre
1950#[macro_export]
1951macro_rules! eyre {
1952 () => {};
1953}
1954
1955//- /color-eyre.rs crate:color-eyre deps:eyre
1956pub use eyre;
1957
1958//- /main.rs crate:main deps:color-eyre
1959fn main() {
1960 ey$0re!();
1961}
1962 "#,
1963 r#"
1964use color_eyre::eyre::eyre;
1965
1966fn main() {
1967 eyre!();
1968}
1969 "#,
1970 );
1971 }
1972
1973 #[test]
1974 fn prefer_underscore_import() {
1975 check_assist_by_label(
1976 auto_import,
1977 r#"
1978mod foo {
1979 #[rust_analyzer::prefer_underscore_import]
1980 pub trait Ext {
1981 fn bar(&self) {}
1982 }
1983 impl<T> Ext for T {}
1984}
1985
1986fn baz() {
1987 1.b$0ar();
1988}
1989 "#,
1990 r#"
1991use foo::Ext as _;
1992
1993mod foo {
1994 #[rust_analyzer::prefer_underscore_import]
1995 pub trait Ext {
1996 fn bar(&self) {}
1997 }
1998 impl<T> Ext for T {}
1999}
2000
2001fn baz() {
2002 1.bar();
2003}
2004 "#,
2005 "Import `foo::Ext`",
2006 );
2007 check_assist_by_label(
2008 auto_import,
2009 r#"
2010mod foo {
2011 #[rust_analyzer::prefer_underscore_import]
2012 pub trait Ext {
2013 fn bar(&self) {}
2014 }
2015 impl<T> Ext for T {}
2016}
2017
2018fn baz() {
2019 1.b$0ar();
2020}
2021 "#,
2022 r#"
2023use foo::Ext;
2024
2025mod foo {
2026 #[rust_analyzer::prefer_underscore_import]
2027 pub trait Ext {
2028 fn bar(&self) {}
2029 }
2030 impl<T> Ext for T {}
2031}
2032
2033fn baz() {
2034 1.bar();
2035}
2036 "#,
2037 "Import `foo::Ext` without `as _`",
2038 );
2039 }
2040}