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,
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
23// Assist: qualify_path
24//
25// If the name is unresolved, provides all possible qualified paths for it.
26//
27// ```
28// fn main() {
29//     let map = HashMap$0::new();
30// }
31// # pub mod std { pub mod collections { pub struct HashMap { } } }
32// ```
33// ->
34// ```
35// fn main() {
36//     let map = std::collections::HashMap::new();
37// }
38// # pub mod std { pub mod collections { pub struct HashMap { } } }
39// ```
40pub(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    // we aren't interested in different namespaces
81    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    // prioritize more relevant imports
87    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        // FIXME: non-trait assoc items completion is unsupported yet, see FIXME in the import_assets.rs for more details
563        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        // Tests that only imports whose last segment matches the identifier get suggested.
1028        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        // Tests that macro-generated items are suggested from external crates.
1054        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        // Tests that differently cased names don't interfere and we only suggest the matching one.
1082        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}