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