aboutsummaryrefslogtreecommitdiff
path: root/crates/ide_completion/src
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2021-05-27 02:22:28 +0100
committerGitHub <[email protected]>2021-05-27 02:22:28 +0100
commit12d46f835e5619f1731b3697c46065f4b737758c (patch)
treee8750a920f92bbbd4fe3cb23be585eed7ad92b24 /crates/ide_completion/src
parentd6ed315806e23d9ebda96ecfbe13da2154a2289c (diff)
parent6ec4ea8d9eb9ad6ad8b91968bde09121b5b791a0 (diff)
Merge #9018
9018: Collapse more CompletionContext booleans into enums r=Veykril a=Veykril bors r+ Co-authored-by: Lukas Wirth <[email protected]>
Diffstat (limited to 'crates/ide_completion/src')
-rw-r--r--crates/ide_completion/src/completions/flyimport.rs3
-rw-r--r--crates/ide_completion/src/completions/keyword.rs39
-rw-r--r--crates/ide_completion/src/completions/snippet.rs2
-rw-r--r--crates/ide_completion/src/completions/unqualified_path.rs3
-rw-r--r--crates/ide_completion/src/context.rs148
-rw-r--r--crates/ide_completion/src/patterns.rs58
6 files changed, 140 insertions, 113 deletions
diff --git a/crates/ide_completion/src/completions/flyimport.rs b/crates/ide_completion/src/completions/flyimport.rs
index 9d5b61562..b7d3ee8ce 100644
--- a/crates/ide_completion/src/completions/flyimport.rs
+++ b/crates/ide_completion/src/completions/flyimport.rs
@@ -114,8 +114,7 @@ pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext)
114 || ctx.attribute_under_caret.is_some() 114 || ctx.attribute_under_caret.is_some()
115 || ctx.mod_declaration_under_caret.is_some() 115 || ctx.mod_declaration_under_caret.is_some()
116 || ctx.record_lit_syntax.is_some() 116 || ctx.record_lit_syntax.is_some()
117 || ctx.has_trait_parent 117 || ctx.has_impl_or_trait_parent()
118 || ctx.has_impl_parent
119 { 118 {
120 return None; 119 return None;
121 } 120 }
diff --git a/crates/ide_completion/src/completions/keyword.rs b/crates/ide_completion/src/completions/keyword.rs
index fa6bcc955..58e35bad9 100644
--- a/crates/ide_completion/src/completions/keyword.rs
+++ b/crates/ide_completion/src/completions/keyword.rs
@@ -49,34 +49,35 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
49 return; 49 return;
50 } 50 }
51 51
52 let has_trait_or_impl_parent = ctx.has_impl_parent || ctx.has_trait_parent; 52 let has_trait_or_impl_parent = ctx.has_impl_or_trait_parent();
53 if ctx.trait_as_prev_sibling || ctx.impl_as_prev_sibling { 53 let has_block_expr_parent = ctx.has_block_expr_parent();
54 let has_item_list_parent = ctx.has_item_list_parent();
55 if ctx.has_impl_or_trait_prev_sibling() {
54 add_keyword(ctx, acc, "where", "where "); 56 add_keyword(ctx, acc, "where", "where ");
55 return; 57 return;
56 } 58 }
57 if ctx.previous_token_is(T![unsafe]) { 59 if ctx.previous_token_is(T![unsafe]) {
58 if ctx.has_item_list_or_source_file_parent || ctx.block_expr_parent { 60 if has_item_list_parent || has_block_expr_parent {
59 add_keyword(ctx, acc, "fn", "fn $1($2) {\n $0\n}") 61 add_keyword(ctx, acc, "fn", "fn $1($2) {\n $0\n}")
60 } 62 }
61 63
62 if (ctx.has_item_list_or_source_file_parent) || ctx.block_expr_parent { 64 if has_item_list_parent || has_block_expr_parent {
63 add_keyword(ctx, acc, "trait", "trait $1 {\n $0\n}"); 65 add_keyword(ctx, acc, "trait", "trait $1 {\n $0\n}");
64 add_keyword(ctx, acc, "impl", "impl $1 {\n $0\n}"); 66 add_keyword(ctx, acc, "impl", "impl $1 {\n $0\n}");
65 } 67 }
66 68
67 return; 69 return;
68 } 70 }
69 if ctx.has_item_list_or_source_file_parent || has_trait_or_impl_parent || ctx.block_expr_parent 71 if has_item_list_parent || has_trait_or_impl_parent || has_block_expr_parent {
70 {
71 add_keyword(ctx, acc, "fn", "fn $1($2) {\n $0\n}"); 72 add_keyword(ctx, acc, "fn", "fn $1($2) {\n $0\n}");
72 } 73 }
73 if (ctx.has_item_list_or_source_file_parent) || ctx.block_expr_parent { 74 if has_item_list_parent || has_block_expr_parent {
74 add_keyword(ctx, acc, "use", "use "); 75 add_keyword(ctx, acc, "use", "use ");
75 add_keyword(ctx, acc, "impl", "impl $1 {\n $0\n}"); 76 add_keyword(ctx, acc, "impl", "impl $1 {\n $0\n}");
76 add_keyword(ctx, acc, "trait", "trait $1 {\n $0\n}"); 77 add_keyword(ctx, acc, "trait", "trait $1 {\n $0\n}");
77 } 78 }
78 79
79 if ctx.has_item_list_or_source_file_parent { 80 if has_item_list_parent {
80 add_keyword(ctx, acc, "enum", "enum $1 {\n $0\n}"); 81 add_keyword(ctx, acc, "enum", "enum $1 {\n $0\n}");
81 add_keyword(ctx, acc, "struct", "struct $0"); 82 add_keyword(ctx, acc, "struct", "struct $0");
82 add_keyword(ctx, acc, "union", "union $1 {\n $0\n}"); 83 add_keyword(ctx, acc, "union", "union $1 {\n $0\n}");
@@ -92,7 +93,7 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
92 add_keyword(ctx, acc, "for", "for $1 in $2 {\n $0\n}"); 93 add_keyword(ctx, acc, "for", "for $1 in $2 {\n $0\n}");
93 } 94 }
94 95
95 if ctx.previous_token_is(T![if]) || ctx.previous_token_is(T![while]) || ctx.block_expr_parent { 96 if ctx.previous_token_is(T![if]) || ctx.previous_token_is(T![while]) || has_block_expr_parent {
96 add_keyword(ctx, acc, "let", "let "); 97 add_keyword(ctx, acc, "let", "let ");
97 } 98 }
98 99
@@ -100,27 +101,23 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
100 add_keyword(ctx, acc, "else", "else {\n $0\n}"); 101 add_keyword(ctx, acc, "else", "else {\n $0\n}");
101 add_keyword(ctx, acc, "else if", "else if $1 {\n $0\n}"); 102 add_keyword(ctx, acc, "else if", "else if $1 {\n $0\n}");
102 } 103 }
103 if (ctx.has_item_list_or_source_file_parent) || ctx.block_expr_parent { 104 if has_item_list_parent || has_block_expr_parent {
104 add_keyword(ctx, acc, "mod", "mod $0"); 105 add_keyword(ctx, acc, "mod", "mod $0");
105 } 106 }
106 if ctx.bind_pat_parent || ctx.ref_pat_parent { 107 if ctx.has_ident_or_ref_pat_parent() {
107 add_keyword(ctx, acc, "mut", "mut "); 108 add_keyword(ctx, acc, "mut", "mut ");
108 } 109 }
109 if ctx.has_item_list_or_source_file_parent || has_trait_or_impl_parent || ctx.block_expr_parent 110 if has_item_list_parent || has_trait_or_impl_parent || has_block_expr_parent {
110 {
111 add_keyword(ctx, acc, "const", "const "); 111 add_keyword(ctx, acc, "const", "const ");
112 add_keyword(ctx, acc, "type", "type "); 112 add_keyword(ctx, acc, "type", "type ");
113 } 113 }
114 if (ctx.has_item_list_or_source_file_parent) || ctx.block_expr_parent { 114 if has_item_list_parent || has_block_expr_parent {
115 add_keyword(ctx, acc, "static", "static "); 115 add_keyword(ctx, acc, "static", "static ");
116 }; 116 };
117 if (ctx.has_item_list_or_source_file_parent) || ctx.block_expr_parent { 117 if has_item_list_parent || has_block_expr_parent {
118 add_keyword(ctx, acc, "extern", "extern "); 118 add_keyword(ctx, acc, "extern", "extern ");
119 } 119 }
120 if ctx.has_item_list_or_source_file_parent 120 if has_item_list_parent || has_trait_or_impl_parent || has_block_expr_parent || ctx.is_match_arm
121 || has_trait_or_impl_parent
122 || ctx.block_expr_parent
123 || ctx.is_match_arm
124 { 121 {
125 add_keyword(ctx, acc, "unsafe", "unsafe "); 122 add_keyword(ctx, acc, "unsafe", "unsafe ");
126 } 123 }
@@ -133,7 +130,7 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
133 add_keyword(ctx, acc, "break", "break"); 130 add_keyword(ctx, acc, "break", "break");
134 } 131 }
135 } 132 }
136 if ctx.has_item_list_or_source_file_parent || ctx.has_impl_parent | ctx.has_field_list_parent { 133 if has_item_list_parent || ctx.has_impl_parent() || ctx.has_field_list_parent() {
137 add_keyword(ctx, acc, "pub(crate)", "pub(crate) "); 134 add_keyword(ctx, acc, "pub(crate)", "pub(crate) ");
138 add_keyword(ctx, acc, "pub", "pub "); 135 add_keyword(ctx, acc, "pub", "pub ");
139 } 136 }
@@ -141,7 +138,7 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
141 if !ctx.is_trivial_path { 138 if !ctx.is_trivial_path {
142 return; 139 return;
143 } 140 }
144 let fn_def = match &ctx.function_syntax { 141 let fn_def = match &ctx.function_def {
145 Some(it) => it, 142 Some(it) => it,
146 None => return, 143 None => return,
147 }; 144 };
diff --git a/crates/ide_completion/src/completions/snippet.rs b/crates/ide_completion/src/completions/snippet.rs
index 14cfb61de..defc25b00 100644
--- a/crates/ide_completion/src/completions/snippet.rs
+++ b/crates/ide_completion/src/completions/snippet.rs
@@ -14,7 +14,7 @@ fn snippet(ctx: &CompletionContext, cap: SnippetCap, label: &str, snippet: &str)
14} 14}
15 15
16pub(crate) fn complete_expr_snippet(acc: &mut Completions, ctx: &CompletionContext) { 16pub(crate) fn complete_expr_snippet(acc: &mut Completions, ctx: &CompletionContext) {
17 if !(ctx.is_trivial_path && ctx.function_syntax.is_some()) { 17 if !(ctx.is_trivial_path && ctx.function_def.is_some()) {
18 return; 18 return;
19 } 19 }
20 let cap = match ctx.config.snippet_cap { 20 let cap = match ctx.config.snippet_cap {
diff --git a/crates/ide_completion/src/completions/unqualified_path.rs b/crates/ide_completion/src/completions/unqualified_path.rs
index b8f8ef25f..7496d26c4 100644
--- a/crates/ide_completion/src/completions/unqualified_path.rs
+++ b/crates/ide_completion/src/completions/unqualified_path.rs
@@ -13,8 +13,7 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC
13 || ctx.record_pat_syntax.is_some() 13 || ctx.record_pat_syntax.is_some()
14 || ctx.attribute_under_caret.is_some() 14 || ctx.attribute_under_caret.is_some()
15 || ctx.mod_declaration_under_caret.is_some() 15 || ctx.mod_declaration_under_caret.is_some()
16 || ctx.has_impl_parent 16 || ctx.has_impl_or_trait_parent()
17 || ctx.has_trait_parent
18 { 17 {
19 return; 18 return;
20 } 19 }
diff --git a/crates/ide_completion/src/context.rs b/crates/ide_completion/src/context.rs
index 6dc6769df..5d15fde2f 100644
--- a/crates/ide_completion/src/context.rs
+++ b/crates/ide_completion/src/context.rs
@@ -18,9 +18,8 @@ use text_edit::Indel;
18use crate::{ 18use crate::{
19 patterns::{ 19 patterns::{
20 for_is_prev2, has_bind_pat_parent, has_block_expr_parent, has_field_list_parent, 20 for_is_prev2, has_bind_pat_parent, has_block_expr_parent, has_field_list_parent,
21 has_impl_as_prev_sibling, has_impl_parent, has_item_list_or_source_file_parent, 21 has_impl_parent, has_item_list_or_source_file_parent, has_prev_sibling, has_ref_parent,
22 has_ref_parent, has_trait_as_prev_sibling, has_trait_parent, inside_impl_trait_block, 22 has_trait_parent, inside_impl_trait_block, is_in_loop_body, is_match_arm, previous_token,
23 is_in_loop_body, is_match_arm, previous_token,
24 }, 23 },
25 CompletionConfig, 24 CompletionConfig,
26}; 25};
@@ -31,6 +30,24 @@ pub(crate) enum PatternRefutability {
31 Irrefutable, 30 Irrefutable,
32} 31}
33 32
33/// Direct parent container of the cursor position
34#[derive(Copy, Clone, Debug, PartialEq, Eq)]
35pub(crate) enum ImmediateLocation {
36 Impl,
37 Trait,
38 RecordFieldList,
39 RefPatOrExpr,
40 IdentPat,
41 BlockExpr,
42 ItemList,
43}
44
45#[derive(Copy, Clone, Debug, PartialEq, Eq)]
46pub(crate) enum PrevSibling {
47 Trait,
48 Impl,
49}
50
34/// `CompletionContext` is created early during completion to figure out, where 51/// `CompletionContext` is created early during completion to figure out, where
35/// exactly is the cursor, syntax-wise. 52/// exactly is the cursor, syntax-wise.
36#[derive(Debug)] 53#[derive(Debug)]
@@ -48,14 +65,19 @@ pub(crate) struct CompletionContext<'a> {
48 pub(super) expected_name: Option<NameOrNameRef>, 65 pub(super) expected_name: Option<NameOrNameRef>,
49 pub(super) expected_type: Option<Type>, 66 pub(super) expected_type: Option<Type>,
50 pub(super) name_ref_syntax: Option<ast::NameRef>, 67 pub(super) name_ref_syntax: Option<ast::NameRef>,
51 pub(super) function_syntax: Option<ast::Fn>, 68
52 pub(super) use_item_syntax: Option<ast::Use>, 69 pub(super) use_item_syntax: Option<ast::Use>,
53 pub(super) record_lit_syntax: Option<ast::RecordExpr>, 70
54 pub(super) record_pat_syntax: Option<ast::RecordPat>, 71 /// The parent function of the cursor position if it exists.
55 pub(super) record_field_syntax: Option<ast::RecordExprField>, 72 pub(super) function_def: Option<ast::Fn>,
56 /// The parent impl of the cursor position if it exists. 73 /// The parent impl of the cursor position if it exists.
57 pub(super) impl_def: Option<ast::Impl>, 74 pub(super) impl_def: Option<ast::Impl>,
58 75
76 /// RecordExpr the token is a field of
77 pub(super) record_lit_syntax: Option<ast::RecordExpr>,
78 /// RecordPat the token is a field of
79 pub(super) record_pat_syntax: Option<ast::RecordPat>,
80
59 // potentially set if we are completing a lifetime 81 // potentially set if we are completing a lifetime
60 pub(super) lifetime_syntax: Option<ast::Lifetime>, 82 pub(super) lifetime_syntax: Option<ast::Lifetime>,
61 pub(super) lifetime_param_syntax: Option<ast::LifetimeParam>, 83 pub(super) lifetime_param_syntax: Option<ast::LifetimeParam>,
@@ -66,6 +88,8 @@ pub(crate) struct CompletionContext<'a> {
66 pub(super) is_pat_or_const: Option<PatternRefutability>, 88 pub(super) is_pat_or_const: Option<PatternRefutability>,
67 pub(super) is_param: bool, 89 pub(super) is_param: bool,
68 90
91 pub(super) completion_location: Option<ImmediateLocation>,
92
69 /// FIXME: `ActiveParameter` is string-based, which is very very wrong 93 /// FIXME: `ActiveParameter` is string-based, which is very very wrong
70 pub(super) active_parameter: Option<ActiveParameter>, 94 pub(super) active_parameter: Option<ActiveParameter>,
71 /// A single-indent path, like `foo`. `::foo` should not be considered a trivial path. 95 /// A single-indent path, like `foo`. `::foo` should not be considered a trivial path.
@@ -94,20 +118,12 @@ pub(crate) struct CompletionContext<'a> {
94 pub(super) locals: Vec<(String, Local)>, 118 pub(super) locals: Vec<(String, Local)>,
95 119
96 pub(super) mod_declaration_under_caret: Option<ast::Module>, 120 pub(super) mod_declaration_under_caret: Option<ast::Module>,
97 pub(super) has_trait_parent: bool,
98 pub(super) has_impl_parent: bool,
99 121
100 // keyword patterns 122 // keyword patterns
101 pub(super) previous_token: Option<SyntaxToken>, 123 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, 124 pub(super) in_loop_body: bool,
106 pub(super) has_field_list_parent: bool, 125 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, 126 pub(super) is_match_arm: bool,
110 pub(super) has_item_list_or_source_file_parent: bool,
111 pub(super) incomplete_let: bool, 127 pub(super) incomplete_let: bool,
112 128
113 no_completion_required: bool, 129 no_completion_required: bool,
@@ -159,11 +175,10 @@ impl<'a> CompletionContext<'a> {
159 name_ref_syntax: None, 175 name_ref_syntax: None,
160 lifetime_syntax: None, 176 lifetime_syntax: None,
161 lifetime_param_syntax: None, 177 lifetime_param_syntax: None,
162 function_syntax: None, 178 function_def: None,
163 use_item_syntax: None, 179 use_item_syntax: None,
164 record_lit_syntax: None, 180 record_lit_syntax: None,
165 record_pat_syntax: None, 181 record_pat_syntax: None,
166 record_field_syntax: None,
167 impl_def: None, 182 impl_def: None,
168 active_parameter: ActiveParameter::at(db, position), 183 active_parameter: ActiveParameter::at(db, position),
169 is_label_ref: false, 184 is_label_ref: false,
@@ -185,17 +200,10 @@ impl<'a> CompletionContext<'a> {
185 attribute_under_caret: None, 200 attribute_under_caret: None,
186 mod_declaration_under_caret: None, 201 mod_declaration_under_caret: None,
187 previous_token: None, 202 previous_token: None,
188 block_expr_parent: false,
189 bind_pat_parent: false,
190 ref_pat_parent: false,
191 in_loop_body: false, 203 in_loop_body: false,
192 has_trait_parent: false, 204 completion_location: None,
193 has_impl_parent: false, 205 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, 206 is_match_arm: false,
198 has_item_list_or_source_file_parent: false,
199 no_completion_required: false, 207 no_completion_required: false,
200 incomplete_let: false, 208 incomplete_let: false,
201 locals, 209 locals,
@@ -274,23 +282,68 @@ impl<'a> CompletionContext<'a> {
274 self.previous_token.as_ref().map_or(false, |tok| tok.kind() == kind) 282 self.previous_token.as_ref().map_or(false, |tok| tok.kind() == kind)
275 } 283 }
276 284
285 pub(crate) fn has_impl_or_trait_parent(&self) -> bool {
286 matches!(
287 self.completion_location,
288 Some(ImmediateLocation::Trait) | Some(ImmediateLocation::Impl)
289 )
290 }
291
292 pub(crate) fn has_block_expr_parent(&self) -> bool {
293 matches!(self.completion_location, Some(ImmediateLocation::BlockExpr))
294 }
295
296 pub(crate) fn has_item_list_parent(&self) -> bool {
297 matches!(self.completion_location, Some(ImmediateLocation::ItemList))
298 }
299
300 pub(crate) fn has_ident_or_ref_pat_parent(&self) -> bool {
301 matches!(
302 self.completion_location,
303 Some(ImmediateLocation::IdentPat) | Some(ImmediateLocation::RefPatOrExpr)
304 )
305 }
306
307 pub(crate) fn has_impl_parent(&self) -> bool {
308 matches!(self.completion_location, Some(ImmediateLocation::Impl))
309 }
310
311 pub(crate) fn has_field_list_parent(&self) -> bool {
312 matches!(self.completion_location, Some(ImmediateLocation::RecordFieldList))
313 }
314
315 pub(crate) fn has_impl_or_trait_prev_sibling(&self) -> bool {
316 self.prev_sibling.is_some()
317 }
318
277 fn fill_keyword_patterns(&mut self, file_with_fake_ident: &SyntaxNode, offset: TextSize) { 319 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(); 320 let fake_ident_token = file_with_fake_ident.token_at_offset(offset).right_biased().unwrap();
279 let syntax_element = NodeOrToken::Token(fake_ident_token); 321 let syntax_element = NodeOrToken::Token(fake_ident_token);
280 self.previous_token = previous_token(syntax_element.clone()); 322 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()); 323 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()); 324 self.is_match_arm = is_match_arm(syntax_element.clone());
325 if has_prev_sibling(syntax_element.clone(), IMPL) {
326 self.prev_sibling = Some(PrevSibling::Impl)
327 } else if has_prev_sibling(syntax_element.clone(), TRAIT) {
328 self.prev_sibling = Some(PrevSibling::Trait)
329 }
330
331 if has_block_expr_parent(syntax_element.clone()) {
332 self.completion_location = Some(ImmediateLocation::BlockExpr);
333 } else if has_bind_pat_parent(syntax_element.clone()) {
334 self.completion_location = Some(ImmediateLocation::IdentPat);
335 } else if has_ref_parent(syntax_element.clone()) {
336 self.completion_location = Some(ImmediateLocation::RefPatOrExpr);
337 } else if has_impl_parent(syntax_element.clone()) {
338 self.completion_location = Some(ImmediateLocation::Impl);
339 } else if has_field_list_parent(syntax_element.clone()) {
340 self.completion_location = Some(ImmediateLocation::RecordFieldList);
341 } else if has_trait_parent(syntax_element.clone()) {
342 self.completion_location = Some(ImmediateLocation::Trait);
343 } else if has_item_list_or_source_file_parent(syntax_element.clone()) {
344 self.completion_location = Some(ImmediateLocation::ItemList);
345 }
291 346
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 = 347 self.mod_declaration_under_caret =
295 find_node_at_offset::<ast::Module>(&file_with_fake_ident, offset) 348 find_node_at_offset::<ast::Module>(&file_with_fake_ident, offset)
296 .filter(|module| module.item_list().is_none()); 349 .filter(|module| module.item_list().is_none());
@@ -542,31 +595,20 @@ impl<'a> CompletionContext<'a> {
542 .last() 595 .last()
543 .unwrap(); 596 .unwrap();
544 597
545 match top_node.parent().map(|it| it.kind()) { 598 if matches!(top_node.parent().map(|it| it.kind()), Some(SOURCE_FILE) | Some(ITEM_LIST)) {
546 Some(SOURCE_FILE) | Some(ITEM_LIST) => { 599 self.is_new_item = true;
547 self.is_new_item = true; 600 return;
548 return;
549 }
550 _ => (),
551 } 601 }
552 602
553 self.use_item_syntax = 603 self.use_item_syntax =
554 self.sema.token_ancestors_with_macros(self.token.clone()).find_map(ast::Use::cast); 604 self.sema.token_ancestors_with_macros(self.token.clone()).find_map(ast::Use::cast);
555 605
556 self.function_syntax = self 606 self.function_def = self
557 .sema 607 .sema
558 .token_ancestors_with_macros(self.token.clone()) 608 .token_ancestors_with_macros(self.token.clone())
559 .take_while(|it| it.kind() != SOURCE_FILE && it.kind() != MODULE) 609 .take_while(|it| it.kind() != SOURCE_FILE && it.kind() != MODULE)
560 .find_map(ast::Fn::cast); 610 .find_map(ast::Fn::cast);
561 611
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() { 612 let parent = match name_ref.syntax().parent() {
571 Some(it) => it, 613 Some(it) => it,
572 None => return, 614 None => return,
@@ -639,6 +681,7 @@ impl<'a> CompletionContext<'a> {
639 } 681 }
640 } 682 }
641 } 683 }
684
642 if let Some(field_expr) = ast::FieldExpr::cast(parent.clone()) { 685 if let Some(field_expr) = ast::FieldExpr::cast(parent.clone()) {
643 // The receiver comes before the point of insertion of the fake 686 // 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 687 // ident, so it should have the same range in the non-modified file
@@ -656,6 +699,7 @@ impl<'a> CompletionContext<'a> {
656 false 699 false
657 }; 700 };
658 } 701 }
702
659 if let Some(method_call_expr) = ast::MethodCallExpr::cast(parent) { 703 if let Some(method_call_expr) = ast::MethodCallExpr::cast(parent) {
660 // As above 704 // As above
661 self.dot_receiver = method_call_expr 705 self.dot_receiver = method_call_expr
diff --git a/crates/ide_completion/src/patterns.rs b/crates/ide_completion/src/patterns.rs
index 3d8a83ed8..04f2c532b 100644
--- a/crates/ide_completion/src/patterns.rs
+++ b/crates/ide_completion/src/patterns.rs
@@ -4,7 +4,7 @@ use syntax::{
4 algo::non_trivia_sibling, 4 algo::non_trivia_sibling,
5 ast::{self, LoopBodyOwner}, 5 ast::{self, LoopBodyOwner},
6 match_ast, AstNode, Direction, NodeOrToken, SyntaxElement, 6 match_ast, AstNode, Direction, NodeOrToken, SyntaxElement,
7 SyntaxKind::*, 7 SyntaxKind::{self, *},
8 SyntaxNode, SyntaxToken, T, 8 SyntaxNode, SyntaxToken, T,
9}; 9};
10 10
@@ -73,6 +73,7 @@ fn test_has_block_expr_parent() {
73pub(crate) fn has_bind_pat_parent(element: SyntaxElement) -> bool { 73pub(crate) fn has_bind_pat_parent(element: SyntaxElement) -> bool {
74 element.ancestors().any(|it| it.kind() == IDENT_PAT) 74 element.ancestors().any(|it| it.kind() == IDENT_PAT)
75} 75}
76
76#[test] 77#[test]
77fn test_has_bind_pat_parent() { 78fn test_has_bind_pat_parent() {
78 check_pattern_is_applicable(r"fn my_fn(m$0) {}", has_bind_pat_parent); 79 check_pattern_is_applicable(r"fn my_fn(m$0) {}", has_bind_pat_parent);
@@ -91,11 +92,10 @@ fn test_has_ref_parent() {
91} 92}
92 93
93pub(crate) fn has_item_list_or_source_file_parent(element: SyntaxElement) -> bool { 94pub(crate) fn has_item_list_or_source_file_parent(element: SyntaxElement) -> bool {
94 let ancestor = not_same_range_ancestor(element); 95 match not_same_range_ancestor(element) {
95 if !ancestor.is_some() { 96 Some(it) => it.kind() == SOURCE_FILE || it.kind() == ITEM_LIST,
96 return true; 97 None => true,
97 } 98 }
98 ancestor.filter(|it| it.kind() == SOURCE_FILE || it.kind() == ITEM_LIST).is_some()
99} 99}
100#[test] 100#[test]
101fn test_has_item_list_or_source_file_parent() { 101fn test_has_item_list_or_source_file_parent() {
@@ -134,42 +134,30 @@ fn test_for_is_prev2() {
134 check_pattern_is_applicable(r"for i i$0", for_is_prev2); 134 check_pattern_is_applicable(r"for i i$0", for_is_prev2);
135} 135}
136 136
137pub(crate) fn has_trait_as_prev_sibling(element: SyntaxElement) -> bool { 137pub(crate) fn has_prev_sibling(element: SyntaxElement, kind: SyntaxKind) -> bool {
138 previous_sibling_or_ancestor_sibling(element).filter(|it| it.kind() == TRAIT).is_some() 138 previous_sibling_or_ancestor_sibling(element).filter(|it| it.kind() == kind).is_some()
139}
140#[test]
141fn test_has_trait_as_prev_sibling() {
142 check_pattern_is_applicable(r"trait A w$0 {}", has_trait_as_prev_sibling);
143}
144
145pub(crate) fn has_impl_as_prev_sibling(element: SyntaxElement) -> bool {
146 previous_sibling_or_ancestor_sibling(element).filter(|it| it.kind() == IMPL).is_some()
147} 139}
148#[test] 140#[test]
149fn test_has_impl_as_prev_sibling() { 141fn test_has_impl_as_prev_sibling() {
150 check_pattern_is_applicable(r"impl A w$0 {}", has_impl_as_prev_sibling); 142 check_pattern_is_applicable(r"impl A w$0 {}", |it| has_prev_sibling(it, IMPL));
151} 143}
152 144
153pub(crate) fn is_in_loop_body(element: SyntaxElement) -> bool { 145pub(crate) fn is_in_loop_body(element: SyntaxElement) -> bool {
154 for node in element.ancestors() { 146 element
155 if node.kind() == FN || node.kind() == CLOSURE_EXPR { 147 .ancestors()
156 break; 148 .take_while(|it| it.kind() != FN && it.kind() != CLOSURE_EXPR)
157 } 149 .find_map(|it| {
158 let loop_body = match_ast! { 150 let loop_body = match_ast! {
159 match node { 151 match it {
160 ast::ForExpr(it) => it.loop_body(), 152 ast::ForExpr(it) => it.loop_body(),
161 ast::WhileExpr(it) => it.loop_body(), 153 ast::WhileExpr(it) => it.loop_body(),
162 ast::LoopExpr(it) => it.loop_body(), 154 ast::LoopExpr(it) => it.loop_body(),
163 _ => None, 155 _ => None,
164 } 156 }
165 }; 157 };
166 if let Some(body) = loop_body { 158 loop_body.filter(|it| it.syntax().text_range().contains_range(element.text_range()))
167 if body.syntax().text_range().contains_range(element.text_range()) { 159 })
168 return true; 160 .is_some()
169 }
170 }
171 }
172 false
173} 161}
174 162
175fn not_same_range_ancestor(element: SyntaxElement) -> Option<SyntaxNode> { 163fn not_same_range_ancestor(element: SyntaxElement) -> Option<SyntaxNode> {