1
1
use syntax:: ast:: { self , AstNode , HasName } ;
2
2
3
- use crate :: { utils:: generate_impl_text, AssistContext , AssistId , AssistKind , Assists } ;
3
+ use crate :: {
4
+ utils:: { generate_impl_text, generate_trait_impl_text} ,
5
+ AssistContext , AssistId , AssistKind , Assists ,
6
+ } ;
4
7
5
8
// Assist: generate_impl
6
9
//
@@ -50,6 +53,54 @@ pub(crate) fn generate_impl(acc: &mut Assists, ctx: &AssistContext<'_>) -> Optio
50
53
)
51
54
}
52
55
56
+ // Assist: generate_trait_impl
57
+ //
58
+ // Adds a new trait impl for a type.
59
+ //
60
+ // ```
61
+ // struct $0Ctx<T: Clone> {
62
+ // data: T,
63
+ // }
64
+ // ```
65
+ // ->
66
+ // ```
67
+ // struct Ctx<T: Clone> {
68
+ // data: T,
69
+ // }
70
+ //
71
+ // impl<T: Clone> $0 for Ctx<T> {
72
+ //
73
+ // }
74
+ // ```
75
+ pub ( crate ) fn generate_trait_impl ( acc : & mut Assists , ctx : & AssistContext < ' _ > ) -> Option < ( ) > {
76
+ let nominal = ctx. find_node_at_offset :: < ast:: Adt > ( ) ?;
77
+ let name = nominal. name ( ) ?;
78
+ let target = nominal. syntax ( ) . text_range ( ) ;
79
+
80
+ if let Some ( _) = ctx. find_node_at_offset :: < ast:: RecordFieldList > ( ) {
81
+ return None ;
82
+ }
83
+
84
+ acc. add (
85
+ AssistId ( "generate_trait_impl" , AssistKind :: Generate ) ,
86
+ format ! ( "Generate trait impl for `{name}`" ) ,
87
+ target,
88
+ |edit| {
89
+ let start_offset = nominal. syntax ( ) . text_range ( ) . end ( ) ;
90
+ match ctx. config . snippet_cap {
91
+ Some ( cap) => {
92
+ let snippet = generate_trait_impl_text ( & nominal, "$0" , "" ) ;
93
+ edit. insert_snippet ( cap, start_offset, snippet) ;
94
+ }
95
+ None => {
96
+ let text = generate_trait_impl_text ( & nominal, "" , "" ) ;
97
+ edit. insert ( start_offset, text) ;
98
+ }
99
+ }
100
+ } ,
101
+ )
102
+ }
103
+
53
104
#[ cfg( test) ]
54
105
mod tests {
55
106
use crate :: tests:: { check_assist, check_assist_target} ;
@@ -211,7 +262,7 @@ mod tests {
211
262
}
212
263
213
264
#[ test]
214
- fn add_trait_impl_target ( ) {
265
+ fn add_impl_target ( ) {
215
266
check_assist_target (
216
267
generate_impl,
217
268
r#"
@@ -223,4 +274,172 @@ mod tests {
223
274
"/// Has a lifetime parameter\n struct Foo<'a, T: Foo<'a>> {}" ,
224
275
) ;
225
276
}
277
+
278
+ #[ test]
279
+ fn test_add_trait_impl ( ) {
280
+ check_assist (
281
+ generate_trait_impl,
282
+ r#"
283
+ struct Foo$0 {}
284
+ "# ,
285
+ r#"
286
+ struct Foo {}
287
+
288
+ impl $0 for Foo {
289
+
290
+ }
291
+ "# ,
292
+ ) ;
293
+ }
294
+
295
+ #[ test]
296
+ fn test_add_trait_impl_with_generics ( ) {
297
+ check_assist (
298
+ generate_trait_impl,
299
+ r#"
300
+ struct Foo$0<T: Clone> {}
301
+ "# ,
302
+ r#"
303
+ struct Foo<T: Clone> {}
304
+
305
+ impl<T: Clone> $0 for Foo<T> {
306
+
307
+ }
308
+ "# ,
309
+ ) ;
310
+ }
311
+
312
+ #[ test]
313
+ fn test_add_trait_impl_with_generics_and_lifetime_parameters ( ) {
314
+ check_assist (
315
+ generate_trait_impl,
316
+ r#"
317
+ struct Foo<'a, T: Foo<'a>>$0 {}
318
+ "# ,
319
+ r#"
320
+ struct Foo<'a, T: Foo<'a>> {}
321
+
322
+ impl<'a, T: Foo<'a>> $0 for Foo<'a, T> {
323
+
324
+ }
325
+ "# ,
326
+ ) ;
327
+ }
328
+
329
+ #[ test]
330
+ fn test_add_trait_impl_with_attributes ( ) {
331
+ check_assist (
332
+ generate_trait_impl,
333
+ r#"
334
+ #[cfg(feature = "foo")]
335
+ struct Foo<'a, T: Foo$0<'a>> {}
336
+ "# ,
337
+ r#"
338
+ #[cfg(feature = "foo")]
339
+ struct Foo<'a, T: Foo<'a>> {}
340
+
341
+ #[cfg(feature = "foo")]
342
+ impl<'a, T: Foo<'a>> $0 for Foo<'a, T> {
343
+
344
+ }
345
+ "# ,
346
+ ) ;
347
+ }
348
+
349
+ #[ test]
350
+ fn test_add_trait_impl_with_default_generic ( ) {
351
+ check_assist (
352
+ generate_trait_impl,
353
+ r#"
354
+ struct Defaulted$0<T = i32> {}
355
+ "# ,
356
+ r#"
357
+ struct Defaulted<T = i32> {}
358
+
359
+ impl<T> $0 for Defaulted<T> {
360
+
361
+ }
362
+ "# ,
363
+ ) ;
364
+ }
365
+
366
+ #[ test]
367
+ fn test_add_trait_impl_with_constrained_default_generic ( ) {
368
+ check_assist (
369
+ generate_trait_impl,
370
+ r#"
371
+ struct Defaulted$0<'a, 'b: 'a, T: Debug + Clone + 'a + 'b = String, const S: usize> {}
372
+ "# ,
373
+ r#"
374
+ struct Defaulted<'a, 'b: 'a, T: Debug + Clone + 'a + 'b = String, const S: usize> {}
375
+
376
+ impl<'a, 'b: 'a, T: Debug + Clone + 'a + 'b, const S: usize> $0 for Defaulted<'a, 'b, T, S> {
377
+
378
+ }
379
+ "# ,
380
+ ) ;
381
+ }
382
+
383
+ #[ test]
384
+ fn test_add_trait_impl_with_const_defaulted_generic ( ) {
385
+ check_assist (
386
+ generate_trait_impl,
387
+ r#"
388
+ struct Defaulted$0<const N: i32 = 0> {}
389
+ "# ,
390
+ r#"
391
+ struct Defaulted<const N: i32 = 0> {}
392
+
393
+ impl<const N: i32> $0 for Defaulted<N> {
394
+
395
+ }
396
+ "# ,
397
+ ) ;
398
+ }
399
+
400
+ #[ test]
401
+ fn test_add_trait_impl_with_trait_constraint ( ) {
402
+ check_assist (
403
+ generate_trait_impl,
404
+ r#"
405
+ pub trait Trait {}
406
+ struct Struct$0<T>
407
+ where
408
+ T: Trait,
409
+ {
410
+ inner: T,
411
+ }
412
+ "# ,
413
+ r#"
414
+ pub trait Trait {}
415
+ struct Struct<T>
416
+ where
417
+ T: Trait,
418
+ {
419
+ inner: T,
420
+ }
421
+
422
+ impl<T> $0 for Struct<T>
423
+ where
424
+ T: Trait,
425
+ {
426
+
427
+ }
428
+ "# ,
429
+ ) ;
430
+ }
431
+
432
+ #[ test]
433
+ fn add_trait_impl_target ( ) {
434
+ check_assist_target (
435
+ generate_trait_impl,
436
+ r#"
437
+ struct SomeThingIrrelevant;
438
+ /// Has a lifetime parameter
439
+ struct Foo$0<'a, T: Foo<'a>> {}
440
+ struct EvenMoreIrrelevant;
441
+ "# ,
442
+ "/// Has a lifetime parameter\n struct Foo<'a, T: Foo<'a>> {}" ,
443
+ ) ;
444
+ }
226
445
}
0 commit comments