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,81 @@ 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 =
148+ make. ty_alias ( [ ] , "Target" , None , None , None , Some ( ( field_type, None ) ) ) ;
149+ let ret_ty =
150+ make. ty_ref ( make. ty_path ( make. path_from_text ( "Self::Target" ) ) . into ( ) , false ) ;
151+ let field_expr = make. expr_field ( make. expr_path ( make. ident_path ( "self" ) ) , field_name) ;
152+ let body = make. block_expr ( [ ] , Some ( make. expr_ref ( field_expr. into ( ) , false ) ) ) ;
153+ let fn_ = make
154+ . fn_ (
155+ [ ] ,
156+ None ,
157+ make. name ( "deref" ) ,
158+ None ,
159+ None ,
160+ make. param_list ( Some ( make. self_param ( ) ) , [ ] ) ,
161+ body,
162+ Some ( make. ret_type ( ret_ty) ) ,
163+ false ,
164+ false ,
165+ false ,
166+ false ,
167+ )
168+ . indent ( 1 . into ( ) ) ;
169+ vec ! [ ast:: AssocItem :: TypeAlias ( target_alias) , ast:: AssocItem :: Fn ( fn_) ]
170+ }
171+ DerefType :: DerefMut => {
172+ let ret_ty =
173+ make. ty_ref ( make. ty_path ( make. path_from_text ( "Self::Target" ) ) . into ( ) , true ) ;
174+ let field_expr = make. expr_field ( make. expr_path ( make. ident_path ( "self" ) ) , field_name) ;
175+ let body = make. block_expr ( [ ] , Some ( make. expr_ref ( field_expr. into ( ) , true ) ) ) ;
176+ let fn_ = make
177+ . fn_ (
178+ [ ] ,
179+ None ,
180+ make. name ( "deref_mut" ) ,
181+ None ,
182+ None ,
183+ make. param_list ( Some ( make. mut_self_param ( ) ) , [ ] ) ,
184+ body,
185+ Some ( make. ret_type ( ret_ty) ) ,
186+ false ,
187+ false ,
188+ false ,
189+ false ,
190+ )
191+ . indent ( 1 . into ( ) ) ;
192+ vec ! [ ast:: AssocItem :: Fn ( fn_) ]
193+ }
151194 } ;
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,
195+
196+ let body = make. assoc_item_list ( assoc_items) ;
197+ let indent = strukt. indent_level ( ) ;
198+ let impl_ = generate_trait_impl_intransitive_with_item ( & make, & strukt_adt, trait_ty, body)
199+ . indent ( indent) ;
200+
201+ let mut editor = edit. make_editor ( strukt. syntax ( ) ) ;
202+ editor. insert_all (
203+ Position :: after ( strukt. syntax ( ) ) ,
204+ vec ! [ make. whitespace( & format!( "\n \n {indent}" ) ) . into( ) , impl_. syntax( ) . clone( ) . into( ) ] ,
157205 ) ;
158- edit. insert ( start_offset, deref_impl) ;
206+ editor. add_mappings ( make. finish_with_mappings ( ) ) ;
207+ edit. add_file_edits ( file_id, editor) ;
159208}
160209
161210fn existing_deref_impl (
0 commit comments