diff options
Diffstat (limited to 'crates/ide_completion/src/completions/keyword.rs')
-rw-r--r-- | crates/ide_completion/src/completions/keyword.rs | 278 |
1 files changed, 60 insertions, 218 deletions
diff --git a/crates/ide_completion/src/completions/keyword.rs b/crates/ide_completion/src/completions/keyword.rs index ba13d3707..407f796ef 100644 --- a/crates/ide_completion/src/completions/keyword.rs +++ b/crates/ide_completion/src/completions/keyword.rs | |||
@@ -18,26 +18,22 @@ pub(crate) fn complete_use_tree_keyword(acc: &mut Completions, ctx: &CompletionC | |||
18 | item | 18 | item |
19 | }; | 19 | }; |
20 | 20 | ||
21 | if ctx.use_item_syntax.is_some() { | 21 | if ctx.in_use_tree() { |
22 | let qual = ctx.path_qual(); | 22 | match &ctx.path_context { |
23 | if qual.is_none() { | 23 | Some(PathCompletionContext { qualifier: Some(qual), use_tree_parent, .. }) => { |
24 | kw_completion("crate::").add_to(acc); | 24 | if iter::successors(Some(qual.clone()), |p| p.qualifier()) |
25 | } | 25 | .all(|p| p.segment().and_then(|s| s.super_token()).is_some()) |
26 | kw_completion("self").add_to(acc); | 26 | { |
27 | if iter::successors(qual.cloned(), |p| p.qualifier()) | 27 | kw_completion("super::").add_to(acc); |
28 | .all(|p| p.segment().and_then(|s| s.super_token()).is_some()) | 28 | } |
29 | { | 29 | if *use_tree_parent { |
30 | kw_completion("super::").add_to(acc); | 30 | kw_completion("self").add_to(acc); |
31 | } | 31 | } |
32 | } | 32 | } |
33 | 33 | _ => { | |
34 | // Suggest .await syntax for types that implement Future trait | 34 | kw_completion("crate::").add_to(acc); |
35 | if let Some(receiver) = ctx.dot_receiver() { | 35 | kw_completion("self::").add_to(acc); |
36 | if let Some(ty) = ctx.sema.type_of_expr(receiver) { | 36 | kw_completion("super::").add_to(acc); |
37 | if ty.impls_future(ctx.db) { | ||
38 | let mut item = kw_completion("await"); | ||
39 | item.detail("expr.await"); | ||
40 | item.add_to(acc); | ||
41 | } | 37 | } |
42 | }; | 38 | }; |
43 | } | 39 | } |
@@ -52,6 +48,23 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte | |||
52 | cov_mark::hit!(no_keyword_completion_in_record_lit); | 48 | cov_mark::hit!(no_keyword_completion_in_record_lit); |
53 | return; | 49 | return; |
54 | } | 50 | } |
51 | if ctx.attribute_under_caret.is_some() { | ||
52 | cov_mark::hit!(no_keyword_completion_in_attr_of_expr); | ||
53 | return; | ||
54 | } | ||
55 | |||
56 | // Suggest .await syntax for types that implement Future trait | ||
57 | if let Some(receiver) = ctx.dot_receiver() { | ||
58 | if let Some(ty) = ctx.sema.type_of_expr(receiver) { | ||
59 | if ty.impls_future(ctx.db) { | ||
60 | let mut item = | ||
61 | CompletionItem::new(CompletionKind::Keyword, ctx.source_range(), "await"); | ||
62 | item.kind(CompletionItemKind::Keyword).detail("expr.await"); | ||
63 | item.add_to(acc); | ||
64 | } | ||
65 | }; | ||
66 | } | ||
67 | |||
55 | let mut add_keyword = |kw, snippet| add_keyword(ctx, acc, kw, snippet); | 68 | let mut add_keyword = |kw, snippet| add_keyword(ctx, acc, kw, snippet); |
56 | 69 | ||
57 | let expects_assoc_item = ctx.expects_assoc_item(); | 70 | let expects_assoc_item = ctx.expects_assoc_item(); |
@@ -60,6 +73,9 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte | |||
60 | 73 | ||
61 | if ctx.has_impl_or_trait_prev_sibling() { | 74 | if ctx.has_impl_or_trait_prev_sibling() { |
62 | add_keyword("where", "where "); | 75 | add_keyword("where", "where "); |
76 | if ctx.has_impl_prev_sibling() { | ||
77 | add_keyword("for", "for "); | ||
78 | } | ||
63 | return; | 79 | return; |
64 | } | 80 | } |
65 | if ctx.previous_token_is(T![unsafe]) { | 81 | if ctx.previous_token_is(T![unsafe]) { |
@@ -75,7 +91,9 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte | |||
75 | return; | 91 | return; |
76 | } | 92 | } |
77 | 93 | ||
78 | if expects_item || ctx.expects_non_trait_assoc_item() || ctx.expect_record_field() { | 94 | if !ctx.has_visibility_prev_sibling() |
95 | && (expects_item || ctx.expects_non_trait_assoc_item() || ctx.expect_field()) | ||
96 | { | ||
79 | add_keyword("pub(crate)", "pub(crate) "); | 97 | add_keyword("pub(crate)", "pub(crate) "); |
80 | add_keyword("pub", "pub "); | 98 | add_keyword("pub", "pub "); |
81 | } | 99 | } |
@@ -88,11 +106,13 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte | |||
88 | } | 106 | } |
89 | 107 | ||
90 | if expects_item || has_block_expr_parent { | 108 | if expects_item || has_block_expr_parent { |
109 | if !ctx.has_visibility_prev_sibling() { | ||
110 | add_keyword("impl", "impl $1 {\n $0\n}"); | ||
111 | add_keyword("extern", "extern $0"); | ||
112 | } | ||
91 | add_keyword("use", "use $0"); | 113 | add_keyword("use", "use $0"); |
92 | add_keyword("impl", "impl $1 {\n $0\n}"); | ||
93 | add_keyword("trait", "trait $1 {\n $0\n}"); | 114 | add_keyword("trait", "trait $1 {\n $0\n}"); |
94 | add_keyword("static", "static $0"); | 115 | add_keyword("static", "static $0"); |
95 | add_keyword("extern", "extern $0"); | ||
96 | add_keyword("mod", "mod $0"); | 116 | add_keyword("mod", "mod $0"); |
97 | } | 117 | } |
98 | 118 | ||
@@ -102,6 +122,10 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte | |||
102 | add_keyword("union", "union $1 {\n $0\n}"); | 122 | add_keyword("union", "union $1 {\n $0\n}"); |
103 | } | 123 | } |
104 | 124 | ||
125 | if ctx.expects_type() { | ||
126 | return; | ||
127 | } | ||
128 | |||
105 | if ctx.expects_expression() { | 129 | if ctx.expects_expression() { |
106 | if !has_block_expr_parent { | 130 | if !has_block_expr_parent { |
107 | add_keyword("unsafe", "unsafe {\n $0\n}"); | 131 | add_keyword("unsafe", "unsafe {\n $0\n}"); |
@@ -186,75 +210,16 @@ mod tests { | |||
186 | use expect_test::{expect, Expect}; | 210 | use expect_test::{expect, Expect}; |
187 | 211 | ||
188 | use crate::{ | 212 | use crate::{ |
189 | test_utils::{check_edit, completion_list}, | 213 | tests::{check_edit, filtered_completion_list}, |
190 | CompletionKind, | 214 | CompletionKind, |
191 | }; | 215 | }; |
192 | 216 | ||
193 | fn check(ra_fixture: &str, expect: Expect) { | 217 | fn check(ra_fixture: &str, expect: Expect) { |
194 | let actual = completion_list(ra_fixture, CompletionKind::Keyword); | 218 | let actual = filtered_completion_list(ra_fixture, CompletionKind::Keyword); |
195 | expect.assert_eq(&actual) | 219 | expect.assert_eq(&actual) |
196 | } | 220 | } |
197 | 221 | ||
198 | #[test] | 222 | #[test] |
199 | fn test_keywords_in_use_stmt() { | ||
200 | check( | ||
201 | r"use $0", | ||
202 | expect![[r#" | ||
203 | kw crate:: | ||
204 | kw self | ||
205 | kw super:: | ||
206 | "#]], | ||
207 | ); | ||
208 | |||
209 | // FIXME: `self` shouldn't be shown here and the check below | ||
210 | check( | ||
211 | r"use a::$0", | ||
212 | expect![[r#" | ||
213 | kw self | ||
214 | "#]], | ||
215 | ); | ||
216 | |||
217 | check( | ||
218 | r"use super::$0", | ||
219 | expect![[r#" | ||
220 | kw self | ||
221 | kw super:: | ||
222 | "#]], | ||
223 | ); | ||
224 | |||
225 | check( | ||
226 | r"use a::{b, $0}", | ||
227 | expect![[r#" | ||
228 | kw self | ||
229 | "#]], | ||
230 | ); | ||
231 | } | ||
232 | |||
233 | #[test] | ||
234 | fn test_keywords_at_source_file_level() { | ||
235 | check( | ||
236 | r"m$0", | ||
237 | expect![[r#" | ||
238 | kw pub(crate) | ||
239 | kw pub | ||
240 | kw unsafe | ||
241 | kw fn | ||
242 | kw const | ||
243 | kw type | ||
244 | kw use | ||
245 | kw impl | ||
246 | kw trait | ||
247 | kw static | ||
248 | kw extern | ||
249 | kw mod | ||
250 | kw enum | ||
251 | kw struct | ||
252 | kw union | ||
253 | "#]], | ||
254 | ); | ||
255 | } | ||
256 | |||
257 | #[test] | ||
258 | fn test_keywords_in_function() { | 223 | fn test_keywords_in_function() { |
259 | check( | 224 | check( |
260 | r"fn quux() { $0 }", | 225 | r"fn quux() { $0 }", |
@@ -263,11 +228,11 @@ mod tests { | |||
263 | kw fn | 228 | kw fn |
264 | kw const | 229 | kw const |
265 | kw type | 230 | kw type |
266 | kw use | ||
267 | kw impl | 231 | kw impl |
232 | kw extern | ||
233 | kw use | ||
268 | kw trait | 234 | kw trait |
269 | kw static | 235 | kw static |
270 | kw extern | ||
271 | kw mod | 236 | kw mod |
272 | kw match | 237 | kw match |
273 | kw while | 238 | kw while |
@@ -291,11 +256,11 @@ mod tests { | |||
291 | kw fn | 256 | kw fn |
292 | kw const | 257 | kw const |
293 | kw type | 258 | kw type |
294 | kw use | ||
295 | kw impl | 259 | kw impl |
260 | kw extern | ||
261 | kw use | ||
296 | kw trait | 262 | kw trait |
297 | kw static | 263 | kw static |
298 | kw extern | ||
299 | kw mod | 264 | kw mod |
300 | kw match | 265 | kw match |
301 | kw while | 266 | kw while |
@@ -319,11 +284,11 @@ mod tests { | |||
319 | kw fn | 284 | kw fn |
320 | kw const | 285 | kw const |
321 | kw type | 286 | kw type |
322 | kw use | ||
323 | kw impl | 287 | kw impl |
288 | kw extern | ||
289 | kw use | ||
324 | kw trait | 290 | kw trait |
325 | kw static | 291 | kw static |
326 | kw extern | ||
327 | kw mod | 292 | kw mod |
328 | kw match | 293 | kw match |
329 | kw while | 294 | kw while |
@@ -370,49 +335,6 @@ fn quux() -> i32 { | |||
370 | } | 335 | } |
371 | 336 | ||
372 | #[test] | 337 | #[test] |
373 | fn test_keywords_in_trait_def() { | ||
374 | check( | ||
375 | r"trait My { $0 }", | ||
376 | expect![[r#" | ||
377 | kw unsafe | ||
378 | kw fn | ||
379 | kw const | ||
380 | kw type | ||
381 | "#]], | ||
382 | ); | ||
383 | } | ||
384 | |||
385 | #[test] | ||
386 | fn test_keywords_in_impl_def() { | ||
387 | check( | ||
388 | r"impl My { $0 }", | ||
389 | expect![[r#" | ||
390 | kw pub(crate) | ||
391 | kw pub | ||
392 | kw unsafe | ||
393 | kw fn | ||
394 | kw const | ||
395 | kw type | ||
396 | "#]], | ||
397 | ); | ||
398 | } | ||
399 | |||
400 | #[test] | ||
401 | fn test_keywords_in_impl_def_with_attr() { | ||
402 | check( | ||
403 | r"impl My { #[foo] $0 }", | ||
404 | expect![[r#" | ||
405 | kw pub(crate) | ||
406 | kw pub | ||
407 | kw unsafe | ||
408 | kw fn | ||
409 | kw const | ||
410 | kw type | ||
411 | "#]], | ||
412 | ); | ||
413 | } | ||
414 | |||
415 | #[test] | ||
416 | fn test_keywords_in_loop() { | 338 | fn test_keywords_in_loop() { |
417 | check( | 339 | check( |
418 | r"fn my() { loop { $0 } }", | 340 | r"fn my() { loop { $0 } }", |
@@ -421,11 +343,11 @@ fn quux() -> i32 { | |||
421 | kw fn | 343 | kw fn |
422 | kw const | 344 | kw const |
423 | kw type | 345 | kw type |
424 | kw use | ||
425 | kw impl | 346 | kw impl |
347 | kw extern | ||
348 | kw use | ||
426 | kw trait | 349 | kw trait |
427 | kw static | 350 | kw static |
428 | kw extern | ||
429 | kw mod | 351 | kw mod |
430 | kw match | 352 | kw match |
431 | kw while | 353 | kw while |
@@ -443,18 +365,6 @@ fn quux() -> i32 { | |||
443 | } | 365 | } |
444 | 366 | ||
445 | #[test] | 367 | #[test] |
446 | fn test_keywords_after_unsafe_in_item_list() { | ||
447 | check( | ||
448 | r"unsafe $0", | ||
449 | expect![[r#" | ||
450 | kw fn | ||
451 | kw trait | ||
452 | kw impl | ||
453 | "#]], | ||
454 | ); | ||
455 | } | ||
456 | |||
457 | #[test] | ||
458 | fn test_keywords_after_unsafe_in_block_expr() { | 368 | fn test_keywords_after_unsafe_in_block_expr() { |
459 | check( | 369 | check( |
460 | r"fn my_fn() { unsafe $0 }", | 370 | r"fn my_fn() { unsafe $0 }", |
@@ -467,44 +377,6 @@ fn quux() -> i32 { | |||
467 | } | 377 | } |
468 | 378 | ||
469 | #[test] | 379 | #[test] |
470 | fn test_mut_in_ref_and_in_fn_parameters_list() { | ||
471 | check( | ||
472 | r"fn my_fn(&$0) {}", | ||
473 | expect![[r#" | ||
474 | kw mut | ||
475 | "#]], | ||
476 | ); | ||
477 | check( | ||
478 | r"fn my_fn($0) {}", | ||
479 | expect![[r#" | ||
480 | kw mut | ||
481 | "#]], | ||
482 | ); | ||
483 | check( | ||
484 | r"fn my_fn() { let &$0 }", | ||
485 | expect![[r#" | ||
486 | kw mut | ||
487 | "#]], | ||
488 | ); | ||
489 | } | ||
490 | |||
491 | #[test] | ||
492 | fn test_where_keyword() { | ||
493 | check( | ||
494 | r"trait A $0", | ||
495 | expect![[r#" | ||
496 | kw where | ||
497 | "#]], | ||
498 | ); | ||
499 | check( | ||
500 | r"impl A $0", | ||
501 | expect![[r#" | ||
502 | kw where | ||
503 | "#]], | ||
504 | ); | ||
505 | } | ||
506 | |||
507 | #[test] | ||
508 | fn no_keyword_completion_in_comments() { | 380 | fn no_keyword_completion_in_comments() { |
509 | cov_mark::check!(no_keyword_completion_in_comments); | 381 | cov_mark::check!(no_keyword_completion_in_comments); |
510 | check( | 382 | check( |
@@ -536,17 +408,11 @@ Some multi-line comment$0 | |||
536 | fn test_completion_await_impls_future() { | 408 | fn test_completion_await_impls_future() { |
537 | check( | 409 | check( |
538 | r#" | 410 | r#" |
539 | //- /main.rs crate:main deps:std | 411 | //- minicore: future |
540 | use std::future::*; | 412 | use core::future::*; |
541 | struct A {} | 413 | struct A {} |
542 | impl Future for A {} | 414 | impl Future for A {} |
543 | fn foo(a: A) { a.$0 } | 415 | fn foo(a: A) { a.$0 } |
544 | |||
545 | //- /std/lib.rs crate:std | ||
546 | pub mod future { | ||
547 | #[lang = "future_trait"] | ||
548 | pub trait Future {} | ||
549 | } | ||
550 | "#, | 416 | "#, |
551 | expect![[r#" | 417 | expect![[r#" |
552 | kw await expr.await | 418 | kw await expr.await |
@@ -555,20 +421,12 @@ pub mod future { | |||
555 | 421 | ||
556 | check( | 422 | check( |
557 | r#" | 423 | r#" |
558 | //- /main.rs crate:main deps:std | 424 | //- minicore: future |
559 | use std::future::*; | 425 | use std::future::*; |
560 | fn foo() { | 426 | fn foo() { |
561 | let a = async {}; | 427 | let a = async {}; |
562 | a.$0 | 428 | a.$0 |
563 | } | 429 | } |
564 | |||
565 | //- /std/lib.rs crate:std | ||
566 | pub mod future { | ||
567 | #[lang = "future_trait"] | ||
568 | pub trait Future { | ||
569 | type Output; | ||
570 | } | ||
571 | } | ||
572 | "#, | 430 | "#, |
573 | expect![[r#" | 431 | expect![[r#" |
574 | kw await expr.await | 432 | kw await expr.await |
@@ -595,22 +453,6 @@ pub mod future { | |||
595 | } | 453 | } |
596 | 454 | ||
597 | #[test] | 455 | #[test] |
598 | fn before_field() { | ||
599 | check( | ||
600 | r#" | ||
601 | struct Foo { | ||
602 | $0 | ||
603 | pub f: i32, | ||
604 | } | ||
605 | "#, | ||
606 | expect![[r#" | ||
607 | kw pub(crate) | ||
608 | kw pub | ||
609 | "#]], | ||
610 | ) | ||
611 | } | ||
612 | |||
613 | #[test] | ||
614 | fn skip_struct_initializer() { | 456 | fn skip_struct_initializer() { |
615 | cov_mark::check!(no_keyword_completion_in_record_lit); | 457 | cov_mark::check!(no_keyword_completion_in_record_lit); |
616 | check( | 458 | check( |