@@ -410,6 +410,10 @@ pub fn analyze(tcx: TyCtxt<'_>, conf: &Config) {
410
410
let ItemKind :: Union ( VariantData :: Struct ( fs, _) , _) = item. kind else { unreachable ! ( ) } ;
411
411
let field_names: IndexVec < FieldIdx , _ > =
412
412
fs. iter ( ) . map ( |f| f. ident . name . to_ident_string ( ) ) . collect ( ) ;
413
+ let field_tys: IndexVec < FieldIdx , _ > = fs
414
+ . iter ( )
415
+ . map ( |f| source_map. span_to_snippet ( f. ty . span ) . unwrap ( ) )
416
+ . collect ( ) ;
413
417
let field_name_to_index = fs
414
418
. iter ( )
415
419
. enumerate ( )
@@ -421,6 +425,7 @@ pub fn analyze(tcx: TyCtxt<'_>, conf: &Config) {
421
425
variant_tags,
422
426
empty_tags,
423
427
field_names,
428
+ field_tys,
424
429
field_name_to_index,
425
430
struct_local_def_id,
426
431
index_in_struct,
@@ -784,6 +789,7 @@ impl {} {{
784
789
suggestions : & mut suggestions,
785
790
786
791
locals : HashMap :: new ( ) ,
792
+ match_targets : HashMap :: new ( ) ,
787
793
} ;
788
794
visitor. visit_body ( hir_body) ;
789
795
}
@@ -1233,6 +1239,7 @@ struct TaggedUnion {
1233
1239
variant_tags : BTreeMap < FieldIdx , Vec < Tag > > ,
1234
1240
empty_tags : Vec < Tag > ,
1235
1241
field_names : IndexVec < FieldIdx , String > ,
1242
+ field_tys : IndexVec < FieldIdx , String > ,
1236
1243
field_name_to_index : HashMap < String , FieldIdx > ,
1237
1244
struct_local_def_id : LocalDefId ,
1238
1245
index_in_struct : FieldIdx ,
@@ -1251,6 +1258,7 @@ struct SuggestingVisitor<'a, 'tcx> {
1251
1258
suggestions : & ' a mut Suggestions < ' tcx > ,
1252
1259
1253
1260
locals : HashMap < HirId , & ' tcx Expr < ' tcx > > ,
1261
+ match_targets : HashMap < Span , String > ,
1254
1262
}
1255
1263
1256
1264
impl < ' tcx > SuggestingVisitor < ' _ , ' tcx > {
@@ -1267,6 +1275,9 @@ impl<'tcx> SuggestingVisitor<'_, 'tcx> {
1267
1275
ExprKind :: Field ( expr_struct, _) => {
1268
1276
let span = expr. span . with_lo ( expr_struct. span . hi ( ) ) ;
1269
1277
self . suggestions . add ( span, format ! ( ".{}" , union_field_name) ) ;
1278
+
1279
+ let s = source_map. span_to_snippet ( expr_struct. span ) . unwrap ( ) ;
1280
+ self . match_targets . insert ( expr. span , normalize_expr_str ( & s) ) ;
1270
1281
}
1271
1282
ExprKind :: Path ( QPath :: Resolved ( _, path) ) => {
1272
1283
let Res :: Local ( hir_id) = path. res else { unreachable ! ( ) } ;
@@ -1275,6 +1286,8 @@ impl<'tcx> SuggestingVisitor<'_, 'tcx> {
1275
1286
let struct_str = source_map. span_to_snippet ( expr_struct. span ) . unwrap ( ) ;
1276
1287
self . suggestions
1277
1288
. add ( expr. span , format ! ( "{}.{}" , struct_str, union_field_name) ) ;
1289
+ self . match_targets
1290
+ . insert ( expr. span , normalize_expr_str ( & struct_str) ) ;
1278
1291
}
1279
1292
_ => unreachable ! ( "{:?}" , expr) ,
1280
1293
}
@@ -1291,12 +1304,6 @@ impl<'tcx> SuggestingVisitor<'_, 'tcx> {
1291
1304
let pat = if tu. empty_tags . contains ( & tag) {
1292
1305
format ! ( "{}::Empty{}" , tu. name, tag)
1293
1306
} else {
1294
- assert ! ( matches!( arm. body. kind, ExprKind :: Block ( _, _) ) ) ;
1295
- let pos = arm. body . span . lo ( ) + BytePos ( 1 ) ;
1296
- let span = arm. body . span . with_lo ( pos) . with_hi ( pos) ;
1297
- self . suggestions
1298
- . add ( span, "let mut __v = __v as *mut _;" . to_string ( ) ) ;
1299
-
1300
1307
let f = tu
1301
1308
. variant_tags
1302
1309
. iter ( )
@@ -1310,6 +1317,14 @@ impl<'tcx> SuggestingVisitor<'_, 'tcx> {
1310
1317
} ,
1311
1318
)
1312
1319
. unwrap ( ) ;
1320
+
1321
+ assert ! ( matches!( arm. body. kind, ExprKind :: Block ( _, _) ) ) ;
1322
+ let pos = arm. body . span . lo ( ) + BytePos ( 1 ) ;
1323
+ let span = arm. body . span . with_lo ( pos) . with_hi ( pos) ;
1324
+ let f_ty = & tu. field_tys [ f] ;
1325
+ let code = format ! ( "let mut __v = __v as *mut {};" , f_ty) ;
1326
+ self . suggestions . add ( span, code) ;
1327
+
1313
1328
let f_name = & tu. field_names [ f] ;
1314
1329
format ! ( "{}::{}{}(ref mut __v)" , tu. name, f_name, tag)
1315
1330
} ;
@@ -1423,57 +1438,75 @@ impl<'tcx> SuggestingVisitor<'_, 'tcx> {
1423
1438
}
1424
1439
}
1425
1440
} else if let Some ( tu) = self . unions . get ( & did) {
1426
- let ( ctx, _) = get_expr_context ( expr, self . tcx ) ;
1427
- match ctx {
1428
- ExprContext :: Value => {
1429
- let call = format ! ( "get_{}()" , field. name) ;
1430
- self . suggestions . add ( field. span , call) ;
1431
- }
1432
- ExprContext :: Store ( _) | ExprContext :: Address => {
1433
- let span = expr. span . shrink_to_lo ( ) ;
1434
- self . suggestions . add ( span, "(*" . to_string ( ) ) ;
1435
-
1436
- let ItemKind :: Union ( VariantData :: Struct ( fs, _) , _) =
1437
- self . tcx . hir ( ) . expect_item ( did) . kind
1438
- else {
1439
- unreachable ! ( )
1440
- } ;
1441
- let ( i, _) = fs
1442
- . iter ( )
1443
- . enumerate ( )
1444
- . find ( |( _, f) | f. ident . name == field. name )
1445
- . unwrap ( ) ;
1446
- let tags = & tu. variant_tags [ & FieldIdx :: from ( i) ] ;
1447
-
1448
- let call = if tags. len ( ) == 1 {
1449
- format ! ( "deref_{}_mut())" , field. name)
1450
- } else {
1451
- let ts = & self . structs [ & tu. struct_local_def_id ] ;
1452
- let field_name = & ts. field_names [ ts. tag_index ] ;
1453
- let ExprKind :: Field ( e2, _) = e. kind else { unreachable ! ( ) } ;
1454
- let tag = format ! (
1455
- "{}.{}" ,
1456
- source_map. span_to_snippet( e2. span) . unwrap( ) ,
1457
- field_name,
1458
- ) ;
1459
- format ! ( "deref_{}_mut({}()))" , field. name, tag)
1460
- } ;
1461
- self . suggestions . add ( field. span , call) ;
1462
-
1463
- let root = get_root ( expr) ;
1464
- if let ExprKind :: Unary ( UnOp :: Deref , e) = root. kind {
1465
- let ty = self . typeck . expr_ty ( e) ;
1466
- if let TyKind :: RawPtr ( TypeAndMut {
1467
- mutbl : Mutability :: Not ,
1468
- ty,
1469
- } ) = ty. kind ( )
1470
- {
1471
- let span = e. span . shrink_to_lo ( ) ;
1472
- self . suggestions . add ( span, "(" . to_string ( ) ) ;
1441
+ let matched = if let Some ( ( match_span, _) ) = self
1442
+ . access_in_matches
1443
+ . iter ( )
1444
+ . find ( |( _, ams) | ams. iter ( ) . any ( |am| am. arm_span . contains ( expr. span ) ) )
1445
+ {
1446
+ let s1 = & self . match_targets [ match_span] ;
1447
+ let ExprKind :: Field ( expr_struct, _) = e. kind else { unreachable ! ( ) } ;
1448
+ let struct_str = source_map. span_to_snippet ( expr_struct. span ) . unwrap ( ) ;
1449
+ let s2 = normalize_expr_str ( & struct_str) ;
1450
+ s1 == & s2
1451
+ } else {
1452
+ false
1453
+ } ;
1454
+
1455
+ if matched {
1456
+ self . suggestions . add ( expr. span , "(*__v)" . to_string ( ) ) ;
1457
+ } else {
1458
+ let ( ctx, _) = get_expr_context ( expr, self . tcx ) ;
1459
+ match ctx {
1460
+ ExprContext :: Value => {
1461
+ let call = format ! ( "get_{}()" , field. name) ;
1462
+ self . suggestions . add ( field. span , call) ;
1463
+ }
1464
+ ExprContext :: Store ( _) | ExprContext :: Address => {
1465
+ let span = expr. span . shrink_to_lo ( ) ;
1466
+ self . suggestions . add ( span, "(*" . to_string ( ) ) ;
1467
+
1468
+ let ItemKind :: Union ( VariantData :: Struct ( fs, _) , _) =
1469
+ self . tcx . hir ( ) . expect_item ( did) . kind
1470
+ else {
1471
+ unreachable ! ( )
1472
+ } ;
1473
+ let ( i, _) = fs
1474
+ . iter ( )
1475
+ . enumerate ( )
1476
+ . find ( |( _, f) | f. ident . name == field. name )
1477
+ . unwrap ( ) ;
1478
+ let tags = & tu. variant_tags [ & FieldIdx :: from ( i) ] ;
1479
+
1480
+ let call = if tags. len ( ) == 1 {
1481
+ format ! ( "deref_{}_mut())" , field. name)
1482
+ } else {
1483
+ let ts = & self . structs [ & tu. struct_local_def_id ] ;
1484
+ let field_name = & ts. field_names [ ts. tag_index ] ;
1485
+ let ExprKind :: Field ( e2, _) = e. kind else { unreachable ! ( ) } ;
1486
+ let tag = format ! (
1487
+ "{}.{}" ,
1488
+ source_map. span_to_snippet( e2. span) . unwrap( ) ,
1489
+ field_name,
1490
+ ) ;
1491
+ format ! ( "deref_{}_mut({}()))" , field. name, tag)
1492
+ } ;
1493
+ self . suggestions . add ( field. span , call) ;
1494
+
1495
+ let root = get_root ( expr) ;
1496
+ if let ExprKind :: Unary ( UnOp :: Deref , e) = root. kind {
1497
+ let ty = self . typeck . expr_ty ( e) ;
1498
+ if let TyKind :: RawPtr ( TypeAndMut {
1499
+ mutbl : Mutability :: Not ,
1500
+ ty,
1501
+ } ) = ty. kind ( )
1502
+ {
1503
+ let span = e. span . shrink_to_lo ( ) ;
1504
+ self . suggestions . add ( span, "(" . to_string ( ) ) ;
1473
1505
1474
- let span = e. span . shrink_to_hi ( ) ;
1475
- let cast = format ! ( " as *mut crate::{:?})" , ty) ;
1476
- self . suggestions . add ( span, cast) ;
1506
+ let span = e. span . shrink_to_hi ( ) ;
1507
+ let cast = format ! ( " as *mut crate::{:?})" , ty) ;
1508
+ self . suggestions . add ( span, cast) ;
1509
+ }
1477
1510
}
1478
1511
}
1479
1512
}
@@ -1995,3 +2028,9 @@ fn unwrap_cast<'a, 'tcx>(e: &'a Expr<'tcx>) -> &'a Expr<'tcx> {
1995
2028
let ExprKind :: Cast ( e, _) = e. kind else { return e } ;
1996
2029
unwrap_cast ( e)
1997
2030
}
2031
+
2032
+ fn normalize_expr_str ( s : & str ) -> String {
2033
+ s. chars ( )
2034
+ . filter ( |& c| !c. is_whitespace ( ) && c != '(' && c != ')' )
2035
+ . collect ( )
2036
+ }
0 commit comments