ra_ap_assists/handlers/
qualify_path.rs

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