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