aboutsummaryrefslogtreecommitdiff
path: root/crates/ide_completion/src/completions/qualified_path.rs
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2021-02-17 14:53:31 +0000
committerAleksey Kladov <[email protected]>2021-02-17 14:53:31 +0000
commit3db64a400c78bbd2708e67ddc07df1001fff3f29 (patch)
tree5386aab9c452981be09bc3e4362643a34e6e3617 /crates/ide_completion/src/completions/qualified_path.rs
parent6334ce866ab095215381c4b72692b20a84d26e96 (diff)
rename completion -> ide_completion
We don't have completion-related PRs in flight, so lets do it
Diffstat (limited to 'crates/ide_completion/src/completions/qualified_path.rs')
-rw-r--r--crates/ide_completion/src/completions/qualified_path.rs815
1 files changed, 815 insertions, 0 deletions
diff --git a/crates/ide_completion/src/completions/qualified_path.rs b/crates/ide_completion/src/completions/qualified_path.rs
new file mode 100644
index 000000000..2afa6979e
--- /dev/null
+++ b/crates/ide_completion/src/completions/qualified_path.rs
@@ -0,0 +1,815 @@
1//! Completion of paths, i.e. `some::prefix::$0`.
2
3use hir::{Adt, HasVisibility, PathResolution, ScopeDef};
4use rustc_hash::FxHashSet;
5use syntax::AstNode;
6use test_utils::mark;
7
8use crate::{CompletionContext, Completions};
9
10pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionContext) {
11 let path = match &ctx.path_qual {
12 Some(path) => path.clone(),
13 None => return,
14 };
15
16 if ctx.attribute_under_caret.is_some() || ctx.mod_declaration_under_caret.is_some() {
17 return;
18 }
19
20 let context_module = ctx.scope.module();
21
22 let resolution = match ctx.sema.resolve_path(&path) {
23 Some(res) => res,
24 None => return,
25 };
26
27 // Add associated types on type parameters and `Self`.
28 resolution.assoc_type_shorthand_candidates(ctx.db, |alias| {
29 acc.add_type_alias(ctx, alias);
30 None::<()>
31 });
32
33 match resolution {
34 PathResolution::Def(hir::ModuleDef::Module(module)) => {
35 let module_scope = module.scope(ctx.db, context_module);
36 for (name, def) in module_scope {
37 if ctx.use_item_syntax.is_some() {
38 if let ScopeDef::Unknown = def {
39 if let Some(name_ref) = ctx.name_ref_syntax.as_ref() {
40 if name_ref.syntax().text() == name.to_string().as_str() {
41 // for `use self::foo$0`, don't suggest `foo` as a completion
42 mark::hit!(dont_complete_current_use);
43 continue;
44 }
45 }
46 }
47 }
48
49 acc.add_resolution(ctx, name.to_string(), &def);
50 }
51 }
52 PathResolution::Def(def @ hir::ModuleDef::Adt(_))
53 | PathResolution::Def(def @ hir::ModuleDef::TypeAlias(_))
54 | PathResolution::Def(def @ hir::ModuleDef::BuiltinType(_)) => {
55 if let hir::ModuleDef::Adt(Adt::Enum(e)) = def {
56 for variant in e.variants(ctx.db) {
57 acc.add_enum_variant(ctx, variant, None);
58 }
59 }
60 let ty = match def {
61 hir::ModuleDef::Adt(adt) => adt.ty(ctx.db),
62 hir::ModuleDef::TypeAlias(a) => a.ty(ctx.db),
63 hir::ModuleDef::BuiltinType(builtin) => {
64 let module = match ctx.scope.module() {
65 Some(it) => it,
66 None => return,
67 };
68 builtin.ty(ctx.db, module)
69 }
70 _ => unreachable!(),
71 };
72
73 // XXX: For parity with Rust bug #22519, this does not complete Ty::AssocType.
74 // (where AssocType is defined on a trait, not an inherent impl)
75
76 let krate = ctx.krate;
77 if let Some(krate) = krate {
78 let traits_in_scope = ctx.scope.traits_in_scope();
79 ty.iterate_path_candidates(ctx.db, krate, &traits_in_scope, None, |_ty, item| {
80 if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) {
81 return None;
82 }
83 match item {
84 hir::AssocItem::Function(func) => {
85 acc.add_function(ctx, func, None);
86 }
87 hir::AssocItem::Const(ct) => acc.add_const(ctx, ct),
88 hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty),
89 }
90 None::<()>
91 });
92
93 // Iterate assoc types separately
94 ty.iterate_assoc_items(ctx.db, krate, |item| {
95 if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) {
96 return None;
97 }
98 match item {
99 hir::AssocItem::Function(_) | hir::AssocItem::Const(_) => {}
100 hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty),
101 }
102 None::<()>
103 });
104 }
105 }
106 PathResolution::Def(hir::ModuleDef::Trait(t)) => {
107 // Handles `Trait::assoc` as well as `<Ty as Trait>::assoc`.
108 for item in t.items(ctx.db) {
109 if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) {
110 continue;
111 }
112 match item {
113 hir::AssocItem::Function(func) => {
114 acc.add_function(ctx, func, None);
115 }
116 hir::AssocItem::Const(ct) => acc.add_const(ctx, ct),
117 hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty),
118 }
119 }
120 }
121 PathResolution::TypeParam(_) | PathResolution::SelfType(_) => {
122 if let Some(krate) = ctx.krate {
123 let ty = match resolution {
124 PathResolution::TypeParam(param) => param.ty(ctx.db),
125 PathResolution::SelfType(impl_def) => impl_def.target_ty(ctx.db),
126 _ => return,
127 };
128
129 if let Some(Adt::Enum(e)) = ty.as_adt() {
130 for variant in e.variants(ctx.db) {
131 acc.add_enum_variant(ctx, variant, None);
132 }
133 }
134
135 let traits_in_scope = ctx.scope.traits_in_scope();
136 let mut seen = FxHashSet::default();
137 ty.iterate_path_candidates(ctx.db, krate, &traits_in_scope, None, |_ty, item| {
138 if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) {
139 return None;
140 }
141
142 // We might iterate candidates of a trait multiple times here, so deduplicate
143 // them.
144 if seen.insert(item) {
145 match item {
146 hir::AssocItem::Function(func) => {
147 acc.add_function(ctx, func, None);
148 }
149 hir::AssocItem::Const(ct) => acc.add_const(ctx, ct),
150 hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty),
151 }
152 }
153 None::<()>
154 });
155 }
156 }
157 _ => {}
158 }
159}
160
161#[cfg(test)]
162mod tests {
163 use expect_test::{expect, Expect};
164 use test_utils::mark;
165
166 use crate::{
167 test_utils::{check_edit, completion_list},
168 CompletionKind,
169 };
170
171 fn check(ra_fixture: &str, expect: Expect) {
172 let actual = completion_list(ra_fixture, CompletionKind::Reference);
173 expect.assert_eq(&actual);
174 }
175
176 fn check_builtin(ra_fixture: &str, expect: Expect) {
177 let actual = completion_list(ra_fixture, CompletionKind::BuiltinType);
178 expect.assert_eq(&actual);
179 }
180
181 #[test]
182 fn dont_complete_current_use() {
183 mark::check!(dont_complete_current_use);
184 check(r#"use self::foo$0;"#, expect![[""]]);
185 }
186
187 #[test]
188 fn dont_complete_current_use_in_braces_with_glob() {
189 check(
190 r#"
191mod foo { pub struct S; }
192use self::{foo::*, bar$0};
193"#,
194 expect![[r#"
195 st S
196 md foo
197 "#]],
198 );
199 }
200
201 #[test]
202 fn dont_complete_primitive_in_use() {
203 check_builtin(r#"use self::$0;"#, expect![[""]]);
204 }
205
206 #[test]
207 fn dont_complete_primitive_in_module_scope() {
208 check_builtin(r#"fn foo() { self::$0 }"#, expect![[""]]);
209 }
210
211 #[test]
212 fn completes_primitives() {
213 check_builtin(
214 r#"fn main() { let _: $0 = 92; }"#,
215 expect![[r#"
216 bt u32
217 bt bool
218 bt u8
219 bt isize
220 bt u16
221 bt u64
222 bt u128
223 bt f32
224 bt i128
225 bt i16
226 bt str
227 bt i64
228 bt char
229 bt f64
230 bt i32
231 bt i8
232 bt usize
233 "#]],
234 );
235 }
236
237 #[test]
238 fn completes_mod_with_same_name_as_function() {
239 check(
240 r#"
241use self::my::$0;
242
243mod my { pub struct Bar; }
244fn my() {}
245"#,
246 expect![[r#"
247 st Bar
248 "#]],
249 );
250 }
251
252 #[test]
253 fn filters_visibility() {
254 check(
255 r#"
256use self::my::$0;
257
258mod my {
259 struct Bar;
260 pub struct Foo;
261 pub use Bar as PublicBar;
262}
263"#,
264 expect![[r#"
265 st Foo
266 st PublicBar
267 "#]],
268 );
269 }
270
271 #[test]
272 fn completes_use_item_starting_with_self() {
273 check(
274 r#"
275use self::m::$0;
276
277mod m { pub struct Bar; }
278"#,
279 expect![[r#"
280 st Bar
281 "#]],
282 );
283 }
284
285 #[test]
286 fn completes_use_item_starting_with_crate() {
287 check(
288 r#"
289//- /lib.rs
290mod foo;
291struct Spam;
292//- /foo.rs
293use crate::Sp$0
294"#,
295 expect![[r#"
296 md foo
297 st Spam
298 "#]],
299 );
300 }
301
302 #[test]
303 fn completes_nested_use_tree() {
304 check(
305 r#"
306//- /lib.rs
307mod foo;
308struct Spam;
309//- /foo.rs
310use crate::{Sp$0};
311"#,
312 expect![[r#"
313 md foo
314 st Spam
315 "#]],
316 );
317 }
318
319 #[test]
320 fn completes_deeply_nested_use_tree() {
321 check(
322 r#"
323//- /lib.rs
324mod foo;
325pub mod bar {
326 pub mod baz {
327 pub struct Spam;
328 }
329}
330//- /foo.rs
331use crate::{bar::{baz::Sp$0}};
332"#,
333 expect![[r#"
334 st Spam
335 "#]],
336 );
337 }
338
339 #[test]
340 fn completes_enum_variant() {
341 check(
342 r#"
343enum E { Foo, Bar(i32) }
344fn foo() { let _ = E::$0 }
345"#,
346 expect![[r#"
347 ev Foo ()
348 ev Bar(…) (i32)
349 "#]],
350 );
351 }
352
353 #[test]
354 fn completes_struct_associated_items() {
355 check(
356 r#"
357//- /lib.rs
358struct S;
359
360impl S {
361 fn a() {}
362 fn b(&self) {}
363 const C: i32 = 42;
364 type T = i32;
365}
366
367fn foo() { let _ = S::$0 }
368"#,
369 expect![[r#"
370 fn a() -> ()
371 me b(…) -> ()
372 ct C const C: i32 = 42;
373 ta T type T = i32;
374 "#]],
375 );
376 }
377
378 #[test]
379 fn associated_item_visibility() {
380 check(
381 r#"
382struct S;
383
384mod m {
385 impl super::S {
386 pub(crate) fn public_method() { }
387 fn private_method() { }
388 pub(crate) type PublicType = u32;
389 type PrivateType = u32;
390 pub(crate) const PUBLIC_CONST: u32 = 1;
391 const PRIVATE_CONST: u32 = 1;
392 }
393}
394
395fn foo() { let _ = S::$0 }
396"#,
397 expect![[r#"
398 fn public_method() -> ()
399 ct PUBLIC_CONST pub(crate) const PUBLIC_CONST: u32 = 1;
400 ta PublicType pub(crate) type PublicType = u32;
401 "#]],
402 );
403 }
404
405 #[test]
406 fn completes_enum_associated_method() {
407 check(
408 r#"
409enum E {};
410impl E { fn m() { } }
411
412fn foo() { let _ = E::$0 }
413 "#,
414 expect![[r#"
415 fn m() -> ()
416 "#]],
417 );
418 }
419
420 #[test]
421 fn completes_union_associated_method() {
422 check(
423 r#"
424union U {};
425impl U { fn m() { } }
426
427fn foo() { let _ = U::$0 }
428"#,
429 expect![[r#"
430 fn m() -> ()
431 "#]],
432 );
433 }
434
435 #[test]
436 fn completes_use_paths_across_crates() {
437 check(
438 r#"
439//- /main.rs crate:main deps:foo
440use foo::$0;
441
442//- /foo/lib.rs crate:foo
443pub mod bar { pub struct S; }
444"#,
445 expect![[r#"
446 md bar
447 "#]],
448 );
449 }
450
451 #[test]
452 fn completes_trait_associated_method_1() {
453 check(
454 r#"
455trait Trait { fn m(); }
456
457fn foo() { let _ = Trait::$0 }
458"#,
459 expect![[r#"
460 fn m() -> ()
461 "#]],
462 );
463 }
464
465 #[test]
466 fn completes_trait_associated_method_2() {
467 check(
468 r#"
469trait Trait { fn m(); }
470
471struct S;
472impl Trait for S {}
473
474fn foo() { let _ = S::$0 }
475"#,
476 expect![[r#"
477 fn m() -> ()
478 "#]],
479 );
480 }
481
482 #[test]
483 fn completes_trait_associated_method_3() {
484 check(
485 r#"
486trait Trait { fn m(); }
487
488struct S;
489impl Trait for S {}
490
491fn foo() { let _ = <S as Trait>::$0 }
492"#,
493 expect![[r#"
494 fn m() -> ()
495 "#]],
496 );
497 }
498
499 #[test]
500 fn completes_ty_param_assoc_ty() {
501 check(
502 r#"
503trait Super {
504 type Ty;
505 const CONST: u8;
506 fn func() {}
507 fn method(&self) {}
508}
509
510trait Sub: Super {
511 type SubTy;
512 const C2: ();
513 fn subfunc() {}
514 fn submethod(&self) {}
515}
516
517fn foo<T: Sub>() { T::$0 }
518"#,
519 expect![[r#"
520 ta SubTy type SubTy;
521 ta Ty type Ty;
522 ct C2 const C2: ();
523 fn subfunc() -> ()
524 me submethod(…) -> ()
525 ct CONST const CONST: u8;
526 fn func() -> ()
527 me method(…) -> ()
528 "#]],
529 );
530 }
531
532 #[test]
533 fn completes_self_param_assoc_ty() {
534 check(
535 r#"
536trait Super {
537 type Ty;
538 const CONST: u8 = 0;
539 fn func() {}
540 fn method(&self) {}
541}
542
543trait Sub: Super {
544 type SubTy;
545 const C2: () = ();
546 fn subfunc() {}
547 fn submethod(&self) {}
548}
549
550struct Wrap<T>(T);
551impl<T> Super for Wrap<T> {}
552impl<T> Sub for Wrap<T> {
553 fn subfunc() {
554 // Should be able to assume `Self: Sub + Super`
555 Self::$0
556 }
557}
558"#,
559 expect![[r#"
560 ta SubTy type SubTy;
561 ta Ty type Ty;
562 ct CONST const CONST: u8 = 0;
563 fn func() -> ()
564 me method(…) -> ()
565 ct C2 const C2: () = ();
566 fn subfunc() -> ()
567 me submethod(…) -> ()
568 "#]],
569 );
570 }
571
572 #[test]
573 fn completes_type_alias() {
574 check(
575 r#"
576struct S;
577impl S { fn foo() {} }
578type T = S;
579impl T { fn bar() {} }
580
581fn main() { T::$0; }
582"#,
583 expect![[r#"
584 fn foo() -> ()
585 fn bar() -> ()
586 "#]],
587 );
588 }
589
590 #[test]
591 fn completes_qualified_macros() {
592 check(
593 r#"
594#[macro_export]
595macro_rules! foo { () => {} }
596
597fn main() { let _ = crate::$0 }
598 "#,
599 expect![[r##"
600 fn main() -> ()
601 ma foo!(…) #[macro_export] macro_rules! foo
602 "##]],
603 );
604 }
605
606 #[test]
607 fn test_super_super_completion() {
608 check(
609 r#"
610mod a {
611 const A: usize = 0;
612 mod b {
613 const B: usize = 0;
614 mod c { use super::super::$0 }
615 }
616}
617"#,
618 expect![[r#"
619 md b
620 ct A
621 "#]],
622 );
623 }
624
625 #[test]
626 fn completes_reexported_items_under_correct_name() {
627 check(
628 r#"
629fn foo() { self::m::$0 }
630
631mod m {
632 pub use super::p::wrong_fn as right_fn;
633 pub use super::p::WRONG_CONST as RIGHT_CONST;
634 pub use super::p::WrongType as RightType;
635}
636mod p {
637 fn wrong_fn() {}
638 const WRONG_CONST: u32 = 1;
639 struct WrongType {};
640}
641"#,
642 expect![[r#"
643 ct RIGHT_CONST
644 fn right_fn() -> ()
645 st RightType
646 "#]],
647 );
648
649 check_edit(
650 "RightType",
651 r#"
652fn foo() { self::m::$0 }
653
654mod m {
655 pub use super::p::wrong_fn as right_fn;
656 pub use super::p::WRONG_CONST as RIGHT_CONST;
657 pub use super::p::WrongType as RightType;
658}
659mod p {
660 fn wrong_fn() {}
661 const WRONG_CONST: u32 = 1;
662 struct WrongType {};
663}
664"#,
665 r#"
666fn foo() { self::m::RightType }
667
668mod m {
669 pub use super::p::wrong_fn as right_fn;
670 pub use super::p::WRONG_CONST as RIGHT_CONST;
671 pub use super::p::WrongType as RightType;
672}
673mod p {
674 fn wrong_fn() {}
675 const WRONG_CONST: u32 = 1;
676 struct WrongType {};
677}
678"#,
679 );
680 }
681
682 #[test]
683 fn completes_in_simple_macro_call() {
684 check(
685 r#"
686macro_rules! m { ($e:expr) => { $e } }
687fn main() { m!(self::f$0); }
688fn foo() {}
689"#,
690 expect![[r#"
691 fn main() -> ()
692 fn foo() -> ()
693 "#]],
694 );
695 }
696
697 #[test]
698 fn function_mod_share_name() {
699 check(
700 r#"
701fn foo() { self::m::$0 }
702
703mod m {
704 pub mod z {}
705 pub fn z() {}
706}
707"#,
708 expect![[r#"
709 md z
710 fn z() -> ()
711 "#]],
712 );
713 }
714
715 #[test]
716 fn completes_hashmap_new() {
717 check(
718 r#"
719struct RandomState;
720struct HashMap<K, V, S = RandomState> {}
721
722impl<K, V> HashMap<K, V, RandomState> {
723 pub fn new() -> HashMap<K, V, RandomState> { }
724}
725fn foo() {
726 HashMap::$0
727}
728"#,
729 expect![[r#"
730 fn new() -> HashMap<K, V, RandomState>
731 "#]],
732 );
733 }
734
735 #[test]
736 fn dont_complete_attr() {
737 check(
738 r#"
739mod foo { pub struct Foo; }
740#[foo::$0]
741fn f() {}
742"#,
743 expect![[""]],
744 );
745 }
746
747 #[test]
748 fn completes_function() {
749 check(
750 r#"
751fn foo(
752 a: i32,
753 b: i32
754) {
755
756}
757
758fn main() {
759 fo$0
760}
761"#,
762 expect![[r#"
763 fn main() -> ()
764 fn foo(…) -> ()
765 "#]],
766 );
767 }
768
769 #[test]
770 fn completes_self_enum() {
771 check(
772 r#"
773enum Foo {
774 Bar,
775 Baz,
776}
777
778impl Foo {
779 fn foo(self) {
780 Self::$0
781 }
782}
783"#,
784 expect![[r#"
785 ev Bar ()
786 ev Baz ()
787 me foo(…) -> ()
788 "#]],
789 );
790 }
791
792 #[test]
793 fn completes_primitive_assoc_const() {
794 check(
795 r#"
796//- /lib.rs crate:lib deps:core
797fn f() {
798 u8::$0
799}
800
801//- /core.rs crate:core
802#[lang = "u8"]
803impl u8 {
804 pub const MAX: Self = 255;
805
806 pub fn func(self) {}
807}
808"#,
809 expect![[r#"
810 ct MAX pub const MAX: Self = 255;
811 me func(…) -> ()
812 "#]],
813 );
814 }
815}