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
11 changes: 10 additions & 1 deletion c2rust-refactor/src/ast_builder/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,7 @@ pub struct Builder {
unsafety: Unsafe,
constness: Const,
ext: Extern,
inline: Inline,
attrs: AttrVec,
span: Span,
id: NodeId,
Expand All @@ -371,6 +372,7 @@ impl Builder {
unsafety: Unsafe::No,
constness: Const::No,
ext: Extern::None,
inline: Inline::No,
attrs: AttrVec::new(),
span: DUMMY_SP,
id: DUMMY_NODE_ID,
Expand All @@ -388,6 +390,13 @@ impl Builder {
self.vis("pub")
}

pub fn inline(self) -> Self {
Builder {
inline: Inline::Yes,
..self
}
}

pub fn set_mutbl<M: Make<Mutability>>(self, mutbl: M) -> Self {
let mutbl = mutbl.make(&self);
Builder {
Expand Down Expand Up @@ -1776,7 +1785,7 @@ impl Builder {
inner_span: self.span,
inject_use_span: DUMMY_SP,
};
ModKind::Loaded(items, Inline::Yes, spans)
ModKind::Loaded(items, self.inline, spans)
}

pub fn mac_item<M>(self, mac: M) -> P<Item>
Expand Down
84 changes: 84 additions & 0 deletions c2rust-refactor/src/ast_manip/load_modules.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
use rustc_ast::mut_visit::{self, MutVisitor};
use rustc_ast::ptr::P;
use rustc_ast::*;
use rustc_parse::new_parser_from_file;
use rustc_session::parse::ParseSess;
use rustc_span::source_map::SourceMap;
use rustc_span::FileName;
use smallvec::SmallVec;
use std::path::PathBuf;

struct LoadModules<'a> {
parse_sess: &'a ParseSess,
source_map: &'a SourceMap,
dir_path: PathBuf,
}

impl<'a> MutVisitor for LoadModules<'a> {
fn flat_map_item(&mut self, mut i: P<Item>) -> SmallVec<[P<Item>; 1]> {
let Item {
ref mut attrs,
ref span,
ref ident,
kind: ItemKind::Mod(_, ref mut mod_kind),
..
} = *i else {
Comment on lines +19 to +25
Copy link
Contributor

@kkysen kkysen Oct 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
let Item {
ref mut attrs,
ref span,
ref ident,
kind: ItemKind::Mod(_, ref mut mod_kind),
..
} = *i else {
let Item {
attrs,
span,
ident,
kind: ItemKind::Mod(_, mod_kind),
..
} = &mut *i else {

return mut_visit::noop_flat_map_item(i, self);
};

match mod_kind {
ModKind::Loaded(_items, Inline::Yes, _spans) => {
// TODO: handle #[path="..."]
}

ModKind::Loaded(_items, Inline::No, _spans) => {
// We shouldn't be seeing any loaded modules at this point
panic!("unexpected loaded module: {i:?}");
}
Comment on lines +30 to +37
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The conjunction of these two comments is confusing: are inline modules not considered loaded modules (such that we might see them)? Or is it that specifically we shouldn't see any non-inline loaded modules yet?


ModKind::Unloaded => {
// Look for dir_path/foo.rs, then try dir_path/foo/mod.rs
let mut mod_file_path = self.dir_path.join(ident.as_str()).with_extension("rs");
if !self.source_map.file_exists(&mod_file_path) {
mod_file_path = self.dir_path.join(ident.as_str()).with_file_name("mod.rs");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't do ${dir_path}/${ident}/mod.rs, it does ${dir_path}/mod.rs.

}
if !self.source_map.file_exists(&mod_file_path) {
panic!("unable to load module file {mod_file_path:?}");
}

let mut parser =
new_parser_from_file(&self.parse_sess, &mod_file_path, Some(*span));
let (mut inner_attrs, items, inner_span) = parser
.parse_mod(&token::Eof)
.expect("failed to parse {mod_file_path:?}");

attrs.append(&mut inner_attrs);
*mod_kind = ModKind::Loaded(items, Inline::No, inner_span);
}
}

self.dir_path.push(ident.as_str());
let res = mut_visit::noop_flat_map_item(i, self);
self.dir_path.pop();

res
}
}

pub fn load_modules(krate: &mut Crate, parse_sess: &ParseSess, source_map: &SourceMap) {
let file_path = match source_map.span_to_filename(krate.spans.inner_span) {
FileName::Real(name) => name
.into_local_path()
.expect("attempting to resolve a file path in an external file"),
other => panic!("crate is not from a real file: {other:?}"),
};
let dir_path = file_path.parent().unwrap_or(&file_path).to_owned();

let mut lm = LoadModules {
parse_sess,
source_map,
dir_path,
};

lm.visit_crate(krate);
}
4 changes: 4 additions & 0 deletions c2rust-refactor/src/ast_manip/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@ mod fold;
mod get_node_id;
mod get_span;
mod list_node_ids;
mod load_modules;
mod output_exprs;
mod remove_paren;
mod seq_edit;
mod span_maps;
mod visit;
mod visit_node;

Expand All @@ -29,9 +31,11 @@ pub use self::fold::{FlatMapNodes, MutVisit, MutVisitNodes, WalkAst};
pub use self::get_node_id::{GetNodeId, MaybeGetNodeId};
pub use self::get_span::GetSpan;
pub use self::list_node_ids::ListNodeIds;
pub use self::load_modules::load_modules;
pub use self::output_exprs::fold_output_exprs;
pub use self::remove_paren::remove_paren;
pub use self::seq_edit::{fold_blocks, fold_modules};
pub use self::span_maps::{AstSpanMaps, NodeSpan, SpanNodeKind};
pub use self::visit::Visit;
pub use self::visit_node::{visit_nodes, visit_nodes_post, VisitNode};

Expand Down
170 changes: 170 additions & 0 deletions c2rust-refactor/src/ast_manip/span_maps.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
use rustc_ast::visit::{self, AssocCtxt, Visitor};
use rustc_ast::*;
use rustc_span::Span;
use std::collections::HashMap;

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum SpanNodeKind {
Crate,
Block,
Pat,
PatField,
Stmt,
Local,
Arm,
ExprField,
Expr,
AssocConstraint,
Ty,
Param,
Variant,
FieldDef,
Item,
ForeignItem,
AssocItem,
// We need a separate kind for ExprKind::Path because
// the rustc macro expander emits `*foo` expressions where
// both the outer and inner expressions have the same span
// We disambiguate by assigning (span, Expr) to the outer one,
// and (span, PathExpr) to the inner expression.
PathExpr,
Comment on lines +25 to +30
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this similar to the span_fix module that driver.rs claims (in a 6-year-old comment) we should be using?

}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct NodeSpan {
pub span: Span,
pub kind: SpanNodeKind,
}

impl NodeSpan {
pub fn new(span: Span, kind: SpanNodeKind) -> Self {
Self { span, kind }
}
}

#[derive(Default, Clone)]
pub struct AstSpanMaps {
pub node_id_to_span_map: HashMap<NodeId, NodeSpan>,
pub span_to_node_id_map: HashMap<NodeSpan, NodeId>,
Comment on lines +47 to +48
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we use HashMap sometimes and FxHashMap other times?

}

impl AstSpanMaps {
pub fn new(krate: &Crate) -> Self {
let mut mapper = AstSpanMapper::default();
mapper.visit_crate(krate);
mapper.0
}
}

#[derive(Default, Clone)]
struct AstSpanMapper(AstSpanMaps);

impl AstSpanMapper {
fn insert_mapping(&mut self, id: NodeId, span: Span, kind: SpanNodeKind) {
if id == DUMMY_NODE_ID || span.is_dummy() {
return;
}

let ns = NodeSpan { span, kind };
let old_ns = self.0.node_id_to_span_map.insert(id, ns);
let _old_id = self.0.span_to_node_id_map.insert(ns, id);

assert!(
old_ns.is_none(),
"id {id:?} already has span {old_ns:?} != {ns:?}"
);
// Some spans can show up in multiple nodes
//assert!(old_id.is_none(), "span {ns:?} already has id {old_id:?} != {id:?}");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't this redundant?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh this is old_id not old_ns, nevermind.

}
}

impl Visitor<'_> for AstSpanMapper {
fn visit_crate(&mut self, krate: &Crate) {
self.insert_mapping(krate.id, krate.spans.inner_span, SpanNodeKind::Crate);
visit::walk_crate(self, krate);
}

fn visit_block(&mut self, block: &Block) {
self.insert_mapping(block.id, block.span, SpanNodeKind::Block);
visit::walk_block(self, block);
}

fn visit_pat(&mut self, pat: &Pat) {
self.insert_mapping(pat.id, pat.span, SpanNodeKind::Pat);
visit::walk_pat(self, pat);
}

fn visit_pat_field(&mut self, pf: &PatField) {
self.insert_mapping(pf.id, pf.span, SpanNodeKind::PatField);
visit::walk_pat_field(self, pf);
}

fn visit_stmt(&mut self, stmt: &Stmt) {
self.insert_mapping(stmt.id, stmt.span, SpanNodeKind::Stmt);
visit::walk_stmt(self, stmt);
}

fn visit_local(&mut self, local: &Local) {
self.insert_mapping(local.id, local.span, SpanNodeKind::Local);
visit::walk_local(self, local);
}

fn visit_arm(&mut self, arm: &Arm) {
self.insert_mapping(arm.id, arm.span, SpanNodeKind::Arm);
visit::walk_arm(self, arm);
}

fn visit_expr_field(&mut self, ef: &ExprField) {
self.insert_mapping(ef.id, ef.span, SpanNodeKind::ExprField);
visit::walk_expr_field(self, ef);
}

fn visit_expr(&mut self, expr: &Expr) {
if matches!(expr.kind, ExprKind::Path(..)) {
self.insert_mapping(expr.id, expr.span, SpanNodeKind::PathExpr);
} else {
self.insert_mapping(expr.id, expr.span, SpanNodeKind::Expr);
}
visit::walk_expr(self, expr);
}

fn visit_assoc_constraint(&mut self, ac: &AssocConstraint) {
self.insert_mapping(ac.id, ac.span, SpanNodeKind::AssocConstraint);
visit::walk_assoc_constraint(self, ac);
}

fn visit_ty(&mut self, ty: &Ty) {
self.insert_mapping(ty.id, ty.span, SpanNodeKind::Ty);
visit::walk_ty(self, ty);
}

fn visit_param(&mut self, param: &Param) {
self.insert_mapping(param.id, param.span, SpanNodeKind::Param);
visit::walk_param(self, param);
}

fn visit_variant(&mut self, var: &Variant) {
self.insert_mapping(var.id, var.span, SpanNodeKind::Variant);
visit::walk_variant(self, var);
}

fn visit_field_def(&mut self, fd: &FieldDef) {
self.insert_mapping(fd.id, fd.span, SpanNodeKind::FieldDef);
visit::walk_field_def(self, fd);
}

fn visit_item(&mut self, i: &Item) {
self.insert_mapping(i.id, i.span, SpanNodeKind::Item);
visit::walk_item(self, i);
}

fn visit_foreign_item(&mut self, i: &ForeignItem) {
self.insert_mapping(i.id, i.span, SpanNodeKind::ForeignItem);
visit::walk_foreign_item(self, i);
}

fn visit_assoc_item(&mut self, i: &AssocItem, ctxt: AssocCtxt) {
self.insert_mapping(i.id, i.span, SpanNodeKind::AssocItem);
visit::walk_assoc_item(self, i, ctxt);
}
}
10 changes: 5 additions & 5 deletions c2rust-refactor/src/collapse/mac_table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use rustc_target::spec::abi::Abi;
use rustc_ast::ptr::P;
use rustc_ast::visit::{AssocCtxt, Visitor};
use rustc_span::source_map::Spanned;
use rustc_span::Symbol;
use rustc_span::{sym, Symbol};
use std::fmt::Debug;
use std::rc::Rc;

Expand Down Expand Up @@ -399,7 +399,7 @@ fn is_derived<'a>(invoc: InvocKind<'a>, new: MacNodeRef<'a>) -> bool {
_ => None,
};
if let Some(attrs) = attrs {
if crate::util::contains_name(attrs, Symbol::intern("automatically_derived")) {
if crate::util::contains_name(attrs, sym::automatically_derived) {
return true;
}
}
Expand Down Expand Up @@ -520,9 +520,9 @@ impl CollectMacros for NodeId {
}

fn has_macro_attr(attrs: &[Attribute]) -> bool {
crate::util::contains_name(attrs, Symbol::intern("derive"))
|| crate::util::contains_name(attrs, Symbol::intern("cfg"))
|| crate::util::contains_name(attrs, Symbol::intern("test"))
crate::util::contains_name(attrs, sym::derive)
|| crate::util::contains_name(attrs, sym::cfg)
|| crate::util::contains_name(attrs, sym::test)
}

trait MaybeInvoc {
Expand Down
Loading
Loading