// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. // Decoding metadata from a single crate's metadata #![allow(non_camel_case_types)] use back::svh::Svh; use metadata::cstore::crate_metadata; use metadata::common::*; use metadata::csearch::StaticMethodInfo; use metadata::csearch; use metadata::cstore; use metadata::tydecode::{parse_ty_data, parse_def_id, parse_type_param_def_data, parse_bare_fn_ty_data, parse_trait_ref_data}; use middle::ty::{ImplContainer, TraitContainer}; use middle::ty; use middle::typeck; use middle::astencode::vtable_decoder_helpers; use std::u64; use std::hash; use std::hash::Hash; use std::io; use std::io::extensions::u64_from_be_bytes; use std::option; use std::rc::Rc; use serialize::ebml::reader; use serialize::ebml; use serialize::Decodable; use syntax::ast_map; use syntax::attr; use syntax::parse::token::{IdentInterner, special_idents}; use syntax::parse::token; use syntax::print::pprust; use syntax::ast; use syntax::codemap; use syntax::crateid::CrateId; pub type Cmd<'a> = &'a crate_metadata; // A function that takes a def_id relative to the crate being searched and // returns a def_id relative to the compilation environment, i.e. if we hit a // def_id for an item defined in another crate, somebody needs to figure out // what crate that's in and give us a def_id that makes sense for the current // build. fn lookup_hash<'a>(d: ebml::Doc<'a>, eq_fn: |&[u8]| -> bool, hash: u64) -> Option> { let index = reader::get_doc(d, tag_index); let table = reader::get_doc(index, tag_index_table); let hash_pos = table.start + (hash % 256 * 4) as uint; let pos = u64_from_be_bytes(d.data, hash_pos, 4) as uint; let tagged_doc = reader::doc_at(d.data, pos).unwrap(); let belt = tag_index_buckets_bucket_elt; let mut ret = None; reader::tagged_docs(tagged_doc.doc, belt, |elt| { let pos = u64_from_be_bytes(elt.data, elt.start, 4) as uint; if eq_fn(elt.data.slice(elt.start + 4, elt.end)) { ret = Some(reader::doc_at(d.data, pos).unwrap().doc); false } else { true } }); ret } pub fn maybe_find_item<'a>(item_id: ast::NodeId, items: ebml::Doc<'a>) -> Option> { fn eq_item(bytes: &[u8], item_id: ast::NodeId) -> bool { return u64_from_be_bytes( bytes.slice(0u, 4u), 0u, 4u) as ast::NodeId == item_id; } lookup_hash(items, |a| eq_item(a, item_id), hash::hash(&(item_id as i64))) } fn find_item<'a>(item_id: ast::NodeId, items: ebml::Doc<'a>) -> ebml::Doc<'a> { match maybe_find_item(item_id, items) { None => fail!("lookup_item: id not found: {}", item_id), Some(d) => d } } // Looks up an item in the given metadata and returns an ebml doc pointing // to the item data. fn lookup_item<'a>(item_id: ast::NodeId, data: &'a [u8]) -> ebml::Doc<'a> { let items = reader::get_doc(reader::Doc(data), tag_items); find_item(item_id, items) } #[deriving(Eq)] enum Family { ImmStatic, // c MutStatic, // b Fn, // f UnsafeFn, // u StaticMethod, // F UnsafeStaticMethod, // U Type, // y ForeignType, // T Mod, // m ForeignMod, // n Enum, // t TupleVariant, // v StructVariant, // V Impl, // i Trait, // I Struct, // S PublicField, // g InheritedField // N } fn item_family(item: ebml::Doc) -> Family { let fam = reader::get_doc(item, tag_items_data_item_family); match reader::doc_as_u8(fam) as char { 'c' => ImmStatic, 'b' => MutStatic, 'f' => Fn, 'u' => UnsafeFn, 'F' => StaticMethod, 'U' => UnsafeStaticMethod, 'y' => Type, 'T' => ForeignType, 'm' => Mod, 'n' => ForeignMod, 't' => Enum, 'v' => TupleVariant, 'V' => StructVariant, 'i' => Impl, 'I' => Trait, 'S' => Struct, 'g' => PublicField, 'N' => InheritedField, c => fail!("unexpected family char: {}", c) } } fn item_visibility(item: ebml::Doc) -> ast::Visibility { match reader::maybe_get_doc(item, tag_items_data_item_visibility) { None => ast::Public, Some(visibility_doc) => { match reader::doc_as_u8(visibility_doc) as char { 'y' => ast::Public, 'i' => ast::Inherited, _ => fail!("unknown visibility character") } } } } fn item_sized(item: ebml::Doc) -> ast::Sized { match reader::maybe_get_doc(item, tag_items_data_item_sized) { None => ast::StaticSize, Some(sized_doc) => { match reader::doc_as_u8(sized_doc) as char { 'd' => ast::DynSize, 's' => ast::StaticSize, _ => fail!("unknown sized-ness character") } } } } fn item_method_sort(item: ebml::Doc) -> char { let mut ret = 'r'; reader::tagged_docs(item, tag_item_trait_method_sort, |doc| { ret = doc.as_str_slice()[0] as char; false }); ret } fn item_symbol(item: ebml::Doc) -> ~str { reader::get_doc(item, tag_items_data_item_symbol).as_str() } fn item_parent_item(d: ebml::Doc) -> Option { let mut ret = None; reader::tagged_docs(d, tag_items_data_parent_item, |did| { ret = Some(reader::with_doc_data(did, parse_def_id)); false }); ret } fn item_reqd_and_translated_parent_item(cnum: ast::CrateNum, d: ebml::Doc) -> ast::DefId { let trait_did = item_parent_item(d).expect("item without parent"); ast::DefId { krate: cnum, node: trait_did.node } } fn item_def_id(d: ebml::Doc, cdata: Cmd) -> ast::DefId { let tagdoc = reader::get_doc(d, tag_def_id); return translate_def_id(cdata, reader::with_doc_data(tagdoc, parse_def_id)); } fn get_provided_source(d: ebml::Doc, cdata: Cmd) -> Option { reader::maybe_get_doc(d, tag_item_method_provided_source).map(|doc| { translate_def_id(cdata, reader::with_doc_data(doc, parse_def_id)) }) } fn each_reexport(d: ebml::Doc, f: |ebml::Doc| -> bool) -> bool { reader::tagged_docs(d, tag_items_data_item_reexport, f) } fn variant_disr_val(d: ebml::Doc) -> Option { reader::maybe_get_doc(d, tag_disr_val).and_then(|val_doc| { reader::with_doc_data(val_doc, |data| u64::parse_bytes(data, 10u)) }) } fn doc_type(doc: ebml::Doc, tcx: &ty::ctxt, cdata: Cmd) -> ty::t { let tp = reader::get_doc(doc, tag_items_data_item_type); parse_ty_data(tp.data, cdata.cnum, tp.start, tcx, |_, did| translate_def_id(cdata, did)) } fn doc_method_fty(doc: ebml::Doc, tcx: &ty::ctxt, cdata: Cmd) -> ty::BareFnTy { let tp = reader::get_doc(doc, tag_item_method_fty); parse_bare_fn_ty_data(tp.data, cdata.cnum, tp.start, tcx, |_, did| translate_def_id(cdata, did)) } pub fn item_type(_item_id: ast::DefId, item: ebml::Doc, tcx: &ty::ctxt, cdata: Cmd) -> ty::t { doc_type(item, tcx, cdata) } fn doc_trait_ref(doc: ebml::Doc, tcx: &ty::ctxt, cdata: Cmd) -> ty::TraitRef { parse_trait_ref_data(doc.data, cdata.cnum, doc.start, tcx, |_, did| translate_def_id(cdata, did)) } fn item_trait_ref(doc: ebml::Doc, tcx: &ty::ctxt, cdata: Cmd) -> ty::TraitRef { let tp = reader::get_doc(doc, tag_item_trait_ref); doc_trait_ref(tp, tcx, cdata) } fn item_ty_param_defs(item: ebml::Doc, tcx: &ty::ctxt, cdata: Cmd, tag: uint) -> Rc > { let mut bounds = Vec::new(); reader::tagged_docs(item, tag, |p| { let bd = parse_type_param_def_data( p.data, p.start, cdata.cnum, tcx, |_, did| translate_def_id(cdata, did)); bounds.push(bd); true }); Rc::new(bounds) } fn item_region_param_defs(item_doc: ebml::Doc, cdata: Cmd) -> Rc > { let mut v = Vec::new(); reader::tagged_docs(item_doc, tag_region_param_def, |rp_doc| { let ident_str_doc = reader::get_doc(rp_doc, tag_region_param_def_ident); let ident = item_name(&*token::get_ident_interner(), ident_str_doc); let def_id_doc = reader::get_doc(rp_doc, tag_region_param_def_def_id); let def_id = reader::with_doc_data(def_id_doc, parse_def_id); let def_id = translate_def_id(cdata, def_id); v.push(ty::RegionParameterDef { name: ident.name, def_id: def_id }); true }); Rc::new(v) } fn enum_variant_ids(item: ebml::Doc, cdata: Cmd) -> Vec { let mut ids: Vec = Vec::new(); let v = tag_items_data_item_variant; reader::tagged_docs(item, v, |p| { let ext = reader::with_doc_data(p, parse_def_id); ids.push(ast::DefId { krate: cdata.cnum, node: ext.node }); true }); return ids; } fn item_path(item_doc: ebml::Doc) -> Vec { let path_doc = reader::get_doc(item_doc, tag_path); let len_doc = reader::get_doc(path_doc, tag_path_len); let len = reader::doc_as_u32(len_doc) as uint; let mut result = Vec::with_capacity(len); reader::docs(path_doc, |tag, elt_doc| { if tag == tag_path_elem_mod { let s = elt_doc.as_str_slice(); result.push(ast_map::PathMod(token::intern(s))); } else if tag == tag_path_elem_name { let s = elt_doc.as_str_slice(); result.push(ast_map::PathName(token::intern(s))); } else { // ignore tag_path_len element } true }); result } fn item_name(intr: &IdentInterner, item: ebml::Doc) -> ast::Ident { let name = reader::get_doc(item, tag_paths_data_name); let string = name.as_str_slice(); match intr.find_equiv(&string) { None => token::str_to_ident(string), Some(val) => ast::Ident::new(val as ast::Name), } } fn item_to_def_like(item: ebml::Doc, did: ast::DefId, cnum: ast::CrateNum) -> DefLike { let fam = item_family(item); match fam { ImmStatic => DlDef(ast::DefStatic(did, false)), MutStatic => DlDef(ast::DefStatic(did, true)), Struct => DlDef(ast::DefStruct(did)), UnsafeFn => DlDef(ast::DefFn(did, ast::UnsafeFn)), Fn => DlDef(ast::DefFn(did, ast::NormalFn)), StaticMethod | UnsafeStaticMethod => { let fn_style = if fam == UnsafeStaticMethod { ast::UnsafeFn } else { ast::NormalFn }; // def_static_method carries an optional field of its enclosing // trait or enclosing impl (if this is an inherent static method). // So we need to detect whether this is in a trait or not, which // we do through the mildly hacky way of checking whether there is // a trait_method_sort. let provenance = if reader::maybe_get_doc( item, tag_item_trait_method_sort).is_some() { ast::FromTrait(item_reqd_and_translated_parent_item(cnum, item)) } else { ast::FromImpl(item_reqd_and_translated_parent_item(cnum, item)) }; DlDef(ast::DefStaticMethod(did, provenance, fn_style)) } Type | ForeignType => DlDef(ast::DefTy(did)), Mod => DlDef(ast::DefMod(did)), ForeignMod => DlDef(ast::DefForeignMod(did)), StructVariant => { let enum_did = item_reqd_and_translated_parent_item(cnum, item); DlDef(ast::DefVariant(enum_did, did, true)) } TupleVariant => { let enum_did = item_reqd_and_translated_parent_item(cnum, item); DlDef(ast::DefVariant(enum_did, did, false)) } Trait => DlDef(ast::DefTrait(did)), Enum => DlDef(ast::DefTy(did)), Impl => DlImpl(did), PublicField | InheritedField => DlField, } } pub fn get_trait_def(cdata: Cmd, item_id: ast::NodeId, tcx: &ty::ctxt) -> ty::TraitDef { let item_doc = lookup_item(item_id, cdata.data()); let tp_defs = item_ty_param_defs(item_doc, tcx, cdata, tag_items_data_item_ty_param_bounds); let rp_defs = item_region_param_defs(item_doc, cdata); let sized = item_sized(item_doc); let mut bounds = ty::EmptyBuiltinBounds(); // Collect the builtin bounds from the encoded supertraits. // FIXME(#8559): They should be encoded directly. reader::tagged_docs(item_doc, tag_item_super_trait_ref, |trait_doc| { // NB. Bypasses real supertraits. See get_supertraits() if you wanted them. let trait_ref = doc_trait_ref(trait_doc, tcx, cdata); tcx.lang_items.to_builtin_kind(trait_ref.def_id).map(|bound| { bounds.add(bound); }); true }); // Turn sized into a bound, FIXME(#8559). if sized == ast::StaticSize { tcx.lang_items.to_builtin_kind(tcx.lang_items.sized_trait().unwrap()).map(|bound| { bounds.add(bound); }); } ty::TraitDef { generics: ty::Generics {type_param_defs: tp_defs, region_param_defs: rp_defs}, bounds: bounds, trait_ref: Rc::new(item_trait_ref(item_doc, tcx, cdata)) } } pub fn get_type(cdata: Cmd, id: ast::NodeId, tcx: &ty::ctxt) -> ty::ty_param_bounds_and_ty { let item = lookup_item(id, cdata.data()); let t = item_type(ast::DefId { krate: cdata.cnum, node: id }, item, tcx, cdata); let tp_defs = item_ty_param_defs(item, tcx, cdata, tag_items_data_item_ty_param_bounds); let rp_defs = item_region_param_defs(item, cdata); ty::ty_param_bounds_and_ty { generics: ty::Generics {type_param_defs: tp_defs, region_param_defs: rp_defs}, ty: t } } pub fn get_impl_trait(cdata: Cmd, id: ast::NodeId, tcx: &ty::ctxt) -> Option> { let item_doc = lookup_item(id, cdata.data()); reader::maybe_get_doc(item_doc, tag_item_trait_ref).map(|tp| { Rc::new(doc_trait_ref(tp, tcx, cdata)) }) } pub fn get_impl_vtables(cdata: Cmd, id: ast::NodeId, tcx: &ty::ctxt) -> typeck::impl_res { let item_doc = lookup_item(id, cdata.data()); let vtables_doc = reader::get_doc(item_doc, tag_item_impl_vtables); let mut decoder = reader::Decoder(vtables_doc); typeck::impl_res { trait_vtables: decoder.read_vtable_res(tcx, cdata), self_vtables: decoder.read_vtable_param_res(tcx, cdata) } } pub fn get_symbol(data: &[u8], id: ast::NodeId) -> ~str { return item_symbol(lookup_item(id, data)); } // Something that a name can resolve to. #[deriving(Clone)] pub enum DefLike { DlDef(ast::Def), DlImpl(ast::DefId), DlField } /// Iterates over the language items in the given crate. pub fn each_lang_item(cdata: Cmd, f: |ast::NodeId, uint| -> bool) -> bool { let root = reader::Doc(cdata.data()); let lang_items = reader::get_doc(root, tag_lang_items); reader::tagged_docs(lang_items, tag_lang_items_item, |item_doc| { let id_doc = reader::get_doc(item_doc, tag_lang_items_item_id); let id = reader::doc_as_u32(id_doc) as uint; let node_id_doc = reader::get_doc(item_doc, tag_lang_items_item_node_id); let node_id = reader::doc_as_u32(node_id_doc) as ast::NodeId; f(node_id, id) }) } pub type GetCrateDataCb<'a> = |ast::CrateNum|: 'a -> Rc; fn each_child_of_item_or_crate(intr: Rc, cdata: Cmd, item_doc: ebml::Doc, get_crate_data: GetCrateDataCb, callback: |DefLike, ast::Ident, ast::Visibility|) { // Iterate over all children. let _ = reader::tagged_docs(item_doc, tag_mod_child, |child_info_doc| { let child_def_id = reader::with_doc_data(child_info_doc, parse_def_id); let child_def_id = translate_def_id(cdata, child_def_id); // This item may be in yet another crate if it was the child of a // reexport. let crate_data = if child_def_id.krate == cdata.cnum { None } else { Some(get_crate_data(child_def_id.krate)) }; let crate_data = match crate_data { Some(ref cdata) => &**cdata, None => cdata }; let other_crates_items = reader::get_doc(reader::Doc(crate_data.data()), tag_items); // Get the item. match maybe_find_item(child_def_id.node, other_crates_items) { None => {} Some(child_item_doc) => { // Hand off the item to the callback. let child_name = item_name(&*intr, child_item_doc); let def_like = item_to_def_like(child_item_doc, child_def_id, cdata.cnum); let visibility = item_visibility(child_item_doc); callback(def_like, child_name, visibility); } } true }); // As a special case, iterate over all static methods of // associated implementations too. This is a bit of a botch. // --pcwalton let _ = reader::tagged_docs(item_doc, tag_items_data_item_inherent_impl, |inherent_impl_def_id_doc| { let inherent_impl_def_id = item_def_id(inherent_impl_def_id_doc, cdata); let items = reader::get_doc(reader::Doc(cdata.data()), tag_items); match maybe_find_item(inherent_impl_def_id.node, items) { None => {} Some(inherent_impl_doc) => { let _ = reader::tagged_docs(inherent_impl_doc, tag_item_impl_method, |impl_method_def_id_doc| { let impl_method_def_id = reader::with_doc_data(impl_method_def_id_doc, parse_def_id); let impl_method_def_id = translate_def_id(cdata, impl_method_def_id); match maybe_find_item(impl_method_def_id.node, items) { None => {} Some(impl_method_doc) => { match item_family(impl_method_doc) { StaticMethod | UnsafeStaticMethod => { // Hand off the static method // to the callback. let static_method_name = item_name(&*intr, impl_method_doc); let static_method_def_like = item_to_def_like(impl_method_doc, impl_method_def_id, cdata.cnum); callback(static_method_def_like, static_method_name, item_visibility(impl_method_doc)); } _ => {} } } } true }); } } true }); // Iterate over all reexports. let _ = each_reexport(item_doc, |reexport_doc| { let def_id_doc = reader::get_doc(reexport_doc, tag_items_data_item_reexport_def_id); let child_def_id = reader::with_doc_data(def_id_doc, parse_def_id); let child_def_id = translate_def_id(cdata, child_def_id); let name_doc = reader::get_doc(reexport_doc, tag_items_data_item_reexport_name); let name = name_doc.as_str_slice(); // This reexport may be in yet another crate. let crate_data = if child_def_id.krate == cdata.cnum { None } else { Some(get_crate_data(child_def_id.krate)) }; let crate_data = match crate_data { Some(ref cdata) => &**cdata, None => cdata }; let other_crates_items = reader::get_doc(reader::Doc(crate_data.data()), tag_items); // Get the item. match maybe_find_item(child_def_id.node, other_crates_items) { None => {} Some(child_item_doc) => { // Hand off the item to the callback. let def_like = item_to_def_like(child_item_doc, child_def_id, child_def_id.krate); // These items have a public visibility because they're part of // a public re-export. callback(def_like, token::str_to_ident(name), ast::Public); } } true }); } /// Iterates over each child of the given item. pub fn each_child_of_item(intr: Rc, cdata: Cmd, id: ast::NodeId, get_crate_data: GetCrateDataCb, callback: |DefLike, ast::Ident, ast::Visibility|) { // Find the item. let root_doc = reader::Doc(cdata.data()); let items = reader::get_doc(root_doc, tag_items); let item_doc = match maybe_find_item(id, items) { None => return, Some(item_doc) => item_doc, }; each_child_of_item_or_crate(intr, cdata, item_doc, get_crate_data, callback) } /// Iterates over all the top-level crate items. pub fn each_top_level_item_of_crate(intr: Rc, cdata: Cmd, get_crate_data: GetCrateDataCb, callback: |DefLike, ast::Ident, ast::Visibility|) { let root_doc = reader::Doc(cdata.data()); let misc_info_doc = reader::get_doc(root_doc, tag_misc_info); let crate_items_doc = reader::get_doc(misc_info_doc, tag_misc_info_crate_items); each_child_of_item_or_crate(intr, cdata, crate_items_doc, get_crate_data, callback) } pub fn get_item_path(cdata: Cmd, id: ast::NodeId) -> Vec { item_path(lookup_item(id, cdata.data())) } pub type DecodeInlinedItem<'a> = |cdata: Cmd, tcx: &ty::ctxt, path: Vec, par_doc: ebml::Doc|: 'a -> Result >; pub fn maybe_get_item_ast(cdata: Cmd, tcx: &ty::ctxt, id: ast::NodeId, decode_inlined_item: DecodeInlinedItem) -> csearch::found_ast { debug!("Looking up item: {}", id); let item_doc = lookup_item(id, cdata.data()); let path = Vec::from_slice(item_path(item_doc).init()); match decode_inlined_item(cdata, tcx, path, item_doc) { Ok(ref ii) => csearch::found(*ii), Err(path) => { match item_parent_item(item_doc) { Some(did) => { let did = translate_def_id(cdata, did); let parent_item = lookup_item(did.node, cdata.data()); match decode_inlined_item(cdata, tcx, path, parent_item) { Ok(ref ii) => csearch::found_parent(did, *ii), Err(_) => csearch::not_found } } None => csearch::not_found } } } } pub fn get_enum_variants(intr: Rc, cdata: Cmd, id: ast::NodeId, tcx: &ty::ctxt) -> Vec> { let data = cdata.data(); let items = reader::get_doc(reader::Doc(data), tag_items); let item = find_item(id, items); let mut disr_val = 0; enum_variant_ids(item, cdata).iter().map(|did| { let item = find_item(did.node, items); let ctor_ty = item_type(ast::DefId { krate: cdata.cnum, node: id}, item, tcx, cdata); let name = item_name(&*intr, item); let arg_tys = match ty::get(ctor_ty).sty { ty::ty_bare_fn(ref f) => f.sig.inputs.clone(), _ => Vec::new(), // Nullary enum variant. }; match variant_disr_val(item) { Some(val) => { disr_val = val; } _ => { /* empty */ } } let old_disr_val = disr_val; disr_val += 1; Rc::new(ty::VariantInfo { args: arg_tys, arg_names: None, ctor_ty: ctor_ty, name: name, // I'm not even sure if we encode visibility // for variants -- TEST -- tjc id: *did, disr_val: old_disr_val, vis: ast::Inherited }) }).collect() } fn get_explicit_self(item: ebml::Doc) -> ast::ExplicitSelf_ { fn get_mutability(ch: u8) -> ast::Mutability { match ch as char { 'i' => ast::MutImmutable, 'm' => ast::MutMutable, _ => fail!("unknown mutability character: `{}`", ch as char), } } let explicit_self_doc = reader::get_doc(item, tag_item_trait_method_explicit_self); let string = explicit_self_doc.as_str_slice(); let explicit_self_kind = string[0]; match explicit_self_kind as char { 's' => ast::SelfStatic, 'v' => ast::SelfValue, '~' => ast::SelfUniq, // FIXME(#4846) expl. region '&' => ast::SelfRegion(None, get_mutability(string[1])), _ => fail!("unknown self type code: `{}`", explicit_self_kind as char) } } /// Returns information about the given implementation. pub fn get_impl_methods(cdata: Cmd, impl_id: ast::NodeId) -> Vec { let mut methods = Vec::new(); reader::tagged_docs(lookup_item(impl_id, cdata.data()), tag_item_impl_method, |doc| { let m_did = reader::with_doc_data(doc, parse_def_id); methods.push(translate_def_id(cdata, m_did)); true }); methods } pub fn get_method_name_and_explicit_self( intr: Rc, cdata: Cmd, id: ast::NodeId) -> (ast::Ident, ast::ExplicitSelf_) { let method_doc = lookup_item(id, cdata.data()); let name = item_name(&*intr, method_doc); let explicit_self = get_explicit_self(method_doc); (name, explicit_self) } pub fn get_method(intr: Rc, cdata: Cmd, id: ast::NodeId, tcx: &ty::ctxt) -> ty::Method { let method_doc = lookup_item(id, cdata.data()); let def_id = item_def_id(method_doc, cdata); let container_id = item_reqd_and_translated_parent_item(cdata.cnum, method_doc); let container_doc = lookup_item(container_id.node, cdata.data()); let container = match item_family(container_doc) { Trait => TraitContainer(container_id), _ => ImplContainer(container_id), }; let name = item_name(&*intr, method_doc); let type_param_defs = item_ty_param_defs(method_doc, tcx, cdata, tag_item_method_tps); let rp_defs = item_region_param_defs(method_doc, cdata); let fty = doc_method_fty(method_doc, tcx, cdata); let vis = item_visibility(method_doc); let explicit_self = get_explicit_self(method_doc); let provided_source = get_provided_source(method_doc, cdata); ty::Method::new( name, ty::Generics { type_param_defs: type_param_defs, region_param_defs: rp_defs, }, fty, explicit_self, vis, def_id, container, provided_source ) } pub fn get_trait_method_def_ids(cdata: Cmd, id: ast::NodeId) -> Vec { let data = cdata.data(); let item = lookup_item(id, data); let mut result = Vec::new(); reader::tagged_docs(item, tag_item_trait_method, |mth| { result.push(item_def_id(mth, cdata)); true }); result } pub fn get_item_variances(cdata: Cmd, id: ast::NodeId) -> ty::ItemVariances { let data = cdata.data(); let item_doc = lookup_item(id, data); let variance_doc = reader::get_doc(item_doc, tag_item_variances); let mut decoder = reader::Decoder(variance_doc); Decodable::decode(&mut decoder).unwrap() } pub fn get_provided_trait_methods(intr: Rc, cdata: Cmd, id: ast::NodeId, tcx: &ty::ctxt) -> Vec> { let data = cdata.data(); let item = lookup_item(id, data); let mut result = Vec::new(); reader::tagged_docs(item, tag_item_trait_method, |mth_id| { let did = item_def_id(mth_id, cdata); let mth = lookup_item(did.node, data); if item_method_sort(mth) == 'p' { result.push(Rc::new(get_method(intr.clone(), cdata, did.node, tcx))); } true }); return result; } /// Returns the supertraits of the given trait. pub fn get_supertraits(cdata: Cmd, id: ast::NodeId, tcx: &ty::ctxt) -> Vec> { let mut results = Vec::new(); let item_doc = lookup_item(id, cdata.data()); reader::tagged_docs(item_doc, tag_item_super_trait_ref, |trait_doc| { // NB. Only reads the ones that *aren't* builtin-bounds. See also // get_trait_def() for collecting the builtin bounds. // FIXME(#8559): The builtin bounds shouldn't be encoded in the first place. let trait_ref = doc_trait_ref(trait_doc, tcx, cdata); if tcx.lang_items.to_builtin_kind(trait_ref.def_id).is_none() { results.push(Rc::new(trait_ref)); } true }); return results; } pub fn get_type_name_if_impl(cdata: Cmd, node_id: ast::NodeId) -> Option { let item = lookup_item(node_id, cdata.data()); if item_family(item) != Impl { return None; } let mut ret = None; reader::tagged_docs(item, tag_item_impl_type_basename, |doc| { ret = Some(token::str_to_ident(doc.as_str_slice())); false }); ret } pub fn get_static_methods_if_impl(intr: Rc, cdata: Cmd, node_id: ast::NodeId) -> Option > { let item = lookup_item(node_id, cdata.data()); if item_family(item) != Impl { return None; } // If this impl implements a trait, don't consider it. let ret = reader::tagged_docs(item, tag_item_trait_ref, |_doc| { false }); if !ret { return None } let mut impl_method_ids = Vec::new(); reader::tagged_docs(item, tag_item_impl_method, |impl_method_doc| { impl_method_ids.push(reader::with_doc_data(impl_method_doc, parse_def_id)); true }); let mut static_impl_methods = Vec::new(); for impl_method_id in impl_method_ids.iter() { let impl_method_doc = lookup_item(impl_method_id.node, cdata.data()); let family = item_family(impl_method_doc); match family { StaticMethod | UnsafeStaticMethod => { let fn_style; match item_family(impl_method_doc) { StaticMethod => fn_style = ast::NormalFn, UnsafeStaticMethod => fn_style = ast::UnsafeFn, _ => fail!() } static_impl_methods.push(StaticMethodInfo { ident: item_name(&*intr, impl_method_doc), def_id: item_def_id(impl_method_doc, cdata), fn_style: fn_style, vis: item_visibility(impl_method_doc), }); } _ => {} } } return Some(static_impl_methods); } /// If node_id is the constructor of a tuple struct, retrieve the NodeId of /// the actual type definition, otherwise, return None pub fn get_tuple_struct_definition_if_ctor(cdata: Cmd, node_id: ast::NodeId) -> Option { let item = lookup_item(node_id, cdata.data()); let mut ret = None; reader::tagged_docs(item, tag_items_data_item_is_tuple_struct_ctor, |_| { ret = Some(item_reqd_and_translated_parent_item(cdata.cnum, item)); false }); ret } pub fn get_item_attrs(cdata: Cmd, orig_node_id: ast::NodeId, f: |Vec<@ast::MetaItem> |) { // The attributes for a tuple struct are attached to the definition, not the ctor; // we assume that someone passing in a tuple struct ctor is actually wanting to // look at the definition let node_id = get_tuple_struct_definition_if_ctor(cdata, orig_node_id); let node_id = node_id.map(|x| x.node).unwrap_or(orig_node_id); let item = lookup_item(node_id, cdata.data()); reader::tagged_docs(item, tag_attributes, |attributes| { reader::tagged_docs(attributes, tag_attribute, |attribute| { f(get_meta_items(attribute)); true }); true }); } fn struct_field_family_to_visibility(family: Family) -> ast::Visibility { match family { PublicField => ast::Public, InheritedField => ast::Inherited, _ => fail!() } } pub fn get_struct_fields(intr: Rc, cdata: Cmd, id: ast::NodeId) -> Vec { let data = cdata.data(); let item = lookup_item(id, data); let mut result = Vec::new(); reader::tagged_docs(item, tag_item_field, |an_item| { let f = item_family(an_item); if f == PublicField || f == InheritedField { // FIXME #6993: name should be of type Name, not Ident let name = item_name(&*intr, an_item); let did = item_def_id(an_item, cdata); let tagdoc = reader::get_doc(an_item, tag_item_field_origin); let origin_id = translate_def_id(cdata, reader::with_doc_data(tagdoc, parse_def_id)); result.push(ty::field_ty { name: name.name, id: did, vis: struct_field_family_to_visibility(f), origin: origin_id, }); } true }); reader::tagged_docs(item, tag_item_unnamed_field, |an_item| { let did = item_def_id(an_item, cdata); let tagdoc = reader::get_doc(an_item, tag_item_field_origin); let f = item_family(an_item); let origin_id = translate_def_id(cdata, reader::with_doc_data(tagdoc, parse_def_id)); result.push(ty::field_ty { name: special_idents::unnamed_field.name, id: did, vis: struct_field_family_to_visibility(f), origin: origin_id, }); true }); result } fn get_meta_items(md: ebml::Doc) -> Vec<@ast::MetaItem> { let mut items: Vec<@ast::MetaItem> = Vec::new(); reader::tagged_docs(md, tag_meta_item_word, |meta_item_doc| { let nd = reader::get_doc(meta_item_doc, tag_meta_item_name); let n = token::intern_and_get_ident(nd.as_str_slice()); items.push(attr::mk_word_item(n)); true }); reader::tagged_docs(md, tag_meta_item_name_value, |meta_item_doc| { let nd = reader::get_doc(meta_item_doc, tag_meta_item_name); let vd = reader::get_doc(meta_item_doc, tag_meta_item_value); let n = token::intern_and_get_ident(nd.as_str_slice()); let v = token::intern_and_get_ident(vd.as_str_slice()); // FIXME (#623): Should be able to decode MetaNameValue variants, // but currently the encoder just drops them items.push(attr::mk_name_value_item_str(n, v)); true }); reader::tagged_docs(md, tag_meta_item_list, |meta_item_doc| { let nd = reader::get_doc(meta_item_doc, tag_meta_item_name); let n = token::intern_and_get_ident(nd.as_str_slice()); let subitems = get_meta_items(meta_item_doc); items.push(attr::mk_list_item(n, subitems.move_iter().collect())); true }); return items; } fn get_attributes(md: ebml::Doc) -> Vec { let mut attrs: Vec = Vec::new(); match reader::maybe_get_doc(md, tag_attributes) { option::Some(attrs_d) => { reader::tagged_docs(attrs_d, tag_attribute, |attr_doc| { let meta_items = get_meta_items(attr_doc); // Currently it's only possible to have a single meta item on // an attribute assert_eq!(meta_items.len(), 1u); let meta_item = *meta_items.get(0); attrs.push( codemap::Spanned { node: ast::Attribute_ { style: ast::AttrOuter, value: meta_item, is_sugared_doc: false, }, span: codemap::DUMMY_SP }); true }); } option::None => () } return attrs; } fn list_crate_attributes(md: ebml::Doc, hash: &Svh, out: &mut io::Writer) -> io::IoResult<()> { try!(write!(out, "=Crate Attributes ({})=\n", *hash)); let r = get_attributes(md); for attr in r.iter() { try!(write!(out, "{}\n", pprust::attribute_to_str(attr))); } write!(out, "\n\n") } pub fn get_crate_attributes(data: &[u8]) -> Vec { get_attributes(reader::Doc(data)) } #[deriving(Clone)] pub struct CrateDep { pub cnum: ast::CrateNum, pub crate_id: CrateId, pub hash: Svh, } pub fn get_crate_deps(data: &[u8]) -> Vec { let mut deps: Vec = Vec::new(); let cratedoc = reader::Doc(data); let depsdoc = reader::get_doc(cratedoc, tag_crate_deps); let mut crate_num = 1; fn docstr(doc: ebml::Doc, tag_: uint) -> ~str { let d = reader::get_doc(doc, tag_); d.as_str_slice().to_str() } reader::tagged_docs(depsdoc, tag_crate_dep, |depdoc| { let crate_id = from_str(docstr(depdoc, tag_crate_dep_crateid)).unwrap(); let hash = Svh::new(docstr(depdoc, tag_crate_dep_hash)); deps.push(CrateDep { cnum: crate_num, crate_id: crate_id, hash: hash, }); crate_num += 1; true }); return deps; } fn list_crate_deps(data: &[u8], out: &mut io::Writer) -> io::IoResult<()> { try!(write!(out, "=External Dependencies=\n")); for dep in get_crate_deps(data).iter() { try!(write!(out, "{} {}-{}\n", dep.cnum, dep.crate_id, dep.hash)); } try!(write!(out, "\n")); Ok(()) } pub fn maybe_get_crate_hash(data: &[u8]) -> Option { let cratedoc = reader::Doc(data); reader::maybe_get_doc(cratedoc, tag_crate_hash).map(|doc| { Svh::new(doc.as_str_slice()) }) } pub fn get_crate_hash(data: &[u8]) -> Svh { let cratedoc = reader::Doc(data); let hashdoc = reader::get_doc(cratedoc, tag_crate_hash); Svh::new(hashdoc.as_str_slice()) } pub fn maybe_get_crate_id(data: &[u8]) -> Option { let cratedoc = reader::Doc(data); reader::maybe_get_doc(cratedoc, tag_crate_crateid).map(|doc| { from_str(doc.as_str_slice()).unwrap() }) } pub fn get_crate_triple(data: &[u8]) -> ~str { let cratedoc = reader::Doc(data); let triple_doc = reader::maybe_get_doc(cratedoc, tag_crate_triple); triple_doc.expect("No triple in crate").as_str() } pub fn get_crate_id(data: &[u8]) -> CrateId { let cratedoc = reader::Doc(data); let hashdoc = reader::get_doc(cratedoc, tag_crate_crateid); from_str(hashdoc.as_str_slice()).unwrap() } pub fn list_crate_metadata(bytes: &[u8], out: &mut io::Writer) -> io::IoResult<()> { let hash = get_crate_hash(bytes); let md = reader::Doc(bytes); try!(list_crate_attributes(md, &hash, out)); list_crate_deps(bytes, out) } // Translates a def_id from an external crate to a def_id for the current // compilation environment. We use this when trying to load types from // external crates - if those types further refer to types in other crates // then we must translate the crate number from that encoded in the external // crate to the correct local crate number. pub fn translate_def_id(cdata: Cmd, did: ast::DefId) -> ast::DefId { if did.krate == ast::LOCAL_CRATE { return ast::DefId { krate: cdata.cnum, node: did.node }; } match cdata.cnum_map.find(&did.krate) { Some(&n) => { ast::DefId { krate: n, node: did.node, } } None => fail!("didn't find a crate in the cnum_map") } } pub fn each_impl(cdata: Cmd, callback: |ast::DefId|) { let impls_doc = reader::get_doc(reader::Doc(cdata.data()), tag_impls); let _ = reader::tagged_docs(impls_doc, tag_impls_impl, |impl_doc| { callback(item_def_id(impl_doc, cdata)); true }); } pub fn each_implementation_for_type(cdata: Cmd, id: ast::NodeId, callback: |ast::DefId|) { let item_doc = lookup_item(id, cdata.data()); reader::tagged_docs(item_doc, tag_items_data_item_inherent_impl, |impl_doc| { let implementation_def_id = item_def_id(impl_doc, cdata); callback(implementation_def_id); true }); } pub fn each_implementation_for_trait(cdata: Cmd, id: ast::NodeId, callback: |ast::DefId|) { let item_doc = lookup_item(id, cdata.data()); let _ = reader::tagged_docs(item_doc, tag_items_data_item_extension_impl, |impl_doc| { let implementation_def_id = item_def_id(impl_doc, cdata); callback(implementation_def_id); true }); } pub fn get_trait_of_method(cdata: Cmd, id: ast::NodeId, tcx: &ty::ctxt) -> Option { let item_doc = lookup_item(id, cdata.data()); let parent_item_id = match item_parent_item(item_doc) { None => return None, Some(item_id) => item_id, }; let parent_item_id = translate_def_id(cdata, parent_item_id); let parent_item_doc = lookup_item(parent_item_id.node, cdata.data()); match item_family(parent_item_doc) { Trait => Some(item_def_id(parent_item_doc, cdata)), Impl => { reader::maybe_get_doc(parent_item_doc, tag_item_trait_ref) .map(|_| item_trait_ref(parent_item_doc, tcx, cdata).def_id) } _ => None } } pub fn get_native_libraries(cdata: Cmd) -> Vec<(cstore::NativeLibaryKind, ~str)> { let libraries = reader::get_doc(reader::Doc(cdata.data()), tag_native_libraries); let mut result = Vec::new(); reader::tagged_docs(libraries, tag_native_libraries_lib, |lib_doc| { let kind_doc = reader::get_doc(lib_doc, tag_native_libraries_kind); let name_doc = reader::get_doc(lib_doc, tag_native_libraries_name); let kind: cstore::NativeLibaryKind = FromPrimitive::from_u32(reader::doc_as_u32(kind_doc)).unwrap(); let name = name_doc.as_str(); result.push((kind, name)); true }); return result; } pub fn get_macro_registrar_fn(data: &[u8]) -> Option { reader::maybe_get_doc(reader::Doc(data), tag_macro_registrar_fn) .map(|doc| FromPrimitive::from_u32(reader::doc_as_u32(doc)).unwrap()) } pub fn get_exported_macros(data: &[u8]) -> Vec<~str> { let macros = reader::get_doc(reader::Doc(data), tag_exported_macros); let mut result = Vec::new(); reader::tagged_docs(macros, tag_macro_def, |macro_doc| { result.push(macro_doc.as_str()); true }); result } pub fn get_dylib_dependency_formats(cdata: Cmd) -> Vec<(ast::CrateNum, cstore::LinkagePreference)> { let formats = reader::get_doc(reader::Doc(cdata.data()), tag_dylib_dependency_formats); let mut result = Vec::new(); debug!("found dylib deps: {}", formats.as_str_slice()); for spec in formats.as_str_slice().split(',') { if spec.len() == 0 { continue } let cnum = spec.split(':').nth(0).unwrap(); let link = spec.split(':').nth(1).unwrap(); let cnum = from_str(cnum).unwrap(); let cnum = match cdata.cnum_map.find(&cnum) { Some(&n) => n, None => fail!("didn't find a crate in the cnum_map") }; result.push((cnum, if link == "d" { cstore::RequireDynamic } else { cstore::RequireStatic })); } return result; }