ide_completion/completions/
keyword.rs

1//! Completes `where` and `for` keywords.
2
3use syntax::ast::{self, Item};
4
5use crate::{CompletionContext, Completions};
6
7pub(crate) fn complete_for_and_where(
8    acc: &mut Completions,
9    ctx: &CompletionContext<'_>,
10    keyword_item: &ast::Item,
11) {
12    let mut add_keyword = |kw, snippet| acc.add_keyword_snippet(ctx, kw, snippet);
13
14    match keyword_item {
15        Item::Impl(it) => {
16            if it.for_token().is_none() && it.trait_().is_none() && it.self_ty().is_some() {
17                add_keyword("for", "for $0");
18            }
19            add_keyword("where", "where $0");
20        }
21        Item::Enum(_)
22        | Item::Fn(_)
23        | Item::Struct(_)
24        | Item::Trait(_)
25        | Item::TypeAlias(_)
26        | Item::Union(_) => {
27            add_keyword("where", "where $0");
28        }
29        _ => (),
30    }
31}
32
33#[cfg(test)]
34mod tests {
35    use expect_test::expect;
36
37    use crate::tests::{check, check_edit};
38
39    #[test]
40    fn test_else_edit_after_if() {
41        check_edit(
42            "else",
43            r#"fn quux() { if true { () } $0 }"#,
44            r#"fn quux() { if true { () } else {
45    $0
46} }"#,
47        );
48    }
49
50    #[test]
51    fn test_keywords_after_unsafe_in_block_expr() {
52        check(
53            r"fn my_fn() { unsafe $0 }",
54            expect![[r#"
55                kw async
56                kw extern
57                kw fn
58                kw impl
59                kw impl for
60                kw trait
61            "#]],
62        );
63    }
64
65    #[test]
66    fn test_completion_await_impls_future() {
67        check(
68            r#"
69//- minicore: future
70use core::future::*;
71struct A {}
72impl Future for A {}
73fn foo(a: A) { a.$0 }
74"#,
75            expect![[r#"
76                me into_future() (as IntoFuture) fn(self) -> <Self as IntoFuture>::IntoFuture
77                kw await                                                           expr.await
78                sn box                                                         Box::new(expr)
79                sn call                                                        function(expr)
80                sn const                                                             const {}
81                sn dbg                                                             dbg!(expr)
82                sn dbgr                                                           dbg!(&expr)
83                sn deref                                                                *expr
84                sn let                                                                    let
85                sn letm                                                               let mut
86                sn match                                                        match expr {}
87                sn ref                                                                  &expr
88                sn refm                                                             &mut expr
89                sn return                                                         return expr
90                sn unsafe                                                           unsafe {}
91            "#]],
92        );
93
94        check(
95            r#"
96//- minicore: future
97use std::future::*;
98fn foo() {
99    let a = async {};
100    a.$0
101}
102"#,
103            expect![[r#"
104                me into_future() (use core::future::IntoFuture) fn(self) -> <Self as IntoFuture>::IntoFuture
105                kw await                                                                          expr.await
106                sn box                                                                        Box::new(expr)
107                sn call                                                                       function(expr)
108                sn const                                                                            const {}
109                sn dbg                                                                            dbg!(expr)
110                sn dbgr                                                                          dbg!(&expr)
111                sn deref                                                                               *expr
112                sn let                                                                                   let
113                sn letm                                                                              let mut
114                sn match                                                                       match expr {}
115                sn ref                                                                                 &expr
116                sn refm                                                                            &mut expr
117                sn return                                                                        return expr
118                sn unsafe                                                                          unsafe {}
119            "#]],
120        );
121    }
122
123    #[test]
124    fn test_completion_await_impls_into_future() {
125        check(
126            r#"
127//- minicore: future
128use core::future::*;
129struct A {}
130impl IntoFuture for A {}
131fn foo(a: A) { a.$0 }
132"#,
133            expect![[r#"
134                me into_future() (as IntoFuture) fn(self) -> <Self as IntoFuture>::IntoFuture
135                kw await                                                           expr.await
136                sn box                                                         Box::new(expr)
137                sn call                                                        function(expr)
138                sn const                                                             const {}
139                sn dbg                                                             dbg!(expr)
140                sn dbgr                                                           dbg!(&expr)
141                sn deref                                                                *expr
142                sn let                                                                    let
143                sn letm                                                               let mut
144                sn match                                                        match expr {}
145                sn ref                                                                  &expr
146                sn refm                                                             &mut expr
147                sn return                                                         return expr
148                sn unsafe                                                           unsafe {}
149            "#]],
150        );
151    }
152
153    #[test]
154    fn for_in_impl() {
155        check_edit(
156            "for",
157            r#"
158struct X;
159impl X $0 {}
160"#,
161            r#"
162struct X;
163impl X for $0 {}
164"#,
165        );
166        check_edit(
167            "for",
168            r#"
169fn foo() {
170    struct X;
171    impl X $0 {}
172}
173"#,
174            r#"
175fn foo() {
176    struct X;
177    impl X for $0 {}
178}
179"#,
180        );
181        check_edit(
182            "for",
183            r#"
184fn foo() {
185    struct X;
186    impl X $0
187}
188"#,
189            r#"
190fn foo() {
191    struct X;
192    impl X for $0
193}
194"#,
195        );
196        check_edit(
197            "for",
198            r#"
199fn foo() {
200    struct X;
201    impl X { fn bar() { $0 } }
202}
203"#,
204            r#"
205fn foo() {
206    struct X;
207    impl X { fn bar() { for $1 in $2 {
208    $0
209} } }
210}
211"#,
212        );
213    }
214
215    #[test]
216    fn let_semi() {
217        cov_mark::check!(let_semi);
218        check_edit(
219            "match",
220            r#"
221fn main() { let x = $0 }
222"#,
223            r#"
224fn main() { let x = match $1 {
225    $0
226}; }
227"#,
228        );
229
230        check_edit(
231            "if",
232            r#"
233fn main() {
234    let x = $0
235    let y = 92;
236}
237"#,
238            r#"
239fn main() {
240    let x = if $1 {
241    $2
242} else {
243    $0
244};
245    let y = 92;
246}
247"#,
248        );
249
250        check_edit(
251            "else",
252            r#"
253fn main() {
254    let x = if true {
255        ()
256    } $0
257    let y = 92;
258}
259"#,
260            r#"
261fn main() {
262    let x = if true {
263        ()
264    } else {
265    $0
266};
267    let y = 92;
268}
269"#,
270        );
271
272        check_edit(
273            "else if",
274            r#"
275fn main() {
276    let x = if true {
277        ()
278    } $0 else {};
279}
280"#,
281            r#"
282fn main() {
283    let x = if true {
284        ()
285    } else if $1 {
286    $0
287} else {};
288}
289"#,
290        );
291
292        check_edit(
293            "else if",
294            r#"
295fn main() {
296    let x = if true {
297        ()
298    } $0 else if true {};
299}
300"#,
301            r#"
302fn main() {
303    let x = if true {
304        ()
305    } else if $1 {
306    $0
307} else if true {};
308}
309"#,
310        );
311
312        check_edit(
313            "else",
314            r#"
315fn main() {
316    let x = 2 $0
317    let y = 92;
318}
319"#,
320            r#"
321fn main() {
322    let x = 2 else {
323    $0
324};
325    let y = 92;
326}
327"#,
328        );
329
330        check_edit(
331            "loop",
332            r#"
333fn main() {
334    let x = $0
335    bar();
336}
337"#,
338            r#"
339fn main() {
340    let x = loop {
341    $0
342};
343    bar();
344}
345"#,
346        );
347
348        check_edit(
349            "loop",
350            r#"
351fn main() {
352    let x = &$0
353    bar();
354}
355"#,
356            r#"
357fn main() {
358    let x = &loop {
359    $0
360};
361    bar();
362}
363"#,
364        );
365
366        check_edit(
367            "loop",
368            r#"
369fn main() {
370    let x = -$0
371    bar();
372}
373"#,
374            r#"
375fn main() {
376    let x = -loop {
377    $0
378};
379    bar();
380}
381"#,
382        );
383
384        check_edit(
385            "loop",
386            r#"
387fn main() {
388    let x = 2 + $0
389    bar();
390}
391"#,
392            r#"
393fn main() {
394    let x = 2 + loop {
395    $0
396};
397    bar();
398}
399"#,
400        );
401    }
402
403    #[test]
404    fn if_completion_in_match_guard() {
405        check_edit(
406            "if",
407            r"
408fn main() {
409    match () {
410        () $0
411    }
412}
413",
414            r"
415fn main() {
416    match () {
417        () if $0
418    }
419}
420",
421        )
422    }
423
424    #[test]
425    fn if_completion_in_match_arm_expr() {
426        check_edit(
427            "if",
428            r"
429fn main() {
430    match () {
431        () => $0
432    }
433}
434",
435            r"
436fn main() {
437    match () {
438        () => if $1 {
439    $0
440}
441    }
442}
443",
444        )
445    }
446
447    #[test]
448    fn if_completion_in_match_arm_expr_block() {
449        check_edit(
450            "if",
451            r"
452fn main() {
453    match () {
454        () => {
455            $0
456        }
457    }
458}
459",
460            r"
461fn main() {
462    match () {
463        () => {
464            if $1 {
465    $0
466}
467        }
468    }
469}
470",
471        )
472    }
473
474    #[test]
475    fn if_completion_in_parameter() {
476        check_edit(
477            "if",
478            r"
479fn main() {
480    foo($0)
481}
482",
483            r"
484fn main() {
485    foo(if $1 {
486    $2
487} else {
488    $0
489})
490}
491",
492        );
493
494        check_edit(
495            "if",
496            r"
497fn main() {
498    foo($0, 2)
499}
500",
501            r"
502fn main() {
503    foo(if $1 {
504    $2
505} else {
506    $0
507}, 2)
508}
509",
510        );
511
512        check_edit(
513            "if",
514            r"
515fn main() {
516    foo(2, $0)
517}
518",
519            r"
520fn main() {
521    foo(2, if $1 {
522    $2
523} else {
524    $0
525})
526}
527",
528        );
529
530        check_edit(
531            "if let",
532            r"
533fn main() {
534    foo(2, $0)
535}
536",
537            r"
538fn main() {
539    foo(2, if let $1 = $2 {
540    $3
541} else {
542    $0
543})
544}
545",
546        );
547    }
548
549    #[test]
550    fn if_completion_in_let_statement() {
551        check_edit(
552            "if",
553            r"
554fn main() {
555    let x = $0;
556}
557",
558            r"
559fn main() {
560    let x = if $1 {
561    $2
562} else {
563    $0
564};
565}
566",
567        );
568
569        check_edit(
570            "if let",
571            r"
572fn main() {
573    let x = $0;
574}
575",
576            r"
577fn main() {
578    let x = if let $1 = $2 {
579    $3
580} else {
581    $0
582};
583}
584",
585        );
586    }
587
588    #[test]
589    fn if_completion_in_format() {
590        check_edit(
591            "if",
592            r#"
593//- minicore: fmt
594fn main() {
595    format_args!("{}", $0);
596}
597"#,
598            r#"
599fn main() {
600    format_args!("{}", if $1 {
601    $2
602} else {
603    $0
604});
605}
606"#,
607        );
608
609        check_edit(
610            "if",
611            r#"
612//- minicore: fmt
613fn main() {
614    format_args!("{}", if$0);
615}
616"#,
617            r#"
618fn main() {
619    format_args!("{}", if $1 {
620    $2
621} else {
622    $0
623});
624}
625"#,
626        );
627    }
628
629    #[test]
630    fn if_completion_in_value_expected_expressions() {
631        check_edit(
632            "if",
633            r#"
634fn main() {
635    2 + $0;
636}
637"#,
638            r#"
639fn main() {
640    2 + if $1 {
641    $2
642} else {
643    $0
644};
645}
646"#,
647        );
648
649        check_edit(
650            "if",
651            r#"
652fn main() {
653    -$0;
654}
655"#,
656            r#"
657fn main() {
658    -if $1 {
659    $2
660} else {
661    $0
662};
663}
664"#,
665        );
666
667        check_edit(
668            "if",
669            r#"
670fn main() {
671    return $0;
672}
673"#,
674            r#"
675fn main() {
676    return if $1 {
677    $2
678} else {
679    $0
680};
681}
682"#,
683        );
684
685        check_edit(
686            "if",
687            r#"
688fn main() {
689    loop {
690        break $0;
691    }
692}
693"#,
694            r#"
695fn main() {
696    loop {
697        break if $1 {
698    $2
699} else {
700    $0
701};
702    }
703}
704"#,
705        );
706
707        check_edit(
708            "if",
709            r#"
710struct Foo { x: i32 }
711fn main() {
712    Foo { x: $0 }
713}
714"#,
715            r#"
716struct Foo { x: i32 }
717fn main() {
718    Foo { x: if $1 {
719    $2
720} else {
721    $0
722} }
723}
724"#,
725        );
726    }
727
728    #[test]
729    fn completes_let_in_block() {
730        check_edit(
731            "let",
732            r#"
733fn main() {
734    $0
735}
736"#,
737            r#"
738fn main() {
739    let $1 = $0;
740}
741"#,
742        );
743        check_edit(
744            "letm",
745            r#"
746fn main() {
747    $0
748}
749"#,
750            r#"
751fn main() {
752    let mut $1 = $0;
753}
754"#,
755        );
756    }
757
758    #[test]
759    fn completes_let_in_condition() {
760        check_edit(
761            "let",
762            r#"
763fn main() {
764    if $0 {}
765}
766"#,
767            r#"
768fn main() {
769    if let $1 = $0 {}
770}
771"#,
772        );
773        check_edit(
774            "letm",
775            r#"
776fn main() {
777    if $0 {}
778}
779"#,
780            r#"
781fn main() {
782    if let mut $1 = $0 {}
783}
784"#,
785        );
786    }
787
788    #[test]
789    fn completes_let_in_no_empty_condition() {
790        check_edit(
791            "let",
792            r#"
793fn main() {
794    if $0x {}
795}
796"#,
797            r#"
798fn main() {
799    if let $1 = $0x {}
800}
801"#,
802        );
803        check_edit(
804            "letm",
805            r#"
806fn main() {
807    if $0x {}
808}
809"#,
810            r#"
811fn main() {
812    if let mut $1 = $0x {}
813}
814"#,
815        );
816    }
817
818    #[test]
819    fn completes_let_in_condition_block() {
820        check_edit(
821            "let",
822            r#"
823fn main() {
824    if { $0 } {}
825}
826"#,
827            r#"
828fn main() {
829    if { let $1 = $0; } {}
830}
831"#,
832        );
833        check_edit(
834            "letm",
835            r#"
836fn main() {
837    if { $0 } {}
838}
839"#,
840            r#"
841fn main() {
842    if { let mut $1 = $0; } {}
843}
844"#,
845        );
846    }
847}