diff options
author | Aleksey Kladov <[email protected]> | 2020-07-04 09:36:12 +0100 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2020-07-04 09:41:50 +0100 |
commit | f2f6a46aa4751393ae18e8b21aa631c9919c5f43 (patch) | |
tree | 6c0d0cbde03a3f593256d76e7ab3784349868a3b /crates | |
parent | caeddff5435d9cf604aac7af7b53cc4ac8bb4a13 (diff) |
Cleanup dot completiont tests
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ra_ide/src/completion/complete_dot.rs | 984 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/complete_keyword.rs | 35 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/complete_qualified_path.rs | 39 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/presentation.rs | 69 |
4 files changed, 407 insertions, 720 deletions
diff --git a/crates/ra_ide/src/completion/complete_dot.rs b/crates/ra_ide/src/completion/complete_dot.rs index 520652a37..667a8b949 100644 --- a/crates/ra_ide/src/completion/complete_dot.rs +++ b/crates/ra_ide/src/completion/complete_dot.rs | |||
@@ -2,16 +2,11 @@ | |||
2 | 2 | ||
3 | use hir::{HasVisibility, Type}; | 3 | use hir::{HasVisibility, Type}; |
4 | use rustc_hash::FxHashSet; | 4 | use rustc_hash::FxHashSet; |
5 | use test_utils::mark; | ||
5 | 6 | ||
6 | use crate::{ | 7 | use crate::completion::{completion_context::CompletionContext, completion_item::Completions}; |
7 | completion::{ | ||
8 | completion_context::CompletionContext, | ||
9 | completion_item::{CompletionKind, Completions}, | ||
10 | }, | ||
11 | CompletionItem, | ||
12 | }; | ||
13 | 8 | ||
14 | /// Complete dot accesses, i.e. fields or methods (and .await syntax). | 9 | /// Complete dot accesses, i.e. fields or methods. |
15 | pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) { | 10 | pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) { |
16 | let dot_receiver = match &ctx.dot_receiver { | 11 | let dot_receiver = match &ctx.dot_receiver { |
17 | Some(expr) => expr, | 12 | Some(expr) => expr, |
@@ -23,18 +18,12 @@ pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) { | |||
23 | _ => return, | 18 | _ => return, |
24 | }; | 19 | }; |
25 | 20 | ||
26 | if !ctx.is_call { | 21 | if ctx.is_call { |
22 | mark::hit!(test_no_struct_field_completion_for_method_call); | ||
23 | } else { | ||
27 | complete_fields(acc, ctx, &receiver_ty); | 24 | complete_fields(acc, ctx, &receiver_ty); |
28 | } | 25 | } |
29 | complete_methods(acc, ctx, &receiver_ty); | 26 | complete_methods(acc, ctx, &receiver_ty); |
30 | |||
31 | // Suggest .await syntax for types that implement Future trait | ||
32 | if receiver_ty.impls_future(ctx.db) { | ||
33 | CompletionItem::new(CompletionKind::Keyword, ctx.source_range(), "await") | ||
34 | .detail("expr.await") | ||
35 | .insert_text("await") | ||
36 | .add_to(acc); | ||
37 | } | ||
38 | } | 27 | } |
39 | 28 | ||
40 | fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: &Type) { | 29 | fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: &Type) { |
@@ -72,801 +61,356 @@ fn complete_methods(acc: &mut Completions, ctx: &CompletionContext, receiver: &T | |||
72 | 61 | ||
73 | #[cfg(test)] | 62 | #[cfg(test)] |
74 | mod tests { | 63 | mod tests { |
75 | use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; | 64 | use expect::{expect, Expect}; |
76 | use insta::assert_debug_snapshot; | 65 | use test_utils::mark; |
66 | |||
67 | use crate::completion::{test_utils::completion_list, CompletionKind}; | ||
77 | 68 | ||
78 | fn do_ref_completion(code: &str) -> Vec<CompletionItem> { | 69 | fn check(ra_fixture: &str, expect: Expect) { |
79 | do_completion(code, CompletionKind::Reference) | 70 | let actual = completion_list(ra_fixture, CompletionKind::Reference); |
71 | expect.assert_eq(&actual); | ||
80 | } | 72 | } |
81 | 73 | ||
82 | #[test] | 74 | #[test] |
83 | fn test_struct_field_completion() { | 75 | fn test_struct_field_and_method_completion() { |
84 | assert_debug_snapshot!( | 76 | check( |
85 | do_ref_completion( | 77 | r#" |
86 | r" | 78 | struct S { foo: u32 } |
87 | struct A { the_field: u32 } | 79 | impl S { |
88 | fn foo(a: A) { | 80 | fn bar(&self) {} |
89 | a.<|> | 81 | } |
90 | } | 82 | fn foo(s: S) { s.<|> } |
91 | ", | 83 | "#, |
92 | ), | 84 | expect![[r#" |
93 | @r###" | 85 | me bar() fn bar(&self) |
94 | [ | 86 | fd foo u32 |
95 | CompletionItem { | 87 | "#]], |
96 | label: "the_field", | ||
97 | source_range: 45..45, | ||
98 | delete: 45..45, | ||
99 | insert: "the_field", | ||
100 | kind: Field, | ||
101 | detail: "u32", | ||
102 | }, | ||
103 | ] | ||
104 | "### | ||
105 | ); | 88 | ); |
106 | } | 89 | } |
107 | 90 | ||
108 | #[test] | 91 | #[test] |
109 | fn test_struct_field_completion_self() { | 92 | fn test_struct_field_completion_self() { |
110 | assert_debug_snapshot!( | 93 | check( |
111 | do_ref_completion( | 94 | r#" |
112 | r" | 95 | struct S { the_field: (u32,) } |
113 | struct A { | 96 | impl S { |
114 | /// This is the_field | 97 | fn foo(self) { self.<|> } |
115 | the_field: (u32,) | 98 | } |
116 | } | 99 | "#, |
117 | impl A { | 100 | expect![[r#" |
118 | fn foo(self) { | 101 | me foo() fn foo(self) |
119 | self.<|> | 102 | fd the_field (u32,) |
120 | } | 103 | "#]], |
121 | } | 104 | ) |
122 | ", | ||
123 | ), | ||
124 | @r###" | ||
125 | [ | ||
126 | CompletionItem { | ||
127 | label: "foo()", | ||
128 | source_range: 102..102, | ||
129 | delete: 102..102, | ||
130 | insert: "foo()$0", | ||
131 | kind: Method, | ||
132 | lookup: "foo", | ||
133 | detail: "fn foo(self)", | ||
134 | }, | ||
135 | CompletionItem { | ||
136 | label: "the_field", | ||
137 | source_range: 102..102, | ||
138 | delete: 102..102, | ||
139 | insert: "the_field", | ||
140 | kind: Field, | ||
141 | detail: "(u32,)", | ||
142 | documentation: Documentation( | ||
143 | "This is the_field", | ||
144 | ), | ||
145 | }, | ||
146 | ] | ||
147 | "### | ||
148 | ); | ||
149 | } | 105 | } |
150 | 106 | ||
151 | #[test] | 107 | #[test] |
152 | fn test_struct_field_completion_autoderef() { | 108 | fn test_struct_field_completion_autoderef() { |
153 | assert_debug_snapshot!( | 109 | check( |
154 | do_ref_completion( | 110 | r#" |
155 | r" | 111 | struct A { the_field: (u32, i32) } |
156 | struct A { the_field: (u32, i32) } | 112 | impl A { |
157 | impl A { | 113 | fn foo(&self) { self.<|> } |
158 | fn foo(&self) { | 114 | } |
159 | self.<|> | 115 | "#, |
160 | } | 116 | expect![[r#" |
161 | } | 117 | me foo() fn foo(&self) |
162 | ", | 118 | fd the_field (u32, i32) |
163 | ), | 119 | "#]], |
164 | @r###" | 120 | ) |
165 | [ | ||
166 | CompletionItem { | ||
167 | label: "foo()", | ||
168 | source_range: 77..77, | ||
169 | delete: 77..77, | ||
170 | insert: "foo()$0", | ||
171 | kind: Method, | ||
172 | lookup: "foo", | ||
173 | detail: "fn foo(&self)", | ||
174 | }, | ||
175 | CompletionItem { | ||
176 | label: "the_field", | ||
177 | source_range: 77..77, | ||
178 | delete: 77..77, | ||
179 | insert: "the_field", | ||
180 | kind: Field, | ||
181 | detail: "(u32, i32)", | ||
182 | }, | ||
183 | ] | ||
184 | "### | ||
185 | ); | ||
186 | } | 121 | } |
187 | 122 | ||
188 | #[test] | 123 | #[test] |
189 | fn test_no_struct_field_completion_for_method_call() { | 124 | fn test_no_struct_field_completion_for_method_call() { |
190 | assert_debug_snapshot!( | 125 | mark::check!(test_no_struct_field_completion_for_method_call); |
191 | do_ref_completion( | 126 | check( |
192 | r" | 127 | r#" |
193 | struct A { the_field: u32 } | 128 | struct A { the_field: u32 } |
194 | fn foo(a: A) { | 129 | fn foo(a: A) { a.<|>() } |
195 | a.<|>() | 130 | "#, |
196 | } | 131 | expect![[""]], |
197 | ", | ||
198 | ), | ||
199 | @"[]" | ||
200 | ); | 132 | ); |
201 | } | 133 | } |
202 | 134 | ||
203 | #[test] | 135 | #[test] |
204 | fn test_struct_field_visibility_private() { | 136 | fn test_visibility_filtering() { |
205 | assert_debug_snapshot!( | 137 | check( |
206 | do_ref_completion( | 138 | r#" |
207 | r" | 139 | mod inner { |
208 | mod inner { | 140 | pub struct A { |
209 | struct A { | 141 | private_field: u32, |
210 | private_field: u32, | 142 | pub pub_field: u32, |
211 | pub pub_field: u32, | 143 | pub(crate) crate_field: u32, |
212 | pub(crate) crate_field: u32, | 144 | pub(super) super_field: u32, |
213 | pub(super) super_field: u32, | ||
214 | } | ||
215 | } | ||
216 | fn foo(a: inner::A) { | ||
217 | a.<|> | ||
218 | } | ||
219 | ", | ||
220 | ), | ||
221 | @r###" | ||
222 | [ | ||
223 | CompletionItem { | ||
224 | label: "crate_field", | ||
225 | source_range: 192..192, | ||
226 | delete: 192..192, | ||
227 | insert: "crate_field", | ||
228 | kind: Field, | ||
229 | detail: "u32", | ||
230 | }, | ||
231 | CompletionItem { | ||
232 | label: "pub_field", | ||
233 | source_range: 192..192, | ||
234 | delete: 192..192, | ||
235 | insert: "pub_field", | ||
236 | kind: Field, | ||
237 | detail: "u32", | ||
238 | }, | ||
239 | CompletionItem { | ||
240 | label: "super_field", | ||
241 | source_range: 192..192, | ||
242 | delete: 192..192, | ||
243 | insert: "super_field", | ||
244 | kind: Field, | ||
245 | detail: "u32", | ||
246 | }, | ||
247 | ] | ||
248 | "### | ||
249 | ); | ||
250 | } | 145 | } |
251 | 146 | } | |
252 | #[test] | 147 | fn foo(a: inner::A) { a.<|> } |
253 | fn test_union_field_completion() { | 148 | "#, |
254 | assert_debug_snapshot!( | 149 | expect![[r#" |
255 | do_ref_completion( | 150 | fd crate_field u32 |
256 | r" | 151 | fd pub_field u32 |
257 | union Un { | 152 | fd super_field u32 |
258 | field: u8, | 153 | "#]], |
259 | other: u16, | ||
260 | } | ||
261 | |||
262 | fn foo(u: Un) { | ||
263 | u.<|> | ||
264 | } | ||
265 | ", | ||
266 | ), | ||
267 | @r###" | ||
268 | [ | ||
269 | CompletionItem { | ||
270 | label: "field", | ||
271 | source_range: 67..67, | ||
272 | delete: 67..67, | ||
273 | insert: "field", | ||
274 | kind: Field, | ||
275 | detail: "u8", | ||
276 | }, | ||
277 | CompletionItem { | ||
278 | label: "other", | ||
279 | source_range: 67..67, | ||
280 | delete: 67..67, | ||
281 | insert: "other", | ||
282 | kind: Field, | ||
283 | detail: "u16", | ||
284 | }, | ||
285 | ] | ||
286 | "### | ||
287 | ); | 154 | ); |
288 | } | ||
289 | 155 | ||
290 | #[test] | 156 | check( |
291 | fn test_method_completion() { | 157 | r#" |
292 | assert_debug_snapshot!( | 158 | struct A {} |
293 | do_ref_completion( | 159 | mod m { |
294 | r" | 160 | impl super::A { |
295 | struct A {} | 161 | fn private_method(&self) {} |
296 | impl A { | 162 | pub(super) fn the_method(&self) {} |
297 | fn the_method(&self) {} | 163 | } |
298 | } | 164 | } |
299 | fn foo(a: A) { | 165 | fn foo(a: A) { a.<|> } |
300 | a.<|> | 166 | "#, |
301 | } | 167 | expect![[r#" |
302 | ", | 168 | me the_method() pub(super) fn the_method(&self) |
303 | ), | 169 | "#]], |
304 | @r###" | ||
305 | [ | ||
306 | CompletionItem { | ||
307 | label: "the_method()", | ||
308 | source_range: 71..71, | ||
309 | delete: 71..71, | ||
310 | insert: "the_method()$0", | ||
311 | kind: Method, | ||
312 | lookup: "the_method", | ||
313 | detail: "fn the_method(&self)", | ||
314 | }, | ||
315 | ] | ||
316 | "### | ||
317 | ); | 170 | ); |
318 | } | 171 | } |
319 | 172 | ||
320 | #[test] | 173 | #[test] |
321 | fn test_method_completion_only_fitting_impls() { | 174 | fn test_union_field_completion() { |
322 | assert_debug_snapshot!( | 175 | check( |
323 | do_ref_completion( | 176 | r#" |
324 | r" | 177 | union U { field: u8, other: u16 } |
325 | struct A<T> {} | 178 | fn foo(u: U) { u.<|> } |
326 | impl A<u32> { | 179 | "#, |
327 | fn the_method(&self) {} | 180 | expect![[r#" |
328 | } | 181 | fd field u8 |
329 | impl A<i32> { | 182 | fd other u16 |
330 | fn the_other_method(&self) {} | 183 | "#]], |
331 | } | ||
332 | fn foo(a: A<u32>) { | ||
333 | a.<|> | ||
334 | } | ||
335 | ", | ||
336 | ), | ||
337 | @r###" | ||
338 | [ | ||
339 | CompletionItem { | ||
340 | label: "the_method()", | ||
341 | source_range: 134..134, | ||
342 | delete: 134..134, | ||
343 | insert: "the_method()$0", | ||
344 | kind: Method, | ||
345 | lookup: "the_method", | ||
346 | detail: "fn the_method(&self)", | ||
347 | }, | ||
348 | ] | ||
349 | "### | ||
350 | ); | 184 | ); |
351 | } | 185 | } |
352 | 186 | ||
353 | #[test] | 187 | #[test] |
354 | fn test_method_completion_private() { | 188 | fn test_method_completion_only_fitting_impls() { |
355 | assert_debug_snapshot!( | 189 | check( |
356 | do_ref_completion( | 190 | r#" |
357 | r" | 191 | struct A<T> {} |
358 | struct A {} | 192 | impl A<u32> { |
359 | mod m { | 193 | fn the_method(&self) {} |
360 | impl super::A { | 194 | } |
361 | fn private_method(&self) {} | 195 | impl A<i32> { |
362 | pub(super) fn the_method(&self) {} | 196 | fn the_other_method(&self) {} |
363 | } | 197 | } |
364 | } | 198 | fn foo(a: A<u32>) { a.<|> } |
365 | fn foo(a: A) { | 199 | "#, |
366 | a.<|> | 200 | expect![[r#" |
367 | } | 201 | me the_method() fn the_method(&self) |
368 | ", | 202 | "#]], |
369 | ), | 203 | ) |
370 | @r###" | ||
371 | [ | ||
372 | CompletionItem { | ||
373 | label: "the_method()", | ||
374 | source_range: 147..147, | ||
375 | delete: 147..147, | ||
376 | insert: "the_method()$0", | ||
377 | kind: Method, | ||
378 | lookup: "the_method", | ||
379 | detail: "pub(super) fn the_method(&self)", | ||
380 | }, | ||
381 | ] | ||
382 | "### | ||
383 | ); | ||
384 | } | 204 | } |
385 | 205 | ||
386 | #[test] | 206 | #[test] |
387 | fn test_trait_method_completion() { | 207 | fn test_trait_method_completion() { |
388 | assert_debug_snapshot!( | 208 | check( |
389 | do_ref_completion( | 209 | r#" |
390 | r" | 210 | struct A {} |
391 | struct A {} | 211 | trait Trait { fn the_method(&self); } |
392 | trait Trait { fn the_method(&self); } | 212 | impl Trait for A {} |
393 | impl Trait for A {} | 213 | fn foo(a: A) { a.<|> } |
394 | fn foo(a: A) { | 214 | "#, |
395 | a.<|> | 215 | expect![[r#" |
396 | } | 216 | me the_method() fn the_method(&self) |
397 | ", | 217 | "#]], |
398 | ), | ||
399 | @r###" | ||
400 | [ | ||
401 | CompletionItem { | ||
402 | label: "the_method()", | ||
403 | source_range: 90..90, | ||
404 | delete: 90..90, | ||
405 | insert: "the_method()$0", | ||
406 | kind: Method, | ||
407 | lookup: "the_method", | ||
408 | detail: "fn the_method(&self)", | ||
409 | }, | ||
410 | ] | ||
411 | "### | ||
412 | ); | 218 | ); |
413 | } | 219 | } |
414 | 220 | ||
415 | #[test] | 221 | #[test] |
416 | fn test_trait_method_completion_deduplicated() { | 222 | fn test_trait_method_completion_deduplicated() { |
417 | assert_debug_snapshot!( | 223 | check( |
418 | do_ref_completion( | 224 | r" |
419 | r" | 225 | struct A {} |
420 | struct A {} | 226 | trait Trait { fn the_method(&self); } |
421 | trait Trait { fn the_method(&self); } | 227 | impl<T> Trait for T {} |
422 | impl<T> Trait for T {} | 228 | fn foo(a: &A) { a.<|> } |
423 | fn foo(a: &A) { | 229 | ", |
424 | a.<|> | 230 | expect![[r#" |
425 | } | 231 | me the_method() fn the_method(&self) |
426 | ", | 232 | "#]], |
427 | ), | ||
428 | @r###" | ||
429 | [ | ||
430 | CompletionItem { | ||
431 | label: "the_method()", | ||
432 | source_range: 94..94, | ||
433 | delete: 94..94, | ||
434 | insert: "the_method()$0", | ||
435 | kind: Method, | ||
436 | lookup: "the_method", | ||
437 | detail: "fn the_method(&self)", | ||
438 | }, | ||
439 | ] | ||
440 | "### | ||
441 | ); | 233 | ); |
442 | } | 234 | } |
443 | 235 | ||
444 | #[test] | 236 | #[test] |
445 | fn completes_trait_method_from_other_module() { | 237 | fn completes_trait_method_from_other_module() { |
446 | assert_debug_snapshot!( | 238 | check( |
447 | do_ref_completion( | ||
448 | r" | ||
449 | struct A {} | ||
450 | mod m { | ||
451 | pub trait Trait { fn the_method(&self); } | ||
452 | } | ||
453 | use m::Trait; | ||
454 | impl Trait for A {} | ||
455 | fn foo(a: A) { | ||
456 | a.<|> | ||
457 | } | ||
458 | ", | ||
459 | ), | ||
460 | @r###" | ||
461 | [ | ||
462 | CompletionItem { | ||
463 | label: "the_method()", | ||
464 | source_range: 122..122, | ||
465 | delete: 122..122, | ||
466 | insert: "the_method()$0", | ||
467 | kind: Method, | ||
468 | lookup: "the_method", | ||
469 | detail: "fn the_method(&self)", | ||
470 | }, | ||
471 | ] | ||
472 | "### | ||
473 | ); | ||
474 | } | ||
475 | |||
476 | #[test] | ||
477 | fn test_no_non_self_method() { | ||
478 | assert_debug_snapshot!( | ||
479 | do_ref_completion( | ||
480 | r" | 239 | r" |
481 | struct A {} | 240 | struct A {} |
482 | impl A { | 241 | mod m { |
483 | fn the_method() {} | 242 | pub trait Trait { fn the_method(&self); } |
484 | } | 243 | } |
485 | fn foo(a: A) { | 244 | use m::Trait; |
486 | a.<|> | 245 | impl Trait for A {} |
487 | } | 246 | fn foo(a: A) { a.<|> } |
488 | ", | 247 | ", |
489 | ), | 248 | expect![[r#" |
490 | @"[]" | 249 | me the_method() fn the_method(&self) |
250 | "#]], | ||
491 | ); | 251 | ); |
492 | } | 252 | } |
493 | 253 | ||
494 | #[test] | 254 | #[test] |
495 | fn test_method_attr_filtering() { | 255 | fn test_no_non_self_method() { |
496 | assert_debug_snapshot!( | 256 | check( |
497 | do_ref_completion( | 257 | r#" |
498 | r" | 258 | struct A {} |
499 | struct A {} | 259 | impl A { |
500 | impl A { | 260 | fn the_method() {} |
501 | #[inline] | 261 | } |
502 | fn the_method(&self) { | 262 | fn foo(a: A) { |
503 | let x = 1; | 263 | a.<|> |
504 | let y = 2; | 264 | } |
505 | } | 265 | "#, |
506 | } | 266 | expect![[""]], |
507 | fn foo(a: A) { | ||
508 | a.<|> | ||
509 | } | ||
510 | ", | ||
511 | ), | ||
512 | @r###" | ||
513 | [ | ||
514 | CompletionItem { | ||
515 | label: "the_method()", | ||
516 | source_range: 128..128, | ||
517 | delete: 128..128, | ||
518 | insert: "the_method()$0", | ||
519 | kind: Method, | ||
520 | lookup: "the_method", | ||
521 | detail: "fn the_method(&self)", | ||
522 | }, | ||
523 | ] | ||
524 | "### | ||
525 | ); | 267 | ); |
526 | } | 268 | } |
527 | 269 | ||
528 | #[test] | 270 | #[test] |
529 | fn test_tuple_field_completion() { | 271 | fn test_tuple_field_completion() { |
530 | assert_debug_snapshot!( | 272 | check( |
531 | do_ref_completion( | 273 | r#" |
532 | r" | 274 | fn foo() { |
533 | fn foo() { | 275 | let b = (0, 3.14); |
534 | let b = (0, 3.14); | 276 | b.<|> |
535 | b.<|> | 277 | } |
536 | } | 278 | "#, |
537 | ", | 279 | expect![[r#" |
538 | ), | 280 | fd 0 i32 |
539 | @r###" | 281 | fd 1 f64 |
540 | [ | 282 | "#]], |
541 | CompletionItem { | 283 | ) |
542 | label: "0", | ||
543 | source_range: 38..38, | ||
544 | delete: 38..38, | ||
545 | insert: "0", | ||
546 | kind: Field, | ||
547 | detail: "i32", | ||
548 | }, | ||
549 | CompletionItem { | ||
550 | label: "1", | ||
551 | source_range: 38..38, | ||
552 | delete: 38..38, | ||
553 | insert: "1", | ||
554 | kind: Field, | ||
555 | detail: "f64", | ||
556 | }, | ||
557 | ] | ||
558 | "### | ||
559 | ); | ||
560 | } | 284 | } |
561 | 285 | ||
562 | #[test] | 286 | #[test] |
563 | fn test_tuple_field_inference() { | 287 | fn test_tuple_field_inference() { |
564 | assert_debug_snapshot!( | 288 | check( |
565 | do_ref_completion( | 289 | r#" |
566 | r" | 290 | pub struct S; |
567 | pub struct S; | 291 | impl S { pub fn blah(&self) {} } |
568 | impl S { | ||
569 | pub fn blah(&self) {} | ||
570 | } | ||
571 | 292 | ||
572 | struct T(S); | 293 | struct T(S); |
573 | 294 | ||
574 | impl T { | 295 | impl T { |
575 | fn foo(&self) { | 296 | fn foo(&self) { |
576 | // FIXME: This doesn't work without the trailing `a` as `0.` is a float | 297 | // FIXME: This doesn't work without the trailing `a` as `0.` is a float |
577 | self.0.a<|> | 298 | self.0.a<|> |
578 | } | ||
579 | } | ||
580 | ", | ||
581 | ), | ||
582 | @r###" | ||
583 | [ | ||
584 | CompletionItem { | ||
585 | label: "blah()", | ||
586 | source_range: 190..191, | ||
587 | delete: 190..191, | ||
588 | insert: "blah()$0", | ||
589 | kind: Method, | ||
590 | lookup: "blah", | ||
591 | detail: "pub fn blah(&self)", | ||
592 | }, | ||
593 | ] | ||
594 | "### | ||
595 | ); | ||
596 | } | 299 | } |
597 | 300 | } | |
598 | #[test] | 301 | "#, |
599 | fn test_completion_works_in_consts() { | 302 | expect![[r#" |
600 | assert_debug_snapshot!( | 303 | me blah() pub fn blah(&self) |
601 | do_ref_completion( | 304 | "#]], |
602 | r" | ||
603 | struct A { the_field: u32 } | ||
604 | const X: u32 = { | ||
605 | A { the_field: 92 }.<|> | ||
606 | }; | ||
607 | ", | ||
608 | ), | ||
609 | @r###" | ||
610 | [ | ||
611 | CompletionItem { | ||
612 | label: "the_field", | ||
613 | source_range: 69..69, | ||
614 | delete: 69..69, | ||
615 | insert: "the_field", | ||
616 | kind: Field, | ||
617 | detail: "u32", | ||
618 | }, | ||
619 | ] | ||
620 | "### | ||
621 | ); | 305 | ); |
622 | } | 306 | } |
623 | 307 | ||
624 | #[test] | 308 | #[test] |
625 | fn test_completion_await_impls_future() { | 309 | fn test_completion_works_in_consts() { |
626 | assert_debug_snapshot!( | 310 | check( |
627 | do_completion( | 311 | r#" |
628 | r###" | 312 | struct A { the_field: u32 } |
629 | //- /main.rs | 313 | const X: u32 = { |
630 | use std::future::*; | 314 | A { the_field: 92 }.<|> |
631 | struct A {} | 315 | }; |
632 | impl Future for A {} | 316 | "#, |
633 | fn foo(a: A) { | 317 | expect![[r#" |
634 | a.<|> | 318 | fd the_field u32 |
635 | } | 319 | "#]], |
636 | |||
637 | //- /std/lib.rs | ||
638 | pub mod future { | ||
639 | #[lang = "future_trait"] | ||
640 | pub trait Future {} | ||
641 | } | ||
642 | "###, CompletionKind::Keyword), | ||
643 | @r###" | ||
644 | [ | ||
645 | CompletionItem { | ||
646 | label: "await", | ||
647 | source_range: 74..74, | ||
648 | delete: 74..74, | ||
649 | insert: "await", | ||
650 | detail: "expr.await", | ||
651 | }, | ||
652 | ] | ||
653 | "### | ||
654 | ) | ||
655 | } | ||
656 | |||
657 | #[test] | ||
658 | fn test_super_super_completion() { | ||
659 | assert_debug_snapshot!( | ||
660 | do_ref_completion( | ||
661 | r" | ||
662 | mod a { | ||
663 | const A: usize = 0; | ||
664 | |||
665 | mod b { | ||
666 | const B: usize = 0; | ||
667 | |||
668 | mod c { | ||
669 | use super::super::<|> | ||
670 | } | ||
671 | } | ||
672 | } | ||
673 | ", | ||
674 | ), | ||
675 | @r###" | ||
676 | [ | ||
677 | CompletionItem { | ||
678 | label: "A", | ||
679 | source_range: 120..120, | ||
680 | delete: 120..120, | ||
681 | insert: "A", | ||
682 | kind: Const, | ||
683 | }, | ||
684 | CompletionItem { | ||
685 | label: "b", | ||
686 | source_range: 120..120, | ||
687 | delete: 120..120, | ||
688 | insert: "b", | ||
689 | kind: Module, | ||
690 | }, | ||
691 | ] | ||
692 | "### | ||
693 | ); | 320 | ); |
694 | } | 321 | } |
695 | 322 | ||
696 | #[test] | 323 | #[test] |
697 | fn works_in_simple_macro_1() { | 324 | fn works_in_simple_macro_1() { |
698 | assert_debug_snapshot!( | 325 | check( |
699 | do_ref_completion( | 326 | r#" |
700 | r" | 327 | macro_rules! m { ($e:expr) => { $e } } |
701 | macro_rules! m { ($e:expr) => { $e } } | 328 | struct A { the_field: u32 } |
702 | struct A { the_field: u32 } | 329 | fn foo(a: A) { |
703 | fn foo(a: A) { | 330 | m!(a.x<|>) |
704 | m!(a.x<|>) | 331 | } |
705 | } | 332 | "#, |
706 | ", | 333 | expect![[r#" |
707 | ), | 334 | fd the_field u32 |
708 | @r###" | 335 | "#]], |
709 | [ | ||
710 | CompletionItem { | ||
711 | label: "the_field", | ||
712 | source_range: 91..92, | ||
713 | delete: 91..92, | ||
714 | insert: "the_field", | ||
715 | kind: Field, | ||
716 | detail: "u32", | ||
717 | }, | ||
718 | ] | ||
719 | "### | ||
720 | ); | ||
721 | } | ||
722 | |||
723 | #[test] | ||
724 | fn works_in_simple_macro_recursive() { | ||
725 | assert_debug_snapshot!( | ||
726 | do_ref_completion( | ||
727 | r" | ||
728 | macro_rules! m { ($e:expr) => { $e } } | ||
729 | struct A { the_field: u32 } | ||
730 | fn foo(a: A) { | ||
731 | m!(a.x<|>) | ||
732 | } | ||
733 | ", | ||
734 | ), | ||
735 | @r###" | ||
736 | [ | ||
737 | CompletionItem { | ||
738 | label: "the_field", | ||
739 | source_range: 91..92, | ||
740 | delete: 91..92, | ||
741 | insert: "the_field", | ||
742 | kind: Field, | ||
743 | detail: "u32", | ||
744 | }, | ||
745 | ] | ||
746 | "### | ||
747 | ); | 336 | ); |
748 | } | 337 | } |
749 | 338 | ||
750 | #[test] | 339 | #[test] |
751 | fn works_in_simple_macro_2() { | 340 | fn works_in_simple_macro_2() { |
752 | // this doesn't work yet because the macro doesn't expand without the token -- maybe it can be fixed with better recovery | 341 | // this doesn't work yet because the macro doesn't expand without the token -- maybe it can be fixed with better recovery |
753 | assert_debug_snapshot!( | 342 | check( |
754 | do_ref_completion( | 343 | r#" |
755 | r" | 344 | macro_rules! m { ($e:expr) => { $e } } |
756 | macro_rules! m { ($e:expr) => { $e } } | 345 | struct A { the_field: u32 } |
757 | struct A { the_field: u32 } | 346 | fn foo(a: A) { |
758 | fn foo(a: A) { | 347 | m!(a.<|>) |
759 | m!(a.<|>) | 348 | } |
760 | } | 349 | "#, |
761 | ", | 350 | expect![[r#" |
762 | ), | 351 | fd the_field u32 |
763 | @r###" | 352 | "#]], |
764 | [ | ||
765 | CompletionItem { | ||
766 | label: "the_field", | ||
767 | source_range: 91..91, | ||
768 | delete: 91..91, | ||
769 | insert: "the_field", | ||
770 | kind: Field, | ||
771 | detail: "u32", | ||
772 | }, | ||
773 | ] | ||
774 | "### | ||
775 | ); | 353 | ); |
776 | } | 354 | } |
777 | 355 | ||
778 | #[test] | 356 | #[test] |
779 | fn works_in_simple_macro_recursive_1() { | 357 | fn works_in_simple_macro_recursive_1() { |
780 | assert_debug_snapshot!( | 358 | check( |
781 | do_ref_completion( | 359 | r#" |
782 | r" | 360 | macro_rules! m { ($e:expr) => { $e } } |
783 | macro_rules! m { ($e:expr) => { $e } } | 361 | struct A { the_field: u32 } |
784 | struct A { the_field: u32 } | 362 | fn foo(a: A) { |
785 | fn foo(a: A) { | 363 | m!(m!(m!(a.x<|>))) |
786 | m!(m!(m!(a.x<|>))) | 364 | } |
787 | } | 365 | "#, |
788 | ", | 366 | expect![[r#" |
789 | ), | 367 | fd the_field u32 |
790 | @r###" | 368 | "#]], |
791 | [ | ||
792 | CompletionItem { | ||
793 | label: "the_field", | ||
794 | source_range: 97..98, | ||
795 | delete: 97..98, | ||
796 | insert: "the_field", | ||
797 | kind: Field, | ||
798 | detail: "u32", | ||
799 | }, | ||
800 | ] | ||
801 | "### | ||
802 | ); | 369 | ); |
803 | } | 370 | } |
804 | 371 | ||
805 | #[test] | 372 | #[test] |
806 | fn macro_expansion_resilient() { | 373 | fn macro_expansion_resilient() { |
807 | assert_debug_snapshot!( | 374 | check( |
808 | do_ref_completion( | 375 | r#" |
809 | r" | 376 | macro_rules! dbg { |
810 | macro_rules! dbg { | 377 | () => {}; |
811 | () => {}; | 378 | ($val:expr) => { |
812 | ($val:expr) => { | 379 | match $val { tmp => { tmp } } |
813 | match $val { tmp => { tmp } } | 380 | }; |
814 | }; | 381 | // Trailing comma with single argument is ignored |
815 | // Trailing comma with single argument is ignored | 382 | ($val:expr,) => { $crate::dbg!($val) }; |
816 | ($val:expr,) => { $crate::dbg!($val) }; | 383 | ($($val:expr),+ $(,)?) => { |
817 | ($($val:expr),+ $(,)?) => { | 384 | ($($crate::dbg!($val)),+,) |
818 | ($($crate::dbg!($val)),+,) | 385 | }; |
819 | }; | 386 | } |
820 | } | 387 | struct A { the_field: u32 } |
821 | struct A { the_field: u32 } | 388 | fn foo(a: A) { |
822 | fn foo(a: A) { | 389 | dbg!(a.<|>) |
823 | dbg!(a.<|>) | 390 | } |
824 | } | 391 | "#, |
825 | ", | 392 | expect![[r#" |
826 | ), | 393 | fd the_field u32 |
827 | @r###" | 394 | "#]], |
828 | [ | ||
829 | CompletionItem { | ||
830 | label: "the_field", | ||
831 | source_range: 327..327, | ||
832 | delete: 327..327, | ||
833 | insert: "the_field", | ||
834 | kind: Field, | ||
835 | detail: "u32", | ||
836 | }, | ||
837 | ] | ||
838 | "### | ||
839 | ); | 395 | ); |
840 | } | 396 | } |
841 | 397 | ||
842 | #[test] | 398 | #[test] |
843 | fn test_method_completion_3547() { | 399 | fn test_method_completion_issue_3547() { |
844 | assert_debug_snapshot!( | 400 | check( |
845 | do_ref_completion( | 401 | r#" |
846 | r" | 402 | struct HashSet<T> {} |
847 | struct HashSet<T> {} | 403 | impl<T> HashSet<T> { |
848 | impl<T> HashSet<T> { | 404 | pub fn the_method(&self) {} |
849 | pub fn the_method(&self) {} | 405 | } |
850 | } | 406 | fn foo() { |
851 | fn foo() { | 407 | let s: HashSet<_>; |
852 | let s: HashSet<_>; | 408 | s.<|> |
853 | s.<|> | 409 | } |
854 | } | 410 | "#, |
855 | ", | 411 | expect![[r#" |
856 | ), | 412 | me the_method() pub fn the_method(&self) |
857 | @r###" | 413 | "#]], |
858 | [ | ||
859 | CompletionItem { | ||
860 | label: "the_method()", | ||
861 | source_range: 116..116, | ||
862 | delete: 116..116, | ||
863 | insert: "the_method()$0", | ||
864 | kind: Method, | ||
865 | lookup: "the_method", | ||
866 | detail: "pub fn the_method(&self)", | ||
867 | }, | ||
868 | ] | ||
869 | "### | ||
870 | ); | 414 | ); |
871 | } | 415 | } |
872 | } | 416 | } |
diff --git a/crates/ra_ide/src/completion/complete_keyword.rs b/crates/ra_ide/src/completion/complete_keyword.rs index 086b917ce..340d57a49 100644 --- a/crates/ra_ide/src/completion/complete_keyword.rs +++ b/crates/ra_ide/src/completion/complete_keyword.rs | |||
@@ -35,6 +35,19 @@ pub(super) fn complete_use_tree_keyword(acc: &mut Completions, ctx: &CompletionC | |||
35 | } | 35 | } |
36 | _ => {} | 36 | _ => {} |
37 | } | 37 | } |
38 | |||
39 | // Suggest .await syntax for types that implement Future trait | ||
40 | if let Some(receiver) = &ctx.dot_receiver { | ||
41 | if let Some(ty) = ctx.sema.type_of_expr(receiver) { | ||
42 | if ty.impls_future(ctx.db) { | ||
43 | CompletionItem::new(CompletionKind::Keyword, ctx.source_range(), "await") | ||
44 | .kind(CompletionItemKind::Keyword) | ||
45 | .detail("expr.await") | ||
46 | .insert_text("await") | ||
47 | .add_to(acc); | ||
48 | } | ||
49 | }; | ||
50 | } | ||
38 | } | 51 | } |
39 | 52 | ||
40 | pub(super) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionContext) { | 53 | pub(super) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionContext) { |
@@ -490,4 +503,26 @@ Some multi-line comment<|> | |||
490 | expect![[""]], | 503 | expect![[""]], |
491 | ); | 504 | ); |
492 | } | 505 | } |
506 | |||
507 | #[test] | ||
508 | fn test_completion_await_impls_future() { | ||
509 | check( | ||
510 | r#" | ||
511 | //- /main.rs | ||
512 | use std::future::*; | ||
513 | struct A {} | ||
514 | impl Future for A {} | ||
515 | fn foo(a: A) { a.<|> } | ||
516 | |||
517 | //- /std/lib.rs | ||
518 | pub mod future { | ||
519 | #[lang = "future_trait"] | ||
520 | pub trait Future {} | ||
521 | } | ||
522 | "#, | ||
523 | expect![[r#" | ||
524 | kw await expr.await | ||
525 | "#]], | ||
526 | ) | ||
527 | } | ||
493 | } | 528 | } |
diff --git a/crates/ra_ide/src/completion/complete_qualified_path.rs b/crates/ra_ide/src/completion/complete_qualified_path.rs index f133ce3ce..a16866cd2 100644 --- a/crates/ra_ide/src/completion/complete_qualified_path.rs +++ b/crates/ra_ide/src/completion/complete_qualified_path.rs | |||
@@ -1206,6 +1206,45 @@ mod tests { | |||
1206 | } | 1206 | } |
1207 | 1207 | ||
1208 | #[test] | 1208 | #[test] |
1209 | fn test_super_super_completion() { | ||
1210 | assert_debug_snapshot!( | ||
1211 | do_reference_completion( | ||
1212 | r" | ||
1213 | mod a { | ||
1214 | const A: usize = 0; | ||
1215 | |||
1216 | mod b { | ||
1217 | const B: usize = 0; | ||
1218 | |||
1219 | mod c { | ||
1220 | use super::super::<|> | ||
1221 | } | ||
1222 | } | ||
1223 | } | ||
1224 | ", | ||
1225 | ), | ||
1226 | @r###" | ||
1227 | [ | ||
1228 | CompletionItem { | ||
1229 | label: "A", | ||
1230 | source_range: 120..120, | ||
1231 | delete: 120..120, | ||
1232 | insert: "A", | ||
1233 | kind: Const, | ||
1234 | }, | ||
1235 | CompletionItem { | ||
1236 | label: "b", | ||
1237 | source_range: 120..120, | ||
1238 | delete: 120..120, | ||
1239 | insert: "b", | ||
1240 | kind: Module, | ||
1241 | }, | ||
1242 | ] | ||
1243 | "### | ||
1244 | ); | ||
1245 | } | ||
1246 | |||
1247 | #[test] | ||
1209 | fn completes_reexported_items_under_correct_name() { | 1248 | fn completes_reexported_items_under_correct_name() { |
1210 | assert_debug_snapshot!( | 1249 | assert_debug_snapshot!( |
1211 | do_reference_completion( | 1250 | do_reference_completion( |
diff --git a/crates/ra_ide/src/completion/presentation.rs b/crates/ra_ide/src/completion/presentation.rs index bd48156b0..dc391c46b 100644 --- a/crates/ra_ide/src/completion/presentation.rs +++ b/crates/ra_ide/src/completion/presentation.rs | |||
@@ -644,6 +644,75 @@ fn foo() { A { the<|> } } | |||
644 | } | 644 | } |
645 | 645 | ||
646 | #[test] | 646 | #[test] |
647 | fn renders_docs() { | ||
648 | check( | ||
649 | r#" | ||
650 | struct S { | ||
651 | /// Field docs | ||
652 | foo: | ||
653 | } | ||
654 | impl S { | ||
655 | /// Method docs | ||
656 | fn bar(self) { self.<|> } | ||
657 | }"#, | ||
658 | expect![[r#" | ||
659 | [ | ||
660 | CompletionItem { | ||
661 | label: "bar()", | ||
662 | source_range: 94..94, | ||
663 | delete: 94..94, | ||
664 | insert: "bar()$0", | ||
665 | kind: Method, | ||
666 | lookup: "bar", | ||
667 | detail: "fn bar(self)", | ||
668 | documentation: Documentation( | ||
669 | "Method docs", | ||
670 | ), | ||
671 | }, | ||
672 | CompletionItem { | ||
673 | label: "foo", | ||
674 | source_range: 94..94, | ||
675 | delete: 94..94, | ||
676 | insert: "foo", | ||
677 | kind: Field, | ||
678 | detail: "{unknown}", | ||
679 | documentation: Documentation( | ||
680 | "Field docs", | ||
681 | ), | ||
682 | }, | ||
683 | ] | ||
684 | "#]], | ||
685 | ) | ||
686 | } | ||
687 | |||
688 | #[test] | ||
689 | fn dont_render_attrs() { | ||
690 | check( | ||
691 | r#" | ||
692 | struct S; | ||
693 | impl S { | ||
694 | #[inline] | ||
695 | fn the_method(&self) { } | ||
696 | } | ||
697 | fn foo(s: S) { s.<|> } | ||
698 | "#, | ||
699 | expect![[r#" | ||
700 | [ | ||
701 | CompletionItem { | ||
702 | label: "the_method()", | ||
703 | source_range: 81..81, | ||
704 | delete: 81..81, | ||
705 | insert: "the_method()$0", | ||
706 | kind: Method, | ||
707 | lookup: "the_method", | ||
708 | detail: "fn the_method(&self)", | ||
709 | }, | ||
710 | ] | ||
711 | "#]], | ||
712 | ) | ||
713 | } | ||
714 | |||
715 | #[test] | ||
647 | fn inserts_parens_for_function_calls() { | 716 | fn inserts_parens_for_function_calls() { |
648 | mark::check!(inserts_parens_for_function_calls); | 717 | mark::check!(inserts_parens_for_function_calls); |
649 | check_edit( | 718 | check_edit( |