aboutsummaryrefslogtreecommitdiff
path: root/crates/ide_completion/src/completions/keyword.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide_completion/src/completions/keyword.rs')
-rw-r--r--crates/ide_completion/src/completions/keyword.rs220
1 files changed, 117 insertions, 103 deletions
diff --git a/crates/ide_completion/src/completions/keyword.rs b/crates/ide_completion/src/completions/keyword.rs
index 58e35bad9..0d035c611 100644
--- a/crates/ide_completion/src/completions/keyword.rs
+++ b/crates/ide_completion/src/completions/keyword.rs
@@ -4,7 +4,10 @@ use std::iter;
4 4
5use syntax::{SyntaxKind, T}; 5use syntax::{SyntaxKind, T};
6 6
7use crate::{CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions}; 7use crate::{
8 patterns::ImmediateLocation, CompletionContext, CompletionItem, CompletionItemKind,
9 CompletionKind, Completions,
10};
8 11
9pub(crate) fn complete_use_tree_keyword(acc: &mut Completions, ctx: &CompletionContext) { 12pub(crate) fn complete_use_tree_keyword(acc: &mut Completions, ctx: &CompletionContext) {
10 // complete keyword "crate" in use stmt 13 // complete keyword "crate" in use stmt
@@ -44,96 +47,95 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
44 cov_mark::hit!(no_keyword_completion_in_comments); 47 cov_mark::hit!(no_keyword_completion_in_comments);
45 return; 48 return;
46 } 49 }
47 if ctx.record_lit_syntax.is_some() { 50 if matches!(ctx.completion_location, Some(ImmediateLocation::RecordExpr(_))) {
48 cov_mark::hit!(no_keyword_completion_in_record_lit); 51 cov_mark::hit!(no_keyword_completion_in_record_lit);
49 return; 52 return;
50 } 53 }
54 let mut add_keyword = |kw, snippet| add_keyword(ctx, acc, kw, snippet);
51 55
52 let has_trait_or_impl_parent = ctx.has_impl_or_trait_parent(); 56 let expects_assoc_item = ctx.expects_assoc_item();
53 let has_block_expr_parent = ctx.has_block_expr_parent(); 57 let has_block_expr_parent = ctx.has_block_expr_parent();
54 let has_item_list_parent = ctx.has_item_list_parent(); 58 let expects_item = ctx.expects_item();
59
55 if ctx.has_impl_or_trait_prev_sibling() { 60 if ctx.has_impl_or_trait_prev_sibling() {
56 add_keyword(ctx, acc, "where", "where "); 61 add_keyword("where", "where ");
57 return; 62 return;
58 } 63 }
59 if ctx.previous_token_is(T![unsafe]) { 64 if ctx.previous_token_is(T![unsafe]) {
60 if has_item_list_parent || has_block_expr_parent { 65 if expects_item || expects_assoc_item || has_block_expr_parent {
61 add_keyword(ctx, acc, "fn", "fn $1($2) {\n $0\n}") 66 add_keyword("fn", "fn $1($2) {\n $0\n}")
62 } 67 }
63 68
64 if has_item_list_parent || has_block_expr_parent { 69 if expects_item || has_block_expr_parent {
65 add_keyword(ctx, acc, "trait", "trait $1 {\n $0\n}"); 70 add_keyword("trait", "trait $1 {\n $0\n}");
66 add_keyword(ctx, acc, "impl", "impl $1 {\n $0\n}"); 71 add_keyword("impl", "impl $1 {\n $0\n}");
67 } 72 }
68 73
69 return; 74 return;
70 } 75 }
71 if has_item_list_parent || has_trait_or_impl_parent || has_block_expr_parent {
72 add_keyword(ctx, acc, "fn", "fn $1($2) {\n $0\n}");
73 }
74 if has_item_list_parent || has_block_expr_parent {
75 add_keyword(ctx, acc, "use", "use ");
76 add_keyword(ctx, acc, "impl", "impl $1 {\n $0\n}");
77 add_keyword(ctx, acc, "trait", "trait $1 {\n $0\n}");
78 }
79 76
80 if has_item_list_parent { 77 if expects_item || ctx.expects_non_trait_assoc_item() || ctx.expect_record_field() {
81 add_keyword(ctx, acc, "enum", "enum $1 {\n $0\n}"); 78 add_keyword("pub(crate)", "pub(crate) ");
82 add_keyword(ctx, acc, "struct", "struct $0"); 79 add_keyword("pub", "pub ");
83 add_keyword(ctx, acc, "union", "union $1 {\n $0\n}");
84 } 80 }
85 81
86 if ctx.is_expr { 82 if expects_item || expects_assoc_item || has_block_expr_parent {
87 add_keyword(ctx, acc, "match", "match $1 {\n $0\n}"); 83 add_keyword("unsafe", "unsafe ");
88 add_keyword(ctx, acc, "while", "while $1 {\n $0\n}"); 84 add_keyword("fn", "fn $1($2) {\n $0\n}");
89 add_keyword(ctx, acc, "while let", "while let $1 = $2 {\n $0\n}"); 85 add_keyword("const", "const $0");
90 add_keyword(ctx, acc, "loop", "loop {\n $0\n}"); 86 add_keyword("type", "type $0");
91 add_keyword(ctx, acc, "if", "if $1 {\n $0\n}");
92 add_keyword(ctx, acc, "if let", "if let $1 = $2 {\n $0\n}");
93 add_keyword(ctx, acc, "for", "for $1 in $2 {\n $0\n}");
94 } 87 }
95 88
96 if ctx.previous_token_is(T![if]) || ctx.previous_token_is(T![while]) || has_block_expr_parent { 89 if expects_item || has_block_expr_parent {
97 add_keyword(ctx, acc, "let", "let "); 90 add_keyword("use", "use $0");
91 add_keyword("impl", "impl $1 {\n $0\n}");
92 add_keyword("trait", "trait $1 {\n $0\n}");
93 add_keyword("static", "static $0");
94 add_keyword("extern", "extern $0");
95 add_keyword("mod", "mod $0");
98 } 96 }
99 97
100 if ctx.after_if { 98 if expects_item {
101 add_keyword(ctx, acc, "else", "else {\n $0\n}"); 99 add_keyword("enum", "enum $1 {\n $0\n}");
102 add_keyword(ctx, acc, "else if", "else if $1 {\n $0\n}"); 100 add_keyword("struct", "struct $0");
103 } 101 add_keyword("union", "union $1 {\n $0\n}");
104 if has_item_list_parent || has_block_expr_parent {
105 add_keyword(ctx, acc, "mod", "mod $0");
106 } 102 }
107 if ctx.has_ident_or_ref_pat_parent() { 103
108 add_keyword(ctx, acc, "mut", "mut "); 104 if ctx.expects_expression() {
105 if !has_block_expr_parent {
106 add_keyword("unsafe", "unsafe {\n $0\n}");
107 }
108 add_keyword("match", "match $1 {\n $0\n}");
109 add_keyword("while", "while $1 {\n $0\n}");
110 add_keyword("while let", "while let $1 = $2 {\n $0\n}");
111 add_keyword("loop", "loop {\n $0\n}");
112 add_keyword("if", "if $1 {\n $0\n}");
113 add_keyword("if let", "if let $1 = $2 {\n $0\n}");
114 add_keyword("for", "for $1 in $2 {\n $0\n}");
109 } 115 }
110 if has_item_list_parent || has_trait_or_impl_parent || has_block_expr_parent { 116
111 add_keyword(ctx, acc, "const", "const "); 117 if ctx.previous_token_is(T![if]) || ctx.previous_token_is(T![while]) || has_block_expr_parent {
112 add_keyword(ctx, acc, "type", "type "); 118 add_keyword("let", "let ");
113 } 119 }
114 if has_item_list_parent || has_block_expr_parent { 120
115 add_keyword(ctx, acc, "static", "static "); 121 if ctx.after_if() {
116 }; 122 add_keyword("else", "else {\n $0\n}");
117 if has_item_list_parent || has_block_expr_parent { 123 add_keyword("else if", "else if $1 {\n $0\n}");
118 add_keyword(ctx, acc, "extern", "extern ");
119 } 124 }
120 if has_item_list_parent || has_trait_or_impl_parent || has_block_expr_parent || ctx.is_match_arm 125
121 { 126 if ctx.expects_ident_pat_or_ref_expr() {
122 add_keyword(ctx, acc, "unsafe", "unsafe "); 127 add_keyword("mut", "mut ");
123 } 128 }
129
124 if ctx.in_loop_body { 130 if ctx.in_loop_body {
125 if ctx.can_be_stmt { 131 if ctx.can_be_stmt {
126 add_keyword(ctx, acc, "continue", "continue;"); 132 add_keyword("continue", "continue;");
127 add_keyword(ctx, acc, "break", "break;"); 133 add_keyword("break", "break;");
128 } else { 134 } else {
129 add_keyword(ctx, acc, "continue", "continue"); 135 add_keyword("continue", "continue");
130 add_keyword(ctx, acc, "break", "break"); 136 add_keyword("break", "break");
131 } 137 }
132 } 138 }
133 if has_item_list_parent || ctx.has_impl_parent() || ctx.has_field_list_parent() {
134 add_keyword(ctx, acc, "pub(crate)", "pub(crate) ");
135 add_keyword(ctx, acc, "pub", "pub ");
136 }
137 139
138 if !ctx.is_trivial_path { 140 if !ctx.is_trivial_path {
139 return; 141 return;
@@ -144,8 +146,6 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
144 }; 146 };
145 147
146 add_keyword( 148 add_keyword(
147 ctx,
148 acc,
149 "return", 149 "return",
150 match (ctx.can_be_stmt, fn_def.ret_type().is_some()) { 150 match (ctx.can_be_stmt, fn_def.ret_type().is_some()) {
151 (true, true) => "return $0;", 151 (true, true) => "return $0;",
@@ -162,15 +162,12 @@ fn add_keyword(ctx: &CompletionContext, acc: &mut Completions, kw: &str, snippet
162 162
163 match ctx.config.snippet_cap { 163 match ctx.config.snippet_cap {
164 Some(cap) => { 164 Some(cap) => {
165 let tmp; 165 if snippet.ends_with('}') && ctx.incomplete_let {
166 let snippet = if snippet.ends_with('}') && ctx.incomplete_let {
167 cov_mark::hit!(let_semi); 166 cov_mark::hit!(let_semi);
168 tmp = format!("{};", snippet); 167 item.insert_snippet(cap, format!("{};", snippet));
169 &tmp
170 } else { 168 } else {
171 snippet 169 item.insert_snippet(cap, snippet);
172 }; 170 }
173 item.insert_snippet(cap, snippet);
174 } 171 }
175 None => { 172 None => {
176 item.insert_text(if snippet.contains('$') { kw } else { snippet }); 173 item.insert_text(if snippet.contains('$') { kw } else { snippet });
@@ -233,21 +230,21 @@ mod tests {
233 check( 230 check(
234 r"m$0", 231 r"m$0",
235 expect![[r#" 232 expect![[r#"
233 kw pub(crate)
234 kw pub
235 kw unsafe
236 kw fn 236 kw fn
237 kw const
238 kw type
237 kw use 239 kw use
238 kw impl 240 kw impl
239 kw trait 241 kw trait
242 kw static
243 kw extern
244 kw mod
240 kw enum 245 kw enum
241 kw struct 246 kw struct
242 kw union 247 kw union
243 kw mod
244 kw const
245 kw type
246 kw static
247 kw extern
248 kw unsafe
249 kw pub(crate)
250 kw pub
251 "#]], 248 "#]],
252 ); 249 );
253 } 250 }
@@ -257,10 +254,16 @@ mod tests {
257 check( 254 check(
258 r"fn quux() { $0 }", 255 r"fn quux() { $0 }",
259 expect![[r#" 256 expect![[r#"
257 kw unsafe
260 kw fn 258 kw fn
259 kw const
260 kw type
261 kw use 261 kw use
262 kw impl 262 kw impl
263 kw trait 263 kw trait
264 kw static
265 kw extern
266 kw mod
264 kw match 267 kw match
265 kw while 268 kw while
266 kw while let 269 kw while let
@@ -269,12 +272,6 @@ mod tests {
269 kw if let 272 kw if let
270 kw for 273 kw for
271 kw let 274 kw let
272 kw mod
273 kw const
274 kw type
275 kw static
276 kw extern
277 kw unsafe
278 kw return 275 kw return
279 "#]], 276 "#]],
280 ); 277 );
@@ -285,10 +282,16 @@ mod tests {
285 check( 282 check(
286 r"fn quux() { if true { $0 } }", 283 r"fn quux() { if true { $0 } }",
287 expect![[r#" 284 expect![[r#"
285 kw unsafe
288 kw fn 286 kw fn
287 kw const
288 kw type
289 kw use 289 kw use
290 kw impl 290 kw impl
291 kw trait 291 kw trait
292 kw static
293 kw extern
294 kw mod
292 kw match 295 kw match
293 kw while 296 kw while
294 kw while let 297 kw while let
@@ -297,12 +300,6 @@ mod tests {
297 kw if let 300 kw if let
298 kw for 301 kw for
299 kw let 302 kw let
300 kw mod
301 kw const
302 kw type
303 kw static
304 kw extern
305 kw unsafe
306 kw return 303 kw return
307 "#]], 304 "#]],
308 ); 305 );
@@ -313,10 +310,16 @@ mod tests {
313 check( 310 check(
314 r#"fn quux() { if true { () } $0 }"#, 311 r#"fn quux() { if true { () } $0 }"#,
315 expect![[r#" 312 expect![[r#"
313 kw unsafe
316 kw fn 314 kw fn
315 kw const
316 kw type
317 kw use 317 kw use
318 kw impl 318 kw impl
319 kw trait 319 kw trait
320 kw static
321 kw extern
322 kw mod
320 kw match 323 kw match
321 kw while 324 kw while
322 kw while let 325 kw while let
@@ -327,12 +330,6 @@ mod tests {
327 kw let 330 kw let
328 kw else 331 kw else
329 kw else if 332 kw else if
330 kw mod
331 kw const
332 kw type
333 kw static
334 kw extern
335 kw unsafe
336 kw return 333 kw return
337 "#]], 334 "#]],
338 ); 335 );
@@ -354,6 +351,7 @@ fn quux() -> i32 {
354} 351}
355"#, 352"#,
356 expect![[r#" 353 expect![[r#"
354 kw unsafe
357 kw match 355 kw match
358 kw while 356 kw while
359 kw while let 357 kw while let
@@ -361,7 +359,6 @@ fn quux() -> i32 {
361 kw if 359 kw if
362 kw if let 360 kw if let
363 kw for 361 kw for
364 kw unsafe
365 kw return 362 kw return
366 "#]], 363 "#]],
367 ); 364 );
@@ -372,10 +369,10 @@ fn quux() -> i32 {
372 check( 369 check(
373 r"trait My { $0 }", 370 r"trait My { $0 }",
374 expect![[r#" 371 expect![[r#"
372 kw unsafe
375 kw fn 373 kw fn
376 kw const 374 kw const
377 kw type 375 kw type
378 kw unsafe
379 "#]], 376 "#]],
380 ); 377 );
381 } 378 }
@@ -385,12 +382,27 @@ fn quux() -> i32 {
385 check( 382 check(
386 r"impl My { $0 }", 383 r"impl My { $0 }",
387 expect![[r#" 384 expect![[r#"
385 kw pub(crate)
386 kw pub
387 kw unsafe
388 kw fn 388 kw fn
389 kw const 389 kw const
390 kw type 390 kw type
391 kw unsafe 391 "#]],
392 );
393 }
394
395 #[test]
396 fn test_keywords_in_impl_def_with_attr() {
397 check(
398 r"impl My { #[foo] $0 }",
399 expect![[r#"
392 kw pub(crate) 400 kw pub(crate)
393 kw pub 401 kw pub
402 kw unsafe
403 kw fn
404 kw const
405 kw type
394 "#]], 406 "#]],
395 ); 407 );
396 } 408 }
@@ -400,10 +412,16 @@ fn quux() -> i32 {
400 check( 412 check(
401 r"fn my() { loop { $0 } }", 413 r"fn my() { loop { $0 } }",
402 expect![[r#" 414 expect![[r#"
415 kw unsafe
403 kw fn 416 kw fn
417 kw const
418 kw type
404 kw use 419 kw use
405 kw impl 420 kw impl
406 kw trait 421 kw trait
422 kw static
423 kw extern
424 kw mod
407 kw match 425 kw match
408 kw while 426 kw while
409 kw while let 427 kw while let
@@ -412,12 +430,6 @@ fn quux() -> i32 {
412 kw if let 430 kw if let
413 kw for 431 kw for
414 kw let 432 kw let
415 kw mod
416 kw const
417 kw type
418 kw static
419 kw extern
420 kw unsafe
421 kw continue 433 kw continue
422 kw break 434 kw break
423 kw return 435 kw return
@@ -564,6 +576,7 @@ pub mod future {
564 check( 576 check(
565 r#"fn main() { let _ = $0 }"#, 577 r#"fn main() { let _ = $0 }"#,
566 expect![[r#" 578 expect![[r#"
579 kw unsafe
567 kw match 580 kw match
568 kw while 581 kw while
569 kw while let 582 kw while let
@@ -624,6 +637,7 @@ fn foo() {
624} 637}
625"#, 638"#,
626 expect![[r#" 639 expect![[r#"
640 kw unsafe
627 kw match 641 kw match
628 kw while 642 kw while
629 kw while let 643 kw while let