1use std::cmp::Reverse;
2use std::iter;
3
4use hir::AsAssocItem;
5use ide_db::RootDatabase;
6use ide_db::{
7 helpers::mod_path_to_ast_with_factory,
8 imports::import_assets::{ImportCandidate, LocatedImport},
9};
10use syntax::Edition;
11use syntax::ast::HasGenericArgs;
12use syntax::{AstNode, ast, ast::HasArgList, syntax_editor::SyntaxEditor};
13
14use crate::{
15 AssistId, GroupLabel,
16 assist_context::{AssistContext, Assists},
17 handlers::auto_import::find_importable_node,
18};
19
20pub(crate) fn qualify_path(acc: &mut Assists, ctx: &AssistContext<'_, '_>) -> Option<()> {
38 let (import_assets, syntax_under_caret, expected) = find_importable_node(ctx)?;
39 let cfg = ctx.config.import_path_config();
40
41 let mut proposed_imports: Vec<_> =
42 import_assets.search_for_relative_paths(&ctx.sema, cfg).collect();
43 if proposed_imports.is_empty() {
44 return None;
45 }
46
47 let range = ctx.sema.original_range(&syntax_under_caret).range;
48 let current_module = ctx.sema.scope(&syntax_under_caret).map(|scope| scope.module());
49
50 let candidate = import_assets.import_candidate();
51 let qualify_candidate = match candidate {
52 ImportCandidate::Path(candidate) if !candidate.qualifier.is_empty() => {
53 cov_mark::hit!(qualify_path_qualifier_start);
54 let path = ast::Path::cast(syntax_under_caret.clone())?;
55 let first_seg_generics = path.segments().next()?.generic_arg_list();
56 QualifyCandidate::QualifierStart(path, first_seg_generics)
57 }
58 ImportCandidate::Path(_) => {
59 cov_mark::hit!(qualify_path_unqualified_name);
60 let path = ast::Path::cast(syntax_under_caret.clone())?;
61 let generics = path.segment()?.generic_arg_list();
62 QualifyCandidate::UnqualifiedName(generics)
63 }
64 ImportCandidate::TraitAssocItem(_) => {
65 cov_mark::hit!(qualify_path_trait_assoc_item);
66 let path = ast::Path::cast(syntax_under_caret.clone())?;
67 let (qualifier, segment) = (path.qualifier()?, path.segment()?);
68 QualifyCandidate::TraitAssocItem(qualifier, segment)
69 }
70 ImportCandidate::TraitMethod(_) => {
71 cov_mark::hit!(qualify_path_trait_method);
72 let mcall_expr = ast::MethodCallExpr::cast(syntax_under_caret.clone())?;
73 QualifyCandidate::TraitMethod(ctx.sema.db, mcall_expr)
74 }
75 };
76
77 proposed_imports.sort_by(|a, b| a.import_path.cmp(&b.import_path));
79 proposed_imports.dedup_by(|a, b| a.import_path == b.import_path);
80
81 let current_edition =
82 current_module.map(|it| it.krate(ctx.db()).edition(ctx.db())).unwrap_or(Edition::CURRENT);
83 proposed_imports.sort_by_key(|import| {
85 Reverse(super::auto_import::relevance_score(
86 ctx,
87 import,
88 expected.as_ref(),
89 current_module.as_ref(),
90 ))
91 });
92
93 let group_label = group_label(candidate);
94 for import in proposed_imports {
95 acc.add_group(
96 &group_label,
97 AssistId::quick_fix("qualify_path"),
98 label(ctx.db(), candidate, &import, current_edition),
99 range,
100 |builder| {
101 let editor = builder.make_editor(&syntax_under_caret);
102 qualify_candidate.qualify(
103 |replace_with: String| builder.replace(range, replace_with),
104 &editor,
105 &import.import_path,
106 import.item_to_import,
107 current_edition,
108 );
109 builder.add_file_edits(ctx.vfs_file_id(), editor);
110 },
111 );
112 }
113 Some(())
114}
115pub(crate) enum QualifyCandidate<'db> {
116 QualifierStart(ast::Path, Option<ast::GenericArgList>),
117 UnqualifiedName(Option<ast::GenericArgList>),
118 TraitAssocItem(ast::Path, ast::PathSegment),
119 TraitMethod(&'db RootDatabase, ast::MethodCallExpr),
120 ImplMethod(&'db RootDatabase, ast::MethodCallExpr, hir::Function),
121}
122
123impl QualifyCandidate<'_> {
124 pub(crate) fn qualify(
125 &self,
126 mut replacer: impl FnMut(String),
127 editor: &SyntaxEditor,
128 import: &hir::ModPath,
129 item: hir::ItemInNs,
130 edition: Edition,
131 ) {
132 let import = mod_path_to_ast_with_factory(editor.make(), import, edition);
133 match self {
134 QualifyCandidate::QualifierStart(path, generics) => {
135 let generics = generics.as_ref().map_or_else(String::new, ToString::to_string);
136 let suffix =
137 path.segments().skip(1).map(|s| s.to_string()).collect::<Vec<_>>().join("::");
138 replacer(format!("{import}{generics}::{suffix}"));
139 }
140 QualifyCandidate::UnqualifiedName(generics) => {
141 let generics = generics.as_ref().map_or_else(String::new, ToString::to_string);
142 replacer(format!("{import}{generics}"));
143 }
144 QualifyCandidate::TraitAssocItem(qualifier, segment) => {
145 replacer(format!("<{qualifier} as {import}>::{segment}"));
146 }
147 QualifyCandidate::TraitMethod(db, mcall_expr) => {
148 Self::qualify_trait_method(db, mcall_expr, editor, import, item);
149 }
150 QualifyCandidate::ImplMethod(db, mcall_expr, hir_fn) => {
151 Self::qualify_fn_call(db, mcall_expr, editor, import, hir_fn);
152 }
153 }
154 }
155
156 fn qualify_fn_call(
157 db: &RootDatabase,
158 mcall_expr: &ast::MethodCallExpr,
159 editor: &SyntaxEditor,
160 import: ast::Path,
161 hir_fn: &hir::Function,
162 ) -> Option<()> {
163 let make = editor.make();
164 let receiver = mcall_expr.receiver()?;
165 let method_name = mcall_expr.name_ref()?;
166 let generics =
167 mcall_expr.generic_arg_list().as_ref().map_or_else(String::new, ToString::to_string);
168 let arg_list = mcall_expr.arg_list().map(|arg_list| arg_list.args());
169
170 if let Some(self_access) = hir_fn.self_param(db).map(|sp| sp.access(db)) {
171 let receiver = match self_access {
172 hir::Access::Shared => make.expr_ref(receiver, false),
173 hir::Access::Exclusive => make.expr_ref(receiver, true),
174 hir::Access::Owned => receiver,
175 };
176 let arg_list = match arg_list {
177 Some(args) => make.arg_list(iter::once(receiver).chain(args)),
178 None => make.arg_list(iter::once(receiver)),
179 };
180 let call_path = make.path_from_text(&format!("{import}::{method_name}{generics}"));
181 let call_expr = make.expr_call(make.expr_path(call_path), arg_list);
182 editor.replace(mcall_expr.syntax(), call_expr.syntax());
183 }
184 Some(())
185 }
186
187 fn qualify_trait_method(
188 db: &RootDatabase,
189 mcall_expr: &ast::MethodCallExpr,
190 editor: &SyntaxEditor,
191 import: ast::Path,
192 item: hir::ItemInNs,
193 ) -> Option<()> {
194 let trait_method_name = mcall_expr.name_ref()?;
195 let trait_ = item_as_trait(db, item)?;
196 let method = find_trait_method(db, trait_, &trait_method_name)?;
197 Self::qualify_fn_call(db, mcall_expr, editor, import, &method)
198 }
199}
200
201fn find_trait_method(
202 db: &RootDatabase,
203 trait_: hir::Trait,
204 trait_method_name: &ast::NameRef,
205) -> Option<hir::Function> {
206 if let Some(hir::AssocItem::Function(method)) =
207 trait_.items(db).into_iter().find(|item: &hir::AssocItem| {
208 item.name(db)
209 .map(|name| name.as_str() == trait_method_name.text().trim_start_matches("r#"))
210 .unwrap_or(false)
211 })
212 {
213 Some(method)
214 } else {
215 None
216 }
217}
218
219fn item_as_trait(db: &RootDatabase, item: hir::ItemInNs) -> Option<hir::Trait> {
220 match item.into_module_def() {
221 hir::ModuleDef::Trait(trait_) => Some(trait_),
222 item_module_def => item_module_def.as_assoc_item(db)?.container_trait(db),
223 }
224}
225
226fn group_label(candidate: &ImportCandidate<'_>) -> GroupLabel {
227 let name = match candidate {
228 ImportCandidate::Path(it) => &it.name,
229 ImportCandidate::TraitAssocItem(it) | ImportCandidate::TraitMethod(it) => {
230 &it.assoc_item_name
231 }
232 }
233 .text();
234 GroupLabel(format!("Qualify {name}"))
235}
236
237fn label(
238 db: &RootDatabase,
239 candidate: &ImportCandidate<'_>,
240 import: &LocatedImport,
241 edition: Edition,
242) -> String {
243 let import_path = &import.import_path;
244
245 match candidate {
246 ImportCandidate::Path(candidate) if candidate.qualifier.is_empty() => {
247 format!("Qualify as `{}`", import_path.display(db, edition))
248 }
249 _ => format!("Qualify with `{}`", import_path.display(db, edition)),
250 }
251}
252
253#[cfg(test)]
254mod tests {
255 use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target};
256
257 use super::*;
258
259 #[test]
260 fn applicable_when_found_an_import_partial() {
261 cov_mark::check!(qualify_path_unqualified_name);
262 check_assist(
263 qualify_path,
264 r#"
265mod std {
266 pub mod fmt {
267 pub struct Formatter;
268 }
269}
270
271use std::fmt;
272
273$0Formatter
274"#,
275 r#"
276mod std {
277 pub mod fmt {
278 pub struct Formatter;
279 }
280}
281
282use std::fmt;
283
284fmt::Formatter
285"#,
286 );
287 }
288
289 #[test]
290 fn applicable_when_multiple_segments() {
291 check_assist(
292 qualify_path,
293 r#"
294 mod a { pub mod b { pub mod c { pub fn foo() {} } } }
295b::c::foo$0
296"#,
297 r#"
298 mod a { pub mod b { pub mod c { pub fn foo() {} } } }
299a::b::c::foo
300"#,
301 );
302 check_assist(
303 qualify_path,
304 r#"
305 mod a { pub mod b { pub mod c { pub fn foo() {} } } }
306b::c$0::foo
307"#,
308 r#"
309 mod a { pub mod b { pub mod c { pub fn foo() {} } } }
310a::b::c::foo
311"#,
312 );
313 check_assist(
314 qualify_path,
315 r#"
316 mod a { pub mod b { pub mod c { pub fn foo() {} } } }
317b$0::c::foo
318"#,
319 r#"
320 mod a { pub mod b { pub mod c { pub fn foo() {} } } }
321a::b::c::foo
322"#,
323 );
324 }
325
326 #[test]
327 fn applicable_when_multiple_segments_with_generics() {
328 check_assist(
329 qualify_path,
330 r#"
331mod a {
332 pub mod b {
333 pub struct TestStruct<T>(T);
334 impl<T> TestStruct<T> {
335 pub const TEST_CONST: u8 = 42;
336 }
337 }
338}
339fn main() {
340 b::TestStruct::<()>::TEST_CONST$0;
341}
342"#,
343 r#"
344mod a {
345 pub mod b {
346 pub struct TestStruct<T>(T);
347 impl<T> TestStruct<T> {
348 pub const TEST_CONST: u8 = 42;
349 }
350 }
351}
352fn main() {
353 a::b::TestStruct::<()>::TEST_CONST;
354}
355"#,
356 );
357 }
358
359 #[test]
360 fn applicable_when_found_an_import() {
361 check_assist(
362 qualify_path,
363 r#"
364$0PubStruct
365
366pub mod PubMod {
367 pub struct PubStruct;
368}
369"#,
370 r#"
371PubMod::PubStruct
372
373pub mod PubMod {
374 pub struct PubStruct;
375}
376"#,
377 );
378 }
379
380 #[test]
381 fn applicable_in_macros() {
382 check_assist(
383 qualify_path,
384 r#"
385macro_rules! foo {
386 ($i:ident) => { fn foo(a: $i) {} }
387}
388foo!(Pub$0Struct);
389
390pub mod PubMod {
391 pub struct PubStruct;
392}
393"#,
394 r#"
395macro_rules! foo {
396 ($i:ident) => { fn foo(a: $i) {} }
397}
398foo!(PubMod::PubStruct);
399
400pub mod PubMod {
401 pub struct PubStruct;
402}
403"#,
404 );
405 }
406
407 #[test]
408 fn applicable_when_found_multiple_imports() {
409 check_assist(
410 qualify_path,
411 r#"
412PubSt$0ruct
413
414pub mod PubMod1 {
415 pub struct PubStruct;
416}
417pub mod PubMod2 {
418 pub struct PubStruct;
419}
420pub mod PubMod3 {
421 pub struct PubStruct;
422}
423"#,
424 r#"
425PubMod1::PubStruct
426
427pub mod PubMod1 {
428 pub struct PubStruct;
429}
430pub mod PubMod2 {
431 pub struct PubStruct;
432}
433pub mod PubMod3 {
434 pub struct PubStruct;
435}
436"#,
437 );
438 }
439
440 #[test]
441 fn not_applicable_for_already_imported_types() {
442 check_assist_not_applicable(
443 qualify_path,
444 r#"
445use PubMod::PubStruct;
446
447PubStruct$0
448
449pub mod PubMod {
450 pub struct PubStruct;
451}
452"#,
453 );
454 }
455
456 #[test]
457 fn not_applicable_for_types_with_private_paths() {
458 check_assist_not_applicable(
459 qualify_path,
460 r#"
461PrivateStruct$0
462
463pub mod PubMod {
464 struct PrivateStruct;
465}
466"#,
467 );
468 }
469
470 #[test]
471 fn not_applicable_when_no_imports_found() {
472 check_assist_not_applicable(qualify_path, r#"PubStruct$0"#);
473 }
474
475 #[test]
476 fn qualify_function() {
477 check_assist(
478 qualify_path,
479 r#"
480test_function$0
481
482pub mod PubMod {
483 pub fn test_function() {};
484}
485"#,
486 r#"
487PubMod::test_function
488
489pub mod PubMod {
490 pub fn test_function() {};
491}
492"#,
493 );
494 }
495
496 #[test]
497 fn qualify_macro() {
498 check_assist(
499 qualify_path,
500 r#"
501//- /lib.rs crate:crate_with_macro
502#[macro_export]
503macro_rules! foo {
504 () => ()
505}
506
507//- /main.rs crate:main deps:crate_with_macro
508fn main() {
509 foo$0
510}
511"#,
512 r#"
513fn main() {
514 crate_with_macro::foo
515}
516"#,
517 );
518 }
519
520 #[test]
521 fn qualify_path_target() {
522 check_assist_target(
523 qualify_path,
524 r#"
525struct AssistInfo {
526 group_label: Option<$0GroupLabel>,
527}
528
529mod m { pub struct GroupLabel; }
530"#,
531 "GroupLabel",
532 )
533 }
534
535 #[test]
536 fn not_applicable_when_path_start_is_imported() {
537 check_assist_not_applicable(
538 qualify_path,
539 r#"
540pub mod mod1 {
541 pub mod mod2 {
542 pub mod mod3 {
543 pub struct TestStruct;
544 }
545 }
546}
547
548use mod1::mod2;
549fn main() {
550 mod2::mod3::TestStruct$0
551}
552"#,
553 );
554 }
555
556 #[test]
557 fn not_applicable_for_imported_function() {
558 check_assist_not_applicable(
559 qualify_path,
560 r#"
561pub mod test_mod {
562 pub fn test_function() {}
563}
564
565use test_mod::test_function;
566fn main() {
567 test_function$0
568}
569"#,
570 );
571 }
572
573 #[test]
574 fn associated_struct_function() {
575 check_assist(
576 qualify_path,
577 r#"
578mod test_mod {
579 pub struct TestStruct {}
580 impl TestStruct {
581 pub fn test_function() {}
582 }
583}
584
585fn main() {
586 TestStruct::test_function$0
587}
588"#,
589 r#"
590mod test_mod {
591 pub struct TestStruct {}
592 impl TestStruct {
593 pub fn test_function() {}
594 }
595}
596
597fn main() {
598 test_mod::TestStruct::test_function
599}
600"#,
601 );
602 }
603
604 #[test]
605 fn associated_struct_const() {
606 cov_mark::check!(qualify_path_qualifier_start);
607 check_assist(
608 qualify_path,
609 r#"
610mod test_mod {
611 pub struct TestStruct {}
612 impl TestStruct {
613 const TEST_CONST: u8 = 42;
614 }
615}
616
617fn main() {
618 TestStruct::TEST_CONST$0
619}
620"#,
621 r#"
622mod test_mod {
623 pub struct TestStruct {}
624 impl TestStruct {
625 const TEST_CONST: u8 = 42;
626 }
627}
628
629fn main() {
630 test_mod::TestStruct::TEST_CONST
631}
632"#,
633 );
634 }
635
636 #[test]
637 fn associated_struct_const_unqualified() {
638 check_assist_not_applicable(
640 qualify_path,
641 r#"
642mod test_mod {
643 pub struct TestStruct {}
644 impl TestStruct {
645 const TEST_CONST: u8 = 42;
646 }
647}
648
649fn main() {
650 TEST_CONST$0
651}
652"#,
653 );
654 }
655
656 #[test]
657 fn associated_trait_function() {
658 check_assist(
659 qualify_path,
660 r#"
661mod test_mod {
662 pub trait TestTrait {
663 fn test_function();
664 }
665 pub struct TestStruct {}
666 impl TestTrait for TestStruct {
667 fn test_function() {}
668 }
669}
670
671fn main() {
672 test_mod::TestStruct::test_function$0
673}
674"#,
675 r#"
676mod test_mod {
677 pub trait TestTrait {
678 fn test_function();
679 }
680 pub struct TestStruct {}
681 impl TestTrait for TestStruct {
682 fn test_function() {}
683 }
684}
685
686fn main() {
687 <test_mod::TestStruct as test_mod::TestTrait>::test_function
688}
689"#,
690 );
691 }
692
693 #[test]
694 fn not_applicable_for_imported_trait_for_function() {
695 check_assist_not_applicable(
696 qualify_path,
697 r#"
698mod test_mod {
699 pub trait TestTrait {
700 fn test_function();
701 }
702 pub trait TestTrait2 {
703 fn test_function();
704 }
705 pub enum TestEnum {
706 One,
707 Two,
708 }
709 impl TestTrait2 for TestEnum {
710 fn test_function() {}
711 }
712 impl TestTrait for TestEnum {
713 fn test_function() {}
714 }
715}
716
717use test_mod::TestTrait2;
718fn main() {
719 test_mod::TestEnum::test_function$0;
720}
721"#,
722 )
723 }
724
725 #[test]
726 fn associated_trait_const() {
727 cov_mark::check!(qualify_path_trait_assoc_item);
728 check_assist(
729 qualify_path,
730 r#"
731mod test_mod {
732 pub trait TestTrait {
733 const TEST_CONST: u8;
734 }
735 pub struct TestStruct {}
736 impl TestTrait for TestStruct {
737 const TEST_CONST: u8 = 42;
738 }
739}
740
741fn main() {
742 test_mod::TestStruct::TEST_CONST$0
743}
744"#,
745 r#"
746mod test_mod {
747 pub trait TestTrait {
748 const TEST_CONST: u8;
749 }
750 pub struct TestStruct {}
751 impl TestTrait for TestStruct {
752 const TEST_CONST: u8 = 42;
753 }
754}
755
756fn main() {
757 <test_mod::TestStruct as test_mod::TestTrait>::TEST_CONST
758}
759"#,
760 );
761 }
762
763 #[test]
764 fn not_applicable_for_imported_trait_for_const() {
765 check_assist_not_applicable(
766 qualify_path,
767 r#"
768mod test_mod {
769 pub trait TestTrait {
770 const TEST_CONST: u8;
771 }
772 pub trait TestTrait2 {
773 const TEST_CONST: f64;
774 }
775 pub enum TestEnum {
776 One,
777 Two,
778 }
779 impl TestTrait2 for TestEnum {
780 const TEST_CONST: f64 = 42.0;
781 }
782 impl TestTrait for TestEnum {
783 const TEST_CONST: u8 = 42;
784 }
785}
786
787use test_mod::TestTrait2;
788fn main() {
789 test_mod::TestEnum::TEST_CONST$0;
790}
791"#,
792 )
793 }
794
795 #[test]
796 fn trait_method() {
797 cov_mark::check!(qualify_path_trait_method);
798 check_assist(
799 qualify_path,
800 r#"
801mod test_mod {
802 pub trait TestTrait {
803 fn test_method(&self);
804 }
805 pub struct TestStruct {}
806 impl TestTrait for TestStruct {
807 fn test_method(&self) {}
808 }
809}
810
811fn main() {
812 let test_struct = test_mod::TestStruct {};
813 test_struct.test_meth$0od()
814}
815"#,
816 r#"
817mod test_mod {
818 pub trait TestTrait {
819 fn test_method(&self);
820 }
821 pub struct TestStruct {}
822 impl TestTrait for TestStruct {
823 fn test_method(&self) {}
824 }
825}
826
827fn main() {
828 let test_struct = test_mod::TestStruct {};
829 test_mod::TestTrait::test_method(&test_struct)
830}
831"#,
832 );
833 }
834
835 #[test]
836 fn trait_method_multi_params() {
837 check_assist(
838 qualify_path,
839 r#"
840mod test_mod {
841 pub trait TestTrait {
842 fn test_method(&self, test: i32);
843 }
844 pub struct TestStruct {}
845 impl TestTrait for TestStruct {
846 fn test_method(&self, test: i32) {}
847 }
848}
849
850fn main() {
851 let test_struct = test_mod::TestStruct {};
852 test_struct.test_meth$0od(42)
853}
854"#,
855 r#"
856mod test_mod {
857 pub trait TestTrait {
858 fn test_method(&self, test: i32);
859 }
860 pub struct TestStruct {}
861 impl TestTrait for TestStruct {
862 fn test_method(&self, test: i32) {}
863 }
864}
865
866fn main() {
867 let test_struct = test_mod::TestStruct {};
868 test_mod::TestTrait::test_method(&test_struct, 42)
869}
870"#,
871 );
872 }
873
874 #[test]
875 fn trait_method_consume() {
876 check_assist(
877 qualify_path,
878 r#"
879mod test_mod {
880 pub trait TestTrait {
881 fn test_method(self);
882 }
883 pub struct TestStruct {}
884 impl TestTrait for TestStruct {
885 fn test_method(self) {}
886 }
887}
888
889fn main() {
890 let test_struct = test_mod::TestStruct {};
891 test_struct.test_meth$0od()
892}
893"#,
894 r#"
895mod test_mod {
896 pub trait TestTrait {
897 fn test_method(self);
898 }
899 pub struct TestStruct {}
900 impl TestTrait for TestStruct {
901 fn test_method(self) {}
902 }
903}
904
905fn main() {
906 let test_struct = test_mod::TestStruct {};
907 test_mod::TestTrait::test_method(test_struct)
908}
909"#,
910 );
911 }
912
913 #[test]
914 fn trait_method_cross_crate() {
915 check_assist(
916 qualify_path,
917 r#"
918//- /main.rs crate:main deps:dep
919fn main() {
920 let test_struct = dep::test_mod::TestStruct {};
921 test_struct.test_meth$0od()
922}
923//- /dep.rs crate:dep
924pub mod test_mod {
925 pub trait TestTrait {
926 fn test_method(&self);
927 }
928 pub struct TestStruct {}
929 impl TestTrait for TestStruct {
930 fn test_method(&self) {}
931 }
932}
933"#,
934 r#"
935fn main() {
936 let test_struct = dep::test_mod::TestStruct {};
937 dep::test_mod::TestTrait::test_method(&test_struct)
938}
939"#,
940 );
941 }
942
943 #[test]
944 fn assoc_fn_cross_crate() {
945 check_assist(
946 qualify_path,
947 r#"
948//- /main.rs crate:main deps:dep
949fn main() {
950 dep::test_mod::TestStruct::test_func$0tion
951}
952//- /dep.rs crate:dep
953pub mod test_mod {
954 pub trait TestTrait {
955 fn test_function();
956 }
957 pub struct TestStruct {}
958 impl TestTrait for TestStruct {
959 fn test_function() {}
960 }
961}
962"#,
963 r#"
964fn main() {
965 <dep::test_mod::TestStruct as dep::test_mod::TestTrait>::test_function
966}
967"#,
968 );
969 }
970
971 #[test]
972 fn assoc_const_cross_crate() {
973 check_assist(
974 qualify_path,
975 r#"
976//- /main.rs crate:main deps:dep
977fn main() {
978 dep::test_mod::TestStruct::CONST$0
979}
980//- /dep.rs crate:dep
981pub mod test_mod {
982 pub trait TestTrait {
983 const CONST: bool;
984 }
985 pub struct TestStruct {}
986 impl TestTrait for TestStruct {
987 const CONST: bool = true;
988 }
989}
990"#,
991 r#"
992fn main() {
993 <dep::test_mod::TestStruct as dep::test_mod::TestTrait>::CONST
994}
995"#,
996 );
997 }
998
999 #[test]
1000 fn assoc_fn_as_method_cross_crate() {
1001 check_assist_not_applicable(
1002 qualify_path,
1003 r#"
1004//- /main.rs crate:main deps:dep
1005fn main() {
1006 let test_struct = dep::test_mod::TestStruct {};
1007 test_struct.test_func$0tion()
1008}
1009//- /dep.rs crate:dep
1010pub mod test_mod {
1011 pub trait TestTrait {
1012 fn test_function();
1013 }
1014 pub struct TestStruct {}
1015 impl TestTrait for TestStruct {
1016 fn test_function() {}
1017 }
1018}
1019"#,
1020 );
1021 }
1022
1023 #[test]
1024 fn private_trait_cross_crate() {
1025 check_assist_not_applicable(
1026 qualify_path,
1027 r#"
1028//- /main.rs crate:main deps:dep
1029fn main() {
1030 let test_struct = dep::test_mod::TestStruct {};
1031 test_struct.test_meth$0od()
1032}
1033//- /dep.rs crate:dep
1034pub mod test_mod {
1035 trait TestTrait {
1036 fn test_method(&self);
1037 }
1038 pub struct TestStruct {}
1039 impl TestTrait for TestStruct {
1040 fn test_method(&self) {}
1041 }
1042}
1043"#,
1044 );
1045 }
1046
1047 #[test]
1048 fn not_applicable_for_imported_trait_for_method() {
1049 check_assist_not_applicable(
1050 qualify_path,
1051 r#"
1052mod test_mod {
1053 pub trait TestTrait {
1054 fn test_method(&self);
1055 }
1056 pub trait TestTrait2 {
1057 fn test_method(&self);
1058 }
1059 pub enum TestEnum {
1060 One,
1061 Two,
1062 }
1063 impl TestTrait2 for TestEnum {
1064 fn test_method(&self) {}
1065 }
1066 impl TestTrait for TestEnum {
1067 fn test_method(&self) {}
1068 }
1069}
1070
1071use test_mod::TestTrait2;
1072fn main() {
1073 let one = test_mod::TestEnum::One;
1074 one.test$0_method();
1075}
1076"#,
1077 )
1078 }
1079
1080 #[test]
1081 fn dep_import() {
1082 check_assist(
1083 qualify_path,
1084 r"
1085//- /lib.rs crate:dep
1086pub struct Struct;
1087
1088//- /main.rs crate:main deps:dep
1089fn main() {
1090 Struct$0
1091}
1092",
1093 r"
1094fn main() {
1095 dep::Struct
1096}
1097",
1098 );
1099 }
1100
1101 #[test]
1102 fn whole_segment() {
1103 check_assist(
1105 qualify_path,
1106 r"
1107//- /lib.rs crate:dep
1108pub mod fmt {
1109 pub trait Display {}
1110}
1111
1112pub fn panic_fmt() {}
1113
1114//- /main.rs crate:main deps:dep
1115struct S;
1116
1117impl f$0mt::Display for S {}
1118",
1119 r"
1120struct S;
1121
1122impl dep::fmt::Display for S {}
1123",
1124 );
1125 }
1126
1127 #[test]
1128 fn macro_generated() {
1129 check_assist(
1131 qualify_path,
1132 r"
1133//- /lib.rs crate:dep
1134macro_rules! mac {
1135 () => {
1136 pub struct Cheese;
1137 };
1138}
1139
1140mac!();
1141
1142//- /main.rs crate:main deps:dep
1143fn main() {
1144 Cheese$0;
1145}
1146",
1147 r"
1148fn main() {
1149 dep::Cheese;
1150}
1151",
1152 );
1153 }
1154
1155 #[test]
1156 fn casing() {
1157 check_assist(
1159 qualify_path,
1160 r"
1161//- /lib.rs crate:dep
1162pub struct FMT;
1163pub struct fmt;
1164
1165//- /main.rs crate:main deps:dep
1166fn main() {
1167 FMT$0;
1168}
1169",
1170 r"
1171fn main() {
1172 dep::FMT;
1173}
1174",
1175 );
1176 }
1177
1178 #[test]
1179 fn keep_generic_annotations() {
1180 check_assist(
1181 qualify_path,
1182 r"
1183//- /lib.rs crate:dep
1184pub mod generic { pub struct Thing<'a, T>(&'a T); }
1185
1186//- /main.rs crate:main deps:dep
1187fn foo() -> Thin$0g<'static, ()> {}
1188
1189fn main() {}
1190",
1191 r"
1192fn foo() -> dep::generic::Thing<'static, ()> {}
1193
1194fn main() {}
1195",
1196 );
1197 }
1198
1199 #[test]
1200 fn keep_generic_annotations_leading_colon() {
1201 check_assist(
1202 qualify_path,
1203 r#"
1204//- /lib.rs crate:dep
1205pub mod generic { pub struct Thing<'a, T>(&'a T); }
1206
1207//- /main.rs crate:main deps:dep
1208fn foo() -> Thin$0g::<'static, ()> {}
1209
1210fn main() {}
1211"#,
1212 r"
1213fn foo() -> dep::generic::Thing::<'static, ()> {}
1214
1215fn main() {}
1216",
1217 );
1218 }
1219
1220 #[test]
1221 fn associated_struct_const_generic() {
1222 check_assist(
1223 qualify_path,
1224 r#"
1225mod test_mod {
1226 pub struct TestStruct<T> {}
1227 impl<T> TestStruct<T> {
1228 const TEST_CONST: u8 = 42;
1229 }
1230}
1231
1232fn main() {
1233 TestStruct::<()>::TEST_CONST$0
1234}
1235"#,
1236 r#"
1237mod test_mod {
1238 pub struct TestStruct<T> {}
1239 impl<T> TestStruct<T> {
1240 const TEST_CONST: u8 = 42;
1241 }
1242}
1243
1244fn main() {
1245 test_mod::TestStruct::<()>::TEST_CONST
1246}
1247"#,
1248 );
1249 }
1250
1251 #[test]
1252 fn associated_trait_const_generic() {
1253 check_assist(
1254 qualify_path,
1255 r#"
1256mod test_mod {
1257 pub trait TestTrait {
1258 const TEST_CONST: u8;
1259 }
1260 pub struct TestStruct<T> {}
1261 impl<T> TestTrait for TestStruct<T> {
1262 const TEST_CONST: u8 = 42;
1263 }
1264}
1265
1266fn main() {
1267 test_mod::TestStruct::<()>::TEST_CONST$0
1268}
1269"#,
1270 r#"
1271mod test_mod {
1272 pub trait TestTrait {
1273 const TEST_CONST: u8;
1274 }
1275 pub struct TestStruct<T> {}
1276 impl<T> TestTrait for TestStruct<T> {
1277 const TEST_CONST: u8 = 42;
1278 }
1279}
1280
1281fn main() {
1282 <test_mod::TestStruct::<()> as test_mod::TestTrait>::TEST_CONST
1283}
1284"#,
1285 );
1286 }
1287
1288 #[test]
1289 fn trait_method_generic() {
1290 check_assist(
1291 qualify_path,
1292 r#"
1293mod test_mod {
1294 pub trait TestTrait {
1295 fn test_method<T>(&self);
1296 }
1297 pub struct TestStruct {}
1298 impl TestTrait for TestStruct {
1299 fn test_method<T>(&self) {}
1300 }
1301}
1302
1303fn main() {
1304 let test_struct = test_mod::TestStruct {};
1305 test_struct.test_meth$0od::<()>()
1306}
1307"#,
1308 r#"
1309mod test_mod {
1310 pub trait TestTrait {
1311 fn test_method<T>(&self);
1312 }
1313 pub struct TestStruct {}
1314 impl TestTrait for TestStruct {
1315 fn test_method<T>(&self) {}
1316 }
1317}
1318
1319fn main() {
1320 let test_struct = test_mod::TestStruct {};
1321 test_mod::TestTrait::test_method::<()>(&test_struct)
1322}
1323"#,
1324 );
1325 }
1326
1327 #[test]
1328 fn works_in_derives() {
1329 check_assist(
1330 qualify_path,
1331 r#"
1332//- minicore:derive
1333mod foo {
1334 #[rustc_builtin_macro]
1335 pub macro Copy {}
1336}
1337#[derive(Copy$0)]
1338struct Foo;
1339"#,
1340 r#"
1341mod foo {
1342 #[rustc_builtin_macro]
1343 pub macro Copy {}
1344}
1345#[derive(foo::Copy)]
1346struct Foo;
1347"#,
1348 );
1349 }
1350
1351 #[test]
1352 fn works_in_use_start() {
1353 check_assist(
1354 qualify_path,
1355 r#"
1356mod bar {
1357 pub mod foo {
1358 pub struct Foo;
1359 }
1360}
1361use foo$0::Foo;
1362"#,
1363 r#"
1364mod bar {
1365 pub mod foo {
1366 pub struct Foo;
1367 }
1368}
1369use bar::foo::Foo;
1370"#,
1371 );
1372 }
1373
1374 #[test]
1375 fn not_applicable_in_non_start_use() {
1376 check_assist_not_applicable(
1377 qualify_path,
1378 r"
1379mod bar {
1380 pub mod foo {
1381 pub struct Foo;
1382 }
1383}
1384use foo::Foo$0;
1385",
1386 );
1387 }
1388}