Skip to content

Commit 906bf45

Browse files
committed
Fix format! macro spans for correct collapsing.
This depends on rust-lang/rust#64793 landing upstream.
1 parent fc624e4 commit 906bf45

File tree

1 file changed

+84
-24
lines changed

1 file changed

+84
-24
lines changed

c2rust-refactor/src/span_fix.rs

+84-24
Original file line numberDiff line numberDiff line change
@@ -21,22 +21,61 @@ use crate::ast_manip::MutVisit;
2121
/// causes problems for us later on. This folder detects nodes like `&foo` and gives them a
2222
/// macro-generated span to fix the problem.
2323
struct FixFormat {
24+
ctxt: FormatCtxt,
25+
}
26+
27+
#[derive(Clone)]
28+
struct FormatCtxt {
2429
/// The span of the most recent ancestor `Expr`.
2530
parent_span: Span,
2631
/// Are we currently inside (the macro-generated part of) a `format!` invocation?
2732
in_format: bool,
33+
/// Are we currently inside the match in (the macro-generated part of) a
34+
/// `format!` invocation?
35+
in_match: bool,
36+
}
37+
38+
impl FormatCtxt {
39+
fn new(span: Span) -> Self {
40+
FormatCtxt {
41+
parent_span: span,
42+
in_format: false,
43+
in_match: false,
44+
}
45+
}
46+
47+
fn enter_span(&self, span: Span) -> Self {
48+
FormatCtxt {
49+
parent_span: span,
50+
..*self
51+
}
52+
}
53+
54+
fn enter_format(&self, span: Span) -> Self {
55+
FormatCtxt {
56+
parent_span: span,
57+
in_format: true,
58+
..*self
59+
}
60+
}
61+
62+
fn enter_match(&self, span: Span) -> Self {
63+
FormatCtxt {
64+
parent_span: span,
65+
in_match: true,
66+
..*self
67+
}
68+
}
2869
}
2970

3071
impl FixFormat {
31-
fn descend<F, R>(&mut self, in_format: bool, cur_span: Span, f: F) -> R
72+
fn descend<F, R>(&mut self, new_ctxt: FormatCtxt, f: F) -> R
3273
where
3374
F: FnOnce(&mut Self) -> R,
3475
{
35-
let old_in_format = mem::replace(&mut self.in_format, in_format);
36-
let old_parent_span = mem::replace(&mut self.parent_span, cur_span);
76+
let old_ctxt = mem::replace(&mut self.ctxt, new_ctxt);
3777
let r = f(self);
38-
self.in_format = old_in_format;
39-
self.parent_span = old_parent_span;
78+
self.ctxt = old_ctxt;
4079
r
4180
}
4281

@@ -48,40 +87,62 @@ impl FixFormat {
4887
// recognize it by its span: it's macro-generated, but the "macro definition" actually
4988
// points to the format string, which lies inside the macro invocation itself.
5089

51-
if !matches!([e.node] ExprKind::Match(..)) {
90+
if !e.span.from_expansion() {
5291
return false;
5392
}
5493

55-
if !e.span.from_expansion() {
56-
return false;
94+
if let ExprKind::Call(callee, _) = &e.node {
95+
if let ExprKind::Path(None, path) = &callee.node {
96+
let matches_fmt_args = path.segments.len() == 4 &&
97+
path.segments[1].ident.as_str() == "fmt" &&
98+
path.segments[2].ident.as_str() == "Arguments" &&
99+
(path.segments[3].ident.as_str() == "new_v1" ||
100+
path.segments[3].ident.as_str() == "new_v1_formatted");
101+
return matches_fmt_args;
102+
}
57103
}
58104

59-
e.span.source_callsite().contains(e.span)
105+
false
60106
}
61107
}
62108

63109
impl MutVisitor for FixFormat {
64110
fn visit_expr(&mut self, e: &mut P<Expr>) {
65-
if self.in_format
66-
&& !e.span.from_expansion()
111+
if !e.span.from_expansion()
112+
&& self.ctxt.in_match
67113
&& matches!([e.node] ExprKind::AddrOf(..))
68114
{
69115
trace!("EXITING format! at {:?}", e);
70-
// Current node is the `&foo`. We need to change its span. On recursing into `foo`,
71-
// we are no longer inside a `format!` invocation.
72-
let new_span = self.parent_span;
73-
self.descend(false, e.span, |this| {
116+
// Current node is the `&foo`. We need to change its span. On
117+
// recursing into `foo`, we are no longer inside a `format!`
118+
// invocation.
119+
let mac_span = self.ctxt.parent_span;
120+
let leave_ctxt = FormatCtxt::new(e.span);
121+
self.descend(leave_ctxt, |this| {
74122
mut_visit::noop_visit_expr(e, this);
75-
e.span = new_span;
123+
e.span = mac_span;
76124
})
77-
} else if !self.in_format && self.is_format_entry(&e) {
125+
} else if !e.span.from_expansion()
126+
&& self.ctxt.in_format
127+
&& !self.ctxt.in_match
128+
{
129+
trace!("Fixing format! string at {:?}", e);
130+
let mac_span = self.ctxt.parent_span;
131+
let new_ctxt = self.ctxt.enter_span(mac_span);
132+
self.descend(new_ctxt, |this| {
133+
mut_visit::noop_visit_expr(e, this);
134+
e.span = mac_span;
135+
})
136+
} else if self.ctxt.in_format && matches!([e.node] ExprKind::Match(..)) {
137+
let new_ctxt = self.ctxt.enter_match(e.span);
138+
self.descend(new_ctxt, |this| mut_visit::noop_visit_expr(e, this))
139+
} else if !self.ctxt.in_format && self.is_format_entry(&e) {
78140
trace!("ENTERING format! at {:?}", e);
79-
self.descend(true, e.span, |this| mut_visit::noop_visit_expr(e, this))
141+
let new_ctxt = self.ctxt.enter_format(e.span);
142+
self.descend(new_ctxt, |this| mut_visit::noop_visit_expr(e, this))
80143
} else {
81-
let in_format = self.in_format;
82-
self.descend(in_format, e.span, |this| {
83-
mut_visit::noop_visit_expr(e, this)
84-
})
144+
let new_ctxt = self.ctxt.enter_span(e.span);
145+
self.descend(new_ctxt, |this| mut_visit::noop_visit_expr(e, this))
85146
}
86147
}
87148

@@ -129,8 +190,7 @@ impl MutVisitor for FixAttrs {
129190
#[cfg_attr(feature = "profile", flame)]
130191
pub fn fix_format<T: MutVisit>(node: &mut T) {
131192
let mut fix_format = FixFormat {
132-
parent_span: DUMMY_SP,
133-
in_format: false,
193+
ctxt: FormatCtxt::new(DUMMY_SP),
134194
};
135195
node.visit(&mut fix_format)
136196
}

0 commit comments

Comments
 (0)