diff options
Diffstat (limited to 'crates/ra_ide_api/src/completion/complete_dot.rs')
-rw-r--r-- | crates/ra_ide_api/src/completion/complete_dot.rs | 456 |
1 files changed, 0 insertions, 456 deletions
diff --git a/crates/ra_ide_api/src/completion/complete_dot.rs b/crates/ra_ide_api/src/completion/complete_dot.rs deleted file mode 100644 index b6fe48627..000000000 --- a/crates/ra_ide_api/src/completion/complete_dot.rs +++ /dev/null | |||
@@ -1,456 +0,0 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
3 | use hir::Type; | ||
4 | |||
5 | use crate::completion::completion_item::CompletionKind; | ||
6 | use crate::{ | ||
7 | completion::{completion_context::CompletionContext, completion_item::Completions}, | ||
8 | CompletionItem, | ||
9 | }; | ||
10 | use rustc_hash::FxHashSet; | ||
11 | |||
12 | /// Complete dot accesses, i.e. fields or methods (and .await syntax). | ||
13 | pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) { | ||
14 | let dot_receiver = match &ctx.dot_receiver { | ||
15 | Some(expr) => expr, | ||
16 | _ => return, | ||
17 | }; | ||
18 | |||
19 | let receiver_ty = match ctx.analyzer.type_of(ctx.db, &dot_receiver) { | ||
20 | Some(ty) => ty, | ||
21 | _ => return, | ||
22 | }; | ||
23 | |||
24 | if !ctx.is_call { | ||
25 | complete_fields(acc, ctx, &receiver_ty); | ||
26 | } | ||
27 | complete_methods(acc, ctx, &receiver_ty); | ||
28 | |||
29 | // Suggest .await syntax for types that implement Future trait | ||
30 | if ctx.analyzer.impls_future(ctx.db, receiver_ty.into_ty()) { | ||
31 | CompletionItem::new(CompletionKind::Keyword, ctx.source_range(), "await") | ||
32 | .detail("expr.await") | ||
33 | .insert_text("await") | ||
34 | .add_to(acc); | ||
35 | } | ||
36 | } | ||
37 | |||
38 | fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: &Type) { | ||
39 | for receiver in receiver.autoderef(ctx.db) { | ||
40 | for (field, ty) in receiver.fields(ctx.db) { | ||
41 | acc.add_field(ctx, field, &ty); | ||
42 | } | ||
43 | for (i, ty) in receiver.tuple_fields(ctx.db).into_iter().enumerate() { | ||
44 | acc.add_tuple_field(ctx, i, &ty); | ||
45 | } | ||
46 | } | ||
47 | } | ||
48 | |||
49 | fn complete_methods(acc: &mut Completions, ctx: &CompletionContext, receiver: &Type) { | ||
50 | let mut seen_methods = FxHashSet::default(); | ||
51 | ctx.analyzer.iterate_method_candidates(ctx.db, receiver, None, |_ty, func| { | ||
52 | if func.has_self_param(ctx.db) && seen_methods.insert(func.name(ctx.db)) { | ||
53 | acc.add_function(ctx, func); | ||
54 | } | ||
55 | None::<()> | ||
56 | }); | ||
57 | } | ||
58 | |||
59 | #[cfg(test)] | ||
60 | mod tests { | ||
61 | use crate::completion::{do_completion, CompletionItem, CompletionKind}; | ||
62 | use insta::assert_debug_snapshot; | ||
63 | |||
64 | fn do_ref_completion(code: &str) -> Vec<CompletionItem> { | ||
65 | do_completion(code, CompletionKind::Reference) | ||
66 | } | ||
67 | |||
68 | #[test] | ||
69 | fn test_struct_field_completion() { | ||
70 | assert_debug_snapshot!( | ||
71 | do_ref_completion( | ||
72 | r" | ||
73 | struct A { the_field: u32 } | ||
74 | fn foo(a: A) { | ||
75 | a.<|> | ||
76 | } | ||
77 | ", | ||
78 | ), | ||
79 | @r###" | ||
80 | [ | ||
81 | CompletionItem { | ||
82 | label: "the_field", | ||
83 | source_range: [94; 94), | ||
84 | delete: [94; 94), | ||
85 | insert: "the_field", | ||
86 | kind: Field, | ||
87 | detail: "u32", | ||
88 | }, | ||
89 | ] | ||
90 | "### | ||
91 | ); | ||
92 | } | ||
93 | |||
94 | #[test] | ||
95 | fn test_struct_field_completion_self() { | ||
96 | assert_debug_snapshot!( | ||
97 | do_ref_completion( | ||
98 | r" | ||
99 | struct A { | ||
100 | /// This is the_field | ||
101 | the_field: (u32,) | ||
102 | } | ||
103 | impl A { | ||
104 | fn foo(self) { | ||
105 | self.<|> | ||
106 | } | ||
107 | } | ||
108 | ", | ||
109 | ), | ||
110 | @r###" | ||
111 | [ | ||
112 | CompletionItem { | ||
113 | label: "foo()", | ||
114 | source_range: [187; 187), | ||
115 | delete: [187; 187), | ||
116 | insert: "foo()$0", | ||
117 | kind: Method, | ||
118 | lookup: "foo", | ||
119 | detail: "fn foo(self)", | ||
120 | }, | ||
121 | CompletionItem { | ||
122 | label: "the_field", | ||
123 | source_range: [187; 187), | ||
124 | delete: [187; 187), | ||
125 | insert: "the_field", | ||
126 | kind: Field, | ||
127 | detail: "(u32,)", | ||
128 | documentation: Documentation( | ||
129 | "This is the_field", | ||
130 | ), | ||
131 | }, | ||
132 | ] | ||
133 | "### | ||
134 | ); | ||
135 | } | ||
136 | |||
137 | #[test] | ||
138 | fn test_struct_field_completion_autoderef() { | ||
139 | assert_debug_snapshot!( | ||
140 | do_ref_completion( | ||
141 | r" | ||
142 | struct A { the_field: (u32, i32) } | ||
143 | impl A { | ||
144 | fn foo(&self) { | ||
145 | self.<|> | ||
146 | } | ||
147 | } | ||
148 | ", | ||
149 | ), | ||
150 | @r###" | ||
151 | [ | ||
152 | CompletionItem { | ||
153 | label: "foo()", | ||
154 | source_range: [126; 126), | ||
155 | delete: [126; 126), | ||
156 | insert: "foo()$0", | ||
157 | kind: Method, | ||
158 | lookup: "foo", | ||
159 | detail: "fn foo(&self)", | ||
160 | }, | ||
161 | CompletionItem { | ||
162 | label: "the_field", | ||
163 | source_range: [126; 126), | ||
164 | delete: [126; 126), | ||
165 | insert: "the_field", | ||
166 | kind: Field, | ||
167 | detail: "(u32, i32)", | ||
168 | }, | ||
169 | ] | ||
170 | "### | ||
171 | ); | ||
172 | } | ||
173 | |||
174 | #[test] | ||
175 | fn test_no_struct_field_completion_for_method_call() { | ||
176 | assert_debug_snapshot!( | ||
177 | do_ref_completion( | ||
178 | r" | ||
179 | struct A { the_field: u32 } | ||
180 | fn foo(a: A) { | ||
181 | a.<|>() | ||
182 | } | ||
183 | ", | ||
184 | ), | ||
185 | @"[]" | ||
186 | ); | ||
187 | } | ||
188 | |||
189 | #[test] | ||
190 | fn test_method_completion() { | ||
191 | assert_debug_snapshot!( | ||
192 | do_ref_completion( | ||
193 | r" | ||
194 | struct A {} | ||
195 | impl A { | ||
196 | fn the_method(&self) {} | ||
197 | } | ||
198 | fn foo(a: A) { | ||
199 | a.<|> | ||
200 | } | ||
201 | ", | ||
202 | ), | ||
203 | @r###" | ||
204 | [ | ||
205 | CompletionItem { | ||
206 | label: "the_method()", | ||
207 | source_range: [144; 144), | ||
208 | delete: [144; 144), | ||
209 | insert: "the_method()$0", | ||
210 | kind: Method, | ||
211 | lookup: "the_method", | ||
212 | detail: "fn the_method(&self)", | ||
213 | }, | ||
214 | ] | ||
215 | "### | ||
216 | ); | ||
217 | } | ||
218 | |||
219 | #[test] | ||
220 | fn test_trait_method_completion() { | ||
221 | assert_debug_snapshot!( | ||
222 | do_ref_completion( | ||
223 | r" | ||
224 | struct A {} | ||
225 | trait Trait { fn the_method(&self); } | ||
226 | impl Trait for A {} | ||
227 | fn foo(a: A) { | ||
228 | a.<|> | ||
229 | } | ||
230 | ", | ||
231 | ), | ||
232 | @r###" | ||
233 | [ | ||
234 | CompletionItem { | ||
235 | label: "the_method()", | ||
236 | source_range: [151; 151), | ||
237 | delete: [151; 151), | ||
238 | insert: "the_method()$0", | ||
239 | kind: Method, | ||
240 | lookup: "the_method", | ||
241 | detail: "fn the_method(&self)", | ||
242 | }, | ||
243 | ] | ||
244 | "### | ||
245 | ); | ||
246 | } | ||
247 | |||
248 | #[test] | ||
249 | fn test_trait_method_completion_deduplicated() { | ||
250 | assert_debug_snapshot!( | ||
251 | do_ref_completion( | ||
252 | r" | ||
253 | struct A {} | ||
254 | trait Trait { fn the_method(&self); } | ||
255 | impl<T> Trait for T {} | ||
256 | fn foo(a: &A) { | ||
257 | a.<|> | ||
258 | } | ||
259 | ", | ||
260 | ), | ||
261 | @r###" | ||
262 | [ | ||
263 | CompletionItem { | ||
264 | label: "the_method()", | ||
265 | source_range: [155; 155), | ||
266 | delete: [155; 155), | ||
267 | insert: "the_method()$0", | ||
268 | kind: Method, | ||
269 | lookup: "the_method", | ||
270 | detail: "fn the_method(&self)", | ||
271 | }, | ||
272 | ] | ||
273 | "### | ||
274 | ); | ||
275 | } | ||
276 | |||
277 | #[test] | ||
278 | fn test_no_non_self_method() { | ||
279 | assert_debug_snapshot!( | ||
280 | do_ref_completion( | ||
281 | r" | ||
282 | struct A {} | ||
283 | impl A { | ||
284 | fn the_method() {} | ||
285 | } | ||
286 | fn foo(a: A) { | ||
287 | a.<|> | ||
288 | } | ||
289 | ", | ||
290 | ), | ||
291 | @"[]" | ||
292 | ); | ||
293 | } | ||
294 | |||
295 | #[test] | ||
296 | fn test_method_attr_filtering() { | ||
297 | assert_debug_snapshot!( | ||
298 | do_ref_completion( | ||
299 | r" | ||
300 | struct A {} | ||
301 | impl A { | ||
302 | #[inline] | ||
303 | fn the_method(&self) { | ||
304 | let x = 1; | ||
305 | let y = 2; | ||
306 | } | ||
307 | } | ||
308 | fn foo(a: A) { | ||
309 | a.<|> | ||
310 | } | ||
311 | ", | ||
312 | ), | ||
313 | @r###" | ||
314 | [ | ||
315 | CompletionItem { | ||
316 | label: "the_method()", | ||
317 | source_range: [249; 249), | ||
318 | delete: [249; 249), | ||
319 | insert: "the_method()$0", | ||
320 | kind: Method, | ||
321 | lookup: "the_method", | ||
322 | detail: "fn the_method(&self)", | ||
323 | }, | ||
324 | ] | ||
325 | "### | ||
326 | ); | ||
327 | } | ||
328 | |||
329 | #[test] | ||
330 | fn test_tuple_field_completion() { | ||
331 | assert_debug_snapshot!( | ||
332 | do_ref_completion( | ||
333 | r" | ||
334 | fn foo() { | ||
335 | let b = (0, 3.14); | ||
336 | b.<|> | ||
337 | } | ||
338 | ", | ||
339 | ), | ||
340 | @r###" | ||
341 | [ | ||
342 | CompletionItem { | ||
343 | label: "0", | ||
344 | source_range: [75; 75), | ||
345 | delete: [75; 75), | ||
346 | insert: "0", | ||
347 | kind: Field, | ||
348 | detail: "i32", | ||
349 | }, | ||
350 | CompletionItem { | ||
351 | label: "1", | ||
352 | source_range: [75; 75), | ||
353 | delete: [75; 75), | ||
354 | insert: "1", | ||
355 | kind: Field, | ||
356 | detail: "f64", | ||
357 | }, | ||
358 | ] | ||
359 | "### | ||
360 | ); | ||
361 | } | ||
362 | |||
363 | #[test] | ||
364 | fn test_tuple_field_inference() { | ||
365 | assert_debug_snapshot!( | ||
366 | do_ref_completion( | ||
367 | r" | ||
368 | pub struct S; | ||
369 | impl S { | ||
370 | pub fn blah(&self) {} | ||
371 | } | ||
372 | |||
373 | struct T(S); | ||
374 | |||
375 | impl T { | ||
376 | fn foo(&self) { | ||
377 | // FIXME: This doesn't work without the trailing `a` as `0.` is a float | ||
378 | self.0.a<|> | ||
379 | } | ||
380 | } | ||
381 | ", | ||
382 | ), | ||
383 | @r###" | ||
384 | [ | ||
385 | CompletionItem { | ||
386 | label: "blah()", | ||
387 | source_range: [299; 300), | ||
388 | delete: [299; 300), | ||
389 | insert: "blah()$0", | ||
390 | kind: Method, | ||
391 | lookup: "blah", | ||
392 | detail: "pub fn blah(&self)", | ||
393 | }, | ||
394 | ] | ||
395 | "### | ||
396 | ); | ||
397 | } | ||
398 | |||
399 | #[test] | ||
400 | fn test_completion_works_in_consts() { | ||
401 | assert_debug_snapshot!( | ||
402 | do_ref_completion( | ||
403 | r" | ||
404 | struct A { the_field: u32 } | ||
405 | const X: u32 = { | ||
406 | A { the_field: 92 }.<|> | ||
407 | }; | ||
408 | ", | ||
409 | ), | ||
410 | @r###" | ||
411 | [ | ||
412 | CompletionItem { | ||
413 | label: "the_field", | ||
414 | source_range: [106; 106), | ||
415 | delete: [106; 106), | ||
416 | insert: "the_field", | ||
417 | kind: Field, | ||
418 | detail: "u32", | ||
419 | }, | ||
420 | ] | ||
421 | "### | ||
422 | ); | ||
423 | } | ||
424 | |||
425 | #[test] | ||
426 | fn test_completion_await_impls_future() { | ||
427 | assert_debug_snapshot!( | ||
428 | do_completion( | ||
429 | r###" | ||
430 | //- /main.rs | ||
431 | use std::future::*; | ||
432 | struct A {} | ||
433 | impl Future for A {} | ||
434 | fn foo(a: A) { | ||
435 | a.<|> | ||
436 | } | ||
437 | |||
438 | //- /std/lib.rs | ||
439 | pub mod future { | ||
440 | pub trait Future {} | ||
441 | } | ||
442 | "###, CompletionKind::Keyword), | ||
443 | @r###" | ||
444 | [ | ||
445 | CompletionItem { | ||
446 | label: "await", | ||
447 | source_range: [74; 74), | ||
448 | delete: [74; 74), | ||
449 | insert: "await", | ||
450 | detail: "expr.await", | ||
451 | }, | ||
452 | ] | ||
453 | "### | ||
454 | ) | ||
455 | } | ||
456 | } | ||