Skip to content

Commit 92b9e5e

Browse files
bors[bot]Veykril
andauthored
9068: Move more `CompletinoContext` fields to `ImmediateLocation` r=Veykril a=Veykril bors r+ Co-authored-by: Lukas Wirth <[email protected]>
2 parents 088b670 + 5660408 commit 92b9e5e

File tree

6 files changed

+163
-146
lines changed

6 files changed

+163
-146
lines changed

crates/ide_completion/src/completions/fn_param.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,4 +128,19 @@ fn outer(text: String) {
128128
"#]],
129129
)
130130
}
131+
132+
#[test]
133+
fn completes_non_ident_pat_param() {
134+
check(
135+
r#"
136+
struct Bar { bar: u32 }
137+
138+
fn foo(Bar { bar }: Bar) {}
139+
fn foo2($0) {}
140+
"#,
141+
expect![[r#"
142+
bn Bar { bar }: Bar
143+
"#]],
144+
)
145+
}
131146
}

crates/ide_completion/src/completions/keyword.rs

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@ use std::iter;
44

55
use syntax::{SyntaxKind, T};
66

7-
use crate::{CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions};
7+
use crate::{
8+
patterns::ImmediateLocation, CompletionContext, CompletionItem, CompletionItemKind,
9+
CompletionKind, Completions,
10+
};
811

912
pub(crate) fn complete_use_tree_keyword(acc: &mut Completions, ctx: &CompletionContext) {
1013
// complete keyword "crate" in use stmt
@@ -44,7 +47,7 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
4447
cov_mark::hit!(no_keyword_completion_in_comments);
4548
return;
4649
}
47-
if ctx.record_lit_syntax.is_some() {
50+
if matches!(ctx.completion_location, Some(ImmediateLocation::RecordExpr(_))) {
4851
cov_mark::hit!(no_keyword_completion_in_record_lit);
4952
return;
5053
}
@@ -55,7 +58,6 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
5558
let expects_item = ctx.expects_item();
5659

5760
if ctx.has_impl_or_trait_prev_sibling() {
58-
// FIXME this also incorrectly shows up after a complete trait/impl
5961
add_keyword("where", "where ");
6062
return;
6163
}
@@ -77,11 +79,8 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
7779
add_keyword("pub", "pub ");
7880
}
7981

80-
if expects_item || expects_assoc_item || has_block_expr_parent || ctx.is_match_arm {
81-
add_keyword("unsafe", "unsafe ");
82-
}
83-
8482
if expects_item || expects_assoc_item || has_block_expr_parent {
83+
add_keyword("unsafe", "unsafe ");
8584
add_keyword("fn", "fn $1($2) {\n $0\n}");
8685
add_keyword("const", "const $0");
8786
add_keyword("type", "type $0");
@@ -103,6 +102,9 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
103102
}
104103

105104
if ctx.expects_expression() {
105+
if !has_block_expr_parent {
106+
add_keyword("unsafe", "unsafe {\n $0\n}");
107+
}
106108
add_keyword("match", "match $1 {\n $0\n}");
107109
add_keyword("while", "while $1 {\n $0\n}");
108110
add_keyword("while let", "while let $1 = $2 {\n $0\n}");
@@ -574,6 +576,7 @@ pub mod future {
574576
check(
575577
r#"fn main() { let _ = $0 }"#,
576578
expect![[r#"
579+
kw unsafe
577580
kw match
578581
kw while
579582
kw while let
@@ -634,6 +637,7 @@ fn foo() {
634637
}
635638
"#,
636639
expect![[r#"
640+
kw unsafe
637641
kw match
638642
kw while
639643
kw while let

crates/ide_completion/src/completions/mod_.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,14 @@ use ide_db::{
99
};
1010
use rustc_hash::FxHashSet;
1111

12-
use crate::CompletionItem;
12+
use crate::{patterns::ImmediateLocation, CompletionItem};
1313

1414
use crate::{context::CompletionContext, item::CompletionKind, Completions};
1515

1616
/// Complete mod declaration, i.e. `mod $0 ;`
1717
pub(crate) fn complete_mod(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
18-
let mod_under_caret = match &ctx.mod_declaration_under_caret {
19-
Some(mod_under_caret) if mod_under_caret.item_list().is_none() => mod_under_caret,
18+
let mod_under_caret = match &ctx.completion_location {
19+
Some(ImmediateLocation::ModDeclaration(mod_under_caret)) => mod_under_caret,
2020
_ => return None,
2121
};
2222

crates/ide_completion/src/completions/record.rs

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,21 @@
22
use ide_db::{helpers::FamousDefs, SymbolKind};
33
use syntax::ast::Expr;
44

5-
use crate::{item::CompletionKind, CompletionContext, CompletionItem, Completions};
5+
use crate::{
6+
item::CompletionKind, patterns::ImmediateLocation, CompletionContext, CompletionItem,
7+
Completions,
8+
};
69

710
pub(crate) fn complete_record(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
8-
let missing_fields = match (ctx.record_pat_syntax.as_ref(), ctx.record_lit_syntax.as_ref()) {
9-
(None, None) => return None,
10-
(Some(_), Some(_)) => unreachable!("A record cannot be both a literal and a pattern"),
11-
(Some(record_pat), _) => ctx.sema.record_pattern_missing_fields(record_pat),
12-
(_, Some(record_lit)) => {
13-
let ty = ctx.sema.type_of_expr(&Expr::RecordExpr(record_lit.clone()));
11+
let missing_fields = match &ctx.completion_location {
12+
Some(ImmediateLocation::RecordExpr(record_expr)) => {
13+
let ty = ctx.sema.type_of_expr(&Expr::RecordExpr(record_expr.clone()));
1414
let default_trait = FamousDefs(&ctx.sema, ctx.krate).core_default_Default();
1515
let impl_default_trait = default_trait
1616
.zip(ty)
1717
.map_or(false, |(default_trait, ty)| ty.impls_trait(ctx.db, default_trait, &[]));
1818

19-
let missing_fields = ctx.sema.record_literal_missing_fields(record_lit);
19+
let missing_fields = ctx.sema.record_literal_missing_fields(record_expr);
2020
if impl_default_trait && !missing_fields.is_empty() {
2121
let completion_text = "..Default::default()";
2222
let mut item = CompletionItem::new(
@@ -32,6 +32,10 @@ pub(crate) fn complete_record(acc: &mut Completions, ctx: &CompletionContext) ->
3232

3333
missing_fields
3434
}
35+
Some(ImmediateLocation::RecordPat(record_pat)) => {
36+
ctx.sema.record_pattern_missing_fields(record_pat)
37+
}
38+
_ => return None,
3539
};
3640

3741
for (field, ty) in missing_fields {

crates/ide_completion/src/context.rs

Lines changed: 35 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use text_edit::Indel;
1818
use crate::{
1919
patterns::{
2020
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,
2222
},
2323
CompletionConfig,
2424
};
@@ -54,11 +54,6 @@ pub(crate) struct CompletionContext<'a> {
5454
/// The parent impl of the cursor position if it exists.
5555
pub(super) impl_def: Option<ast::Impl>,
5656

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-
6257
// potentially set if we are completing a lifetime
6358
pub(super) lifetime_syntax: Option<ast::Lifetime>,
6459
pub(super) lifetime_param_syntax: Option<ast::LifetimeParam>,
@@ -71,6 +66,7 @@ pub(crate) struct CompletionContext<'a> {
7166

7267
pub(super) completion_location: Option<ImmediateLocation>,
7368
pub(super) prev_sibling: Option<ImmediatePrevSibling>,
69+
pub(super) attribute_under_caret: Option<ast::Attr>,
7470

7571
/// FIXME: `ActiveParameter` is string-based, which is very very wrong
7672
pub(super) active_parameter: Option<ActiveParameter>,
@@ -95,14 +91,10 @@ pub(crate) struct CompletionContext<'a> {
9591
pub(super) is_macro_call: bool,
9692
pub(super) is_path_type: bool,
9793
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>,
10094
pub(super) locals: Vec<(String, Local)>,
10195

102-
// keyword patterns
10396
pub(super) previous_token: Option<SyntaxToken>,
10497
pub(super) in_loop_body: bool,
105-
pub(super) is_match_arm: bool,
10698
pub(super) incomplete_let: bool,
10799

108100
no_completion_required: bool,
@@ -157,8 +149,6 @@ impl<'a> CompletionContext<'a> {
157149
lifetime_param_syntax: None,
158150
function_def: None,
159151
use_item_syntax: None,
160-
record_lit_syntax: None,
161-
record_pat_syntax: None,
162152
impl_def: None,
163153
active_parameter: ActiveParameter::at(db, position),
164154
is_label_ref: false,
@@ -176,15 +166,13 @@ impl<'a> CompletionContext<'a> {
176166
is_macro_call: false,
177167
is_path_type: false,
178168
has_type_args: false,
179-
attribute_under_caret: None,
180-
mod_declaration_under_caret: None,
181169
previous_token: None,
182170
in_loop_body: false,
183171
completion_location: None,
184172
prev_sibling: None,
185-
is_match_arm: false,
186173
no_completion_required: false,
187174
incomplete_let: false,
175+
attribute_under_caret: None,
188176
locals,
189177
};
190178

@@ -227,7 +215,6 @@ impl<'a> CompletionContext<'a> {
227215
break;
228216
}
229217
}
230-
ctx.fill_keyword_patterns(&speculative_file, offset);
231218
ctx.fill(&original_file, speculative_file, offset);
232219
Some(ctx)
233220
}
@@ -311,31 +298,13 @@ impl<'a> CompletionContext<'a> {
311298
}
312299

313300
pub(crate) fn is_path_disallowed(&self) -> bool {
314-
self.record_lit_syntax.is_some()
315-
|| self.record_pat_syntax.is_some()
316-
|| self.attribute_under_caret.is_some()
317-
|| self.mod_declaration_under_caret.is_some()
318-
}
319-
320-
fn fill_keyword_patterns(&mut self, file_with_fake_ident: &SyntaxNode, offset: TextSize) {
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;
301+
matches!(
302+
self.completion_location,
303+
Some(ImmediateLocation::Attribute(_))
304+
| Some(ImmediateLocation::ModDeclaration(_))
305+
| Some(ImmediateLocation::RecordPat(_))
306+
| Some(ImmediateLocation::RecordExpr(_))
307+
) || self.attribute_under_caret.is_some()
339308
}
340309

341310
fn fill_impl_def(&mut self) {
@@ -453,25 +422,43 @@ impl<'a> CompletionContext<'a> {
453422
file_with_fake_ident: SyntaxNode,
454423
offset: TextSize,
455424
) {
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+
456442
let (expected_type, expected_name) = self.expected_type_and_name();
457443
self.expected_type = expected_type;
458444
self.expected_name = expected_name;
459-
self.attribute_under_caret = find_node_at_offset(&file_with_fake_ident, offset);
445+
460446
let name_like = match find_node_at_offset(&&file_with_fake_ident, offset) {
461447
Some(it) => it,
462448
None => return,
463449
};
464-
self.completion_location = determine_location(&name_like);
450+
self.completion_location =
451+
determine_location(&self.sema, original_file, offset, &name_like);
465452
self.prev_sibling = determine_prev_sibling(&name_like);
466453
match name_like {
467454
ast::NameLike::Lifetime(lifetime) => {
468455
self.classify_lifetime(original_file, lifetime, offset);
469456
}
470457
ast::NameLike::NameRef(name_ref) => {
471-
self.classify_name_ref(original_file, name_ref, offset);
458+
self.classify_name_ref(original_file, name_ref);
472459
}
473460
ast::NameLike::Name(name) => {
474-
self.classify_name(original_file, name, offset);
461+
self.classify_name(name);
475462
}
476463
}
477464
}
@@ -505,7 +492,7 @@ impl<'a> CompletionContext<'a> {
505492
}
506493
}
507494

508-
fn classify_name(&mut self, original_file: &SyntaxNode, name: ast::Name, offset: TextSize) {
495+
fn classify_name(&mut self, name: ast::Name) {
509496
if let Some(bind_pat) = name.syntax().parent().and_then(ast::IdentPat::cast) {
510497
self.is_pat_or_const = Some(PatternRefutability::Refutable);
511498
// if any of these is here our bind pat can't be a const pat anymore
@@ -543,28 +530,12 @@ impl<'a> CompletionContext<'a> {
543530

544531
self.fill_impl_def();
545532
}
533+
546534
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-
}
551535
}
552536

553-
fn classify_name_ref(
554-
&mut self,
555-
original_file: &SyntaxNode,
556-
name_ref: ast::NameRef,
557-
offset: TextSize,
558-
) {
537+
fn classify_name_ref(&mut self, original_file: &SyntaxNode, name_ref: ast::NameRef) {
559538
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-
}
568539

569540
self.name_ref_syntax =
570541
find_node_at_offset(original_file, name_ref.syntax().text_range().start());

0 commit comments

Comments
 (0)