]> git.lizzy.rs Git - rust.git/blob - crates/ide_completion/src/completions/qualified_path.rs
Merge #10563
[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(ast::NameLike::NameRef(name_ref)) = ctx.name_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         hir::PathResolution::Macro(mac) => acc.add_macro(ctx, None, mac),
227         _ => {}
228     }
229 }
230
231 fn add_assoc_item(acc: &mut Completions, ctx: &CompletionContext, item: hir::AssocItem) {
232     match item {
233         hir::AssocItem::Function(func) if !ctx.expects_type() => acc.add_function(ctx, func, None),
234         hir::AssocItem::Const(ct) if !ctx.expects_type() || ctx.expects_generic_arg() => {
235             acc.add_const(ctx, ct)
236         }
237         hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty),
238         _ => (),
239     }
240 }
241
242 fn add_enum_variants(acc: &mut Completions, ctx: &CompletionContext, e: hir::Enum) {
243     if ctx.expects_type() {
244         return;
245     }
246     e.variants(ctx.db).into_iter().for_each(|variant| acc.add_enum_variant(ctx, variant, None));
247 }
248
249 #[cfg(test)]
250 mod tests {
251     use expect_test::{expect, Expect};
252
253     use crate::{
254         tests::{check_edit, filtered_completion_list},
255         CompletionKind,
256     };
257
258     fn check(ra_fixture: &str, expect: Expect) {
259         let actual = filtered_completion_list(ra_fixture, CompletionKind::Reference);
260         expect.assert_eq(&actual);
261     }
262
263     #[test]
264     fn associated_item_visibility() {
265         check(
266             r#"
267 //- /lib.rs crate:lib new_source_root:library
268 pub struct S;
269
270 impl S {
271     pub fn public_method() { }
272     fn private_method() { }
273     pub type PublicType = u32;
274     type PrivateType = u32;
275     pub const PUBLIC_CONST: u32 = 1;
276     const PRIVATE_CONST: u32 = 1;
277 }
278
279 //- /main.rs crate:main deps:lib new_source_root:local
280 fn foo() { let _ = lib::S::$0 }
281 "#,
282             expect![[r#"
283                 fn public_method() fn()
284                 ct PUBLIC_CONST    pub const PUBLIC_CONST: u32 = 1;
285                 ta PublicType      pub type PublicType = u32;
286             "#]],
287         );
288     }
289
290     #[test]
291     fn completes_union_associated_method() {
292         check(
293             r#"
294 union U {};
295 impl U { fn m() { } }
296
297 fn foo() { let _ = U::$0 }
298 "#,
299             expect![[r#"
300                 fn m() fn()
301             "#]],
302         );
303     }
304
305     #[test]
306     fn completes_trait_associated_method_1() {
307         check(
308             r#"
309 trait Trait { fn m(); }
310
311 fn foo() { let _ = Trait::$0 }
312 "#,
313             expect![[r#"
314                 fn m() (as Trait) fn()
315             "#]],
316         );
317     }
318
319     #[test]
320     fn completes_trait_associated_method_2() {
321         check(
322             r#"
323 trait Trait { fn m(); }
324
325 struct S;
326 impl Trait for S {}
327
328 fn foo() { let _ = S::$0 }
329 "#,
330             expect![[r#"
331                 fn m() (as Trait) fn()
332             "#]],
333         );
334     }
335
336     #[test]
337     fn completes_trait_associated_method_3() {
338         check(
339             r#"
340 trait Trait { fn m(); }
341
342 struct S;
343 impl Trait for S {}
344
345 fn foo() { let _ = <S as Trait>::$0 }
346 "#,
347             expect![[r#"
348                 fn m() (as Trait) fn()
349             "#]],
350         );
351     }
352
353     #[test]
354     fn completes_ty_param_assoc_ty() {
355         check(
356             r#"
357 trait Super {
358     type Ty;
359     const CONST: u8;
360     fn func() {}
361     fn method(&self) {}
362 }
363
364 trait Sub: Super {
365     type SubTy;
366     const C2: ();
367     fn subfunc() {}
368     fn submethod(&self) {}
369 }
370
371 fn foo<T: Sub>() { T::$0 }
372 "#,
373             expect![[r#"
374                 ta SubTy (as Sub)        type SubTy;
375                 ta Ty (as Super)         type Ty;
376                 ct C2 (as Sub)           const C2: ();
377                 fn subfunc() (as Sub)    fn()
378                 me submethod(…) (as Sub) fn(&self)
379                 ct CONST (as Super)      const CONST: u8;
380                 fn func() (as Super)     fn()
381                 me method(…) (as Super)  fn(&self)
382             "#]],
383         );
384     }
385
386     #[test]
387     fn completes_self_param_assoc_ty() {
388         check(
389             r#"
390 trait Super {
391     type Ty;
392     const CONST: u8 = 0;
393     fn func() {}
394     fn method(&self) {}
395 }
396
397 trait Sub: Super {
398     type SubTy;
399     const C2: () = ();
400     fn subfunc() {}
401     fn submethod(&self) {}
402 }
403
404 struct Wrap<T>(T);
405 impl<T> Super for Wrap<T> {}
406 impl<T> Sub for Wrap<T> {
407     fn subfunc() {
408         // Should be able to assume `Self: Sub + Super`
409         Self::$0
410     }
411 }
412 "#,
413             expect![[r#"
414                 ta SubTy (as Sub)        type SubTy;
415                 ta Ty (as Super)         type Ty;
416                 ct CONST (as Super)      const CONST: u8 = 0;
417                 fn func() (as Super)     fn()
418                 me method(…) (as Super)  fn(&self)
419                 ct C2 (as Sub)           const C2: () = ();
420                 fn subfunc() (as Sub)    fn()
421                 me submethod(…) (as Sub) fn(&self)
422             "#]],
423         );
424     }
425
426     #[test]
427     fn completes_type_alias() {
428         check(
429             r#"
430 struct S;
431 impl S { fn foo() {} }
432 type T = S;
433 impl T { fn bar() {} }
434
435 fn main() { T::$0; }
436 "#,
437             expect![[r#"
438                 fn foo() fn()
439                 fn bar() fn()
440             "#]],
441         );
442     }
443
444     #[test]
445     fn completes_qualified_macros() {
446         check(
447             r#"
448 #[macro_export]
449 macro_rules! foo { () => {} }
450
451 fn main() { let _ = crate::$0 }
452 "#,
453             expect![[r##"
454                 fn main()  fn()
455                 ma foo!(…) #[macro_export] macro_rules! foo
456             "##]],
457         );
458     }
459
460     #[test]
461     fn does_not_complete_non_fn_macros() {
462         check(
463             r#"
464 mod m {
465     #[rustc_builtin_macro]
466     pub macro Clone {}
467 }
468
469 fn f() {m::$0}
470 "#,
471             expect![[r#""#]],
472         );
473         check(
474             r#"
475 mod m {
476     #[rustc_builtin_macro]
477     pub macro bench {}
478 }
479
480 fn f() {m::$0}
481 "#,
482             expect![[r#""#]],
483         );
484     }
485
486     #[test]
487     fn completes_reexported_items_under_correct_name() {
488         check(
489             r#"
490 fn foo() { self::m::$0 }
491
492 mod m {
493     pub use super::p::wrong_fn as right_fn;
494     pub use super::p::WRONG_CONST as RIGHT_CONST;
495     pub use super::p::WrongType as RightType;
496 }
497 mod p {
498     fn wrong_fn() {}
499     const WRONG_CONST: u32 = 1;
500     struct WrongType {};
501 }
502 "#,
503             expect![[r#"
504                 ct RIGHT_CONST
505                 fn right_fn()  fn()
506                 st RightType
507             "#]],
508         );
509
510         check_edit(
511             "RightType",
512             r#"
513 fn foo() { self::m::$0 }
514
515 mod m {
516     pub use super::p::wrong_fn as right_fn;
517     pub use super::p::WRONG_CONST as RIGHT_CONST;
518     pub use super::p::WrongType as RightType;
519 }
520 mod p {
521     fn wrong_fn() {}
522     const WRONG_CONST: u32 = 1;
523     struct WrongType {};
524 }
525 "#,
526             r#"
527 fn foo() { self::m::RightType }
528
529 mod m {
530     pub use super::p::wrong_fn as right_fn;
531     pub use super::p::WRONG_CONST as RIGHT_CONST;
532     pub use super::p::WrongType as RightType;
533 }
534 mod p {
535     fn wrong_fn() {}
536     const WRONG_CONST: u32 = 1;
537     struct WrongType {};
538 }
539 "#,
540         );
541     }
542
543     #[test]
544     fn completes_in_simple_macro_call() {
545         check(
546             r#"
547 macro_rules! m { ($e:expr) => { $e } }
548 fn main() { m!(self::f$0); }
549 fn foo() {}
550 "#,
551             expect![[r#"
552                 fn main() fn()
553                 fn foo()  fn()
554             "#]],
555         );
556     }
557
558     #[test]
559     fn function_mod_share_name() {
560         check(
561             r#"
562 fn foo() { self::m::$0 }
563
564 mod m {
565     pub mod z {}
566     pub fn z() {}
567 }
568 "#,
569             expect![[r#"
570                 md z
571                 fn z() fn()
572             "#]],
573         );
574     }
575
576     #[test]
577     fn completes_hashmap_new() {
578         check(
579             r#"
580 struct RandomState;
581 struct HashMap<K, V, S = RandomState> {}
582
583 impl<K, V> HashMap<K, V, RandomState> {
584     pub fn new() -> HashMap<K, V, RandomState> { }
585 }
586 fn foo() {
587     HashMap::$0
588 }
589 "#,
590             expect![[r#"
591                 fn new() fn() -> HashMap<K, V, RandomState>
592             "#]],
593         );
594     }
595
596     #[test]
597     fn dont_complete_attr() {
598         check(
599             r#"
600 mod foo { pub struct Foo; }
601 #[foo::$0]
602 fn f() {}
603 "#,
604             expect![[""]],
605         );
606     }
607
608     #[test]
609     fn completes_variant_through_self() {
610         check(
611             r#"
612 enum Foo {
613     Bar,
614     Baz,
615 }
616
617 impl Foo {
618     fn foo(self) {
619         Self::$0
620     }
621 }
622 "#,
623             expect![[r#"
624                 ev Bar    ()
625                 ev Baz    ()
626                 me foo(…) fn(self)
627             "#]],
628         );
629     }
630
631     #[test]
632     fn completes_primitive_assoc_const() {
633         cov_mark::check!(completes_primitive_assoc_const);
634         check(
635             r#"
636 //- /lib.rs crate:lib deps:core
637 fn f() {
638     u8::$0
639 }
640
641 //- /core.rs crate:core
642 #[lang = "u8"]
643 impl u8 {
644     pub const MAX: Self = 255;
645
646     pub fn func(self) {}
647 }
648 "#,
649             expect![[r#"
650                 ct MAX     pub const MAX: Self = 255;
651                 me func(…) fn(self)
652             "#]],
653         );
654     }
655
656     #[test]
657     fn completes_variant_through_alias() {
658         cov_mark::check!(completes_variant_through_alias);
659         check(
660             r#"
661 enum Foo {
662     Bar
663 }
664 type Foo2 = Foo;
665 fn main() {
666     Foo2::$0
667 }
668 "#,
669             expect![[r#"
670                 ev Bar ()
671             "#]],
672         );
673     }
674
675     #[test]
676     fn respects_doc_hidden() {
677         cov_mark::check!(qualified_path_doc_hidden);
678         check(
679             r#"
680 //- /lib.rs crate:lib deps:dep
681 fn f() {
682     dep::$0
683 }
684
685 //- /dep.rs crate:dep
686 #[doc(hidden)]
687 #[macro_export]
688 macro_rules! m {
689     () => {}
690 }
691
692 #[doc(hidden)]
693 pub fn f() {}
694
695 #[doc(hidden)]
696 pub struct S;
697
698 #[doc(hidden)]
699 pub mod m {}
700             "#,
701             expect![[r#""#]],
702         )
703     }
704 }