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