diff options
author | Lukas Wirth <[email protected]> | 2021-05-28 14:09:10 +0100 |
---|---|---|
committer | Lukas Wirth <[email protected]> | 2021-05-31 14:10:20 +0100 |
commit | 4507382f2e66cd0e6498228bfdffb16769063b0f (patch) | |
tree | a3f95f4b5bdaa8e1d5f861e169d66ecb8e7723da | |
parent | d346f5bf75bfe3c7dc357c748c257569c0fb23c3 (diff) |
Move unprefixed field/method completion to `dot`
-rw-r--r-- | crates/ide_completion/src/completions.rs | 45 | ||||
-rw-r--r-- | crates/ide_completion/src/completions/dot.rs | 103 | ||||
-rw-r--r-- | crates/ide_completion/src/completions/unqualified_path.rs | 46 |
3 files changed, 101 insertions, 93 deletions
diff --git a/crates/ide_completion/src/completions.rs b/crates/ide_completion/src/completions.rs index dd92bc510..ffdcdc930 100644 --- a/crates/ide_completion/src/completions.rs +++ b/crates/ide_completion/src/completions.rs | |||
@@ -18,10 +18,8 @@ pub(crate) mod unqualified_path; | |||
18 | 18 | ||
19 | use std::iter; | 19 | use std::iter; |
20 | 20 | ||
21 | use either::Either; | 21 | use hir::known; |
22 | use hir::{known, HasVisibility}; | ||
23 | use ide_db::SymbolKind; | 22 | use ide_db::SymbolKind; |
24 | use rustc_hash::FxHashSet; | ||
25 | 23 | ||
26 | use crate::{ | 24 | use crate::{ |
27 | item::{Builder, CompletionKind}, | 25 | item::{Builder, CompletionKind}, |
@@ -254,44 +252,3 @@ fn complete_enum_variants( | |||
254 | } | 252 | } |
255 | } | 253 | } |
256 | } | 254 | } |
257 | |||
258 | fn complete_fields( | ||
259 | ctx: &CompletionContext, | ||
260 | receiver: &hir::Type, | ||
261 | mut f: impl FnMut(Either<hir::Field, usize>, hir::Type), | ||
262 | ) { | ||
263 | for receiver in receiver.autoderef(ctx.db) { | ||
264 | for (field, ty) in receiver.fields(ctx.db) { | ||
265 | if ctx.scope.module().map_or(false, |m| !field.is_visible_from(ctx.db, m)) { | ||
266 | // Skip private field. FIXME: If the definition location of the | ||
267 | // field is editable, we should show the completion | ||
268 | continue; | ||
269 | } | ||
270 | f(Either::Left(field), ty); | ||
271 | } | ||
272 | for (i, ty) in receiver.tuple_fields(ctx.db).into_iter().enumerate() { | ||
273 | // FIXME: Handle visibility | ||
274 | f(Either::Right(i), ty); | ||
275 | } | ||
276 | } | ||
277 | } | ||
278 | |||
279 | fn complete_methods( | ||
280 | ctx: &CompletionContext, | ||
281 | receiver: &hir::Type, | ||
282 | mut f: impl FnMut(hir::Function), | ||
283 | ) { | ||
284 | if let Some(krate) = ctx.krate { | ||
285 | let mut seen_methods = FxHashSet::default(); | ||
286 | let traits_in_scope = ctx.scope.traits_in_scope(); | ||
287 | receiver.iterate_method_candidates(ctx.db, krate, &traits_in_scope, None, |_ty, func| { | ||
288 | if func.self_param(ctx.db).is_some() | ||
289 | && ctx.scope.module().map_or(true, |m| func.is_visible_from(ctx.db, m)) | ||
290 | && seen_methods.insert(func.name(ctx.db)) | ||
291 | { | ||
292 | f(func); | ||
293 | } | ||
294 | None::<()> | ||
295 | }); | ||
296 | } | ||
297 | } | ||
diff --git a/crates/ide_completion/src/completions/dot.rs b/crates/ide_completion/src/completions/dot.rs index 93f7bd6d4..886251639 100644 --- a/crates/ide_completion/src/completions/dot.rs +++ b/crates/ide_completion/src/completions/dot.rs | |||
@@ -1,6 +1,8 @@ | |||
1 | //! Completes references after dot (fields and method calls). | 1 | //! Completes references after dot (fields and method calls). |
2 | 2 | ||
3 | use either::Either; | 3 | use either::Either; |
4 | use hir::{HasVisibility, ScopeDef}; | ||
5 | use rustc_hash::FxHashSet; | ||
4 | 6 | ||
5 | use crate::{context::CompletionContext, Completions}; | 7 | use crate::{context::CompletionContext, Completions}; |
6 | 8 | ||
@@ -8,7 +10,7 @@ use crate::{context::CompletionContext, Completions}; | |||
8 | pub(crate) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) { | 10 | pub(crate) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) { |
9 | let dot_receiver = match &ctx.dot_receiver { | 11 | let dot_receiver = match &ctx.dot_receiver { |
10 | Some(expr) => expr, | 12 | Some(expr) => expr, |
11 | _ => return, | 13 | _ => return complete_undotted_self(acc, ctx), |
12 | }; | 14 | }; |
13 | 15 | ||
14 | let receiver_ty = match ctx.sema.type_of_expr(&dot_receiver) { | 16 | let receiver_ty = match ctx.sema.type_of_expr(&dot_receiver) { |
@@ -19,12 +21,77 @@ pub(crate) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) { | |||
19 | if ctx.is_call { | 21 | if ctx.is_call { |
20 | cov_mark::hit!(test_no_struct_field_completion_for_method_call); | 22 | cov_mark::hit!(test_no_struct_field_completion_for_method_call); |
21 | } else { | 23 | } else { |
22 | super::complete_fields(ctx, &receiver_ty, |field, ty| match field { | 24 | complete_fields(ctx, &receiver_ty, |field, ty| match field { |
23 | Either::Left(field) => acc.add_field(ctx, None, field, &ty), | 25 | Either::Left(field) => acc.add_field(ctx, None, field, &ty), |
24 | Either::Right(tuple_idx) => acc.add_tuple_field(ctx, None, tuple_idx, &ty), | 26 | Either::Right(tuple_idx) => acc.add_tuple_field(ctx, None, tuple_idx, &ty), |
25 | }); | 27 | }); |
26 | } | 28 | } |
27 | super::complete_methods(ctx, &receiver_ty, |func| acc.add_method(ctx, func, None, None)); | 29 | complete_methods(ctx, &receiver_ty, |func| acc.add_method(ctx, func, None, None)); |
30 | } | ||
31 | |||
32 | fn complete_undotted_self(acc: &mut Completions, ctx: &CompletionContext) { | ||
33 | if !ctx.is_trivial_path { | ||
34 | return; | ||
35 | } | ||
36 | ctx.scope.process_all_names(&mut |name, def| { | ||
37 | if let ScopeDef::Local(local) = &def { | ||
38 | if local.is_self(ctx.db) { | ||
39 | let ty = local.ty(ctx.db); | ||
40 | complete_fields(ctx, &ty, |field, ty| match field { | ||
41 | either::Either::Left(field) => { | ||
42 | acc.add_field(ctx, Some(name.clone()), field, &ty) | ||
43 | } | ||
44 | either::Either::Right(tuple_idx) => { | ||
45 | acc.add_tuple_field(ctx, Some(name.clone()), tuple_idx, &ty) | ||
46 | } | ||
47 | }); | ||
48 | complete_methods(ctx, &ty, |func| { | ||
49 | acc.add_method(ctx, func, Some(name.clone()), None) | ||
50 | }); | ||
51 | } | ||
52 | } | ||
53 | }); | ||
54 | } | ||
55 | |||
56 | fn complete_fields( | ||
57 | ctx: &CompletionContext, | ||
58 | receiver: &hir::Type, | ||
59 | mut f: impl FnMut(Either<hir::Field, usize>, hir::Type), | ||
60 | ) { | ||
61 | for receiver in receiver.autoderef(ctx.db) { | ||
62 | for (field, ty) in receiver.fields(ctx.db) { | ||
63 | if ctx.scope.module().map_or(false, |m| !field.is_visible_from(ctx.db, m)) { | ||
64 | // Skip private field. FIXME: If the definition location of the | ||
65 | // field is editable, we should show the completion | ||
66 | continue; | ||
67 | } | ||
68 | f(Either::Left(field), ty); | ||
69 | } | ||
70 | for (i, ty) in receiver.tuple_fields(ctx.db).into_iter().enumerate() { | ||
71 | // FIXME: Handle visibility | ||
72 | f(Either::Right(i), ty); | ||
73 | } | ||
74 | } | ||
75 | } | ||
76 | |||
77 | fn complete_methods( | ||
78 | ctx: &CompletionContext, | ||
79 | receiver: &hir::Type, | ||
80 | mut f: impl FnMut(hir::Function), | ||
81 | ) { | ||
82 | if let Some(krate) = ctx.krate { | ||
83 | let mut seen_methods = FxHashSet::default(); | ||
84 | let traits_in_scope = ctx.scope.traits_in_scope(); | ||
85 | receiver.iterate_method_candidates(ctx.db, krate, &traits_in_scope, None, |_ty, func| { | ||
86 | if func.self_param(ctx.db).is_some() | ||
87 | && ctx.scope.module().map_or(true, |m| func.is_visible_from(ctx.db, m)) | ||
88 | && seen_methods.insert(func.name(ctx.db)) | ||
89 | { | ||
90 | f(func); | ||
91 | } | ||
92 | None::<()> | ||
93 | }); | ||
94 | } | ||
28 | } | 95 | } |
29 | 96 | ||
30 | #[cfg(test)] | 97 | #[cfg(test)] |
@@ -453,4 +520,34 @@ impl S { | |||
453 | "#]], | 520 | "#]], |
454 | ); | 521 | ); |
455 | } | 522 | } |
523 | |||
524 | #[test] | ||
525 | fn completes_bare_fields_and_methods_in_methods() { | ||
526 | check( | ||
527 | r#" | ||
528 | struct Foo { field: i32 } | ||
529 | |||
530 | impl Foo { fn foo(&self) { $0 } }"#, | ||
531 | expect![[r#" | ||
532 | lc self &Foo | ||
533 | sp Self | ||
534 | st Foo | ||
535 | fd self.field i32 | ||
536 | me self.foo() fn(&self) | ||
537 | "#]], | ||
538 | ); | ||
539 | check( | ||
540 | r#" | ||
541 | struct Foo(i32); | ||
542 | |||
543 | impl Foo { fn foo(&mut self) { $0 } }"#, | ||
544 | expect![[r#" | ||
545 | lc self &mut Foo | ||
546 | sp Self | ||
547 | st Foo | ||
548 | fd self.0 i32 | ||
549 | me self.foo() fn(&mut self) | ||
550 | "#]], | ||
551 | ); | ||
552 | } | ||
456 | } | 553 | } |
diff --git a/crates/ide_completion/src/completions/unqualified_path.rs b/crates/ide_completion/src/completions/unqualified_path.rs index 83cb67101..20188a7dd 100644 --- a/crates/ide_completion/src/completions/unqualified_path.rs +++ b/crates/ide_completion/src/completions/unqualified_path.rs | |||
@@ -47,22 +47,6 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC | |||
47 | cov_mark::hit!(skip_lifetime_completion); | 47 | cov_mark::hit!(skip_lifetime_completion); |
48 | return; | 48 | return; |
49 | } | 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.clone()), field, &ty) | ||
56 | } | ||
57 | either::Either::Right(tuple_idx) => { | ||
58 | acc.add_tuple_field(ctx, Some(name.clone()), tuple_idx, &ty) | ||
59 | } | ||
60 | }); | ||
61 | super::complete_methods(ctx, &ty, |func| { | ||
62 | acc.add_method(ctx, func, Some(name.clone()), None) | ||
63 | }); | ||
64 | } | ||
65 | } | ||
66 | acc.add_resolution(ctx, name, &res); | 50 | acc.add_resolution(ctx, name, &res); |
67 | }); | 51 | }); |
68 | } | 52 | } |
@@ -394,36 +378,6 @@ fn foo() { | |||
394 | } | 378 | } |
395 | 379 | ||
396 | #[test] | 380 | #[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] | ||
427 | fn completes_prelude() { | 381 | fn completes_prelude() { |
428 | check( | 382 | check( |
429 | r#" | 383 | r#" |