diff options
Diffstat (limited to 'crates/ide_completion/src/completions')
-rw-r--r-- | crates/ide_completion/src/completions/lifetime.rs | 285 | ||||
-rw-r--r-- | crates/ide_completion/src/completions/pattern.rs | 2 |
2 files changed, 286 insertions, 1 deletions
diff --git a/crates/ide_completion/src/completions/lifetime.rs b/crates/ide_completion/src/completions/lifetime.rs new file mode 100644 index 000000000..628c1fb9b --- /dev/null +++ b/crates/ide_completion/src/completions/lifetime.rs | |||
@@ -0,0 +1,285 @@ | |||
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 | } | ||
74 | |||
75 | #[test] | ||
76 | fn complete_lifetime_in_ref() { | ||
77 | check( | ||
78 | r#" | ||
79 | fn foo<'lifetime>(foo: &'a$0 usize) {} | ||
80 | "#, | ||
81 | expect![[r#" | ||
82 | lt 'lifetime | ||
83 | lt 'static | ||
84 | "#]], | ||
85 | ); | ||
86 | } | ||
87 | |||
88 | #[test] | ||
89 | fn complete_lifetime_in_ref_missing_ty() { | ||
90 | check( | ||
91 | r#" | ||
92 | fn foo<'lifetime>(foo: &'a$0) {} | ||
93 | "#, | ||
94 | expect![[r#" | ||
95 | lt 'lifetime | ||
96 | lt 'static | ||
97 | "#]], | ||
98 | ); | ||
99 | } | ||
100 | #[test] | ||
101 | fn complete_lifetime_in_self_ref() { | ||
102 | check( | ||
103 | r#" | ||
104 | struct Foo; | ||
105 | impl<'impl> Foo { | ||
106 | fn foo<'func>(&'a$0 self) {} | ||
107 | } | ||
108 | "#, | ||
109 | expect![[r#" | ||
110 | lt 'func | ||
111 | lt 'impl | ||
112 | lt 'static | ||
113 | "#]], | ||
114 | ); | ||
115 | } | ||
116 | |||
117 | #[test] | ||
118 | fn complete_lifetime_in_arg_list() { | ||
119 | check( | ||
120 | r#" | ||
121 | struct Foo<'lt>; | ||
122 | fn foo<'lifetime>(_: Foo<'a$0>) {} | ||
123 | "#, | ||
124 | expect![[r#" | ||
125 | lt 'lifetime | ||
126 | lt 'static | ||
127 | "#]], | ||
128 | ); | ||
129 | } | ||
130 | |||
131 | #[test] | ||
132 | fn complete_lifetime_in_where_pred() { | ||
133 | check( | ||
134 | r#" | ||
135 | fn foo2<'lifetime, T>() where 'a$0 {} | ||
136 | "#, | ||
137 | expect![[r#" | ||
138 | lt 'lifetime | ||
139 | lt 'static | ||
140 | "#]], | ||
141 | ); | ||
142 | } | ||
143 | |||
144 | #[test] | ||
145 | fn complete_lifetime_in_ty_bound() { | ||
146 | check( | ||
147 | r#" | ||
148 | fn foo2<'lifetime, T>() where T: 'a$0 {} | ||
149 | "#, | ||
150 | expect![[r#" | ||
151 | lt 'lifetime | ||
152 | lt 'static | ||
153 | "#]], | ||
154 | ); | ||
155 | check( | ||
156 | r#" | ||
157 | fn foo2<'lifetime, T>() where T: Trait<'a$0> {} | ||
158 | "#, | ||
159 | expect![[r#" | ||
160 | lt 'lifetime | ||
161 | lt 'static | ||
162 | "#]], | ||
163 | ); | ||
164 | } | ||
165 | |||
166 | #[test] | ||
167 | fn dont_complete_lifetime_in_assoc_ty_bound() { | ||
168 | check( | ||
169 | r#" | ||
170 | fn foo2<'lifetime, T>() where T: Trait<Item = 'a$0> {} | ||
171 | "#, | ||
172 | expect![[r#""#]], | ||
173 | ); | ||
174 | } | ||
175 | |||
176 | #[test] | ||
177 | fn complete_lifetime_in_param_list() { | ||
178 | check( | ||
179 | r#" | ||
180 | fn foo<'a$0>() {} | ||
181 | "#, | ||
182 | expect![[r#""#]], | ||
183 | ); | ||
184 | check( | ||
185 | r#" | ||
186 | fn foo<'footime, 'lifetime: 'a$0>() {} | ||
187 | "#, | ||
188 | expect![[r#" | ||
189 | lt 'footime | ||
190 | "#]], | ||
191 | ); | ||
192 | } | ||
193 | |||
194 | #[test] | ||
195 | fn complete_label_in_loop() { | ||
196 | check( | ||
197 | r#" | ||
198 | fn foo() { | ||
199 | 'foop: loop { | ||
200 | break '$0 | ||
201 | } | ||
202 | } | ||
203 | "#, | ||
204 | expect![[r#" | ||
205 | lb 'foop | ||
206 | "#]], | ||
207 | ); | ||
208 | check( | ||
209 | r#" | ||
210 | fn foo() { | ||
211 | 'foop: loop { | ||
212 | continue '$0 | ||
213 | } | ||
214 | } | ||
215 | "#, | ||
216 | expect![[r#" | ||
217 | lb 'foop | ||
218 | "#]], | ||
219 | ); | ||
220 | } | ||
221 | |||
222 | #[test] | ||
223 | fn complete_label_in_block_nested() { | ||
224 | check( | ||
225 | r#" | ||
226 | fn foo() { | ||
227 | 'foop: { | ||
228 | 'baap: { | ||
229 | break '$0 | ||
230 | } | ||
231 | } | ||
232 | } | ||
233 | "#, | ||
234 | expect![[r#" | ||
235 | lb 'baap | ||
236 | lb 'foop | ||
237 | "#]], | ||
238 | ); | ||
239 | } | ||
240 | |||
241 | #[test] | ||
242 | fn complete_label_in_loop_with_value() { | ||
243 | check( | ||
244 | r#" | ||
245 | fn foo() { | ||
246 | 'foop: loop { | ||
247 | break '$0 i32; | ||
248 | } | ||
249 | } | ||
250 | "#, | ||
251 | expect![[r#" | ||
252 | lb 'foop | ||
253 | "#]], | ||
254 | ); | ||
255 | } | ||
256 | |||
257 | #[test] | ||
258 | fn complete_label_in_while_cond() { | ||
259 | check( | ||
260 | r#" | ||
261 | fn foo() { | ||
262 | 'outer: while { 'inner: loop { break '$0 } } {} | ||
263 | } | ||
264 | "#, | ||
265 | expect![[r#" | ||
266 | lb 'inner | ||
267 | lb 'outer | ||
268 | "#]], | ||
269 | ); | ||
270 | } | ||
271 | |||
272 | #[test] | ||
273 | fn complete_label_in_for_iterable() { | ||
274 | check( | ||
275 | r#" | ||
276 | fn foo() { | ||
277 | 'outer: for _ in [{ 'inner: loop { break '$0 } }] {} | ||
278 | } | ||
279 | "#, | ||
280 | expect![[r#" | ||
281 | lb 'inner | ||
282 | "#]], | ||
283 | ); | ||
284 | } | ||
285 | } | ||
diff --git a/crates/ide_completion/src/completions/pattern.rs b/crates/ide_completion/src/completions/pattern.rs index 476eecff0..b06498e6d 100644 --- a/crates/ide_completion/src/completions/pattern.rs +++ b/crates/ide_completion/src/completions/pattern.rs | |||
@@ -1,4 +1,4 @@ | |||
1 | //! Completes constats and paths in patterns. | 1 | //! Completes constants and paths in patterns. |
2 | 2 | ||
3 | use crate::{CompletionContext, Completions}; | 3 | use crate::{CompletionContext, Completions}; |
4 | 4 | ||