@@ -221,24 +221,47 @@ fn rename_to_self(
221221 let source_file = sema. parse ( position. file_id ) ;
222222 let syn = source_file. syntax ( ) ;
223223
224- let fn_def = find_node_at_offset :: < ast:: Fn > ( syn, position. offset )
224+ let ( fn_def, fn_ast) = find_node_at_offset :: < ast:: Fn > ( syn, position. offset )
225+ . and_then ( |fn_ast| sema. to_def ( & fn_ast) . zip ( Some ( fn_ast) ) )
225226 . ok_or_else ( || RenameError ( "No surrounding method declaration found" . to_string ( ) ) ) ?;
226- let params =
227- fn_def. param_list ( ) . ok_or_else ( || RenameError ( "Method has no parameters" . to_string ( ) ) ) ?;
228- if params. self_param ( ) . is_some ( ) {
227+ let param_range = fn_ast
228+ . param_list ( )
229+ . and_then ( |p| p. params ( ) . next ( ) )
230+ . ok_or_else ( || RenameError ( "Method has no parameters" . to_string ( ) ) ) ?
231+ . syntax ( )
232+ . text_range ( ) ;
233+ if !param_range. contains ( position. offset ) {
234+ return Err ( RenameError ( "Only the first parameter can be self" . to_string ( ) ) ) ;
235+ }
236+
237+ let impl_block = find_node_at_offset :: < ast:: Impl > ( syn, position. offset )
238+ . and_then ( |def| sema. to_def ( & def) )
239+ . ok_or_else ( || RenameError ( "No impl block found for function" . to_string ( ) ) ) ?;
240+ if fn_def. self_param ( sema. db ) . is_some ( ) {
229241 return Err ( RenameError ( "Method already has a self parameter" . to_string ( ) ) ) ;
230242 }
243+
244+ let params = fn_def. params ( sema. db ) ;
231245 let first_param =
232- params. params ( ) . next ( ) . ok_or_else ( || RenameError ( "Method has no parameters" . into ( ) ) ) ?;
233- let mutable = match first_param. ty ( ) {
234- Some ( ast:: Type :: RefType ( rt) ) => rt. mut_token ( ) . is_some ( ) ,
235- _ => return Err ( RenameError ( "Not renaming other types" . to_string ( ) ) ) ,
246+ params. first ( ) . ok_or_else ( || RenameError ( "Method has no parameters" . into ( ) ) ) ?;
247+ let first_param_ty = first_param. ty ( ) ;
248+ let impl_ty = impl_block. target_ty ( sema. db ) ;
249+ let ( ty, self_param) = if impl_ty. remove_ref ( ) . is_some ( ) {
250+ // if the impl is a ref to the type we can just match the `&T` with self directly
251+ ( first_param_ty. clone ( ) , "self" )
252+ } else {
253+ first_param_ty. remove_ref ( ) . map_or ( ( first_param_ty. clone ( ) , "self" ) , |ty| {
254+ ( ty, if first_param_ty. is_mutable_reference ( ) { "&mut self" } else { "&self" } )
255+ } )
236256 } ;
237257
258+ if ty != impl_ty {
259+ return Err ( RenameError ( "Parameter type differs from impl block type" . to_string ( ) ) ) ;
260+ }
261+
238262 let RangeInfo { range, info : refs } = find_all_refs ( sema, position, None )
239263 . ok_or_else ( || RenameError ( "No reference found at position" . to_string ( ) ) ) ?;
240264
241- let param_range = first_param. syntax ( ) . text_range ( ) ;
242265 let ( param_ref, usages) : ( Vec < Reference > , Vec < Reference > ) = refs
243266 . into_iter ( )
244267 . partition ( |reference| param_range. intersect ( reference. file_range . range ) . is_some ( ) ) ;
@@ -254,10 +277,7 @@ fn rename_to_self(
254277
255278 edits. push ( SourceFileEdit {
256279 file_id : position. file_id ,
257- edit : TextEdit :: replace (
258- param_range,
259- String :: from ( if mutable { "&mut self" } else { "&self" } ) ,
260- ) ,
280+ edit : TextEdit :: replace ( param_range, String :: from ( self_param) ) ,
261281 } ) ;
262282
263283 Ok ( RangeInfo :: new ( range, SourceChange :: from ( edits) ) )
@@ -1084,6 +1104,95 @@ impl Foo {
10841104 self.i
10851105 }
10861106}
1107+ "# ,
1108+ ) ;
1109+ check (
1110+ "self" ,
1111+ r#"
1112+ struct Foo { i: i32 }
1113+
1114+ impl Foo {
1115+ fn f(foo<|>: Foo) -> i32 {
1116+ foo.i
1117+ }
1118+ }
1119+ "# ,
1120+ r#"
1121+ struct Foo { i: i32 }
1122+
1123+ impl Foo {
1124+ fn f(self) -> i32 {
1125+ self.i
1126+ }
1127+ }
1128+ "# ,
1129+ ) ;
1130+ }
1131+
1132+ #[ test]
1133+ fn test_parameter_to_self_error_no_impl ( ) {
1134+ check (
1135+ "self" ,
1136+ r#"
1137+ struct Foo { i: i32 }
1138+
1139+ fn f(foo<|>: &mut Foo) -> i32 {
1140+ foo.i
1141+ }
1142+ "# ,
1143+ "error: No impl block found for function" ,
1144+ ) ;
1145+ check (
1146+ "self" ,
1147+ r#"
1148+ struct Foo { i: i32 }
1149+ struct Bar;
1150+
1151+ impl Bar {
1152+ fn f(foo<|>: &mut Foo) -> i32 {
1153+ foo.i
1154+ }
1155+ }
1156+ "# ,
1157+ "error: Parameter type differs from impl block type" ,
1158+ ) ;
1159+ }
1160+
1161+ #[ test]
1162+ fn test_parameter_to_self_error_not_first ( ) {
1163+ check (
1164+ "self" ,
1165+ r#"
1166+ struct Foo { i: i32 }
1167+ impl Foo {
1168+ fn f(x: (), foo<|>: &mut Foo) -> i32 {
1169+ foo.i
1170+ }
1171+ }
1172+ "# ,
1173+ "error: Only the first parameter can be self" ,
1174+ ) ;
1175+ }
1176+
1177+ #[ test]
1178+ fn test_parameter_to_self_impl_ref ( ) {
1179+ check (
1180+ "self" ,
1181+ r#"
1182+ struct Foo { i: i32 }
1183+ impl &Foo {
1184+ fn f(foo<|>: &Foo) -> i32 {
1185+ foo.i
1186+ }
1187+ }
1188+ "# ,
1189+ r#"
1190+ struct Foo { i: i32 }
1191+ impl &Foo {
1192+ fn f(self) -> i32 {
1193+ self.i
1194+ }
1195+ }
10871196"# ,
10881197 ) ;
10891198 }
0 commit comments