1
1
use std:: fmt:: Display ;
2
2
3
+ use hir:: { ModPath , ModuleDef } ;
3
4
use ide_db:: { famous_defs:: FamousDefs , RootDatabase } ;
4
5
use syntax:: {
5
6
ast:: { self , HasName } ,
@@ -17,6 +18,7 @@ use crate::{
17
18
// Generate `Deref` impl using the given struct field.
18
19
//
19
20
// ```
21
+ // # //- minicore: deref, deref_mut
20
22
// struct A;
21
23
// struct B {
22
24
// $0a: A
@@ -29,7 +31,7 @@ use crate::{
29
31
// a: A
30
32
// }
31
33
//
32
- // impl std ::ops::Deref for B {
34
+ // impl core ::ops::Deref for B {
33
35
// type Target = A;
34
36
//
35
37
// fn deref(&self) -> &Self::Target {
@@ -45,19 +47,36 @@ fn generate_record_deref(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
45
47
let strukt = ctx. find_node_at_offset :: < ast:: Struct > ( ) ?;
46
48
let field = ctx. find_node_at_offset :: < ast:: RecordField > ( ) ?;
47
49
48
- if existing_deref_impl ( & ctx. sema , & strukt) . is_some ( ) {
49
- cov_mark:: hit!( test_add_record_deref_impl_already_exists) ;
50
- return None ;
51
- }
50
+ let deref_type_to_generate = match existing_deref_impl ( & ctx. sema , & strukt) {
51
+ None => DerefType :: Deref ,
52
+ Some ( DerefType :: Deref ) => DerefType :: DerefMut ,
53
+ Some ( DerefType :: DerefMut ) => {
54
+ cov_mark:: hit!( test_add_record_deref_impl_already_exists) ;
55
+ return None ;
56
+ }
57
+ } ;
58
+
59
+ let module = ctx. sema . to_def ( & strukt) ?. module ( ctx. db ( ) ) ;
60
+ let trait_ = deref_type_to_generate. to_trait ( & ctx. sema , module. krate ( ) ) ?;
61
+ let trait_path = module. find_use_path ( ctx. db ( ) , ModuleDef :: Trait ( trait_) ) ?;
52
62
53
63
let field_type = field. ty ( ) ?;
54
64
let field_name = field. name ( ) ?;
55
65
let target = field. syntax ( ) . text_range ( ) ;
56
66
acc. add (
57
67
AssistId ( "generate_deref" , AssistKind :: Generate ) ,
58
- format ! ( "Generate `Deref ` impl using `{}`" , field_name) ,
68
+ format ! ( "Generate `{:?} ` impl using `{}`" , deref_type_to_generate , field_name) ,
59
69
target,
60
- |edit| generate_edit ( edit, strukt, field_type. syntax ( ) , field_name. syntax ( ) ) ,
70
+ |edit| {
71
+ generate_edit (
72
+ edit,
73
+ strukt,
74
+ field_type. syntax ( ) ,
75
+ field_name. syntax ( ) ,
76
+ deref_type_to_generate,
77
+ trait_path,
78
+ )
79
+ } ,
61
80
)
62
81
}
63
82
@@ -68,18 +87,35 @@ fn generate_tuple_deref(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
68
87
let field_list_index =
69
88
field_list. syntax ( ) . children ( ) . into_iter ( ) . position ( |s| & s == field. syntax ( ) ) ?;
70
89
71
- if existing_deref_impl ( & ctx. sema , & strukt) . is_some ( ) {
72
- cov_mark:: hit!( test_add_field_deref_impl_already_exists) ;
73
- return None ;
74
- }
90
+ let deref_type_to_generate = match existing_deref_impl ( & ctx. sema , & strukt) {
91
+ None => DerefType :: Deref ,
92
+ Some ( DerefType :: Deref ) => DerefType :: DerefMut ,
93
+ Some ( DerefType :: DerefMut ) => {
94
+ cov_mark:: hit!( test_add_field_deref_impl_already_exists) ;
95
+ return None ;
96
+ }
97
+ } ;
98
+
99
+ let module = ctx. sema . to_def ( & strukt) ?. module ( ctx. db ( ) ) ;
100
+ let trait_ = deref_type_to_generate. to_trait ( & ctx. sema , module. krate ( ) ) ?;
101
+ let trait_path = module. find_use_path ( ctx. db ( ) , ModuleDef :: Trait ( trait_) ) ?;
75
102
76
103
let field_type = field. ty ( ) ?;
77
104
let target = field. syntax ( ) . text_range ( ) ;
78
105
acc. add (
79
106
AssistId ( "generate_deref" , AssistKind :: Generate ) ,
80
- format ! ( "Generate `Deref ` impl using `{}`" , field. syntax( ) ) ,
107
+ format ! ( "Generate `{:?} ` impl using `{}`" , deref_type_to_generate , field. syntax( ) ) ,
81
108
target,
82
- |edit| generate_edit ( edit, strukt, field_type. syntax ( ) , field_list_index) ,
109
+ |edit| {
110
+ generate_edit (
111
+ edit,
112
+ strukt,
113
+ field_type. syntax ( ) ,
114
+ field_list_index,
115
+ deref_type_to_generate,
116
+ trait_path,
117
+ )
118
+ } ,
83
119
)
84
120
}
85
121
@@ -88,38 +124,72 @@ fn generate_edit(
88
124
strukt : ast:: Struct ,
89
125
field_type_syntax : & SyntaxNode ,
90
126
field_name : impl Display ,
127
+ deref_type : DerefType ,
128
+ trait_path : ModPath ,
91
129
) {
92
130
let start_offset = strukt. syntax ( ) . text_range ( ) . end ( ) ;
93
- let impl_code = format ! (
94
- r#" type Target = {0};
131
+ let impl_code = match deref_type {
132
+ DerefType :: Deref => format ! (
133
+ r#" type Target = {0};
95
134
96
135
fn deref(&self) -> &Self::Target {{
97
136
&self.{1}
98
137
}}"# ,
99
- field_type_syntax, field_name
100
- ) ;
138
+ field_type_syntax, field_name
139
+ ) ,
140
+ DerefType :: DerefMut => format ! (
141
+ r#" fn deref_mut(&mut self) -> &mut Self::Target {{
142
+ &mut self.{}
143
+ }}"# ,
144
+ field_name
145
+ ) ,
146
+ } ;
101
147
let strukt_adt = ast:: Adt :: Struct ( strukt) ;
102
- let deref_impl = generate_trait_impl_text ( & strukt_adt, "std::ops::Deref" , & impl_code) ;
148
+ let deref_impl = generate_trait_impl_text ( & strukt_adt, & trait_path . to_string ( ) , & impl_code) ;
103
149
edit. insert ( start_offset, deref_impl) ;
104
150
}
105
151
106
152
fn existing_deref_impl (
107
- sema : & ' _ hir:: Semantics < ' _ , RootDatabase > ,
153
+ sema : & hir:: Semantics < ' _ , RootDatabase > ,
108
154
strukt : & ast:: Struct ,
109
- ) -> Option < ( ) > {
155
+ ) -> Option < DerefType > {
110
156
let strukt = sema. to_def ( strukt) ?;
111
157
let krate = strukt. module ( sema. db ) . krate ( ) ;
112
158
113
159
let deref_trait = FamousDefs ( sema, krate) . core_ops_Deref ( ) ?;
160
+ let deref_mut_trait = FamousDefs ( sema, krate) . core_ops_DerefMut ( ) ?;
114
161
let strukt_type = strukt. ty ( sema. db ) ;
115
162
116
163
if strukt_type. impls_trait ( sema. db , deref_trait, & [ ] ) {
117
- Some ( ( ) )
164
+ if strukt_type. impls_trait ( sema. db , deref_mut_trait, & [ ] ) {
165
+ Some ( DerefType :: DerefMut )
166
+ } else {
167
+ Some ( DerefType :: Deref )
168
+ }
118
169
} else {
119
170
None
120
171
}
121
172
}
122
173
174
+ #[ derive( Debug ) ]
175
+ enum DerefType {
176
+ Deref ,
177
+ DerefMut ,
178
+ }
179
+
180
+ impl DerefType {
181
+ fn to_trait (
182
+ & self ,
183
+ sema : & hir:: Semantics < ' _ , RootDatabase > ,
184
+ krate : hir:: Crate ,
185
+ ) -> Option < hir:: Trait > {
186
+ match self {
187
+ DerefType :: Deref => FamousDefs ( sema, krate) . core_ops_Deref ( ) ,
188
+ DerefType :: DerefMut => FamousDefs ( sema, krate) . core_ops_DerefMut ( ) ,
189
+ }
190
+ }
191
+ }
192
+
123
193
#[ cfg( test) ]
124
194
mod tests {
125
195
use crate :: tests:: { check_assist, check_assist_not_applicable} ;
@@ -130,12 +200,39 @@ mod tests {
130
200
fn test_generate_record_deref ( ) {
131
201
check_assist (
132
202
generate_deref,
133
- r#"struct A { }
203
+ r#"
204
+ //- minicore: deref
205
+ struct A { }
134
206
struct B { $0a: A }"# ,
135
- r#"struct A { }
207
+ r#"
208
+ struct A { }
136
209
struct B { a: A }
137
210
138
- impl std::ops::Deref for B {
211
+ impl core::ops::Deref for B {
212
+ type Target = A;
213
+
214
+ fn deref(&self) -> &Self::Target {
215
+ &self.a
216
+ }
217
+ }"# ,
218
+ ) ;
219
+ }
220
+
221
+ #[ test]
222
+ fn test_generate_record_deref_short_path ( ) {
223
+ check_assist (
224
+ generate_deref,
225
+ r#"
226
+ //- minicore: deref
227
+ use core::ops::Deref;
228
+ struct A { }
229
+ struct B { $0a: A }"# ,
230
+ r#"
231
+ use core::ops::Deref;
232
+ struct A { }
233
+ struct B { a: A }
234
+
235
+ impl Deref for B {
139
236
type Target = A;
140
237
141
238
fn deref(&self) -> &Self::Target {
@@ -149,12 +246,15 @@ impl std::ops::Deref for B {
149
246
fn test_generate_field_deref_idx_0 ( ) {
150
247
check_assist (
151
248
generate_deref,
152
- r#"struct A { }
249
+ r#"
250
+ //- minicore: deref
251
+ struct A { }
153
252
struct B($0A);"# ,
154
- r#"struct A { }
253
+ r#"
254
+ struct A { }
155
255
struct B(A);
156
256
157
- impl std ::ops::Deref for B {
257
+ impl core ::ops::Deref for B {
158
258
type Target = A;
159
259
160
260
fn deref(&self) -> &Self::Target {
@@ -167,12 +267,15 @@ impl std::ops::Deref for B {
167
267
fn test_generate_field_deref_idx_1 ( ) {
168
268
check_assist (
169
269
generate_deref,
170
- r#"struct A { }
270
+ r#"
271
+ //- minicore: deref
272
+ struct A { }
171
273
struct B(u8, $0A);"# ,
172
- r#"struct A { }
274
+ r#"
275
+ struct A { }
173
276
struct B(u8, A);
174
277
175
- impl std ::ops::Deref for B {
278
+ impl core ::ops::Deref for B {
176
279
type Target = A;
177
280
178
281
fn deref(&self) -> &Self::Target {
@@ -182,23 +285,43 @@ impl std::ops::Deref for B {
182
285
) ;
183
286
}
184
287
288
+ #[ test]
289
+ fn test_generates_derefmut_when_deref_present ( ) {
290
+ check_assist (
291
+ generate_deref,
292
+ r#"
293
+ //- minicore: deref, deref_mut
294
+ struct B { $0a: u8 }
295
+
296
+ impl core::ops::Deref for B {}
297
+ "# ,
298
+ r#"
299
+ struct B { a: u8 }
300
+
301
+ impl core::ops::DerefMut for B {
302
+ fn deref_mut(&mut self) -> &mut Self::Target {
303
+ &mut self.a
304
+ }
305
+ }
306
+
307
+ impl core::ops::Deref for B {}
308
+ "# ,
309
+ ) ;
310
+ }
311
+
185
312
#[ test]
186
313
fn test_generate_record_deref_not_applicable_if_already_impl ( ) {
187
314
cov_mark:: check!( test_add_record_deref_impl_already_exists) ;
188
315
check_assist_not_applicable (
189
316
generate_deref,
190
317
r#"
191
- //- minicore: deref
318
+ //- minicore: deref, deref_mut
192
319
struct A { }
193
320
struct B { $0a: A }
194
321
195
- impl core::ops::Deref for B {
196
- type Target = A;
197
-
198
- fn deref(&self) -> &Self::Target {
199
- &self.a
200
- }
201
- }"# ,
322
+ impl core::ops::Deref for B {}
323
+ impl core::ops::DerefMut for B {}
324
+ "# ,
202
325
)
203
326
}
204
327
@@ -208,17 +331,13 @@ impl core::ops::Deref for B {
208
331
check_assist_not_applicable (
209
332
generate_deref,
210
333
r#"
211
- //- minicore: deref
334
+ //- minicore: deref, deref_mut
212
335
struct A { }
213
336
struct B($0A)
214
337
215
- impl core::ops::Deref for B {
216
- type Target = A;
217
-
218
- fn deref(&self) -> &Self::Target {
219
- &self.0
220
- }
221
- }"# ,
338
+ impl core::ops::Deref for B {}
339
+ impl core::ops::DerefMut for B {}
340
+ "# ,
222
341
)
223
342
}
224
343
}
0 commit comments