Skip to content

Commit cafb45c

Browse files
committed
refactor: avoid reordering attributes when restoring them
1 parent 8254c36 commit cafb45c

File tree

1 file changed

+15
-10
lines changed

1 file changed

+15
-10
lines changed

c2rust-refactor/src/collapse/macros.rs

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -338,18 +338,20 @@ impl<'a> MutVisitor for CollapseMacros<'a> {
338338
/// with known effects (such as `#[cfg]`, which removes itself when the condition is met) and tries
339339
/// to reverse those specific effects on `new.attrs`.
340340
fn restore_attrs(new_attrs: &mut Vec<Attribute>, old_attrs: &[Attribute]) {
341-
// If the original item had a `#[derive]` attr, transfer it to the new one.
342-
// TODO: handle multiple instances of `#[derive]`
343-
// TODO: try to keep attrs in the same order
344-
if let Some(attr) = crate::util::find_by_name(old_attrs, sym::derive) {
345-
if !crate::util::contains_name(&new_attrs, sym::derive) {
346-
new_attrs.push(attr.clone());
347-
}
341+
fn same_attr(a: &Attribute, b: &Attribute) -> bool {
342+
Iterator::eq(
343+
a.tokens().to_tokenstream().into_trees(),
344+
b.tokens().to_tokenstream().into_trees(),
345+
)
348346
}
349347

350-
if let Some(attr) = crate::util::find_by_name(old_attrs, sym::cfg) {
351-
if !crate::util::contains_name(&new_attrs, sym::cfg) {
352-
new_attrs.push(attr.clone());
348+
// If the original item had `#[derive]` or `#[cfg]` attrs, transfer them to the new one.
349+
for old_attr in old_attrs.iter().rev() {
350+
if old_attr.has_name(sym::derive) || old_attr.has_name(sym::cfg) {
351+
// Only copy the attr if an identical one is not already present.
352+
if !new_attrs.iter().any(|a| same_attr(a, old_attr)) {
353+
new_attrs.push(old_attr.clone());
354+
}
353355
}
354356
}
355357

@@ -358,6 +360,9 @@ fn restore_attrs(new_attrs: &mut Vec<Attribute>, old_attrs: &[Attribute]) {
358360
// (It can be written explicitly, but is also inserted by #[derive(Eq)].)
359361
!attr.has_name(sym::structural_match)
360362
});
363+
364+
// Sort the attributes by their original source position to avoid reordering.
365+
new_attrs.sort_by_key(|attr| attr.span.lo());
361366
}
362367

363368
fn spans_overlap(sp1: Span, sp2: Span) -> bool {

0 commit comments

Comments
 (0)