1- use std:: fmt:: Display ;
2-
31use hir:: { ModPath , ModuleDef } ;
4- use ide_db:: { RootDatabase , famous_defs:: FamousDefs } ;
2+ use ide_db:: { FileId , RootDatabase , famous_defs:: FamousDefs } ;
53use syntax:: {
6- AstNode , Edition , SyntaxNode ,
7- ast:: { self , HasName } ,
4+ Edition ,
5+ ast:: { self , AstNode , HasName , edit:: AstNodeEdit , syntax_factory:: SyntaxFactory } ,
6+ syntax_editor:: Position ,
87} ;
98
109use crate :: {
1110 AssistId ,
1211 assist_context:: { AssistContext , Assists , SourceChangeBuilder } ,
13- utils:: generate_trait_impl_text_intransitive ,
12+ utils:: generate_trait_impl_intransitive_with_item ,
1413} ;
1514
1615// Assist: generate_deref
@@ -64,6 +63,7 @@ fn generate_record_deref(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<(
6463 let field_type = field. ty ( ) ?;
6564 let field_name = field. name ( ) ?;
6665 let target = field. syntax ( ) . text_range ( ) ;
66+ let file_id = ctx. vfs_file_id ( ) ;
6767 acc. add (
6868 AssistId :: generate ( "generate_deref" ) ,
6969 format ! ( "Generate `{deref_type_to_generate:?}` impl using `{field_name}`" ) ,
@@ -72,9 +72,10 @@ fn generate_record_deref(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<(
7272 generate_edit (
7373 ctx. db ( ) ,
7474 edit,
75+ file_id,
7576 strukt,
76- field_type. syntax ( ) ,
77- field_name. syntax ( ) ,
77+ field_type,
78+ & field_name. to_string ( ) ,
7879 deref_type_to_generate,
7980 trait_path,
8081 module. krate ( ctx. db ( ) ) . edition ( ctx. db ( ) ) ,
@@ -105,6 +106,7 @@ fn generate_tuple_deref(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()
105106
106107 let field_type = field. ty ( ) ?;
107108 let target = field. syntax ( ) . text_range ( ) ;
109+ let file_id = ctx. vfs_file_id ( ) ;
108110 acc. add (
109111 AssistId :: generate ( "generate_deref" ) ,
110112 format ! ( "Generate `{deref_type_to_generate:?}` impl using `{field}`" ) ,
@@ -113,9 +115,10 @@ fn generate_tuple_deref(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()
113115 generate_edit (
114116 ctx. db ( ) ,
115117 edit,
118+ file_id,
116119 strukt,
117- field_type. syntax ( ) ,
118- field_list_index,
120+ field_type,
121+ & field_list_index. to_string ( ) ,
119122 deref_type_to_generate,
120123 trait_path,
121124 module. krate ( ctx. db ( ) ) . edition ( ctx. db ( ) ) ,
@@ -127,35 +130,94 @@ fn generate_tuple_deref(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()
127130fn generate_edit (
128131 db : & RootDatabase ,
129132 edit : & mut SourceChangeBuilder ,
133+ file_id : FileId ,
130134 strukt : ast:: Struct ,
131- field_type_syntax : & SyntaxNode ,
132- field_name : impl Display ,
135+ field_type : ast :: Type ,
136+ field_name : & str ,
133137 deref_type : DerefType ,
134138 trait_path : ModPath ,
135139 edition : Edition ,
136140) {
137- let start_offset = strukt. syntax ( ) . text_range ( ) . end ( ) ;
138- let impl_code = match deref_type {
139- DerefType :: Deref => format ! (
140- r#" type Target = {field_type_syntax};
141-
142- fn deref(&self) -> &Self::Target {{
143- &self.{field_name}
144- }}"# ,
145- ) ,
146- DerefType :: DerefMut => format ! (
147- r#" fn deref_mut(&mut self) -> &mut Self::Target {{
148- &mut self.{field_name}
149- }}"# ,
150- ) ,
141+ let make = SyntaxFactory :: with_mappings ( ) ;
142+ let strukt_adt = ast:: Adt :: Struct ( strukt. clone ( ) ) ;
143+ let trait_ty = make. ty ( & trait_path. display ( db, edition) . to_string ( ) ) ;
144+
145+ let assoc_items: Vec < ast:: AssocItem > = match deref_type {
146+ DerefType :: Deref => {
147+ let target_alias = make. ty_alias (
148+ [ ] ,
149+ "Target" ,
150+ None ,
151+ None ,
152+ None ,
153+ Some ( ( field_type, None ) ) ,
154+ ) ;
155+ let ret_ty =
156+ make. ty_ref ( make. ty_path ( make. path_from_text ( "Self::Target" ) ) . into ( ) , false ) ;
157+ let field_expr =
158+ make. expr_field ( make. expr_path ( make. ident_path ( "self" ) ) , field_name) ;
159+ let body =
160+ make. block_expr ( [ ] , Some ( make. expr_ref ( field_expr. into ( ) , false ) ) ) ;
161+ let fn_ = make
162+ . fn_ (
163+ [ ] ,
164+ None ,
165+ make. name ( "deref" ) ,
166+ None ,
167+ None ,
168+ make. param_list ( Some ( make. self_param ( ) ) , [ ] ) ,
169+ body,
170+ Some ( make. ret_type ( ret_ty) ) ,
171+ false ,
172+ false ,
173+ false ,
174+ false ,
175+ )
176+ . indent ( 1 . into ( ) ) ;
177+ vec ! [
178+ ast:: AssocItem :: TypeAlias ( target_alias) ,
179+ ast:: AssocItem :: Fn ( fn_) ,
180+ ]
181+ }
182+ DerefType :: DerefMut => {
183+ let ret_ty =
184+ make. ty_ref ( make. ty_path ( make. path_from_text ( "Self::Target" ) ) . into ( ) , true ) ;
185+ let field_expr =
186+ make. expr_field ( make. expr_path ( make. ident_path ( "self" ) ) , field_name) ;
187+ let body =
188+ make. block_expr ( [ ] , Some ( make. expr_ref ( field_expr. into ( ) , true ) ) ) ;
189+ let fn_ = make
190+ . fn_ (
191+ [ ] ,
192+ None ,
193+ make. name ( "deref_mut" ) ,
194+ None ,
195+ None ,
196+ make. param_list ( Some ( make. mut_self_param ( ) ) , [ ] ) ,
197+ body,
198+ Some ( make. ret_type ( ret_ty) ) ,
199+ false ,
200+ false ,
201+ false ,
202+ false ,
203+ )
204+ . indent ( 1 . into ( ) ) ;
205+ vec ! [ ast:: AssocItem :: Fn ( fn_) ]
206+ }
151207 } ;
152- let strukt_adt = ast:: Adt :: Struct ( strukt) ;
153- let deref_impl = generate_trait_impl_text_intransitive (
154- & strukt_adt,
155- & trait_path. display ( db, edition) . to_string ( ) ,
156- & impl_code,
208+
209+ let body = make. assoc_item_list ( assoc_items) ;
210+ let indent = strukt. indent_level ( ) ;
211+ let impl_ = generate_trait_impl_intransitive_with_item ( & make, & strukt_adt, trait_ty, body)
212+ . indent ( indent) ;
213+
214+ let mut editor = edit. make_editor ( strukt. syntax ( ) ) ;
215+ editor. insert_all (
216+ Position :: after ( strukt. syntax ( ) ) ,
217+ vec ! [ make. whitespace( & format!( "\n \n {indent}" ) ) . into( ) , impl_. syntax( ) . clone( ) . into( ) ] ,
157218 ) ;
158- edit. insert ( start_offset, deref_impl) ;
219+ editor. add_mappings ( make. finish_with_mappings ( ) ) ;
220+ edit. add_file_edits ( file_id, editor) ;
159221}
160222
161223fn existing_deref_impl (
0 commit comments