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