@@ -192,19 +192,20 @@ fn check_field_shorthand(acc: &mut Vec<Diagnostic>, file_id: FileId, node: &Synt
192192 match_ast ! {
193193 match node {
194194 ast:: RecordExpr ( it) => check_expr_field_shorthand( acc, file_id, it) ,
195- _ => None
195+ ast:: RecordPat ( it) => check_pat_field_shorthand( acc, file_id, it) ,
196+ _ => ( )
196197 }
197198 } ;
198199}
199200
200201fn check_expr_field_shorthand (
201202 acc : & mut Vec < Diagnostic > ,
202203 file_id : FileId ,
203- record_lit : ast:: RecordExpr ,
204+ record_expr : ast:: RecordExpr ,
204205) {
205- let record_field_list = match record_lit . record_expr_field_list ( ) {
206+ let record_field_list = match record_expr . record_expr_field_list ( ) {
206207 Some ( it) => it,
207- None => ( ) ,
208+ None => return ,
208209 } ;
209210 for record_field in record_field_list. fields ( ) {
210211 let ( name_ref, expr) = match record_field. name_ref ( ) . zip ( record_field. expr ( ) ) {
@@ -239,6 +240,48 @@ fn check_expr_field_shorthand(
239240 }
240241}
241242
243+ fn check_pat_field_shorthand (
244+ acc : & mut Vec < Diagnostic > ,
245+ file_id : FileId ,
246+ record_pat : ast:: RecordPat ,
247+ ) {
248+ let record_pat_field_list = match record_pat. record_pat_field_list ( ) {
249+ Some ( it) => it,
250+ None => return ,
251+ } ;
252+ for record_pat_field in record_pat_field_list. fields ( ) {
253+ let ( name_ref, pat) = match record_pat_field. name_ref ( ) . zip ( record_pat_field. pat ( ) ) {
254+ Some ( it) => it,
255+ None => continue ,
256+ } ;
257+
258+ let field_name = name_ref. syntax ( ) . text ( ) . to_string ( ) ;
259+ let field_pat = pat. syntax ( ) . text ( ) . to_string ( ) ;
260+ let field_name_is_tup_index = name_ref. as_tuple_field ( ) . is_some ( ) ;
261+ if field_name != field_pat || field_name_is_tup_index {
262+ continue ;
263+ }
264+
265+ let mut edit_builder = TextEdit :: builder ( ) ;
266+ edit_builder. delete ( record_pat_field. syntax ( ) . text_range ( ) ) ;
267+ edit_builder. insert ( record_pat_field. syntax ( ) . text_range ( ) . start ( ) , field_name) ;
268+ let edit = edit_builder. finish ( ) ;
269+
270+ let field_range = record_pat_field. syntax ( ) . text_range ( ) ;
271+ acc. push ( Diagnostic {
272+ // name: None,
273+ range : field_range,
274+ message : "Shorthand struct pattern" . to_string ( ) ,
275+ severity : Severity :: WeakWarning ,
276+ fix : Some ( Fix :: new (
277+ "Use struct field shorthand" ,
278+ SourceFileEdit { file_id, edit } . into ( ) ,
279+ field_range,
280+ ) ) ,
281+ } ) ;
282+ }
283+ }
284+
242285#[ cfg( test) ]
243286mod tests {
244287 use expect_test:: { expect, Expect } ;
@@ -735,7 +778,7 @@ mod a {
735778 }
736779
737780 #[ test]
738- fn test_check_struct_shorthand_initialization ( ) {
781+ fn test_check_expr_field_shorthand ( ) {
739782 check_no_diagnostics (
740783 r#"
741784struct A { a: &'static str }
@@ -786,6 +829,52 @@ fn main() {
786829 ) ;
787830 }
788831
832+ #[ test]
833+ fn test_check_pat_field_shorthand ( ) {
834+ check_no_diagnostics (
835+ r#"
836+ struct A { a: &'static str }
837+ fn f(a: A) { let A { a: hello } = a; }
838+ "# ,
839+ ) ;
840+ check_no_diagnostics (
841+ r#"
842+ struct A(usize);
843+ fn f(a: A) { let A { 0: 0 } = a; }
844+ "# ,
845+ ) ;
846+
847+ check_fix (
848+ r#"
849+ struct A { a: &'static str }
850+ fn f(a: A) {
851+ let A { a<|>: a } = a;
852+ }
853+ "# ,
854+ r#"
855+ struct A { a: &'static str }
856+ fn f(a: A) {
857+ let A { a } = a;
858+ }
859+ "# ,
860+ ) ;
861+
862+ check_fix (
863+ r#"
864+ struct A { a: &'static str, b: &'static str }
865+ fn f(a: A) {
866+ let A { a<|>: a, b } = a;
867+ }
868+ "# ,
869+ r#"
870+ struct A { a: &'static str, b: &'static str }
871+ fn f(a: A) {
872+ let A { a, b } = a;
873+ }
874+ "# ,
875+ ) ;
876+ }
877+
789878 #[ test]
790879 fn test_add_field_from_usage ( ) {
791880 check_fix (
0 commit comments