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