Skip to main content

ide_assists/handlers/
qualify_path.rs

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
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, 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    // we aren't interested in different namespaces
78    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    // prioritize more relevant imports
84    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        // FIXME: non-trait assoc items completion is unsupported yet, see FIXME in the import_assets.rs for more details
639        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        // Tests that only imports whose last segment matches the identifier get suggested.
1104        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        // Tests that macro-generated items are suggested from external crates.
1130        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        // Tests that differently cased names don't interfere and we only suggest the matching one.
1158        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}