]> git.lizzy.rs Git - rust.git/blob - crates/ide_completion/src/completions/lifetime.rs
5eeddf7a401aa79585be2d0d96b57991a3130d68
[rust.git] / crates / ide_completion / src / completions / lifetime.rs
1 //! Completes lifetimes and labels.
2 use hir::ScopeDef;
3
4 use crate::{completions::Completions, context::CompletionContext};
5
6 /// Completes lifetimes.
7 pub(crate) fn complete_lifetime(acc: &mut Completions, ctx: &CompletionContext) {
8     if !ctx.lifetime_allowed {
9         return;
10     }
11     let param_lifetime = match (
12         &ctx.lifetime_syntax,
13         ctx.lifetime_param_syntax.as_ref().and_then(|lp| lp.lifetime()),
14     ) {
15         (Some(lt), Some(lp)) if lp == lt.clone() => return,
16         (Some(_), Some(lp)) => Some(lp.to_string()),
17         _ => None,
18     };
19
20     ctx.scope.process_all_names(&mut |name, res| {
21         if let ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_)) = res {
22             if param_lifetime != Some(name.to_string()) {
23                 acc.add_resolution(ctx, name.to_string(), &res);
24             }
25         }
26     });
27     if param_lifetime.is_none() {
28         acc.add_static_lifetime(ctx);
29     }
30 }
31
32 /// Completes labels.
33 pub(crate) fn complete_label(acc: &mut Completions, ctx: &CompletionContext) {
34     if !ctx.is_label_ref {
35         return;
36     }
37     ctx.scope.process_all_names(&mut |name, res| {
38         if let ScopeDef::Label(_) = res {
39             acc.add_resolution(ctx, name.to_string(), &res);
40         }
41     });
42 }
43
44 #[cfg(test)]
45 mod tests {
46     use expect_test::{expect, Expect};
47
48     use crate::{
49         test_utils::{check_edit, completion_list_with_config, TEST_CONFIG},
50         CompletionConfig, CompletionKind,
51     };
52
53     fn check(ra_fixture: &str, expect: Expect) {
54         check_with_config(TEST_CONFIG, ra_fixture, expect);
55     }
56
57     fn check_with_config(config: CompletionConfig, ra_fixture: &str, expect: Expect) {
58         let actual = completion_list_with_config(config, ra_fixture, CompletionKind::Reference);
59         expect.assert_eq(&actual)
60     }
61
62     #[test]
63     fn check_lifetime_edit() {
64         check_edit(
65             "'lifetime",
66             r#"
67 fn func<'lifetime>(foo: &'li$0) {}
68 "#,
69             r#"
70 fn func<'lifetime>(foo: &'lifetime) {}
71 "#,
72         );
73         cov_mark::check!(completes_if_lifetime_without_idents);
74         check_edit(
75             "'lifetime",
76             r#"
77 fn func<'lifetime>(foo: &'$0) {}
78 "#,
79             r#"
80 fn func<'lifetime>(foo: &'lifetime) {}
81 "#,
82         );
83     }
84
85     #[test]
86     fn complete_lifetime_in_ref() {
87         check(
88             r#"
89 fn foo<'lifetime>(foo: &'a$0 usize) {}
90 "#,
91             expect![[r#"
92                 lt 'lifetime
93                 lt 'static
94             "#]],
95         );
96     }
97
98     #[test]
99     fn complete_lifetime_in_ref_missing_ty() {
100         check(
101             r#"
102 fn foo<'lifetime>(foo: &'a$0) {}
103 "#,
104             expect![[r#"
105                 lt 'lifetime
106                 lt 'static
107             "#]],
108         );
109     }
110     #[test]
111     fn complete_lifetime_in_self_ref() {
112         check(
113             r#"
114 struct Foo;
115 impl<'impl> Foo {
116     fn foo<'func>(&'a$0 self) {}
117 }
118 "#,
119             expect![[r#"
120                 lt 'func
121                 lt 'impl
122                 lt 'static
123             "#]],
124         );
125     }
126
127     #[test]
128     fn complete_lifetime_in_arg_list() {
129         check(
130             r#"
131 struct Foo<'lt>;
132 fn foo<'lifetime>(_: Foo<'a$0>) {}
133 "#,
134             expect![[r#"
135                 lt 'lifetime
136                 lt 'static
137             "#]],
138         );
139     }
140
141     #[test]
142     fn complete_lifetime_in_where_pred() {
143         check(
144             r#"
145 fn foo2<'lifetime, T>() where 'a$0 {}
146 "#,
147             expect![[r#"
148                 lt 'lifetime
149                 lt 'static
150             "#]],
151         );
152     }
153
154     #[test]
155     fn complete_lifetime_in_ty_bound() {
156         check(
157             r#"
158 fn foo2<'lifetime, T>() where T: 'a$0 {}
159 "#,
160             expect![[r#"
161                 lt 'lifetime
162                 lt 'static
163             "#]],
164         );
165         check(
166             r#"
167 fn foo2<'lifetime, T>() where T: Trait<'a$0> {}
168 "#,
169             expect![[r#"
170                 lt 'lifetime
171                 lt 'static
172             "#]],
173         );
174     }
175
176     #[test]
177     fn dont_complete_lifetime_in_assoc_ty_bound() {
178         check(
179             r#"
180 fn foo2<'lifetime, T>() where T: Trait<Item = 'a$0> {}
181 "#,
182             expect![[r#""#]],
183         );
184     }
185
186     #[test]
187     fn complete_lifetime_in_param_list() {
188         check(
189             r#"
190 fn foo<'a$0>() {}
191 "#,
192             expect![[r#""#]],
193         );
194         check(
195             r#"
196 fn foo<'footime, 'lifetime: 'a$0>() {}
197 "#,
198             expect![[r#"
199                 lt 'footime
200             "#]],
201         );
202     }
203
204     #[test]
205     fn check_label_edit() {
206         check_edit(
207             "'label",
208             r#"
209 fn foo() {
210     'label: loop {
211         break '$0
212     }
213 }
214 "#,
215             r#"
216 fn foo() {
217     'label: loop {
218         break 'label
219     }
220 }
221 "#,
222         );
223     }
224
225     #[test]
226     fn complete_label_in_loop() {
227         check(
228             r#"
229 fn foo() {
230     'foop: loop {
231         break '$0
232     }
233 }
234 "#,
235             expect![[r#"
236                 lb 'foop
237             "#]],
238         );
239         check(
240             r#"
241 fn foo() {
242     'foop: loop {
243         continue '$0
244     }
245 }
246 "#,
247             expect![[r#"
248                 lb 'foop
249             "#]],
250         );
251     }
252
253     #[test]
254     fn complete_label_in_block_nested() {
255         check(
256             r#"
257 fn foo() {
258     'foop: {
259         'baap: {
260             break '$0
261         }
262     }
263 }
264 "#,
265             expect![[r#"
266                 lb 'baap
267                 lb 'foop
268             "#]],
269         );
270     }
271
272     #[test]
273     fn complete_label_in_loop_with_value() {
274         check(
275             r#"
276 fn foo() {
277     'foop: loop {
278         break '$0 i32;
279     }
280 }
281 "#,
282             expect![[r#"
283                 lb 'foop
284             "#]],
285         );
286     }
287
288     #[test]
289     fn complete_label_in_while_cond() {
290         check(
291             r#"
292 fn foo() {
293     'outer: while { 'inner: loop { break '$0 } } {}
294 }
295 "#,
296             expect![[r#"
297                 lb 'inner
298                 lb 'outer
299             "#]],
300         );
301     }
302
303     #[test]
304     fn complete_label_in_for_iterable() {
305         check(
306             r#"
307 fn foo() {
308     'outer: for _ in [{ 'inner: loop { break '$0 } }] {}
309 }
310 "#,
311             expect![[r#"
312                 lb 'inner
313             "#]],
314         );
315     }
316 }