aboutsummaryrefslogtreecommitdiff
path: root/crates/ide_completion/src/context.rs
diff options
context:
space:
mode:
authorLukas Wirth <[email protected]>2021-05-27 01:54:49 +0100
committerLukas Wirth <[email protected]>2021-05-27 01:54:49 +0100
commit7de925b8abcf0d26869dc96f346510af61663edf (patch)
tree38bcf6bc8d2cabb051b127e2f1f6cd2a9b94027c /crates/ide_completion/src/context.rs
parentd6ed315806e23d9ebda96ecfbe13da2154a2289c (diff)
Collapse more CompletionContext booleans into enums
Diffstat (limited to 'crates/ide_completion/src/context.rs')
-rw-r--r--crates/ide_completion/src/context.rs143
1 files changed, 94 insertions, 49 deletions
diff --git a/crates/ide_completion/src/context.rs b/crates/ide_completion/src/context.rs
index 6dc6769df..dfac8f29f 100644
--- a/crates/ide_completion/src/context.rs
+++ b/crates/ide_completion/src/context.rs
@@ -31,6 +31,24 @@ pub(crate) enum PatternRefutability {
31 Irrefutable, 31 Irrefutable,
32} 32}
33 33
34/// Direct parent container of the cursor position
35#[derive(Copy, Clone, Debug, PartialEq, Eq)]
36pub(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)]
47pub enum PrevSibling {
48 Trait,
49 Impl,
50}
51
34/// `CompletionContext` is created early during completion to figure out, where 52/// `CompletionContext` is created early during completion to figure out, where
35/// exactly is the cursor, syntax-wise. 53/// exactly is the cursor, syntax-wise.
36#[derive(Debug)] 54#[derive(Debug)]
@@ -48,14 +66,19 @@ pub(crate) struct CompletionContext<'a> {
48 pub(super) expected_name: Option<NameOrNameRef>, 66 pub(super) expected_name: Option<NameOrNameRef>,
49 pub(super) expected_type: Option<Type>, 67 pub(super) expected_type: Option<Type>,
50 pub(super) name_ref_syntax: Option<ast::NameRef>, 68 pub(super) name_ref_syntax: Option<ast::NameRef>,
51 pub(super) function_syntax: Option<ast::Fn>, 69
52 pub(super) use_item_syntax: Option<ast::Use>, 70 pub(super) use_item_syntax: Option<ast::Use>,
53 pub(super) record_lit_syntax: Option<ast::RecordExpr>, 71
54 pub(super) record_pat_syntax: Option<ast::RecordPat>, 72 /// The parent function of the cursor position if it exists.
55 pub(super) record_field_syntax: Option<ast::RecordExprField>, 73 pub(super) function_def: Option<ast::Fn>,
56 /// The parent impl of the cursor position if it exists. 74 /// The parent impl of the cursor position if it exists.
57 pub(super) impl_def: Option<ast::Impl>, 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 // potentially set if we are completing a lifetime 82 // potentially set if we are completing a lifetime
60 pub(super) lifetime_syntax: Option<ast::Lifetime>, 83 pub(super) lifetime_syntax: Option<ast::Lifetime>,
61 pub(super) lifetime_param_syntax: Option<ast::LifetimeParam>, 84 pub(super) lifetime_param_syntax: Option<ast::LifetimeParam>,
@@ -66,6 +89,8 @@ pub(crate) struct CompletionContext<'a> {
66 pub(super) is_pat_or_const: Option<PatternRefutability>, 89 pub(super) is_pat_or_const: Option<PatternRefutability>,
67 pub(super) is_param: bool, 90 pub(super) is_param: bool,
68 91
92 pub(super) completion_location: Option<ImmediateLocation>,
93
69 /// FIXME: `ActiveParameter` is string-based, which is very very wrong 94 /// FIXME: `ActiveParameter` is string-based, which is very very wrong
70 pub(super) active_parameter: Option<ActiveParameter>, 95 pub(super) active_parameter: Option<ActiveParameter>,
71 /// A single-indent path, like `foo`. `::foo` should not be considered a trivial path. 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 pub(super) locals: Vec<(String, Local)>, 119 pub(super) locals: Vec<(String, Local)>,
95 120
96 pub(super) mod_declaration_under_caret: Option<ast::Module>, 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 // keyword patterns 123 // keyword patterns
101 pub(super) previous_token: Option<SyntaxToken>, 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 pub(super) in_loop_body: bool, 125 pub(super) in_loop_body: bool,
106 pub(super) has_field_list_parent: bool, 126 pub(super) prev_sibling: Option<PrevSibling>,
107 pub(super) trait_as_prev_sibling: bool,
108 pub(super) impl_as_prev_sibling: bool,
109 pub(super) is_match_arm: bool, 127 pub(super) is_match_arm: bool,
110 pub(super) has_item_list_or_source_file_parent: bool,
111 pub(super) incomplete_let: bool, 128 pub(super) incomplete_let: bool,
112 129
113 no_completion_required: bool, 130 no_completion_required: bool,
@@ -159,11 +176,10 @@ impl<'a> CompletionContext<'a> {
159 name_ref_syntax: None, 176 name_ref_syntax: None,
160 lifetime_syntax: None, 177 lifetime_syntax: None,
161 lifetime_param_syntax: None, 178 lifetime_param_syntax: None,
162 function_syntax: None, 179 function_def: None,
163 use_item_syntax: None, 180 use_item_syntax: None,
164 record_lit_syntax: None, 181 record_lit_syntax: None,
165 record_pat_syntax: None, 182 record_pat_syntax: None,
166 record_field_syntax: None,
167 impl_def: None, 183 impl_def: None,
168 active_parameter: ActiveParameter::at(db, position), 184 active_parameter: ActiveParameter::at(db, position),
169 is_label_ref: false, 185 is_label_ref: false,
@@ -185,17 +201,10 @@ impl<'a> CompletionContext<'a> {
185 attribute_under_caret: None, 201 attribute_under_caret: None,
186 mod_declaration_under_caret: None, 202 mod_declaration_under_caret: None,
187 previous_token: None, 203 previous_token: None,
188 block_expr_parent: false,
189 bind_pat_parent: false,
190 ref_pat_parent: false,
191 in_loop_body: false, 204 in_loop_body: false,
192 has_trait_parent: false, 205 completion_location: None,
193 has_impl_parent: false, 206 prev_sibling: None,
194 has_field_list_parent: false,
195 trait_as_prev_sibling: false,
196 impl_as_prev_sibling: false,
197 is_match_arm: false, 207 is_match_arm: false,
198 has_item_list_or_source_file_parent: false,
199 no_completion_required: false, 208 no_completion_required: false,
200 incomplete_let: false, 209 incomplete_let: false,
201 locals, 210 locals,
@@ -274,23 +283,68 @@ impl<'a> CompletionContext<'a> {
274 self.previous_token.as_ref().map_or(false, |tok| tok.kind() == kind) 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 fn fill_keyword_patterns(&mut self, file_with_fake_ident: &SyntaxNode, offset: TextSize) { 320 fn fill_keyword_patterns(&mut self, file_with_fake_ident: &SyntaxNode, offset: TextSize) {
278 let fake_ident_token = file_with_fake_ident.token_at_offset(offset).right_biased().unwrap(); 321 let fake_ident_token = file_with_fake_ident.token_at_offset(offset).right_biased().unwrap();
279 let syntax_element = NodeOrToken::Token(fake_ident_token); 322 let syntax_element = NodeOrToken::Token(fake_ident_token);
280 self.previous_token = previous_token(syntax_element.clone()); 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 self.in_loop_body = is_in_loop_body(syntax_element.clone()); 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 self.is_match_arm = is_match_arm(syntax_element.clone()); 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 self.mod_declaration_under_caret = 348 self.mod_declaration_under_caret =
295 find_node_at_offset::<ast::Module>(&file_with_fake_ident, offset) 349 find_node_at_offset::<ast::Module>(&file_with_fake_ident, offset)
296 .filter(|module| module.item_list().is_none()); 350 .filter(|module| module.item_list().is_none());
@@ -542,31 +596,20 @@ impl<'a> CompletionContext<'a> {
542 .last() 596 .last()
543 .unwrap(); 597 .unwrap();
544 598
545 match top_node.parent().map(|it| it.kind()) { 599 if matches!(top_node.parent().map(|it| it.kind()), Some(SOURCE_FILE) | Some(ITEM_LIST)) {
546 Some(SOURCE_FILE) | Some(ITEM_LIST) => { 600 self.is_new_item = true;
547 self.is_new_item = true; 601 return;
548 return;
549 }
550 _ => (),
551 } 602 }
552 603
553 self.use_item_syntax = 604 self.use_item_syntax =
554 self.sema.token_ancestors_with_macros(self.token.clone()).find_map(ast::Use::cast); 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 .sema 608 .sema
558 .token_ancestors_with_macros(self.token.clone()) 609 .token_ancestors_with_macros(self.token.clone())
559 .take_while(|it| it.kind() != SOURCE_FILE && it.kind() != MODULE) 610 .take_while(|it| it.kind() != SOURCE_FILE && it.kind() != MODULE)
560 .find_map(ast::Fn::cast); 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 let parent = match name_ref.syntax().parent() { 613 let parent = match name_ref.syntax().parent() {
571 Some(it) => it, 614 Some(it) => it,
572 None => return, 615 None => return,
@@ -639,6 +682,7 @@ impl<'a> CompletionContext<'a> {
639 } 682 }
640 } 683 }
641 } 684 }
685
642 if let Some(field_expr) = ast::FieldExpr::cast(parent.clone()) { 686 if let Some(field_expr) = ast::FieldExpr::cast(parent.clone()) {
643 // The receiver comes before the point of insertion of the fake 687 // The receiver comes before the point of insertion of the fake
644 // ident, so it should have the same range in the non-modified file 688 // ident, so it should have the same range in the non-modified file
@@ -656,6 +700,7 @@ impl<'a> CompletionContext<'a> {
656 false 700 false
657 }; 701 };
658 } 702 }
703
659 if let Some(method_call_expr) = ast::MethodCallExpr::cast(parent) { 704 if let Some(method_call_expr) = ast::MethodCallExpr::cast(parent) {
660 // As above 705 // As above
661 self.dot_receiver = method_call_expr 706 self.dot_receiver = method_call_expr