11use crate :: assist_context:: { AssistContext , Assists } ;
2- use ide_db:: assists:: AssistId ;
2+ use ide_db:: { assists:: AssistId , defs :: Definition , search :: SearchScope } ;
33use syntax:: {
4- AstNode , AstToken , SyntaxKind , T ,
4+ AstNode , AstToken , SyntaxKind , T , TextRange ,
55 ast:: {
66 self , HasDocComments , HasGenericParams , HasName , HasVisibility , edit:: AstNodeEdit ,
77 syntax_factory:: SyntaxFactory ,
@@ -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,42 @@ 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 item_in_trait_range = |item| match item {
177+ ast:: AssocItem :: Const ( _) | ast:: AssocItem :: MacroCall ( _) | ast:: AssocItem :: TypeAlias ( _) => {
178+ item. syntax ( ) . text_range ( )
179+ }
180+ ast:: AssocItem :: Fn ( fn_item) => {
181+ let range = fn_item. syntax ( ) . text_range ( ) ;
182+ fn_item. body ( ) . map_or ( range, |body| {
183+ TextRange :: new ( range. start ( ) , body. syntax ( ) . text_range ( ) . start ( ) )
184+ } )
185+ }
186+ } ;
187+ let trait_ranges = impl_ast
188+ . assoc_item_list ( )
189+ . into_iter ( )
190+ . flat_map ( |list| list. assoc_items ( ) )
191+ . map ( item_in_trait_range)
192+ . collect :: < Vec < _ > > ( ) ;
193+ let used_in_impl = |param : & ast:: GenericParam | {
194+ let Some ( def) = ctx. sema . to_def ( param) else { return true } ;
195+ Definition :: GenericParam ( def)
196+ . usages ( & ctx. sema )
197+ . in_scope ( & SearchScope :: single_file ( ctx. file_id ( ) ) )
198+ . all ( )
199+ . file_ranges ( )
200+ . any ( |it| trait_ranges. iter ( ) . any ( |range| range. contains_range ( it. range ) ) )
201+ } ;
202+ let params = impl_ast. generic_param_list ( ) ?;
203+ let mut params = params. generic_params ( ) . filter ( used_in_impl) . peekable ( ) ;
204+ params. peek ( ) . is_some ( ) . then ( || make. generic_param_list ( params) )
205+ }
206+
170207fn trait_name ( items : & ast:: AssocItemList , make : & SyntaxFactory ) -> ast:: Name {
171208 let mut fn_names = items
172209 . assoc_items ( )
@@ -391,6 +428,61 @@ impl<const N: usize> NewTrait<N> for Foo<N> {
391428 )
392429 }
393430
431+ #[ test]
432+ fn test_impl_with_generics_only_used_in_trait ( ) {
433+ check_assist_no_snippet_cap (
434+ generate_trait_from_impl,
435+ r#"
436+ struct Foo<T, const N: usize>([T; N]);
437+
438+ impl<T, const N: usize> F$0oo<T, N> {
439+ fn spec_len(&self) -> usize {
440+ N
441+ }
442+ }
443+ "# ,
444+ r#"
445+ struct Foo<T, const N: usize>([T; N]);
446+
447+ trait SpecLen {
448+ fn spec_len(&self) -> usize;
449+ }
450+
451+ impl<T, const N: usize> SpecLen for Foo<T, N> {
452+ fn spec_len(&self) -> usize {
453+ N
454+ }
455+ }
456+ "# ,
457+ ) ;
458+
459+ check_assist_no_snippet_cap (
460+ generate_trait_from_impl,
461+ r#"
462+ struct Foo<T, const N: usize>([T; N]);
463+
464+ impl<T, const N: usize> F$0oo<T, N> {
465+ fn spec_len(&self, other: [T; N]) -> usize {
466+ 0
467+ }
468+ }
469+ "# ,
470+ r#"
471+ struct Foo<T, const N: usize>([T; N]);
472+
473+ trait SpecLen<T, const N: usize> {
474+ fn spec_len(&self, other: [T; N]) -> usize;
475+ }
476+
477+ impl<T, const N: usize> SpecLen<T, N> for Foo<T, N> {
478+ fn spec_len(&self, other: [T; N]) -> usize {
479+ 0
480+ }
481+ }
482+ "# ,
483+ ) ;
484+ }
485+
394486 #[ test]
395487 fn test_trait_items_should_not_have_vis ( ) {
396488 check_assist_no_snippet_cap (
0 commit comments