11use crate :: assist_context:: { AssistContext , Assists } ;
2- use ide_db:: assists:: AssistId ;
2+ use ide_db:: { assists:: AssistId , defs :: Definition , search :: SearchScope } ;
33use syntax:: {
44 AstNode , AstToken , SyntaxKind , T ,
55 ast:: {
@@ -114,10 +114,11 @@ pub(crate) fn generate_trait_from_impl(
114114
115115 let editor = builder. make_editor ( impl_ast. syntax ( ) ) ;
116116 let make = editor. make ( ) ;
117+ let params = used_params ( & impl_ast, make, ctx) ;
117118 let trait_ast = make. trait_ (
118119 false ,
119120 & trait_name ( & impl_assoc_items, make) . text ( ) ,
120- impl_ast . generic_param_list ( ) ,
121+ params . clone ( ) ,
121122 impl_ast. where_clause ( ) ,
122123 trait_items,
123124 ) ;
@@ -133,7 +134,7 @@ pub(crate) fn generate_trait_from_impl(
133134 make. whitespace( " " ) . into( ) ,
134135 ] ;
135136
136- if let Some ( params) = impl_ast . generic_param_list ( ) {
137+ if let Some ( params) = params {
137138 let gen_args = & params. to_generic_args ( make) ;
138139 elements. insert ( 1 , gen_args. syntax ( ) . clone ( ) . into ( ) ) ;
139140 }
@@ -167,6 +168,35 @@ pub(crate) fn generate_trait_from_impl(
167168 Some ( ( ) )
168169}
169170
171+ fn used_params (
172+ impl_ast : & ast:: Impl ,
173+ make : & SyntaxFactory ,
174+ ctx : & AssistContext < ' _ , ' _ > ,
175+ ) -> Option < ast:: GenericParamList > {
176+ let impl_only_ranges = impl_ast
177+ . assoc_item_list ( )
178+ . into_iter ( )
179+ . flat_map ( |list| list. assoc_items ( ) )
180+ . filter_map ( |item| match item {
181+ ast:: AssocItem :: Fn ( f) => Some ( f. body ( ) ?. syntax ( ) . text_range ( ) ) ,
182+ _ => None ,
183+ } )
184+ . chain ( impl_ast. self_ty ( ) . map ( |it| it. syntax ( ) . text_range ( ) ) )
185+ . collect :: < Vec < _ > > ( ) ;
186+ let used_in_impl = |param : & ast:: GenericParam | {
187+ let Some ( def) = ctx. sema . to_def ( param) else { return true } ;
188+ Definition :: GenericParam ( def)
189+ . usages ( & ctx. sema )
190+ . in_scope ( & SearchScope :: single_file ( ctx. file_id ( ) ) )
191+ . all ( )
192+ . file_ranges ( )
193+ . any ( |it| !impl_only_ranges. iter ( ) . any ( |range| range. contains_range ( it. range ) ) )
194+ } ;
195+ let params = impl_ast. generic_param_list ( ) ?;
196+ let mut params = params. generic_params ( ) . filter ( used_in_impl) . peekable ( ) ;
197+ params. peek ( ) . is_some ( ) . then ( || make. generic_param_list ( params) )
198+ }
199+
170200fn trait_name ( items : & ast:: AssocItemList , make : & SyntaxFactory ) -> ast:: Name {
171201 let mut fn_names = items
172202 . assoc_items ( )
@@ -391,6 +421,87 @@ impl<const N: usize> NewTrait<N> for Foo<N> {
391421 )
392422 }
393423
424+ #[ test]
425+ fn test_impl_with_generics_only_used_in_trait ( ) {
426+ check_assist_no_snippet_cap (
427+ generate_trait_from_impl,
428+ r#"
429+ struct Foo<T, const N: usize>([T; N]);
430+
431+ impl<T, const N: usize> F$0oo<T, N> {
432+ fn spec_len(&self) -> usize {
433+ N
434+ }
435+ }
436+ "# ,
437+ r#"
438+ struct Foo<T, const N: usize>([T; N]);
439+
440+ trait SpecLen {
441+ fn spec_len(&self) -> usize;
442+ }
443+
444+ impl<T, const N: usize> SpecLen for Foo<T, N> {
445+ fn spec_len(&self) -> usize {
446+ N
447+ }
448+ }
449+ "# ,
450+ ) ;
451+
452+ check_assist_no_snippet_cap (
453+ generate_trait_from_impl,
454+ r#"
455+ struct Foo<T, const N: usize>([T; N]);
456+
457+ impl<T, const N: usize> F$0oo<T, N> {
458+ fn spec_len(&self, other: [T; N]) -> usize {
459+ 0
460+ }
461+ }
462+ "# ,
463+ r#"
464+ struct Foo<T, const N: usize>([T; N]);
465+
466+ trait SpecLen<T, const N: usize> {
467+ fn spec_len(&self, other: [T; N]) -> usize;
468+ }
469+
470+ impl<T, const N: usize> SpecLen<T, N> for Foo<T, N> {
471+ fn spec_len(&self, other: [T; N]) -> usize {
472+ 0
473+ }
474+ }
475+ "# ,
476+ ) ;
477+
478+ check_assist_no_snippet_cap (
479+ generate_trait_from_impl,
480+ r#"
481+ struct Foo<T, const N: usize>([T; N]);
482+
483+ impl<T, const N: usize> F$0oo<T, N> where T: Copy {
484+ fn spec_len(&self) -> usize {
485+ 0
486+ }
487+ }
488+ "# ,
489+ r#"
490+ struct Foo<T, const N: usize>([T; N]);
491+
492+ trait SpecLen<T> where T: Copy {
493+ fn spec_len(&self) -> usize;
494+ }
495+
496+ impl<T, const N: usize> SpecLen<T> for Foo<T, N> where T: Copy {
497+ fn spec_len(&self) -> usize {
498+ 0
499+ }
500+ }
501+ "# ,
502+ ) ;
503+ }
504+
394505 #[ test]
395506 fn test_trait_items_should_not_have_vis ( ) {
396507 check_assist_no_snippet_cap (
0 commit comments