Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add proper parenting to ast_map #26419

Closed
wants to merge 2 commits into from
Closed
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
228 changes: 161 additions & 67 deletions src/librustc/ast_map/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,27 +121,28 @@ pub enum Node<'ast> {
NodeLifetime(&'ast Lifetime),
}

/// Represents an entry and its parent Node ID
/// Represents an entry and its parent NodeID and parent_node NodeID, see
/// get_parent_node for the distinction.
/// The odd layout is to bring down the total size.
#[derive(Copy, Debug)]
enum MapEntry<'ast> {
/// Placeholder for holes in the map.
NotPresent,

/// All the node types, with a parent ID.
EntryItem(NodeId, &'ast Item),
EntryForeignItem(NodeId, &'ast ForeignItem),
EntryTraitItem(NodeId, &'ast TraitItem),
EntryImplItem(NodeId, &'ast ImplItem),
EntryVariant(NodeId, &'ast Variant),
EntryExpr(NodeId, &'ast Expr),
EntryStmt(NodeId, &'ast Stmt),
EntryArg(NodeId, &'ast Pat),
EntryLocal(NodeId, &'ast Pat),
EntryPat(NodeId, &'ast Pat),
EntryBlock(NodeId, &'ast Block),
EntryStructCtor(NodeId, &'ast StructDef),
EntryLifetime(NodeId, &'ast Lifetime),
/// All the node types, with a parent and scope ID.
EntryItem(NodeId, NodeId, &'ast Item),
EntryForeignItem(NodeId, NodeId, &'ast ForeignItem),
EntryTraitItem(NodeId, NodeId, &'ast TraitItem),
EntryImplItem(NodeId, NodeId, &'ast ImplItem),
EntryVariant(NodeId, NodeId, &'ast Variant),
EntryExpr(NodeId, NodeId, &'ast Expr),
EntryStmt(NodeId, NodeId, &'ast Stmt),
EntryArg(NodeId, NodeId, &'ast Pat),
EntryLocal(NodeId, NodeId, &'ast Pat),
EntryPat(NodeId, NodeId, &'ast Pat),
EntryBlock(NodeId, NodeId, &'ast Block),
EntryStructCtor(NodeId, NodeId, &'ast StructDef),
EntryLifetime(NodeId, NodeId, &'ast Lifetime),

/// Roots for node trees.
RootCrate,
Expand All @@ -161,58 +162,77 @@ struct InlinedParent {
}

impl<'ast> MapEntry<'ast> {
fn from_node(p: NodeId, node: Node<'ast>) -> MapEntry<'ast> {
fn from_node(p: NodeId, s: NodeId, node: Node<'ast>) -> MapEntry<'ast> {
match node {
NodeItem(n) => EntryItem(p, n),
NodeForeignItem(n) => EntryForeignItem(p, n),
NodeTraitItem(n) => EntryTraitItem(p, n),
NodeImplItem(n) => EntryImplItem(p, n),
NodeVariant(n) => EntryVariant(p, n),
NodeExpr(n) => EntryExpr(p, n),
NodeStmt(n) => EntryStmt(p, n),
NodeArg(n) => EntryArg(p, n),
NodeLocal(n) => EntryLocal(p, n),
NodePat(n) => EntryPat(p, n),
NodeBlock(n) => EntryBlock(p, n),
NodeStructCtor(n) => EntryStructCtor(p, n),
NodeLifetime(n) => EntryLifetime(p, n)
NodeItem(n) => EntryItem(p, s, n),
NodeForeignItem(n) => EntryForeignItem(p, s, n),
NodeTraitItem(n) => EntryTraitItem(p, s, n),
NodeImplItem(n) => EntryImplItem(p, s, n),
NodeVariant(n) => EntryVariant(p, s, n),
NodeExpr(n) => EntryExpr(p, s, n),
NodeStmt(n) => EntryStmt(p, s, n),
NodeArg(n) => EntryArg(p, s, n),
NodeLocal(n) => EntryLocal(p, s, n),
NodePat(n) => EntryPat(p, s, n),
NodeBlock(n) => EntryBlock(p, s, n),
NodeStructCtor(n) => EntryStructCtor(p, s, n),
NodeLifetime(n) => EntryLifetime(p, s, n)
}
}

fn parent(self) -> Option<NodeId> {
Some(match self {
EntryItem(id, _) => id,
EntryForeignItem(id, _) => id,
EntryTraitItem(id, _) => id,
EntryImplItem(id, _) => id,
EntryVariant(id, _) => id,
EntryExpr(id, _) => id,
EntryStmt(id, _) => id,
EntryArg(id, _) => id,
EntryLocal(id, _) => id,
EntryPat(id, _) => id,
EntryBlock(id, _) => id,
EntryStructCtor(id, _) => id,
EntryLifetime(id, _) => id,
EntryItem(id, _, _) => id,
EntryForeignItem(id, _, _) => id,
EntryTraitItem(id, _, _) => id,
EntryImplItem(id, _, _) => id,
EntryVariant(id, _, _) => id,
EntryExpr(id, _, _) => id,
EntryStmt(id, _, _) => id,
EntryArg(id, _, _) => id,
EntryLocal(id, _, _) => id,
EntryPat(id, _, _) => id,
EntryBlock(id, _, _) => id,
EntryStructCtor(id, _, _) => id,
EntryLifetime(id, _, _) => id,
_ => return None
})
}

fn parent_node(self) -> Option<NodeId> {
Some(match self {
EntryItem(_, id, _) => id,
EntryForeignItem(_, id, _) => id,
EntryTraitItem(_, id, _) => id,
EntryImplItem(_, id, _) => id,
EntryVariant(_, id, _) => id,
EntryExpr(_, id, _) => id,
EntryStmt(_, id, _) => id,
EntryArg(_, id, _) => id,
EntryLocal(_, id, _) => id,
EntryPat(_, id, _) => id,
EntryBlock(_, id, _) => id,
EntryStructCtor(_, id, _) => id,
EntryLifetime(_, id, _) => id,
_ => return None
})
}

fn to_node(self) -> Option<Node<'ast>> {
Some(match self {
EntryItem(_, n) => NodeItem(n),
EntryForeignItem(_, n) => NodeForeignItem(n),
EntryTraitItem(_, n) => NodeTraitItem(n),
EntryImplItem(_, n) => NodeImplItem(n),
EntryVariant(_, n) => NodeVariant(n),
EntryExpr(_, n) => NodeExpr(n),
EntryStmt(_, n) => NodeStmt(n),
EntryArg(_, n) => NodeArg(n),
EntryLocal(_, n) => NodeLocal(n),
EntryPat(_, n) => NodePat(n),
EntryBlock(_, n) => NodeBlock(n),
EntryStructCtor(_, n) => NodeStructCtor(n),
EntryLifetime(_, n) => NodeLifetime(n),
EntryItem(_, _, n) => NodeItem(n),
EntryForeignItem(_, _, n) => NodeForeignItem(n),
EntryTraitItem(_, _, n) => NodeTraitItem(n),
EntryImplItem(_, _, n) => NodeImplItem(n),
EntryVariant(_, _, n) => NodeVariant(n),
EntryExpr(_, _, n) => NodeExpr(n),
EntryStmt(_, _, n) => NodeStmt(n),
EntryArg(_, _, n) => NodeArg(n),
EntryLocal(_, _, n) => NodeLocal(n),
EntryPat(_, _, n) => NodePat(n),
EntryBlock(_, _, n) => NodeBlock(n),
EntryStructCtor(_, _, n) => NodeStructCtor(n),
EntryLifetime(_, _, n) => NodeLifetime(n),
_ => return None
})
}
Expand Down Expand Up @@ -289,6 +309,46 @@ impl<'ast> Map<'ast> {
self.find_entry(id).and_then(|x| x.parent()).unwrap_or(id)
}

/// Similar to get_parent, returns the parent node id or id if there is no
/// parent.
/// This function returns the most direct parent in the AST, whereas get_parent
/// returns the enclosing item. Note that this might not be the actual parent
/// node in the AST - some kinds of nodes are not in the map and these will
/// never appear as the parent_node. So you can always walk the parent_nodes
/// from a node to the root of the ast (unless you get the same id back here
/// that can happen if the id is not in the map itself or is just weird).
pub fn get_parent_node(&self, id: NodeId) -> NodeId {
self.find_entry(id).and_then(|x| x.parent_node()).unwrap_or(id)
}

/// Returns the nearest enclosing scope. A scope is an item or block.
/// FIXME it is not clear to me that all items qualify as scopes - statics
/// and associated types probably shouldn't, for example. Behaviour in this
/// regard should be expected to be highly unstable.
pub fn get_enclosing_scope(&self, id: NodeId) -> Option<NodeId> {
let mut last_id = id;
// Walk up the chain of parents until we find a 'scope'.
loop {
let cur_id = self.get_parent_node(last_id);
if cur_id == last_id {
return None;
}

match self.get(cur_id) {
NodeItem(_) |
NodeForeignItem(_) |
NodeTraitItem(_) |
NodeImplItem(_) |
NodeBlock(_) => {
return Some(cur_id);
}
_ => {}
}

last_id = cur_id;
}
}

pub fn get_parent_did(&self, id: NodeId) -> DefId {
let parent = self.get_parent(id);
match self.find_entry(parent) {
Expand All @@ -301,7 +361,7 @@ impl<'ast> Map<'ast> {
pub fn get_foreign_abi(&self, id: NodeId) -> abi::Abi {
let parent = self.get_parent(id);
let abi = match self.find_entry(parent) {
Some(EntryItem(_, i)) => {
Some(EntryItem(_, _, i)) => {
match i.node {
ItemForeignMod(ref nm) => Some(nm.abi),
_ => None
Expand Down Expand Up @@ -591,11 +651,11 @@ impl<'a, 'ast> Iterator for NodesMatchingSuffix<'a, 'ast> {
}
self.idx += 1;
let (p, name) = match self.map.find_entry(idx) {
Some(EntryItem(p, n)) => (p, n.name()),
Some(EntryForeignItem(p, n))=> (p, n.name()),
Some(EntryTraitItem(p, n)) => (p, n.name()),
Some(EntryImplItem(p, n)) => (p, n.name()),
Some(EntryVariant(p, n)) => (p, n.name()),
Some(EntryItem(p, _, n)) => (p, n.name()),
Some(EntryForeignItem(p, _, n))=> (p, n.name()),
Some(EntryTraitItem(p, _, n)) => (p, n.name()),
Some(EntryImplItem(p, _, n)) => (p, n.name()),
Some(EntryVariant(p, _, n)) => (p, n.name()),
_ => continue,
};
if self.matches_names(p, name) {
Expand Down Expand Up @@ -648,7 +708,8 @@ impl<F: FoldOps> Folder for IdAndSpanUpdater<F> {
struct NodeCollector<'ast> {
map: Vec<MapEntry<'ast>>,
/// The node in which we are currently mapping (an item or a method).
parent: NodeId
parent: NodeId,
parent_node: NodeId,
}

impl<'ast> NodeCollector<'ast> {
Expand All @@ -662,7 +723,7 @@ impl<'ast> NodeCollector<'ast> {
}

fn insert(&mut self, id: NodeId, node: Node<'ast>) {
let entry = MapEntry::from_node(self.parent, node);
let entry = MapEntry::from_node(self.parent, self.parent_node, node);
self.insert_entry(id, entry);
}

Expand All @@ -678,6 +739,8 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
self.insert(i.id, NodeItem(i));
let parent = self.parent;
self.parent = i.id;
let parent_node = self.parent_node;
self.parent_node = i.id;
match i.node {
ItemImpl(_, _, _, _, _, ref impl_items) => {
for ii in impl_items {
Expand Down Expand Up @@ -728,64 +791,93 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
}
visit::walk_item(self, i);
self.parent = parent;
self.parent_node = parent_node;
}

fn visit_trait_item(&mut self, ti: &'ast TraitItem) {
let parent = self.parent;
self.parent = ti.id;
let parent_node = self.parent_node;
self.parent_node = ti.id;
visit::walk_trait_item(self, ti);
self.parent = parent;
self.parent_node = parent_node;
}

fn visit_impl_item(&mut self, ii: &'ast ImplItem) {
let parent = self.parent;
self.parent = ii.id;
let parent_node = self.parent_node;
self.parent_node = ii.id;
visit::walk_impl_item(self, ii);
self.parent = parent;
self.parent_node = parent_node;
}

fn visit_pat(&mut self, pat: &'ast Pat) {
let parent_node = self.parent_node;
self.parent_node = pat.id;
self.insert(pat.id, match pat.node {
// Note: this is at least *potentially* a pattern...
PatIdent(..) => NodeLocal(pat),
_ => NodePat(pat)
});
visit::walk_pat(self, pat);
self.parent_node = parent_node;
}

fn visit_expr(&mut self, expr: &'ast Expr) {
let parent_node = self.parent_node;
self.parent_node = expr.id;
self.insert(expr.id, NodeExpr(expr));
visit::walk_expr(self, expr);
self.parent_node = parent_node;
}

fn visit_stmt(&mut self, stmt: &'ast Stmt) {
self.insert(ast_util::stmt_id(stmt), NodeStmt(stmt));
let id = ast_util::stmt_id(stmt);
let parent_node = self.parent_node;
self.parent_node = id;
self.insert(id, NodeStmt(stmt));
visit::walk_stmt(self, stmt);
self.parent_node = parent_node;
}

fn visit_fn(&mut self, fk: visit::FnKind<'ast>, fd: &'ast FnDecl,
b: &'ast Block, s: Span, _: NodeId) {
b: &'ast Block, s: Span, id: NodeId) {
let parent_node = self.parent_node;
self.parent_node = id;
self.visit_fn_decl(fd);
visit::walk_fn(self, fk, fd, b, s);
self.parent_node = parent_node;
}

fn visit_ty(&mut self, ty: &'ast Ty) {
let parent_node = self.parent_node;
self.parent_node = ty.id;
match ty.node {
TyBareFn(ref fd) => {
self.visit_fn_decl(&*fd.decl);
}
_ => {}
}
visit::walk_ty(self, ty);
self.parent_node = parent_node;
}

fn visit_block(&mut self, block: &'ast Block) {
let parent_node = self.parent_node;
self.parent_node = block.id;
self.insert(block.id, NodeBlock(block));
visit::walk_block(self, block);
self.parent_node = parent_node;
}

fn visit_lifetime_ref(&mut self, lifetime: &'ast Lifetime) {
let parent_node = self.parent_node;
self.parent_node = lifetime.id;
self.insert(lifetime.id, NodeLifetime(lifetime));
self.parent_node = parent_node;
}

fn visit_lifetime_def(&mut self, def: &'ast LifetimeDef) {
Expand All @@ -809,7 +901,8 @@ pub fn map_crate<'ast, F: FoldOps>(forest: &'ast mut Forest, fold_ops: F) -> Map

let mut collector = NodeCollector {
map: vec![],
parent: CRATE_NODE_ID
parent: CRATE_NODE_ID,
parent_node: CRATE_NODE_ID,
};
collector.insert_entry(CRATE_NODE_ID, RootCrate);
visit::walk_crate(&mut collector, &forest.krate);
Expand Down Expand Up @@ -866,7 +959,8 @@ pub fn map_decoded_item<'ast, F: FoldOps>(map: &Map<'ast>,

let mut collector = NodeCollector {
map: mem::replace(&mut *map.map.borrow_mut(), vec![]),
parent: fld.new_id(DUMMY_NODE_ID)
parent: fld.new_id(DUMMY_NODE_ID),
parent_node: fld.new_id(DUMMY_NODE_ID),
};
let ii_parent_id = collector.parent;
collector.insert_entry(ii_parent_id, RootInlinedParent(ii_parent));
Expand Down
Loading