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