1- use ide_db:: famous_defs:: FamousDefs ;
1+ use ide_db:: { famous_defs:: FamousDefs , traits :: resolve_target_trait } ;
22use syntax:: {
33 AstNode ,
44 ast:: { self , edit_in_place:: Indent , make} ,
@@ -48,36 +48,34 @@ pub(crate) fn generate_mut_trait_impl(acc: &mut Assists, ctx: &AssistContext<'_>
4848 let impl_def = ctx. find_node_at_offset :: < ast:: Impl > ( ) ?. clone_for_update ( ) ;
4949 let indent = impl_def. indent_level ( ) ;
5050
51- let trait_ = impl_def. trait_ ( ) ?;
52- if let ast:: Type :: PathType ( trait_path) = trait_ {
53- let trait_type = ctx. sema . resolve_trait ( & trait_path. path ( ) ?) ?;
54- let scope = ctx. sema . scope ( trait_path. syntax ( ) ) ?;
55- if trait_type != FamousDefs ( & ctx. sema , scope. krate ( ) ) . core_convert_Index ( ) ? {
56- return None ;
57- }
58- }
51+ let ast:: Type :: PathType ( path) = impl_def. trait_ ( ) ? else {
52+ return None ;
53+ } ;
54+ let trait_name = path. path ( ) ?. segment ( ) ?. name_ref ( ) ?;
55+
56+ let scope = ctx. sema . scope ( impl_def. trait_ ( ) ?. syntax ( ) ) ?;
57+ let famous = FamousDefs ( & ctx. sema , scope. krate ( ) ) ;
58+
59+ let trait_ = resolve_target_trait ( & ctx. sema , & impl_def) ?;
60+ let trait_new = get_trait_mut ( & trait_, famous) ?;
5961
6062 // Index -> IndexMut
61- let index_trait = impl_def
62- . syntax ( )
63- . descendants ( )
64- . filter_map ( ast:: NameRef :: cast)
65- . find ( |it| it. text ( ) == "Index" ) ?;
66- ted:: replace (
67- index_trait. syntax ( ) ,
68- make:: path_segment ( make:: name_ref ( "IndexMut" ) ) . clone_for_update ( ) . syntax ( ) ,
69- ) ;
63+ ted:: replace ( trait_name. syntax ( ) , make:: name_ref ( trait_new) . clone_for_update ( ) . syntax ( ) ) ;
7064
7165 // index -> index_mut
72- let trait_method_name = impl_def
66+ let ( trait_method_name, new_trait_method_name ) = impl_def
7367 . syntax ( )
7468 . descendants ( )
7569 . filter_map ( ast:: Name :: cast)
76- . find ( |it| it. text ( ) == "index" ) ?;
77- ted:: replace ( trait_method_name. syntax ( ) , make:: name ( "index_mut" ) . clone_for_update ( ) . syntax ( ) ) ;
70+ . find_map ( process_method_name) ?;
71+ ted:: replace (
72+ trait_method_name. syntax ( ) ,
73+ make:: name ( new_trait_method_name) . clone_for_update ( ) . syntax ( ) ,
74+ ) ;
7875
79- let type_alias = impl_def. syntax ( ) . descendants ( ) . find_map ( ast:: TypeAlias :: cast) ?;
80- ted:: remove ( type_alias. syntax ( ) ) ;
76+ if let Some ( type_alias) = impl_def. syntax ( ) . descendants ( ) . find_map ( ast:: TypeAlias :: cast) {
77+ ted:: remove ( type_alias. syntax ( ) ) ;
78+ }
8179
8280 // &self -> &mut self
8381 let mut_self_param = make:: mut_self_param ( ) ;
@@ -87,10 +85,8 @@ pub(crate) fn generate_mut_trait_impl(acc: &mut Assists, ctx: &AssistContext<'_>
8785
8886 // &Self::Output -> &mut Self::Output
8987 let ret_type = impl_def. syntax ( ) . descendants ( ) . find_map ( ast:: RetType :: cast) ?;
90- ted:: replace (
91- ret_type. syntax ( ) ,
92- make:: ret_type ( make:: ty ( "&mut Self::Output" ) ) . clone_for_update ( ) . syntax ( ) ,
93- ) ;
88+ let new_ret_type = process_ret_type ( & ret_type) ?;
89+ ted:: replace ( ret_type. syntax ( ) , make:: ret_type ( new_ret_type) . clone_for_update ( ) . syntax ( ) ) ;
9490
9591 let fn_ = impl_def. assoc_item_list ( ) ?. assoc_items ( ) . find_map ( |it| match it {
9692 ast:: AssocItem :: Fn ( f) => Some ( f) ,
@@ -104,14 +100,46 @@ pub(crate) fn generate_mut_trait_impl(acc: &mut Assists, ctx: &AssistContext<'_>
104100 let target = impl_def. syntax ( ) . text_range ( ) ;
105101 acc. add (
106102 AssistId :: generate ( "generate_mut_trait_impl" ) ,
107- "Generate `IndexMut ` impl from this `Index ` trait" ,
103+ format ! ( "Generate `{trait_new} ` impl from this `{trait_name} ` trait" ) ,
108104 target,
109105 |edit| {
110106 edit. insert ( target. start ( ) , format ! ( "$0{impl_def}\n \n {indent}" ) ) ;
111107 } ,
112108 )
113109}
114110
111+ fn get_trait_mut ( apply_trait : & hir:: Trait , famous : FamousDefs < ' _ , ' _ > ) -> Option < & ' static str > {
112+ let trait_ = Some ( apply_trait) ;
113+ if trait_ == famous. core_convert_Index ( ) . as_ref ( ) {
114+ return Some ( "IndexMut" ) ;
115+ }
116+ if trait_ == famous. core_convert_AsRef ( ) . as_ref ( ) {
117+ return Some ( "AsMut" ) ;
118+ }
119+ if trait_ == famous. core_borrow_Borrow ( ) . as_ref ( ) {
120+ return Some ( "BorrowMut" ) ;
121+ }
122+ None
123+ }
124+
125+ fn process_method_name ( name : ast:: Name ) -> Option < ( ast:: Name , & ' static str ) > {
126+ let new_name = match & * name. text ( ) {
127+ "index" => "index_mut" ,
128+ "as_ref" => "as_mut" ,
129+ "borrow" => "borrow_mut" ,
130+ _ => return None ,
131+ } ;
132+ Some ( ( name, new_name) )
133+ }
134+
135+ fn process_ret_type ( ref_ty : & ast:: RetType ) -> Option < ast:: Type > {
136+ let ty = ref_ty. ty ( ) ?;
137+ let ast:: Type :: RefType ( ref_type) = ty else {
138+ return None ;
139+ } ;
140+ Some ( make:: ty_ref ( ref_type. ty ( ) ?, true ) )
141+ }
142+
115143#[ cfg( test) ]
116144mod tests {
117145 use crate :: tests:: { check_assist, check_assist_not_applicable} ;
@@ -186,6 +214,35 @@ impl<T> core::ops::Index<Axis> for [T; 3] where T: Copy {
186214 var_name
187215 }
188216}
217+ "# ,
218+ ) ;
219+
220+ check_assist (
221+ generate_mut_trait_impl,
222+ r#"
223+ //- minicore: as_ref
224+ struct Foo(i32);
225+
226+ impl core::convert::AsRef$0<i32> for Foo {
227+ fn as_ref(&self) -> &i32 {
228+ &self.0
229+ }
230+ }
231+ "# ,
232+ r#"
233+ struct Foo(i32);
234+
235+ $0impl core::convert::AsMut<i32> for Foo {
236+ fn as_mut(&mut self) -> &mut i32 {
237+ &self.0
238+ }
239+ }
240+
241+ impl core::convert::AsRef<i32> for Foo {
242+ fn as_ref(&self) -> &i32 {
243+ &self.0
244+ }
245+ }
189246"# ,
190247 ) ;
191248 }
@@ -285,6 +342,14 @@ mod foo {
285342pub trait Index<Idx: ?Sized> {}
286343
287344impl<T> Index$0<i32> for [T; 3] {}
345+ "# ,
346+ ) ;
347+ check_assist_not_applicable (
348+ generate_mut_trait_impl,
349+ r#"
350+ pub trait AsRef<T: ?Sized> {}
351+
352+ impl AsRef$0<i32> for [T; 3] {}
288353"# ,
289354 ) ;
290355 }
0 commit comments