1
- use ide_db:: famous_defs:: FamousDefs ;
1
+ use ide_db:: { famous_defs:: FamousDefs , traits :: resolve_target_trait } ;
2
2
use syntax:: {
3
3
AstNode ,
4
4
ast:: { self , edit_in_place:: Indent , make} ,
@@ -48,36 +48,34 @@ pub(crate) fn generate_mut_trait_impl(acc: &mut Assists, ctx: &AssistContext<'_>
48
48
let impl_def = ctx. find_node_at_offset :: < ast:: Impl > ( ) ?. clone_for_update ( ) ;
49
49
let indent = impl_def. indent_level ( ) ;
50
50
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) ?;
59
61
60
62
// 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 ( ) ) ;
70
64
71
65
// index -> index_mut
72
- let trait_method_name = impl_def
66
+ let ( trait_method_name, new_trait_method_name ) = impl_def
73
67
. syntax ( )
74
68
. descendants ( )
75
69
. 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
+ ) ;
78
75
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
+ }
81
79
82
80
// &self -> &mut self
83
81
let mut_self_param = make:: mut_self_param ( ) ;
@@ -87,10 +85,8 @@ pub(crate) fn generate_mut_trait_impl(acc: &mut Assists, ctx: &AssistContext<'_>
87
85
88
86
// &Self::Output -> &mut Self::Output
89
87
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 ( ) ) ;
94
90
95
91
let fn_ = impl_def. assoc_item_list ( ) ?. assoc_items ( ) . find_map ( |it| match it {
96
92
ast:: AssocItem :: Fn ( f) => Some ( f) ,
@@ -104,14 +100,46 @@ pub(crate) fn generate_mut_trait_impl(acc: &mut Assists, ctx: &AssistContext<'_>
104
100
let target = impl_def. syntax ( ) . text_range ( ) ;
105
101
acc. add (
106
102
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" ) ,
108
104
target,
109
105
|edit| {
110
106
edit. insert ( target. start ( ) , format ! ( "$0{impl_def}\n \n {indent}" ) ) ;
111
107
} ,
112
108
)
113
109
}
114
110
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
+
115
143
#[ cfg( test) ]
116
144
mod tests {
117
145
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 {
186
214
var_name
187
215
}
188
216
}
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
+ }
189
246
"# ,
190
247
) ;
191
248
}
@@ -285,6 +342,14 @@ mod foo {
285
342
pub trait Index<Idx: ?Sized> {}
286
343
287
344
impl<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] {}
288
353
"# ,
289
354
) ;
290
355
}
0 commit comments