aboutsummaryrefslogtreecommitdiff
path: root/crates/ide_completion/src/context.rs
diff options
context:
space:
mode:
authorLukas Wirth <[email protected]>2021-03-20 21:43:42 +0000
committerLukas Wirth <[email protected]>2021-03-20 22:25:07 +0000
commit3c000c6364ebcf94652d221ee9ffe8970540589c (patch)
treea1f10f8ef2d3a923ad723e11d6a4ff43dbcc5f49 /crates/ide_completion/src/context.rs
parent5cc8ad0c4afda0c8b6222156b0c725cfb61892c0 (diff)
Add basic lifetime completion
Diffstat (limited to 'crates/ide_completion/src/context.rs')
-rw-r--r--crates/ide_completion/src/context.rs34
1 files changed, 31 insertions, 3 deletions
diff --git a/crates/ide_completion/src/context.rs b/crates/ide_completion/src/context.rs
index 6d57da06a..3c31de9ad 100644
--- a/crates/ide_completion/src/context.rs
+++ b/crates/ide_completion/src/context.rs
@@ -38,12 +38,15 @@ pub(crate) struct CompletionContext<'a> {
38 pub(super) expected_name: Option<String>, 38 pub(super) expected_name: Option<String>,
39 pub(super) expected_type: Option<Type>, 39 pub(super) expected_type: Option<Type>,
40 pub(super) name_ref_syntax: Option<ast::NameRef>, 40 pub(super) name_ref_syntax: Option<ast::NameRef>,
41 pub(super) lifetime_syntax: Option<ast::Lifetime>,
42 pub(super) lifetime_param_syntax: Option<ast::LifetimeParam>,
41 pub(super) function_syntax: Option<ast::Fn>, 43 pub(super) function_syntax: Option<ast::Fn>,
42 pub(super) use_item_syntax: Option<ast::Use>, 44 pub(super) use_item_syntax: Option<ast::Use>,
43 pub(super) record_lit_syntax: Option<ast::RecordExpr>, 45 pub(super) record_lit_syntax: Option<ast::RecordExpr>,
44 pub(super) record_pat_syntax: Option<ast::RecordPat>, 46 pub(super) record_pat_syntax: Option<ast::RecordPat>,
45 pub(super) record_field_syntax: Option<ast::RecordExprField>, 47 pub(super) record_field_syntax: Option<ast::RecordExprField>,
46 pub(super) impl_def: Option<ast::Impl>, 48 pub(super) impl_def: Option<ast::Impl>,
49 pub(super) lifetime_allowed: bool,
47 /// FIXME: `ActiveParameter` is string-based, which is very very wrong 50 /// FIXME: `ActiveParameter` is string-based, which is very very wrong
48 pub(super) active_parameter: Option<ActiveParameter>, 51 pub(super) active_parameter: Option<ActiveParameter>,
49 pub(super) is_param: bool, 52 pub(super) is_param: bool,
@@ -136,9 +139,12 @@ impl<'a> CompletionContext<'a> {
136 original_token, 139 original_token,
137 token, 140 token,
138 krate, 141 krate,
142 lifetime_allowed: false,
139 expected_name: None, 143 expected_name: None,
140 expected_type: None, 144 expected_type: None,
141 name_ref_syntax: None, 145 name_ref_syntax: None,
146 lifetime_syntax: None,
147 lifetime_param_syntax: None,
142 function_syntax: None, 148 function_syntax: None,
143 use_item_syntax: None, 149 use_item_syntax: None,
144 record_lit_syntax: None, 150 record_lit_syntax: None,
@@ -241,7 +247,7 @@ impl<'a> CompletionContext<'a> {
241 pub(crate) fn source_range(&self) -> TextRange { 247 pub(crate) fn source_range(&self) -> TextRange {
242 // check kind of macro-expanded token, but use range of original token 248 // check kind of macro-expanded token, but use range of original token
243 let kind = self.token.kind(); 249 let kind = self.token.kind();
244 if kind == IDENT || kind == UNDERSCORE || kind.is_keyword() { 250 if kind == IDENT || kind == LIFETIME_IDENT || kind == UNDERSCORE || kind.is_keyword() {
245 cov_mark::hit!(completes_if_prefix_is_keyword); 251 cov_mark::hit!(completes_if_prefix_is_keyword);
246 self.original_token.text_range() 252 self.original_token.text_range()
247 } else { 253 } else {
@@ -386,6 +392,11 @@ impl<'a> CompletionContext<'a> {
386 self.expected_name = expected.1; 392 self.expected_name = expected.1;
387 self.attribute_under_caret = find_node_at_offset(&file_with_fake_ident, offset); 393 self.attribute_under_caret = find_node_at_offset(&file_with_fake_ident, offset);
388 394
395 if let Some(lifetime) = find_node_at_offset::<ast::Lifetime>(&file_with_fake_ident, offset)
396 {
397 self.classify_lifetime(original_file, lifetime, offset);
398 }
399
389 // First, let's try to complete a reference to some declaration. 400 // First, let's try to complete a reference to some declaration.
390 if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(&file_with_fake_ident, offset) { 401 if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(&file_with_fake_ident, offset) {
391 // Special case, `trait T { fn foo(i_am_a_name_ref) {} }`. 402 // Special case, `trait T { fn foo(i_am_a_name_ref) {} }`.
@@ -445,6 +456,23 @@ impl<'a> CompletionContext<'a> {
445 } 456 }
446 } 457 }
447 458
459 fn classify_lifetime(
460 &mut self,
461 original_file: &SyntaxNode,
462 lifetime: ast::Lifetime,
463 offset: TextSize,
464 ) {
465 self.lifetime_syntax =
466 find_node_at_offset(original_file, lifetime.syntax().text_range().start());
467 if lifetime.syntax().parent().map_or(false, |p| p.kind() != syntax::SyntaxKind::ERROR) {
468 self.lifetime_allowed = true;
469 }
470 if let Some(_) = lifetime.syntax().parent().and_then(ast::LifetimeParam::cast) {
471 self.lifetime_param_syntax =
472 self.sema.find_node_at_offset_with_macros(original_file, offset);
473 }
474 }
475
448 fn classify_name_ref( 476 fn classify_name_ref(
449 &mut self, 477 &mut self,
450 original_file: &SyntaxNode, 478 original_file: &SyntaxNode,
@@ -452,11 +480,11 @@ impl<'a> CompletionContext<'a> {
452 offset: TextSize, 480 offset: TextSize,
453 ) { 481 ) {
454 self.name_ref_syntax = 482 self.name_ref_syntax =
455 find_node_at_offset(&original_file, name_ref.syntax().text_range().start()); 483 find_node_at_offset(original_file, name_ref.syntax().text_range().start());
456 let name_range = name_ref.syntax().text_range(); 484 let name_range = name_ref.syntax().text_range();
457 if ast::RecordExprField::for_field_name(&name_ref).is_some() { 485 if ast::RecordExprField::for_field_name(&name_ref).is_some() {
458 self.record_lit_syntax = 486 self.record_lit_syntax =
459 self.sema.find_node_at_offset_with_macros(&original_file, offset); 487 self.sema.find_node_at_offset_with_macros(original_file, offset);
460 } 488 }
461 489
462 self.fill_impl_def(); 490 self.fill_impl_def();