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