1
1
//! Completes references after dot (fields and method calls).
2
2
3
- use hir:: { HasVisibility , Type } ;
3
+ use either:: Either ;
4
+ use hir:: { HasVisibility , ScopeDef } ;
4
5
use rustc_hash:: FxHashSet ;
5
6
6
7
use crate :: { context:: CompletionContext , Completions } ;
@@ -9,7 +10,7 @@ use crate::{context::CompletionContext, Completions};
9
10
pub ( crate ) fn complete_dot ( acc : & mut Completions , ctx : & CompletionContext ) {
10
11
let dot_receiver = match & ctx. dot_receiver {
11
12
Some ( expr) => expr,
12
- _ => return ,
13
+ _ => return complete_undotted_self ( acc , ctx ) ,
13
14
} ;
14
15
15
16
let receiver_ty = match ctx. sema . type_of_expr ( & dot_receiver) {
@@ -20,29 +21,64 @@ pub(crate) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) {
20
21
if ctx. is_call {
21
22
cov_mark:: hit!( test_no_struct_field_completion_for_method_call) ;
22
23
} else {
23
- complete_fields ( acc, ctx, & receiver_ty) ;
24
+ complete_fields ( ctx, & receiver_ty, |field, ty| match field {
25
+ Either :: Left ( field) => acc. add_field ( ctx, None , field, & ty) ,
26
+ Either :: Right ( tuple_idx) => acc. add_tuple_field ( ctx, None , tuple_idx, & ty) ,
27
+ } ) ;
24
28
}
25
- complete_methods ( acc, ctx, & receiver_ty) ;
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 || !ctx. config . enable_self_on_the_fly {
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
+ } ) ;
26
54
}
27
55
28
- fn complete_fields ( acc : & mut Completions , ctx : & CompletionContext , receiver : & Type ) {
56
+ fn complete_fields (
57
+ ctx : & CompletionContext ,
58
+ receiver : & hir:: Type ,
59
+ mut f : impl FnMut ( Either < hir:: Field , usize > , hir:: Type ) ,
60
+ ) {
29
61
for receiver in receiver. autoderef ( ctx. db ) {
30
62
for ( field, ty) in receiver. fields ( ctx. db ) {
31
63
if ctx. scope . module ( ) . map_or ( false , |m| !field. is_visible_from ( ctx. db , m) ) {
32
64
// Skip private field. FIXME: If the definition location of the
33
65
// field is editable, we should show the completion
34
66
continue ;
35
67
}
36
- acc . add_field ( ctx , field, & ty) ;
68
+ f ( Either :: Left ( field) , ty) ;
37
69
}
38
70
for ( i, ty) in receiver. tuple_fields ( ctx. db ) . into_iter ( ) . enumerate ( ) {
39
71
// FIXME: Handle visibility
40
- acc . add_tuple_field ( ctx , i , & ty) ;
72
+ f ( Either :: Right ( i ) , ty) ;
41
73
}
42
74
}
43
75
}
44
76
45
- fn complete_methods ( acc : & mut Completions , ctx : & CompletionContext , receiver : & Type ) {
77
+ fn complete_methods (
78
+ ctx : & CompletionContext ,
79
+ receiver : & hir:: Type ,
80
+ mut f : impl FnMut ( hir:: Function ) ,
81
+ ) {
46
82
if let Some ( krate) = ctx. krate {
47
83
let mut seen_methods = FxHashSet :: default ( ) ;
48
84
let traits_in_scope = ctx. scope . traits_in_scope ( ) ;
@@ -51,7 +87,7 @@ fn complete_methods(acc: &mut Completions, ctx: &CompletionContext, receiver: &T
51
87
&& ctx. scope . module ( ) . map_or ( true , |m| func. is_visible_from ( ctx. db , m) )
52
88
&& seen_methods. insert ( func. name ( ctx. db ) )
53
89
{
54
- acc . add_method ( ctx , func, None ) ;
90
+ f ( func) ;
55
91
}
56
92
None :: < ( ) >
57
93
} ) ;
@@ -484,4 +520,34 @@ impl S {
484
520
"# ] ] ,
485
521
) ;
486
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
+ }
487
553
}
0 commit comments