@@ -7,7 +7,7 @@ use ide_db::{
7
7
search:: { FileReference , SearchScope } ,
8
8
} ;
9
9
use itertools:: Itertools ;
10
- use syntax:: ast:: syntax_factory:: SyntaxFactory ;
10
+ use syntax:: ast:: { HasName , syntax_factory:: SyntaxFactory } ;
11
11
use syntax:: syntax_editor:: SyntaxEditor ;
12
12
use syntax:: { AstNode , Edition , SmolStr , SyntaxNode , ToSmolStr , ast} ;
13
13
@@ -71,13 +71,14 @@ fn destructure_struct_binding_impl(
71
71
72
72
struct StructEditData {
73
73
ident_pat : ast:: IdentPat ,
74
+ name : ast:: Name ,
74
75
kind : hir:: StructKind ,
75
76
struct_def_path : hir:: ModPath ,
76
77
visible_fields : Vec < hir:: Field > ,
77
78
usages : Vec < FileReference > ,
78
79
names_in_scope : FxHashSet < SmolStr > ,
79
80
has_private_members : bool ,
80
- is_nested : bool ,
81
+ need_record_field_name : bool ,
81
82
is_ref : bool ,
82
83
edition : Edition ,
83
84
}
@@ -114,7 +115,11 @@ fn collect_data(ident_pat: ast::IdentPat, ctx: &AssistContext<'_>) -> Option<Str
114
115
}
115
116
116
117
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 ( ) ) ;
118
123
119
124
let usages = ctx
120
125
. sema
@@ -133,14 +138,15 @@ fn collect_data(ident_pat: ast::IdentPat, ctx: &AssistContext<'_>) -> Option<Str
133
138
let names_in_scope = get_names_in_scope ( ctx, & ident_pat, & usages) . unwrap_or_default ( ) ;
134
139
135
140
Some ( StructEditData {
141
+ name : ident_pat. name ( ) ?,
136
142
ident_pat,
137
143
kind,
138
144
struct_def_path,
139
145
usages,
140
146
has_private_members,
141
147
visible_fields,
142
148
names_in_scope,
143
- is_nested ,
149
+ need_record_field_name ,
144
150
is_ref,
145
151
edition : module. krate ( ) . edition ( ctx. db ( ) ) ,
146
152
} )
@@ -177,6 +183,7 @@ fn destructure_pat(
177
183
field_names : & [ ( SmolStr , SmolStr ) ] ,
178
184
) {
179
185
let ident_pat = & data. ident_pat ;
186
+ let name = & data. name ;
180
187
181
188
let struct_path = mod_path_to_ast ( & data. struct_def_path , data. edition ) ;
182
189
let is_ref = ident_pat. ref_token ( ) . is_some ( ) ;
@@ -194,9 +201,9 @@ fn destructure_pat(
194
201
hir:: StructKind :: Record => {
195
202
let fields = field_names. iter ( ) . map ( |( old_name, new_name) | {
196
203
// Use shorthand syntax if possible
197
- if old_name == new_name && !is_mut {
204
+ if old_name == new_name {
198
205
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 ( ) ,
200
207
)
201
208
} else {
202
209
make. record_pat_field (
@@ -215,8 +222,8 @@ fn destructure_pat(
215
222
216
223
// If the binding is nested inside a record, we need to wrap the new
217
224
// 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 ( )
220
227
} else {
221
228
new_pat. syntax ( ) . clone ( )
222
229
} ;
@@ -579,14 +586,94 @@ mod tests {
579
586
struct Foo { bar: i32, baz: i32 }
580
587
581
588
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 };
583
590
let bar2 = bar;
584
591
let baz2 = &baz;
585
592
}
586
593
"# ,
587
594
)
588
595
}
589
596
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
+
590
677
#[ test]
591
678
fn mut_ref ( ) {
592
679
check_assist (
0 commit comments