NotFound,
}
+#[derive(Copy, Clone, Debug)]
+pub struct ExternCrate {
+ /// def_id of an `extern crate` in the current crate that caused
+ /// this crate to be loaded; note that there could be multiple
+ /// such ids
+ pub def_id: DefId,
+
+ /// span of the extern crate that caused this to be loaded
+ pub span: Span,
+
+ /// If true, then this crate is the crate named by the extern
+ /// crate referenced above. If false, then this crate is a dep
+ /// of the crate.
+ pub direct: bool,
+
+ /// Number of links to reach the extern crate `def_id`
+ /// declaration; used to select the extern crate with the shortest
+ /// path
+ pub path_len: usize,
+}
+
/// A store of Rust crates, through with their metadata
/// can be accessed.
///
fn repr_attrs(&self, def: DefId) -> Vec<attr::ReprAttr>;
fn item_type(&self, tcx: &TyCtxt<'tcx>, def: DefId)
-> ty::TypeScheme<'tcx>;
- fn item_path(&self, def: DefId) -> Vec<hir_map::PathElem>;
+ fn relative_item_path(&self, def: DefId) -> Vec<hir_map::PathElem>;
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)
fn is_staged_api(&self, cnum: ast::CrateNum) -> bool;
fn is_explicitly_linked(&self, cnum: ast::CrateNum) -> bool;
fn is_allocator(&self, cnum: ast::CrateNum) -> bool;
+ fn extern_crate(&self, cnum: ast::CrateNum) -> Option<ExternCrate>;
fn crate_attrs(&self, cnum: ast::CrateNum) -> Vec<ast::Attribute>;
/// The name of the crate as it is referred to in source code of the current
/// crate.
fn reachable_ids(&self, cnum: ast::CrateNum) -> Vec<DefId>;
// resolve
- fn def_path(&self, def: DefId) -> hir_map::DefPath;
+ fn def_key(&self, def: DefId) -> hir_map::DefKey;
+ fn relative_def_path(&self, def: DefId) -> hir_map::DefPath;
fn variant_kind(&self, def_id: DefId) -> Option<VariantKind>;
fn struct_ctor_def_id(&self, struct_def_id: DefId) -> Option<DefId>;
fn tuple_struct_definition_if_ctor(&self, did: DefId) -> Option<DefId>;
fn repr_attrs(&self, def: DefId) -> Vec<attr::ReprAttr> { unimplemented!() }
fn item_type(&self, tcx: &TyCtxt<'tcx>, def: DefId)
-> ty::TypeScheme<'tcx> { unimplemented!() }
- fn item_path(&self, def: DefId) -> Vec<hir_map::PathElem> { unimplemented!() }
+ fn relative_item_path(&self, def: DefId) -> Vec<hir_map::PathElem> { 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)
fn is_staged_api(&self, cnum: ast::CrateNum) -> bool { unimplemented!() }
fn is_explicitly_linked(&self, cnum: ast::CrateNum) -> bool { unimplemented!() }
fn is_allocator(&self, cnum: ast::CrateNum) -> bool { unimplemented!() }
+ fn extern_crate(&self, cnum: ast::CrateNum) -> Option<ExternCrate> { unimplemented!() }
fn crate_attrs(&self, cnum: ast::CrateNum) -> Vec<ast::Attribute>
{ unimplemented!() }
fn crate_name(&self, cnum: ast::CrateNum) -> InternedString { unimplemented!() }
fn reachable_ids(&self, cnum: ast::CrateNum) -> Vec<DefId> { unimplemented!() }
// resolve
- fn def_path(&self, def: DefId) -> hir_map::DefPath { unimplemented!() }
+ fn def_key(&self, def: DefId) -> hir_map::DefKey { unimplemented!() }
+ fn relative_def_path(&self, def: DefId) -> hir_map::DefPath { unimplemented!() }
fn variant_kind(&self, def_id: DefId) -> Option<VariantKind> { unimplemented!() }
fn struct_ctor_def_id(&self, struct_def_id: DefId) -> Option<DefId>
{ unimplemented!() }
self.with_path(id, |path| ast_map::path_to_string(path))
}
+ /// Returns the `DefPath` of an item. Note that if `id` is not
+ /// local to this crate -- or is inlined into this crate -- the
+ /// result will be a non-local `DefPath`.
pub fn def_path(&self, id: DefId) -> ast_map::DefPath {
if id.is_local() {
self.map.def_path(id)
} else {
- self.sess.cstore.def_path(id)
+ self.sess.cstore.relative_def_path(id)
}
}
if let Some(id) = self.map.as_local_node_id(id) {
self.map.with_path(id, f)
} else {
- f(self.sess.cstore.item_path(id).iter().cloned().chain(LinkedPath::empty()))
+ let mut path: Vec<_>;
+ if let Some(extern_crate) = self.sess.cstore.extern_crate(id.krate) {
+ if !extern_crate.direct {
+ // this comes from some crate that we don't have a direct
+ // path to; we'll settle for just prepending the name of
+ // the crate.
+ path = self.sess.cstore.extern_item_path(id)
+ } else {
+ // start with the path to the extern crate, then
+ // add the relative path to the actual item
+ fn collector(elems: ast_map::PathElems) -> Vec<ast_map::PathElem> {
+ elems.collect()
+ }
+ path = self.with_path(extern_crate.def_id, collector);
+ path.extend(self.sess.cstore.relative_item_path(id));
+ }
+ } else {
+ // if this was injected, just make a path with name of crate
+ path = self.sess.cstore.extern_item_path(id);
+ }
+ f(path.iter().cloned().chain(LinkedPath::empty()))
}
}
use rustc::dep_graph::DepNode;
use rustc::session::{config, Session};
use rustc::session::search_paths::PathKind;
-use rustc::middle::cstore::{CrateStore, validate_crate_name};
+use rustc::middle::cstore::{CrateStore, validate_crate_name, ExternCrate};
use rustc::util::nodemap::FnvHashMap;
use rustc::front::map as hir_map;
use syntax::attr::AttrMetaMethods;
use syntax::errors::FatalError;
use syntax::parse::token::InternedString;
-use syntax::util::small_vector::SmallVector;
use rustc_front::intravisit::Visitor;
use rustc_front::hir;
use log;
let cmeta = Rc::new(cstore::crate_metadata {
name: name.to_string(),
- local_path: RefCell::new(SmallVector::zero()),
- local_def_path: RefCell::new(vec![]),
+ extern_crate: Cell::new(None),
index: decoder::load_index(metadata.as_slice()),
xref_index: decoder::load_xrefs(metadata.as_slice()),
data: metadata,
cnum_map: RefCell::new(cnum_map),
cnum: cnum,
codemap_import_info: RefCell::new(vec![]),
- span: span,
staged_api: staged_api,
explicitly_linked: Cell::new(explicitly_linked),
});
span: Span,
kind: PathKind,
explicitly_linked: bool)
- -> (ast::CrateNum, Rc<cstore::crate_metadata>,
- cstore::CrateSource) {
+ -> (ast::CrateNum, Rc<cstore::crate_metadata>, cstore::CrateSource) {
enum LookupResult {
Previous(ast::CrateNum),
Loaded(loader::Library),
}
}
+ fn update_extern_crate(&mut self,
+ cnum: ast::CrateNum,
+ mut extern_crate: ExternCrate)
+ {
+ let cmeta = self.cstore.get_crate_data(cnum);
+ let old_extern_crate = cmeta.extern_crate.get();
+
+ // Prefer:
+ // - something over nothing (tuple.0);
+ // - direct extern crate to indirect (tuple.1);
+ // - shorter paths to longer (tuple.2).
+ let new_rank = (true, extern_crate.direct, !extern_crate.path_len);
+ let old_rank = match old_extern_crate {
+ None => (false, false, !0),
+ Some(ref c) => (true, c.direct, !c.path_len),
+ };
+
+ if old_rank >= new_rank {
+ return; // no change needed
+ }
+
+ cmeta.extern_crate.set(Some(extern_crate));
+
+ // Propagate the extern crate info to dependencies.
+ extern_crate.direct = false;
+ for &dep_cnum in cmeta.cnum_map.borrow().values() {
+ self.update_extern_crate(dep_cnum, extern_crate);
+ }
+ }
+
// Go through the crate metadata and load any crates that it references
fn resolve_crate_deps(&mut self,
root: &Option<CratePaths>,
- cdata: &[u8], span : Span)
- -> cstore::cnum_map {
+ cdata: &[u8],
+ span : Span)
+ -> cstore::cnum_map {
debug!("resolving deps of external crate");
// The map from crate numbers in the crate we're resolving to local crate
// numbers
decoder::get_crate_deps(cdata).iter().map(|dep| {
debug!("resolving dep crate {} hash: `{}`", dep.name, dep.hash);
let (local_cnum, _, _) = self.resolve_crate(root,
- &dep.name,
- &dep.name,
- Some(&dep.hash),
- span,
- PathKind::Dependency,
- dep.explicitly_linked);
+ &dep.name,
+ &dep.name,
+ Some(&dep.hash),
+ span,
+ PathKind::Dependency,
+ dep.explicitly_linked);
(dep.cnum, local_cnum)
}).collect()
}
match self.creader.extract_crate_info_hir(i) {
Some(info) => {
- let (cnum, cmeta, _) = self.creader.resolve_crate(&None,
- &info.ident,
- &info.name,
- None,
- i.span,
- PathKind::Crate,
- true);
+ let (cnum, _, _) = self.creader.resolve_crate(&None,
+ &info.ident,
+ &info.name,
+ None,
+ i.span,
+ PathKind::Crate,
+ true);
let def_id = self.ast_map.local_def_id(i.id);
- let def_path = self.ast_map.def_path(def_id);
- cmeta.update_local_def_path(def_path);
- self.ast_map.with_path(i.id, |path| {
- cmeta.update_local_path(path)
- });
+
+ let len = self.ast_map.def_path(def_id).data.len();
+
+ self.creader.update_extern_crate(cnum,
+ ExternCrate {
+ def_id: def_id,
+ span: i.span,
+ direct: true,
+ path_len: len,
+ });
self.cstore.add_extern_mod_stmt_cnum(info.id, cnum);
}
None => ()
use encoder;
use loader;
-use middle::cstore::{CrateStore, CrateSource, ChildItem, FoundAst};
+use middle::cstore::{CrateStore, CrateSource, ChildItem, ExternCrate, FoundAst};
use middle::cstore::{NativeLibraryKind, LinkMeta, LinkagePreference};
use middle::def;
use middle::lang_items;
decoder::get_method_arg_names(&cdata, did.index)
}
- fn item_path(&self, def: DefId) -> Vec<hir_map::PathElem> {
+ fn relative_item_path(&self, def: DefId) -> Vec<hir_map::PathElem> {
let cdata = self.get_crate_data(def.krate);
- let path = decoder::get_item_path(&cdata, def.index);
-
- cdata.with_local_path(|cpath| {
- let mut r = Vec::with_capacity(cpath.len() + path.len());
- r.extend_from_slice(cpath);
- r.extend_from_slice(&path);
- r
- })
+ decoder::get_item_path(&cdata, def.index)
}
fn extern_item_path(&self, def: DefId) -> Vec<hir_map::PathElem> {
token::intern_and_get_ident(&self.get_crate_data(cnum).name())
}
+ fn extern_crate(&self, cnum: ast::CrateNum) -> Option<ExternCrate>
+ {
+ self.get_crate_data(cnum).extern_crate.get()
+ }
+
fn crate_hash(&self, cnum: ast::CrateNum) -> Svh
{
let cdata = self.get_crate_data(cnum);
decoder::get_reachable_ids(&cdata)
}
- fn def_path(&self, def: DefId) -> hir_map::DefPath
- {
+ /// Returns the `DefKey` for a given `DefId`. This indicates the
+ /// parent `DefId` as well as some idea of what kind of data the
+ /// `DefId` refers to.
+ fn def_key(&self, def: DefId) -> hir_map::DefKey {
+ let cdata = self.get_crate_data(def.krate);
+ decoder::def_key(&cdata, def.index)
+ }
+
+ fn relative_def_path(&self, def: DefId) -> hir_map::DefPath {
let cdata = self.get_crate_data(def.krate);
- let path = decoder::def_path(&cdata, def.index);
- let local_path = cdata.local_def_path();
- local_path.into_iter().chain(path).collect()
+ decoder::def_path(&cdata, def.index)
}
fn variant_kind(&self, def_id: DefId) -> Option<VariantKind> {
use loader;
use rustc::back::svh::Svh;
-use rustc::front::map as ast_map;
+use rustc::middle::cstore::{ExternCrate};
use rustc::util::nodemap::{FnvHashMap, NodeMap, NodeSet};
use std::cell::{RefCell, Ref, Cell};
use syntax::ast;
use syntax::attr;
use syntax::codemap;
-use syntax::parse::token;
use syntax::parse::token::IdentInterner;
-use syntax::util::small_vector::SmallVector;
pub use middle::cstore::{NativeLibraryKind, LinkagePreference};
pub use middle::cstore::{NativeStatic, NativeFramework, NativeUnknown};
pub struct crate_metadata {
pub name: String,
- pub local_path: RefCell<SmallVector<ast_map::PathElem>>,
- pub local_def_path: RefCell<ast_map::DefPath>,
+
+ /// Information about the extern crate that caused this crate to
+ /// be loaded. If this is `None`, then the crate was injected
+ /// (e.g., by the allocator)
+ pub extern_crate: Cell<Option<ExternCrate>>,
+
pub data: MetadataBlob,
pub cnum_map: RefCell<cnum_map>,
pub cnum: ast::CrateNum,
pub codemap_import_info: RefCell<Vec<ImportedFileMap>>,
- pub span: codemap::Span,
pub staged_api: bool,
pub index: index::Index,
}
}
- pub fn with_local_path<T, F>(&self, f: F) -> T
- where F: Fn(&[ast_map::PathElem]) -> T
- {
- let cpath = self.local_path.borrow();
- if cpath.is_empty() {
- let name = ast_map::PathMod(token::intern(&self.name));
- f(&[name])
- } else {
- f(cpath.as_slice())
- }
- }
-
- pub fn update_local_path<'a, 'b>(&self, candidate: ast_map::PathElems<'a, 'b>) {
- let mut cpath = self.local_path.borrow_mut();
- let cap = cpath.len();
- match cap {
- 0 => *cpath = candidate.collect(),
- 1 => (),
- _ => {
- let candidate: SmallVector<_> = candidate.collect();
- if candidate.len() < cap {
- *cpath = candidate;
- }
- },
- }
- }
-
- pub fn local_def_path(&self) -> ast_map::DefPath {
- let local_def_path = self.local_def_path.borrow();
- if local_def_path.is_empty() {
- let name = ast_map::DefPathData::DetachedCrate(token::intern(&self.name));
- vec![ast_map::DisambiguatedDefPathData { data: name, disambiguator: 0 }]
- } else {
- local_def_path.clone()
- }
- }
-
- pub fn update_local_def_path(&self, candidate: ast_map::DefPath) {
- let mut local_def_path = self.local_def_path.borrow_mut();
- if local_def_path.is_empty() || candidate.len() < local_def_path.len() {
- *local_def_path = candidate;
- }
- }
-
pub fn is_allocator(&self) -> bool {
let attrs = decoder::get_crate_attributes(self.data());
attr::contains_name(&attrs, "allocator")
.parse_closure_ty()
}
-fn def_key(item_doc: rbml::Doc) -> hir_map::DefKey {
+pub fn def_key(cdata: Cmd, id: DefIndex) -> hir_map::DefKey {
+ debug!("def_key: id={:?}", id);
+ let item_doc = cdata.lookup_item(id);
match reader::maybe_get_doc(item_doc, tag_def_key) {
Some(def_key_doc) => {
let mut decoder = reader::Decoder::new(def_key_doc);