aboutsummaryrefslogtreecommitdiff
path: root/crates/assists/src/handlers
diff options
context:
space:
mode:
authorLukas Wirth <[email protected]>2020-10-14 18:56:20 +0100
committerLukas Wirth <[email protected]>2020-10-14 18:56:20 +0100
commit9f41f074be3a600a40b398dd3f4e57a0d69db256 (patch)
tree6e5f06f49c8aa34e1705500b028734811742d9d0 /crates/assists/src/handlers
parent84d6cdef86dfe1054ecafaedfddbf90a2b3a469d (diff)
Add qualify path assist
Diffstat (limited to 'crates/assists/src/handlers')
-rw-r--r--crates/assists/src/handlers/qualify_path.rs1020
1 files changed, 1020 insertions, 0 deletions
diff --git a/crates/assists/src/handlers/qualify_path.rs b/crates/assists/src/handlers/qualify_path.rs
new file mode 100644
index 000000000..cff207889
--- /dev/null
+++ b/crates/assists/src/handlers/qualify_path.rs
@@ -0,0 +1,1020 @@
1use std::collections::BTreeSet;
2
3use syntax::{ast, AstNode, TextRange};
4
5use crate::{
6 assist_context::{AssistContext, Assists},
7 utils::import_assets::{ImportAssets, ImportCandidate},
8 utils::mod_path_to_ast,
9 AssistId, AssistKind, GroupLabel,
10};
11
12// Assist: qualify_path
13//
14// If the name is unresolved, provides all possible qualified paths for it.
15//
16// ```
17// fn main() {
18// let map = HashMap<|>::new();
19// }
20// # pub mod std { pub mod collections { pub struct HashMap { } } }
21// ```
22// ->
23// ```
24// fn main() {
25// let map = std::collections::HashMap::new();
26// }
27// # pub mod std { pub mod collections { pub struct HashMap { } } }
28// ```
29pub(crate) fn qualify_path(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
30 let import_assets =
31 if let Some(path_under_caret) = ctx.find_node_at_offset_with_descend::<ast::Path>() {
32 ImportAssets::for_regular_path(path_under_caret, &ctx.sema)
33 } else if let Some(method_under_caret) =
34 ctx.find_node_at_offset_with_descend::<ast::MethodCallExpr>()
35 {
36 ImportAssets::for_method_call(method_under_caret, &ctx.sema)
37 } else {
38 None
39 }?;
40 let proposed_imports = import_assets.search_for_relative_paths(&ctx.sema);
41 if proposed_imports.is_empty() {
42 return None;
43 }
44
45 let range = ctx.sema.original_range(import_assets.syntax_under_caret()).range;
46 match import_assets.import_candidate() {
47 ImportCandidate::QualifierStart(candidate) => {
48 let path = ast::Path::cast(import_assets.syntax_under_caret().clone())?;
49 let segment = path.segment()?;
50 qualify_path_qualifier_start(acc, proposed_imports, range, segment, &candidate.name)
51 }
52 ImportCandidate::UnqualifiedName(candidate) => {
53 qualify_path_unqualified_name(acc, proposed_imports, range, &candidate.name)
54 }
55 ImportCandidate::TraitAssocItem(candidate) => {
56 let path = ast::Path::cast(import_assets.syntax_under_caret().clone())?;
57 let (qualifier, segment) = (path.qualifier()?, path.segment()?);
58 qualify_path_trait_assoc_item(
59 acc,
60 proposed_imports,
61 range,
62 qualifier,
63 segment,
64 &candidate.name,
65 )
66 }
67 ImportCandidate::TraitMethod(candidate) => {
68 let mcall_expr = ast::MethodCallExpr::cast(import_assets.syntax_under_caret().clone())?;
69 let receiver = mcall_expr.receiver()?;
70 let name_ref = mcall_expr.name_ref()?;
71 qualify_path_trait_method(
72 acc,
73 proposed_imports,
74 range,
75 receiver,
76 name_ref,
77 &candidate.name,
78 )
79 }
80 };
81 Some(())
82}
83
84// a test that covers this -> `associated_struct_const`
85fn qualify_path_qualifier_start(
86 acc: &mut Assists,
87 proposed_imports: BTreeSet<hir::ModPath>,
88 range: TextRange,
89 segment: ast::PathSegment,
90 qualifier_start: &str,
91) {
92 let group_label = GroupLabel(format!("Qualify {}", qualifier_start));
93 for import in proposed_imports {
94 acc.add_group(
95 &group_label,
96 AssistId("qualify_path", AssistKind::QuickFix),
97 format!("Qualify with `{}`", &import),
98 range,
99 |builder| {
100 let import = mod_path_to_ast(&import);
101 builder.replace(range, format!("{}::{}", import, segment));
102 },
103 );
104 }
105}
106
107// a test that covers this -> `applicable_when_found_an_import_partial`
108fn qualify_path_unqualified_name(
109 acc: &mut Assists,
110 proposed_imports: BTreeSet<hir::ModPath>,
111 range: TextRange,
112 name: &str,
113) {
114 let group_label = GroupLabel(format!("Qualify {}", name));
115 for import in proposed_imports {
116 acc.add_group(
117 &group_label,
118 AssistId("qualify_path", AssistKind::QuickFix),
119 format!("Qualify as `{}`", &import),
120 range,
121 |builder| builder.replace(range, mod_path_to_ast(&import).to_string()),
122 );
123 }
124}
125
126// a test that covers this -> `associated_trait_const`
127fn qualify_path_trait_assoc_item(
128 acc: &mut Assists,
129 proposed_imports: BTreeSet<hir::ModPath>,
130 range: TextRange,
131 qualifier: ast::Path,
132 segment: ast::PathSegment,
133 trait_assoc_item_name: &str,
134) {
135 let group_label = GroupLabel(format!("Qualify {}", trait_assoc_item_name));
136 for import in proposed_imports {
137 acc.add_group(
138 &group_label,
139 AssistId("qualify_path", AssistKind::QuickFix),
140 format!("Qualify with cast as `{}`", &import),
141 range,
142 |builder| {
143 let import = mod_path_to_ast(&import);
144 builder.replace(range, format!("<{} as {}>::{}", qualifier, import, segment));
145 },
146 );
147 }
148}
149
150// a test that covers this -> `trait_method`
151fn qualify_path_trait_method(
152 acc: &mut Assists,
153 proposed_imports: BTreeSet<hir::ModPath>,
154 range: TextRange,
155 receiver: ast::Expr,
156 name_ref: ast::NameRef,
157 trait_method_name: &str,
158) {
159 let group_label = GroupLabel(format!("Qualify {}", trait_method_name));
160 for import in proposed_imports {
161 acc.add_group(
162 &group_label,
163 AssistId("qualify_path", AssistKind::QuickFix), // < Does this still count as quickfix?
164 format!("Qualify `{}`", &import),
165 range,
166 |builder| {
167 let import = mod_path_to_ast(&import);
168 // TODO: check the receiver self type and emit refs accordingly, don't discard other function parameters
169 builder.replace(range, format!("{}::{}(&{})", import, name_ref, receiver));
170 },
171 );
172 }
173}
174
175#[cfg(test)]
176mod tests {
177 use super::*;
178 use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target};
179 #[test]
180 fn applicable_when_found_an_import_partial() {
181 check_assist(
182 qualify_path,
183 r"
184 mod std {
185 pub mod fmt {
186 pub struct Formatter;
187 }
188 }
189
190 use std::fmt;
191
192 <|>Formatter
193 ",
194 r"
195 mod std {
196 pub mod fmt {
197 pub struct Formatter;
198 }
199 }
200
201 use std::fmt;
202
203 fmt::Formatter
204 ",
205 );
206 }
207
208 #[test]
209 fn applicable_when_found_an_import() {
210 check_assist(
211 qualify_path,
212 r"
213 <|>PubStruct
214
215 pub mod PubMod {
216 pub struct PubStruct;
217 }
218 ",
219 r"
220 PubMod::PubStruct
221
222 pub mod PubMod {
223 pub struct PubStruct;
224 }
225 ",
226 );
227 }
228
229 #[test]
230 fn applicable_in_macros() {
231 check_assist(
232 qualify_path,
233 r"
234 macro_rules! foo {
235 ($i:ident) => { fn foo(a: $i) {} }
236 }
237 foo!(Pub<|>Struct);
238
239 pub mod PubMod {
240 pub struct PubStruct;
241 }
242 ",
243 r"
244 macro_rules! foo {
245 ($i:ident) => { fn foo(a: $i) {} }
246 }
247 foo!(PubMod::PubStruct);
248
249 pub mod PubMod {
250 pub struct PubStruct;
251 }
252 ",
253 );
254 }
255
256 #[test]
257 fn applicable_when_found_multiple_imports() {
258 check_assist(
259 qualify_path,
260 r"
261 PubSt<|>ruct
262
263 pub mod PubMod1 {
264 pub struct PubStruct;
265 }
266 pub mod PubMod2 {
267 pub struct PubStruct;
268 }
269 pub mod PubMod3 {
270 pub struct PubStruct;
271 }
272 ",
273 r"
274 PubMod3::PubStruct
275
276 pub mod PubMod1 {
277 pub struct PubStruct;
278 }
279 pub mod PubMod2 {
280 pub struct PubStruct;
281 }
282 pub mod PubMod3 {
283 pub struct PubStruct;
284 }
285 ",
286 );
287 }
288
289 #[test]
290 fn not_applicable_for_already_imported_types() {
291 check_assist_not_applicable(
292 qualify_path,
293 r"
294 use PubMod::PubStruct;
295
296 PubStruct<|>
297
298 pub mod PubMod {
299 pub struct PubStruct;
300 }
301 ",
302 );
303 }
304
305 #[test]
306 fn not_applicable_for_types_with_private_paths() {
307 check_assist_not_applicable(
308 qualify_path,
309 r"
310 PrivateStruct<|>
311
312 pub mod PubMod {
313 struct PrivateStruct;
314 }
315 ",
316 );
317 }
318
319 #[test]
320 fn not_applicable_when_no_imports_found() {
321 check_assist_not_applicable(
322 qualify_path,
323 "
324 PubStruct<|>",
325 );
326 }
327
328 #[test]
329 fn not_applicable_in_import_statements() {
330 check_assist_not_applicable(
331 qualify_path,
332 r"
333 use PubStruct<|>;
334
335 pub mod PubMod {
336 pub struct PubStruct;
337 }",
338 );
339 }
340
341 #[test]
342 fn qualify_function() {
343 check_assist(
344 qualify_path,
345 r"
346 test_function<|>
347
348 pub mod PubMod {
349 pub fn test_function() {};
350 }
351 ",
352 r"
353 PubMod::test_function
354
355 pub mod PubMod {
356 pub fn test_function() {};
357 }
358 ",
359 );
360 }
361
362 #[test]
363 fn qualify_macro() {
364 check_assist(
365 qualify_path,
366 r"
367//- /lib.rs crate:crate_with_macro
368#[macro_export]
369macro_rules! foo {
370 () => ()
371}
372
373//- /main.rs crate:main deps:crate_with_macro
374fn main() {
375 foo<|>
376}
377",
378 r"
379fn main() {
380 crate_with_macro::foo
381}
382",
383 );
384 }
385
386 #[test]
387 fn qualify_path_target() {
388 check_assist_target(
389 qualify_path,
390 r"
391 struct AssistInfo {
392 group_label: Option<<|>GroupLabel>,
393 }
394
395 mod m { pub struct GroupLabel; }
396 ",
397 "GroupLabel",
398 )
399 }
400
401 #[test]
402 fn not_applicable_when_path_start_is_imported() {
403 check_assist_not_applicable(
404 qualify_path,
405 r"
406 pub mod mod1 {
407 pub mod mod2 {
408 pub mod mod3 {
409 pub struct TestStruct;
410 }
411 }
412 }
413
414 use mod1::mod2;
415 fn main() {
416 mod2::mod3::TestStruct<|>
417 }
418 ",
419 );
420 }
421
422 #[test]
423 fn not_applicable_for_imported_function() {
424 check_assist_not_applicable(
425 qualify_path,
426 r"
427 pub mod test_mod {
428 pub fn test_function() {}
429 }
430
431 use test_mod::test_function;
432 fn main() {
433 test_function<|>
434 }
435 ",
436 );
437 }
438
439 #[test]
440 fn associated_struct_function() {
441 check_assist(
442 qualify_path,
443 r"
444 mod test_mod {
445 pub struct TestStruct {}
446 impl TestStruct {
447 pub fn test_function() {}
448 }
449 }
450
451 fn main() {
452 TestStruct::test_function<|>
453 }
454 ",
455 r"
456 mod test_mod {
457 pub struct TestStruct {}
458 impl TestStruct {
459 pub fn test_function() {}
460 }
461 }
462
463 fn main() {
464 test_mod::TestStruct::test_function
465 }
466 ",
467 );
468 }
469
470 #[test]
471 fn associated_struct_const() {
472 check_assist(
473 qualify_path,
474 r"
475 mod test_mod {
476 pub struct TestStruct {}
477 impl TestStruct {
478 const TEST_CONST: u8 = 42;
479 }
480 }
481
482 fn main() {
483 TestStruct::TEST_CONST<|>
484 }
485 ",
486 r"
487 mod test_mod {
488 pub struct TestStruct {}
489 impl TestStruct {
490 const TEST_CONST: u8 = 42;
491 }
492 }
493
494 fn main() {
495 test_mod::TestStruct::TEST_CONST
496 }
497 ",
498 );
499 }
500
501 #[test]
502 fn associated_trait_function() {
503 check_assist(
504 qualify_path,
505 r"
506 mod test_mod {
507 pub trait TestTrait {
508 fn test_function();
509 }
510 pub struct TestStruct {}
511 impl TestTrait for TestStruct {
512 fn test_function() {}
513 }
514 }
515
516 fn main() {
517 test_mod::TestStruct::test_function<|>
518 }
519 ",
520 r"
521 mod test_mod {
522 pub trait TestTrait {
523 fn test_function();
524 }
525 pub struct TestStruct {}
526 impl TestTrait for TestStruct {
527 fn test_function() {}
528 }
529 }
530
531 fn main() {
532 <test_mod::TestStruct as test_mod::TestTrait>::test_function
533 }
534 ",
535 );
536 }
537
538 #[test]
539 fn not_applicable_for_imported_trait_for_function() {
540 check_assist_not_applicable(
541 qualify_path,
542 r"
543 mod test_mod {
544 pub trait TestTrait {
545 fn test_function();
546 }
547 pub trait TestTrait2 {
548 fn test_function();
549 }
550 pub enum TestEnum {
551 One,
552 Two,
553 }
554 impl TestTrait2 for TestEnum {
555 fn test_function() {}
556 }
557 impl TestTrait for TestEnum {
558 fn test_function() {}
559 }
560 }
561
562 use test_mod::TestTrait2;
563 fn main() {
564 test_mod::TestEnum::test_function<|>;
565 }
566 ",
567 )
568 }
569
570 #[test]
571 fn associated_trait_const() {
572 check_assist(
573 qualify_path,
574 r"
575 mod test_mod {
576 pub trait TestTrait {
577 const TEST_CONST: u8;
578 }
579 pub struct TestStruct {}
580 impl TestTrait for TestStruct {
581 const TEST_CONST: u8 = 42;
582 }
583 }
584
585 fn main() {
586 test_mod::TestStruct::TEST_CONST<|>
587 }
588 ",
589 r"
590 mod test_mod {
591 pub trait TestTrait {
592 const TEST_CONST: u8;
593 }
594 pub struct TestStruct {}
595 impl TestTrait for TestStruct {
596 const TEST_CONST: u8 = 42;
597 }
598 }
599
600 fn main() {
601 <test_mod::TestStruct as test_mod::TestTrait>::TEST_CONST
602 }
603 ",
604 );
605 }
606
607 #[test]
608 fn not_applicable_for_imported_trait_for_const() {
609 check_assist_not_applicable(
610 qualify_path,
611 r"
612 mod test_mod {
613 pub trait TestTrait {
614 const TEST_CONST: u8;
615 }
616 pub trait TestTrait2 {
617 const TEST_CONST: f64;
618 }
619 pub enum TestEnum {
620 One,
621 Two,
622 }
623 impl TestTrait2 for TestEnum {
624 const TEST_CONST: f64 = 42.0;
625 }
626 impl TestTrait for TestEnum {
627 const TEST_CONST: u8 = 42;
628 }
629 }
630
631 use test_mod::TestTrait2;
632 fn main() {
633 test_mod::TestEnum::TEST_CONST<|>;
634 }
635 ",
636 )
637 }
638
639 #[test]
640 fn trait_method() {
641 check_assist(
642 qualify_path,
643 r"
644 mod test_mod {
645 pub trait TestTrait {
646 fn test_method(&self);
647 }
648 pub struct TestStruct {}
649 impl TestTrait for TestStruct {
650 fn test_method(&self) {}
651 }
652 }
653
654 fn main() {
655 let test_struct = test_mod::TestStruct {};
656 test_struct.test_meth<|>od()
657 }
658 ",
659 r"
660 mod test_mod {
661 pub trait TestTrait {
662 fn test_method(&self);
663 }
664 pub struct TestStruct {}
665 impl TestTrait for TestStruct {
666 fn test_method(&self) {}
667 }
668 }
669
670 fn main() {
671 let test_struct = test_mod::TestStruct {};
672 test_mod::TestTrait::test_method(&test_struct)
673 }
674 ",
675 );
676 }
677
678 #[test]
679 fn trait_method_multi_params() {
680 check_assist(
681 qualify_path,
682 r"
683 mod test_mod {
684 pub trait TestTrait {
685 fn test_method(&self, test: i32);
686 }
687 pub struct TestStruct {}
688 impl TestTrait for TestStruct {
689 fn test_method(&self, test: i32) {}
690 }
691 }
692
693 fn main() {
694 let test_struct = test_mod::TestStruct {};
695 test_struct.test_meth<|>od(42)
696 }
697 ",
698 r"
699 mod test_mod {
700 pub trait TestTrait {
701 fn test_method(&self, test: i32);
702 }
703 pub struct TestStruct {}
704 impl TestTrait for TestStruct {
705 fn test_method(&self, test: i32) {}
706 }
707 }
708
709 fn main() {
710 let test_struct = test_mod::TestStruct {};
711 test_mod::TestTrait::test_method(&test_struct, 42)
712 }
713 ",
714 );
715 }
716
717 #[test]
718 fn trait_method_consume() {
719 check_assist(
720 qualify_path,
721 r"
722 mod test_mod {
723 pub trait TestTrait {
724 fn test_method(self);
725 }
726 pub struct TestStruct {}
727 impl TestTrait for TestStruct {
728 fn test_method(self) {}
729 }
730 }
731
732 fn main() {
733 let test_struct = test_mod::TestStruct {};
734 test_struct.test_meth<|>od()
735 }
736 ",
737 r"
738 mod test_mod {
739 pub trait TestTrait {
740 fn test_method(self);
741 }
742 pub struct TestStruct {}
743 impl TestTrait for TestStruct {
744 fn test_method(self) {}
745 }
746 }
747
748 fn main() {
749 let test_struct = test_mod::TestStruct {};
750 test_mod::TestTrait::test_method(test_struct)
751 }
752 ",
753 );
754 }
755
756 #[test]
757 fn trait_method_cross_crate() {
758 check_assist(
759 qualify_path,
760 r"
761 //- /main.rs crate:main deps:dep
762 fn main() {
763 let test_struct = dep::test_mod::TestStruct {};
764 test_struct.test_meth<|>od()
765 }
766 //- /dep.rs crate:dep
767 pub mod test_mod {
768 pub trait TestTrait {
769 fn test_method(&self);
770 }
771 pub struct TestStruct {}
772 impl TestTrait for TestStruct {
773 fn test_method(&self) {}
774 }
775 }
776 ",
777 r"
778 fn main() {
779 let test_struct = dep::test_mod::TestStruct {};
780 dep::test_mod::TestTrait::test_method(&test_struct)
781 }
782 ",
783 );
784 }
785
786 #[test]
787 fn assoc_fn_cross_crate() {
788 check_assist(
789 qualify_path,
790 r"
791 //- /main.rs crate:main deps:dep
792 fn main() {
793 dep::test_mod::TestStruct::test_func<|>tion
794 }
795 //- /dep.rs crate:dep
796 pub mod test_mod {
797 pub trait TestTrait {
798 fn test_function();
799 }
800 pub struct TestStruct {}
801 impl TestTrait for TestStruct {
802 fn test_function() {}
803 }
804 }
805 ",
806 r"
807 fn main() {
808 <dep::test_mod::TestStruct as dep::test_mod::TestTrait>::test_function
809 }
810 ",
811 );
812 }
813
814 #[test]
815 fn assoc_const_cross_crate() {
816 check_assist(
817 qualify_path,
818 r"
819 //- /main.rs crate:main deps:dep
820 fn main() {
821 dep::test_mod::TestStruct::CONST<|>
822 }
823 //- /dep.rs crate:dep
824 pub mod test_mod {
825 pub trait TestTrait {
826 const CONST: bool;
827 }
828 pub struct TestStruct {}
829 impl TestTrait for TestStruct {
830 const CONST: bool = true;
831 }
832 }
833 ",
834 r"
835 fn main() {
836 <dep::test_mod::TestStruct as dep::test_mod::TestTrait>::CONST
837 }
838 ",
839 );
840 }
841
842 #[test]
843 fn assoc_fn_as_method_cross_crate() {
844 check_assist_not_applicable(
845 qualify_path,
846 r"
847 //- /main.rs crate:main deps:dep
848 fn main() {
849 let test_struct = dep::test_mod::TestStruct {};
850 test_struct.test_func<|>tion()
851 }
852 //- /dep.rs crate:dep
853 pub mod test_mod {
854 pub trait TestTrait {
855 fn test_function();
856 }
857 pub struct TestStruct {}
858 impl TestTrait for TestStruct {
859 fn test_function() {}
860 }
861 }
862 ",
863 );
864 }
865
866 #[test]
867 fn private_trait_cross_crate() {
868 check_assist_not_applicable(
869 qualify_path,
870 r"
871 //- /main.rs crate:main deps:dep
872 fn main() {
873 let test_struct = dep::test_mod::TestStruct {};
874 test_struct.test_meth<|>od()
875 }
876 //- /dep.rs crate:dep
877 pub mod test_mod {
878 trait TestTrait {
879 fn test_method(&self);
880 }
881 pub struct TestStruct {}
882 impl TestTrait for TestStruct {
883 fn test_method(&self) {}
884 }
885 }
886 ",
887 );
888 }
889
890 #[test]
891 fn not_applicable_for_imported_trait_for_method() {
892 check_assist_not_applicable(
893 qualify_path,
894 r"
895 mod test_mod {
896 pub trait TestTrait {
897 fn test_method(&self);
898 }
899 pub trait TestTrait2 {
900 fn test_method(&self);
901 }
902 pub enum TestEnum {
903 One,
904 Two,
905 }
906 impl TestTrait2 for TestEnum {
907 fn test_method(&self) {}
908 }
909 impl TestTrait for TestEnum {
910 fn test_method(&self) {}
911 }
912 }
913
914 use test_mod::TestTrait2;
915 fn main() {
916 let one = test_mod::TestEnum::One;
917 one.test<|>_method();
918 }
919 ",
920 )
921 }
922
923 #[test]
924 fn dep_import() {
925 check_assist(
926 qualify_path,
927 r"
928//- /lib.rs crate:dep
929pub struct Struct;
930
931//- /main.rs crate:main deps:dep
932fn main() {
933 Struct<|>
934}
935",
936 r"
937fn main() {
938 dep::Struct
939}
940",
941 );
942 }
943
944 #[test]
945 fn whole_segment() {
946 // Tests that only imports whose last segment matches the identifier get suggested.
947 check_assist(
948 qualify_path,
949 r"
950//- /lib.rs crate:dep
951pub mod fmt {
952 pub trait Display {}
953}
954
955pub fn panic_fmt() {}
956
957//- /main.rs crate:main deps:dep
958struct S;
959
960impl f<|>mt::Display for S {}
961",
962 r"
963struct S;
964
965impl dep::fmt::Display for S {}
966",
967 );
968 }
969
970 #[test]
971 fn macro_generated() {
972 // Tests that macro-generated items are suggested from external crates.
973 check_assist(
974 qualify_path,
975 r"
976//- /lib.rs crate:dep
977macro_rules! mac {
978 () => {
979 pub struct Cheese;
980 };
981}
982
983mac!();
984
985//- /main.rs crate:main deps:dep
986fn main() {
987 Cheese<|>;
988}
989",
990 r"
991fn main() {
992 dep::Cheese;
993}
994",
995 );
996 }
997
998 #[test]
999 fn casing() {
1000 // Tests that differently cased names don't interfere and we only suggest the matching one.
1001 check_assist(
1002 qualify_path,
1003 r"
1004//- /lib.rs crate:dep
1005pub struct FMT;
1006pub struct fmt;
1007
1008//- /main.rs crate:main deps:dep
1009fn main() {
1010 FMT<|>;
1011}
1012",
1013 r"
1014fn main() {
1015 dep::FMT;
1016}
1017",
1018 );
1019 }
1020}