11use std:: fmt:: Display ;
22
3+ use hir:: { ModPath , ModuleDef } ;
34use ide_db:: { famous_defs:: FamousDefs , RootDatabase } ;
45use syntax:: {
56 ast:: { self , HasName } ,
@@ -17,6 +18,7 @@ use crate::{
1718// Generate `Deref` impl using the given struct field.
1819//
1920// ```
21+ // # //- minicore: deref, deref_mut
2022// struct A;
2123// struct B {
2224// $0a: A
@@ -29,7 +31,7 @@ use crate::{
2931// a: A
3032// }
3133//
32- // impl std ::ops::Deref for B {
34+ // impl core ::ops::Deref for B {
3335// type Target = A;
3436//
3537// fn deref(&self) -> &Self::Target {
@@ -45,19 +47,36 @@ fn generate_record_deref(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
4547 let strukt = ctx. find_node_at_offset :: < ast:: Struct > ( ) ?;
4648 let field = ctx. find_node_at_offset :: < ast:: RecordField > ( ) ?;
4749
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_) ) ?;
5262
5363 let field_type = field. ty ( ) ?;
5464 let field_name = field. name ( ) ?;
5565 let target = field. syntax ( ) . text_range ( ) ;
5666 acc. add (
5767 AssistId ( "generate_deref" , AssistKind :: Generate ) ,
58- format ! ( "Generate `Deref ` impl using `{}`" , field_name) ,
68+ format ! ( "Generate `{:?} ` impl using `{}`" , deref_type_to_generate , field_name) ,
5969 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+ } ,
6180 )
6281}
6382
@@ -68,18 +87,35 @@ fn generate_tuple_deref(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
6887 let field_list_index =
6988 field_list. syntax ( ) . children ( ) . into_iter ( ) . position ( |s| & s == field. syntax ( ) ) ?;
7089
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_) ) ?;
75102
76103 let field_type = field. ty ( ) ?;
77104 let target = field. syntax ( ) . text_range ( ) ;
78105 acc. add (
79106 AssistId ( "generate_deref" , AssistKind :: Generate ) ,
80- format ! ( "Generate `Deref ` impl using `{}`" , field. syntax( ) ) ,
107+ format ! ( "Generate `{:?} ` impl using `{}`" , deref_type_to_generate , field. syntax( ) ) ,
81108 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+ } ,
83119 )
84120}
85121
@@ -88,38 +124,72 @@ fn generate_edit(
88124 strukt : ast:: Struct ,
89125 field_type_syntax : & SyntaxNode ,
90126 field_name : impl Display ,
127+ deref_type : DerefType ,
128+ trait_path : ModPath ,
91129) {
92130 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};
95134
96135 fn deref(&self) -> &Self::Target {{
97136 &self.{1}
98137 }}"# ,
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+ } ;
101147 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) ;
103149 edit. insert ( start_offset, deref_impl) ;
104150}
105151
106152fn existing_deref_impl (
107- sema : & ' _ hir:: Semantics < ' _ , RootDatabase > ,
153+ sema : & hir:: Semantics < ' _ , RootDatabase > ,
108154 strukt : & ast:: Struct ,
109- ) -> Option < ( ) > {
155+ ) -> Option < DerefType > {
110156 let strukt = sema. to_def ( strukt) ?;
111157 let krate = strukt. module ( sema. db ) . krate ( ) ;
112158
113159 let deref_trait = FamousDefs ( sema, krate) . core_ops_Deref ( ) ?;
160+ let deref_mut_trait = FamousDefs ( sema, krate) . core_ops_DerefMut ( ) ?;
114161 let strukt_type = strukt. ty ( sema. db ) ;
115162
116163 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+ }
118169 } else {
119170 None
120171 }
121172}
122173
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+
123193#[ cfg( test) ]
124194mod tests {
125195 use crate :: tests:: { check_assist, check_assist_not_applicable} ;
@@ -130,12 +200,39 @@ mod tests {
130200 fn test_generate_record_deref ( ) {
131201 check_assist (
132202 generate_deref,
133- r#"struct A { }
203+ r#"
204+ //- minicore: deref
205+ struct A { }
134206struct B { $0a: A }"# ,
135- r#"struct A { }
207+ r#"
208+ struct A { }
136209struct B { a: A }
137210
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 {
139236 type Target = A;
140237
141238 fn deref(&self) -> &Self::Target {
@@ -149,12 +246,15 @@ impl std::ops::Deref for B {
149246 fn test_generate_field_deref_idx_0 ( ) {
150247 check_assist (
151248 generate_deref,
152- r#"struct A { }
249+ r#"
250+ //- minicore: deref
251+ struct A { }
153252struct B($0A);"# ,
154- r#"struct A { }
253+ r#"
254+ struct A { }
155255struct B(A);
156256
157- impl std ::ops::Deref for B {
257+ impl core ::ops::Deref for B {
158258 type Target = A;
159259
160260 fn deref(&self) -> &Self::Target {
@@ -167,12 +267,15 @@ impl std::ops::Deref for B {
167267 fn test_generate_field_deref_idx_1 ( ) {
168268 check_assist (
169269 generate_deref,
170- r#"struct A { }
270+ r#"
271+ //- minicore: deref
272+ struct A { }
171273struct B(u8, $0A);"# ,
172- r#"struct A { }
274+ r#"
275+ struct A { }
173276struct B(u8, A);
174277
175- impl std ::ops::Deref for B {
278+ impl core ::ops::Deref for B {
176279 type Target = A;
177280
178281 fn deref(&self) -> &Self::Target {
@@ -182,23 +285,43 @@ impl std::ops::Deref for B {
182285 ) ;
183286 }
184287
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+
185312 #[ test]
186313 fn test_generate_record_deref_not_applicable_if_already_impl ( ) {
187314 cov_mark:: check!( test_add_record_deref_impl_already_exists) ;
188315 check_assist_not_applicable (
189316 generate_deref,
190317 r#"
191- //- minicore: deref
318+ //- minicore: deref, deref_mut
192319struct A { }
193320struct B { $0a: A }
194321
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+ "# ,
202325 )
203326 }
204327
@@ -208,17 +331,13 @@ impl core::ops::Deref for B {
208331 check_assist_not_applicable (
209332 generate_deref,
210333 r#"
211- //- minicore: deref
334+ //- minicore: deref, deref_mut
212335struct A { }
213336struct B($0A)
214337
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+ "# ,
222341 )
223342 }
224343}
0 commit comments