@@ -7,7 +7,7 @@ use ide_db::{
77 search:: { FileReference , SearchScope } ,
88} ;
99use itertools:: Itertools ;
10- use syntax:: ast:: syntax_factory:: SyntaxFactory ;
10+ use syntax:: ast:: { HasName , syntax_factory:: SyntaxFactory } ;
1111use syntax:: syntax_editor:: SyntaxEditor ;
1212use syntax:: { AstNode , Edition , SmolStr , SyntaxNode , ToSmolStr , ast} ;
1313
@@ -71,13 +71,14 @@ fn destructure_struct_binding_impl(
7171
7272struct StructEditData {
7373 ident_pat : ast:: IdentPat ,
74+ name : ast:: Name ,
7475 kind : hir:: StructKind ,
7576 struct_def_path : hir:: ModPath ,
7677 visible_fields : Vec < hir:: Field > ,
7778 usages : Vec < FileReference > ,
7879 names_in_scope : FxHashSet < SmolStr > ,
7980 has_private_members : bool ,
80- is_nested : bool ,
81+ need_record_field_name : bool ,
8182 is_ref : bool ,
8283 edition : Edition ,
8384}
@@ -114,7 +115,11 @@ fn collect_data(ident_pat: ast::IdentPat, ctx: &AssistContext<'_>) -> Option<Str
114115 }
115116
116117 let is_ref = ty. is_reference ( ) ;
117- let is_nested = ident_pat. syntax ( ) . parent ( ) . and_then ( ast:: RecordPatField :: cast) . is_some ( ) ;
118+ let need_record_field_name = ident_pat
119+ . syntax ( )
120+ . parent ( )
121+ . and_then ( ast:: RecordPatField :: cast)
122+ . is_some_and ( |field| field. colon_token ( ) . is_none ( ) ) ;
118123
119124 let usages = ctx
120125 . sema
@@ -133,14 +138,15 @@ fn collect_data(ident_pat: ast::IdentPat, ctx: &AssistContext<'_>) -> Option<Str
133138 let names_in_scope = get_names_in_scope ( ctx, & ident_pat, & usages) . unwrap_or_default ( ) ;
134139
135140 Some ( StructEditData {
141+ name : ident_pat. name ( ) ?,
136142 ident_pat,
137143 kind,
138144 struct_def_path,
139145 usages,
140146 has_private_members,
141147 visible_fields,
142148 names_in_scope,
143- is_nested ,
149+ need_record_field_name ,
144150 is_ref,
145151 edition : module. krate ( ) . edition ( ctx. db ( ) ) ,
146152 } )
@@ -177,6 +183,7 @@ fn destructure_pat(
177183 field_names : & [ ( SmolStr , SmolStr ) ] ,
178184) {
179185 let ident_pat = & data. ident_pat ;
186+ let name = & data. name ;
180187
181188 let struct_path = mod_path_to_ast ( & data. struct_def_path , data. edition ) ;
182189 let is_ref = ident_pat. ref_token ( ) . is_some ( ) ;
@@ -194,9 +201,9 @@ fn destructure_pat(
194201 hir:: StructKind :: Record => {
195202 let fields = field_names. iter ( ) . map ( |( old_name, new_name) | {
196203 // Use shorthand syntax if possible
197- if old_name == new_name && !is_mut {
204+ if old_name == new_name {
198205 make. record_pat_field_shorthand (
199- make. ident_pat ( false , false , make. name ( old_name) ) . into ( ) ,
206+ make. ident_pat ( is_ref , is_mut , make. name ( old_name) ) . into ( ) ,
200207 )
201208 } else {
202209 make. record_pat_field (
@@ -215,8 +222,8 @@ fn destructure_pat(
215222
216223 // If the binding is nested inside a record, we need to wrap the new
217224 // destructured pattern in a non-shorthand record field
218- let destructured_pat = if data. is_nested {
219- make. record_pat_field ( make. name_ref ( & ident_pat . to_string ( ) ) , new_pat) . syntax ( ) . clone ( )
225+ let destructured_pat = if data. need_record_field_name {
226+ make. record_pat_field ( make. name_ref ( & name . to_string ( ) ) , new_pat) . syntax ( ) . clone ( )
220227 } else {
221228 new_pat. syntax ( ) . clone ( )
222229 } ;
@@ -579,14 +586,94 @@ mod tests {
579586 struct Foo { bar: i32, baz: i32 }
580587
581588 fn main() {
582- let Foo { bar: mut bar, baz: mut baz } = Foo { bar: 1, baz: 2 };
589+ let Foo { mut bar, mut baz } = Foo { bar: 1, baz: 2 };
583590 let bar2 = bar;
584591 let baz2 = &baz;
585592 }
586593 "# ,
587594 )
588595 }
589596
597+ #[ test]
598+ fn mut_record_field ( ) {
599+ check_assist (
600+ destructure_struct_binding,
601+ r#"
602+ struct Foo { x: () }
603+ struct Bar { foo: Foo }
604+ fn f(Bar { mut $0foo }: Bar) {}
605+ "# ,
606+ r#"
607+ struct Foo { x: () }
608+ struct Bar { foo: Foo }
609+ fn f(Bar { foo: Foo { mut x } }: Bar) {}
610+ "# ,
611+ )
612+ }
613+
614+ #[ test]
615+ fn ref_record_field ( ) {
616+ check_assist (
617+ destructure_struct_binding,
618+ r#"
619+ struct Foo { x: () }
620+ struct Bar { foo: Foo }
621+ fn f(Bar { ref $0foo }: Bar) {
622+ let _ = foo.x;
623+ }
624+ "# ,
625+ r#"
626+ struct Foo { x: () }
627+ struct Bar { foo: Foo }
628+ fn f(Bar { foo: Foo { ref x } }: Bar) {
629+ let _ = *x;
630+ }
631+ "# ,
632+ )
633+ }
634+
635+ #[ test]
636+ fn ref_mut_record_field ( ) {
637+ check_assist (
638+ destructure_struct_binding,
639+ r#"
640+ struct Foo { x: () }
641+ struct Bar { foo: Foo }
642+ fn f(Bar { ref mut $0foo }: Bar) {
643+ let _ = foo.x;
644+ }
645+ "# ,
646+ r#"
647+ struct Foo { x: () }
648+ struct Bar { foo: Foo }
649+ fn f(Bar { foo: Foo { ref mut x } }: Bar) {
650+ let _ = *x;
651+ }
652+ "# ,
653+ )
654+ }
655+
656+ #[ test]
657+ fn ref_mut_record_renamed_field ( ) {
658+ check_assist (
659+ destructure_struct_binding,
660+ r#"
661+ struct Foo { x: () }
662+ struct Bar { foo: Foo }
663+ fn f(Bar { foo: ref mut $0foo1 }: Bar) {
664+ let _ = foo1.x;
665+ }
666+ "# ,
667+ r#"
668+ struct Foo { x: () }
669+ struct Bar { foo: Foo }
670+ fn f(Bar { foo: Foo { ref mut x } }: Bar) {
671+ let _ = *x;
672+ }
673+ "# ,
674+ )
675+ }
676+
590677 #[ test]
591678 fn mut_ref ( ) {
592679 check_assist (
0 commit comments