]> git.lizzy.rs Git - rust.git/blob - crates/ide_completion/src/completions/qualified_path.rs
Move out completion type position tests
[rust.git] / crates / ide_completion / src / completions / qualified_path.rs
1 //! Completion of paths, i.e. `some::prefix::$0`.
2
3 use hir::HasVisibility;
4 use rustc_hash::FxHashSet;
5 use syntax::AstNode;
6
7 use crate::{CompletionContext, Completions};
8
9 pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionContext) {
10     if ctx.is_path_disallowed() {
11         return;
12     }
13     let path = match ctx.path_qual() {
14         Some(path) => path,
15         None => return,
16     };
17
18     let resolution = match ctx.sema.resolve_path(path) {
19         Some(res) => res,
20         None => return,
21     };
22
23     let context_module = ctx.scope.module();
24
25     if ctx.expects_item() || ctx.expects_assoc_item() {
26         if let hir::PathResolution::Def(hir::ModuleDef::Module(module)) = resolution {
27             let module_scope = module.scope(ctx.db, context_module);
28             for (name, def) in module_scope {
29                 if let hir::ScopeDef::MacroDef(macro_def) = def {
30                     if macro_def.is_fn_like() {
31                         acc.add_macro(ctx, Some(name.clone()), macro_def);
32                     }
33                 }
34                 if let hir::ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) = def {
35                     acc.add_resolution(ctx, name, &def);
36                 }
37             }
38         }
39         return;
40     }
41
42     // Add associated types on type parameters and `Self`.
43     resolution.assoc_type_shorthand_candidates(ctx.db, |_, alias| {
44         acc.add_type_alias(ctx, alias);
45         None::<()>
46     });
47
48     match resolution {
49         hir::PathResolution::Def(hir::ModuleDef::Module(module)) => {
50             let module_scope = module.scope(ctx.db, context_module);
51             for (name, def) in module_scope {
52                 if ctx.in_use_tree() {
53                     if let hir::ScopeDef::Unknown = def {
54                         if let Some(name_ref) = ctx.name_ref_syntax.as_ref() {
55                             if name_ref.syntax().text() == name.to_string().as_str() {
56                                 // for `use self::foo$0`, don't suggest `foo` as a completion
57                                 cov_mark::hit!(dont_complete_current_use);
58                                 continue;
59                             }
60                         }
61                     }
62                 }
63
64                 let add_resolution = match def {
65                     // Don't suggest attribute macros and derives.
66                     hir::ScopeDef::MacroDef(mac) => mac.is_fn_like(),
67                     // no values in type places
68                     hir::ScopeDef::ModuleDef(
69                         hir::ModuleDef::Function(_)
70                         | hir::ModuleDef::Variant(_)
71                         | hir::ModuleDef::Static(_),
72                     )
73                     | hir::ScopeDef::Local(_) => !ctx.expects_type(),
74                     // unless its a constant in a generic arg list position
75                     hir::ScopeDef::ModuleDef(hir::ModuleDef::Const(_)) => {
76                         !ctx.expects_type() || ctx.expects_generic_arg()
77                     }
78                     _ => true,
79                 };
80
81                 if add_resolution {
82                     acc.add_resolution(ctx, name, &def);
83                 }
84             }
85         }
86         hir::PathResolution::Def(
87             def
88             @
89             (hir::ModuleDef::Adt(_)
90             | hir::ModuleDef::TypeAlias(_)
91             | hir::ModuleDef::BuiltinType(_)),
92         ) => {
93             if let hir::ModuleDef::Adt(hir::Adt::Enum(e)) = def {
94                 add_enum_variants(acc, ctx, e);
95             }
96             let ty = match def {
97                 hir::ModuleDef::Adt(adt) => adt.ty(ctx.db),
98                 hir::ModuleDef::TypeAlias(a) => {
99                     let ty = a.ty(ctx.db);
100                     if let Some(hir::Adt::Enum(e)) = ty.as_adt() {
101                         cov_mark::hit!(completes_variant_through_alias);
102                         add_enum_variants(acc, ctx, e);
103                     }
104                     ty
105                 }
106                 hir::ModuleDef::BuiltinType(builtin) => {
107                     let module = match ctx.scope.module() {
108                         Some(it) => it,
109                         None => return,
110                     };
111                     cov_mark::hit!(completes_primitive_assoc_const);
112                     builtin.ty(ctx.db, module)
113                 }
114                 _ => unreachable!(),
115             };
116
117             // XXX: For parity with Rust bug #22519, this does not complete Ty::AssocType.
118             // (where AssocType is defined on a trait, not an inherent impl)
119
120             let krate = ctx.krate;
121             if let Some(krate) = krate {
122                 let traits_in_scope = ctx.scope.traits_in_scope();
123                 ty.iterate_path_candidates(ctx.db, krate, &traits_in_scope, None, |_ty, item| {
124                     if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) {
125                         return None;
126                     }
127                     add_assoc_item(acc, ctx, item);
128                     None::<()>
129                 });
130
131                 // Iterate assoc types separately
132                 ty.iterate_assoc_items(ctx.db, krate, |item| {
133                     if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) {
134                         return None;
135                     }
136                     if let hir::AssocItem::TypeAlias(ty) = item {
137                         acc.add_type_alias(ctx, ty)
138                     }
139                     None::<()>
140                 });
141             }
142         }
143         hir::PathResolution::Def(hir::ModuleDef::Trait(t)) => {
144             // Handles `Trait::assoc` as well as `<Ty as Trait>::assoc`.
145             for item in t.items(ctx.db) {
146                 if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) {
147                     continue;
148                 }
149                 add_assoc_item(acc, ctx, item);
150             }
151         }
152         hir::PathResolution::TypeParam(_) | hir::PathResolution::SelfType(_) => {
153             if let Some(krate) = ctx.krate {
154                 let ty = match resolution {
155                     hir::PathResolution::TypeParam(param) => param.ty(ctx.db),
156                     hir::PathResolution::SelfType(impl_def) => impl_def.self_ty(ctx.db),
157                     _ => return,
158                 };
159
160                 if let Some(hir::Adt::Enum(e)) = ty.as_adt() {
161                     add_enum_variants(acc, ctx, e);
162                 }
163
164                 let traits_in_scope = ctx.scope.traits_in_scope();
165                 let mut seen = FxHashSet::default();
166                 ty.iterate_path_candidates(ctx.db, krate, &traits_in_scope, None, |_ty, item| {
167                     if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) {
168                         return None;
169                     }
170
171                     // We might iterate candidates of a trait multiple times here, so deduplicate
172                     // them.
173                     if seen.insert(item) {
174                         add_assoc_item(acc, ctx, item);
175                     }
176                     None::<()>
177                 });
178             }
179         }
180         _ => {}
181     }
182 }
183
184 fn add_assoc_item(acc: &mut Completions, ctx: &CompletionContext, item: hir::AssocItem) {
185     match item {
186         hir::AssocItem::Function(func) if !ctx.expects_type() => acc.add_function(ctx, func, None),
187         hir::AssocItem::Const(ct) if !ctx.expects_type() || ctx.expects_generic_arg() => {
188             acc.add_const(ctx, ct)
189         }
190         hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty),
191         _ => (),
192     }
193 }
194
195 fn add_enum_variants(acc: &mut Completions, ctx: &CompletionContext, e: hir::Enum) {
196     if ctx.expects_type() {
197         return;
198     }
199     e.variants(ctx.db).into_iter().for_each(|variant| acc.add_enum_variant(ctx, variant, None));
200 }
201
202 #[cfg(test)]
203 mod tests {
204     use expect_test::{expect, Expect};
205
206     use crate::{
207         tests::{check_edit, filtered_completion_list},
208         CompletionKind,
209     };
210
211     fn check(ra_fixture: &str, expect: Expect) {
212         let actual = filtered_completion_list(ra_fixture, CompletionKind::Reference);
213         expect.assert_eq(&actual);
214     }
215
216     fn check_builtin(ra_fixture: &str, expect: Expect) {
217         let actual = filtered_completion_list(ra_fixture, CompletionKind::BuiltinType);
218         expect.assert_eq(&actual);
219     }
220
221     #[test]
222     fn dont_complete_primitive_in_use() {
223         check_builtin(r#"use self::$0;"#, expect![[""]]);
224     }
225
226     #[test]
227     fn dont_complete_primitive_in_module_scope() {
228         check_builtin(r#"fn foo() { self::$0 }"#, expect![[""]]);
229     }
230
231     #[test]
232     fn completes_enum_variant() {
233         check(
234             r#"
235 enum E { Foo, Bar(i32) }
236 fn foo() { let _ = E::$0 }
237 "#,
238             expect![[r#"
239                 ev Foo    ()
240                 ev Bar(…) (i32)
241             "#]],
242         );
243     }
244
245     #[test]
246     fn completes_struct_associated_items() {
247         check(
248             r#"
249 //- /lib.rs
250 struct S;
251
252 impl S {
253     fn a() {}
254     fn b(&self) {}
255     const C: i32 = 42;
256     type T = i32;
257 }
258
259 fn foo() { let _ = S::$0 }
260 "#,
261             expect![[r#"
262                 fn a()  fn()
263                 me b(…) fn(&self)
264                 ct C    const C: i32 = 42;
265                 ta T    type T = i32;
266             "#]],
267         );
268     }
269
270     #[test]
271     fn associated_item_visibility() {
272         check(
273             r#"
274 struct S;
275
276 mod m {
277     impl super::S {
278         pub(crate) fn public_method() { }
279         fn private_method() { }
280         pub(crate) type PublicType = u32;
281         type PrivateType = u32;
282         pub(crate) const PUBLIC_CONST: u32 = 1;
283         const PRIVATE_CONST: u32 = 1;
284     }
285 }
286
287 fn foo() { let _ = S::$0 }
288 "#,
289             expect![[r#"
290                 fn public_method() fn()
291                 ct PUBLIC_CONST    pub(crate) const PUBLIC_CONST: u32 = 1;
292                 ta PublicType      pub(crate) type PublicType = u32;
293             "#]],
294         );
295     }
296
297     #[test]
298     fn completes_enum_associated_method() {
299         check(
300             r#"
301 enum E {};
302 impl E { fn m() { } }
303
304 fn foo() { let _ = E::$0 }
305         "#,
306             expect![[r#"
307                 fn m() fn()
308             "#]],
309         );
310     }
311
312     #[test]
313     fn completes_union_associated_method() {
314         check(
315             r#"
316 union U {};
317 impl U { fn m() { } }
318
319 fn foo() { let _ = U::$0 }
320 "#,
321             expect![[r#"
322                 fn m() fn()
323             "#]],
324         );
325     }
326
327     #[test]
328     fn completes_trait_associated_method_1() {
329         check(
330             r#"
331 trait Trait { fn m(); }
332
333 fn foo() { let _ = Trait::$0 }
334 "#,
335             expect![[r#"
336                 fn m() fn()
337             "#]],
338         );
339     }
340
341     #[test]
342     fn completes_trait_associated_method_2() {
343         check(
344             r#"
345 trait Trait { fn m(); }
346
347 struct S;
348 impl Trait for S {}
349
350 fn foo() { let _ = S::$0 }
351 "#,
352             expect![[r#"
353                 fn m() fn()
354             "#]],
355         );
356     }
357
358     #[test]
359     fn completes_trait_associated_method_3() {
360         check(
361             r#"
362 trait Trait { fn m(); }
363
364 struct S;
365 impl Trait for S {}
366
367 fn foo() { let _ = <S as Trait>::$0 }
368 "#,
369             expect![[r#"
370                 fn m() fn()
371             "#]],
372         );
373     }
374
375     #[test]
376     fn completes_ty_param_assoc_ty() {
377         check(
378             r#"
379 trait Super {
380     type Ty;
381     const CONST: u8;
382     fn func() {}
383     fn method(&self) {}
384 }
385
386 trait Sub: Super {
387     type SubTy;
388     const C2: ();
389     fn subfunc() {}
390     fn submethod(&self) {}
391 }
392
393 fn foo<T: Sub>() { T::$0 }
394 "#,
395             expect![[r#"
396                 ta SubTy        type SubTy;
397                 ta Ty           type Ty;
398                 ct C2           const C2: ();
399                 fn subfunc()    fn()
400                 me submethod(…) fn(&self)
401                 ct CONST        const CONST: u8;
402                 fn func()       fn()
403                 me method(…)    fn(&self)
404             "#]],
405         );
406     }
407
408     #[test]
409     fn completes_self_param_assoc_ty() {
410         check(
411             r#"
412 trait Super {
413     type Ty;
414     const CONST: u8 = 0;
415     fn func() {}
416     fn method(&self) {}
417 }
418
419 trait Sub: Super {
420     type SubTy;
421     const C2: () = ();
422     fn subfunc() {}
423     fn submethod(&self) {}
424 }
425
426 struct Wrap<T>(T);
427 impl<T> Super for Wrap<T> {}
428 impl<T> Sub for Wrap<T> {
429     fn subfunc() {
430         // Should be able to assume `Self: Sub + Super`
431         Self::$0
432     }
433 }
434 "#,
435             expect![[r#"
436                 ta SubTy        type SubTy;
437                 ta Ty           type Ty;
438                 ct CONST        const CONST: u8 = 0;
439                 fn func()       fn()
440                 me method(…)    fn(&self)
441                 ct C2           const C2: () = ();
442                 fn subfunc()    fn()
443                 me submethod(…) fn(&self)
444             "#]],
445         );
446     }
447
448     #[test]
449     fn completes_type_alias() {
450         check(
451             r#"
452 struct S;
453 impl S { fn foo() {} }
454 type T = S;
455 impl T { fn bar() {} }
456
457 fn main() { T::$0; }
458 "#,
459             expect![[r#"
460                 fn foo() fn()
461                 fn bar() fn()
462             "#]],
463         );
464     }
465
466     #[test]
467     fn completes_qualified_macros() {
468         check(
469             r#"
470 #[macro_export]
471 macro_rules! foo { () => {} }
472
473 fn main() { let _ = crate::$0 }
474 "#,
475             expect![[r##"
476                 fn main()  fn()
477                 ma foo!(…) #[macro_export] macro_rules! foo
478             "##]],
479         );
480     }
481
482     #[test]
483     fn does_not_complete_non_fn_macros() {
484         check(
485             r#"
486 mod m {
487     #[rustc_builtin_macro]
488     pub macro Clone {}
489 }
490
491 fn f() {m::$0}
492 "#,
493             expect![[r#""#]],
494         );
495         check(
496             r#"
497 mod m {
498     #[rustc_builtin_macro]
499     pub macro bench {}
500 }
501
502 fn f() {m::$0}
503 "#,
504             expect![[r#""#]],
505         );
506     }
507
508     #[test]
509     fn completes_reexported_items_under_correct_name() {
510         check(
511             r#"
512 fn foo() { self::m::$0 }
513
514 mod m {
515     pub use super::p::wrong_fn as right_fn;
516     pub use super::p::WRONG_CONST as RIGHT_CONST;
517     pub use super::p::WrongType as RightType;
518 }
519 mod p {
520     fn wrong_fn() {}
521     const WRONG_CONST: u32 = 1;
522     struct WrongType {};
523 }
524 "#,
525             expect![[r#"
526                 ct RIGHT_CONST
527                 fn right_fn()  fn()
528                 st RightType
529             "#]],
530         );
531
532         check_edit(
533             "RightType",
534             r#"
535 fn foo() { self::m::$0 }
536
537 mod m {
538     pub use super::p::wrong_fn as right_fn;
539     pub use super::p::WRONG_CONST as RIGHT_CONST;
540     pub use super::p::WrongType as RightType;
541 }
542 mod p {
543     fn wrong_fn() {}
544     const WRONG_CONST: u32 = 1;
545     struct WrongType {};
546 }
547 "#,
548             r#"
549 fn foo() { self::m::RightType }
550
551 mod m {
552     pub use super::p::wrong_fn as right_fn;
553     pub use super::p::WRONG_CONST as RIGHT_CONST;
554     pub use super::p::WrongType as RightType;
555 }
556 mod p {
557     fn wrong_fn() {}
558     const WRONG_CONST: u32 = 1;
559     struct WrongType {};
560 }
561 "#,
562         );
563     }
564
565     #[test]
566     fn completes_in_simple_macro_call() {
567         check(
568             r#"
569 macro_rules! m { ($e:expr) => { $e } }
570 fn main() { m!(self::f$0); }
571 fn foo() {}
572 "#,
573             expect![[r#"
574                 fn main() fn()
575                 fn foo()  fn()
576             "#]],
577         );
578     }
579
580     #[test]
581     fn function_mod_share_name() {
582         check(
583             r#"
584 fn foo() { self::m::$0 }
585
586 mod m {
587     pub mod z {}
588     pub fn z() {}
589 }
590 "#,
591             expect![[r#"
592                 md z
593                 fn z() fn()
594             "#]],
595         );
596     }
597
598     #[test]
599     fn completes_hashmap_new() {
600         check(
601             r#"
602 struct RandomState;
603 struct HashMap<K, V, S = RandomState> {}
604
605 impl<K, V> HashMap<K, V, RandomState> {
606     pub fn new() -> HashMap<K, V, RandomState> { }
607 }
608 fn foo() {
609     HashMap::$0
610 }
611 "#,
612             expect![[r#"
613                 fn new() fn() -> HashMap<K, V, RandomState>
614             "#]],
615         );
616     }
617
618     #[test]
619     fn dont_complete_attr() {
620         check(
621             r#"
622 mod foo { pub struct Foo; }
623 #[foo::$0]
624 fn f() {}
625 "#,
626             expect![[""]],
627         );
628     }
629
630     #[test]
631     fn completes_variant_through_self() {
632         check(
633             r#"
634 enum Foo {
635     Bar,
636     Baz,
637 }
638
639 impl Foo {
640     fn foo(self) {
641         Self::$0
642     }
643 }
644 "#,
645             expect![[r#"
646                 ev Bar    ()
647                 ev Baz    ()
648                 me foo(…) fn(self)
649             "#]],
650         );
651     }
652
653     #[test]
654     fn completes_primitive_assoc_const() {
655         cov_mark::check!(completes_primitive_assoc_const);
656         check(
657             r#"
658 //- /lib.rs crate:lib deps:core
659 fn f() {
660     u8::$0
661 }
662
663 //- /core.rs crate:core
664 #[lang = "u8"]
665 impl u8 {
666     pub const MAX: Self = 255;
667
668     pub fn func(self) {}
669 }
670 "#,
671             expect![[r#"
672                 ct MAX     pub const MAX: Self = 255;
673                 me func(…) fn(self)
674             "#]],
675         );
676     }
677
678     #[test]
679     fn completes_variant_through_alias() {
680         cov_mark::check!(completes_variant_through_alias);
681         check(
682             r#"
683 enum Foo {
684     Bar
685 }
686 type Foo2 = Foo;
687 fn main() {
688     Foo2::$0
689 }
690 "#,
691             expect![[r#"
692                 ev Bar ()
693             "#]],
694         );
695     }
696 }