5 import_assets::{ImportCandidate, LocatedImport},
6 item_name, mod_path_to_ast,
8 use ide_db::RootDatabase;
11 ast::{make, ArgListOwner},
16 assist_context::{AssistContext, Assists},
17 AssistId, AssistKind, GroupLabel,
20 use super::auto_import::find_importable_node;
22 // Assist: qualify_path
24 // If the name is unresolved, provides all possible qualified paths for it.
28 // let map = HashMap$0::new();
30 // # pub mod std { pub mod collections { pub struct HashMap { } } }
35 // let map = std::collections::HashMap::new();
37 // # pub mod std { pub mod collections { pub struct HashMap { } } }
39 pub(crate) fn qualify_path(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
40 let (import_assets, syntax_under_caret) = find_importable_node(ctx)?;
41 let proposed_imports = import_assets.search_for_relative_paths(&ctx.sema);
42 if proposed_imports.is_empty() {
46 let candidate = import_assets.import_candidate();
47 let range = ctx.sema.original_range(&syntax_under_caret).range;
49 let qualify_candidate = match candidate {
50 ImportCandidate::Path(candidate) => {
51 if candidate.qualifier.is_some() {
52 cov_mark::hit!(qualify_path_qualifier_start);
53 let path = ast::Path::cast(syntax_under_caret)?;
54 let (prev_segment, segment) = (path.qualifier()?.segment()?, path.segment()?);
55 QualifyCandidate::QualifierStart(segment, prev_segment.generic_arg_list())
57 cov_mark::hit!(qualify_path_unqualified_name);
58 let path = ast::Path::cast(syntax_under_caret)?;
59 let generics = path.segment()?.generic_arg_list();
60 QualifyCandidate::UnqualifiedName(generics)
63 ImportCandidate::TraitAssocItem(_) => {
64 cov_mark::hit!(qualify_path_trait_assoc_item);
65 let path = ast::Path::cast(syntax_under_caret)?;
66 let (qualifier, segment) = (path.qualifier()?, path.segment()?);
67 QualifyCandidate::TraitAssocItem(qualifier, segment)
69 ImportCandidate::TraitMethod(_) => {
70 cov_mark::hit!(qualify_path_trait_method);
71 let mcall_expr = ast::MethodCallExpr::cast(syntax_under_caret)?;
72 QualifyCandidate::TraitMethod(ctx.sema.db, mcall_expr)
76 let group_label = group_label(candidate);
77 for import in proposed_imports {
80 AssistId("qualify_path", AssistKind::QuickFix),
81 label(ctx.db(), candidate, &import),
84 qualify_candidate.qualify(
85 |replace_with: String| builder.replace(range, replace_with),
87 import.item_to_import,
95 enum QualifyCandidate<'db> {
96 QualifierStart(ast::PathSegment, Option<ast::GenericArgList>),
97 UnqualifiedName(Option<ast::GenericArgList>),
98 TraitAssocItem(ast::Path, ast::PathSegment),
99 TraitMethod(&'db RootDatabase, ast::MethodCallExpr),
102 impl QualifyCandidate<'_> {
105 mut replacer: impl FnMut(String),
106 import: &hir::ModPath,
109 let import = mod_path_to_ast(import);
111 QualifyCandidate::QualifierStart(segment, generics) => {
112 let generics = generics.as_ref().map_or_else(String::new, ToString::to_string);
113 replacer(format!("{}{}::{}", import, generics, segment));
115 QualifyCandidate::UnqualifiedName(generics) => {
116 let generics = generics.as_ref().map_or_else(String::new, ToString::to_string);
117 replacer(format!("{}{}", import.to_string(), generics));
119 QualifyCandidate::TraitAssocItem(qualifier, segment) => {
120 replacer(format!("<{} as {}>::{}", qualifier, import, segment));
122 &QualifyCandidate::TraitMethod(db, ref mcall_expr) => {
123 Self::qualify_trait_method(db, mcall_expr, replacer, import, item);
128 fn qualify_trait_method(
130 mcall_expr: &ast::MethodCallExpr,
131 mut replacer: impl FnMut(String),
135 let receiver = mcall_expr.receiver()?;
136 let trait_method_name = mcall_expr.name_ref()?;
138 mcall_expr.generic_arg_list().as_ref().map_or_else(String::new, ToString::to_string);
139 let arg_list = mcall_expr.arg_list().map(|arg_list| arg_list.args());
140 let trait_ = item_as_trait(db, item)?;
141 let method = find_trait_method(db, trait_, &trait_method_name)?;
142 if let Some(self_access) = method.self_param(db).map(|sp| sp.access(db)) {
143 let receiver = match self_access {
144 hir::Access::Shared => make::expr_ref(receiver, false),
145 hir::Access::Exclusive => make::expr_ref(receiver, true),
146 hir::Access::Owned => receiver,
154 Some(args) => make::arg_list(iter::once(receiver).chain(args)),
155 None => make::arg_list(iter::once(receiver)),
163 fn find_trait_method(
166 trait_method_name: &ast::NameRef,
167 ) -> Option<hir::Function> {
168 if let Some(hir::AssocItem::Function(method)) =
169 trait_.items(db).into_iter().find(|item: &hir::AssocItem| {
171 .map(|name| name.to_string() == trait_method_name.to_string())
181 fn item_as_trait(db: &RootDatabase, item: hir::ItemInNs) -> Option<hir::Trait> {
182 let item_module_def = hir::ModuleDef::from(item.as_module_def_id()?);
184 if let hir::ModuleDef::Trait(trait_) = item_module_def {
187 item_module_def.as_assoc_item(db)?.containing_trait(db)
191 fn group_label(candidate: &ImportCandidate) -> GroupLabel {
192 let name = match candidate {
193 ImportCandidate::Path(it) => &it.name,
194 ImportCandidate::TraitAssocItem(it) | ImportCandidate::TraitMethod(it) => {
199 GroupLabel(format!("Qualify {}", name))
202 fn label(db: &RootDatabase, candidate: &ImportCandidate, import: &LocatedImport) -> String {
203 let display_path = match item_name(db, import.original_item) {
204 Some(display_path) => display_path.to_string(),
205 None => "{unknown}".to_string(),
208 ImportCandidate::Path(candidate) => {
209 if candidate.qualifier.is_some() {
210 format!("Qualify with `{}`", display_path)
212 format!("Qualify as `{}`", display_path)
215 ImportCandidate::TraitAssocItem(_) => format!("Qualify `{}`", display_path),
216 ImportCandidate::TraitMethod(_) => format!("Qualify with cast as `{}`", display_path),
222 use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target};
227 fn applicable_when_found_an_import_partial() {
228 cov_mark::check!(qualify_path_unqualified_name);
234 pub struct Formatter;
245 pub struct Formatter;
257 fn applicable_when_found_an_import() {
264 pub struct PubStruct;
271 pub struct PubStruct;
278 fn applicable_in_macros() {
283 ($i:ident) => { fn foo(a: $i) {} }
288 pub struct PubStruct;
293 ($i:ident) => { fn foo(a: $i) {} }
295 foo!(PubMod::PubStruct);
298 pub struct PubStruct;
305 fn applicable_when_found_multiple_imports() {
312 pub struct PubStruct;
315 pub struct PubStruct;
318 pub struct PubStruct;
325 pub struct PubStruct;
328 pub struct PubStruct;
331 pub struct PubStruct;
338 fn not_applicable_for_already_imported_types() {
339 check_assist_not_applicable(
342 use PubMod::PubStruct;
347 pub struct PubStruct;
354 fn not_applicable_for_types_with_private_paths() {
355 check_assist_not_applicable(
361 struct PrivateStruct;
368 fn not_applicable_when_no_imports_found() {
369 check_assist_not_applicable(
377 fn not_applicable_in_import_statements() {
378 check_assist_not_applicable(
384 pub struct PubStruct;
390 fn qualify_function() {
397 pub fn test_function() {};
401 PubMod::test_function
404 pub fn test_function() {};
415 //- /lib.rs crate:crate_with_macro
421 //- /main.rs crate:main deps:crate_with_macro
428 crate_with_macro::foo
435 fn qualify_path_target() {
440 group_label: Option<$0GroupLabel>,
443 mod m { pub struct GroupLabel; }
450 fn not_applicable_when_path_start_is_imported() {
451 check_assist_not_applicable(
457 pub struct TestStruct;
464 mod2::mod3::TestStruct$0
471 fn not_applicable_for_imported_function() {
472 check_assist_not_applicable(
476 pub fn test_function() {}
479 use test_mod::test_function;
488 fn associated_struct_function() {
493 pub struct TestStruct {}
495 pub fn test_function() {}
500 TestStruct::test_function$0
505 pub struct TestStruct {}
507 pub fn test_function() {}
512 test_mod::TestStruct::test_function
519 fn associated_struct_const() {
520 cov_mark::check!(qualify_path_qualifier_start);
525 pub struct TestStruct {}
527 const TEST_CONST: u8 = 42;
532 TestStruct::TEST_CONST$0
537 pub struct TestStruct {}
539 const TEST_CONST: u8 = 42;
544 test_mod::TestStruct::TEST_CONST
551 fn associated_trait_function() {
556 pub trait TestTrait {
559 pub struct TestStruct {}
560 impl TestTrait for TestStruct {
561 fn test_function() {}
566 test_mod::TestStruct::test_function$0
571 pub trait TestTrait {
574 pub struct TestStruct {}
575 impl TestTrait for TestStruct {
576 fn test_function() {}
581 <test_mod::TestStruct as test_mod::TestTrait>::test_function
588 fn not_applicable_for_imported_trait_for_function() {
589 check_assist_not_applicable(
593 pub trait TestTrait {
596 pub trait TestTrait2 {
603 impl TestTrait2 for TestEnum {
604 fn test_function() {}
606 impl TestTrait for TestEnum {
607 fn test_function() {}
611 use test_mod::TestTrait2;
613 test_mod::TestEnum::test_function$0;
620 fn associated_trait_const() {
621 cov_mark::check!(qualify_path_trait_assoc_item);
626 pub trait TestTrait {
627 const TEST_CONST: u8;
629 pub struct TestStruct {}
630 impl TestTrait for TestStruct {
631 const TEST_CONST: u8 = 42;
636 test_mod::TestStruct::TEST_CONST$0
641 pub trait TestTrait {
642 const TEST_CONST: u8;
644 pub struct TestStruct {}
645 impl TestTrait for TestStruct {
646 const TEST_CONST: u8 = 42;
651 <test_mod::TestStruct as test_mod::TestTrait>::TEST_CONST
658 fn not_applicable_for_imported_trait_for_const() {
659 check_assist_not_applicable(
663 pub trait TestTrait {
664 const TEST_CONST: u8;
666 pub trait TestTrait2 {
667 const TEST_CONST: f64;
673 impl TestTrait2 for TestEnum {
674 const TEST_CONST: f64 = 42.0;
676 impl TestTrait for TestEnum {
677 const TEST_CONST: u8 = 42;
681 use test_mod::TestTrait2;
683 test_mod::TestEnum::TEST_CONST$0;
691 cov_mark::check!(qualify_path_trait_method);
696 pub trait TestTrait {
697 fn test_method(&self);
699 pub struct TestStruct {}
700 impl TestTrait for TestStruct {
701 fn test_method(&self) {}
706 let test_struct = test_mod::TestStruct {};
707 test_struct.test_meth$0od()
712 pub trait TestTrait {
713 fn test_method(&self);
715 pub struct TestStruct {}
716 impl TestTrait for TestStruct {
717 fn test_method(&self) {}
722 let test_struct = test_mod::TestStruct {};
723 test_mod::TestTrait::test_method(&test_struct)
730 fn trait_method_multi_params() {
735 pub trait TestTrait {
736 fn test_method(&self, test: i32);
738 pub struct TestStruct {}
739 impl TestTrait for TestStruct {
740 fn test_method(&self, test: i32) {}
745 let test_struct = test_mod::TestStruct {};
746 test_struct.test_meth$0od(42)
751 pub trait TestTrait {
752 fn test_method(&self, test: i32);
754 pub struct TestStruct {}
755 impl TestTrait for TestStruct {
756 fn test_method(&self, test: i32) {}
761 let test_struct = test_mod::TestStruct {};
762 test_mod::TestTrait::test_method(&test_struct, 42)
769 fn trait_method_consume() {
774 pub trait TestTrait {
775 fn test_method(self);
777 pub struct TestStruct {}
778 impl TestTrait for TestStruct {
779 fn test_method(self) {}
784 let test_struct = test_mod::TestStruct {};
785 test_struct.test_meth$0od()
790 pub trait TestTrait {
791 fn test_method(self);
793 pub struct TestStruct {}
794 impl TestTrait for TestStruct {
795 fn test_method(self) {}
800 let test_struct = test_mod::TestStruct {};
801 test_mod::TestTrait::test_method(test_struct)
808 fn trait_method_cross_crate() {
812 //- /main.rs crate:main deps:dep
814 let test_struct = dep::test_mod::TestStruct {};
815 test_struct.test_meth$0od()
817 //- /dep.rs crate:dep
819 pub trait TestTrait {
820 fn test_method(&self);
822 pub struct TestStruct {}
823 impl TestTrait for TestStruct {
824 fn test_method(&self) {}
830 let test_struct = dep::test_mod::TestStruct {};
831 dep::test_mod::TestTrait::test_method(&test_struct)
838 fn assoc_fn_cross_crate() {
842 //- /main.rs crate:main deps:dep
844 dep::test_mod::TestStruct::test_func$0tion
846 //- /dep.rs crate:dep
848 pub trait TestTrait {
851 pub struct TestStruct {}
852 impl TestTrait for TestStruct {
853 fn test_function() {}
859 <dep::test_mod::TestStruct as dep::test_mod::TestTrait>::test_function
866 fn assoc_const_cross_crate() {
870 //- /main.rs crate:main deps:dep
872 dep::test_mod::TestStruct::CONST$0
874 //- /dep.rs crate:dep
876 pub trait TestTrait {
879 pub struct TestStruct {}
880 impl TestTrait for TestStruct {
881 const CONST: bool = true;
887 <dep::test_mod::TestStruct as dep::test_mod::TestTrait>::CONST
894 fn assoc_fn_as_method_cross_crate() {
895 check_assist_not_applicable(
898 //- /main.rs crate:main deps:dep
900 let test_struct = dep::test_mod::TestStruct {};
901 test_struct.test_func$0tion()
903 //- /dep.rs crate:dep
905 pub trait TestTrait {
908 pub struct TestStruct {}
909 impl TestTrait for TestStruct {
910 fn test_function() {}
918 fn private_trait_cross_crate() {
919 check_assist_not_applicable(
922 //- /main.rs crate:main deps:dep
924 let test_struct = dep::test_mod::TestStruct {};
925 test_struct.test_meth$0od()
927 //- /dep.rs crate:dep
930 fn test_method(&self);
932 pub struct TestStruct {}
933 impl TestTrait for TestStruct {
934 fn test_method(&self) {}
942 fn not_applicable_for_imported_trait_for_method() {
943 check_assist_not_applicable(
947 pub trait TestTrait {
948 fn test_method(&self);
950 pub trait TestTrait2 {
951 fn test_method(&self);
957 impl TestTrait2 for TestEnum {
958 fn test_method(&self) {}
960 impl TestTrait for TestEnum {
961 fn test_method(&self) {}
965 use test_mod::TestTrait2;
967 let one = test_mod::TestEnum::One;
979 //- /lib.rs crate:dep
982 //- /main.rs crate:main deps:dep
997 // Tests that only imports whose last segment matches the identifier get suggested.
1001 //- /lib.rs crate:dep
1003 pub trait Display {}
1006 pub fn panic_fmt() {}
1008 //- /main.rs crate:main deps:dep
1011 impl f$0mt::Display for S {}
1016 impl dep::fmt::Display for S {}
1022 fn macro_generated() {
1023 // Tests that macro-generated items are suggested from external crates.
1027 //- /lib.rs crate:dep
1036 //- /main.rs crate:main deps:dep
1051 // Tests that differently cased names don't interfere and we only suggest the matching one.
1055 //- /lib.rs crate:dep
1059 //- /main.rs crate:main deps:dep
1073 fn keep_generic_annotations() {
1077 //- /lib.rs crate:dep
1078 pub mod generic { pub struct Thing<'a, T>(&'a T); }
1080 //- /main.rs crate:main deps:dep
1081 fn foo() -> Thin$0g<'static, ()> {}
1086 fn foo() -> dep::generic::Thing<'static, ()> {}
1094 fn keep_generic_annotations_leading_colon() {
1098 //- /lib.rs crate:dep
1099 pub mod generic { pub struct Thing<'a, T>(&'a T); }
1101 //- /main.rs crate:main deps:dep
1102 fn foo() -> Thin$0g::<'static, ()> {}
1107 fn foo() -> dep::generic::Thing::<'static, ()> {}
1115 fn associated_struct_const_generic() {
1120 pub struct TestStruct<T> {}
1121 impl<T> TestStruct<T> {
1122 const TEST_CONST: u8 = 42;
1127 TestStruct::<()>::TEST_CONST$0
1132 pub struct TestStruct<T> {}
1133 impl<T> TestStruct<T> {
1134 const TEST_CONST: u8 = 42;
1139 test_mod::TestStruct::<()>::TEST_CONST
1146 fn associated_trait_const_generic() {
1151 pub trait TestTrait {
1152 const TEST_CONST: u8;
1154 pub struct TestStruct<T> {}
1155 impl<T> TestTrait for TestStruct<T> {
1156 const TEST_CONST: u8 = 42;
1161 test_mod::TestStruct::<()>::TEST_CONST$0
1166 pub trait TestTrait {
1167 const TEST_CONST: u8;
1169 pub struct TestStruct<T> {}
1170 impl<T> TestTrait for TestStruct<T> {
1171 const TEST_CONST: u8 = 42;
1176 <test_mod::TestStruct::<()> as test_mod::TestTrait>::TEST_CONST
1183 fn trait_method_generic() {
1188 pub trait TestTrait {
1189 fn test_method<T>(&self);
1191 pub struct TestStruct {}
1192 impl TestTrait for TestStruct {
1193 fn test_method<T>(&self) {}
1198 let test_struct = test_mod::TestStruct {};
1199 test_struct.test_meth$0od::<()>()
1204 pub trait TestTrait {
1205 fn test_method<T>(&self);
1207 pub struct TestStruct {}
1208 impl TestTrait for TestStruct {
1209 fn test_method<T>(&self) {}
1214 let test_struct = test_mod::TestStruct {};
1215 test_mod::TestTrait::test_method::<()>(&test_struct)