@@ -18,9 +18,8 @@ use text_edit::Indel;
18
18
use crate :: {
19
19
patterns:: {
20
20
for_is_prev2, has_bind_pat_parent, has_block_expr_parent, has_field_list_parent,
21
- has_impl_as_prev_sibling, has_impl_parent, has_item_list_or_source_file_parent,
22
- has_ref_parent, has_trait_as_prev_sibling, has_trait_parent, inside_impl_trait_block,
23
- is_in_loop_body, is_match_arm, previous_token,
21
+ has_impl_parent, has_item_list_or_source_file_parent, has_prev_sibling, has_ref_parent,
22
+ has_trait_parent, inside_impl_trait_block, is_in_loop_body, is_match_arm, previous_token,
24
23
} ,
25
24
CompletionConfig ,
26
25
} ;
@@ -31,6 +30,24 @@ pub(crate) enum PatternRefutability {
31
30
Irrefutable ,
32
31
}
33
32
33
+ /// Direct parent container of the cursor position
34
+ #[ derive( Copy , Clone , Debug , PartialEq , Eq ) ]
35
+ pub ( crate ) enum ImmediateLocation {
36
+ Impl ,
37
+ Trait ,
38
+ RecordFieldList ,
39
+ RefPatOrExpr ,
40
+ IdentPat ,
41
+ BlockExpr ,
42
+ ItemList ,
43
+ }
44
+
45
+ #[ derive( Copy , Clone , Debug , PartialEq , Eq ) ]
46
+ pub ( crate ) enum PrevSibling {
47
+ Trait ,
48
+ Impl ,
49
+ }
50
+
34
51
/// `CompletionContext` is created early during completion to figure out, where
35
52
/// exactly is the cursor, syntax-wise.
36
53
#[ derive( Debug ) ]
@@ -48,14 +65,19 @@ pub(crate) struct CompletionContext<'a> {
48
65
pub ( super ) expected_name : Option < NameOrNameRef > ,
49
66
pub ( super ) expected_type : Option < Type > ,
50
67
pub ( super ) name_ref_syntax : Option < ast:: NameRef > ,
51
- pub ( super ) function_syntax : Option < ast :: Fn > ,
68
+
52
69
pub ( super ) use_item_syntax : Option < ast:: Use > ,
53
- pub ( super ) record_lit_syntax : Option < ast :: RecordExpr > ,
54
- pub ( super ) record_pat_syntax : Option < ast :: RecordPat > ,
55
- pub ( super ) record_field_syntax : Option < ast:: RecordExprField > ,
70
+
71
+ /// The parent function of the cursor position if it exists.
72
+ pub ( super ) function_def : Option < ast:: Fn > ,
56
73
/// The parent impl of the cursor position if it exists.
57
74
pub ( super ) impl_def : Option < ast:: Impl > ,
58
75
76
+ /// RecordExpr the token is a field of
77
+ pub ( super ) record_lit_syntax : Option < ast:: RecordExpr > ,
78
+ /// RecordPat the token is a field of
79
+ pub ( super ) record_pat_syntax : Option < ast:: RecordPat > ,
80
+
59
81
// potentially set if we are completing a lifetime
60
82
pub ( super ) lifetime_syntax : Option < ast:: Lifetime > ,
61
83
pub ( super ) lifetime_param_syntax : Option < ast:: LifetimeParam > ,
@@ -66,6 +88,8 @@ pub(crate) struct CompletionContext<'a> {
66
88
pub ( super ) is_pat_or_const : Option < PatternRefutability > ,
67
89
pub ( super ) is_param : bool ,
68
90
91
+ pub ( super ) completion_location : Option < ImmediateLocation > ,
92
+
69
93
/// FIXME: `ActiveParameter` is string-based, which is very very wrong
70
94
pub ( super ) active_parameter : Option < ActiveParameter > ,
71
95
/// A single-indent path, like `foo`. `::foo` should not be considered a trivial path.
@@ -94,20 +118,12 @@ pub(crate) struct CompletionContext<'a> {
94
118
pub ( super ) locals : Vec < ( String , Local ) > ,
95
119
96
120
pub ( super ) mod_declaration_under_caret : Option < ast:: Module > ,
97
- pub ( super ) has_trait_parent : bool ,
98
- pub ( super ) has_impl_parent : bool ,
99
121
100
122
// keyword patterns
101
123
pub ( super ) previous_token : Option < SyntaxToken > ,
102
- pub ( super ) block_expr_parent : bool ,
103
- pub ( super ) bind_pat_parent : bool ,
104
- pub ( super ) ref_pat_parent : bool ,
105
124
pub ( super ) in_loop_body : bool ,
106
- pub ( super ) has_field_list_parent : bool ,
107
- pub ( super ) trait_as_prev_sibling : bool ,
108
- pub ( super ) impl_as_prev_sibling : bool ,
125
+ pub ( super ) prev_sibling : Option < PrevSibling > ,
109
126
pub ( super ) is_match_arm : bool ,
110
- pub ( super ) has_item_list_or_source_file_parent : bool ,
111
127
pub ( super ) incomplete_let : bool ,
112
128
113
129
no_completion_required : bool ,
@@ -159,11 +175,10 @@ impl<'a> CompletionContext<'a> {
159
175
name_ref_syntax : None ,
160
176
lifetime_syntax : None ,
161
177
lifetime_param_syntax : None ,
162
- function_syntax : None ,
178
+ function_def : None ,
163
179
use_item_syntax : None ,
164
180
record_lit_syntax : None ,
165
181
record_pat_syntax : None ,
166
- record_field_syntax : None ,
167
182
impl_def : None ,
168
183
active_parameter : ActiveParameter :: at ( db, position) ,
169
184
is_label_ref : false ,
@@ -185,17 +200,10 @@ impl<'a> CompletionContext<'a> {
185
200
attribute_under_caret : None ,
186
201
mod_declaration_under_caret : None ,
187
202
previous_token : None ,
188
- block_expr_parent : false ,
189
- bind_pat_parent : false ,
190
- ref_pat_parent : false ,
191
203
in_loop_body : false ,
192
- has_trait_parent : false ,
193
- has_impl_parent : false ,
194
- has_field_list_parent : false ,
195
- trait_as_prev_sibling : false ,
196
- impl_as_prev_sibling : false ,
204
+ completion_location : None ,
205
+ prev_sibling : None ,
197
206
is_match_arm : false ,
198
- has_item_list_or_source_file_parent : false ,
199
207
no_completion_required : false ,
200
208
incomplete_let : false ,
201
209
locals,
@@ -274,23 +282,68 @@ impl<'a> CompletionContext<'a> {
274
282
self . previous_token . as_ref ( ) . map_or ( false , |tok| tok. kind ( ) == kind)
275
283
}
276
284
285
+ pub ( crate ) fn has_impl_or_trait_parent ( & self ) -> bool {
286
+ matches ! (
287
+ self . completion_location,
288
+ Some ( ImmediateLocation :: Trait ) | Some ( ImmediateLocation :: Impl )
289
+ )
290
+ }
291
+
292
+ pub ( crate ) fn has_block_expr_parent ( & self ) -> bool {
293
+ matches ! ( self . completion_location, Some ( ImmediateLocation :: BlockExpr ) )
294
+ }
295
+
296
+ pub ( crate ) fn has_item_list_parent ( & self ) -> bool {
297
+ matches ! ( self . completion_location, Some ( ImmediateLocation :: ItemList ) )
298
+ }
299
+
300
+ pub ( crate ) fn has_ident_or_ref_pat_parent ( & self ) -> bool {
301
+ matches ! (
302
+ self . completion_location,
303
+ Some ( ImmediateLocation :: IdentPat ) | Some ( ImmediateLocation :: RefPatOrExpr )
304
+ )
305
+ }
306
+
307
+ pub ( crate ) fn has_impl_parent ( & self ) -> bool {
308
+ matches ! ( self . completion_location, Some ( ImmediateLocation :: Impl ) )
309
+ }
310
+
311
+ pub ( crate ) fn has_field_list_parent ( & self ) -> bool {
312
+ matches ! ( self . completion_location, Some ( ImmediateLocation :: RecordFieldList ) )
313
+ }
314
+
315
+ pub ( crate ) fn has_impl_or_trait_prev_sibling ( & self ) -> bool {
316
+ self . prev_sibling . is_some ( )
317
+ }
318
+
277
319
fn fill_keyword_patterns ( & mut self , file_with_fake_ident : & SyntaxNode , offset : TextSize ) {
278
320
let fake_ident_token = file_with_fake_ident. token_at_offset ( offset) . right_biased ( ) . unwrap ( ) ;
279
321
let syntax_element = NodeOrToken :: Token ( fake_ident_token) ;
280
322
self . previous_token = previous_token ( syntax_element. clone ( ) ) ;
281
- self . block_expr_parent = has_block_expr_parent ( syntax_element. clone ( ) ) ;
282
- self . bind_pat_parent = has_bind_pat_parent ( syntax_element. clone ( ) ) ;
283
- self . ref_pat_parent = has_ref_parent ( syntax_element. clone ( ) ) ;
284
323
self . in_loop_body = is_in_loop_body ( syntax_element. clone ( ) ) ;
285
- self . has_trait_parent = has_trait_parent ( syntax_element. clone ( ) ) ;
286
- self . has_impl_parent = has_impl_parent ( syntax_element. clone ( ) ) ;
287
- self . has_field_list_parent = has_field_list_parent ( syntax_element. clone ( ) ) ;
288
- self . impl_as_prev_sibling = has_impl_as_prev_sibling ( syntax_element. clone ( ) ) ;
289
- self . trait_as_prev_sibling = has_trait_as_prev_sibling ( syntax_element. clone ( ) ) ;
290
324
self . is_match_arm = is_match_arm ( syntax_element. clone ( ) ) ;
325
+ if has_prev_sibling ( syntax_element. clone ( ) , IMPL ) {
326
+ self . prev_sibling = Some ( PrevSibling :: Impl )
327
+ } else if has_prev_sibling ( syntax_element. clone ( ) , TRAIT ) {
328
+ self . prev_sibling = Some ( PrevSibling :: Trait )
329
+ }
330
+
331
+ if has_block_expr_parent ( syntax_element. clone ( ) ) {
332
+ self . completion_location = Some ( ImmediateLocation :: BlockExpr ) ;
333
+ } else if has_bind_pat_parent ( syntax_element. clone ( ) ) {
334
+ self . completion_location = Some ( ImmediateLocation :: IdentPat ) ;
335
+ } else if has_ref_parent ( syntax_element. clone ( ) ) {
336
+ self . completion_location = Some ( ImmediateLocation :: RefPatOrExpr ) ;
337
+ } else if has_impl_parent ( syntax_element. clone ( ) ) {
338
+ self . completion_location = Some ( ImmediateLocation :: Impl ) ;
339
+ } else if has_field_list_parent ( syntax_element. clone ( ) ) {
340
+ self . completion_location = Some ( ImmediateLocation :: RecordFieldList ) ;
341
+ } else if has_trait_parent ( syntax_element. clone ( ) ) {
342
+ self . completion_location = Some ( ImmediateLocation :: Trait ) ;
343
+ } else if has_item_list_or_source_file_parent ( syntax_element. clone ( ) ) {
344
+ self . completion_location = Some ( ImmediateLocation :: ItemList ) ;
345
+ }
291
346
292
- self . has_item_list_or_source_file_parent =
293
- has_item_list_or_source_file_parent ( syntax_element. clone ( ) ) ;
294
347
self . mod_declaration_under_caret =
295
348
find_node_at_offset :: < ast:: Module > ( & file_with_fake_ident, offset)
296
349
. filter ( |module| module. item_list ( ) . is_none ( ) ) ;
@@ -542,31 +595,20 @@ impl<'a> CompletionContext<'a> {
542
595
. last ( )
543
596
. unwrap ( ) ;
544
597
545
- match top_node. parent ( ) . map ( |it| it. kind ( ) ) {
546
- Some ( SOURCE_FILE ) | Some ( ITEM_LIST ) => {
547
- self . is_new_item = true ;
548
- return ;
549
- }
550
- _ => ( ) ,
598
+ if matches ! ( top_node. parent( ) . map( |it| it. kind( ) ) , Some ( SOURCE_FILE ) | Some ( ITEM_LIST ) ) {
599
+ self . is_new_item = true ;
600
+ return ;
551
601
}
552
602
553
603
self . use_item_syntax =
554
604
self . sema . token_ancestors_with_macros ( self . token . clone ( ) ) . find_map ( ast:: Use :: cast) ;
555
605
556
- self . function_syntax = self
606
+ self . function_def = self
557
607
. sema
558
608
. token_ancestors_with_macros ( self . token . clone ( ) )
559
609
. take_while ( |it| it. kind ( ) != SOURCE_FILE && it. kind ( ) != MODULE )
560
610
. find_map ( ast:: Fn :: cast) ;
561
611
562
- self . record_field_syntax = self
563
- . sema
564
- . token_ancestors_with_macros ( self . token . clone ( ) )
565
- . take_while ( |it| {
566
- it. kind ( ) != SOURCE_FILE && it. kind ( ) != MODULE && it. kind ( ) != CALL_EXPR
567
- } )
568
- . find_map ( ast:: RecordExprField :: cast) ;
569
-
570
612
let parent = match name_ref. syntax ( ) . parent ( ) {
571
613
Some ( it) => it,
572
614
None => return ,
@@ -639,6 +681,7 @@ impl<'a> CompletionContext<'a> {
639
681
}
640
682
}
641
683
}
684
+
642
685
if let Some ( field_expr) = ast:: FieldExpr :: cast ( parent. clone ( ) ) {
643
686
// The receiver comes before the point of insertion of the fake
644
687
// ident, so it should have the same range in the non-modified file
@@ -656,6 +699,7 @@ impl<'a> CompletionContext<'a> {
656
699
false
657
700
} ;
658
701
}
702
+
659
703
if let Some ( method_call_expr) = ast:: MethodCallExpr :: cast ( parent) {
660
704
// As above
661
705
self . dot_receiver = method_call_expr
0 commit comments