]> git.lizzy.rs Git - rust.git/blob - src/librustc/metadata/decoder.rs
librustc: Remove uses of `token::ident_to_str()` from librustc
[rust.git] / src / librustc / metadata / decoder.rs
1 // Copyright 2012 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
14 use metadata::cstore::crate_metadata;
15 use metadata::common::*;
16 use metadata::csearch::StaticMethodInfo;
17 use metadata::csearch;
18 use metadata::cstore;
19 use metadata::decoder;
20 use metadata::tydecode::{parse_ty_data, parse_def_id,
21                          parse_type_param_def_data,
22                          parse_bare_fn_ty_data, parse_trait_ref_data};
23 use middle::ty::{ImplContainer, TraitContainer};
24 use middle::ty;
25 use middle::typeck;
26 use middle::astencode::vtable_decoder_helpers;
27
28 use std::at_vec;
29 use std::u64;
30 use std::io;
31 use std::io::extensions::u64_from_be_bytes;
32 use std::option;
33 use std::vec;
34 use extra::ebml::reader;
35 use extra::ebml;
36 use extra::serialize::Decodable;
37 use syntax::ast_map;
38 use syntax::attr;
39 use syntax::parse::token::{IdentInterner, special_idents};
40 use syntax::print::pprust;
41 use syntax::ast;
42 use syntax::codemap;
43 use syntax::parse::token;
44
45 type Cmd = @crate_metadata;
46
47 // A function that takes a def_id relative to the crate being searched and
48 // returns a def_id relative to the compilation environment, i.e. if we hit a
49 // def_id for an item defined in another crate, somebody needs to figure out
50 // what crate that's in and give us a def_id that makes sense for the current
51 // build.
52
53 fn lookup_hash<'a>(d: ebml::Doc<'a>, eq_fn: |&[u8]| -> bool,
54                    hash: u64) -> Option<ebml::Doc<'a>> {
55     let index = reader::get_doc(d, tag_index);
56     let table = reader::get_doc(index, tag_index_table);
57     let hash_pos = table.start + (hash % 256 * 4) as uint;
58     let pos = u64_from_be_bytes(d.data, hash_pos, 4) as uint;
59     let tagged_doc = reader::doc_at(d.data, pos);
60
61     let belt = tag_index_buckets_bucket_elt;
62
63     let mut ret = None;
64     reader::tagged_docs(tagged_doc.doc, belt, |elt| {
65         let pos = u64_from_be_bytes(elt.data, elt.start, 4) as uint;
66         if eq_fn(elt.data.slice(elt.start + 4, elt.end)) {
67             ret = Some(reader::doc_at(d.data, pos).doc);
68             false
69         } else {
70             true
71         }
72     });
73     ret
74 }
75
76 pub type GetCrateDataCb<'a> = 'a |ast::CrateNum| -> Cmd;
77
78 pub fn maybe_find_item<'a>(item_id: ast::NodeId,
79                            items: ebml::Doc<'a>) -> Option<ebml::Doc<'a>> {
80     fn eq_item(bytes: &[u8], item_id: ast::NodeId) -> bool {
81         return u64_from_be_bytes(
82             bytes.slice(0u, 4u), 0u, 4u) as ast::NodeId
83             == item_id;
84     }
85     lookup_hash(items,
86                 |a| eq_item(a, item_id),
87                 (item_id as i64).hash())
88 }
89
90 fn find_item<'a>(item_id: ast::NodeId, items: ebml::Doc<'a>) -> ebml::Doc<'a> {
91     match maybe_find_item(item_id, items) {
92        None => fail!("lookup_item: id not found: {}", item_id),
93        Some(d) => d
94     }
95 }
96
97 // Looks up an item in the given metadata and returns an ebml doc pointing
98 // to the item data.
99 pub fn lookup_item<'a>(item_id: ast::NodeId, data: &'a [u8]) -> ebml::Doc<'a> {
100     let items = reader::get_doc(reader::Doc(data), tag_items);
101     find_item(item_id, items)
102 }
103
104 #[deriving(Eq)]
105 enum Family {
106     ImmStatic,             // c
107     MutStatic,             // b
108     Fn,                    // f
109     UnsafeFn,              // u
110     StaticMethod,          // F
111     UnsafeStaticMethod,    // U
112     ForeignFn,             // e
113     Type,                  // y
114     ForeignType,           // T
115     Mod,                   // m
116     ForeignMod,            // n
117     Enum,                  // t
118     TupleVariant,          // v
119     StructVariant,         // V
120     Impl,                  // i
121     Trait,                 // I
122     Struct,                // S
123     PublicField,           // g
124     PrivateField,          // j
125     InheritedField         // N
126 }
127
128 fn item_family(item: ebml::Doc) -> Family {
129     let fam = reader::get_doc(item, tag_items_data_item_family);
130     match reader::doc_as_u8(fam) as char {
131       'c' => ImmStatic,
132       'b' => MutStatic,
133       'f' => Fn,
134       'u' => UnsafeFn,
135       'F' => StaticMethod,
136       'U' => UnsafeStaticMethod,
137       'e' => ForeignFn,
138       'y' => Type,
139       'T' => ForeignType,
140       'm' => Mod,
141       'n' => ForeignMod,
142       't' => Enum,
143       'v' => TupleVariant,
144       'V' => StructVariant,
145       'i' => Impl,
146       'I' => Trait,
147       'S' => Struct,
148       'g' => PublicField,
149       'j' => PrivateField,
150       'N' => InheritedField,
151        c => fail!("unexpected family char: {}", c)
152     }
153 }
154
155 fn item_visibility(item: ebml::Doc) -> ast::Visibility {
156     match reader::maybe_get_doc(item, tag_items_data_item_visibility) {
157         None => ast::Public,
158         Some(visibility_doc) => {
159             match reader::doc_as_u8(visibility_doc) as char {
160                 'y' => ast::Public,
161                 'n' => ast::Private,
162                 'i' => ast::Inherited,
163                 _ => fail!("unknown visibility character")
164             }
165         }
166     }
167 }
168
169 fn item_method_sort(item: ebml::Doc) -> char {
170     let mut ret = 'r';
171     reader::tagged_docs(item, tag_item_trait_method_sort, |doc| {
172         ret = doc.as_str_slice()[0] as char;
173         false
174     });
175     ret
176 }
177
178 fn item_symbol(item: ebml::Doc) -> ~str {
179     reader::get_doc(item, tag_items_data_item_symbol).as_str()
180 }
181
182 fn item_parent_item(d: ebml::Doc) -> Option<ast::DefId> {
183     let mut ret = None;
184     reader::tagged_docs(d, tag_items_data_parent_item, |did| {
185         ret = Some(reader::with_doc_data(did, parse_def_id));
186         false
187     });
188     ret
189 }
190
191 fn item_reqd_and_translated_parent_item(cnum: ast::CrateNum,
192                                         d: ebml::Doc) -> ast::DefId {
193     let trait_did = item_parent_item(d).expect("item without parent");
194     ast::DefId { crate: cnum, node: trait_did.node }
195 }
196
197 fn item_def_id(d: ebml::Doc, cdata: Cmd) -> ast::DefId {
198     let tagdoc = reader::get_doc(d, tag_def_id);
199     return translate_def_id(cdata, reader::with_doc_data(tagdoc, parse_def_id));
200 }
201
202 fn get_provided_source(d: ebml::Doc, cdata: Cmd) -> Option<ast::DefId> {
203     reader::maybe_get_doc(d, tag_item_method_provided_source).map(|doc| {
204         translate_def_id(cdata, reader::with_doc_data(doc, parse_def_id))
205     })
206 }
207
208 fn each_reexport(d: ebml::Doc, f: |ebml::Doc| -> bool) -> bool {
209     reader::tagged_docs(d, tag_items_data_item_reexport, f)
210 }
211
212 fn variant_disr_val(d: ebml::Doc) -> Option<ty::Disr> {
213     reader::maybe_get_doc(d, tag_disr_val).and_then(|val_doc| {
214         reader::with_doc_data(val_doc, |data| u64::parse_bytes(data, 10u))
215     })
216 }
217
218 fn doc_type(doc: ebml::Doc, tcx: ty::ctxt, cdata: Cmd) -> ty::t {
219     let tp = reader::get_doc(doc, tag_items_data_item_type);
220     parse_ty_data(tp.data, cdata.cnum, tp.start, tcx,
221                   |_, did| translate_def_id(cdata, did))
222 }
223
224 fn doc_method_fty(doc: ebml::Doc, tcx: ty::ctxt, cdata: Cmd) -> ty::BareFnTy {
225     let tp = reader::get_doc(doc, tag_item_method_fty);
226     parse_bare_fn_ty_data(tp.data, cdata.cnum, tp.start, tcx,
227                           |_, did| translate_def_id(cdata, did))
228 }
229
230 pub fn item_type(_item_id: ast::DefId, item: ebml::Doc,
231                  tcx: ty::ctxt, cdata: Cmd) -> ty::t {
232     doc_type(item, tcx, cdata)
233 }
234
235 fn doc_trait_ref(doc: ebml::Doc, tcx: ty::ctxt, cdata: Cmd) -> ty::TraitRef {
236     parse_trait_ref_data(doc.data, cdata.cnum, doc.start, tcx,
237                          |_, did| translate_def_id(cdata, did))
238 }
239
240 fn item_trait_ref(doc: ebml::Doc, tcx: ty::ctxt, cdata: Cmd) -> ty::TraitRef {
241     let tp = reader::get_doc(doc, tag_item_trait_ref);
242     doc_trait_ref(tp, tcx, cdata)
243 }
244
245 fn item_ty_param_defs(item: ebml::Doc,
246                       tcx: ty::ctxt,
247                       cdata: Cmd,
248                       tag: uint)
249                       -> @~[ty::TypeParameterDef] {
250     let mut bounds = ~[];
251     reader::tagged_docs(item, tag, |p| {
252         let bd = parse_type_param_def_data(
253             p.data, p.start, cdata.cnum, tcx,
254             |_, did| translate_def_id(cdata, did));
255         bounds.push(bd);
256         true
257     });
258     @bounds
259 }
260
261 fn item_region_param_defs(item_doc: ebml::Doc,
262                           tcx: ty::ctxt,
263                           cdata: Cmd)
264                           -> @[ty::RegionParameterDef] {
265     at_vec::build(None, |push| {
266         reader::tagged_docs(item_doc, tag_region_param_def, |rp_doc| {
267             let ident_str_doc = reader::get_doc(rp_doc,
268                                                 tag_region_param_def_ident);
269             let ident = item_name(tcx.sess.intr(), ident_str_doc);
270             let def_id_doc = reader::get_doc(rp_doc,
271                                              tag_region_param_def_def_id);
272             let def_id = reader::with_doc_data(def_id_doc, parse_def_id);
273             let def_id = translate_def_id(cdata, def_id);
274             push(ty::RegionParameterDef { ident: ident,
275                                           def_id: def_id });
276             true
277         });
278     })
279 }
280
281 fn item_ty_param_count(item: ebml::Doc) -> uint {
282     let mut n = 0u;
283     reader::tagged_docs(item, tag_items_data_item_ty_param_bounds,
284                       |_p| { n += 1u; true } );
285     n
286 }
287
288 fn enum_variant_ids(item: ebml::Doc, cdata: Cmd) -> ~[ast::DefId] {
289     let mut ids: ~[ast::DefId] = ~[];
290     let v = tag_items_data_item_variant;
291     reader::tagged_docs(item, v, |p| {
292         let ext = reader::with_doc_data(p, parse_def_id);
293         ids.push(ast::DefId { crate: cdata.cnum, node: ext.node });
294         true
295     });
296     return ids;
297 }
298
299 pub fn item_path(item_doc: ebml::Doc) -> ast_map::Path {
300     let path_doc = reader::get_doc(item_doc, tag_path);
301
302     let len_doc = reader::get_doc(path_doc, tag_path_len);
303     let len = reader::doc_as_u32(len_doc) as uint;
304
305     let mut result = vec::with_capacity(len);
306     reader::docs(path_doc, |tag, elt_doc| {
307         if tag == tag_path_elem_mod {
308             let str = elt_doc.as_str_slice();
309             result.push(ast_map::PathMod(token::str_to_ident(str)));
310         } else if tag == tag_path_elem_name {
311             let str = elt_doc.as_str_slice();
312             result.push(ast_map::PathName(token::str_to_ident(str)));
313         } else if tag == tag_path_elem_pretty_name {
314             let name_doc = reader::get_doc(elt_doc,
315                                            tag_path_elem_pretty_name_ident);
316             let extra_doc = reader::get_doc(elt_doc,
317                                             tag_path_elem_pretty_name_extra);
318             let str = name_doc.as_str_slice();
319             let extra = reader::doc_as_u64(extra_doc);
320             result.push(ast_map::PathPrettyName(token::str_to_ident(str),
321                                                 extra));
322         } else {
323             // ignore tag_path_len element
324         }
325         true
326     });
327
328     return result;
329 }
330
331 fn item_name(intr: @IdentInterner, item: ebml::Doc) -> ast::Ident {
332     let name = reader::get_doc(item, tag_paths_data_name);
333     let string = name.as_str_slice();
334     match intr.find_equiv(&string) {
335         None => token::str_to_ident(string),
336         Some(val) => ast::Ident::new(val as ast::Name),
337     }
338 }
339
340 pub fn item_to_def_like(item: ebml::Doc, did: ast::DefId, cnum: ast::CrateNum)
341     -> DefLike {
342     let fam = item_family(item);
343     match fam {
344         ImmStatic => DlDef(ast::DefStatic(did, false)),
345         MutStatic => DlDef(ast::DefStatic(did, true)),
346         Struct    => DlDef(ast::DefStruct(did)),
347         UnsafeFn  => DlDef(ast::DefFn(did, ast::UnsafeFn)),
348         Fn        => DlDef(ast::DefFn(did, ast::ImpureFn)),
349         ForeignFn => DlDef(ast::DefFn(did, ast::ExternFn)),
350         StaticMethod | UnsafeStaticMethod => {
351             let purity = if fam == UnsafeStaticMethod { ast::UnsafeFn } else
352                 { ast::ImpureFn };
353             // def_static_method carries an optional field of its enclosing
354             // trait or enclosing impl (if this is an inherent static method).
355             // So we need to detect whether this is in a trait or not, which
356             // we do through the mildly hacky way of checking whether there is
357             // a trait_method_sort.
358             let provenance = if reader::maybe_get_doc(
359                   item, tag_item_trait_method_sort).is_some() {
360                 ast::FromTrait(item_reqd_and_translated_parent_item(cnum,
361                                                                     item))
362             } else {
363                 ast::FromImpl(item_reqd_and_translated_parent_item(cnum,
364                                                                    item))
365             };
366             DlDef(ast::DefStaticMethod(did, provenance, purity))
367         }
368         Type | ForeignType => DlDef(ast::DefTy(did)),
369         Mod => DlDef(ast::DefMod(did)),
370         ForeignMod => DlDef(ast::DefForeignMod(did)),
371         StructVariant => {
372             let enum_did = item_reqd_and_translated_parent_item(cnum, item);
373             DlDef(ast::DefVariant(enum_did, did, true))
374         }
375         TupleVariant => {
376             let enum_did = item_reqd_and_translated_parent_item(cnum, item);
377             DlDef(ast::DefVariant(enum_did, did, false))
378         }
379         Trait => DlDef(ast::DefTrait(did)),
380         Enum => DlDef(ast::DefTy(did)),
381         Impl => DlImpl(did),
382         PublicField | PrivateField | InheritedField => DlField,
383     }
384 }
385
386 pub fn lookup_def(cnum: ast::CrateNum, data: &[u8], did_: ast::DefId) ->
387    ast::Def {
388     let item = lookup_item(did_.node, data);
389     let did = ast::DefId { crate: cnum, node: did_.node };
390     // We treat references to enums as references to types.
391     return def_like_to_def(item_to_def_like(item, did, cnum));
392 }
393
394 pub fn get_trait_def(cdata: Cmd,
395                      item_id: ast::NodeId,
396                      tcx: ty::ctxt) -> ty::TraitDef
397 {
398     let item_doc = lookup_item(item_id, cdata.data());
399     let tp_defs = item_ty_param_defs(item_doc, tcx, cdata,
400                                      tag_items_data_item_ty_param_bounds);
401     let rp_defs = item_region_param_defs(item_doc, tcx, cdata);
402     let mut bounds = ty::EmptyBuiltinBounds();
403     // Collect the builtin bounds from the encoded supertraits.
404     // FIXME(#8559): They should be encoded directly.
405     reader::tagged_docs(item_doc, tag_item_super_trait_ref, |trait_doc| {
406         // NB. Bypasses real supertraits. See get_supertraits() if you wanted them.
407         let trait_ref = doc_trait_ref(trait_doc, tcx, cdata);
408         tcx.lang_items.to_builtin_kind(trait_ref.def_id).map(|bound| {
409             bounds.add(bound);
410         });
411         true
412     });
413     ty::TraitDef {
414         generics: ty::Generics {type_param_defs: tp_defs,
415                                 region_param_defs: rp_defs},
416         bounds: bounds,
417         trait_ref: @item_trait_ref(item_doc, tcx, cdata)
418     }
419 }
420
421 pub fn get_type(cdata: Cmd, id: ast::NodeId, tcx: ty::ctxt)
422     -> ty::ty_param_bounds_and_ty {
423
424     let item = lookup_item(id, cdata.data());
425
426     let t = item_type(ast::DefId { crate: cdata.cnum, node: id }, item, tcx,
427                       cdata);
428
429     let tp_defs = item_ty_param_defs(item, tcx, cdata, tag_items_data_item_ty_param_bounds);
430     let rp_defs = item_region_param_defs(item, tcx, cdata);
431
432     ty::ty_param_bounds_and_ty {
433         generics: ty::Generics {type_param_defs: tp_defs,
434                                 region_param_defs: rp_defs},
435         ty: t
436     }
437 }
438
439 pub fn get_type_param_count(data: &[u8], id: ast::NodeId) -> uint {
440     item_ty_param_count(lookup_item(id, data))
441 }
442
443 pub fn get_impl_trait(cdata: Cmd,
444                       id: ast::NodeId,
445                       tcx: ty::ctxt) -> Option<@ty::TraitRef>
446 {
447     let item_doc = lookup_item(id, cdata.data());
448     reader::maybe_get_doc(item_doc, tag_item_trait_ref).map(|tp| {
449         @doc_trait_ref(tp, tcx, cdata)
450     })
451 }
452
453 pub fn get_impl_vtables(cdata: Cmd,
454                         id: ast::NodeId,
455                         tcx: ty::ctxt) -> typeck::impl_res
456 {
457     let item_doc = lookup_item(id, cdata.data());
458     let vtables_doc = reader::get_doc(item_doc, tag_item_impl_vtables);
459     let mut decoder = reader::Decoder(vtables_doc);
460
461     typeck::impl_res {
462         trait_vtables: decoder.read_vtable_res(tcx, cdata),
463         self_vtables: decoder.read_vtable_param_res(tcx, cdata)
464     }
465 }
466
467
468 pub fn get_impl_method(intr: @IdentInterner, cdata: Cmd, id: ast::NodeId,
469                        name: ast::Ident) -> Option<ast::DefId> {
470     let items = reader::get_doc(reader::Doc(cdata.data()), tag_items);
471     let mut found = None;
472     reader::tagged_docs(find_item(id, items), tag_item_impl_method, |mid| {
473         let m_did = reader::with_doc_data(mid, parse_def_id);
474         if item_name(intr, find_item(m_did.node, items)) == name {
475             found = Some(translate_def_id(cdata, m_did));
476         }
477         true
478     });
479     found
480 }
481
482 pub fn get_symbol(data: &[u8], id: ast::NodeId) -> ~str {
483     return item_symbol(lookup_item(id, data));
484 }
485
486 // Something that a name can resolve to.
487 #[deriving(Clone)]
488 pub enum DefLike {
489     DlDef(ast::Def),
490     DlImpl(ast::DefId),
491     DlField
492 }
493
494 pub fn def_like_to_def(def_like: DefLike) -> ast::Def {
495     match def_like {
496         DlDef(def) => return def,
497         DlImpl(..) => fail!("found impl in def_like_to_def"),
498         DlField => fail!("found field in def_like_to_def")
499     }
500 }
501
502 /// Iterates over the language items in the given crate.
503 pub fn each_lang_item(cdata: Cmd, f: |ast::NodeId, uint| -> bool) -> bool {
504     let root = reader::Doc(cdata.data());
505     let lang_items = reader::get_doc(root, tag_lang_items);
506     reader::tagged_docs(lang_items, tag_lang_items_item, |item_doc| {
507         let id_doc = reader::get_doc(item_doc, tag_lang_items_item_id);
508         let id = reader::doc_as_u32(id_doc) as uint;
509         let node_id_doc = reader::get_doc(item_doc,
510                                           tag_lang_items_item_node_id);
511         let node_id = reader::doc_as_u32(node_id_doc) as ast::NodeId;
512
513         f(node_id, id)
514     })
515 }
516
517 fn each_child_of_item_or_crate(intr: @IdentInterner,
518                                cdata: Cmd,
519                                item_doc: ebml::Doc,
520                                get_crate_data: GetCrateDataCb,
521                                callback: |DefLike,
522                                           ast::Ident,
523                                           ast::Visibility|) {
524     // Iterate over all children.
525     let _ = reader::tagged_docs(item_doc, tag_mod_child, |child_info_doc| {
526         let child_def_id = reader::with_doc_data(child_info_doc,
527                                                  parse_def_id);
528         let child_def_id = translate_def_id(cdata, child_def_id);
529
530         // This item may be in yet another crate if it was the child of a
531         // reexport.
532         let other_crates_items = if child_def_id.crate == cdata.cnum {
533             reader::get_doc(reader::Doc(cdata.data()), tag_items)
534         } else {
535             let crate_data = get_crate_data(child_def_id.crate);
536             reader::get_doc(reader::Doc(crate_data.data()), tag_items)
537         };
538
539         // Get the item.
540         match maybe_find_item(child_def_id.node, other_crates_items) {
541             None => {}
542             Some(child_item_doc) => {
543                 // Hand off the item to the callback.
544                 let child_name = item_name(intr, child_item_doc);
545                 let def_like = item_to_def_like(child_item_doc,
546                                                 child_def_id,
547                                                 cdata.cnum);
548                 let visibility = item_visibility(child_item_doc);
549                 callback(def_like, child_name, visibility);
550
551             }
552         }
553
554         true
555     });
556
557     // As a special case, iterate over all static methods of
558     // associated implementations too. This is a bit of a botch.
559     // --pcwalton
560     let _ = reader::tagged_docs(item_doc,
561                                 tag_items_data_item_inherent_impl,
562                                 |inherent_impl_def_id_doc| {
563         let inherent_impl_def_id = item_def_id(inherent_impl_def_id_doc,
564                                                cdata);
565         let items = reader::get_doc(reader::Doc(cdata.data()), tag_items);
566         match maybe_find_item(inherent_impl_def_id.node, items) {
567             None => {}
568             Some(inherent_impl_doc) => {
569                 let _ = reader::tagged_docs(inherent_impl_doc,
570                                             tag_item_impl_method,
571                                             |impl_method_def_id_doc| {
572                     let impl_method_def_id =
573                         reader::with_doc_data(impl_method_def_id_doc,
574                                               parse_def_id);
575                     let impl_method_def_id =
576                         translate_def_id(cdata, impl_method_def_id);
577                     match maybe_find_item(impl_method_def_id.node, items) {
578                         None => {}
579                         Some(impl_method_doc) => {
580                             match item_family(impl_method_doc) {
581                                 StaticMethod | UnsafeStaticMethod => {
582                                     // Hand off the static method
583                                     // to the callback.
584                                     let static_method_name =
585                                         item_name(intr, impl_method_doc);
586                                     let static_method_def_like =
587                                         item_to_def_like(impl_method_doc,
588                                                          impl_method_def_id,
589                                                          cdata.cnum);
590                                     callback(static_method_def_like,
591                                              static_method_name,
592                                              item_visibility(impl_method_doc));
593                                 }
594                                 _ => {}
595                             }
596                         }
597                     }
598
599                     true
600                 });
601             }
602         }
603
604         true
605     });
606
607     // Iterate over all reexports.
608     let _ = each_reexport(item_doc, |reexport_doc| {
609         let def_id_doc = reader::get_doc(reexport_doc,
610                                          tag_items_data_item_reexport_def_id);
611         let child_def_id = reader::with_doc_data(def_id_doc,
612                                                  parse_def_id);
613         let child_def_id = translate_def_id(cdata, child_def_id);
614
615         let name_doc = reader::get_doc(reexport_doc,
616                                        tag_items_data_item_reexport_name);
617         let name = name_doc.as_str_slice();
618
619         // This reexport may be in yet another crate.
620         let other_crates_items = if child_def_id.crate == cdata.cnum {
621             reader::get_doc(reader::Doc(cdata.data()), tag_items)
622         } else {
623             let crate_data = get_crate_data(child_def_id.crate);
624             reader::get_doc(reader::Doc(crate_data.data()), tag_items)
625         };
626
627         // Get the item.
628         match maybe_find_item(child_def_id.node, other_crates_items) {
629             None => {}
630             Some(child_item_doc) => {
631                 // Hand off the item to the callback.
632                 let def_like = item_to_def_like(child_item_doc,
633                                                 child_def_id,
634                                                 cdata.cnum);
635                 // These items have a public visibility because they're part of
636                 // a public re-export.
637                 callback(def_like, token::str_to_ident(name), ast::Public);
638             }
639         }
640
641         true
642     });
643 }
644
645 /// Iterates over each child of the given item.
646 pub fn each_child_of_item(intr: @IdentInterner,
647                           cdata: Cmd,
648                           id: ast::NodeId,
649                           get_crate_data: GetCrateDataCb,
650                           callback: |DefLike, ast::Ident, ast::Visibility|) {
651     // Find the item.
652     let root_doc = reader::Doc(cdata.data());
653     let items = reader::get_doc(root_doc, tag_items);
654     let item_doc = match maybe_find_item(id, items) {
655         None => return,
656         Some(item_doc) => item_doc,
657     };
658
659     each_child_of_item_or_crate(intr,
660                                 cdata,
661                                 item_doc,
662                                 get_crate_data,
663                                 callback)
664 }
665
666 /// Iterates over all the top-level crate items.
667 pub fn each_top_level_item_of_crate(intr: @IdentInterner,
668                                     cdata: Cmd,
669                                     get_crate_data: GetCrateDataCb,
670                                     callback: |DefLike,
671                                                ast::Ident,
672                                                ast::Visibility|) {
673     let root_doc = reader::Doc(cdata.data());
674     let misc_info_doc = reader::get_doc(root_doc, tag_misc_info);
675     let crate_items_doc = reader::get_doc(misc_info_doc,
676                                           tag_misc_info_crate_items);
677
678     each_child_of_item_or_crate(intr,
679                                 cdata,
680                                 crate_items_doc,
681                                 get_crate_data,
682                                 callback)
683 }
684
685 pub fn get_item_path(cdata: Cmd, id: ast::NodeId) -> ast_map::Path {
686     item_path(lookup_item(id, cdata.data()))
687 }
688
689 pub type decode_inlined_item<'a> = 'a |cdata: @cstore::crate_metadata,
690                                              tcx: ty::ctxt,
691                                              path: ast_map::Path,
692                                              par_doc: ebml::Doc|
693                                              -> Option<ast::InlinedItem>;
694
695 pub fn maybe_get_item_ast(cdata: Cmd, tcx: ty::ctxt,
696                           id: ast::NodeId,
697                           decode_inlined_item: decode_inlined_item)
698                        -> csearch::found_ast {
699     debug!("Looking up item: {}", id);
700     let item_doc = lookup_item(id, cdata.data());
701     let path = {
702         let item_path = item_path(item_doc);
703         item_path.init().to_owned()
704     };
705     match decode_inlined_item(cdata, tcx, /*bad*/path.clone(), item_doc) {
706       Some(ref ii) => csearch::found(*ii),
707       None => {
708         match item_parent_item(item_doc) {
709           Some(did) => {
710             let did = translate_def_id(cdata, did);
711             let parent_item = lookup_item(did.node, cdata.data());
712             match decode_inlined_item(cdata, tcx, path, parent_item) {
713               Some(ref ii) => csearch::found_parent(did, *ii),
714               None => csearch::not_found
715             }
716           }
717           None => csearch::not_found
718         }
719       }
720     }
721 }
722
723 pub fn get_enum_variants(intr: @IdentInterner, cdata: Cmd, id: ast::NodeId,
724                      tcx: ty::ctxt) -> ~[@ty::VariantInfo] {
725     let data = cdata.data();
726     let items = reader::get_doc(reader::Doc(data), tag_items);
727     let item = find_item(id, items);
728     let mut infos: ~[@ty::VariantInfo] = ~[];
729     let variant_ids = enum_variant_ids(item, cdata);
730     let mut disr_val = 0;
731     for did in variant_ids.iter() {
732         let item = find_item(did.node, items);
733         let ctor_ty = item_type(ast::DefId { crate: cdata.cnum, node: id},
734                                 item, tcx, cdata);
735         let name = item_name(intr, item);
736         let arg_tys = match ty::get(ctor_ty).sty {
737           ty::ty_bare_fn(ref f) => f.sig.inputs.clone(),
738           _ => ~[], // Nullary enum variant.
739         };
740         match variant_disr_val(item) {
741           Some(val) => { disr_val = val; }
742           _         => { /* empty */ }
743         }
744         infos.push(@ty::VariantInfo{
745             args: arg_tys,
746             arg_names: None,
747             ctor_ty: ctor_ty,
748             name: name,
749             // I'm not even sure if we encode visibility
750             // for variants -- TEST -- tjc
751             id: *did,
752             disr_val: disr_val,
753             vis: ast::Inherited});
754         disr_val += 1;
755     }
756     return infos;
757 }
758
759 fn get_explicit_self(item: ebml::Doc) -> ast::ExplicitSelf_ {
760     fn get_mutability(ch: u8) -> ast::Mutability {
761         match ch as char {
762             'i' => ast::MutImmutable,
763             'm' => ast::MutMutable,
764             _ => fail!("unknown mutability character: `{}`", ch as char),
765         }
766     }
767
768     let explicit_self_doc = reader::get_doc(item, tag_item_trait_method_explicit_self);
769     let string = explicit_self_doc.as_str_slice();
770
771     let explicit_self_kind = string[0];
772     match explicit_self_kind as char {
773         's' => ast::SelfStatic,
774         'v' => ast::SelfValue,
775         '@' => ast::SelfBox,
776         '~' => ast::SelfUniq,
777         // FIXME(#4846) expl. region
778         '&' => ast::SelfRegion(None, get_mutability(string[1])),
779         _ => fail!("unknown self type code: `{}`", explicit_self_kind as char)
780     }
781 }
782
783 fn item_impl_methods(intr: @IdentInterner, cdata: Cmd, item: ebml::Doc,
784                      tcx: ty::ctxt) -> ~[@ty::Method] {
785     let mut rslt = ~[];
786     reader::tagged_docs(item, tag_item_impl_method, |doc| {
787         let m_did = reader::with_doc_data(doc, parse_def_id);
788         rslt.push(@get_method(intr, cdata, m_did.node, tcx));
789         true
790     });
791
792     rslt
793 }
794
795 /// Returns information about the given implementation.
796 pub fn get_impl(intr: @IdentInterner, cdata: Cmd, impl_id: ast::NodeId,
797                tcx: ty::ctxt)
798                 -> ty::Impl {
799     let data = cdata.data();
800     let impl_item = lookup_item(impl_id, data);
801     ty::Impl {
802         did: ast::DefId {
803             crate: cdata.cnum,
804             node: impl_id,
805         },
806         ident: item_name(intr, impl_item),
807         methods: item_impl_methods(intr, cdata, impl_item, tcx),
808     }
809 }
810
811 pub fn get_method_name_and_explicit_self(
812     intr: @IdentInterner,
813     cdata: Cmd,
814     id: ast::NodeId) -> (ast::Ident, ast::ExplicitSelf_)
815 {
816     let method_doc = lookup_item(id, cdata.data());
817     let name = item_name(intr, method_doc);
818     let explicit_self = get_explicit_self(method_doc);
819     (name, explicit_self)
820 }
821
822 pub fn get_method(intr: @IdentInterner, cdata: Cmd, id: ast::NodeId,
823                   tcx: ty::ctxt) -> ty::Method
824 {
825     let method_doc = lookup_item(id, cdata.data());
826     let def_id = item_def_id(method_doc, cdata);
827
828     let container_id = item_reqd_and_translated_parent_item(cdata.cnum,
829                                                             method_doc);
830     let container_doc = lookup_item(container_id.node, cdata.data());
831     let container = match item_family(container_doc) {
832         Trait => TraitContainer(container_id),
833         _ => ImplContainer(container_id),
834     };
835
836     let name = item_name(intr, method_doc);
837     let type_param_defs = item_ty_param_defs(method_doc, tcx, cdata,
838                                              tag_item_method_tps);
839     let rp_defs = item_region_param_defs(method_doc, tcx, cdata);
840     let fty = doc_method_fty(method_doc, tcx, cdata);
841     let vis = item_visibility(method_doc);
842     let explicit_self = get_explicit_self(method_doc);
843     let provided_source = get_provided_source(method_doc, cdata);
844
845     ty::Method::new(
846         name,
847         ty::Generics {
848             type_param_defs: type_param_defs,
849             region_param_defs: rp_defs,
850         },
851         fty,
852         explicit_self,
853         vis,
854         def_id,
855         container,
856         provided_source
857     )
858 }
859
860 pub fn get_trait_method_def_ids(cdata: Cmd,
861                                 id: ast::NodeId) -> ~[ast::DefId] {
862     let data = cdata.data();
863     let item = lookup_item(id, data);
864     let mut result = ~[];
865     reader::tagged_docs(item, tag_item_trait_method, |mth| {
866         result.push(item_def_id(mth, cdata));
867         true
868     });
869     result
870 }
871
872 pub fn get_item_variances(cdata: Cmd, id: ast::NodeId) -> ty::ItemVariances {
873     let data = cdata.data();
874     let item_doc = lookup_item(id, data);
875     let variance_doc = reader::get_doc(item_doc, tag_item_variances);
876     let mut decoder = reader::Decoder(variance_doc);
877     Decodable::decode(&mut decoder)
878 }
879
880 pub fn get_provided_trait_methods(intr: @IdentInterner, cdata: Cmd,
881                                   id: ast::NodeId, tcx: ty::ctxt) ->
882         ~[@ty::Method] {
883     let data = cdata.data();
884     let item = lookup_item(id, data);
885     let mut result = ~[];
886
887     reader::tagged_docs(item, tag_item_trait_method, |mth_id| {
888         let did = item_def_id(mth_id, cdata);
889         let mth = lookup_item(did.node, data);
890
891         if item_method_sort(mth) == 'p' {
892             result.push(@get_method(intr, cdata, did.node, tcx));
893         }
894         true
895     });
896
897     return result;
898 }
899
900 /// Returns the supertraits of the given trait.
901 pub fn get_supertraits(cdata: Cmd, id: ast::NodeId, tcx: ty::ctxt)
902                     -> ~[@ty::TraitRef] {
903     let mut results = ~[];
904     let item_doc = lookup_item(id, cdata.data());
905     reader::tagged_docs(item_doc, tag_item_super_trait_ref, |trait_doc| {
906         // NB. Only reads the ones that *aren't* builtin-bounds. See also
907         // get_trait_def() for collecting the builtin bounds.
908         // FIXME(#8559): The builtin bounds shouldn't be encoded in the first place.
909         let trait_ref = doc_trait_ref(trait_doc, tcx, cdata);
910         if tcx.lang_items.to_builtin_kind(trait_ref.def_id).is_none() {
911             results.push(@trait_ref);
912         }
913         true
914     });
915     return results;
916 }
917
918 pub fn get_type_name_if_impl(cdata: Cmd,
919                              node_id: ast::NodeId) -> Option<ast::Ident> {
920     let item = lookup_item(node_id, cdata.data());
921     if item_family(item) != Impl {
922         return None;
923     }
924
925     let mut ret = None;
926     reader::tagged_docs(item, tag_item_impl_type_basename, |doc| {
927         ret = Some(token::str_to_ident(doc.as_str_slice()));
928         false
929     });
930
931     ret
932 }
933
934 pub fn get_static_methods_if_impl(intr: @IdentInterner,
935                                   cdata: Cmd,
936                                   node_id: ast::NodeId)
937                                -> Option<~[StaticMethodInfo]> {
938     let item = lookup_item(node_id, cdata.data());
939     if item_family(item) != Impl {
940         return None;
941     }
942
943     // If this impl implements a trait, don't consider it.
944     let ret = reader::tagged_docs(item, tag_item_trait_ref, |_doc| {
945         false
946     });
947
948     if !ret { return None }
949
950     let mut impl_method_ids = ~[];
951     reader::tagged_docs(item, tag_item_impl_method, |impl_method_doc| {
952         impl_method_ids.push(reader::with_doc_data(impl_method_doc, parse_def_id));
953         true
954     });
955
956     let mut static_impl_methods = ~[];
957     for impl_method_id in impl_method_ids.iter() {
958         let impl_method_doc = lookup_item(impl_method_id.node, cdata.data());
959         let family = item_family(impl_method_doc);
960         match family {
961             StaticMethod | UnsafeStaticMethod => {
962                 let purity;
963                 match item_family(impl_method_doc) {
964                     StaticMethod => purity = ast::ImpureFn,
965                     UnsafeStaticMethod => purity = ast::UnsafeFn,
966                     _ => fail!()
967                 }
968
969                 static_impl_methods.push(StaticMethodInfo {
970                     ident: item_name(intr, impl_method_doc),
971                     def_id: item_def_id(impl_method_doc, cdata),
972                     purity: purity,
973                     vis: item_visibility(impl_method_doc),
974                 });
975             }
976             _ => {}
977         }
978     }
979
980     return Some(static_impl_methods);
981 }
982
983 pub fn get_item_attrs(cdata: Cmd,
984                       node_id: ast::NodeId,
985                       f: |~[@ast::MetaItem]|) {
986     let item = lookup_item(node_id, cdata.data());
987     reader::tagged_docs(item, tag_attributes, |attributes| {
988         reader::tagged_docs(attributes, tag_attribute, |attribute| {
989             f(get_meta_items(attribute));
990             true
991         });
992         true
993     });
994 }
995
996 fn struct_field_family_to_visibility(family: Family) -> ast::Visibility {
997     match family {
998       PublicField => ast::Public,
999       PrivateField => ast::Private,
1000       InheritedField => ast::Inherited,
1001       _ => fail!()
1002     }
1003 }
1004
1005 pub fn get_struct_fields(intr: @IdentInterner, cdata: Cmd, id: ast::NodeId)
1006     -> ~[ty::field_ty] {
1007     let data = cdata.data();
1008     let item = lookup_item(id, data);
1009     let mut result = ~[];
1010     reader::tagged_docs(item, tag_item_field, |an_item| {
1011         let f = item_family(an_item);
1012         if f == PublicField || f == PrivateField || f == InheritedField {
1013             // FIXME #6993: name should be of type Name, not Ident
1014             let name = item_name(intr, an_item);
1015             let did = item_def_id(an_item, cdata);
1016             result.push(ty::field_ty {
1017                 name: name.name,
1018                 id: did, vis:
1019                 struct_field_family_to_visibility(f),
1020             });
1021         }
1022         true
1023     });
1024     reader::tagged_docs(item, tag_item_unnamed_field, |an_item| {
1025         let did = item_def_id(an_item, cdata);
1026         result.push(ty::field_ty {
1027             name: special_idents::unnamed_field.name,
1028             id: did,
1029             vis: ast::Inherited,
1030         });
1031         true
1032     });
1033     result
1034 }
1035
1036 pub fn get_item_visibility(cdata: Cmd, id: ast::NodeId)
1037                         -> ast::Visibility {
1038     item_visibility(lookup_item(id, cdata.data()))
1039 }
1040
1041 fn get_meta_items(md: ebml::Doc) -> ~[@ast::MetaItem] {
1042     let mut items: ~[@ast::MetaItem] = ~[];
1043     reader::tagged_docs(md, tag_meta_item_word, |meta_item_doc| {
1044         let nd = reader::get_doc(meta_item_doc, tag_meta_item_name);
1045         let n = token::intern_and_get_ident(nd.as_str_slice());
1046         items.push(attr::mk_word_item(n));
1047         true
1048     });
1049     reader::tagged_docs(md, tag_meta_item_name_value, |meta_item_doc| {
1050         let nd = reader::get_doc(meta_item_doc, tag_meta_item_name);
1051         let vd = reader::get_doc(meta_item_doc, tag_meta_item_value);
1052         let n = token::intern_and_get_ident(nd.as_str_slice());
1053         let v = token::intern_and_get_ident(vd.as_str_slice());
1054         // FIXME (#623): Should be able to decode MetaNameValue variants,
1055         // but currently the encoder just drops them
1056         items.push(attr::mk_name_value_item_str(n, v));
1057         true
1058     });
1059     reader::tagged_docs(md, tag_meta_item_list, |meta_item_doc| {
1060         let nd = reader::get_doc(meta_item_doc, tag_meta_item_name);
1061         let n = token::intern_and_get_ident(nd.as_str_slice());
1062         let subitems = get_meta_items(meta_item_doc);
1063         items.push(attr::mk_list_item(n, subitems));
1064         true
1065     });
1066     return items;
1067 }
1068
1069 fn get_attributes(md: ebml::Doc) -> ~[ast::Attribute] {
1070     let mut attrs: ~[ast::Attribute] = ~[];
1071     match reader::maybe_get_doc(md, tag_attributes) {
1072       option::Some(attrs_d) => {
1073         reader::tagged_docs(attrs_d, tag_attribute, |attr_doc| {
1074             let meta_items = get_meta_items(attr_doc);
1075             // Currently it's only possible to have a single meta item on
1076             // an attribute
1077             assert_eq!(meta_items.len(), 1u);
1078             let meta_item = meta_items[0];
1079             attrs.push(
1080                 codemap::Spanned {
1081                     node: ast::Attribute_ {
1082                         style: ast::AttrOuter,
1083                         value: meta_item,
1084                         is_sugared_doc: false,
1085                     },
1086                     span: codemap::DUMMY_SP
1087                 });
1088             true
1089         });
1090       }
1091       option::None => ()
1092     }
1093     return attrs;
1094 }
1095
1096 fn list_crate_attributes(intr: @IdentInterner, md: ebml::Doc, hash: &str,
1097                          out: &mut io::Writer) {
1098     write!(out, "=Crate Attributes ({})=\n", hash);
1099
1100     let r = get_attributes(md);
1101     for attr in r.iter() {
1102         write!(out, "{}\n", pprust::attribute_to_str(attr, intr));
1103     }
1104
1105     write!(out, "\n\n");
1106 }
1107
1108 pub fn get_crate_attributes(data: &[u8]) -> ~[ast::Attribute] {
1109     return get_attributes(reader::Doc(data));
1110 }
1111
1112 #[deriving(Clone)]
1113 pub struct CrateDep {
1114     cnum: ast::CrateNum,
1115     name: ast::Ident,
1116     vers: ~str,
1117     hash: ~str
1118 }
1119
1120 pub fn get_crate_deps(data: &[u8]) -> ~[CrateDep] {
1121     let mut deps: ~[CrateDep] = ~[];
1122     let cratedoc = reader::Doc(data);
1123     let depsdoc = reader::get_doc(cratedoc, tag_crate_deps);
1124     let mut crate_num = 1;
1125     fn docstr(doc: ebml::Doc, tag_: uint) -> ~str {
1126         let d = reader::get_doc(doc, tag_);
1127         d.as_str_slice().to_str()
1128     }
1129     reader::tagged_docs(depsdoc, tag_crate_dep, |depdoc| {
1130         deps.push(CrateDep {cnum: crate_num,
1131                   name: token::str_to_ident(docstr(depdoc, tag_crate_dep_name)),
1132                   vers: docstr(depdoc, tag_crate_dep_vers),
1133                   hash: docstr(depdoc, tag_crate_dep_hash)});
1134         crate_num += 1;
1135         true
1136     });
1137     return deps;
1138 }
1139
1140 fn list_crate_deps(data: &[u8], out: &mut io::Writer) {
1141     write!(out, "=External Dependencies=\n");
1142
1143     let r = get_crate_deps(data);
1144     for dep in r.iter() {
1145         let string = token::get_ident(dep.name.name);
1146         write!(out,
1147                "{} {}-{}-{}\n",
1148                dep.cnum,
1149                string.get(),
1150                dep.hash,
1151                dep.vers);
1152     }
1153
1154     write!(out, "\n");
1155 }
1156
1157 pub fn get_crate_hash(data: &[u8]) -> ~str {
1158     let cratedoc = reader::Doc(data);
1159     let hashdoc = reader::get_doc(cratedoc, tag_crate_hash);
1160     hashdoc.as_str_slice().to_str()
1161 }
1162
1163 pub fn get_crate_vers(data: &[u8]) -> ~str {
1164     let attrs = decoder::get_crate_attributes(data);
1165     match attr::find_crateid(attrs) {
1166         None => ~"0.0",
1167         Some(crateid) => crateid.version_or_default().to_str(),
1168     }
1169 }
1170
1171 pub fn list_crate_metadata(intr: @IdentInterner, bytes: &[u8],
1172                            out: &mut io::Writer) {
1173     let hash = get_crate_hash(bytes);
1174     let md = reader::Doc(bytes);
1175     list_crate_attributes(intr, md, hash, out);
1176     list_crate_deps(bytes, out);
1177 }
1178
1179 // Translates a def_id from an external crate to a def_id for the current
1180 // compilation environment. We use this when trying to load types from
1181 // external crates - if those types further refer to types in other crates
1182 // then we must translate the crate number from that encoded in the external
1183 // crate to the correct local crate number.
1184 pub fn translate_def_id(cdata: Cmd, did: ast::DefId) -> ast::DefId {
1185     if did.crate == ast::LOCAL_CRATE {
1186         return ast::DefId { crate: cdata.cnum, node: did.node };
1187     }
1188
1189     let cnum_map = cdata.cnum_map.borrow();
1190     match cnum_map.get().find(&did.crate) {
1191         Some(&n) => {
1192             ast::DefId {
1193                 crate: n,
1194                 node: did.node,
1195             }
1196         }
1197         None => fail!("didn't find a crate in the cnum_map")
1198     }
1199 }
1200
1201 pub fn each_impl(cdata: Cmd, callback: |ast::DefId|) {
1202     let impls_doc = reader::get_doc(reader::Doc(cdata.data()), tag_impls);
1203     let _ = reader::tagged_docs(impls_doc, tag_impls_impl, |impl_doc| {
1204         callback(item_def_id(impl_doc, cdata));
1205         true
1206     });
1207 }
1208
1209 pub fn each_implementation_for_type(cdata: Cmd,
1210                                     id: ast::NodeId,
1211                                     callback: |ast::DefId|) {
1212     let item_doc = lookup_item(id, cdata.data());
1213     reader::tagged_docs(item_doc,
1214                         tag_items_data_item_inherent_impl,
1215                         |impl_doc| {
1216         let implementation_def_id = item_def_id(impl_doc, cdata);
1217         callback(implementation_def_id);
1218         true
1219     });
1220 }
1221
1222 pub fn each_implementation_for_trait(cdata: Cmd,
1223                                      id: ast::NodeId,
1224                                      callback: |ast::DefId|) {
1225     let item_doc = lookup_item(id, cdata.data());
1226
1227     let _ = reader::tagged_docs(item_doc,
1228                                 tag_items_data_item_extension_impl,
1229                                 |impl_doc| {
1230         let implementation_def_id = item_def_id(impl_doc, cdata);
1231         callback(implementation_def_id);
1232         true
1233     });
1234 }
1235
1236 pub fn get_trait_of_method(cdata: Cmd, id: ast::NodeId, tcx: ty::ctxt)
1237                            -> Option<ast::DefId> {
1238     let item_doc = lookup_item(id, cdata.data());
1239     let parent_item_id = match item_parent_item(item_doc) {
1240         None => return None,
1241         Some(item_id) => item_id,
1242     };
1243     let parent_item_id = translate_def_id(cdata, parent_item_id);
1244     let parent_item_doc = lookup_item(parent_item_id.node, cdata.data());
1245     match item_family(parent_item_doc) {
1246         Trait => Some(item_def_id(parent_item_doc, cdata)),
1247         Impl => {
1248             reader::maybe_get_doc(parent_item_doc, tag_item_trait_ref)
1249                 .map(|_| item_trait_ref(parent_item_doc, tcx, cdata).def_id)
1250         }
1251         _ => None
1252     }
1253 }
1254
1255
1256 pub fn get_native_libraries(cdata: Cmd) -> ~[(cstore::NativeLibaryKind, ~str)] {
1257     let libraries = reader::get_doc(reader::Doc(cdata.data()),
1258                                     tag_native_libraries);
1259     let mut result = ~[];
1260     reader::tagged_docs(libraries, tag_native_libraries_lib, |lib_doc| {
1261         let kind_doc = reader::get_doc(lib_doc, tag_native_libraries_kind);
1262         let name_doc = reader::get_doc(lib_doc, tag_native_libraries_name);
1263         let kind: cstore::NativeLibaryKind =
1264             FromPrimitive::from_u32(reader::doc_as_u32(kind_doc)).unwrap();
1265         let name = name_doc.as_str();
1266         result.push((kind, name));
1267         true
1268     });
1269     return result;
1270 }
1271
1272 pub fn get_macro_registrar_fn(cdata: Cmd) -> Option<ast::DefId> {
1273     reader::maybe_get_doc(reader::Doc(cdata.data()), tag_macro_registrar_fn)
1274         .map(|doc| item_def_id(doc, cdata))
1275 }
1276
1277 pub fn get_exported_macros(cdata: Cmd) -> ~[~str] {
1278     let macros = reader::get_doc(reader::Doc(cdata.data()),
1279                                  tag_exported_macros);
1280     let mut result = ~[];
1281     reader::tagged_docs(macros, tag_macro_def, |macro_doc| {
1282         result.push(macro_doc.as_str());
1283         true
1284     });
1285     result
1286 }