diff options
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ide_completion/src/completions/flyimport.rs | 3 | ||||
-rw-r--r-- | crates/ide_completion/src/completions/keyword.rs | 39 | ||||
-rw-r--r-- | crates/ide_completion/src/completions/snippet.rs | 2 | ||||
-rw-r--r-- | crates/ide_completion/src/completions/unqualified_path.rs | 3 | ||||
-rw-r--r-- | crates/ide_completion/src/context.rs | 148 | ||||
-rw-r--r-- | crates/ide_completion/src/patterns.rs | 58 |
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 | ||
16 | pub(crate) fn complete_expr_snippet(acc: &mut Completions, ctx: &CompletionContext) { | 16 | pub(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; | |||
18 | use crate::{ | 18 | use 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)] | ||
35 | pub(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)] | ||
46 | pub(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() { | |||
73 | pub(crate) fn has_bind_pat_parent(element: SyntaxElement) -> bool { | 73 | pub(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] |
77 | fn test_has_bind_pat_parent() { | 78 | fn 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 | ||
93 | pub(crate) fn has_item_list_or_source_file_parent(element: SyntaxElement) -> bool { | 94 | pub(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] |
101 | fn test_has_item_list_or_source_file_parent() { | 101 | fn 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 | ||
137 | pub(crate) fn has_trait_as_prev_sibling(element: SyntaxElement) -> bool { | 137 | pub(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] | ||
141 | fn test_has_trait_as_prev_sibling() { | ||
142 | check_pattern_is_applicable(r"trait A w$0 {}", has_trait_as_prev_sibling); | ||
143 | } | ||
144 | |||
145 | pub(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] |
149 | fn test_has_impl_as_prev_sibling() { | 141 | fn 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 | ||
153 | pub(crate) fn is_in_loop_body(element: SyntaxElement) -> bool { | 145 | pub(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 | ||
175 | fn not_same_range_ancestor(element: SyntaxElement) -> Option<SyntaxNode> { | 163 | fn not_same_range_ancestor(element: SyntaxElement) -> Option<SyntaxNode> { |