aboutsummaryrefslogtreecommitdiff
path: root/crates/ide_completion/src/context.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide_completion/src/context.rs')
-rw-r--r--crates/ide_completion/src/context.rs99
1 files changed, 35 insertions, 64 deletions
diff --git a/crates/ide_completion/src/context.rs b/crates/ide_completion/src/context.rs
index 8d6440cb2..7c46c815d 100644
--- a/crates/ide_completion/src/context.rs
+++ b/crates/ide_completion/src/context.rs
@@ -18,7 +18,7 @@ use text_edit::Indel;
18use crate::{ 18use crate::{
19 patterns::{ 19 patterns::{
20 determine_location, determine_prev_sibling, for_is_prev2, inside_impl_trait_block, 20 determine_location, determine_prev_sibling, for_is_prev2, inside_impl_trait_block,
21 is_in_loop_body, is_match_arm, previous_token, ImmediateLocation, ImmediatePrevSibling, 21 is_in_loop_body, previous_token, ImmediateLocation, ImmediatePrevSibling,
22 }, 22 },
23 CompletionConfig, 23 CompletionConfig,
24}; 24};
@@ -54,11 +54,6 @@ pub(crate) struct CompletionContext<'a> {
54 /// The parent impl of the cursor position if it exists. 54 /// The parent impl of the cursor position if it exists.
55 pub(super) impl_def: Option<ast::Impl>, 55 pub(super) impl_def: Option<ast::Impl>,
56 56
57 /// RecordExpr the token is a field of
58 pub(super) record_lit_syntax: Option<ast::RecordExpr>,
59 /// RecordPat the token is a field of
60 pub(super) record_pat_syntax: Option<ast::RecordPat>,
61
62 // potentially set if we are completing a lifetime 57 // potentially set if we are completing a lifetime
63 pub(super) lifetime_syntax: Option<ast::Lifetime>, 58 pub(super) lifetime_syntax: Option<ast::Lifetime>,
64 pub(super) lifetime_param_syntax: Option<ast::LifetimeParam>, 59 pub(super) lifetime_param_syntax: Option<ast::LifetimeParam>,
@@ -71,6 +66,7 @@ pub(crate) struct CompletionContext<'a> {
71 66
72 pub(super) completion_location: Option<ImmediateLocation>, 67 pub(super) completion_location: Option<ImmediateLocation>,
73 pub(super) prev_sibling: Option<ImmediatePrevSibling>, 68 pub(super) prev_sibling: Option<ImmediatePrevSibling>,
69 pub(super) attribute_under_caret: Option<ast::Attr>,
74 70
75 /// FIXME: `ActiveParameter` is string-based, which is very very wrong 71 /// FIXME: `ActiveParameter` is string-based, which is very very wrong
76 pub(super) active_parameter: Option<ActiveParameter>, 72 pub(super) active_parameter: Option<ActiveParameter>,
@@ -95,14 +91,10 @@ pub(crate) struct CompletionContext<'a> {
95 pub(super) is_macro_call: bool, 91 pub(super) is_macro_call: bool,
96 pub(super) is_path_type: bool, 92 pub(super) is_path_type: bool,
97 pub(super) has_type_args: bool, 93 pub(super) has_type_args: bool,
98 pub(super) attribute_under_caret: Option<ast::Attr>,
99 pub(super) mod_declaration_under_caret: Option<ast::Module>,
100 pub(super) locals: Vec<(String, Local)>, 94 pub(super) locals: Vec<(String, Local)>,
101 95
102 // keyword patterns
103 pub(super) previous_token: Option<SyntaxToken>, 96 pub(super) previous_token: Option<SyntaxToken>,
104 pub(super) in_loop_body: bool, 97 pub(super) in_loop_body: bool,
105 pub(super) is_match_arm: bool,
106 pub(super) incomplete_let: bool, 98 pub(super) incomplete_let: bool,
107 99
108 no_completion_required: bool, 100 no_completion_required: bool,
@@ -157,8 +149,6 @@ impl<'a> CompletionContext<'a> {
157 lifetime_param_syntax: None, 149 lifetime_param_syntax: None,
158 function_def: None, 150 function_def: None,
159 use_item_syntax: None, 151 use_item_syntax: None,
160 record_lit_syntax: None,
161 record_pat_syntax: None,
162 impl_def: None, 152 impl_def: None,
163 active_parameter: ActiveParameter::at(db, position), 153 active_parameter: ActiveParameter::at(db, position),
164 is_label_ref: false, 154 is_label_ref: false,
@@ -176,15 +166,13 @@ impl<'a> CompletionContext<'a> {
176 is_macro_call: false, 166 is_macro_call: false,
177 is_path_type: false, 167 is_path_type: false,
178 has_type_args: false, 168 has_type_args: false,
179 attribute_under_caret: None,
180 mod_declaration_under_caret: None,
181 previous_token: None, 169 previous_token: None,
182 in_loop_body: false, 170 in_loop_body: false,
183 completion_location: None, 171 completion_location: None,
184 prev_sibling: None, 172 prev_sibling: None,
185 is_match_arm: false,
186 no_completion_required: false, 173 no_completion_required: false,
187 incomplete_let: false, 174 incomplete_let: false,
175 attribute_under_caret: None,
188 locals, 176 locals,
189 }; 177 };
190 178
@@ -227,7 +215,6 @@ impl<'a> CompletionContext<'a> {
227 break; 215 break;
228 } 216 }
229 } 217 }
230 ctx.fill_keyword_patterns(&speculative_file, offset);
231 ctx.fill(&original_file, speculative_file, offset); 218 ctx.fill(&original_file, speculative_file, offset);
232 Some(ctx) 219 Some(ctx)
233 } 220 }
@@ -311,31 +298,13 @@ impl<'a> CompletionContext<'a> {
311 } 298 }
312 299
313 pub(crate) fn is_path_disallowed(&self) -> bool { 300 pub(crate) fn is_path_disallowed(&self) -> bool {
314 self.record_lit_syntax.is_some() 301 matches!(
315 || self.record_pat_syntax.is_some() 302 self.completion_location,
316 || self.attribute_under_caret.is_some() 303 Some(ImmediateLocation::Attribute(_))
317 || self.mod_declaration_under_caret.is_some() 304 | Some(ImmediateLocation::ModDeclaration(_))
318 } 305 | Some(ImmediateLocation::RecordPat(_))
319 306 | Some(ImmediateLocation::RecordExpr(_))
320 fn fill_keyword_patterns(&mut self, file_with_fake_ident: &SyntaxNode, offset: TextSize) { 307 ) || self.attribute_under_caret.is_some()
321 let fake_ident_token = file_with_fake_ident.token_at_offset(offset).right_biased().unwrap();
322 let syntax_element = NodeOrToken::Token(fake_ident_token);
323 self.previous_token = previous_token(syntax_element.clone());
324 self.in_loop_body = is_in_loop_body(syntax_element.clone());
325 self.is_match_arm = is_match_arm(syntax_element.clone());
326
327 self.mod_declaration_under_caret =
328 find_node_at_offset::<ast::Module>(&file_with_fake_ident, offset)
329 .filter(|module| module.item_list().is_none());
330 self.incomplete_let =
331 syntax_element.ancestors().take(6).find_map(ast::LetStmt::cast).map_or(false, |it| {
332 it.syntax().text_range().end() == syntax_element.text_range().end()
333 });
334
335 let inside_impl_trait_block = inside_impl_trait_block(syntax_element.clone());
336 let fn_is_prev = self.previous_token_is(T![fn]);
337 let for_is_prev2 = for_is_prev2(syntax_element.clone());
338 self.no_completion_required = (fn_is_prev && !inside_impl_trait_block) || for_is_prev2;
339 } 308 }
340 309
341 fn fill_impl_def(&mut self) { 310 fn fill_impl_def(&mut self) {
@@ -453,25 +422,43 @@ impl<'a> CompletionContext<'a> {
453 file_with_fake_ident: SyntaxNode, 422 file_with_fake_ident: SyntaxNode,
454 offset: TextSize, 423 offset: TextSize,
455 ) { 424 ) {
425 let fake_ident_token = file_with_fake_ident.token_at_offset(offset).right_biased().unwrap();
426 let syntax_element = NodeOrToken::Token(fake_ident_token);
427 self.previous_token = previous_token(syntax_element.clone());
428 self.attribute_under_caret = syntax_element.ancestors().find_map(ast::Attr::cast);
429 self.no_completion_required = {
430 let inside_impl_trait_block = inside_impl_trait_block(syntax_element.clone());
431 let fn_is_prev = self.previous_token_is(T![fn]);
432 let for_is_prev2 = for_is_prev2(syntax_element.clone());
433 (fn_is_prev && !inside_impl_trait_block) || for_is_prev2
434 };
435 self.in_loop_body = is_in_loop_body(syntax_element.clone());
436
437 self.incomplete_let =
438 syntax_element.ancestors().take(6).find_map(ast::LetStmt::cast).map_or(false, |it| {
439 it.syntax().text_range().end() == syntax_element.text_range().end()
440 });
441
456 let (expected_type, expected_name) = self.expected_type_and_name(); 442 let (expected_type, expected_name) = self.expected_type_and_name();
457 self.expected_type = expected_type; 443 self.expected_type = expected_type;
458 self.expected_name = expected_name; 444 self.expected_name = expected_name;
459 self.attribute_under_caret = find_node_at_offset(&file_with_fake_ident, offset); 445
460 let name_like = match find_node_at_offset(&&file_with_fake_ident, offset) { 446 let name_like = match find_node_at_offset(&&file_with_fake_ident, offset) {
461 Some(it) => it, 447 Some(it) => it,
462 None => return, 448 None => return,
463 }; 449 };
464 self.completion_location = determine_location(&name_like); 450 self.completion_location =
451 determine_location(&self.sema, original_file, offset, &name_like);
465 self.prev_sibling = determine_prev_sibling(&name_like); 452 self.prev_sibling = determine_prev_sibling(&name_like);
466 match name_like { 453 match name_like {
467 ast::NameLike::Lifetime(lifetime) => { 454 ast::NameLike::Lifetime(lifetime) => {
468 self.classify_lifetime(original_file, lifetime, offset); 455 self.classify_lifetime(original_file, lifetime, offset);
469 } 456 }
470 ast::NameLike::NameRef(name_ref) => { 457 ast::NameLike::NameRef(name_ref) => {
471 self.classify_name_ref(original_file, name_ref, offset); 458 self.classify_name_ref(original_file, name_ref);
472 } 459 }
473 ast::NameLike::Name(name) => { 460 ast::NameLike::Name(name) => {
474 self.classify_name(original_file, name, offset); 461 self.classify_name(name);
475 } 462 }
476 } 463 }
477 } 464 }
@@ -505,7 +492,7 @@ impl<'a> CompletionContext<'a> {
505 } 492 }
506 } 493 }
507 494
508 fn classify_name(&mut self, original_file: &SyntaxNode, name: ast::Name, offset: TextSize) { 495 fn classify_name(&mut self, name: ast::Name) {
509 if let Some(bind_pat) = name.syntax().parent().and_then(ast::IdentPat::cast) { 496 if let Some(bind_pat) = name.syntax().parent().and_then(ast::IdentPat::cast) {
510 self.is_pat_or_const = Some(PatternRefutability::Refutable); 497 self.is_pat_or_const = Some(PatternRefutability::Refutable);
511 // if any of these is here our bind pat can't be a const pat anymore 498 // if any of these is here our bind pat can't be a const pat anymore
@@ -543,28 +530,12 @@ impl<'a> CompletionContext<'a> {
543 530
544 self.fill_impl_def(); 531 self.fill_impl_def();
545 } 532 }
533
546 self.is_param |= is_node::<ast::Param>(name.syntax()); 534 self.is_param |= is_node::<ast::Param>(name.syntax());
547 if ast::RecordPatField::for_field_name(&name).is_some() {
548 self.record_pat_syntax =
549 self.sema.find_node_at_offset_with_macros(&original_file, offset);
550 }
551 } 535 }
552 536
553 fn classify_name_ref( 537 fn classify_name_ref(&mut self, original_file: &SyntaxNode, name_ref: ast::NameRef) {
554 &mut self,
555 original_file: &SyntaxNode,
556 name_ref: ast::NameRef,
557 offset: TextSize,
558 ) {
559 self.fill_impl_def(); 538 self.fill_impl_def();
560 if ast::RecordExprField::for_field_name(&name_ref).is_some() {
561 self.record_lit_syntax =
562 self.sema.find_node_at_offset_with_macros(original_file, offset);
563 }
564 if ast::RecordPatField::for_field_name_ref(&name_ref).is_some() {
565 self.record_pat_syntax =
566 self.sema.find_node_at_offset_with_macros(&original_file, offset);
567 }
568 539
569 self.name_ref_syntax = 540 self.name_ref_syntax =
570 find_node_at_offset(original_file, name_ref.syntax().text_range().start()); 541 find_node_at_offset(original_file, name_ref.syntax().text_range().start());