]> git.lizzy.rs Git - rust.git/blob - src/librustc/metadata/decoder.rs
Auto merge of #28138 - nrc:hir, r=nikomatsakis
[rust.git] / src / librustc / metadata / decoder.rs
1 // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 // Decoding metadata from a single crate's metadata
12
13 #![allow(non_camel_case_types)]
14
15 pub use self::DefLike::*;
16 use self::Family::*;
17
18 use front::map as ast_map;
19 use rustc_front::print::pprust;
20 use rustc_front::hir;
21
22 use back::svh::Svh;
23 use metadata::cstore::crate_metadata;
24 use metadata::common::*;
25 use metadata::csearch::MethodInfo;
26 use metadata::csearch;
27 use metadata::cstore;
28 use metadata::encoder::def_to_u64;
29 use metadata::inline::InlinedItem;
30 use metadata::tydecode::TyDecoder;
31 use middle::def;
32 use middle::def_id::{DefId, LOCAL_CRATE};
33 use middle::lang_items;
34 use middle::subst;
35 use middle::ty::{ImplContainer, TraitContainer};
36 use middle::ty::{self, RegionEscape, Ty};
37 use util::nodemap::FnvHashMap;
38
39 use std::cell::{Cell, RefCell};
40 use std::collections::HashMap;
41 use std::hash::{Hash, SipHasher, Hasher};
42 use std::io::prelude::*;
43 use std::io;
44 use std::rc::Rc;
45 use std::slice::bytes;
46 use std::str;
47
48 use rbml::reader;
49 use rbml;
50 use serialize::Decodable;
51 use rustc_front::attr;
52 use syntax::parse::token::{IdentInterner, special_idents};
53 use syntax::parse::token;
54 use syntax::ast;
55 use syntax::abi;
56 use syntax::codemap;
57 use syntax::ptr::P;
58
59
60 pub type Cmd<'a> = &'a crate_metadata;
61
62 // A function that takes a def_id relative to the crate being searched and
63 // returns a def_id relative to the compilation environment, i.e. if we hit a
64 // def_id for an item defined in another crate, somebody needs to figure out
65 // what crate that's in and give us a def_id that makes sense for the current
66 // build.
67
68 fn u32_from_be_bytes(bytes: &[u8]) -> u32 {
69     let mut b = [0; 4];
70     bytes::copy_memory(&bytes[..4], &mut b);
71     unsafe { (*(b.as_ptr() as *const u32)).to_be() }
72 }
73
74 fn lookup_hash<'a, F>(d: rbml::Doc<'a>, mut eq_fn: F, hash: u64) -> Option<rbml::Doc<'a>> where
75     F: FnMut(&[u8]) -> bool,
76 {
77     let index = reader::get_doc(d, tag_index);
78     let table = reader::get_doc(index, tag_index_table);
79     let hash_pos = table.start + (hash % 256 * 4) as usize;
80     let pos = u32_from_be_bytes(&d.data[hash_pos..]) as usize;
81     let tagged_doc = reader::doc_at(d.data, pos).unwrap();
82
83     reader::tagged_docs(tagged_doc.doc, tag_index_buckets_bucket_elt).find(|elt| {
84         eq_fn(&elt.data[elt.start + 4 .. elt.end])
85     }).map(|elt| {
86         let pos = u32_from_be_bytes(&elt.data[elt.start..]) as usize;
87         reader::doc_at(d.data, pos).unwrap().doc
88     })
89 }
90
91 pub fn maybe_find_item<'a>(item_id: ast::NodeId,
92                            items: rbml::Doc<'a>) -> Option<rbml::Doc<'a>> {
93     fn eq_item(bytes: &[u8], item_id: ast::NodeId) -> bool {
94         u32_from_be_bytes(bytes) == item_id
95     }
96     let mut s = SipHasher::new_with_keys(0, 0);
97     (item_id as i64).hash(&mut s);
98     lookup_hash(items, |a| eq_item(a, item_id), s.finish())
99 }
100
101 fn find_item<'a>(item_id: ast::NodeId, items: rbml::Doc<'a>) -> rbml::Doc<'a> {
102     match maybe_find_item(item_id, items) {
103        None => panic!("lookup_item: id not found: {}", item_id),
104        Some(d) => d
105     }
106 }
107
108 // Looks up an item in the given metadata and returns an rbml doc pointing
109 // to the item data.
110 fn lookup_item<'a>(item_id: ast::NodeId, data: &'a [u8]) -> rbml::Doc<'a> {
111     let items = reader::get_doc(rbml::Doc::new(data), tag_items);
112     find_item(item_id, items)
113 }
114
115 #[derive(Debug, PartialEq)]
116 enum Family {
117     ImmStatic,             // c
118     MutStatic,             // b
119     Fn,                    // f
120     CtorFn,                // o
121     StaticMethod,          // F
122     Method,                // h
123     Type,                  // y
124     Mod,                   // m
125     ForeignMod,            // n
126     Enum,                  // t
127     TupleVariant,          // v
128     StructVariant,         // V
129     Impl,                  // i
130     DefaultImpl,              // d
131     Trait,                 // I
132     Struct,                // S
133     PublicField,           // g
134     InheritedField,        // N
135     Constant,              // C
136 }
137
138 fn item_family(item: rbml::Doc) -> Family {
139     let fam = reader::get_doc(item, tag_items_data_item_family);
140     match reader::doc_as_u8(fam) as char {
141       'C' => Constant,
142       'c' => ImmStatic,
143       'b' => MutStatic,
144       'f' => Fn,
145       'o' => CtorFn,
146       'F' => StaticMethod,
147       'h' => Method,
148       'y' => Type,
149       'm' => Mod,
150       'n' => ForeignMod,
151       't' => Enum,
152       'v' => TupleVariant,
153       'V' => StructVariant,
154       'i' => Impl,
155       'd' => DefaultImpl,
156       'I' => Trait,
157       'S' => Struct,
158       'g' => PublicField,
159       'N' => InheritedField,
160        c => panic!("unexpected family char: {}", c)
161     }
162 }
163
164 fn item_visibility(item: rbml::Doc) -> hir::Visibility {
165     match reader::maybe_get_doc(item, tag_items_data_item_visibility) {
166         None => hir::Public,
167         Some(visibility_doc) => {
168             match reader::doc_as_u8(visibility_doc) as char {
169                 'y' => hir::Public,
170                 'i' => hir::Inherited,
171                 _ => panic!("unknown visibility character")
172             }
173         }
174     }
175 }
176
177 fn fn_constness(item: rbml::Doc) -> hir::Constness {
178     match reader::maybe_get_doc(item, tag_items_data_item_constness) {
179         None => hir::Constness::NotConst,
180         Some(constness_doc) => {
181             match reader::doc_as_u8(constness_doc) as char {
182                 'c' => hir::Constness::Const,
183                 'n' => hir::Constness::NotConst,
184                 _ => panic!("unknown constness character")
185             }
186         }
187     }
188 }
189
190 fn item_sort(item: rbml::Doc) -> Option<char> {
191     reader::tagged_docs(item, tag_item_trait_item_sort).nth(0).map(|doc| {
192         doc.as_str_slice().as_bytes()[0] as char
193     })
194 }
195
196 fn item_symbol(item: rbml::Doc) -> String {
197     reader::get_doc(item, tag_items_data_item_symbol).as_str().to_string()
198 }
199
200 fn translated_def_id(cdata: Cmd, d: rbml::Doc) -> DefId {
201     let id = reader::doc_as_u64(d);
202     let def_id = DefId { krate: (id >> 32) as u32, node: id as u32 };
203     translate_def_id(cdata, def_id)
204 }
205
206 fn item_parent_item(cdata: Cmd, d: rbml::Doc) -> Option<DefId> {
207     reader::tagged_docs(d, tag_items_data_parent_item).nth(0).map(|did| {
208         translated_def_id(cdata, did)
209     })
210 }
211
212 fn item_require_parent_item(cdata: Cmd, d: rbml::Doc) -> DefId {
213     translated_def_id(cdata, reader::get_doc(d, tag_items_data_parent_item))
214 }
215
216 fn item_def_id(d: rbml::Doc, cdata: Cmd) -> DefId {
217     translated_def_id(cdata, reader::get_doc(d, tag_def_id))
218 }
219
220 fn get_provided_source(d: rbml::Doc, cdata: Cmd) -> Option<DefId> {
221     reader::maybe_get_doc(d, tag_item_method_provided_source).map(|doc| {
222         translated_def_id(cdata, doc)
223     })
224 }
225
226 fn reexports<'a>(d: rbml::Doc<'a>) -> reader::TaggedDocsIterator<'a> {
227     reader::tagged_docs(d, tag_items_data_item_reexport)
228 }
229
230 fn variant_disr_val(d: rbml::Doc) -> Option<ty::Disr> {
231     reader::maybe_get_doc(d, tag_disr_val).and_then(|val_doc| {
232         reader::with_doc_data(val_doc, |data| {
233             str::from_utf8(data).ok().and_then(|s| s.parse().ok())
234         })
235     })
236 }
237
238 fn doc_type<'tcx>(doc: rbml::Doc, tcx: &ty::ctxt<'tcx>, cdata: Cmd) -> Ty<'tcx> {
239     let tp = reader::get_doc(doc, tag_items_data_item_type);
240     TyDecoder::with_doc(tcx, cdata.cnum, tp,
241                         &mut |_, did| translate_def_id(cdata, did))
242         .parse_ty()
243 }
244
245 fn maybe_doc_type<'tcx>(doc: rbml::Doc, tcx: &ty::ctxt<'tcx>, cdata: Cmd) -> Option<Ty<'tcx>> {
246     reader::maybe_get_doc(doc, tag_items_data_item_type).map(|tp| {
247         TyDecoder::with_doc(tcx, cdata.cnum, tp,
248                             &mut |_, did| translate_def_id(cdata, did))
249             .parse_ty()
250     })
251 }
252
253 fn doc_method_fty<'tcx>(doc: rbml::Doc, tcx: &ty::ctxt<'tcx>,
254                         cdata: Cmd) -> ty::BareFnTy<'tcx> {
255     let tp = reader::get_doc(doc, tag_item_method_fty);
256     TyDecoder::with_doc(tcx, cdata.cnum, tp,
257                         &mut |_, did| translate_def_id(cdata, did))
258         .parse_bare_fn_ty()
259 }
260
261 pub fn item_type<'tcx>(_item_id: DefId, item: rbml::Doc,
262                        tcx: &ty::ctxt<'tcx>, cdata: Cmd) -> Ty<'tcx> {
263     doc_type(item, tcx, cdata)
264 }
265
266 fn doc_trait_ref<'tcx>(doc: rbml::Doc, tcx: &ty::ctxt<'tcx>, cdata: Cmd)
267                        -> ty::TraitRef<'tcx> {
268     TyDecoder::with_doc(tcx, cdata.cnum, doc,
269                         &mut |_, did| translate_def_id(cdata, did))
270         .parse_trait_ref()
271 }
272
273 fn item_trait_ref<'tcx>(doc: rbml::Doc, tcx: &ty::ctxt<'tcx>, cdata: Cmd)
274                         -> ty::TraitRef<'tcx> {
275     let tp = reader::get_doc(doc, tag_item_trait_ref);
276     doc_trait_ref(tp, tcx, cdata)
277 }
278
279 fn item_path(item_doc: rbml::Doc) -> Vec<ast_map::PathElem> {
280     let path_doc = reader::get_doc(item_doc, tag_path);
281     reader::docs(path_doc).filter_map(|(tag, elt_doc)| {
282         if tag == tag_path_elem_mod {
283             let s = elt_doc.as_str_slice();
284             Some(ast_map::PathMod(token::intern(s)))
285         } else if tag == tag_path_elem_name {
286             let s = elt_doc.as_str_slice();
287             Some(ast_map::PathName(token::intern(s)))
288         } else {
289             // ignore tag_path_len element
290             None
291         }
292     }).collect()
293 }
294
295 fn item_name(intr: &IdentInterner, item: rbml::Doc) -> ast::Name {
296     let name = reader::get_doc(item, tag_paths_data_name);
297     let string = name.as_str_slice();
298     match intr.find(string) {
299         None => token::intern(string),
300         Some(val) => val,
301     }
302 }
303
304 fn item_to_def_like(cdata: Cmd, item: rbml::Doc, did: DefId) -> DefLike {
305     let fam = item_family(item);
306     match fam {
307         Constant  => {
308             // Check whether we have an associated const item.
309             if item_sort(item) == Some('C') {
310                 DlDef(def::DefAssociatedConst(did))
311             } else {
312                 // Regular const item.
313                 DlDef(def::DefConst(did))
314             }
315         }
316         ImmStatic => DlDef(def::DefStatic(did, false)),
317         MutStatic => DlDef(def::DefStatic(did, true)),
318         Struct    => DlDef(def::DefStruct(did)),
319         Fn        => DlDef(def::DefFn(did, false)),
320         CtorFn    => DlDef(def::DefFn(did, true)),
321         Method | StaticMethod => {
322             DlDef(def::DefMethod(did))
323         }
324         Type => {
325             if item_sort(item) == Some('t') {
326                 let trait_did = item_require_parent_item(cdata, item);
327                 DlDef(def::DefAssociatedTy(trait_did, did))
328             } else {
329                 DlDef(def::DefTy(did, false))
330             }
331         }
332         Mod => DlDef(def::DefMod(did)),
333         ForeignMod => DlDef(def::DefForeignMod(did)),
334         StructVariant => {
335             let enum_did = item_require_parent_item(cdata, item);
336             DlDef(def::DefVariant(enum_did, did, true))
337         }
338         TupleVariant => {
339             let enum_did = item_require_parent_item(cdata, item);
340             DlDef(def::DefVariant(enum_did, did, false))
341         }
342         Trait => DlDef(def::DefTrait(did)),
343         Enum => DlDef(def::DefTy(did, true)),
344         Impl | DefaultImpl => DlImpl(did),
345         PublicField | InheritedField => DlField,
346     }
347 }
348
349 fn parse_unsafety(item_doc: rbml::Doc) -> hir::Unsafety {
350     let unsafety_doc = reader::get_doc(item_doc, tag_unsafety);
351     if reader::doc_as_u8(unsafety_doc) != 0 {
352         hir::Unsafety::Unsafe
353     } else {
354         hir::Unsafety::Normal
355     }
356 }
357
358 fn parse_paren_sugar(item_doc: rbml::Doc) -> bool {
359     let paren_sugar_doc = reader::get_doc(item_doc, tag_paren_sugar);
360     reader::doc_as_u8(paren_sugar_doc) != 0
361 }
362
363 fn parse_polarity(item_doc: rbml::Doc) -> hir::ImplPolarity {
364     let polarity_doc = reader::get_doc(item_doc, tag_polarity);
365     if reader::doc_as_u8(polarity_doc) != 0 {
366         hir::ImplPolarity::Negative
367     } else {
368         hir::ImplPolarity::Positive
369     }
370 }
371
372 fn parse_associated_type_names(item_doc: rbml::Doc) -> Vec<ast::Name> {
373     let names_doc = reader::get_doc(item_doc, tag_associated_type_names);
374     reader::tagged_docs(names_doc, tag_associated_type_name)
375         .map(|name_doc| token::intern(name_doc.as_str_slice()))
376         .collect()
377 }
378
379 pub fn get_trait_def<'tcx>(cdata: Cmd,
380                            item_id: ast::NodeId,
381                            tcx: &ty::ctxt<'tcx>) -> ty::TraitDef<'tcx>
382 {
383     let item_doc = lookup_item(item_id, cdata.data());
384     let generics = doc_generics(item_doc, tcx, cdata, tag_item_generics);
385     let unsafety = parse_unsafety(item_doc);
386     let associated_type_names = parse_associated_type_names(item_doc);
387     let paren_sugar = parse_paren_sugar(item_doc);
388
389     ty::TraitDef {
390         paren_sugar: paren_sugar,
391         unsafety: unsafety,
392         generics: generics,
393         trait_ref: item_trait_ref(item_doc, tcx, cdata),
394         associated_type_names: associated_type_names,
395         nonblanket_impls: RefCell::new(FnvHashMap()),
396         blanket_impls: RefCell::new(vec![]),
397         flags: Cell::new(ty::TraitFlags::NO_TRAIT_FLAGS)
398     }
399 }
400
401 pub fn get_adt_def<'tcx>(intr: &IdentInterner,
402                          cdata: Cmd,
403                          item_id: ast::NodeId,
404                          tcx: &ty::ctxt<'tcx>) -> ty::AdtDefMaster<'tcx>
405 {
406     fn get_enum_variants<'tcx>(intr: &IdentInterner,
407                                cdata: Cmd,
408                                doc: rbml::Doc,
409                                tcx: &ty::ctxt<'tcx>) -> Vec<ty::VariantDefData<'tcx, 'tcx>> {
410         let mut disr_val = 0;
411         reader::tagged_docs(doc, tag_items_data_item_variant).map(|p| {
412             let did = translated_def_id(cdata, p);
413             let item = lookup_item(did.node, cdata.data());
414
415             if let Some(disr) = variant_disr_val(item) {
416                 disr_val = disr;
417             }
418             let disr = disr_val;
419             disr_val = disr_val.wrapping_add(1);
420
421             ty::VariantDefData {
422                 did: did,
423                 name: item_name(intr, item),
424                 fields: get_variant_fields(intr, cdata, item, tcx),
425                 disr_val: disr
426             }
427         }).collect()
428     }
429     fn get_variant_fields<'tcx>(intr: &IdentInterner,
430                                 cdata: Cmd,
431                                 doc: rbml::Doc,
432                                 tcx: &ty::ctxt<'tcx>) -> Vec<ty::FieldDefData<'tcx, 'tcx>> {
433         reader::tagged_docs(doc, tag_item_field).map(|f| {
434             let ff = item_family(f);
435             match ff {
436                 PublicField | InheritedField => {},
437                 _ => tcx.sess.bug(&format!("expected field, found {:?}", ff))
438             };
439             ty::FieldDefData::new(item_def_id(f, cdata),
440                                   item_name(intr, f),
441                                   struct_field_family_to_visibility(ff))
442         }).chain(reader::tagged_docs(doc, tag_item_unnamed_field).map(|f| {
443             let ff = item_family(f);
444             ty::FieldDefData::new(item_def_id(f, cdata),
445                                   special_idents::unnamed_field.name,
446                                   struct_field_family_to_visibility(ff))
447         })).collect()
448     }
449     fn get_struct_variant<'tcx>(intr: &IdentInterner,
450                                 cdata: Cmd,
451                                 doc: rbml::Doc,
452                                 did: DefId,
453                                 tcx: &ty::ctxt<'tcx>) -> ty::VariantDefData<'tcx, 'tcx> {
454         ty::VariantDefData {
455             did: did,
456             name: item_name(intr, doc),
457             fields: get_variant_fields(intr, cdata, doc, tcx),
458             disr_val: 0
459         }
460     }
461
462     let doc = lookup_item(item_id, cdata.data());
463     let did = DefId { krate: cdata.cnum, node: item_id };
464     let (kind, variants) = match item_family(doc) {
465         Enum => (ty::AdtKind::Enum,
466                  get_enum_variants(intr, cdata, doc, tcx)),
467         Struct => (ty::AdtKind::Struct,
468                    vec![get_struct_variant(intr, cdata, doc, did, tcx)]),
469         _ => tcx.sess.bug("get_adt_def called on a non-ADT")
470     };
471
472     let adt = tcx.intern_adt_def(did, kind, variants);
473
474     // this needs to be done *after* the variant is interned,
475     // to support recursive structures
476     for variant in &adt.variants {
477         if variant.kind() == ty::VariantKind::Tuple &&
478             adt.adt_kind() == ty::AdtKind::Enum {
479             // tuple-like enum variant fields aren't real items - get the types
480             // from the ctor.
481             debug!("evaluating the ctor-type of {:?}",
482                    variant.name);
483             let ctor_ty = get_type(cdata, variant.did.node, tcx).ty;
484             debug!("evaluating the ctor-type of {:?}.. {:?}",
485                    variant.name,
486                    ctor_ty);
487             let field_tys = match ctor_ty.sty {
488                 ty::TyBareFn(_, &ty::BareFnTy { sig: ty::Binder(ty::FnSig {
489                     ref inputs, ..
490                 }), ..}) => {
491                     // tuple-struct constructors don't have escaping regions
492                     assert!(!inputs.has_escaping_regions());
493                     inputs
494                 },
495                 _ => tcx.sess.bug("tuple-variant ctor is not an ADT")
496             };
497             for (field, &ty) in variant.fields.iter().zip(field_tys.iter()) {
498                 field.fulfill_ty(ty);
499             }
500         } else {
501             for field in &variant.fields {
502                 debug!("evaluating the type of {:?}::{:?}", variant.name, field.name);
503                 let ty = get_type(cdata, field.did.node, tcx).ty;
504                 field.fulfill_ty(ty);
505                 debug!("evaluating the type of {:?}::{:?}: {:?}",
506                        variant.name, field.name, ty);
507             }
508         }
509     }
510
511     adt
512 }
513
514 pub fn get_predicates<'tcx>(cdata: Cmd,
515                             item_id: ast::NodeId,
516                             tcx: &ty::ctxt<'tcx>)
517                             -> ty::GenericPredicates<'tcx>
518 {
519     let item_doc = lookup_item(item_id, cdata.data());
520     doc_predicates(item_doc, tcx, cdata, tag_item_generics)
521 }
522
523 pub fn get_super_predicates<'tcx>(cdata: Cmd,
524                                   item_id: ast::NodeId,
525                                   tcx: &ty::ctxt<'tcx>)
526                                   -> ty::GenericPredicates<'tcx>
527 {
528     let item_doc = lookup_item(item_id, cdata.data());
529     doc_predicates(item_doc, tcx, cdata, tag_item_super_predicates)
530 }
531
532 pub fn get_type<'tcx>(cdata: Cmd, id: ast::NodeId, tcx: &ty::ctxt<'tcx>)
533                       -> ty::TypeScheme<'tcx>
534 {
535     let item_doc = lookup_item(id, cdata.data());
536     let t = item_type(DefId { krate: cdata.cnum, node: id }, item_doc, tcx,
537                       cdata);
538     let generics = doc_generics(item_doc, tcx, cdata, tag_item_generics);
539     ty::TypeScheme {
540         generics: generics,
541         ty: t
542     }
543 }
544
545 pub fn get_stability(cdata: Cmd, id: ast::NodeId) -> Option<attr::Stability> {
546     let item = lookup_item(id, cdata.data());
547     reader::maybe_get_doc(item, tag_items_data_item_stability).map(|doc| {
548         let mut decoder = reader::Decoder::new(doc);
549         Decodable::decode(&mut decoder).unwrap()
550     })
551 }
552
553 pub fn get_repr_attrs(cdata: Cmd, id: ast::NodeId) -> Vec<attr::ReprAttr> {
554     let item = lookup_item(id, cdata.data());
555     match reader::maybe_get_doc(item, tag_items_data_item_repr).map(|doc| {
556         let mut decoder = reader::Decoder::new(doc);
557         Decodable::decode(&mut decoder).unwrap()
558     }) {
559         Some(attrs) => attrs,
560         None => Vec::new(),
561     }
562 }
563
564 pub fn get_impl_polarity<'tcx>(cdata: Cmd,
565                                id: ast::NodeId)
566                                -> Option<hir::ImplPolarity>
567 {
568     let item_doc = lookup_item(id, cdata.data());
569     let fam = item_family(item_doc);
570     match fam {
571         Family::Impl => {
572             Some(parse_polarity(item_doc))
573         }
574         _ => None
575     }
576 }
577
578 pub fn get_custom_coerce_unsized_kind<'tcx>(cdata: Cmd,
579                                             id: ast::NodeId)
580                                             -> Option<ty::CustomCoerceUnsized> {
581     let item_doc = lookup_item(id, cdata.data());
582     reader::maybe_get_doc(item_doc, tag_impl_coerce_unsized_kind).map(|kind_doc| {
583         let mut decoder = reader::Decoder::new(kind_doc);
584         Decodable::decode(&mut decoder).unwrap()
585     })
586 }
587
588 pub fn get_impl_trait<'tcx>(cdata: Cmd,
589                             id: ast::NodeId,
590                             tcx: &ty::ctxt<'tcx>)
591                             -> Option<ty::TraitRef<'tcx>>
592 {
593     let item_doc = lookup_item(id, cdata.data());
594     let fam = item_family(item_doc);
595     match fam {
596         Family::Impl | Family::DefaultImpl => {
597             reader::maybe_get_doc(item_doc, tag_item_trait_ref).map(|tp| {
598                 doc_trait_ref(tp, tcx, cdata)
599             })
600         }
601         _ => None
602     }
603 }
604
605 pub fn get_symbol(data: &[u8], id: ast::NodeId) -> String {
606     return item_symbol(lookup_item(id, data));
607 }
608
609 // Something that a name can resolve to.
610 #[derive(Copy, Clone, Debug)]
611 pub enum DefLike {
612     DlDef(def::Def),
613     DlImpl(DefId),
614     DlField
615 }
616
617 /// Iterates over the language items in the given crate.
618 pub fn each_lang_item<F>(cdata: Cmd, mut f: F) -> bool where
619     F: FnMut(ast::NodeId, usize) -> bool,
620 {
621     let root = rbml::Doc::new(cdata.data());
622     let lang_items = reader::get_doc(root, tag_lang_items);
623     reader::tagged_docs(lang_items, tag_lang_items_item).all(|item_doc| {
624         let id_doc = reader::get_doc(item_doc, tag_lang_items_item_id);
625         let id = reader::doc_as_u32(id_doc) as usize;
626         let node_id_doc = reader::get_doc(item_doc,
627                                           tag_lang_items_item_node_id);
628         let node_id = reader::doc_as_u32(node_id_doc) as ast::NodeId;
629
630         f(node_id, id)
631     })
632 }
633
634 fn each_child_of_item_or_crate<F, G>(intr: Rc<IdentInterner>,
635                                      cdata: Cmd,
636                                      item_doc: rbml::Doc,
637                                      mut get_crate_data: G,
638                                      mut callback: F) where
639     F: FnMut(DefLike, ast::Name, hir::Visibility),
640     G: FnMut(ast::CrateNum) -> Rc<crate_metadata>,
641 {
642     // Iterate over all children.
643     for child_info_doc in reader::tagged_docs(item_doc, tag_mod_child) {
644         let child_def_id = translated_def_id(cdata, child_info_doc);
645
646         // This item may be in yet another crate if it was the child of a
647         // reexport.
648         let crate_data = if child_def_id.krate == cdata.cnum {
649             None
650         } else {
651             Some(get_crate_data(child_def_id.krate))
652         };
653         let crate_data = match crate_data {
654             Some(ref cdata) => &**cdata,
655             None => cdata
656         };
657
658         let other_crates_items = reader::get_doc(rbml::Doc::new(crate_data.data()), tag_items);
659
660         // Get the item.
661         match maybe_find_item(child_def_id.node, other_crates_items) {
662             None => {}
663             Some(child_item_doc) => {
664                 // Hand off the item to the callback.
665                 let child_name = item_name(&*intr, child_item_doc);
666                 let def_like = item_to_def_like(crate_data, child_item_doc, child_def_id);
667                 let visibility = item_visibility(child_item_doc);
668                 callback(def_like, child_name, visibility);
669             }
670         }
671     }
672
673     // As a special case, iterate over all static methods of
674     // associated implementations too. This is a bit of a botch.
675     // --pcwalton
676     for inherent_impl_def_id_doc in reader::tagged_docs(item_doc,
677                                                              tag_items_data_item_inherent_impl) {
678         let inherent_impl_def_id = item_def_id(inherent_impl_def_id_doc, cdata);
679         let items = reader::get_doc(rbml::Doc::new(cdata.data()), tag_items);
680         if let Some(inherent_impl_doc) = maybe_find_item(inherent_impl_def_id.node, items) {
681             for impl_item_def_id_doc in reader::tagged_docs(inherent_impl_doc,
682                                                                  tag_item_impl_item) {
683                 let impl_item_def_id = item_def_id(impl_item_def_id_doc,
684                                                    cdata);
685                 if let Some(impl_method_doc) = maybe_find_item(impl_item_def_id.node, items) {
686                     if let StaticMethod = item_family(impl_method_doc) {
687                         // Hand off the static method to the callback.
688                         let static_method_name = item_name(&*intr, impl_method_doc);
689                         let static_method_def_like = item_to_def_like(cdata, impl_method_doc,
690                                                                       impl_item_def_id);
691                         callback(static_method_def_like,
692                                  static_method_name,
693                                  item_visibility(impl_method_doc));
694                     }
695                 }
696             }
697         }
698     }
699
700     for reexport_doc in reexports(item_doc) {
701         let def_id_doc = reader::get_doc(reexport_doc,
702                                          tag_items_data_item_reexport_def_id);
703         let child_def_id = translated_def_id(cdata, def_id_doc);
704
705         let name_doc = reader::get_doc(reexport_doc,
706                                        tag_items_data_item_reexport_name);
707         let name = name_doc.as_str_slice();
708
709         // This reexport may be in yet another crate.
710         let crate_data = if child_def_id.krate == cdata.cnum {
711             None
712         } else {
713             Some(get_crate_data(child_def_id.krate))
714         };
715         let crate_data = match crate_data {
716             Some(ref cdata) => &**cdata,
717             None => cdata
718         };
719
720         let other_crates_items = reader::get_doc(rbml::Doc::new(crate_data.data()), tag_items);
721
722         // Get the item.
723         if let Some(child_item_doc) = maybe_find_item(child_def_id.node, other_crates_items) {
724             // Hand off the item to the callback.
725             let def_like = item_to_def_like(crate_data, child_item_doc, child_def_id);
726             // These items have a public visibility because they're part of
727             // a public re-export.
728             callback(def_like, token::intern(name), hir::Public);
729         }
730     }
731 }
732
733 /// Iterates over each child of the given item.
734 pub fn each_child_of_item<F, G>(intr: Rc<IdentInterner>,
735                                cdata: Cmd,
736                                id: ast::NodeId,
737                                get_crate_data: G,
738                                callback: F) where
739     F: FnMut(DefLike, ast::Name, hir::Visibility),
740     G: FnMut(ast::CrateNum) -> Rc<crate_metadata>,
741 {
742     // Find the item.
743     let root_doc = rbml::Doc::new(cdata.data());
744     let items = reader::get_doc(root_doc, tag_items);
745     let item_doc = match maybe_find_item(id, items) {
746         None => return,
747         Some(item_doc) => item_doc,
748     };
749
750     each_child_of_item_or_crate(intr,
751                                 cdata,
752                                 item_doc,
753                                 get_crate_data,
754                                 callback)
755 }
756
757 /// Iterates over all the top-level crate items.
758 pub fn each_top_level_item_of_crate<F, G>(intr: Rc<IdentInterner>,
759                                           cdata: Cmd,
760                                           get_crate_data: G,
761                                           callback: F) where
762     F: FnMut(DefLike, ast::Name, hir::Visibility),
763     G: FnMut(ast::CrateNum) -> Rc<crate_metadata>,
764 {
765     let root_doc = rbml::Doc::new(cdata.data());
766     let misc_info_doc = reader::get_doc(root_doc, tag_misc_info);
767     let crate_items_doc = reader::get_doc(misc_info_doc,
768                                           tag_misc_info_crate_items);
769
770     each_child_of_item_or_crate(intr,
771                                 cdata,
772                                 crate_items_doc,
773                                 get_crate_data,
774                                 callback)
775 }
776
777 pub fn get_item_path(cdata: Cmd, id: ast::NodeId) -> Vec<ast_map::PathElem> {
778     item_path(lookup_item(id, cdata.data()))
779 }
780
781 pub fn get_item_name(intr: &IdentInterner, cdata: Cmd, id: ast::NodeId) -> ast::Name {
782     item_name(intr, lookup_item(id, cdata.data()))
783 }
784
785 pub type DecodeInlinedItem<'a> =
786     Box<for<'tcx> FnMut(Cmd,
787                         &ty::ctxt<'tcx>,
788                         Vec<ast_map::PathElem>,
789                         rbml::Doc)
790                         -> Result<&'tcx InlinedItem, Vec<ast_map::PathElem>> + 'a>;
791
792 pub fn maybe_get_item_ast<'tcx>(cdata: Cmd, tcx: &ty::ctxt<'tcx>, id: ast::NodeId,
793                                 mut decode_inlined_item: DecodeInlinedItem)
794                                 -> csearch::FoundAst<'tcx> {
795     debug!("Looking up item: {}", id);
796     let item_doc = lookup_item(id, cdata.data());
797     let path = item_path(item_doc).split_last().unwrap().1.to_vec();
798     match decode_inlined_item(cdata, tcx, path, item_doc) {
799         Ok(ii) => csearch::FoundAst::Found(ii),
800         Err(path) => {
801             match item_parent_item(cdata, item_doc) {
802                 Some(did) => {
803                     let parent_item = lookup_item(did.node, cdata.data());
804                     match decode_inlined_item(cdata, tcx, path, parent_item) {
805                         Ok(ii) => csearch::FoundAst::FoundParent(did, ii),
806                         Err(_) => csearch::FoundAst::NotFound
807                     }
808                 }
809                 None => csearch::FoundAst::NotFound
810             }
811         }
812     }
813 }
814
815 fn get_explicit_self(item: rbml::Doc) -> ty::ExplicitSelfCategory {
816     fn get_mutability(ch: u8) -> hir::Mutability {
817         match ch as char {
818             'i' => hir::MutImmutable,
819             'm' => hir::MutMutable,
820             _ => panic!("unknown mutability character: `{}`", ch as char),
821         }
822     }
823
824     let explicit_self_doc = reader::get_doc(item, tag_item_trait_method_explicit_self);
825     let string = explicit_self_doc.as_str_slice();
826
827     let explicit_self_kind = string.as_bytes()[0];
828     match explicit_self_kind as char {
829         's' => ty::StaticExplicitSelfCategory,
830         'v' => ty::ByValueExplicitSelfCategory,
831         '~' => ty::ByBoxExplicitSelfCategory,
832         // FIXME(#4846) expl. region
833         '&' => {
834             ty::ByReferenceExplicitSelfCategory(
835                 ty::ReEmpty,
836                 get_mutability(string.as_bytes()[1]))
837         }
838         _ => panic!("unknown self type code: `{}`", explicit_self_kind as char)
839     }
840 }
841
842 /// Returns the def IDs of all the items in the given implementation.
843 pub fn get_impl_items(cdata: Cmd, impl_id: ast::NodeId)
844                       -> Vec<ty::ImplOrTraitItemId> {
845     reader::tagged_docs(lookup_item(impl_id, cdata.data()), tag_item_impl_item).map(|doc| {
846         let def_id = item_def_id(doc, cdata);
847         match item_sort(doc) {
848             Some('C') => ty::ConstTraitItemId(def_id),
849             Some('r') | Some('p') => ty::MethodTraitItemId(def_id),
850             Some('t') => ty::TypeTraitItemId(def_id),
851             _ => panic!("unknown impl item sort"),
852         }
853     }).collect()
854 }
855
856 pub fn get_trait_name(intr: Rc<IdentInterner>,
857                       cdata: Cmd,
858                       id: ast::NodeId)
859                       -> ast::Name {
860     let doc = lookup_item(id, cdata.data());
861     item_name(&*intr, doc)
862 }
863
864 pub fn is_static_method(cdata: Cmd, id: ast::NodeId) -> bool {
865     let doc = lookup_item(id, cdata.data());
866     match item_sort(doc) {
867         Some('r') | Some('p') => {
868             get_explicit_self(doc) == ty::StaticExplicitSelfCategory
869         }
870         _ => false
871     }
872 }
873
874 pub fn get_impl_or_trait_item<'tcx>(intr: Rc<IdentInterner>,
875                                     cdata: Cmd,
876                                     id: ast::NodeId,
877                                     tcx: &ty::ctxt<'tcx>)
878                                     -> ty::ImplOrTraitItem<'tcx> {
879     let item_doc = lookup_item(id, cdata.data());
880
881     let def_id = item_def_id(item_doc, cdata);
882
883     let container_id = item_require_parent_item(cdata, item_doc);
884     let container_doc = lookup_item(container_id.node, cdata.data());
885     let container = match item_family(container_doc) {
886         Trait => TraitContainer(container_id),
887         _ => ImplContainer(container_id),
888     };
889
890     let name = item_name(&*intr, item_doc);
891     let vis = item_visibility(item_doc);
892
893     match item_sort(item_doc) {
894         Some('C') => {
895             let ty = doc_type(item_doc, tcx, cdata);
896             let default = get_provided_source(item_doc, cdata);
897             ty::ConstTraitItem(Rc::new(ty::AssociatedConst {
898                 name: name,
899                 ty: ty,
900                 vis: vis,
901                 def_id: def_id,
902                 container: container,
903                 default: default,
904             }))
905         }
906         Some('r') | Some('p') => {
907             let generics = doc_generics(item_doc, tcx, cdata, tag_method_ty_generics);
908             let predicates = doc_predicates(item_doc, tcx, cdata, tag_method_ty_generics);
909             let fty = doc_method_fty(item_doc, tcx, cdata);
910             let explicit_self = get_explicit_self(item_doc);
911             let provided_source = get_provided_source(item_doc, cdata);
912
913             ty::MethodTraitItem(Rc::new(ty::Method::new(name,
914                                                         generics,
915                                                         predicates,
916                                                         fty,
917                                                         explicit_self,
918                                                         vis,
919                                                         def_id,
920                                                         container,
921                                                         provided_source)))
922         }
923         Some('t') => {
924             let ty = maybe_doc_type(item_doc, tcx, cdata);
925             ty::TypeTraitItem(Rc::new(ty::AssociatedType {
926                 name: name,
927                 ty: ty,
928                 vis: vis,
929                 def_id: def_id,
930                 container: container,
931             }))
932         }
933         _ => panic!("unknown impl/trait item sort"),
934     }
935 }
936
937 pub fn get_trait_item_def_ids(cdata: Cmd, id: ast::NodeId)
938                               -> Vec<ty::ImplOrTraitItemId> {
939     let data = cdata.data();
940     let item = lookup_item(id, data);
941     reader::tagged_docs(item, tag_item_trait_item).map(|mth| {
942         let def_id = item_def_id(mth, cdata);
943         match item_sort(mth) {
944             Some('C') => ty::ConstTraitItemId(def_id),
945             Some('r') | Some('p') => ty::MethodTraitItemId(def_id),
946             Some('t') => ty::TypeTraitItemId(def_id),
947             _ => panic!("unknown trait item sort"),
948         }
949     }).collect()
950 }
951
952 pub fn get_item_variances(cdata: Cmd, id: ast::NodeId) -> ty::ItemVariances {
953     let data = cdata.data();
954     let item_doc = lookup_item(id, data);
955     let variance_doc = reader::get_doc(item_doc, tag_item_variances);
956     let mut decoder = reader::Decoder::new(variance_doc);
957     Decodable::decode(&mut decoder).unwrap()
958 }
959
960 pub fn get_provided_trait_methods<'tcx>(intr: Rc<IdentInterner>,
961                                         cdata: Cmd,
962                                         id: ast::NodeId,
963                                         tcx: &ty::ctxt<'tcx>)
964                                         -> Vec<Rc<ty::Method<'tcx>>> {
965     let data = cdata.data();
966     let item = lookup_item(id, data);
967
968     reader::tagged_docs(item, tag_item_trait_item).filter_map(|mth_id| {
969         let did = item_def_id(mth_id, cdata);
970         let mth = lookup_item(did.node, data);
971
972         if item_sort(mth) == Some('p') {
973             let trait_item = get_impl_or_trait_item(intr.clone(),
974                                                     cdata,
975                                                     did.node,
976                                                     tcx);
977             if let ty::MethodTraitItem(ref method) = trait_item {
978                 Some((*method).clone())
979             } else {
980                 None
981             }
982         } else {
983             None
984         }
985     }).collect()
986 }
987
988 pub fn get_associated_consts<'tcx>(intr: Rc<IdentInterner>,
989                                    cdata: Cmd,
990                                    id: ast::NodeId,
991                                    tcx: &ty::ctxt<'tcx>)
992                                    -> Vec<Rc<ty::AssociatedConst<'tcx>>> {
993     let data = cdata.data();
994     let item = lookup_item(id, data);
995
996     [tag_item_trait_item, tag_item_impl_item].iter().flat_map(|&tag| {
997         reader::tagged_docs(item, tag).filter_map(|ac_id| {
998             let did = item_def_id(ac_id, cdata);
999             let ac_doc = lookup_item(did.node, data);
1000
1001             if item_sort(ac_doc) == Some('C') {
1002                 let trait_item = get_impl_or_trait_item(intr.clone(),
1003                                                         cdata,
1004                                                         did.node,
1005                                                         tcx);
1006                 if let ty::ConstTraitItem(ref ac) = trait_item {
1007                     Some((*ac).clone())
1008                 } else {
1009                     None
1010                 }
1011             } else {
1012                 None
1013             }
1014         })
1015     }).collect()
1016 }
1017
1018 pub fn get_type_name_if_impl(cdata: Cmd,
1019                              node_id: ast::NodeId) -> Option<ast::Name> {
1020     let item = lookup_item(node_id, cdata.data());
1021     if item_family(item) != Impl {
1022         return None;
1023     }
1024
1025     reader::tagged_docs(item, tag_item_impl_type_basename).nth(0).map(|doc| {
1026         token::intern(doc.as_str_slice())
1027     })
1028 }
1029
1030 pub fn get_methods_if_impl(intr: Rc<IdentInterner>,
1031                                   cdata: Cmd,
1032                                   node_id: ast::NodeId)
1033                                -> Option<Vec<MethodInfo> > {
1034     let item = lookup_item(node_id, cdata.data());
1035     if item_family(item) != Impl {
1036         return None;
1037     }
1038
1039     // If this impl implements a trait, don't consider it.
1040     if reader::tagged_docs(item, tag_item_trait_ref).next().is_some() {
1041         return None;
1042     }
1043
1044     let impl_method_ids = reader::tagged_docs(item, tag_item_impl_item)
1045         .map(|impl_method_doc| item_def_id(impl_method_doc, cdata));
1046
1047     let mut impl_methods = Vec::new();
1048     for impl_method_id in impl_method_ids {
1049         let impl_method_doc = lookup_item(impl_method_id.node, cdata.data());
1050         let family = item_family(impl_method_doc);
1051         match family {
1052             StaticMethod | Method => {
1053                 impl_methods.push(MethodInfo {
1054                     name: item_name(&*intr, impl_method_doc),
1055                     def_id: item_def_id(impl_method_doc, cdata),
1056                     vis: item_visibility(impl_method_doc),
1057                 });
1058             }
1059             _ => {}
1060         }
1061     }
1062
1063     return Some(impl_methods);
1064 }
1065
1066 /// If node_id is the constructor of a tuple struct, retrieve the NodeId of
1067 /// the actual type definition, otherwise, return None
1068 pub fn get_tuple_struct_definition_if_ctor(cdata: Cmd,
1069                                            node_id: ast::NodeId)
1070     -> Option<DefId>
1071 {
1072     let item = lookup_item(node_id, cdata.data());
1073     reader::tagged_docs(item, tag_items_data_item_is_tuple_struct_ctor).next().map(|_| {
1074         item_require_parent_item(cdata, item)
1075     })
1076 }
1077
1078 pub fn get_item_attrs(cdata: Cmd,
1079                       orig_node_id: ast::NodeId)
1080                       -> Vec<hir::Attribute> {
1081     // The attributes for a tuple struct are attached to the definition, not the ctor;
1082     // we assume that someone passing in a tuple struct ctor is actually wanting to
1083     // look at the definition
1084     let node_id = get_tuple_struct_definition_if_ctor(cdata, orig_node_id);
1085     let node_id = node_id.map(|x| x.node).unwrap_or(orig_node_id);
1086     let item = lookup_item(node_id, cdata.data());
1087     get_attributes(item)
1088 }
1089
1090 pub fn get_struct_field_attrs(cdata: Cmd) -> HashMap<ast::NodeId, Vec<hir::Attribute>> {
1091     let data = rbml::Doc::new(cdata.data());
1092     let fields = reader::get_doc(data, tag_struct_fields);
1093     reader::tagged_docs(fields, tag_struct_field).map(|field| {
1094         let id = reader::doc_as_u32(reader::get_doc(field, tag_struct_field_id));
1095         let attrs = get_attributes(field);
1096         (id, attrs)
1097     }).collect()
1098 }
1099
1100 fn struct_field_family_to_visibility(family: Family) -> hir::Visibility {
1101     match family {
1102       PublicField => hir::Public,
1103       InheritedField => hir::Inherited,
1104       _ => panic!()
1105     }
1106 }
1107
1108 pub fn get_struct_field_names(intr: &IdentInterner, cdata: Cmd, id: ast::NodeId)
1109     -> Vec<ast::Name> {
1110     let data = cdata.data();
1111     let item = lookup_item(id, data);
1112     reader::tagged_docs(item, tag_item_field).map(|an_item| {
1113         item_name(intr, an_item)
1114     }).chain(reader::tagged_docs(item, tag_item_unnamed_field).map(|_| {
1115         special_idents::unnamed_field.name
1116     })).collect()
1117 }
1118
1119 fn get_meta_items(md: rbml::Doc) -> Vec<P<hir::MetaItem>> {
1120     reader::tagged_docs(md, tag_meta_item_word).map(|meta_item_doc| {
1121         let nd = reader::get_doc(meta_item_doc, tag_meta_item_name);
1122         let n = token::intern_and_get_ident(nd.as_str_slice());
1123         attr::mk_word_item(n)
1124     }).chain(reader::tagged_docs(md, tag_meta_item_name_value).map(|meta_item_doc| {
1125         let nd = reader::get_doc(meta_item_doc, tag_meta_item_name);
1126         let vd = reader::get_doc(meta_item_doc, tag_meta_item_value);
1127         let n = token::intern_and_get_ident(nd.as_str_slice());
1128         let v = token::intern_and_get_ident(vd.as_str_slice());
1129         // FIXME (#623): Should be able to decode MetaNameValue variants,
1130         // but currently the encoder just drops them
1131         attr::mk_name_value_item_str(n, v)
1132     })).chain(reader::tagged_docs(md, tag_meta_item_list).map(|meta_item_doc| {
1133         let nd = reader::get_doc(meta_item_doc, tag_meta_item_name);
1134         let n = token::intern_and_get_ident(nd.as_str_slice());
1135         let subitems = get_meta_items(meta_item_doc);
1136         attr::mk_list_item(n, subitems)
1137     })).collect()
1138 }
1139
1140 fn get_attributes(md: rbml::Doc) -> Vec<hir::Attribute> {
1141     match reader::maybe_get_doc(md, tag_attributes) {
1142         Some(attrs_d) => {
1143             reader::tagged_docs(attrs_d, tag_attribute).map(|attr_doc| {
1144                 let is_sugared_doc = reader::doc_as_u8(
1145                     reader::get_doc(attr_doc, tag_attribute_is_sugared_doc)
1146                 ) == 1;
1147                 let meta_items = get_meta_items(attr_doc);
1148                 // Currently it's only possible to have a single meta item on
1149                 // an attribute
1150                 assert_eq!(meta_items.len(), 1);
1151                 let meta_item = meta_items.into_iter().nth(0).unwrap();
1152                 codemap::Spanned {
1153                     node: hir::Attribute_ {
1154                         id: attr::mk_attr_id(),
1155                         style: hir::AttrOuter,
1156                         value: meta_item,
1157                         is_sugared_doc: is_sugared_doc,
1158                     },
1159                     span: codemap::DUMMY_SP
1160                 }
1161             }).collect()
1162         },
1163         None => vec![],
1164     }
1165 }
1166
1167 fn list_crate_attributes(md: rbml::Doc, hash: &Svh,
1168                          out: &mut io::Write) -> io::Result<()> {
1169     try!(write!(out, "=Crate Attributes ({})=\n", *hash));
1170
1171     let r = get_attributes(md);
1172     for attr in &r {
1173         try!(write!(out, "{}\n", pprust::attribute_to_string(attr)));
1174     }
1175
1176     write!(out, "\n\n")
1177 }
1178
1179 pub fn get_crate_attributes(data: &[u8]) -> Vec<hir::Attribute> {
1180     get_attributes(rbml::Doc::new(data))
1181 }
1182
1183 #[derive(Clone)]
1184 pub struct CrateDep {
1185     pub cnum: ast::CrateNum,
1186     pub name: String,
1187     pub hash: Svh,
1188     pub explicitly_linked: bool,
1189 }
1190
1191 pub fn get_crate_deps(data: &[u8]) -> Vec<CrateDep> {
1192     let cratedoc = rbml::Doc::new(data);
1193     let depsdoc = reader::get_doc(cratedoc, tag_crate_deps);
1194
1195     fn docstr(doc: rbml::Doc, tag_: usize) -> String {
1196         let d = reader::get_doc(doc, tag_);
1197         d.as_str_slice().to_string()
1198     }
1199
1200     reader::tagged_docs(depsdoc, tag_crate_dep).enumerate().map(|(crate_num, depdoc)| {
1201         let name = docstr(depdoc, tag_crate_dep_crate_name);
1202         let hash = Svh::new(&docstr(depdoc, tag_crate_dep_hash));
1203         let doc = reader::get_doc(depdoc, tag_crate_dep_explicitly_linked);
1204         let explicitly_linked = reader::doc_as_u8(doc) != 0;
1205         CrateDep {
1206             cnum: crate_num as u32 + 1,
1207             name: name,
1208             hash: hash,
1209             explicitly_linked: explicitly_linked,
1210         }
1211     }).collect()
1212 }
1213
1214 fn list_crate_deps(data: &[u8], out: &mut io::Write) -> io::Result<()> {
1215     try!(write!(out, "=External Dependencies=\n"));
1216     for dep in &get_crate_deps(data) {
1217         try!(write!(out, "{} {}-{}\n", dep.cnum, dep.name, dep.hash));
1218     }
1219     try!(write!(out, "\n"));
1220     Ok(())
1221 }
1222
1223 pub fn maybe_get_crate_hash(data: &[u8]) -> Option<Svh> {
1224     let cratedoc = rbml::Doc::new(data);
1225     reader::maybe_get_doc(cratedoc, tag_crate_hash).map(|doc| {
1226         Svh::new(doc.as_str_slice())
1227     })
1228 }
1229
1230 pub fn get_crate_hash(data: &[u8]) -> Svh {
1231     let cratedoc = rbml::Doc::new(data);
1232     let hashdoc = reader::get_doc(cratedoc, tag_crate_hash);
1233     Svh::new(hashdoc.as_str_slice())
1234 }
1235
1236 pub fn maybe_get_crate_name(data: &[u8]) -> Option<String> {
1237     let cratedoc = rbml::Doc::new(data);
1238     reader::maybe_get_doc(cratedoc, tag_crate_crate_name).map(|doc| {
1239         doc.as_str_slice().to_string()
1240     })
1241 }
1242
1243 pub fn get_crate_triple(data: &[u8]) -> Option<String> {
1244     let cratedoc = rbml::Doc::new(data);
1245     let triple_doc = reader::maybe_get_doc(cratedoc, tag_crate_triple);
1246     triple_doc.map(|s| s.as_str().to_string())
1247 }
1248
1249 pub fn get_crate_name(data: &[u8]) -> String {
1250     maybe_get_crate_name(data).expect("no crate name in crate")
1251 }
1252
1253 pub fn list_crate_metadata(bytes: &[u8], out: &mut io::Write) -> io::Result<()> {
1254     let hash = get_crate_hash(bytes);
1255     let md = rbml::Doc::new(bytes);
1256     try!(list_crate_attributes(md, &hash, out));
1257     list_crate_deps(bytes, out)
1258 }
1259
1260 // Translates a def_id from an external crate to a def_id for the current
1261 // compilation environment. We use this when trying to load types from
1262 // external crates - if those types further refer to types in other crates
1263 // then we must translate the crate number from that encoded in the external
1264 // crate to the correct local crate number.
1265 pub fn translate_def_id(cdata: Cmd, did: DefId) -> DefId {
1266     if did.is_local() {
1267         return DefId { krate: cdata.cnum, node: did.node };
1268     }
1269
1270     match cdata.cnum_map.borrow().get(&did.krate) {
1271         Some(&n) => {
1272             DefId {
1273                 krate: n,
1274                 node: did.node,
1275             }
1276         }
1277         None => panic!("didn't find a crate in the cnum_map")
1278     }
1279 }
1280
1281 // Translate a DefId from the current compilation environment to a DefId
1282 // for an external crate.
1283 fn reverse_translate_def_id(cdata: Cmd, did: DefId) -> Option<DefId> {
1284     if did.krate == cdata.cnum {
1285         return Some(DefId { krate: LOCAL_CRATE, node: did.node });
1286     }
1287
1288     for (&local, &global) in cdata.cnum_map.borrow().iter() {
1289         if global == did.krate {
1290             return Some(DefId { krate: local, node: did.node });
1291         }
1292     }
1293
1294     None
1295 }
1296
1297 pub fn each_inherent_implementation_for_type<F>(cdata: Cmd,
1298                                                 id: ast::NodeId,
1299                                                 mut callback: F)
1300     where F: FnMut(DefId),
1301 {
1302     let item_doc = lookup_item(id, cdata.data());
1303     for impl_doc in reader::tagged_docs(item_doc, tag_items_data_item_inherent_impl) {
1304         if reader::maybe_get_doc(impl_doc, tag_item_trait_ref).is_none() {
1305             callback(item_def_id(impl_doc, cdata));
1306         }
1307     }
1308 }
1309
1310 pub fn each_implementation_for_trait<F>(cdata: Cmd,
1311                                         def_id: DefId,
1312                                         mut callback: F) where
1313     F: FnMut(DefId),
1314 {
1315     if cdata.cnum == def_id.krate {
1316         let item_doc = lookup_item(def_id.node, cdata.data());
1317         for impl_doc in reader::tagged_docs(item_doc, tag_items_data_item_extension_impl) {
1318             callback(item_def_id(impl_doc, cdata));
1319         }
1320         return;
1321     }
1322
1323     // Do a reverse lookup beforehand to avoid touching the crate_num
1324     // hash map in the loop below.
1325     if let Some(crate_local_did) = reverse_translate_def_id(cdata, def_id) {
1326         let def_id_u64 = def_to_u64(crate_local_did);
1327
1328         let impls_doc = reader::get_doc(rbml::Doc::new(cdata.data()), tag_impls);
1329         for impl_doc in reader::tagged_docs(impls_doc, tag_impls_impl) {
1330             let impl_trait = reader::get_doc(impl_doc, tag_impls_impl_trait_def_id);
1331             if reader::doc_as_u64(impl_trait) == def_id_u64 {
1332                 callback(item_def_id(impl_doc, cdata));
1333             }
1334         }
1335     }
1336 }
1337
1338 pub fn get_trait_of_item(cdata: Cmd, id: ast::NodeId, tcx: &ty::ctxt)
1339                          -> Option<DefId> {
1340     let item_doc = lookup_item(id, cdata.data());
1341     let parent_item_id = match item_parent_item(cdata, item_doc) {
1342         None => return None,
1343         Some(item_id) => item_id,
1344     };
1345     let parent_item_doc = lookup_item(parent_item_id.node, cdata.data());
1346     match item_family(parent_item_doc) {
1347         Trait => Some(item_def_id(parent_item_doc, cdata)),
1348         Impl | DefaultImpl => {
1349             reader::maybe_get_doc(parent_item_doc, tag_item_trait_ref)
1350                 .map(|_| item_trait_ref(parent_item_doc, tcx, cdata).def_id)
1351         }
1352         _ => None
1353     }
1354 }
1355
1356
1357 pub fn get_native_libraries(cdata: Cmd)
1358                             -> Vec<(cstore::NativeLibraryKind, String)> {
1359     let libraries = reader::get_doc(rbml::Doc::new(cdata.data()),
1360                                     tag_native_libraries);
1361     reader::tagged_docs(libraries, tag_native_libraries_lib).map(|lib_doc| {
1362         let kind_doc = reader::get_doc(lib_doc, tag_native_libraries_kind);
1363         let name_doc = reader::get_doc(lib_doc, tag_native_libraries_name);
1364         let kind: cstore::NativeLibraryKind =
1365             cstore::NativeLibraryKind::from_u32(reader::doc_as_u32(kind_doc)).unwrap();
1366         let name = name_doc.as_str().to_string();
1367         (kind, name)
1368     }).collect()
1369 }
1370
1371 pub fn get_plugin_registrar_fn(data: &[u8]) -> Option<ast::NodeId> {
1372     reader::maybe_get_doc(rbml::Doc::new(data), tag_plugin_registrar_fn)
1373         .map(|doc| reader::doc_as_u32(doc))
1374 }
1375
1376 pub fn each_exported_macro<F>(data: &[u8], intr: &IdentInterner, mut f: F) where
1377     F: FnMut(ast::Name, Vec<hir::Attribute>, String) -> bool,
1378 {
1379     let macros = reader::get_doc(rbml::Doc::new(data), tag_macro_defs);
1380     for macro_doc in reader::tagged_docs(macros, tag_macro_def) {
1381         let name = item_name(intr, macro_doc);
1382         let attrs = get_attributes(macro_doc);
1383         let body = reader::get_doc(macro_doc, tag_macro_def_body);
1384         if !f(name, attrs, body.as_str().to_string()) {
1385             break;
1386         }
1387     }
1388 }
1389
1390 pub fn get_dylib_dependency_formats(cdata: Cmd)
1391     -> Vec<(ast::CrateNum, cstore::LinkagePreference)>
1392 {
1393     let formats = reader::get_doc(rbml::Doc::new(cdata.data()),
1394                                   tag_dylib_dependency_formats);
1395     let mut result = Vec::new();
1396
1397     debug!("found dylib deps: {}", formats.as_str_slice());
1398     for spec in formats.as_str_slice().split(',') {
1399         if spec.is_empty() { continue }
1400         let cnum = spec.split(':').nth(0).unwrap();
1401         let link = spec.split(':').nth(1).unwrap();
1402         let cnum: ast::CrateNum = cnum.parse().unwrap();
1403         let cnum = match cdata.cnum_map.borrow().get(&cnum) {
1404             Some(&n) => n,
1405             None => panic!("didn't find a crate in the cnum_map")
1406         };
1407         result.push((cnum, if link == "d" {
1408             cstore::RequireDynamic
1409         } else {
1410             cstore::RequireStatic
1411         }));
1412     }
1413     return result;
1414 }
1415
1416 pub fn get_missing_lang_items(cdata: Cmd)
1417     -> Vec<lang_items::LangItem>
1418 {
1419     let items = reader::get_doc(rbml::Doc::new(cdata.data()), tag_lang_items);
1420     reader::tagged_docs(items, tag_lang_items_missing).map(|missing_docs| {
1421         lang_items::LangItem::from_u32(reader::doc_as_u32(missing_docs)).unwrap()
1422     }).collect()
1423 }
1424
1425 pub fn get_method_arg_names(cdata: Cmd, id: ast::NodeId) -> Vec<String> {
1426     let method_doc = lookup_item(id, cdata.data());
1427     match reader::maybe_get_doc(method_doc, tag_method_argument_names) {
1428         Some(args_doc) => {
1429             reader::tagged_docs(args_doc, tag_method_argument_name).map(|name_doc| {
1430                 name_doc.as_str_slice().to_string()
1431             }).collect()
1432         },
1433         None => vec![],
1434     }
1435 }
1436
1437 pub fn get_reachable_ids(cdata: Cmd) -> Vec<DefId> {
1438     let items = reader::get_doc(rbml::Doc::new(cdata.data()),
1439                                 tag_reachable_ids);
1440     reader::tagged_docs(items, tag_reachable_id).map(|doc| {
1441         DefId {
1442             krate: cdata.cnum,
1443             node: reader::doc_as_u32(doc),
1444         }
1445     }).collect()
1446 }
1447
1448 pub fn is_typedef(cdata: Cmd, id: ast::NodeId) -> bool {
1449     let item_doc = lookup_item(id, cdata.data());
1450     match item_family(item_doc) {
1451         Type => true,
1452         _ => false,
1453     }
1454 }
1455
1456 pub fn is_const_fn(cdata: Cmd, id: ast::NodeId) -> bool {
1457     let item_doc = lookup_item(id, cdata.data());
1458     match fn_constness(item_doc) {
1459         hir::Constness::Const => true,
1460         hir::Constness::NotConst => false,
1461     }
1462 }
1463
1464 pub fn is_impl(cdata: Cmd, id: ast::NodeId) -> bool {
1465     let item_doc = lookup_item(id, cdata.data());
1466     match item_family(item_doc) {
1467         Impl => true,
1468         _ => false,
1469     }
1470 }
1471
1472 fn doc_generics<'tcx>(base_doc: rbml::Doc,
1473                       tcx: &ty::ctxt<'tcx>,
1474                       cdata: Cmd,
1475                       tag: usize)
1476                       -> ty::Generics<'tcx>
1477 {
1478     let doc = reader::get_doc(base_doc, tag);
1479
1480     let mut types = subst::VecPerParamSpace::empty();
1481     for p in reader::tagged_docs(doc, tag_type_param_def) {
1482         let bd =
1483             TyDecoder::with_doc(tcx, cdata.cnum, p,
1484                                 &mut |_, did| translate_def_id(cdata, did))
1485             .parse_type_param_def();
1486         types.push(bd.space, bd);
1487     }
1488
1489     let mut regions = subst::VecPerParamSpace::empty();
1490     for rp_doc in reader::tagged_docs(doc, tag_region_param_def) {
1491         let ident_str_doc = reader::get_doc(rp_doc,
1492                                             tag_region_param_def_ident);
1493         let name = item_name(&*token::get_ident_interner(), ident_str_doc);
1494         let def_id_doc = reader::get_doc(rp_doc,
1495                                          tag_region_param_def_def_id);
1496         let def_id = translated_def_id(cdata, def_id_doc);
1497
1498         let doc = reader::get_doc(rp_doc, tag_region_param_def_space);
1499         let space = subst::ParamSpace::from_uint(reader::doc_as_u64(doc) as usize);
1500
1501         let doc = reader::get_doc(rp_doc, tag_region_param_def_index);
1502         let index = reader::doc_as_u64(doc) as u32;
1503
1504         let bounds = reader::tagged_docs(rp_doc, tag_items_data_region).map(|p| {
1505             TyDecoder::with_doc(tcx, cdata.cnum, p,
1506                                 &mut |_, did| translate_def_id(cdata, did))
1507             .parse_region()
1508         }).collect();
1509
1510         regions.push(space, ty::RegionParameterDef { name: name,
1511                                                      def_id: def_id,
1512                                                      space: space,
1513                                                      index: index,
1514                                                      bounds: bounds });
1515     }
1516
1517     ty::Generics { types: types, regions: regions }
1518 }
1519
1520 fn doc_predicates<'tcx>(base_doc: rbml::Doc,
1521                         tcx: &ty::ctxt<'tcx>,
1522                         cdata: Cmd,
1523                         tag: usize)
1524                         -> ty::GenericPredicates<'tcx>
1525 {
1526     let doc = reader::get_doc(base_doc, tag);
1527
1528     let mut predicates = subst::VecPerParamSpace::empty();
1529     for predicate_doc in reader::tagged_docs(doc, tag_predicate) {
1530         let space_doc = reader::get_doc(predicate_doc, tag_predicate_space);
1531         let space = subst::ParamSpace::from_uint(reader::doc_as_u8(space_doc) as usize);
1532
1533         let data_doc = reader::get_doc(predicate_doc, tag_predicate_data);
1534         let data =
1535             TyDecoder::with_doc(tcx, cdata.cnum, data_doc,
1536                                 &mut |_, did| translate_def_id(cdata, did))
1537             .parse_predicate();
1538
1539         predicates.push(space, data);
1540     }
1541
1542     ty::GenericPredicates { predicates: predicates }
1543 }
1544
1545 pub fn is_defaulted_trait(cdata: Cmd, trait_id: ast::NodeId) -> bool {
1546     let trait_doc = lookup_item(trait_id, cdata.data());
1547     assert!(item_family(trait_doc) == Family::Trait);
1548     let defaulted_doc = reader::get_doc(trait_doc, tag_defaulted_trait);
1549     reader::doc_as_u8(defaulted_doc) != 0
1550 }
1551
1552 pub fn is_default_impl(cdata: Cmd, impl_id: ast::NodeId) -> bool {
1553     let impl_doc = lookup_item(impl_id, cdata.data());
1554     item_family(impl_doc) == Family::DefaultImpl
1555 }
1556
1557 pub fn get_imported_filemaps(metadata: &[u8]) -> Vec<codemap::FileMap> {
1558     let crate_doc = rbml::Doc::new(metadata);
1559     let cm_doc = reader::get_doc(crate_doc, tag_codemap);
1560
1561     reader::tagged_docs(cm_doc, tag_codemap_filemap).map(|filemap_doc| {
1562         let mut decoder = reader::Decoder::new(filemap_doc);
1563         Decodable::decode(&mut decoder).unwrap()
1564     }).collect()
1565 }
1566
1567 pub fn is_extern_fn(cdata: Cmd, id: ast::NodeId, tcx: &ty::ctxt) -> bool {
1568     let root_doc = rbml::Doc::new(cdata.data());
1569     let items = reader::get_doc(root_doc, tag_items);
1570     let item_doc = match maybe_find_item(id, items) {
1571         Some(doc) => doc,
1572         None => return false,
1573     };
1574     if let Fn = item_family(item_doc) {
1575         let ty::TypeScheme { generics, ty } = get_type(cdata, id, tcx);
1576         generics.types.is_empty() && match ty.sty {
1577             ty::TyBareFn(_, fn_ty) => fn_ty.abi != abi::Rust,
1578             _ => false,
1579         }
1580     } else {
1581         false
1582     }
1583 }