diff options
Diffstat (limited to 'crates/ide_completion/src/completions')
-rw-r--r-- | crates/ide_completion/src/completions/dot.rs | 41 | ||||
-rw-r--r-- | crates/ide_completion/src/completions/record.rs | 2 | ||||
-rw-r--r-- | crates/ide_completion/src/completions/unqualified_path.rs | 48 |
3 files changed, 54 insertions, 37 deletions
diff --git a/crates/ide_completion/src/completions/dot.rs b/crates/ide_completion/src/completions/dot.rs index fd9738743..93f7bd6d4 100644 --- a/crates/ide_completion/src/completions/dot.rs +++ b/crates/ide_completion/src/completions/dot.rs | |||
@@ -1,7 +1,6 @@ | |||
1 | //! Completes references after dot (fields and method calls). | 1 | //! Completes references after dot (fields and method calls). |
2 | 2 | ||
3 | use hir::{HasVisibility, Type}; | 3 | use either::Either; |
4 | use rustc_hash::FxHashSet; | ||
5 | 4 | ||
6 | use crate::{context::CompletionContext, Completions}; | 5 | use crate::{context::CompletionContext, Completions}; |
7 | 6 | ||
@@ -20,42 +19,12 @@ pub(crate) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) { | |||
20 | if ctx.is_call { | 19 | if ctx.is_call { |
21 | cov_mark::hit!(test_no_struct_field_completion_for_method_call); | 20 | cov_mark::hit!(test_no_struct_field_completion_for_method_call); |
22 | } else { | 21 | } else { |
23 | complete_fields(acc, ctx, &receiver_ty); | 22 | super::complete_fields(ctx, &receiver_ty, |field, ty| match field { |
24 | } | 23 | Either::Left(field) => acc.add_field(ctx, None, field, &ty), |
25 | complete_methods(acc, ctx, &receiver_ty); | 24 | Either::Right(tuple_idx) => acc.add_tuple_field(ctx, None, tuple_idx, &ty), |
26 | } | ||
27 | |||
28 | fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: &Type) { | ||
29 | for receiver in receiver.autoderef(ctx.db) { | ||
30 | for (field, ty) in receiver.fields(ctx.db) { | ||
31 | if ctx.scope.module().map_or(false, |m| !field.is_visible_from(ctx.db, m)) { | ||
32 | // Skip private field. FIXME: If the definition location of the | ||
33 | // field is editable, we should show the completion | ||
34 | continue; | ||
35 | } | ||
36 | acc.add_field(ctx, field, &ty); | ||
37 | } | ||
38 | for (i, ty) in receiver.tuple_fields(ctx.db).into_iter().enumerate() { | ||
39 | // FIXME: Handle visibility | ||
40 | acc.add_tuple_field(ctx, i, &ty); | ||
41 | } | ||
42 | } | ||
43 | } | ||
44 | |||
45 | fn complete_methods(acc: &mut Completions, ctx: &CompletionContext, receiver: &Type) { | ||
46 | if let Some(krate) = ctx.krate { | ||
47 | let mut seen_methods = FxHashSet::default(); | ||
48 | let traits_in_scope = ctx.scope.traits_in_scope(); | ||
49 | receiver.iterate_method_candidates(ctx.db, krate, &traits_in_scope, None, |_ty, func| { | ||
50 | if func.self_param(ctx.db).is_some() | ||
51 | && ctx.scope.module().map_or(true, |m| func.is_visible_from(ctx.db, m)) | ||
52 | && seen_methods.insert(func.name(ctx.db)) | ||
53 | { | ||
54 | acc.add_method(ctx, func, None); | ||
55 | } | ||
56 | None::<()> | ||
57 | }); | 25 | }); |
58 | } | 26 | } |
27 | super::complete_methods(ctx, &receiver_ty, |func| acc.add_method(ctx, func, None, None)); | ||
59 | } | 28 | } |
60 | 29 | ||
61 | #[cfg(test)] | 30 | #[cfg(test)] |
diff --git a/crates/ide_completion/src/completions/record.rs b/crates/ide_completion/src/completions/record.rs index 227c08d01..0ac47cdbe 100644 --- a/crates/ide_completion/src/completions/record.rs +++ b/crates/ide_completion/src/completions/record.rs | |||
@@ -39,7 +39,7 @@ pub(crate) fn complete_record(acc: &mut Completions, ctx: &CompletionContext) -> | |||
39 | }; | 39 | }; |
40 | 40 | ||
41 | for (field, ty) in missing_fields { | 41 | for (field, ty) in missing_fields { |
42 | acc.add_field(ctx, field, &ty); | 42 | acc.add_field(ctx, None, field, &ty); |
43 | } | 43 | } |
44 | 44 | ||
45 | Some(()) | 45 | Some(()) |
diff --git a/crates/ide_completion/src/completions/unqualified_path.rs b/crates/ide_completion/src/completions/unqualified_path.rs index 9db8516d0..573a39996 100644 --- a/crates/ide_completion/src/completions/unqualified_path.rs +++ b/crates/ide_completion/src/completions/unqualified_path.rs | |||
@@ -11,6 +11,7 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC | |||
11 | if ctx.is_path_disallowed() || ctx.expects_item() { | 11 | if ctx.is_path_disallowed() || ctx.expects_item() { |
12 | return; | 12 | return; |
13 | } | 13 | } |
14 | |||
14 | if ctx.expects_assoc_item() { | 15 | if ctx.expects_assoc_item() { |
15 | ctx.scope.process_all_names(&mut |name, def| { | 16 | ctx.scope.process_all_names(&mut |name, def| { |
16 | if let ScopeDef::MacroDef(macro_def) = def { | 17 | if let ScopeDef::MacroDef(macro_def) = def { |
@@ -32,6 +33,7 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC | |||
32 | }); | 33 | }); |
33 | return; | 34 | return; |
34 | } | 35 | } |
36 | |||
35 | if let Some(hir::Adt::Enum(e)) = | 37 | if let Some(hir::Adt::Enum(e)) = |
36 | ctx.expected_type.as_ref().and_then(|ty| ty.strip_references().as_adt()) | 38 | ctx.expected_type.as_ref().and_then(|ty| ty.strip_references().as_adt()) |
37 | { | 39 | { |
@@ -45,6 +47,22 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC | |||
45 | cov_mark::hit!(skip_lifetime_completion); | 47 | cov_mark::hit!(skip_lifetime_completion); |
46 | return; | 48 | return; |
47 | } | 49 | } |
50 | if let ScopeDef::Local(local) = &res { | ||
51 | if local.is_self(ctx.db) { | ||
52 | let ty = local.ty(ctx.db); | ||
53 | super::complete_fields(ctx, &ty, |field, ty| match field { | ||
54 | either::Either::Left(field) => { | ||
55 | acc.add_field(ctx, Some(name.to_string()), field, &ty) | ||
56 | } | ||
57 | either::Either::Right(tuple_idx) => { | ||
58 | acc.add_tuple_field(ctx, Some(name.to_string()), tuple_idx, &ty) | ||
59 | } | ||
60 | }); | ||
61 | super::complete_methods(ctx, &ty, |func| { | ||
62 | acc.add_method(ctx, func, Some(name.to_string()), None) | ||
63 | }); | ||
64 | } | ||
65 | } | ||
48 | acc.add_resolution(ctx, name, &res); | 66 | acc.add_resolution(ctx, name, &res); |
49 | }); | 67 | }); |
50 | } | 68 | } |
@@ -376,6 +394,36 @@ fn foo() { | |||
376 | } | 394 | } |
377 | 395 | ||
378 | #[test] | 396 | #[test] |
397 | fn completes_qualified_fields_and_methods_in_methods() { | ||
398 | check( | ||
399 | r#" | ||
400 | struct Foo { field: i32 } | ||
401 | |||
402 | impl Foo { fn foo(&self) { $0 } }"#, | ||
403 | expect![[r#" | ||
404 | fd self.field i32 | ||
405 | me self.foo() fn(&self) | ||
406 | lc self &Foo | ||
407 | sp Self | ||
408 | st Foo | ||
409 | "#]], | ||
410 | ); | ||
411 | check( | ||
412 | r#" | ||
413 | struct Foo(i32); | ||
414 | |||
415 | impl Foo { fn foo(&mut self) { $0 } }"#, | ||
416 | expect![[r#" | ||
417 | fd self.0 i32 | ||
418 | me self.foo() fn(&mut self) | ||
419 | lc self &mut Foo | ||
420 | sp Self | ||
421 | st Foo | ||
422 | "#]], | ||
423 | ); | ||
424 | } | ||
425 | |||
426 | #[test] | ||
379 | fn completes_prelude() { | 427 | fn completes_prelude() { |
380 | check( | 428 | check( |
381 | r#" | 429 | r#" |