aboutsummaryrefslogtreecommitdiff
path: root/crates/ide_completion/src/completions
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide_completion/src/completions')
-rw-r--r--crates/ide_completion/src/completions/dot.rs41
-rw-r--r--crates/ide_completion/src/completions/record.rs2
-rw-r--r--crates/ide_completion/src/completions/unqualified_path.rs48
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
3use hir::{HasVisibility, Type}; 3use either::Either;
4use rustc_hash::FxHashSet;
5 4
6use crate::{context::CompletionContext, Completions}; 5use 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
28fn 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
45fn 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#"
400struct Foo { field: i32 }
401
402impl 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#"
413struct Foo(i32);
414
415impl 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#"