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 @@ -349,6 +349,7 @@ pub struct Builder {
unsafety: Unsafe,
constness: Const,
ext: Extern,
inline: Inline,
attrs: AttrVec,
span: Span,
id: NodeId,
Expand All @@ -368,6 +369,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 @@ -385,6 +387,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 @@ -1773,7 +1782,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 {
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:?}");
}

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");
}
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,
}

#[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>,
}

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:?}");
}
}

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);
}
}
Loading
Loading