Add method `visible_item_path` to `CStore`

This commit is contained in:
Jeffrey Seyfried 2016-03-19 09:01:29 +00:00
parent d5a91e6958
commit 0c6f067961
4 changed files with 111 additions and 6 deletions

View File

@ -32,7 +32,7 @@ use mir::repr::Mir;
use mir::mir_map::MirMap;
use session::Session;
use session::search_paths::PathKind;
use util::nodemap::{FnvHashMap, NodeMap, NodeSet};
use util::nodemap::{FnvHashMap, NodeMap, NodeSet, DefIdMap};
use std::any::Any;
use std::cell::RefCell;
use std::rc::Rc;
@ -169,6 +169,7 @@ pub trait CrateStore<'tcx> : Any {
fn item_type(&self, tcx: &TyCtxt<'tcx>, def: DefId)
-> ty::TypeScheme<'tcx>;
fn relative_item_path(&self, def: DefId) -> Vec<hir_map::PathElem>;
fn visible_parent_map<'a>(&'a self) -> ::std::cell::RefMut<'a, DefIdMap<DefId>>;
fn extern_item_path(&self, def: DefId) -> Vec<hir_map::PathElem>;
fn item_name(&self, def: DefId) -> ast::Name;
fn item_predicates(&self, tcx: &TyCtxt<'tcx>, def: DefId)
@ -347,6 +348,9 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
fn item_type(&self, tcx: &TyCtxt<'tcx>, def: DefId)
-> ty::TypeScheme<'tcx> { unimplemented!() }
fn relative_item_path(&self, def: DefId) -> Vec<hir_map::PathElem> { unimplemented!() }
fn visible_parent_map<'a>(&'a self) -> ::std::cell::RefMut<'a, DefIdMap<DefId>> {
unimplemented!()
}
fn extern_item_path(&self, def: DefId) -> Vec<hir_map::PathElem> { unimplemented!() }
fn item_name(&self, def: DefId) -> ast::Name { unimplemented!() }
fn item_predicates(&self, tcx: &TyCtxt<'tcx>, def: DefId)

View File

@ -10,7 +10,7 @@
use front::map::DefPathData;
use middle::cstore::LOCAL_CRATE;
use middle::def_id::DefId;
use middle::def_id::{DefId, CRATE_DEF_INDEX};
use ty::{self, Ty, TyCtxt};
use syntax::ast;
@ -75,9 +75,51 @@ impl<'tcx> TyCtxt<'tcx> {
}
}
/// If possible, this pushes a global path resolving to `external_def_id` that is visible
/// from at least one local module and returns true. If the crate defining `external_def_id` is
/// declared with an `extern crate`, the path is guarenteed to use the `extern crate`.
pub fn try_push_visible_item_path<T>(&self, buffer: &mut T, external_def_id: DefId) -> bool
where T: ItemPathBuffer
{
let visible_parent_map = self.sess.cstore.visible_parent_map();
let (mut cur_def, mut cur_path) = (external_def_id, Vec::<ast::Name>::new());
loop {
// If `cur_def` is a direct or injected extern crate, push the path to the crate
// followed by the path to the item within the crate and return.
if cur_def.index == CRATE_DEF_INDEX {
match self.sess.cstore.extern_crate(cur_def.krate) {
Some(extern_crate) if extern_crate.direct => {
self.push_item_path(buffer, extern_crate.def_id);
cur_path.iter().rev().map(|segment| buffer.push(&segment.as_str())).count();
return true;
}
None => {
buffer.push(&self.crate_name(cur_def.krate));
cur_path.iter().rev().map(|segment| buffer.push(&segment.as_str())).count();
return true;
}
_ => {},
}
}
cur_path.push(self.sess.cstore.item_name(cur_def));
match visible_parent_map.get(&cur_def) {
Some(&def) => cur_def = def,
None => return false,
};
}
}
pub fn push_item_path<T>(&self, buffer: &mut T, def_id: DefId)
where T: ItemPathBuffer
{
match *buffer.root_mode() {
RootMode::Local if !def_id.is_local() =>
if self.try_push_visible_item_path(buffer, def_id) { return },
_ => {}
}
let key = self.def_key(def_id);
match key.disambiguated_data.data {
DefPathData::CrateRoot => {

View File

@ -13,17 +13,17 @@ use decoder;
use encoder;
use loader;
use middle::cstore::{CrateStore, CrateSource, ChildItem, ExternCrate, FoundAst};
use middle::cstore::{CrateStore, CrateSource, ChildItem, ExternCrate, FoundAst, DefLike};
use middle::cstore::{NativeLibraryKind, LinkMeta, LinkagePreference};
use middle::def;
use middle::lang_items;
use rustc::ty::{self, Ty, TyCtxt, VariantKind};
use middle::def_id::{DefId, DefIndex};
use middle::def_id::{DefId, DefIndex, CRATE_DEF_INDEX};
use rustc::front::map as hir_map;
use rustc::mir::repr::Mir;
use rustc::mir::mir_map::MirMap;
use rustc::util::nodemap::{FnvHashMap, NodeMap, NodeSet};
use rustc::util::nodemap::{FnvHashMap, NodeMap, NodeSet, DefIdMap};
use std::cell::RefCell;
use std::rc::Rc;
@ -544,4 +544,60 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
{
encoder::metadata_encoding_version
}
/// Returns a map from a sufficiently visible external item (i.e. an external item that is
/// visible from at least one local module) to a sufficiently visible parent (considering
/// modules that re-export the external item to be parents).
fn visible_parent_map<'a>(&'a self) -> ::std::cell::RefMut<'a, DefIdMap<DefId>> {
let mut visible_parent_map = self.visible_parent_map.borrow_mut();
if !visible_parent_map.is_empty() { return visible_parent_map; }
use rustc_front::hir;
use rustc::middle::cstore::{CrateStore, ChildItem};
use std::collections::vec_deque::VecDeque;
use std::collections::hash_map::Entry;
for cnum in 1 .. self.next_crate_num() {
let cdata = self.get_crate_data(cnum);
match cdata.extern_crate.get() {
// Ignore crates without a corresponding local `extern crate` item.
Some(extern_crate) if !extern_crate.direct => continue,
_ => {},
}
let mut bfs_queue = &mut VecDeque::new();
let mut add_child = |bfs_queue: &mut VecDeque<_>, child: ChildItem, parent: DefId| {
let child = match child.def {
DefLike::DlDef(def) if child.vis == hir::Public => def.def_id(),
_ => return,
};
match visible_parent_map.entry(child) {
Entry::Occupied(mut entry) => {
// If `child` is defined in crate `cnum`, ensure
// that it is mapped to a parent in `cnum`.
if child.krate == cnum && entry.get().krate != cnum {
entry.insert(parent);
}
}
Entry::Vacant(entry) => {
entry.insert(parent);
bfs_queue.push_back(child);
}
}
};
let croot = DefId { krate: cnum, index: CRATE_DEF_INDEX };
for child in self.crate_top_level_items(cnum) {
add_child(bfs_queue, child, croot);
}
while let Some(def) = bfs_queue.pop_front() {
for child in self.item_children(def) {
add_child(bfs_queue, child, def);
}
}
}
visible_parent_map
}
}

View File

@ -22,7 +22,8 @@ use loader;
use rustc::back::svh::Svh;
use rustc::middle::cstore::{ExternCrate};
use rustc::util::nodemap::{FnvHashMap, NodeMap, NodeSet};
use rustc::util::nodemap::{FnvHashMap, NodeMap, NodeSet, DefIdMap};
use rustc::middle::def_id::DefId;
use std::cell::{RefCell, Ref, Cell};
use std::rc::Rc;
@ -92,6 +93,7 @@ pub struct CStore {
used_link_args: RefCell<Vec<String>>,
statically_included_foreign_items: RefCell<NodeSet>,
pub intr: Rc<IdentInterner>,
pub visible_parent_map: RefCell<DefIdMap<DefId>>,
}
impl CStore {
@ -104,6 +106,7 @@ impl CStore {
used_link_args: RefCell::new(Vec::new()),
intr: intr,
statically_included_foreign_items: RefCell::new(NodeSet()),
visible_parent_map: RefCell::new(FnvHashMap()),
}
}