11use syntax:: ast:: { self , AstNode , HasName } ;
22
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+ } ;
47
58// Assist: generate_impl
69//
@@ -50,6 +53,54 @@ pub(crate) fn generate_impl(acc: &mut Assists, ctx: &AssistContext<'_>) -> Optio
5053 )
5154}
5255
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+
53104#[ cfg( test) ]
54105mod tests {
55106 use crate :: tests:: { check_assist, check_assist_target} ;
@@ -211,7 +262,7 @@ mod tests {
211262 }
212263
213264 #[ test]
214- fn add_trait_impl_target ( ) {
265+ fn add_impl_target ( ) {
215266 check_assist_target (
216267 generate_impl,
217268 r#"
@@ -223,4 +274,172 @@ mod tests {
223274 "/// Has a lifetime parameter\n struct Foo<'a, T: Foo<'a>> {}" ,
224275 ) ;
225276 }
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+ }
226445}
0 commit comments