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