11use crate :: { AssistContext , AssistId , Assists } ;
2- use ra_syntax:: { ast, ast:: { TypeParamsOwner } , AstNode , SyntaxKind } ;
2+ use ra_syntax:: { ast, ast:: TypeParamsOwner , AstNode , SyntaxKind } ;
3+ use std:: collections:: HashSet ;
34
45/// Assist: change_lifetime_anon_to_named
56///
@@ -24,7 +25,7 @@ use ra_syntax::{ast, ast::{TypeParamsOwner}, AstNode, SyntaxKind};
2425/// }
2526/// }
2627/// ```
27- // TODO : How can we handle renaming any one of multiple anonymous lifetimes?
28+ // FIXME : How can we handle renaming any one of multiple anonymous lifetimes?
2829pub ( crate ) fn change_lifetime_anon_to_named ( acc : & mut Assists , ctx : & AssistContext ) -> Option < ( ) > {
2930 let lifetime_token = ctx. find_token_at_offset ( SyntaxKind :: LIFETIME ) ?;
3031 let lifetime_arg = ast:: LifetimeArg :: cast ( lifetime_token. parent ( ) ) ?;
@@ -43,6 +44,22 @@ pub(crate) fn change_lifetime_anon_to_named(acc: &mut Assists, ctx: &AssistConte
4344 if impl_kw. kind ( ) != SyntaxKind :: IMPL_KW {
4445 return None ;
4546 }
47+ let new_lifetime_param = match impl_def. type_param_list ( ) {
48+ Some ( type_params) => {
49+ let used_lifetime_params: HashSet < _ > = type_params
50+ . lifetime_params ( )
51+ . map ( |p| {
52+ let mut param_name = p. syntax ( ) . text ( ) . to_string ( ) ;
53+ param_name. remove ( 0 ) ;
54+ param_name
55+ } )
56+ . collect ( ) ;
57+ "abcdefghijklmnopqrstuvwxyz"
58+ . chars ( )
59+ . find ( |c| !used_lifetime_params. contains ( & c. to_string ( ) ) ) ?
60+ }
61+ None => 'a' ,
62+ } ;
4663 acc. add (
4764 AssistId ( "change_lifetime_anon_to_named" ) ,
4865 "Give anonymous lifetime a name" ,
@@ -52,17 +69,20 @@ pub(crate) fn change_lifetime_anon_to_named(acc: &mut Assists, ctx: &AssistConte
5269 Some ( type_params) => {
5370 builder. insert (
5471 ( u32:: from ( type_params. syntax ( ) . text_range ( ) . end ( ) ) - 1 ) . into ( ) ,
55- ", 'a" ,
72+ format ! ( ", '{}" , new_lifetime_param ) ,
5673 ) ;
57- } ,
74+ }
5875 None => {
5976 builder. insert (
6077 impl_kw. text_range ( ) . end ( ) ,
61- "<'a>" ,
78+ format ! ( "<'{}>" , new_lifetime_param ) ,
6279 ) ;
63- } ,
80+ }
6481 }
65- builder. replace ( lifetime_arg. syntax ( ) . text_range ( ) , "'a" ) ;
82+ builder. replace (
83+ lifetime_arg. syntax ( ) . text_range ( ) ,
84+ format ! ( "'{}" , new_lifetime_param) ,
85+ ) ;
6686 } ,
6787 )
6888 }
@@ -120,4 +140,13 @@ mod tests {
120140 r#"impl<T, 'a> Cursor<T, 'a>"# ,
121141 ) ;
122142 }
143+
144+ #[ test]
145+ fn test_with_existing_lifetime_name_conflict ( ) {
146+ check_assist (
147+ change_lifetime_anon_to_named,
148+ r#"impl<'a, 'b> Cursor<'a, 'b, '_<|>>"# ,
149+ r#"impl<'a, 'b, 'c> Cursor<'a, 'b, 'c>"# ,
150+ ) ;
151+ }
123152}
0 commit comments