Skip to content

Commit ac75014

Browse files
committed
c2rust-refactor: Map NodeIds to HirIds using a set of intermediate Span maps
1 parent a0477c2 commit ac75014

File tree

5 files changed

+211
-8
lines changed

5 files changed

+211
-8
lines changed

c2rust-refactor/src/ast_manip/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ mod load_modules;
1515
mod output_exprs;
1616
mod remove_paren;
1717
mod seq_edit;
18+
mod span_maps;
1819
mod visit;
1920
mod visit_node;
2021

@@ -34,6 +35,7 @@ pub use self::visit::Visit;
3435
pub use self::visit_node::{visit_nodes, visit_nodes_post, VisitNode};
3536
pub use self::comments::{collect_comments, gather_comments, Comment, CommentMap, CommentStyle};
3637
pub use self::load_modules::load_modules;
38+
pub use self::span_maps::AstSpanMaps;
3739

3840
// Modules with more complex APIs are left as `pub`.
3941
pub mod comments;
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
use std::collections::HashMap;
2+
use rustc_ast::*;
3+
use rustc_ast::node_id::NodeMap;
4+
use rustc_ast::visit::{self, AssocCtxt, Visitor};
5+
use rustc_span::Span;
6+
7+
#[derive(Default, Clone)]
8+
pub struct AstSpanMaps {
9+
pub node_id_to_span_map: NodeMap<Span>,
10+
pub span_to_node_id_map: HashMap<Span, NodeId>,
11+
}
12+
13+
impl AstSpanMaps {
14+
pub fn new(krate: &Crate) -> Self {
15+
let mut mapper = AstSpanMapper::default();
16+
mapper.visit_crate(krate);
17+
mapper.0
18+
}
19+
}
20+
21+
#[derive(Default, Clone)]
22+
struct AstSpanMapper(AstSpanMaps);
23+
24+
impl AstSpanMapper {
25+
fn insert_mapping(&mut self, id: NodeId, span: Span) {
26+
if id == DUMMY_NODE_ID || span.is_dummy() {
27+
return;
28+
}
29+
30+
let old_span = self.0.node_id_to_span_map.insert(id, span);
31+
let old_id = self.0.span_to_node_id_map.insert(span, id);
32+
33+
assert!(old_span.is_none(), "id {id:?} already has span {old_span:?} != {span:?}");
34+
// Some spans can show up in multiple nodes, e.g., `impl $trait for $ty`
35+
//assert!(old_id.is_none(), "span {span:?} already has id {old_id:?} != {id:?}");
36+
}
37+
}
38+
39+
impl Visitor<'_> for AstSpanMapper {
40+
fn visit_crate(&mut self, krate: &Crate) {
41+
self.insert_mapping(krate.id, krate.spans.inner_span);
42+
visit::walk_crate(self, krate);
43+
}
44+
45+
fn visit_block(&mut self, block: &Block) {
46+
self.insert_mapping(block.id, block.span);
47+
visit::walk_block(self, block);
48+
}
49+
50+
fn visit_pat(&mut self, pat: &Pat) {
51+
self.insert_mapping(pat.id, pat.span);
52+
visit::walk_pat(self, pat);
53+
}
54+
55+
fn visit_pat_field(&mut self, pf: &PatField) {
56+
self.insert_mapping(pf.id, pf.span);
57+
visit::walk_pat_field(self, pf);
58+
}
59+
60+
fn visit_stmt(&mut self, stmt: &Stmt) {
61+
self.insert_mapping(stmt.id, stmt.span);
62+
visit::walk_stmt(self, stmt);
63+
}
64+
65+
fn visit_local(&mut self, local: &Local) {
66+
self.insert_mapping(local.id, local.span);
67+
visit::walk_local(self, local);
68+
}
69+
70+
fn visit_arm(&mut self, arm: &Arm) {
71+
self.insert_mapping(arm.id, arm.span);
72+
visit::walk_arm(self, arm);
73+
}
74+
75+
fn visit_expr_field(&mut self, ef: &ExprField) {
76+
self.insert_mapping(ef.id, ef.span);
77+
visit::walk_expr_field(self, ef);
78+
}
79+
80+
fn visit_expr(&mut self, expr: &Expr) {
81+
self.insert_mapping(expr.id, expr.span);
82+
visit::walk_expr(self, expr);
83+
}
84+
85+
fn visit_assoc_constraint(&mut self, ac: &AssocConstraint) {
86+
self.insert_mapping(ac.id, ac.span);
87+
visit::walk_assoc_constraint(self, ac);
88+
}
89+
90+
fn visit_ty(&mut self, ty: &Ty) {
91+
self.insert_mapping(ty.id, ty.span);
92+
visit::walk_ty(self, ty);
93+
}
94+
95+
fn visit_param(&mut self, param: &Param) {
96+
self.insert_mapping(param.id, param.span);
97+
visit::walk_param(self, param);
98+
}
99+
100+
fn visit_variant(&mut self, var: &Variant) {
101+
self.insert_mapping(var.id, var.span);
102+
visit::walk_variant(self, var);
103+
}
104+
105+
fn visit_field_def(&mut self, fd: &FieldDef) {
106+
self.insert_mapping(fd.id, fd.span);
107+
visit::walk_field_def(self, fd);
108+
}
109+
110+
fn visit_item(&mut self, i: &Item) {
111+
self.insert_mapping(i.id, i.span);
112+
visit::walk_item(self, i);
113+
}
114+
115+
fn visit_foreign_item(&mut self, i: &ForeignItem) {
116+
self.insert_mapping(i.id, i.span);
117+
visit::walk_foreign_item(self, i);
118+
}
119+
120+
fn visit_assoc_item(&mut self, i: &AssocItem, ctxt: AssocCtxt) {
121+
self.insert_mapping(i.id, i.span);
122+
visit::walk_assoc_item(self, i, ctxt);
123+
}
124+
}

c2rust-refactor/src/command.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ use crate::ast_manip::number_nodes::{
2828
};
2929
use crate::ast_manip::{load_modules, remove_paren, ListNodeIds, MutVisit, Visit};
3030
use crate::ast_manip::{collect_comments, gather_comments, Comment, CommentMap};
31+
use crate::ast_manip::AstSpanMaps;
3132
use crate::collapse::CollapseInfo;
3233
use crate::driver::{self, Phase};
3334
use crate::file_io::FileIO;
@@ -425,6 +426,7 @@ impl RefactorState {
425426
node_id_to_def_id,
426427
def_id_to_node_id,
427428
GenerationalTyCtxt(tcx, tcx_gen.clone()),
429+
AstSpanMaps::new(&expanded),
428430
);
429431
profile_end!("Lower to HIR");
430432

@@ -453,6 +455,7 @@ impl RefactorState {
453455
node_id_to_def_id,
454456
def_id_to_node_id,
455457
GenerationalTyCtxt(tcx, tcx_gen.clone()),
458+
AstSpanMaps::new(&expanded),
456459
);
457460
profile_end!("Compiler Phase 3");
458461

c2rust-refactor/src/context.rs

Lines changed: 79 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use rustc_hir::def_id::{CrateNum, DefId, LocalDefId};
88
use rustc_hir::{self as hir, BodyId, Node, HirId};
99
use rustc_session::Session;
1010
use rustc_session::config::CrateType;
11-
use rustc_middle::hir::map as hir_map;
11+
use rustc_middle::hir::{map as hir_map, nested_filter};
1212
use rustc_middle::ty::subst::InternalSubsts;
1313
use rustc_middle::ty::{FnSig, ParamEnv, PolyFnSig, Ty, TyCtxt, TyKind};
1414
use rustc_errors::{DiagnosticBuilder, Level};
@@ -20,7 +20,7 @@ use rustc_ast::ptr::P;
2020
use rustc_index::vec::IndexVec;
2121
use rustc_span::Span;
2222

23-
use crate::ast_manip::AstEquiv;
23+
use crate::ast_manip::{AstEquiv, AstSpanMaps};
2424
use crate::command::{GenerationalTyCtxt, TyCtxtGeneration};
2525
use crate::ast_manip::util::{namespace, is_export_attr};
2626
use crate::{expect, match_or};
@@ -55,6 +55,57 @@ impl<'a, 'tcx> RefactorCtxt<'a, 'tcx> {
5555
}
5656
}
5757

58+
type SpanToHirMap = FxHashMap<Span, HirId>;
59+
60+
struct SpanToHirMapper<'hir> {
61+
hir_map: hir_map::Map<'hir>,
62+
span_to_hir_map: SpanToHirMap,
63+
}
64+
65+
impl<'hir> hir::intravisit::Visitor<'hir> for SpanToHirMapper<'hir> {
66+
type NestedFilter = nested_filter::OnlyBodies;
67+
68+
fn nested_visit_map(&mut self) -> Self::Map {
69+
self.hir_map
70+
}
71+
72+
fn visit_id(&mut self, id: HirId) {
73+
let span = match self.hir_map.find(id) {
74+
Some(Node::Param(param)) => param.span,
75+
Some(Node::Item(item)) => item.span,
76+
Some(Node::ForeignItem(foreign_item)) => foreign_item.span,
77+
Some(Node::TraitItem(trait_item)) => trait_item.span,
78+
Some(Node::ImplItem(impl_item)) => impl_item.span,
79+
Some(Node::Variant(variant)) => variant.span,
80+
Some(Node::Field(field)) => field.span,
81+
Some(Node::AnonConst(constant)) => self.hir_map.body(constant.body).value.span,
82+
// TODO: Expr only if not Block
83+
Some(Node::Expr(expr)) => expr.span,
84+
Some(Node::Stmt(stmt)) => stmt.span,
85+
// Intentionally skip PathSegment to avoid collisions
86+
// Intentionally skip Ty because we want the actual definitions
87+
Some(Node::TypeBinding(tb)) => tb.span,
88+
// Intentionally skip TraitRef to avoid collisions
89+
Some(Node::Pat(pat)) => pat.span,
90+
Some(Node::Arm(arm)) => arm.span,
91+
Some(Node::Block(block)) => block.span,
92+
Some(Node::Ctor(..)) => self.hir_map.span_with_body(self.hir_map.get_parent_node(id)),
93+
Some(Node::Lifetime(lifetime)) => lifetime.span,
94+
Some(Node::GenericParam(param)) => param.span,
95+
Some(Node::Infer(i)) => i.span,
96+
Some(Node::Local(local)) => local.span,
97+
Some(Node::Crate(item)) => item.spans.inner_span,
98+
_ => return
99+
};
100+
if span.is_dummy() {
101+
return;
102+
}
103+
104+
let old_id = self.span_to_hir_map.insert(span, id);
105+
assert!(old_id.is_none(), "span {span:?} already has id {old_id:?} != {id:?}");
106+
}
107+
}
108+
58109
#[derive(Clone)]
59110
pub struct HirMap<'hir> {
60111
map: hir_map::Map<'hir>,
@@ -65,6 +116,9 @@ pub struct HirMap<'hir> {
65116

66117
node_id_to_def_id: FxHashMap<NodeId, LocalDefId>,
67118
def_id_to_node_id: IndexVec<LocalDefId, NodeId>,
119+
120+
span_to_hir_map: SpanToHirMap,
121+
ast_span_maps: AstSpanMaps,
68122
}
69123

70124
impl<'hir> HirMap<'hir> {
@@ -73,8 +127,16 @@ impl<'hir> HirMap<'hir> {
73127
map: hir_map::Map<'hir>,
74128
node_id_to_def_id: FxHashMap<NodeId, LocalDefId>,
75129
def_id_to_node_id: IndexVec<LocalDefId, NodeId>,
130+
ast_span_maps: AstSpanMaps,
76131
) -> Self {
77-
Self { map, max_node_id, node_id_to_def_id, def_id_to_node_id }
132+
let mut mapper = SpanToHirMapper {
133+
hir_map: map,
134+
span_to_hir_map: Default::default(),
135+
};
136+
map.visit_all_item_likes_in_crate(&mut mapper);
137+
let SpanToHirMapper { span_to_hir_map, .. } = mapper;
138+
139+
Self { map, max_node_id, node_id_to_def_id, def_id_to_node_id, span_to_hir_map, ast_span_maps }
78140
}
79141
}
80142

@@ -611,9 +673,15 @@ impl<'hir> HirMap<'hir> {
611673
if id > self.max_node_id {
612674
None
613675
} else {
614-
self.node_id_to_def_id.get(&id).map(|ldid| {
615-
self.map.local_def_id_to_hir_id(*ldid)
616-
})
676+
if let Some(ldid) = self.node_id_to_def_id.get(&id) {
677+
return Some(self.map.local_def_id_to_hir_id(*ldid));
678+
}
679+
680+
self
681+
.ast_span_maps
682+
.node_id_to_span_map
683+
.get(&id)
684+
.and_then(|span| self.span_to_hir_map.get(&span).copied())
617685
}
618686
}
619687

@@ -643,6 +711,11 @@ impl<'hir> HirMap<'hir> {
643711
}
644712

645713
pub fn hir_to_node_id(&self, id: HirId) -> NodeId {
714+
let span = self.map.span_with_body(id);
715+
if let Some(id) = self.ast_span_maps.span_to_node_id_map.get(&span) {
716+
return *id;
717+
}
718+
646719
self
647720
.map
648721
.opt_local_def_id(id)

c2rust-refactor/src/driver.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ use rustc_span::{FileName, Span, DUMMY_SP};
4242
use rustc_span::edition::Edition;
4343
use rustc_span::def_id::LocalDefId;
4444

45-
use crate::ast_manip::remove_paren;
45+
use crate::ast_manip::{AstSpanMaps, remove_paren};
4646
use crate::command::{GenerationalTyCtxt, RefactorState, Registry};
4747
use crate::file_io::{ArcFileIO, FileIO};
4848
// TODO: don't forget to call span_fix after parsing
@@ -76,8 +76,9 @@ impl<'a, 'tcx: 'a> RefactorCtxt<'a, 'tcx> {
7676
node_id_to_def_id: FxHashMap<NodeId, LocalDefId>,
7777
def_id_to_node_id: IndexVec<LocalDefId, NodeId>,
7878
tcx: GenerationalTyCtxt<'tcx>,
79+
span_maps: AstSpanMaps,
7980
) -> RefactorCtxt<'a, 'tcx> {
80-
RefactorCtxt::new(sess, None, Some(HirMap::new(max_node_id, map, node_id_to_def_id, def_id_to_node_id)), Some(tcx))
81+
RefactorCtxt::new(sess, None, Some(HirMap::new(max_node_id, map, node_id_to_def_id, def_id_to_node_id, span_maps)), Some(tcx))
8182
}
8283
}
8384

0 commit comments

Comments
 (0)