1
1
//! Completes references after dot (fields and method calls).
2
2
3
3
use either:: Either ;
4
+ use hir:: { HasVisibility , ScopeDef } ;
5
+ use rustc_hash:: FxHashSet ;
4
6
5
7
use crate :: { context:: CompletionContext , Completions } ;
6
8
7
9
/// Complete dot accesses, i.e. fields or methods.
8
10
pub ( crate ) fn complete_dot ( acc : & mut Completions , ctx : & CompletionContext ) {
9
11
let dot_receiver = match & ctx. dot_receiver {
10
12
Some ( expr) => expr,
11
- _ => return ,
13
+ _ => return complete_undotted_self ( acc , ctx ) ,
12
14
} ;
13
15
14
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
21
if ctx. is_call {
20
22
cov_mark:: hit!( test_no_struct_field_completion_for_method_call) ;
21
23
} else {
22
- super :: complete_fields ( ctx, & receiver_ty, |field, ty| match field {
24
+ complete_fields ( ctx, & receiver_ty, |field, ty| match field {
23
25
Either :: Left ( field) => acc. add_field ( ctx, None , field, & ty) ,
24
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
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
}
0 commit comments