Skip to content

Commit a24c58c

Browse files
committed
match arm
1 parent 1e1e9e2 commit a24c58c

File tree

1 file changed

+95
-56
lines changed

1 file changed

+95
-56
lines changed

src/tag_analysis.rs

Lines changed: 95 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -410,6 +410,10 @@ pub fn analyze(tcx: TyCtxt<'_>, conf: &Config) {
410410
let ItemKind::Union(VariantData::Struct(fs, _), _) = item.kind else { unreachable!() };
411411
let field_names: IndexVec<FieldIdx, _> =
412412
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();
413417
let field_name_to_index = fs
414418
.iter()
415419
.enumerate()
@@ -421,6 +425,7 @@ pub fn analyze(tcx: TyCtxt<'_>, conf: &Config) {
421425
variant_tags,
422426
empty_tags,
423427
field_names,
428+
field_tys,
424429
field_name_to_index,
425430
struct_local_def_id,
426431
index_in_struct,
@@ -784,6 +789,7 @@ impl {} {{
784789
suggestions: &mut suggestions,
785790

786791
locals: HashMap::new(),
792+
match_targets: HashMap::new(),
787793
};
788794
visitor.visit_body(hir_body);
789795
}
@@ -1233,6 +1239,7 @@ struct TaggedUnion {
12331239
variant_tags: BTreeMap<FieldIdx, Vec<Tag>>,
12341240
empty_tags: Vec<Tag>,
12351241
field_names: IndexVec<FieldIdx, String>,
1242+
field_tys: IndexVec<FieldIdx, String>,
12361243
field_name_to_index: HashMap<String, FieldIdx>,
12371244
struct_local_def_id: LocalDefId,
12381245
index_in_struct: FieldIdx,
@@ -1251,6 +1258,7 @@ struct SuggestingVisitor<'a, 'tcx> {
12511258
suggestions: &'a mut Suggestions<'tcx>,
12521259

12531260
locals: HashMap<HirId, &'tcx Expr<'tcx>>,
1261+
match_targets: HashMap<Span, String>,
12541262
}
12551263

12561264
impl<'tcx> SuggestingVisitor<'_, 'tcx> {
@@ -1267,6 +1275,9 @@ impl<'tcx> SuggestingVisitor<'_, 'tcx> {
12671275
ExprKind::Field(expr_struct, _) => {
12681276
let span = expr.span.with_lo(expr_struct.span.hi());
12691277
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));
12701281
}
12711282
ExprKind::Path(QPath::Resolved(_, path)) => {
12721283
let Res::Local(hir_id) = path.res else { unreachable!() };
@@ -1275,6 +1286,8 @@ impl<'tcx> SuggestingVisitor<'_, 'tcx> {
12751286
let struct_str = source_map.span_to_snippet(expr_struct.span).unwrap();
12761287
self.suggestions
12771288
.add(expr.span, format!("{}.{}", struct_str, union_field_name));
1289+
self.match_targets
1290+
.insert(expr.span, normalize_expr_str(&struct_str));
12781291
}
12791292
_ => unreachable!("{:?}", expr),
12801293
}
@@ -1291,12 +1304,6 @@ impl<'tcx> SuggestingVisitor<'_, 'tcx> {
12911304
let pat = if tu.empty_tags.contains(&tag) {
12921305
format!("{}::Empty{}", tu.name, tag)
12931306
} 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-
13001307
let f = tu
13011308
.variant_tags
13021309
.iter()
@@ -1310,6 +1317,14 @@ impl<'tcx> SuggestingVisitor<'_, 'tcx> {
13101317
},
13111318
)
13121319
.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+
13131328
let f_name = &tu.field_names[f];
13141329
format!("{}::{}{}(ref mut __v)", tu.name, f_name, tag)
13151330
};
@@ -1423,57 +1438,75 @@ impl<'tcx> SuggestingVisitor<'_, 'tcx> {
14231438
}
14241439
}
14251440
} 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());
14731505

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+
}
14771510
}
14781511
}
14791512
}
@@ -1995,3 +2028,9 @@ fn unwrap_cast<'a, 'tcx>(e: &'a Expr<'tcx>) -> &'a Expr<'tcx> {
19952028
let ExprKind::Cast(e, _) = e.kind else { return e };
19962029
unwrap_cast(e)
19972030
}
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

Comments
 (0)