Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 21 additions & 1 deletion c2rust-refactor/src/rewrite/strategy/print.rs
Original file line number Diff line number Diff line change
Expand Up @@ -674,7 +674,27 @@ fn rewrite_at_impl<T>(old_span: Span, new: &T, mut rcx: RewriteCtxtRef) -> bool
where
T: PrintParse + RecoverChildren + Splice + MaybeGetNodeId,
{
let printed = add_comments(new.to_string(), new, &rcx);
let mut printed = add_comments(new.to_string(), new, &rcx);

// Fallback: extract source snippet when pretty-printing produces empty output.
//
// pprust can emit "" for Local statements whose inner Local has DUMMY_NODE_ID
// (sink_lets sets that intentionally). Reparse of "" yields 0 statements and
// hits the lone() assertion. The fallback replaces the empty string with the
// original source via span_to_snippet(), assuming the statement carries a real
// span (set in vars.rs).
if printed.trim().is_empty() {
if let Ok(snippet) = rcx
.session()
.source_map()
.span_to_snippet(new.splice_span())
{
if !snippet.trim().is_empty() {
printed = snippet;
}
}
}

let reparsed = T::parse(rcx.session(), &printed);
let reparsed = reparsed.ast_deref();

Expand Down
37 changes: 35 additions & 2 deletions c2rust-refactor/src/transform/vars.rs
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,18 @@ impl Transform for SinkLets {
Some(x) => x; return);

let mut new_stmts = place_here.iter()
.map(|&id| mk().local_stmt(&locals[&id].local))
.map(|&id| {
let local = &locals[&id].local;
// Set the statement's span to match the local's span.
//
// By default, mk().local_stmt() creates a Stmt with DUMMY_SP. The rewrite system
// uses stmt.span (via the Splice trait) to extract source text for recovery during
// the print/reparse cycle. Without a valid span, source extraction fails.
//
// Setting stmt.span = local.span provides a valid source location. The Splice
// implementation in print.rs will extend this to cover any attributes.
mk().span(local.span).local_stmt(local)
})
.collect::<Vec<_>>();
new_stmts.append(&mut b.stmts);
b.stmts = new_stmts;
Expand Down Expand Up @@ -415,7 +426,20 @@ impl Transform for FoldLetAssign {
let local_mark = local_pos.remove(&hir_id).unwrap();
let mut l = local.clone();
l.kind = LocalKind::Init(init);
curs.replace(|_| mk().local_stmt(l));

// Preserve the original local's span when creating the combined statement.
//
// fold_let_assign transforms:
// let x; <- original local
// x = expr; <- assignment
// into:
// let x = expr; <- combined local
//
// The combined Local keeps l.span from the original declaration. Setting
// stmt.span = l.span allows the rewrite system to extract source text using
// the Splice trait. Without this, stmt.span would be DUMMY_SP and source
// extraction would fail.
curs.replace(move |_| mk().span(l.span).local_stmt(l));

let here = curs.mark();
curs.seek(local_mark);
Expand Down Expand Up @@ -514,6 +538,7 @@ impl Transform for RemoveRedundantLetTypes {
let pat = mcx.parse_stmts("let $pat:Pat : $ty:Ty = $init:Expr;");
let repl = mcx.parse_stmts("let $pat = $init;");
mut_visit_match_with(mcx, pat, krate, |ast, mcx| {
let orig_span = ast.get(0).map(|s| s.span);
let e = mcx.bindings.get::<_, P<Expr>>("$init").unwrap();
let e_ty = cx.adjusted_node_type(e.id);
let e_ty = tcx.normalize_erasing_regions(ParamEnv::empty(), e_ty);
Expand All @@ -523,6 +548,14 @@ impl Transform for RemoveRedundantLetTypes {
let t_ty = tcx.normalize_erasing_regions(ParamEnv::empty(), t_ty);
if e_ty == t_ty {
*ast = repl.clone().subst(st, cx, &mcx.bindings);
// Preserve the original statement's span after replacement.
//
// The subst() call creates a new Stmt from the replacement pattern, which has
// a synthetic span from the pattern parse. Restoring the original span allows
// the rewrite system to extract source text via the Splice trait.
if let (Some(span), Some(first)) = (orig_span, ast.get_mut(0)) {
first.span = span;
}
}
})
}
Expand Down