diff options
author | Zac Pullar-Strecker <[email protected]> | 2020-08-24 10:19:53 +0100 |
---|---|---|
committer | Zac Pullar-Strecker <[email protected]> | 2020-08-24 10:20:13 +0100 |
commit | 7bbca7a1b3f9293d2f5cc5745199bc5f8396f2f0 (patch) | |
tree | bdb47765991cb973b2cd5481a088fac636bd326c /crates/assists/src/handlers/add_missing_impl_members.rs | |
parent | ca464650eeaca6195891199a93f4f76cf3e7e697 (diff) | |
parent | e65d48d1fb3d4d91d9dc1148a7a836ff5c9a3c87 (diff) |
Merge remote-tracking branch 'upstream/master' into 503-hover-doc-links
Diffstat (limited to 'crates/assists/src/handlers/add_missing_impl_members.rs')
-rw-r--r-- | crates/assists/src/handlers/add_missing_impl_members.rs | 766 |
1 files changed, 766 insertions, 0 deletions
diff --git a/crates/assists/src/handlers/add_missing_impl_members.rs b/crates/assists/src/handlers/add_missing_impl_members.rs new file mode 100644 index 000000000..83a2ada9a --- /dev/null +++ b/crates/assists/src/handlers/add_missing_impl_members.rs | |||
@@ -0,0 +1,766 @@ | |||
1 | use hir::HasSource; | ||
2 | use syntax::{ | ||
3 | ast::{ | ||
4 | self, | ||
5 | edit::{self, AstNodeEdit, IndentLevel}, | ||
6 | make, AstNode, NameOwner, | ||
7 | }, | ||
8 | SmolStr, | ||
9 | }; | ||
10 | |||
11 | use crate::{ | ||
12 | assist_context::{AssistContext, Assists}, | ||
13 | ast_transform::{self, AstTransform, QualifyPaths, SubstituteTypeParams}, | ||
14 | utils::{get_missing_assoc_items, render_snippet, resolve_target_trait, Cursor}, | ||
15 | AssistId, AssistKind, | ||
16 | }; | ||
17 | |||
18 | #[derive(PartialEq)] | ||
19 | enum AddMissingImplMembersMode { | ||
20 | DefaultMethodsOnly, | ||
21 | NoDefaultMethods, | ||
22 | } | ||
23 | |||
24 | // Assist: add_impl_missing_members | ||
25 | // | ||
26 | // Adds scaffold for required impl members. | ||
27 | // | ||
28 | // ``` | ||
29 | // trait Trait<T> { | ||
30 | // Type X; | ||
31 | // fn foo(&self) -> T; | ||
32 | // fn bar(&self) {} | ||
33 | // } | ||
34 | // | ||
35 | // impl Trait<u32> for () {<|> | ||
36 | // | ||
37 | // } | ||
38 | // ``` | ||
39 | // -> | ||
40 | // ``` | ||
41 | // trait Trait<T> { | ||
42 | // Type X; | ||
43 | // fn foo(&self) -> T; | ||
44 | // fn bar(&self) {} | ||
45 | // } | ||
46 | // | ||
47 | // impl Trait<u32> for () { | ||
48 | // fn foo(&self) -> u32 { | ||
49 | // ${0:todo!()} | ||
50 | // } | ||
51 | // } | ||
52 | // ``` | ||
53 | pub(crate) fn add_missing_impl_members(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | ||
54 | add_missing_impl_members_inner( | ||
55 | acc, | ||
56 | ctx, | ||
57 | AddMissingImplMembersMode::NoDefaultMethods, | ||
58 | "add_impl_missing_members", | ||
59 | "Implement missing members", | ||
60 | ) | ||
61 | } | ||
62 | |||
63 | // Assist: add_impl_default_members | ||
64 | // | ||
65 | // Adds scaffold for overriding default impl members. | ||
66 | // | ||
67 | // ``` | ||
68 | // trait Trait { | ||
69 | // Type X; | ||
70 | // fn foo(&self); | ||
71 | // fn bar(&self) {} | ||
72 | // } | ||
73 | // | ||
74 | // impl Trait for () { | ||
75 | // Type X = (); | ||
76 | // fn foo(&self) {}<|> | ||
77 | // | ||
78 | // } | ||
79 | // ``` | ||
80 | // -> | ||
81 | // ``` | ||
82 | // trait Trait { | ||
83 | // Type X; | ||
84 | // fn foo(&self); | ||
85 | // fn bar(&self) {} | ||
86 | // } | ||
87 | // | ||
88 | // impl Trait for () { | ||
89 | // Type X = (); | ||
90 | // fn foo(&self) {} | ||
91 | // | ||
92 | // $0fn bar(&self) {} | ||
93 | // } | ||
94 | // ``` | ||
95 | pub(crate) fn add_missing_default_members(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | ||
96 | add_missing_impl_members_inner( | ||
97 | acc, | ||
98 | ctx, | ||
99 | AddMissingImplMembersMode::DefaultMethodsOnly, | ||
100 | "add_impl_default_members", | ||
101 | "Implement default members", | ||
102 | ) | ||
103 | } | ||
104 | |||
105 | fn add_missing_impl_members_inner( | ||
106 | acc: &mut Assists, | ||
107 | ctx: &AssistContext, | ||
108 | mode: AddMissingImplMembersMode, | ||
109 | assist_id: &'static str, | ||
110 | label: &'static str, | ||
111 | ) -> Option<()> { | ||
112 | let _p = profile::span("add_missing_impl_members_inner"); | ||
113 | let impl_def = ctx.find_node_at_offset::<ast::Impl>()?; | ||
114 | let impl_item_list = impl_def.assoc_item_list()?; | ||
115 | |||
116 | let trait_ = resolve_target_trait(&ctx.sema, &impl_def)?; | ||
117 | |||
118 | let def_name = |item: &ast::AssocItem| -> Option<SmolStr> { | ||
119 | match item { | ||
120 | ast::AssocItem::Fn(def) => def.name(), | ||
121 | ast::AssocItem::TypeAlias(def) => def.name(), | ||
122 | ast::AssocItem::Const(def) => def.name(), | ||
123 | ast::AssocItem::MacroCall(_) => None, | ||
124 | } | ||
125 | .map(|it| it.text().clone()) | ||
126 | }; | ||
127 | |||
128 | let missing_items = get_missing_assoc_items(&ctx.sema, &impl_def) | ||
129 | .iter() | ||
130 | .map(|i| match i { | ||
131 | hir::AssocItem::Function(i) => ast::AssocItem::Fn(i.source(ctx.db()).value), | ||
132 | hir::AssocItem::TypeAlias(i) => ast::AssocItem::TypeAlias(i.source(ctx.db()).value), | ||
133 | hir::AssocItem::Const(i) => ast::AssocItem::Const(i.source(ctx.db()).value), | ||
134 | }) | ||
135 | .filter(|t| def_name(&t).is_some()) | ||
136 | .filter(|t| match t { | ||
137 | ast::AssocItem::Fn(def) => match mode { | ||
138 | AddMissingImplMembersMode::DefaultMethodsOnly => def.body().is_some(), | ||
139 | AddMissingImplMembersMode::NoDefaultMethods => def.body().is_none(), | ||
140 | }, | ||
141 | _ => mode == AddMissingImplMembersMode::NoDefaultMethods, | ||
142 | }) | ||
143 | .collect::<Vec<_>>(); | ||
144 | |||
145 | if missing_items.is_empty() { | ||
146 | return None; | ||
147 | } | ||
148 | |||
149 | let target = impl_def.syntax().text_range(); | ||
150 | acc.add(AssistId(assist_id, AssistKind::QuickFix), label, target, |builder| { | ||
151 | let n_existing_items = impl_item_list.assoc_items().count(); | ||
152 | let source_scope = ctx.sema.scope_for_def(trait_); | ||
153 | let target_scope = ctx.sema.scope(impl_item_list.syntax()); | ||
154 | let ast_transform = QualifyPaths::new(&target_scope, &source_scope) | ||
155 | .or(SubstituteTypeParams::for_trait_impl(&source_scope, trait_, impl_def)); | ||
156 | let items = missing_items | ||
157 | .into_iter() | ||
158 | .map(|it| ast_transform::apply(&*ast_transform, it)) | ||
159 | .map(|it| match it { | ||
160 | ast::AssocItem::Fn(def) => ast::AssocItem::Fn(add_body(def)), | ||
161 | ast::AssocItem::TypeAlias(def) => ast::AssocItem::TypeAlias(def.remove_bounds()), | ||
162 | _ => it, | ||
163 | }) | ||
164 | .map(|it| edit::remove_attrs_and_docs(&it)); | ||
165 | let new_impl_item_list = impl_item_list.append_items(items); | ||
166 | let first_new_item = new_impl_item_list.assoc_items().nth(n_existing_items).unwrap(); | ||
167 | |||
168 | let original_range = impl_item_list.syntax().text_range(); | ||
169 | match ctx.config.snippet_cap { | ||
170 | None => builder.replace(original_range, new_impl_item_list.to_string()), | ||
171 | Some(cap) => { | ||
172 | let mut cursor = Cursor::Before(first_new_item.syntax()); | ||
173 | let placeholder; | ||
174 | if let ast::AssocItem::Fn(func) = &first_new_item { | ||
175 | if let Some(m) = func.syntax().descendants().find_map(ast::MacroCall::cast) { | ||
176 | if m.syntax().text() == "todo!()" { | ||
177 | placeholder = m; | ||
178 | cursor = Cursor::Replace(placeholder.syntax()); | ||
179 | } | ||
180 | } | ||
181 | } | ||
182 | builder.replace_snippet( | ||
183 | cap, | ||
184 | original_range, | ||
185 | render_snippet(cap, new_impl_item_list.syntax(), cursor), | ||
186 | ) | ||
187 | } | ||
188 | }; | ||
189 | }) | ||
190 | } | ||
191 | |||
192 | fn add_body(fn_def: ast::Fn) -> ast::Fn { | ||
193 | if fn_def.body().is_some() { | ||
194 | return fn_def; | ||
195 | } | ||
196 | let body = make::block_expr(None, Some(make::expr_todo())).indent(IndentLevel(1)); | ||
197 | fn_def.with_body(body) | ||
198 | } | ||
199 | |||
200 | #[cfg(test)] | ||
201 | mod tests { | ||
202 | use crate::tests::{check_assist, check_assist_not_applicable}; | ||
203 | |||
204 | use super::*; | ||
205 | |||
206 | #[test] | ||
207 | fn test_add_missing_impl_members() { | ||
208 | check_assist( | ||
209 | add_missing_impl_members, | ||
210 | r#" | ||
211 | trait Foo { | ||
212 | type Output; | ||
213 | |||
214 | const CONST: usize = 42; | ||
215 | |||
216 | fn foo(&self); | ||
217 | fn bar(&self); | ||
218 | fn baz(&self); | ||
219 | } | ||
220 | |||
221 | struct S; | ||
222 | |||
223 | impl Foo for S { | ||
224 | fn bar(&self) {} | ||
225 | <|> | ||
226 | }"#, | ||
227 | r#" | ||
228 | trait Foo { | ||
229 | type Output; | ||
230 | |||
231 | const CONST: usize = 42; | ||
232 | |||
233 | fn foo(&self); | ||
234 | fn bar(&self); | ||
235 | fn baz(&self); | ||
236 | } | ||
237 | |||
238 | struct S; | ||
239 | |||
240 | impl Foo for S { | ||
241 | fn bar(&self) {} | ||
242 | |||
243 | $0type Output; | ||
244 | |||
245 | const CONST: usize = 42; | ||
246 | |||
247 | fn foo(&self) { | ||
248 | todo!() | ||
249 | } | ||
250 | |||
251 | fn baz(&self) { | ||
252 | todo!() | ||
253 | } | ||
254 | }"#, | ||
255 | ); | ||
256 | } | ||
257 | |||
258 | #[test] | ||
259 | fn test_copied_overriden_members() { | ||
260 | check_assist( | ||
261 | add_missing_impl_members, | ||
262 | r#" | ||
263 | trait Foo { | ||
264 | fn foo(&self); | ||
265 | fn bar(&self) -> bool { true } | ||
266 | fn baz(&self) -> u32 { 42 } | ||
267 | } | ||
268 | |||
269 | struct S; | ||
270 | |||
271 | impl Foo for S { | ||
272 | fn bar(&self) {} | ||
273 | <|> | ||
274 | }"#, | ||
275 | r#" | ||
276 | trait Foo { | ||
277 | fn foo(&self); | ||
278 | fn bar(&self) -> bool { true } | ||
279 | fn baz(&self) -> u32 { 42 } | ||
280 | } | ||
281 | |||
282 | struct S; | ||
283 | |||
284 | impl Foo for S { | ||
285 | fn bar(&self) {} | ||
286 | |||
287 | fn foo(&self) { | ||
288 | ${0:todo!()} | ||
289 | } | ||
290 | }"#, | ||
291 | ); | ||
292 | } | ||
293 | |||
294 | #[test] | ||
295 | fn test_empty_impl_def() { | ||
296 | check_assist( | ||
297 | add_missing_impl_members, | ||
298 | r#" | ||
299 | trait Foo { fn foo(&self); } | ||
300 | struct S; | ||
301 | impl Foo for S { <|> }"#, | ||
302 | r#" | ||
303 | trait Foo { fn foo(&self); } | ||
304 | struct S; | ||
305 | impl Foo for S { | ||
306 | fn foo(&self) { | ||
307 | ${0:todo!()} | ||
308 | } | ||
309 | }"#, | ||
310 | ); | ||
311 | } | ||
312 | |||
313 | #[test] | ||
314 | fn fill_in_type_params_1() { | ||
315 | check_assist( | ||
316 | add_missing_impl_members, | ||
317 | r#" | ||
318 | trait Foo<T> { fn foo(&self, t: T) -> &T; } | ||
319 | struct S; | ||
320 | impl Foo<u32> for S { <|> }"#, | ||
321 | r#" | ||
322 | trait Foo<T> { fn foo(&self, t: T) -> &T; } | ||
323 | struct S; | ||
324 | impl Foo<u32> for S { | ||
325 | fn foo(&self, t: u32) -> &u32 { | ||
326 | ${0:todo!()} | ||
327 | } | ||
328 | }"#, | ||
329 | ); | ||
330 | } | ||
331 | |||
332 | #[test] | ||
333 | fn fill_in_type_params_2() { | ||
334 | check_assist( | ||
335 | add_missing_impl_members, | ||
336 | r#" | ||
337 | trait Foo<T> { fn foo(&self, t: T) -> &T; } | ||
338 | struct S; | ||
339 | impl<U> Foo<U> for S { <|> }"#, | ||
340 | r#" | ||
341 | trait Foo<T> { fn foo(&self, t: T) -> &T; } | ||
342 | struct S; | ||
343 | impl<U> Foo<U> for S { | ||
344 | fn foo(&self, t: U) -> &U { | ||
345 | ${0:todo!()} | ||
346 | } | ||
347 | }"#, | ||
348 | ); | ||
349 | } | ||
350 | |||
351 | #[test] | ||
352 | fn test_cursor_after_empty_impl_def() { | ||
353 | check_assist( | ||
354 | add_missing_impl_members, | ||
355 | r#" | ||
356 | trait Foo { fn foo(&self); } | ||
357 | struct S; | ||
358 | impl Foo for S {}<|>"#, | ||
359 | r#" | ||
360 | trait Foo { fn foo(&self); } | ||
361 | struct S; | ||
362 | impl Foo for S { | ||
363 | fn foo(&self) { | ||
364 | ${0:todo!()} | ||
365 | } | ||
366 | }"#, | ||
367 | ) | ||
368 | } | ||
369 | |||
370 | #[test] | ||
371 | fn test_qualify_path_1() { | ||
372 | check_assist( | ||
373 | add_missing_impl_members, | ||
374 | r#" | ||
375 | mod foo { | ||
376 | pub struct Bar; | ||
377 | trait Foo { fn foo(&self, bar: Bar); } | ||
378 | } | ||
379 | struct S; | ||
380 | impl foo::Foo for S { <|> }"#, | ||
381 | r#" | ||
382 | mod foo { | ||
383 | pub struct Bar; | ||
384 | trait Foo { fn foo(&self, bar: Bar); } | ||
385 | } | ||
386 | struct S; | ||
387 | impl foo::Foo for S { | ||
388 | fn foo(&self, bar: foo::Bar) { | ||
389 | ${0:todo!()} | ||
390 | } | ||
391 | }"#, | ||
392 | ); | ||
393 | } | ||
394 | |||
395 | #[test] | ||
396 | fn test_qualify_path_generic() { | ||
397 | check_assist( | ||
398 | add_missing_impl_members, | ||
399 | r#" | ||
400 | mod foo { | ||
401 | pub struct Bar<T>; | ||
402 | trait Foo { fn foo(&self, bar: Bar<u32>); } | ||
403 | } | ||
404 | struct S; | ||
405 | impl foo::Foo for S { <|> }"#, | ||
406 | r#" | ||
407 | mod foo { | ||
408 | pub struct Bar<T>; | ||
409 | trait Foo { fn foo(&self, bar: Bar<u32>); } | ||
410 | } | ||
411 | struct S; | ||
412 | impl foo::Foo for S { | ||
413 | fn foo(&self, bar: foo::Bar<u32>) { | ||
414 | ${0:todo!()} | ||
415 | } | ||
416 | }"#, | ||
417 | ); | ||
418 | } | ||
419 | |||
420 | #[test] | ||
421 | fn test_qualify_path_and_substitute_param() { | ||
422 | check_assist( | ||
423 | add_missing_impl_members, | ||
424 | r#" | ||
425 | mod foo { | ||
426 | pub struct Bar<T>; | ||
427 | trait Foo<T> { fn foo(&self, bar: Bar<T>); } | ||
428 | } | ||
429 | struct S; | ||
430 | impl foo::Foo<u32> for S { <|> }"#, | ||
431 | r#" | ||
432 | mod foo { | ||
433 | pub struct Bar<T>; | ||
434 | trait Foo<T> { fn foo(&self, bar: Bar<T>); } | ||
435 | } | ||
436 | struct S; | ||
437 | impl foo::Foo<u32> for S { | ||
438 | fn foo(&self, bar: foo::Bar<u32>) { | ||
439 | ${0:todo!()} | ||
440 | } | ||
441 | }"#, | ||
442 | ); | ||
443 | } | ||
444 | |||
445 | #[test] | ||
446 | fn test_substitute_param_no_qualify() { | ||
447 | // when substituting params, the substituted param should not be qualified! | ||
448 | check_assist( | ||
449 | add_missing_impl_members, | ||
450 | r#" | ||
451 | mod foo { | ||
452 | trait Foo<T> { fn foo(&self, bar: T); } | ||
453 | pub struct Param; | ||
454 | } | ||
455 | struct Param; | ||
456 | struct S; | ||
457 | impl foo::Foo<Param> for S { <|> }"#, | ||
458 | r#" | ||
459 | mod foo { | ||
460 | trait Foo<T> { fn foo(&self, bar: T); } | ||
461 | pub struct Param; | ||
462 | } | ||
463 | struct Param; | ||
464 | struct S; | ||
465 | impl foo::Foo<Param> for S { | ||
466 | fn foo(&self, bar: Param) { | ||
467 | ${0:todo!()} | ||
468 | } | ||
469 | }"#, | ||
470 | ); | ||
471 | } | ||
472 | |||
473 | #[test] | ||
474 | fn test_qualify_path_associated_item() { | ||
475 | check_assist( | ||
476 | add_missing_impl_members, | ||
477 | r#" | ||
478 | mod foo { | ||
479 | pub struct Bar<T>; | ||
480 | impl Bar<T> { type Assoc = u32; } | ||
481 | trait Foo { fn foo(&self, bar: Bar<u32>::Assoc); } | ||
482 | } | ||
483 | struct S; | ||
484 | impl foo::Foo for S { <|> }"#, | ||
485 | r#" | ||
486 | mod foo { | ||
487 | pub struct Bar<T>; | ||
488 | impl Bar<T> { type Assoc = u32; } | ||
489 | trait Foo { fn foo(&self, bar: Bar<u32>::Assoc); } | ||
490 | } | ||
491 | struct S; | ||
492 | impl foo::Foo for S { | ||
493 | fn foo(&self, bar: foo::Bar<u32>::Assoc) { | ||
494 | ${0:todo!()} | ||
495 | } | ||
496 | }"#, | ||
497 | ); | ||
498 | } | ||
499 | |||
500 | #[test] | ||
501 | fn test_qualify_path_nested() { | ||
502 | check_assist( | ||
503 | add_missing_impl_members, | ||
504 | r#" | ||
505 | mod foo { | ||
506 | pub struct Bar<T>; | ||
507 | pub struct Baz; | ||
508 | trait Foo { fn foo(&self, bar: Bar<Baz>); } | ||
509 | } | ||
510 | struct S; | ||
511 | impl foo::Foo for S { <|> }"#, | ||
512 | r#" | ||
513 | mod foo { | ||
514 | pub struct Bar<T>; | ||
515 | pub struct Baz; | ||
516 | trait Foo { fn foo(&self, bar: Bar<Baz>); } | ||
517 | } | ||
518 | struct S; | ||
519 | impl foo::Foo for S { | ||
520 | fn foo(&self, bar: foo::Bar<foo::Baz>) { | ||
521 | ${0:todo!()} | ||
522 | } | ||
523 | }"#, | ||
524 | ); | ||
525 | } | ||
526 | |||
527 | #[test] | ||
528 | fn test_qualify_path_fn_trait_notation() { | ||
529 | check_assist( | ||
530 | add_missing_impl_members, | ||
531 | r#" | ||
532 | mod foo { | ||
533 | pub trait Fn<Args> { type Output; } | ||
534 | trait Foo { fn foo(&self, bar: dyn Fn(u32) -> i32); } | ||
535 | } | ||
536 | struct S; | ||
537 | impl foo::Foo for S { <|> }"#, | ||
538 | r#" | ||
539 | mod foo { | ||
540 | pub trait Fn<Args> { type Output; } | ||
541 | trait Foo { fn foo(&self, bar: dyn Fn(u32) -> i32); } | ||
542 | } | ||
543 | struct S; | ||
544 | impl foo::Foo for S { | ||
545 | fn foo(&self, bar: dyn Fn(u32) -> i32) { | ||
546 | ${0:todo!()} | ||
547 | } | ||
548 | }"#, | ||
549 | ); | ||
550 | } | ||
551 | |||
552 | #[test] | ||
553 | fn test_empty_trait() { | ||
554 | check_assist_not_applicable( | ||
555 | add_missing_impl_members, | ||
556 | r#" | ||
557 | trait Foo; | ||
558 | struct S; | ||
559 | impl Foo for S { <|> }"#, | ||
560 | ) | ||
561 | } | ||
562 | |||
563 | #[test] | ||
564 | fn test_ignore_unnamed_trait_members_and_default_methods() { | ||
565 | check_assist_not_applicable( | ||
566 | add_missing_impl_members, | ||
567 | r#" | ||
568 | trait Foo { | ||
569 | fn (arg: u32); | ||
570 | fn valid(some: u32) -> bool { false } | ||
571 | } | ||
572 | struct S; | ||
573 | impl Foo for S { <|> }"#, | ||
574 | ) | ||
575 | } | ||
576 | |||
577 | #[test] | ||
578 | fn test_with_docstring_and_attrs() { | ||
579 | check_assist( | ||
580 | add_missing_impl_members, | ||
581 | r#" | ||
582 | #[doc(alias = "test alias")] | ||
583 | trait Foo { | ||
584 | /// doc string | ||
585 | type Output; | ||
586 | |||
587 | #[must_use] | ||
588 | fn foo(&self); | ||
589 | } | ||
590 | struct S; | ||
591 | impl Foo for S {}<|>"#, | ||
592 | r#" | ||
593 | #[doc(alias = "test alias")] | ||
594 | trait Foo { | ||
595 | /// doc string | ||
596 | type Output; | ||
597 | |||
598 | #[must_use] | ||
599 | fn foo(&self); | ||
600 | } | ||
601 | struct S; | ||
602 | impl Foo for S { | ||
603 | $0type Output; | ||
604 | |||
605 | fn foo(&self) { | ||
606 | todo!() | ||
607 | } | ||
608 | }"#, | ||
609 | ) | ||
610 | } | ||
611 | |||
612 | #[test] | ||
613 | fn test_default_methods() { | ||
614 | check_assist( | ||
615 | add_missing_default_members, | ||
616 | r#" | ||
617 | trait Foo { | ||
618 | type Output; | ||
619 | |||
620 | const CONST: usize = 42; | ||
621 | |||
622 | fn valid(some: u32) -> bool { false } | ||
623 | fn foo(some: u32) -> bool; | ||
624 | } | ||
625 | struct S; | ||
626 | impl Foo for S { <|> }"#, | ||
627 | r#" | ||
628 | trait Foo { | ||
629 | type Output; | ||
630 | |||
631 | const CONST: usize = 42; | ||
632 | |||
633 | fn valid(some: u32) -> bool { false } | ||
634 | fn foo(some: u32) -> bool; | ||
635 | } | ||
636 | struct S; | ||
637 | impl Foo for S { | ||
638 | $0fn valid(some: u32) -> bool { false } | ||
639 | }"#, | ||
640 | ) | ||
641 | } | ||
642 | |||
643 | #[test] | ||
644 | fn test_generic_single_default_parameter() { | ||
645 | check_assist( | ||
646 | add_missing_impl_members, | ||
647 | r#" | ||
648 | trait Foo<T = Self> { | ||
649 | fn bar(&self, other: &T); | ||
650 | } | ||
651 | |||
652 | struct S; | ||
653 | impl Foo for S { <|> }"#, | ||
654 | r#" | ||
655 | trait Foo<T = Self> { | ||
656 | fn bar(&self, other: &T); | ||
657 | } | ||
658 | |||
659 | struct S; | ||
660 | impl Foo for S { | ||
661 | fn bar(&self, other: &Self) { | ||
662 | ${0:todo!()} | ||
663 | } | ||
664 | }"#, | ||
665 | ) | ||
666 | } | ||
667 | |||
668 | #[test] | ||
669 | fn test_generic_default_parameter_is_second() { | ||
670 | check_assist( | ||
671 | add_missing_impl_members, | ||
672 | r#" | ||
673 | trait Foo<T1, T2 = Self> { | ||
674 | fn bar(&self, this: &T1, that: &T2); | ||
675 | } | ||
676 | |||
677 | struct S<T>; | ||
678 | impl Foo<T> for S<T> { <|> }"#, | ||
679 | r#" | ||
680 | trait Foo<T1, T2 = Self> { | ||
681 | fn bar(&self, this: &T1, that: &T2); | ||
682 | } | ||
683 | |||
684 | struct S<T>; | ||
685 | impl Foo<T> for S<T> { | ||
686 | fn bar(&self, this: &T, that: &Self) { | ||
687 | ${0:todo!()} | ||
688 | } | ||
689 | }"#, | ||
690 | ) | ||
691 | } | ||
692 | |||
693 | #[test] | ||
694 | fn test_assoc_type_bounds_are_removed() { | ||
695 | check_assist( | ||
696 | add_missing_impl_members, | ||
697 | r#" | ||
698 | trait Tr { | ||
699 | type Ty: Copy + 'static; | ||
700 | } | ||
701 | |||
702 | impl Tr for ()<|> { | ||
703 | }"#, | ||
704 | r#" | ||
705 | trait Tr { | ||
706 | type Ty: Copy + 'static; | ||
707 | } | ||
708 | |||
709 | impl Tr for () { | ||
710 | $0type Ty; | ||
711 | }"#, | ||
712 | ) | ||
713 | } | ||
714 | |||
715 | #[test] | ||
716 | fn test_whitespace_fixup_preserves_bad_tokens() { | ||
717 | check_assist( | ||
718 | add_missing_impl_members, | ||
719 | r#" | ||
720 | trait Tr { | ||
721 | fn foo(); | ||
722 | } | ||
723 | |||
724 | impl Tr for ()<|> { | ||
725 | +++ | ||
726 | }"#, | ||
727 | r#" | ||
728 | trait Tr { | ||
729 | fn foo(); | ||
730 | } | ||
731 | |||
732 | impl Tr for () { | ||
733 | fn foo() { | ||
734 | ${0:todo!()} | ||
735 | } | ||
736 | +++ | ||
737 | }"#, | ||
738 | ) | ||
739 | } | ||
740 | |||
741 | #[test] | ||
742 | fn test_whitespace_fixup_preserves_comments() { | ||
743 | check_assist( | ||
744 | add_missing_impl_members, | ||
745 | r#" | ||
746 | trait Tr { | ||
747 | fn foo(); | ||
748 | } | ||
749 | |||
750 | impl Tr for ()<|> { | ||
751 | // very important | ||
752 | }"#, | ||
753 | r#" | ||
754 | trait Tr { | ||
755 | fn foo(); | ||
756 | } | ||
757 | |||
758 | impl Tr for () { | ||
759 | fn foo() { | ||
760 | ${0:todo!()} | ||
761 | } | ||
762 | // very important | ||
763 | }"#, | ||
764 | ) | ||
765 | } | ||
766 | } | ||