aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMikhail Rakhmanov <[email protected]>2020-06-12 23:55:21 +0100
committerMikhail Rakhmanov <[email protected]>2020-06-12 23:55:21 +0100
commit6feb52c12accbf0ef54475cf66a03e035b922749 (patch)
tree62af8c1e8c781e672f6cc9a498ccb2a5abb17274
parent357667104371d446cc029267e8095365c17ba085 (diff)
Add more patterns, tests and fix keywords
-rw-r--r--crates/ra_ide/src/completion/complete_keyword.rs690
-rw-r--r--crates/ra_ide/src/completion/completion_context.rs19
-rw-r--r--crates/ra_ide/src/completion/patterns.rs61
3 files changed, 297 insertions, 473 deletions
diff --git a/crates/ra_ide/src/completion/complete_keyword.rs b/crates/ra_ide/src/completion/complete_keyword.rs
index 432793de2..79432113c 100644
--- a/crates/ra_ide/src/completion/complete_keyword.rs
+++ b/crates/ra_ide/src/completion/complete_keyword.rs
@@ -60,32 +60,104 @@ fn add_keyword(
60} 60}
61 61
62pub(super) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionContext) { 62pub(super) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionContext) {
63 let has_trait_or_impl_parent = ctx.has_impl_parent || ctx.has_trait_parent;
64 if ctx.trait_as_prev_sibling || ctx.impl_as_prev_sibling {
65 add_keyword(ctx, acc, "where", "where ", true);
66 return;
67 }
68 if ctx.unsafe_is_prev {
69 add_keyword(ctx, acc, "fn", "fn $0() {}", ctx.is_new_item || ctx.block_expr_parent);
70 add_keyword(
71 ctx,
72 acc,
73 "trait",
74 "trait $0 {}",
75 (ctx.is_new_item && !has_trait_or_impl_parent) || ctx.block_expr_parent,
76 );
77 add_keyword(
78 ctx,
79 acc,
80 "impl",
81 "impl $0 {}",
82 (ctx.is_new_item && !has_trait_or_impl_parent) || ctx.block_expr_parent,
83 );
84 return;
85 }
63 add_keyword(ctx, acc, "fn", "fn $0() {}", ctx.is_new_item || ctx.block_expr_parent); 86 add_keyword(ctx, acc, "fn", "fn $0() {}", ctx.is_new_item || ctx.block_expr_parent);
64 add_keyword(ctx, acc, "use", "fn $0() {}", ctx.is_new_item || ctx.block_expr_parent); 87 add_keyword(
65 add_keyword(ctx, acc, "impl", "impl $0 {}", ctx.is_new_item); 88 ctx,
66 add_keyword(ctx, acc, "trait", "impl $0 {}", ctx.is_new_item); 89 acc,
67 add_keyword(ctx, acc, "enum", "enum $0 {}", ctx.is_new_item && !ctx.unsafe_is_prev); 90 "use",
68 add_keyword(ctx, acc, "struct", "struct $0 {}", ctx.is_new_item && !ctx.unsafe_is_prev); 91 "use ",
69 add_keyword(ctx, acc, "union", "union $0 {}", ctx.is_new_item && !ctx.unsafe_is_prev); 92 (ctx.is_new_item && !has_trait_or_impl_parent) || ctx.block_expr_parent,
70 add_keyword(ctx, acc, "match", "match $0 {}", ctx.block_expr_parent); 93 );
71 add_keyword(ctx, acc, "loop", "loop {$0}", ctx.block_expr_parent); 94 add_keyword(
95 ctx,
96 acc,
97 "impl",
98 "impl $0 {}",
99 (ctx.is_new_item && !has_trait_or_impl_parent) || ctx.block_expr_parent,
100 );
101 add_keyword(
102 ctx,
103 acc,
104 "trait",
105 "trait $0 {}",
106 (ctx.is_new_item && !has_trait_or_impl_parent) || ctx.block_expr_parent,
107 );
108 add_keyword(ctx, acc, "enum", "enum $0 {}", ctx.is_new_item && !has_trait_or_impl_parent);
109 add_keyword(ctx, acc, "struct", "struct $0 {}", ctx.is_new_item && !has_trait_or_impl_parent);
110 add_keyword(ctx, acc, "union", "union $0 {}", ctx.is_new_item && !has_trait_or_impl_parent);
111 add_keyword(ctx, acc, "match", "match $0 {}", ctx.block_expr_parent || ctx.is_match_arm);
112 add_keyword(ctx, acc, "loop", "loop {$0}", ctx.block_expr_parent || ctx.is_match_arm);
72 add_keyword(ctx, acc, "while", "while $0 {}", ctx.block_expr_parent); 113 add_keyword(ctx, acc, "while", "while $0 {}", ctx.block_expr_parent);
73 add_keyword(ctx, acc, "let", "let ", ctx.if_is_prev || ctx.block_expr_parent); 114 add_keyword(ctx, acc, "let", "let ", ctx.if_is_prev || ctx.block_expr_parent);
115 add_keyword(ctx, acc, "if", "if ", ctx.if_is_prev || ctx.block_expr_parent || ctx.is_match_arm);
116 add_keyword(
117 ctx,
118 acc,
119 "if let",
120 "if let ",
121 ctx.if_is_prev || ctx.block_expr_parent || ctx.is_match_arm,
122 );
74 add_keyword(ctx, acc, "else", "else {$0}", ctx.after_if); 123 add_keyword(ctx, acc, "else", "else {$0}", ctx.after_if);
75 add_keyword(ctx, acc, "else if", "else if $0 {}", ctx.after_if); 124 add_keyword(ctx, acc, "else if", "else if $0 {}", ctx.after_if);
76 add_keyword(ctx, acc, "mod", "mod $0 {}", ctx.is_new_item || ctx.block_expr_parent); 125 add_keyword(
126 ctx,
127 acc,
128 "mod",
129 "mod $0 {}",
130 (ctx.is_new_item && !has_trait_or_impl_parent) || ctx.block_expr_parent,
131 );
77 add_keyword(ctx, acc, "mut", "mut ", ctx.bind_pat_parent || ctx.ref_pat_parent); 132 add_keyword(ctx, acc, "mut", "mut ", ctx.bind_pat_parent || ctx.ref_pat_parent);
78 add_keyword(ctx, acc, "const", "const ", ctx.is_new_item || ctx.block_expr_parent); 133 add_keyword(ctx, acc, "const", "const ", ctx.is_new_item || ctx.block_expr_parent);
79 add_keyword(ctx, acc, "type", "type ", ctx.is_new_item || ctx.block_expr_parent); 134 add_keyword(ctx, acc, "type", "type ", ctx.is_new_item || ctx.block_expr_parent);
80 add_keyword(ctx, acc, "static", "static ", ctx.is_new_item || ctx.block_expr_parent); 135 add_keyword(
81 add_keyword(ctx, acc, "extern", "extern ", ctx.is_new_item || ctx.block_expr_parent); 136 ctx,
82 add_keyword(ctx, acc, "unsafe", "unsafe ", ctx.is_new_item || ctx.block_expr_parent); 137 acc,
138 "static",
139 "static ",
140 (ctx.is_new_item && !has_trait_or_impl_parent) || ctx.block_expr_parent,
141 );
142 add_keyword(
143 ctx,
144 acc,
145 "extern",
146 "extern ",
147 (ctx.is_new_item && !has_trait_or_impl_parent) || ctx.block_expr_parent,
148 );
149 add_keyword(
150 ctx,
151 acc,
152 "unsafe",
153 "unsafe ",
154 ctx.is_new_item || ctx.block_expr_parent || ctx.is_match_arm,
155 );
83 add_keyword(ctx, acc, "continue", "continue;", ctx.in_loop_body && ctx.can_be_stmt); 156 add_keyword(ctx, acc, "continue", "continue;", ctx.in_loop_body && ctx.can_be_stmt);
84 add_keyword(ctx, acc, "break", "break;", ctx.in_loop_body && ctx.can_be_stmt); 157 add_keyword(ctx, acc, "break", "break;", ctx.in_loop_body && ctx.can_be_stmt);
85 add_keyword(ctx, acc, "continue", "continue", ctx.in_loop_body && !ctx.can_be_stmt); 158 add_keyword(ctx, acc, "continue", "continue", ctx.in_loop_body && !ctx.can_be_stmt);
86 add_keyword(ctx, acc, "break", "break", ctx.in_loop_body && !ctx.can_be_stmt); 159 add_keyword(ctx, acc, "break", "break", ctx.in_loop_body && !ctx.can_be_stmt);
87 add_keyword(ctx, acc, "pub", "pub ", ctx.is_new_item && !ctx.inside_trait); 160 add_keyword(ctx, acc, "pub", "pub ", ctx.is_new_item && !ctx.has_trait_parent);
88 add_keyword(ctx, acc, "where", "where ", ctx.trait_as_prev_sibling || ctx.impl_as_prev_sibling);
89 161
90 let fn_def = match &ctx.function_syntax { 162 let fn_def = match &ctx.function_syntax {
91 Some(it) => it, 163 Some(it) => it,
@@ -111,21 +183,17 @@ fn complete_return(
111#[cfg(test)] 183#[cfg(test)]
112mod tests { 184mod tests {
113 use crate::completion::{ 185 use crate::completion::{
114 test_utils::{do_completion, get_completions}, 186 test_utils::get_completions,
115 CompletionItem, CompletionKind, 187 CompletionKind,
116 }; 188 };
117 use insta::assert_debug_snapshot; 189 use insta::assert_debug_snapshot;
118 190
119 fn do_keyword_completion(code: &str) -> Vec<CompletionItem> {
120 do_completion(code, CompletionKind::Keyword)
121 }
122
123 fn get_keyword_completions(code: &str) -> Vec<String> { 191 fn get_keyword_completions(code: &str) -> Vec<String> {
124 get_completions(code, CompletionKind::Keyword) 192 get_completions(code, CompletionKind::Keyword)
125 } 193 }
126 194
127 #[test] 195 #[test]
128 fn completes_keywords_in_use_stmt() { 196 fn test_keywords_in_use_stmt() {
129 assert_debug_snapshot!( 197 assert_debug_snapshot!(
130 get_keyword_completions(r"use <|>"), 198 get_keyword_completions(r"use <|>"),
131 @r###" 199 @r###"
@@ -159,7 +227,7 @@ mod tests {
159 } 227 }
160 228
161 #[test] 229 #[test]
162 fn completes_various_keywords_in_function() { 230 fn test_keywords_in_function() {
163 assert_debug_snapshot!( 231 assert_debug_snapshot!(
164 get_keyword_completions(r"fn quux() { <|> }"), 232 get_keyword_completions(r"fn quux() { <|> }"),
165 @r###" 233 @r###"
@@ -167,12 +235,16 @@ mod tests {
167 "kw const", 235 "kw const",
168 "kw extern", 236 "kw extern",
169 "kw fn", 237 "kw fn",
238 "kw if",
239 "kw if let",
240 "kw impl",
170 "kw let", 241 "kw let",
171 "kw loop", 242 "kw loop",
172 "kw match", 243 "kw match",
173 "kw mod", 244 "kw mod",
174 "kw return", 245 "kw return",
175 "kw static", 246 "kw static",
247 "kw trait",
176 "kw type", 248 "kw type",
177 "kw unsafe", 249 "kw unsafe",
178 "kw use", 250 "kw use",
@@ -183,9 +255,37 @@ mod tests {
183 } 255 }
184 256
185 #[test] 257 #[test]
186 fn completes_else_after_if() { 258 fn test_keywords_inside_block() {
187 assert_debug_snapshot!( 259 assert_debug_snapshot!(
188 do_keyword_completion( 260 get_keyword_completions(r"fn quux() { if true { <|> } }"),
261 @r###"
262 [
263 "kw const",
264 "kw extern",
265 "kw fn",
266 "kw if",
267 "kw if let",
268 "kw impl",
269 "kw let",
270 "kw loop",
271 "kw match",
272 "kw mod",
273 "kw return",
274 "kw static",
275 "kw trait",
276 "kw type",
277 "kw unsafe",
278 "kw use",
279 "kw while",
280 ]
281 "###
282 );
283 }
284
285 #[test]
286 fn test_keywords_after_if() {
287 assert_debug_snapshot!(
288 get_keyword_completions(
189 r" 289 r"
190 fn quux() { 290 fn quux() {
191 if true { 291 if true {
@@ -196,505 +296,189 @@ mod tests {
196 ), 296 ),
197 @r###" 297 @r###"
198 [ 298 [
199 CompletionItem { 299 "kw const",
200 label: "else", 300 "kw else",
201 source_range: 108..108, 301 "kw else if",
202 delete: 108..108, 302 "kw extern",
203 insert: "else {$0}", 303 "kw fn",
204 kind: Keyword, 304 "kw if",
205 }, 305 "kw if let",
206 CompletionItem { 306 "kw impl",
207 label: "else if", 307 "kw let",
208 source_range: 108..108, 308 "kw loop",
209 delete: 108..108, 309 "kw match",
210 insert: "else if $0 {}", 310 "kw mod",
211 kind: Keyword, 311 "kw return",
212 }, 312 "kw static",
213 CompletionItem { 313 "kw trait",
214 label: "if", 314 "kw type",
215 source_range: 108..108, 315 "kw unsafe",
216 delete: 108..108, 316 "kw use",
217 insert: "if $0 {}", 317 "kw while",
218 kind: Keyword,
219 },
220 CompletionItem {
221 label: "loop",
222 source_range: 108..108,
223 delete: 108..108,
224 insert: "loop {$0}",
225 kind: Keyword,
226 },
227 CompletionItem {
228 label: "match",
229 source_range: 108..108,
230 delete: 108..108,
231 insert: "match $0 {}",
232 kind: Keyword,
233 },
234 CompletionItem {
235 label: "return",
236 source_range: 108..108,
237 delete: 108..108,
238 insert: "return;",
239 kind: Keyword,
240 },
241 CompletionItem {
242 label: "while",
243 source_range: 108..108,
244 delete: 108..108,
245 insert: "while $0 {}",
246 kind: Keyword,
247 },
248 ] 318 ]
249 "### 319 "###
250 ); 320 );
251 } 321 }
252 322
253 #[test] 323 #[test]
254 fn test_completion_return_value() { 324 fn test_keywords_in_match_arm() {
255 assert_debug_snapshot!( 325 assert_debug_snapshot!(
256 do_keyword_completion( 326 get_keyword_completions(
257 r" 327 r"
258 fn quux() -> i32 { 328 fn quux() -> i32 {
259 <|> 329 match () {
260 92 330 () => <|>
331 }
261 } 332 }
262 ", 333 ",
263 ), 334 ),
264 @r###" 335 @r###"
265 [ 336 [
266 CompletionItem { 337 "kw if",
267 label: "if", 338 "kw if let",
268 source_range: 56..56, 339 "kw loop",
269 delete: 56..56, 340 "kw match",
270 insert: "if $0 {}", 341 "kw return",
271 kind: Keyword, 342 "kw unsafe",
272 },
273 CompletionItem {
274 label: "loop",
275 source_range: 56..56,
276 delete: 56..56,
277 insert: "loop {$0}",
278 kind: Keyword,
279 },
280 CompletionItem {
281 label: "match",
282 source_range: 56..56,
283 delete: 56..56,
284 insert: "match $0 {}",
285 kind: Keyword,
286 },
287 CompletionItem {
288 label: "return",
289 source_range: 56..56,
290 delete: 56..56,
291 insert: "return $0;",
292 kind: Keyword,
293 },
294 CompletionItem {
295 label: "while",
296 source_range: 56..56,
297 delete: 56..56,
298 insert: "while $0 {}",
299 kind: Keyword,
300 },
301 ] 343 ]
302 "### 344 "###
303 ); 345 );
346 }
347
348 #[test]
349 fn test_keywords_in_trait_def() {
304 assert_debug_snapshot!( 350 assert_debug_snapshot!(
305 do_keyword_completion( 351 get_keyword_completions(r"trait My { <|> }"),
306 r"
307 fn quux() {
308 <|>
309 92
310 }
311 ",
312 ),
313 @r###" 352 @r###"
314 [ 353 [
315 CompletionItem { 354 "kw const",
316 label: "if", 355 "kw fn",
317 source_range: 49..49, 356 "kw type",
318 delete: 49..49, 357 "kw unsafe",
319 insert: "if $0 {}",
320 kind: Keyword,
321 },
322 CompletionItem {
323 label: "loop",
324 source_range: 49..49,
325 delete: 49..49,
326 insert: "loop {$0}",
327 kind: Keyword,
328 },
329 CompletionItem {
330 label: "match",
331 source_range: 49..49,
332 delete: 49..49,
333 insert: "match $0 {}",
334 kind: Keyword,
335 },
336 CompletionItem {
337 label: "return",
338 source_range: 49..49,
339 delete: 49..49,
340 insert: "return;",
341 kind: Keyword,
342 },
343 CompletionItem {
344 label: "while",
345 source_range: 49..49,
346 delete: 49..49,
347 insert: "while $0 {}",
348 kind: Keyword,
349 },
350 ] 358 ]
351 "### 359 "###
352 ); 360 );
353 } 361 }
354 362
355 #[test] 363 #[test]
356 fn dont_add_semi_after_return_if_not_a_statement() { 364 fn test_keywords_in_impl_def() {
357 assert_debug_snapshot!( 365 assert_debug_snapshot!(
358 do_keyword_completion( 366 get_keyword_completions(r"impl My { <|> }"),
359 r"
360 fn quux() -> i32 {
361 match () {
362 () => <|>
363 }
364 }
365 ",
366 ),
367 @r###" 367 @r###"
368 [ 368 [
369 CompletionItem { 369 "kw const",
370 label: "if", 370 "kw fn",
371 source_range: 97..97, 371 "kw pub",
372 delete: 97..97, 372 "kw type",
373 insert: "if $0 {}", 373 "kw unsafe",
374 kind: Keyword,
375 },
376 CompletionItem {
377 label: "loop",
378 source_range: 97..97,
379 delete: 97..97,
380 insert: "loop {$0}",
381 kind: Keyword,
382 },
383 CompletionItem {
384 label: "match",
385 source_range: 97..97,
386 delete: 97..97,
387 insert: "match $0 {}",
388 kind: Keyword,
389 },
390 CompletionItem {
391 label: "return",
392 source_range: 97..97,
393 delete: 97..97,
394 insert: "return $0",
395 kind: Keyword,
396 },
397 CompletionItem {
398 label: "while",
399 source_range: 97..97,
400 delete: 97..97,
401 insert: "while $0 {}",
402 kind: Keyword,
403 },
404 ] 374 ]
405 "### 375 "###
406 ); 376 );
407 } 377 }
408 378
409 #[test] 379 #[test]
410 fn last_return_in_block_has_semi() { 380 fn test_keywords_in_loop() {
411 assert_debug_snapshot!( 381 assert_debug_snapshot!(
412 do_keyword_completion( 382 get_keyword_completions(r"fn my() { loop { <|> } }"),
413 r"
414 fn quux() -> i32 {
415 if condition {
416 <|>
417 }
418 }
419 ",
420 ),
421 @r###" 383 @r###"
422 [ 384 [
423 CompletionItem { 385 "kw break",
424 label: "if", 386 "kw const",
425 source_range: 95..95, 387 "kw continue",
426 delete: 95..95, 388 "kw extern",
427 insert: "if $0 {}", 389 "kw fn",
428 kind: Keyword, 390 "kw if",
429 }, 391 "kw if let",
430 CompletionItem { 392 "kw impl",
431 label: "loop", 393 "kw let",
432 source_range: 95..95, 394 "kw loop",
433 delete: 95..95, 395 "kw match",
434 insert: "loop {$0}", 396 "kw mod",
435 kind: Keyword, 397 "kw return",
436 }, 398 "kw static",
437 CompletionItem { 399 "kw trait",
438 label: "match", 400 "kw type",
439 source_range: 95..95, 401 "kw unsafe",
440 delete: 95..95, 402 "kw use",
441 insert: "match $0 {}", 403 "kw while",
442 kind: Keyword,
443 },
444 CompletionItem {
445 label: "return",
446 source_range: 95..95,
447 delete: 95..95,
448 insert: "return $0;",
449 kind: Keyword,
450 },
451 CompletionItem {
452 label: "while",
453 source_range: 95..95,
454 delete: 95..95,
455 insert: "while $0 {}",
456 kind: Keyword,
457 },
458 ] 404 ]
459 "### 405 "###
460 ); 406 );
407 }
408
409 #[test]
410 fn test_keywords_after_unsafe_in_item_list() {
461 assert_debug_snapshot!( 411 assert_debug_snapshot!(
462 do_keyword_completion( 412 get_keyword_completions(r"unsafe <|>"),
463 r"
464 fn quux() -> i32 {
465 if condition {
466 <|>
467 }
468 let x = 92;
469 x
470 }
471 ",
472 ),
473 @r###" 413 @r###"
474 [ 414 [
475 CompletionItem { 415 "kw fn",
476 label: "if", 416 "kw impl",
477 source_range: 95..95, 417 "kw trait",
478 delete: 95..95,
479 insert: "if $0 {}",
480 kind: Keyword,
481 },
482 CompletionItem {
483 label: "loop",
484 source_range: 95..95,
485 delete: 95..95,
486 insert: "loop {$0}",
487 kind: Keyword,
488 },
489 CompletionItem {
490 label: "match",
491 source_range: 95..95,
492 delete: 95..95,
493 insert: "match $0 {}",
494 kind: Keyword,
495 },
496 CompletionItem {
497 label: "return",
498 source_range: 95..95,
499 delete: 95..95,
500 insert: "return $0;",
501 kind: Keyword,
502 },
503 CompletionItem {
504 label: "while",
505 source_range: 95..95,
506 delete: 95..95,
507 insert: "while $0 {}",
508 kind: Keyword,
509 },
510 ] 418 ]
511 "### 419 "###
512 ); 420 );
513 } 421 }
514 422
515 #[test] 423 #[test]
516 fn completes_break_and_continue_in_loops() { 424 fn test_keywords_after_unsafe_in_block_expr() {
517 assert_debug_snapshot!( 425 assert_debug_snapshot!(
518 do_keyword_completion( 426 get_keyword_completions(r"fn my_fn() { unsafe <|> }"),
519 r"
520 fn quux() -> i32 {
521 loop { <|> }
522 }
523 ",
524 ),
525 @r###" 427 @r###"
526 [ 428 [
527 CompletionItem { 429 "kw fn",
528 label: "break", 430 "kw impl",
529 source_range: 63..63, 431 "kw trait",
530 delete: 63..63,
531 insert: "break;",
532 kind: Keyword,
533 },
534 CompletionItem {
535 label: "continue",
536 source_range: 63..63,
537 delete: 63..63,
538 insert: "continue;",
539 kind: Keyword,
540 },
541 CompletionItem {
542 label: "if",
543 source_range: 63..63,
544 delete: 63..63,
545 insert: "if $0 {}",
546 kind: Keyword,
547 },
548 CompletionItem {
549 label: "loop",
550 source_range: 63..63,
551 delete: 63..63,
552 insert: "loop {$0}",
553 kind: Keyword,
554 },
555 CompletionItem {
556 label: "match",
557 source_range: 63..63,
558 delete: 63..63,
559 insert: "match $0 {}",
560 kind: Keyword,
561 },
562 CompletionItem {
563 label: "return",
564 source_range: 63..63,
565 delete: 63..63,
566 insert: "return $0;",
567 kind: Keyword,
568 },
569 CompletionItem {
570 label: "while",
571 source_range: 63..63,
572 delete: 63..63,
573 insert: "while $0 {}",
574 kind: Keyword,
575 },
576 ] 432 ]
577 "### 433 "###
578 ); 434 );
435 }
579 436
580 // No completion: lambda isolates control flow 437 #[test]
438 fn test_mut_in_ref_and_in_fn_parameters_list() {
581 assert_debug_snapshot!( 439 assert_debug_snapshot!(
582 do_keyword_completion( 440 get_keyword_completions(r"fn my_fn(&<|>) {}"),
583 r" 441 @r###"
584 fn quux() -> i32 { 442 [
585 loop { || { <|> } } 443 "kw mut",
586 } 444 ]
587 ", 445 "###
588 ), 446 );
447 assert_debug_snapshot!(
448 get_keyword_completions(r"fn my_fn(<|>) {}"),
449 @r###"
450 [
451 "kw mut",
452 ]
453 "###
454 );
455 assert_debug_snapshot!(
456 get_keyword_completions(r"fn my_fn() { let &<|> }"),
589 @r###" 457 @r###"
590 [ 458 [
591 CompletionItem { 459 "kw mut",
592 label: "if",
593 source_range: 68..68,
594 delete: 68..68,
595 insert: "if $0 {}",
596 kind: Keyword,
597 },
598 CompletionItem {
599 label: "loop",
600 source_range: 68..68,
601 delete: 68..68,
602 insert: "loop {$0}",
603 kind: Keyword,
604 },
605 CompletionItem {
606 label: "match",
607 source_range: 68..68,
608 delete: 68..68,
609 insert: "match $0 {}",
610 kind: Keyword,
611 },
612 CompletionItem {
613 label: "return",
614 source_range: 68..68,
615 delete: 68..68,
616 insert: "return $0;",
617 kind: Keyword,
618 },
619 CompletionItem {
620 label: "while",
621 source_range: 68..68,
622 delete: 68..68,
623 insert: "while $0 {}",
624 kind: Keyword,
625 },
626 ] 460 ]
627 "### 461 "###
628 ); 462 );
629 } 463 }
630 464
631 #[test] 465 #[test]
632 fn no_semi_after_break_continue_in_expr() { 466 fn test_where_keyword() {
633 assert_debug_snapshot!( 467 assert_debug_snapshot!(
634 do_keyword_completion( 468 get_keyword_completions(r"trait A <|>"),
635 r" 469 @r###"
636 fn f() { 470 [
637 loop { 471 "kw where",
638 match () { 472 ]
639 () => br<|> 473 "###
640 } 474 );
641 } 475 assert_debug_snapshot!(
642 } 476 get_keyword_completions(r"impl A <|>"),
643 ",
644 ),
645 @r###" 477 @r###"
646 [ 478 [
647 CompletionItem { 479 "kw where",
648 label: "break",
649 source_range: 122..124,
650 delete: 122..124,
651 insert: "break",
652 kind: Keyword,
653 },
654 CompletionItem {
655 label: "continue",
656 source_range: 122..124,
657 delete: 122..124,
658 insert: "continue",
659 kind: Keyword,
660 },
661 CompletionItem {
662 label: "if",
663 source_range: 122..124,
664 delete: 122..124,
665 insert: "if $0 {}",
666 kind: Keyword,
667 },
668 CompletionItem {
669 label: "loop",
670 source_range: 122..124,
671 delete: 122..124,
672 insert: "loop {$0}",
673 kind: Keyword,
674 },
675 CompletionItem {
676 label: "match",
677 source_range: 122..124,
678 delete: 122..124,
679 insert: "match $0 {}",
680 kind: Keyword,
681 },
682 CompletionItem {
683 label: "return",
684 source_range: 122..124,
685 delete: 122..124,
686 insert: "return",
687 kind: Keyword,
688 },
689 CompletionItem {
690 label: "while",
691 source_range: 122..124,
692 delete: 122..124,
693 insert: "while $0 {}",
694 kind: Keyword,
695 },
696 ] 480 ]
697 "### 481 "###
698 ) 482 );
699 } 483 }
700} 484}
diff --git a/crates/ra_ide/src/completion/completion_context.rs b/crates/ra_ide/src/completion/completion_context.rs
index 41aec5686..2f96861ca 100644
--- a/crates/ra_ide/src/completion/completion_context.rs
+++ b/crates/ra_ide/src/completion/completion_context.rs
@@ -12,8 +12,9 @@ use ra_syntax::{
12use ra_text_edit::Indel; 12use ra_text_edit::Indel;
13 13
14use super::patterns::{ 14use super::patterns::{
15 has_bind_pat_parent, has_block_expr_parent, has_impl_as_prev_sibling, has_ref_pat_parent, 15 has_bind_pat_parent, has_block_expr_parent, has_impl_as_prev_sibling, has_impl_parent,
16 has_trait_as_prev_sibling, if_is_prev, inside_trait, is_in_loop_body, unsafe_is_prev, 16 has_ref_parent, has_trait_as_prev_sibling, has_trait_parent, if_is_prev, is_in_loop_body,
17 is_match_arm, unsafe_is_prev,
17}; 18};
18use crate::{call_info::ActiveParameter, completion::CompletionConfig, FilePosition}; 19use crate::{call_info::ActiveParameter, completion::CompletionConfig, FilePosition};
19use test_utils::mark; 20use test_utils::mark;
@@ -70,9 +71,11 @@ pub(crate) struct CompletionContext<'a> {
70 pub(super) bind_pat_parent: bool, 71 pub(super) bind_pat_parent: bool,
71 pub(super) ref_pat_parent: bool, 72 pub(super) ref_pat_parent: bool,
72 pub(super) in_loop_body: bool, 73 pub(super) in_loop_body: bool,
73 pub(super) inside_trait: bool, 74 pub(super) has_trait_parent: bool,
75 pub(super) has_impl_parent: bool,
74 pub(super) trait_as_prev_sibling: bool, 76 pub(super) trait_as_prev_sibling: bool,
75 pub(super) impl_as_prev_sibling: bool, 77 pub(super) impl_as_prev_sibling: bool,
78 pub(super) is_match_arm: bool,
76} 79}
77 80
78impl<'a> CompletionContext<'a> { 81impl<'a> CompletionContext<'a> {
@@ -136,10 +139,12 @@ impl<'a> CompletionContext<'a> {
136 ref_pat_parent: false, 139 ref_pat_parent: false,
137 bind_pat_parent: false, 140 bind_pat_parent: false,
138 block_expr_parent: false, 141 block_expr_parent: false,
139 inside_trait: false, 142 has_trait_parent: false,
143 has_impl_parent: false,
140 trait_as_prev_sibling: false, 144 trait_as_prev_sibling: false,
141 impl_as_prev_sibling: false, 145 impl_as_prev_sibling: false,
142 if_is_prev: false, 146 if_is_prev: false,
147 is_match_arm: false,
143 }; 148 };
144 149
145 let mut original_file = original_file.syntax().clone(); 150 let mut original_file = original_file.syntax().clone();
@@ -217,11 +222,13 @@ impl<'a> CompletionContext<'a> {
217 self.unsafe_is_prev = unsafe_is_prev(syntax_element.clone()); 222 self.unsafe_is_prev = unsafe_is_prev(syntax_element.clone());
218 self.if_is_prev = if_is_prev(syntax_element.clone()); 223 self.if_is_prev = if_is_prev(syntax_element.clone());
219 self.bind_pat_parent = has_bind_pat_parent(syntax_element.clone()); 224 self.bind_pat_parent = has_bind_pat_parent(syntax_element.clone());
220 self.ref_pat_parent = has_ref_pat_parent(syntax_element.clone()); 225 self.ref_pat_parent = has_ref_parent(syntax_element.clone());
221 self.in_loop_body = is_in_loop_body(syntax_element.clone()); 226 self.in_loop_body = is_in_loop_body(syntax_element.clone());
222 self.inside_trait = inside_trait(syntax_element.clone()); 227 self.has_trait_parent = has_trait_parent(syntax_element.clone());
228 self.has_impl_parent = has_impl_parent(syntax_element.clone());
223 self.impl_as_prev_sibling = has_impl_as_prev_sibling(syntax_element.clone()); 229 self.impl_as_prev_sibling = has_impl_as_prev_sibling(syntax_element.clone());
224 self.trait_as_prev_sibling = has_trait_as_prev_sibling(syntax_element.clone()); 230 self.trait_as_prev_sibling = has_trait_as_prev_sibling(syntax_element.clone());
231 self.is_match_arm = is_match_arm(syntax_element.clone());
225 } 232 }
226 233
227 fn fill( 234 fn fill(
diff --git a/crates/ra_ide/src/completion/patterns.rs b/crates/ra_ide/src/completion/patterns.rs
index bc39689ab..bc37196d5 100644
--- a/crates/ra_ide/src/completion/patterns.rs
+++ b/crates/ra_ide/src/completion/patterns.rs
@@ -6,16 +6,42 @@ use ra_syntax::{
6 SyntaxNode, SyntaxToken, 6 SyntaxNode, SyntaxToken,
7}; 7};
8 8
9pub(crate) fn inside_trait(element: SyntaxElement) -> bool { 9pub(crate) fn has_trait_parent(element: SyntaxElement) -> bool {
10 element.ancestors().find(|it| it.kind() == TRAIT_DEF).is_some() 10 not_same_range_ancestor(element)
11 .filter(|it| it.kind() == ITEM_LIST)
12 .and_then(|it| it.parent())
13 .filter(|it| it.kind() == TRAIT_DEF)
14 .is_some()
15}
16
17pub(crate) fn has_impl_parent(element: SyntaxElement) -> bool {
18 not_same_range_ancestor(element)
19 .filter(|it| it.kind() == ITEM_LIST)
20 .and_then(|it| it.parent())
21 .filter(|it| it.kind() == IMPL_DEF)
22 .is_some()
23}
24
25pub(crate) fn has_block_expr_parent(element: SyntaxElement) -> bool {
26 not_same_range_ancestor(element).filter(|it| it.kind() == BLOCK_EXPR).is_some()
11} 27}
12 28
13pub(crate) fn has_bind_pat_parent(element: SyntaxElement) -> bool { 29pub(crate) fn has_bind_pat_parent(element: SyntaxElement) -> bool {
14 element.ancestors().find(|it| it.kind() == BIND_PAT).is_some() 30 element.ancestors().find(|it| it.kind() == BIND_PAT).is_some()
15} 31}
16 32
17pub(crate) fn has_ref_pat_parent(element: SyntaxElement) -> bool { 33pub(crate) fn has_ref_parent(element: SyntaxElement) -> bool {
18 element.ancestors().find(|it| it.kind() == REF_PAT).is_some() 34 not_same_range_ancestor(element)
35 .filter(|it| it.kind() == REF_PAT || it.kind() == REF_EXPR)
36 .is_some()
37}
38
39pub(crate) fn is_match_arm(element: SyntaxElement) -> bool {
40 not_same_range_ancestor(element.clone()).filter(|it| it.kind() == MATCH_ARM).is_some()
41 && previous_sibling_or_ancestor_sibling(element)
42 .and_then(|it| it.into_token())
43 .filter(|it| it.kind() == FAT_ARROW)
44 .is_some()
19} 45}
20 46
21pub(crate) fn unsafe_is_prev(element: SyntaxElement) -> bool { 47pub(crate) fn unsafe_is_prev(element: SyntaxElement) -> bool {
@@ -34,10 +60,6 @@ pub(crate) fn if_is_prev(element: SyntaxElement) -> bool {
34 .is_some() 60 .is_some()
35} 61}
36 62
37pub(crate) fn has_block_expr_parent(element: SyntaxElement) -> bool {
38 not_same_range_ancestor(element).filter(|it| it.kind() == BLOCK_EXPR).is_some()
39}
40
41pub(crate) fn has_trait_as_prev_sibling(element: SyntaxElement) -> bool { 63pub(crate) fn has_trait_as_prev_sibling(element: SyntaxElement) -> bool {
42 previous_sibling_or_ancestor_sibling(element).filter(|it| it.kind() == TRAIT_DEF).is_some() 64 previous_sibling_or_ancestor_sibling(element).filter(|it| it.kind() == TRAIT_DEF).is_some()
43} 65}
@@ -114,8 +136,9 @@ fn previous_sibling_or_ancestor_sibling(element: SyntaxElement) -> Option<Syntax
114#[cfg(test)] 136#[cfg(test)]
115mod tests { 137mod tests {
116 use super::{ 138 use super::{
117 has_bind_pat_parent, has_block_expr_parent, has_impl_as_prev_sibling, has_ref_pat_parent, 139 has_bind_pat_parent, has_block_expr_parent, has_impl_as_prev_sibling, has_impl_parent,
118 has_trait_as_prev_sibling, if_is_prev, inside_trait, unsafe_is_prev, 140 has_ref_parent, has_trait_as_prev_sibling, has_trait_parent, if_is_prev, is_match_arm,
141 unsafe_is_prev,
119 }; 142 };
120 use crate::completion::test_utils::check_pattern_is_applicable; 143 use crate::completion::test_utils::check_pattern_is_applicable;
121 144
@@ -130,8 +153,13 @@ mod tests {
130 } 153 }
131 154
132 #[test] 155 #[test]
133 fn test_inside_trait() { 156 fn test_has_trait_parent() {
134 check_pattern_is_applicable(r"trait A { fn<|> }", inside_trait); 157 check_pattern_is_applicable(r"trait A { f<|> }", has_trait_parent);
158 }
159
160 #[test]
161 fn test_has_impl_parent() {
162 check_pattern_is_applicable(r"impl A { f<|> }", has_impl_parent);
135 } 163 }
136 164
137 #[test] 165 #[test]
@@ -151,12 +179,12 @@ mod tests {
151 179
152 #[test] 180 #[test]
153 fn test_has_ref_pat_parent_in_func_parameters() { 181 fn test_has_ref_pat_parent_in_func_parameters() {
154 check_pattern_is_applicable(r"fn my_fn(&<|>) {}", has_ref_pat_parent); 182 check_pattern_is_applicable(r"fn my_fn(&m<|>) {}", has_ref_parent);
155 } 183 }
156 184
157 #[test] 185 #[test]
158 fn test_has_ref_pat_parent_in_let_statement() { 186 fn test_has_ref_pat_parent_in_let_statement() {
159 check_pattern_is_applicable(r"fn my_fn() { let &<|> }", has_ref_pat_parent); 187 check_pattern_is_applicable(r"fn my() { let &m<|> }", has_ref_parent);
160 } 188 }
161 189
162 #[test] 190 #[test]
@@ -168,4 +196,9 @@ mod tests {
168 fn test_has_bind_pat_parent_in_let_statement() { 196 fn test_has_bind_pat_parent_in_let_statement() {
169 check_pattern_is_applicable(r"fn my_fn() { let m<|> }", has_bind_pat_parent); 197 check_pattern_is_applicable(r"fn my_fn() { let m<|> }", has_bind_pat_parent);
170 } 198 }
199
200 #[test]
201 fn test_is_match_arm() {
202 check_pattern_is_applicable(r"fn my_fn() { match () { () => m<|> } }", is_match_arm);
203 }
171} 204}