diff options
Diffstat (limited to 'crates/ide_completion/src/completions/unqualified_path.rs')
-rw-r--r-- | crates/ide_completion/src/completions/unqualified_path.rs | 130 |
1 files changed, 112 insertions, 18 deletions
diff --git a/crates/ide_completion/src/completions/unqualified_path.rs b/crates/ide_completion/src/completions/unqualified_path.rs index bd955aa85..952f052a1 100644 --- a/crates/ide_completion/src/completions/unqualified_path.rs +++ b/crates/ide_completion/src/completions/unqualified_path.rs | |||
@@ -1,30 +1,32 @@ | |||
1 | //! Completion of names from the current scope, e.g. locals and imported items. | 1 | //! Completion of names from the current scope, e.g. locals and imported items. |
2 | 2 | ||
3 | use hir::ScopeDef; | 3 | use hir::ScopeDef; |
4 | use syntax::{ast, AstNode}; | ||
4 | 5 | ||
5 | use crate::{CompletionContext, Completions}; | 6 | use crate::{patterns::ImmediateLocation, CompletionContext, Completions}; |
6 | 7 | ||
7 | pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) { | 8 | pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) { |
8 | if !ctx.is_trivial_path { | 9 | if ctx.is_path_disallowed() || !ctx.is_trivial_path() { |
9 | return; | ||
10 | } | ||
11 | if ctx.is_path_disallowed() || ctx.expects_item() { | ||
12 | return; | 10 | return; |
13 | } | 11 | } |
14 | 12 | ||
15 | if ctx.expects_assoc_item() { | 13 | if ctx.expects_item() || ctx.expects_assoc_item() { |
16 | ctx.scope.process_all_names(&mut |name, def| { | 14 | // only show macros in {Assoc}ItemList |
17 | if let ScopeDef::MacroDef(macro_def) = def { | 15 | ctx.scope.process_all_names(&mut |name, res| { |
18 | acc.add_macro(ctx, Some(name.clone()), macro_def); | 16 | if let hir::ScopeDef::MacroDef(mac) = res { |
17 | if mac.is_fn_like() { | ||
18 | acc.add_macro(ctx, Some(name.clone()), mac); | ||
19 | } | ||
19 | } | 20 | } |
20 | if let ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) = def { | 21 | if let hir::ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) = res { |
21 | acc.add_resolution(ctx, name, &def); | 22 | acc.add_resolution(ctx, name, &res); |
22 | } | 23 | } |
23 | }); | 24 | }); |
24 | return; | 25 | return; |
25 | } | 26 | } |
26 | 27 | ||
27 | if ctx.expects_use_tree() { | 28 | if ctx.expects_use_tree() { |
29 | // only show modules in a fresh UseTree | ||
28 | cov_mark::hit!(only_completes_modules_in_import); | 30 | cov_mark::hit!(only_completes_modules_in_import); |
29 | ctx.scope.process_all_names(&mut |name, res| { | 31 | ctx.scope.process_all_names(&mut |name, res| { |
30 | if let ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) = res { | 32 | if let ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) = res { |
@@ -42,12 +44,32 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC | |||
42 | }); | 44 | }); |
43 | } | 45 | } |
44 | 46 | ||
47 | if let Some(ImmediateLocation::GenericArgList(arg_list)) = &ctx.completion_location { | ||
48 | if let Some(path_seg) = arg_list.syntax().parent().and_then(ast::PathSegment::cast) { | ||
49 | if let Some(hir::PathResolution::Def(hir::ModuleDef::Trait(trait_))) = | ||
50 | ctx.sema.resolve_path(&path_seg.parent_path()) | ||
51 | { | ||
52 | trait_.items(ctx.sema.db).into_iter().for_each(|it| { | ||
53 | if let hir::AssocItem::TypeAlias(alias) = it { | ||
54 | acc.add_type_alias_with_eq(ctx, alias) | ||
55 | } | ||
56 | }); | ||
57 | } | ||
58 | } | ||
59 | } | ||
60 | |||
45 | ctx.scope.process_all_names(&mut |name, res| { | 61 | ctx.scope.process_all_names(&mut |name, res| { |
46 | if let ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_)) = res { | 62 | if let ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_)) = res { |
47 | cov_mark::hit!(skip_lifetime_completion); | 63 | cov_mark::hit!(skip_lifetime_completion); |
48 | return; | 64 | return; |
49 | } | 65 | } |
50 | acc.add_resolution(ctx, name, &res); | 66 | let add_resolution = match res { |
67 | ScopeDef::MacroDef(mac) => mac.is_fn_like(), | ||
68 | _ => true, | ||
69 | }; | ||
70 | if add_resolution { | ||
71 | acc.add_resolution(ctx, name, &res); | ||
72 | } | ||
51 | }); | 73 | }); |
52 | } | 74 | } |
53 | 75 | ||
@@ -70,6 +92,28 @@ mod tests { | |||
70 | } | 92 | } |
71 | 93 | ||
72 | #[test] | 94 | #[test] |
95 | fn dont_complete_values_in_type_pos() { | ||
96 | check( | ||
97 | r#" | ||
98 | const FOO: () = (); | ||
99 | static BAR: () = (); | ||
100 | enum Foo { | ||
101 | Bar | ||
102 | } | ||
103 | struct Baz; | ||
104 | fn foo() { | ||
105 | let local = (); | ||
106 | let _: $0; | ||
107 | } | ||
108 | "#, | ||
109 | expect![[r#" | ||
110 | en Foo | ||
111 | st Baz | ||
112 | "#]], | ||
113 | ); | ||
114 | } | ||
115 | |||
116 | #[test] | ||
73 | fn only_completes_modules_in_import() { | 117 | fn only_completes_modules_in_import() { |
74 | cov_mark::check!(only_completes_modules_in_import); | 118 | cov_mark::check!(only_completes_modules_in_import); |
75 | check( | 119 | check( |
@@ -340,7 +384,6 @@ fn x() -> $0 | |||
340 | "#, | 384 | "#, |
341 | expect![[r#" | 385 | expect![[r#" |
342 | st Foo | 386 | st Foo |
343 | fn x() fn() | ||
344 | "#]], | 387 | "#]], |
345 | ); | 388 | ); |
346 | } | 389 | } |
@@ -392,7 +435,6 @@ pub mod prelude { | |||
392 | } | 435 | } |
393 | "#, | 436 | "#, |
394 | expect![[r#" | 437 | expect![[r#" |
395 | fn foo() fn() | ||
396 | md std | 438 | md std |
397 | st Option | 439 | st Option |
398 | "#]], | 440 | "#]], |
@@ -428,6 +470,44 @@ mod macros { | |||
428 | } | 470 | } |
429 | 471 | ||
430 | #[test] | 472 | #[test] |
473 | fn does_not_complete_non_fn_macros() { | ||
474 | check( | ||
475 | r#" | ||
476 | #[rustc_builtin_macro] | ||
477 | pub macro Clone {} | ||
478 | |||
479 | fn f() {$0} | ||
480 | "#, | ||
481 | expect![[r#" | ||
482 | fn f() fn() | ||
483 | "#]], | ||
484 | ); | ||
485 | check( | ||
486 | r#" | ||
487 | #[rustc_builtin_macro] | ||
488 | pub macro Clone {} | ||
489 | |||
490 | struct S; | ||
491 | impl S { | ||
492 | $0 | ||
493 | } | ||
494 | "#, | ||
495 | expect![[r#""#]], | ||
496 | ); | ||
497 | check( | ||
498 | r#" | ||
499 | #[rustc_builtin_macro] | ||
500 | pub macro bench {} | ||
501 | |||
502 | fn f() {$0} | ||
503 | "#, | ||
504 | expect![[r#" | ||
505 | fn f() fn() | ||
506 | "#]], | ||
507 | ); | ||
508 | } | ||
509 | |||
510 | #[test] | ||
431 | fn completes_std_prelude_if_core_is_defined() { | 511 | fn completes_std_prelude_if_core_is_defined() { |
432 | check( | 512 | check( |
433 | r#" | 513 | r#" |
@@ -449,7 +529,6 @@ pub mod prelude { | |||
449 | } | 529 | } |
450 | "#, | 530 | "#, |
451 | expect![[r#" | 531 | expect![[r#" |
452 | fn foo() fn() | ||
453 | md std | 532 | md std |
454 | md core | 533 | md core |
455 | st String | 534 | st String |
@@ -510,7 +589,6 @@ macro_rules! foo { () => {} } | |||
510 | fn main() { let x: $0 } | 589 | fn main() { let x: $0 } |
511 | "#, | 590 | "#, |
512 | expect![[r#" | 591 | expect![[r#" |
513 | fn main() fn() | ||
514 | ma foo!(…) macro_rules! foo | 592 | ma foo!(…) macro_rules! foo |
515 | "#]], | 593 | "#]], |
516 | ); | 594 | ); |
@@ -693,12 +771,11 @@ impl MyStruct { | |||
693 | "#, | 771 | "#, |
694 | expect![[r#" | 772 | expect![[r#" |
695 | md bar | 773 | md bar |
696 | ma foo! macro_rules! foo | 774 | ma foo!(…) macro_rules! foo |
697 | "#]], | 775 | "#]], |
698 | ) | 776 | ) |
699 | } | 777 | } |
700 | 778 | ||
701 | // FIXME: The completions here currently come from `macro_in_item_position`, but they shouldn't | ||
702 | #[test] | 779 | #[test] |
703 | fn completes_in_item_list() { | 780 | fn completes_in_item_list() { |
704 | check( | 781 | check( |
@@ -715,4 +792,21 @@ $0 | |||
715 | "#]], | 792 | "#]], |
716 | ) | 793 | ) |
717 | } | 794 | } |
795 | |||
796 | #[test] | ||
797 | fn completes_assoc_types_in_dynimpl_trait() { | ||
798 | check( | ||
799 | r#" | ||
800 | trait Foo { | ||
801 | type Bar; | ||
802 | } | ||
803 | |||
804 | fn foo(_: impl Foo<B$0>) {} | ||
805 | "#, | ||
806 | expect![[r#" | ||
807 | ta Bar = type Bar; | ||
808 | tt Foo | ||
809 | "#]], | ||
810 | ); | ||
811 | } | ||
718 | } | 812 | } |