decoder.rs 38.4 KB
Newer Older
1 2 3 4 5 6 7 8 9 10
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

11

12
// Decoding metadata from a single crate's metadata
B
Brian Anderson 已提交
13

14 15
use core::prelude::*;

16 17 18 19 20 21
use cmd = metadata::cstore::crate_metadata;
use dvec::DVec;
use hash::{Hash, HashUtil};
use io::WriterUtil;
use metadata::common::*;
use metadata::csearch::{ProvidedTraitMethodInfo, StaticMethodInfo};
22 23 24
use metadata::csearch;
use metadata::cstore;
use metadata::decoder;
25 26 27 28 29
use metadata::tydecode::{parse_ty_data, parse_def_id, parse_bounds_data};
use metadata::tydecode::{parse_ident};
use middle::ty;
use util::ppaux::ty_to_str;

30 31 32 33 34 35 36 37
use core::cmp;
use core::dvec;
use core::int;
use core::io;
use core::option;
use core::str;
use core::vec;
use std::ebml::reader;
38
use std::ebml;
39 40
use std::oldmap::HashMap;
use std::oldmap;
41
use std::serialize::Decodable;
P
Patrick Walton 已提交
42
use syntax::ast_map;
43
use syntax::attr;
P
Patrick Walton 已提交
44
use syntax::diagnostic::span_handler;
45
use syntax::parse::token::{ident_interner, special_idents};
46 47
use syntax::print::pprust;
use syntax::{ast, ast_util};
J
John Clements 已提交
48
use syntax::codemap;
49

50 51 52 53 54
// A function that takes a def_id relative to the crate being searched and
// returns a def_id relative to the compilation environment, i.e. if we hit a
// def_id for an item defined in another crate, somebody needs to figure out
// what crate that's in and give us a def_id that makes sense for the current
// build.
M
Marijn Haverbeke 已提交
55

56 57
fn lookup_hash(d: ebml::Doc, eq_fn: fn(x:&[u8]) -> bool, hash: uint) ->
   Option<ebml::Doc> {
58 59
    let index = reader::get_doc(d, tag_index);
    let table = reader::get_doc(index, tag_index_table);
M
Marijn Haverbeke 已提交
60
    let hash_pos = table.start + hash % 256u * 4u;
61
    let pos = io::u64_from_be_bytes(*d.data, hash_pos, 4u) as uint;
62
    let tagged_doc = reader::doc_at(d.data, pos);
63

M
Marijn Haverbeke 已提交
64
    let belt = tag_index_buckets_bucket_elt;
65
    for reader::tagged_docs(tagged_doc.doc, belt) |elt| {
66
        let pos = io::u64_from_be_bytes(*elt.data, elt.start, 4u) as uint;
67
        if eq_fn(vec::view(*elt.data, elt.start + 4u, elt.end)) {
68
            return Some(reader::doc_at(d.data, pos).doc);
69
        }
70
    };
B
Brian Anderson 已提交
71
    None
72 73
}

74 75
pub type GetCrateDataCb = &fn(ast::crate_num) -> cmd;

76
pub fn maybe_find_item(item_id: int, items: ebml::Doc) -> Option<ebml::Doc> {
77
    fn eq_item(bytes: &[u8], item_id: int) -> bool {
78
        return io::u64_from_be_bytes(vec::view(bytes, 0u, 4u), 0u, 4u) as int
79
            == item_id;
80
    }
81 82
    lookup_hash(items,
                |a| eq_item(a, item_id),
83
                item_id.hash() as uint)
84 85
}

86
fn find_item(item_id: int, items: ebml::Doc) -> ebml::Doc {
B
Brian Anderson 已提交
87
    return maybe_find_item(item_id, items).get();
88 89
}

90
// Looks up an item in the given metadata and returns an ebml doc pointing
91
// to the item data.
92
fn lookup_item(item_id: int, data: @~[u8]) -> ebml::Doc {
93
    let items = reader::get_doc(reader::Doc(data), tag_items);
94
    match maybe_find_item(item_id, items) {
95
       None => fail!(fmt!("lookup_item: id not found: %d", item_id)),
B
Brian Anderson 已提交
96
       Some(d) => d
T
Tim Chevalier 已提交
97
    }
98 99
}

100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
enum Family {
    Const,                 // c
    Fn,                    // f
    UnsafeFn,              // u
    PureFn,                // p
    StaticMethod,          // F
    UnsafeStaticMethod,    // U
    PureStaticMethod,      // P
    ForeignFn,             // e
    Type,                  // y
    ForeignType,           // T
    Mod,                   // m
    ForeignMod,            // n
    Enum,                  // t
    Variant,               // v
    Impl,                  // i
    Trait,                 // I
    Struct,                // S
    PublicField,           // g
    PrivateField,          // j
    InheritedField         // N
}

123
impl cmp::Eq for Family {
124 125 126 127
    pure fn eq(&self, other: &Family) -> bool {
        ((*self) as uint) == ((*other) as uint)
    }
    pure fn ne(&self, other: &Family) -> bool { !(*self).eq(other) }
128
}
129

130
fn item_family(item: ebml::Doc) -> Family {
131 132
    let fam = reader::get_doc(item, tag_items_data_item_family);
    match reader::doc_as_u8(fam) as char {
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
      'c' => Const,
      'f' => Fn,
      'u' => UnsafeFn,
      'p' => PureFn,
      'F' => StaticMethod,
      'U' => UnsafeStaticMethod,
      'P' => PureStaticMethod,
      'e' => ForeignFn,
      'y' => Type,
      'T' => ForeignType,
      'm' => Mod,
      'n' => ForeignMod,
      't' => Enum,
      'v' => Variant,
      'i' => Impl,
      'I' => Trait,
      'S' => Struct,
      'g' => PublicField,
      'j' => PrivateField,
      'N' => InheritedField,
153
       c => fail!(fmt!("unexpected family char: %c", c))
154
    }
155 156
}

157
fn item_method_sort(item: ebml::Doc) -> char {
158 159
    for reader::tagged_docs(item, tag_item_trait_method_sort) |doc| {
        return str::from_bytes(reader::doc_data(doc))[0] as char;
160 161 162 163
    }
    return 'r';
}

164
fn item_symbol(item: ebml::Doc) -> ~str {
165 166
    let sym = reader::get_doc(item, tag_items_data_item_symbol);
    return str::from_bytes(reader::doc_data(sym));
167 168
}

169
fn item_parent_item(d: ebml::Doc) -> Option<ast::def_id> {
170 171
    for reader::tagged_docs(d, tag_items_data_parent_item) |did| {
        return Some(reader::with_doc_data(did, |d| parse_def_id(d)));
172
    }
B
Brian Anderson 已提交
173
    None
174 175
}

176 177 178
fn translated_parent_item_opt(cnum: ast::crate_num, d: ebml::Doc) ->
        Option<ast::def_id> {
    let trait_did_opt = item_parent_item(d);
179 180 181
    do trait_did_opt.map |trait_did| {
        ast::def_id { crate: cnum, node: trait_did.node }
    }
182 183
}

184 185 186
fn item_reqd_and_translated_parent_item(cnum: ast::crate_num,
                                        d: ebml::Doc) -> ast::def_id {
    let trait_did = item_parent_item(d).expect(~"item without parent");
187
    ast::def_id { crate: cnum, node: trait_did.node }
188 189
}

190
fn item_def_id(d: ebml::Doc, cdata: cmd) -> ast::def_id {
191 192
    let tagdoc = reader::get_doc(d, tag_def_id);
    return translate_def_id(cdata, reader::with_doc_data(tagdoc,
193
                                                    |d| parse_def_id(d)));
T
Tim Chevalier 已提交
194 195
}

196
fn each_reexport(d: ebml::Doc, f: fn(ebml::Doc) -> bool) {
197
    for reader::tagged_docs(d, tag_items_data_item_reexport) |reexport_doc| {
198 199 200 201 202 203
        if !f(reexport_doc) {
            return;
        }
    }
}

204
fn field_mutability(d: ebml::Doc) -> ast::struct_mutability {
205
    // Use maybe_get_doc in case it's a method
B
Brian Anderson 已提交
206
    option::map_default(
207 208
        &reader::maybe_get_doc(d, tag_struct_mut),
        ast::struct_immutable,
B
Brian Anderson 已提交
209
        |d| {
210
            match reader::doc_as_u8(*d) as char {
211 212
              'm' => ast::struct_mutable,
              _   => ast::struct_immutable
B
Brian Anderson 已提交
213 214
            }
        })
215 216
}

217
fn variant_disr_val(d: ebml::Doc) -> Option<int> {
218 219
    do option::chain(reader::maybe_get_doc(d, tag_disr_val)) |val_doc| {
        int::parse_bytes(reader::doc_data(val_doc), 10u)
220 221 222
    }
}

223
fn doc_type(doc: ebml::Doc, tcx: ty::ctxt, cdata: cmd) -> ty::t {
224
    let tp = reader::get_doc(doc, tag_items_data_item_type);
225 226
    parse_ty_data(tp.data, cdata.cnum, tp.start, tcx,
                  |_, did| translate_def_id(cdata, did))
227 228
}

229 230
pub fn item_type(item_id: ast::def_id, item: ebml::Doc,
                 tcx: ty::ctxt, cdata: cmd) -> ty::t {
231
    let t = doc_type(item, tcx, cdata);
232
    if family_names_type(item_family(item)) {
233
        ty::mk_with_id(tcx, t, item_id)
234 235 236
    } else {
        t
    }
237 238
}

239
fn item_impl_traits(item: ebml::Doc, tcx: ty::ctxt, cdata: cmd) -> ~[ty::t] {
240
    let mut results = ~[];
241
    for reader::tagged_docs(item, tag_impl_trait) |ity| {
242
        results.push(doc_type(ity, tcx, cdata));
243
    };
244
    results
245 246
}

247
fn item_ty_param_bounds(item: ebml::Doc, tcx: ty::ctxt, cdata: cmd)
248 249
    -> @~[ty::param_bounds] {
    let mut bounds = ~[];
250
    for reader::tagged_docs(item, tag_items_data_item_ty_param_bounds) |p| {
251 252
        let bd = parse_bounds_data(p.data, p.start, cdata.cnum, tcx,
                                   |_, did| translate_def_id(cdata, did));
253
        bounds.push(bd);
254
    }
255
    @bounds
256 257
}

258
fn item_ty_region_param(item: ebml::Doc) -> Option<ty::region_variance> {
259
    reader::maybe_get_doc(item, tag_region_param).map(|doc| {
260
        Decodable::decode(&reader::Decoder(*doc))
261
    })
262 263
}

264
fn item_ty_param_count(item: ebml::Doc) -> uint {
265
    let mut n = 0u;
266
    reader::tagged_docs(item, tag_items_data_item_ty_param_bounds,
267
                      |_p| { n += 1u; true } );
268 269 270
    n
}

271
fn enum_variant_ids(item: ebml::Doc, cdata: cmd) -> ~[ast::def_id] {
272
    let mut ids: ~[ast::def_id] = ~[];
M
Marijn Haverbeke 已提交
273
    let v = tag_items_data_item_variant;
274 275
    for reader::tagged_docs(item, v) |p| {
        let ext = reader::with_doc_data(p, |d| parse_def_id(d));
276
        ids.push(ast::def_id { crate: cdata.cnum, node: ext.node });
277
    };
B
Brian Anderson 已提交
278
    return ids;
279 280
}

281
fn item_path(intr: @ident_interner, item_doc: ebml::Doc) -> ast_map::path {
282
    let path_doc = reader::get_doc(item_doc, tag_path);
283

284 285
    let len_doc = reader::get_doc(path_doc, tag_path_len);
    let len = reader::doc_as_u32(len_doc) as uint;
286

287
    let mut result = vec::with_capacity(len);
288
    for reader::docs(path_doc) |tag, elt_doc| {
289
        if tag == tag_path_elt_mod {
290
            let str = reader::doc_as_str(elt_doc);
291
            result.push(ast_map::path_mod(intr.intern(@str)));
292
        } else if tag == tag_path_elt_name {
293
            let str = reader::doc_as_str(elt_doc);
294
            result.push(ast_map::path_name(intr.intern(@str)));
295 296 297 298 299
        } else {
            // ignore tag_path_len element
        }
    }

B
Brian Anderson 已提交
300
    return result;
301 302
}

303
fn item_name(intr: @ident_interner, item: ebml::Doc) -> ast::ident {
304 305
    let name = reader::get_doc(item, tag_paths_data_name);
    intr.intern(@str::from_bytes(reader::doc_data(name)))
306 307
}

308
fn item_to_def_like(item: ebml::Doc, did: ast::def_id, cnum: ast::crate_num)
309 310
    -> def_like
{
311 312
    let fam = item_family(item);
    match fam {
313
        Const     => dl_def(ast::def_const(did)),
314
        Struct    => dl_def(ast::def_struct(did)),
315 316 317 318 319
        UnsafeFn  => dl_def(ast::def_fn(did, ast::unsafe_fn)),
        Fn        => dl_def(ast::def_fn(did, ast::impure_fn)),
        PureFn    => dl_def(ast::def_fn(did, ast::pure_fn)),
        ForeignFn => dl_def(ast::def_fn(did, ast::extern_fn)),
        UnsafeStaticMethod => {
320 321
            let trait_did_opt = translated_parent_item_opt(cnum, item);
            dl_def(ast::def_static_method(did, trait_did_opt, ast::unsafe_fn))
322 323
        }
        StaticMethod => {
324 325
            let trait_did_opt = translated_parent_item_opt(cnum, item);
            dl_def(ast::def_static_method(did, trait_did_opt, ast::impure_fn))
326 327
        }
        PureStaticMethod => {
328 329
            let trait_did_opt = translated_parent_item_opt(cnum, item);
            dl_def(ast::def_static_method(did, trait_did_opt, ast::pure_fn))
330 331 332 333 334 335 336 337 338 339 340
        }
        Type | ForeignType => dl_def(ast::def_ty(did)),
        Mod => dl_def(ast::def_mod(did)),
        ForeignMod => dl_def(ast::def_foreign_mod(did)),
        Variant => {
            let enum_did = item_reqd_and_translated_parent_item(cnum, item);
            dl_def(ast::def_variant(enum_did, did))
        }
        Trait | Enum => dl_def(ast::def_ty(did)),
        Impl => dl_impl(did),
        PublicField | PrivateField | InheritedField => dl_field,
341
    }
342 343
}

344
pub fn lookup_def(cnum: ast::crate_num, data: @~[u8], did_: ast::def_id) ->
345 346
   ast::def {
    let item = lookup_item(did_.node, data);
347
    let did = ast::def_id { crate: cnum, node: did_.node };
348
    // We treat references to enums as references to types.
B
Brian Anderson 已提交
349
    return def_like_to_def(item_to_def_like(item, did, cnum));
350 351
}

352
pub fn get_type(cdata: cmd, id: ast::node_id, tcx: ty::ctxt)
353
    -> ty::ty_param_bounds_and_ty {
354

355
    let item = lookup_item(id, cdata.data);
356 357
    let t = item_type(ast::def_id { crate: cdata.cnum, node: id }, item, tcx,
                      cdata);
M
Marijn Haverbeke 已提交
358 359
    let tp_bounds = if family_has_type_params(item_family(item)) {
        item_ty_param_bounds(item, tcx, cdata)
360
    } else { @~[] };
361
    let rp = item_ty_region_param(item);
362 363 364
    return {bounds: tp_bounds,
            region_param: rp,
            ty: t};
365 366
}

367
pub fn get_region_param(cdata: cmd, id: ast::node_id)
B
Brian Anderson 已提交
368
    -> Option<ty::region_variance> {
369

370
    let item = lookup_item(id, cdata.data);
B
Brian Anderson 已提交
371
    return item_ty_region_param(item);
372 373
}

374
pub fn get_type_param_count(data: @~[u8], id: ast::node_id) -> uint {
375
    item_ty_param_count(lookup_item(id, data))
376 377
}

378 379
pub fn get_impl_traits(cdata: cmd, id: ast::node_id, tcx: ty::ctxt)
                    -> ~[ty::t] {
380
    item_impl_traits(lookup_item(id, cdata.data), tcx, cdata)
381 382
}

383 384
pub fn get_impl_method(intr: @ident_interner, cdata: cmd, id: ast::node_id,
                       name: ast::ident) -> ast::def_id {
385
    let items = reader::get_doc(reader::Doc(cdata.data), tag_items);
B
Brian Anderson 已提交
386
    let mut found = None;
387
    for reader::tagged_docs(find_item(id, items), tag_item_impl_method)
388
        |mid| {
389
            let m_did = reader::with_doc_data(mid, |d| parse_def_id(d));
390 391 392
            if item_name(intr, find_item(m_did.node, items)) == name {
                found = Some(translate_def_id(cdata, m_did));
            }
393
        }
B
Brian Anderson 已提交
394
    found.get()
395 396
}

397
pub fn struct_dtor(cdata: cmd, id: ast::node_id) -> Option<ast::def_id> {
398
    let items = reader::get_doc(reader::Doc(cdata.data), tag_items);
B
Brian Anderson 已提交
399
    let mut found = None;
400
    let cls_items = match maybe_find_item(id, items) {
B
Brian Anderson 已提交
401
            Some(it) => it,
402
            None     => fail!(fmt!("struct_dtor: class id not found \
P
Paul Stansifer 已提交
403
              when looking up dtor for %d", id))
404
    };
405 406 407
    for reader::tagged_docs(cls_items, tag_item_dtor) |doc| {
         let doc1 = reader::get_doc(doc, tag_def_id);
         let did = reader::with_doc_data(doc1, |d| parse_def_id(d));
B
Brian Anderson 已提交
408
         found = Some(translate_def_id(cdata, did));
409 410
    };
    found
411 412
}

413
pub fn get_symbol(data: @~[u8], id: ast::node_id) -> ~str {
B
Brian Anderson 已提交
414
    return item_symbol(lookup_item(id, data));
415 416
}

417
// Something that a name can resolve to.
418
pub enum def_like {
419 420 421 422 423 424
    dl_def(ast::def),
    dl_impl(ast::def_id),
    dl_field
}

fn def_like_to_def(def_like: def_like) -> ast::def {
425
    match def_like {
B
Brian Anderson 已提交
426
        dl_def(def) => return def,
427 428
        dl_impl(*) => fail!(~"found impl in def_like_to_def"),
        dl_field => fail!(~"found field in def_like_to_def")
429 430 431
    }
}

432
/// Iterates over the language items in the given crate.
433
pub fn each_lang_item(cdata: cmd, f: &fn(ast::node_id, uint) -> bool) {
434 435 436 437 438 439 440 441 442 443 444 445 446 447 448
    let root = reader::Doc(cdata.data);
    let lang_items = reader::get_doc(root, tag_lang_items);
    for reader::tagged_docs(lang_items, tag_lang_items_item) |item_doc| {
        let id_doc = reader::get_doc(item_doc, tag_lang_items_item_id);
        let id = reader::doc_as_u32(id_doc) as uint;
        let node_id_doc = reader::get_doc(item_doc,
                                          tag_lang_items_item_node_id);
        let node_id = reader::doc_as_u32(node_id_doc) as ast::node_id;

        if !f(node_id, id) {
            break;
        }
    }
}

449
/// Iterates over all the paths in the given crate.
450 451 452
pub fn each_path(intr: @ident_interner, cdata: cmd,
                 get_crate_data: GetCrateDataCb,
                 f: fn(&str, def_like) -> bool) {
453 454 455
    let root = reader::Doc(cdata.data);
    let items = reader::get_doc(root, tag_items);
    let items_data = reader::get_doc(items, tag_items_data);
456 457 458 459

    let mut broken = false;

    // First, go through all the explicit items.
460
    for reader::tagged_docs(items_data, tag_items_data_item) |item_doc| {
461
        if !broken {
P
Paul Stansifer 已提交
462 463
            let path = ast_map::path_to_str_with_sep(
                item_path(intr, item_doc), ~"::", intr);
464 465
            let path_is_empty = path.is_empty();
            if !path_is_empty {
466
                // Extract the def ID.
467
                let def_id = item_def_id(item_doc, cdata);
468 469

                // Construct the def for this item.
P
Paul Stansifer 已提交
470
                debug!("(each_path) yielding explicit item: %s", path);
471 472 473
                let def_like = item_to_def_like(item_doc, def_id, cdata.cnum);

                // Hand the information off to the iteratee.
474 475
                if !f(path, def_like) {
                    broken = true;      // FIXME #4572: This is awful.
476 477
                }
            }
478

479 480 481 482
            // If this is a module, find the reexports.
            for each_reexport(item_doc) |reexport_doc| {
                if !broken {
                    let def_id_doc =
483
                        reader::get_doc(reexport_doc,
484 485
                            tag_items_data_item_reexport_def_id);
                    let def_id =
486
                        reader::with_doc_data(def_id_doc,
487
                                              |d| parse_def_id(d));
488 489 490
                    let def_id = translate_def_id(cdata, def_id);

                    let reexport_name_doc =
491
                        reader::get_doc(reexport_doc,
492
                                      tag_items_data_item_reexport_name);
493
                    let reexport_name = reader::doc_as_str(reexport_name_doc);
494 495

                    let reexport_path;
496
                    if path_is_empty {
497 498 499 500
                        reexport_path = reexport_name;
                    } else {
                        reexport_path = path + ~"::" + reexport_name;
                    }
501

502 503 504 505 506
                    // This reexport may be in yet another crate
                    let other_crates_items = if def_id.crate == cdata.cnum {
                        items
                    } else {
                        let crate_data = get_crate_data(def_id.crate);
507 508
                        let root = reader::Doc(crate_data.data);
                        reader::get_doc(root, tag_items)
509 510
                    };

511
                    // Get the item.
512
                    match maybe_find_item(def_id.node, other_crates_items) {
B
Brian Anderson 已提交
513 514
                        None => {}
                        Some(item_doc) => {
515 516 517 518 519 520 521 522 523
                            // Construct the def for this item.
                            let def_like = item_to_def_like(item_doc,
                                                            def_id,
                                                            cdata.cnum);

                            // Hand the information off to the iteratee.
                            debug!("(each_path) yielding reexported \
                                    item: %s", reexport_path);

524 525
                            if (!f(reexport_path, def_like)) {
                                broken = true;  // FIXME #4572: This is awful.
526 527
                            }
                        }
528 529 530 531 532
                    }
                }
            }
        }
    }
533

534 535 536
    // If broken, stop here.
    if broken {
        return;
537
    }
538 539
}

540
pub fn get_item_path(intr: @ident_interner, cdata: cmd, id: ast::node_id)
P
Paul Stansifer 已提交
541 542
    -> ast_map::path {
    item_path(intr, lookup_item(id, cdata.data))
543 544
}

545
pub type decode_inlined_item = fn(
546 547 548
    cdata: cstore::crate_metadata,
    tcx: ty::ctxt,
    path: ast_map::path,
549
    par_doc: ebml::Doc) -> Option<ast::inlined_item>;
550

551 552 553 554
pub fn maybe_get_item_ast(intr: @ident_interner, cdata: cmd, tcx: ty::ctxt,
                          id: ast::node_id,
                          decode_inlined_item: decode_inlined_item)
                       -> csearch::found_ast {
P
Paul Stansifer 已提交
555
    debug!("Looking up item: %d", id);
556
    let item_doc = lookup_item(id, cdata.data);
P
Paul Stansifer 已提交
557
    let path = vec::init(item_path(intr, item_doc));
558
    match decode_inlined_item(cdata, tcx, path, item_doc) {
559
      Some(ref ii) => csearch::found((/*bad*/copy *ii)),
B
Brian Anderson 已提交
560
      None => {
561
        match item_parent_item(item_doc) {
B
Brian Anderson 已提交
562
          Some(did) => {
563 564
            let did = translate_def_id(cdata, did);
            let parent_item = lookup_item(did.node, cdata.data);
565
            match decode_inlined_item(cdata, tcx, path,
566
                                               parent_item) {
567
              Some(ref ii) => csearch::found_parent(did, (/*bad*/copy *ii)),
B
Brian Anderson 已提交
568
              None => csearch::not_found
569 570
            }
          }
B
Brian Anderson 已提交
571
          None => csearch::not_found
572 573 574
        }
      }
    }
575 576
}

577
pub fn get_enum_variants(intr: @ident_interner, cdata: cmd, id: ast::node_id,
578
                     tcx: ty::ctxt) -> ~[ty::VariantInfo] {
579
    let data = cdata.data;
580
    let items = reader::get_doc(reader::Doc(data), tag_items);
581
    let item = find_item(id, items);
582
    let mut infos: ~[ty::VariantInfo] = ~[];
583
    let variant_ids = enum_variant_ids(item, cdata);
584
    let mut disr_val = 0;
B
Brian Anderson 已提交
585
    for variant_ids.each |did| {
M
Marijn Haverbeke 已提交
586
        let item = find_item(did.node, items);
587 588
        let ctor_ty = item_type(ast::def_id { crate: cdata.cnum, node: id},
                                item, tcx, cdata);
P
Paul Stansifer 已提交
589
        let name = item_name(intr, item);
E
Erick Tryzelaar 已提交
590
        let arg_tys = match ty::get(ctor_ty).sty {
591 592
          ty::ty_bare_fn(ref f) => f.sig.inputs.map(|a| a.ty),
          _ => ~[], // Nullary enum variant.
E
Erick Tryzelaar 已提交
593
        };
594
        match variant_disr_val(item) {
B
Brian Anderson 已提交
595
          Some(val) => { disr_val = val; }
B
Brian Anderson 已提交
596
          _         => { /* empty */ }
597
        }
598 599 600 601 602
        infos.push(@ty::VariantInfo_{args: arg_tys,
                       ctor_ty: ctor_ty, name: name,
                  // I'm not even sure if we encode visibility
                  // for variants -- TEST -- tjc
                  id: *did, disr_val: disr_val, vis: ast::inherited});
603
        disr_val += 1;
604
    }
B
Brian Anderson 已提交
605
    return infos;
606 607
}

608
// NB: These types are duplicated in resolve.rs
609
pub type method_info = {
610 611 612 613 614 615
    did: ast::def_id,
    n_tps: uint,
    ident: ast::ident,
    self_type: ast::self_ty_
};

616 617 618 619 620
pub type _impl = {
    did: ast::def_id,
    ident: ast::ident,
    methods: ~[@method_info]
};
621

622
fn get_self_ty(item: ebml::Doc) -> ast::self_ty_ {
623
    fn get_mutability(ch: u8) -> ast::mutability {
624
        match ch as char {
625 626 627 628
            'i' => { ast::m_imm }
            'm' => { ast::m_mutbl }
            'c' => { ast::m_const }
            _ => {
629
                fail!(fmt!("unknown mutability character: `%c`", ch as char))
630 631 632 633
            }
        }
    }

634 635
    let self_type_doc = reader::get_doc(item, tag_item_trait_method_self_ty);
    let string = reader::doc_as_str(self_type_doc);
636 637

    let self_ty_kind = string[0];
638
    match self_ty_kind as char {
639
        's' => { return ast::sty_static; }
B
Brian Anderson 已提交
640 641 642 643
        'r' => { return ast::sty_by_ref; }
        'v' => { return ast::sty_value; }
        '@' => { return ast::sty_box(get_mutability(string[1])); }
        '~' => { return ast::sty_uniq(get_mutability(string[1])); }
644
        '&' => { return ast::sty_region(get_mutability(string[1])); }
645
        _ => {
646
            fail!(fmt!("unknown self type code: `%c`", self_ty_kind as char));
647 648 649 650
        }
    }
}

651
fn item_impl_methods(intr: @ident_interner, cdata: cmd, item: ebml::Doc,
P
Paul Stansifer 已提交
652
                     base_tps: uint) -> ~[@method_info] {
653
    let mut rslt = ~[];
654 655
    for reader::tagged_docs(item, tag_item_impl_method) |doc| {
        let m_did = reader::with_doc_data(doc, |d| parse_def_id(d));
656
        let mth_item = lookup_item(m_did.node, cdata.data);
657
        let self_ty = get_self_ty(mth_item);
658
        rslt.push(@{did: translate_def_id(cdata, m_did),
659
                   n_tps: item_ty_param_count(mth_item) - base_tps,
P
Paul Stansifer 已提交
660
                   ident: item_name(intr, mth_item),
661
                   self_type: self_ty});
662 663 664 665
    }
    rslt
}

666 667 668 669 670
pub fn get_impls_for_mod(intr: @ident_interner,
                         cdata: cmd,
                         m_id: ast::node_id,
                         name: Option<ast::ident>,
                         get_cdata: &fn(ast::crate_num) -> cmd)
671
                      -> @~[@_impl] {
672
    let data = cdata.data;
673
    let mod_item = lookup_item(m_id, data);
674
    let mut result = ~[];
675 676
    for reader::tagged_docs(mod_item, tag_mod_impl) |doc| {
        let did = reader::with_doc_data(doc, |d| parse_def_id(d));
677
        let local_did = translate_def_id(cdata, did);
P
Paul Stansifer 已提交
678 679
        debug!("(get impls for mod) getting did %? for '%?'",
               local_did, name);
680 681
          // The impl may be defined in a different crate. Ask the caller
          // to give us the metadata
682 683 684
        let impl_cdata = get_cdata(local_did.crate);
        let impl_data = impl_cdata.data;
        let item = lookup_item(local_did.node, impl_data);
P
Paul Stansifer 已提交
685
        let nm = item_name(intr, item);
B
Brian Anderson 已提交
686
        if match name { Some(n) => { n == nm } None => { true } } {
687
           let base_tps = item_ty_param_count(item);
688
           result.push(@{
689
                did: local_did, ident: nm,
P
Paul Stansifer 已提交
690
                methods: item_impl_methods(intr, impl_cdata, item, base_tps)
691
            });
692
        };
693 694 695 696
    }
    @result
}

697
/* Works for both classes and traits */
698 699
pub fn get_trait_methods(intr: @ident_interner, cdata: cmd, id: ast::node_id,
                         tcx: ty::ctxt) -> @~[ty::method] {
700
    let data = cdata.data;
701
    let item = lookup_item(id, data);
702
    let mut result = ~[];
703
    for reader::tagged_docs(item, tag_item_trait_method) |mth| {
M
Marijn Haverbeke 已提交
704
        let bounds = item_ty_param_bounds(mth, tcx, cdata);
P
Paul Stansifer 已提交
705
        let name = item_name(intr, mth);
706
        let ty = doc_type(mth, tcx, cdata);
707
        let def_id = item_def_id(mth, cdata);
708
        let fty = match ty::get(ty).sty {
709 710 711 712 713 714
            ty::ty_bare_fn(ref f) => copy *f,
            _ => {
                tcx.diag.handler().bug(
                    ~"get_trait_methods: id has non-function type");
            }
        };
715
        let self_ty = get_self_ty(mth);
716 717
        result.push({ident: name, tps: bounds, fty: fty, self_ty: self_ty,
                     vis: ast::public, def_id: def_id});
718
    }
719
    debug!("get_trait_methods: }");
720 721 722
    @result
}

723 724
pub fn get_provided_trait_methods(intr: @ident_interner, cdata: cmd,
                                  id: ast::node_id, tcx: ty::ctxt) ->
725 726 727 728 729
        ~[ProvidedTraitMethodInfo] {
    let data = cdata.data;
    let item = lookup_item(id, data);
    let mut result = ~[];

730
    for reader::tagged_docs(item, tag_item_trait_method) |mth| {
731 732 733 734 735 736 737 738
        if item_method_sort(mth) != 'p' { loop; }

        let did = item_def_id(mth, cdata);

        let bounds = item_ty_param_bounds(mth, tcx, cdata);
        let name = item_name(intr, mth);
        let ty = doc_type(mth, tcx, cdata);

739 740
        let fty = match ty::get(ty).sty {
            ty::ty_bare_fn(ref f) => copy *f,
741 742 743 744
            _ => {
                tcx.diag.handler().bug(~"get_provided_trait_methods(): id \
                                         has non-function type");
            }
745
        };
746 747 748 749 750 751 752 753 754 755 756 757 758 759 760

        let self_ty = get_self_ty(mth);
        let ty_method = {ident: name, tps: bounds, fty: fty, self_ty: self_ty,
                         vis: ast::public, def_id: did};
        let provided_trait_method_info = ProvidedTraitMethodInfo {
            ty: ty_method,
            def_id: did
        };

        vec::push(&mut result, move provided_trait_method_info);
    }

    return move result;
}

761
/// Returns the supertraits of the given trait.
762 763
pub fn get_supertraits(cdata: cmd, id: ast::node_id, tcx: ty::ctxt)
                    -> ~[ty::t] {
764 765
    let results = dvec::DVec();
    let item_doc = lookup_item(id, cdata.data);
766
    for reader::tagged_docs(item_doc, tag_impl_trait) |trait_doc| {
767 768 769 770 771
        results.push(doc_type(trait_doc, tcx, cdata));
    }
    return dvec::unwrap(move results);
}

772 773 774
// If the item in question is a trait, returns its set of methods and
// their self types. Otherwise, returns none. This overlaps in an
// annoying way with get_trait_methods.
775 776 777
pub fn get_method_names_if_trait(intr: @ident_interner, cdata: cmd,
                                 node_id: ast::node_id)
                              -> Option<@DVec<(ast::ident, ast::self_ty_)>> {
778 779

    let item = lookup_item(node_id, cdata.data);
780
    if item_family(item) != Trait {
B
Brian Anderson 已提交
781
        return None;
782 783
    }

784
    let resulting_methods = @DVec();
785
    for reader::tagged_docs(item, tag_item_trait_method) |method| {
786
        resulting_methods.push(
P
Paul Stansifer 已提交
787
            (item_name(intr, method), get_self_ty(method)));
788
    }
B
Brian Anderson 已提交
789
    return Some(resulting_methods);
790 791
}

792 793 794
pub fn get_type_name_if_impl(intr: @ident_interner,
                             cdata: cmd,
                             node_id: ast::node_id) -> Option<ast::ident> {
795 796 797 798 799
    let item = lookup_item(node_id, cdata.data);
    if item_family(item) != Impl {
        return None;
    }

800 801
    for reader::tagged_docs(item, tag_item_impl_type_basename) |doc| {
        return Some(intr.intern(@str::from_bytes(reader::doc_data(doc))));
802 803 804 805 806
    }

    return None;
}

807 808 809 810
pub fn get_static_methods_if_impl(intr: @ident_interner,
                                  cdata: cmd,
                                  node_id: ast::node_id)
                               -> Option<~[StaticMethodInfo]> {
811 812 813 814 815 816
    let item = lookup_item(node_id, cdata.data);
    if item_family(item) != Impl {
        return None;
    }

    // If this impl has a trait ref, don't consider it.
817
    for reader::tagged_docs(item, tag_impl_trait) |_doc| {
818 819 820 821
        return None;
    }

    let impl_method_ids = DVec();
822 823
    for reader::tagged_docs(item, tag_item_impl_method) |impl_method_doc| {
        impl_method_ids.push(parse_def_id(reader::doc_data(impl_method_doc)));
824 825 826 827 828 829 830 831 832 833 834 835 836
    }

    let static_impl_methods = DVec();
    for impl_method_ids.each |impl_method_id| {
        let impl_method_doc = lookup_item(impl_method_id.node, cdata.data);
        let family = item_family(impl_method_doc);
        match family {
            StaticMethod | UnsafeStaticMethod | PureStaticMethod => {
                let purity;
                match item_family(impl_method_doc) {
                    StaticMethod => purity = ast::impure_fn,
                    UnsafeStaticMethod => purity = ast::unsafe_fn,
                    PureStaticMethod => purity = ast::pure_fn,
837
                    _ => fail!()
838 839 840 841 842 843 844 845 846 847 848 849 850 851 852
                }

                static_impl_methods.push(StaticMethodInfo {
                    ident: item_name(intr, impl_method_doc),
                    def_id: item_def_id(impl_method_doc, cdata),
                    purity: purity
                });
            }
            _ => {}
        }
    }

    return Some(dvec::unwrap(move static_impl_methods));
}

853 854 855
pub fn get_item_attrs(cdata: cmd,
                      node_id: ast::node_id,
                      f: fn(~[@ast::meta_item])) {
856 857

    let item = lookup_item(node_id, cdata.data);
858 859
    for reader::tagged_docs(item, tag_attributes) |attributes| {
        for reader::tagged_docs(attributes, tag_attribute) |attribute| {
860 861 862 863 864
            f(get_meta_items(attribute));
        }
    }
}

865 866 867 868 869
pure fn family_to_visibility(family: Family) -> ast::visibility {
    match family {
      PublicField => ast::public,
      PrivateField => ast::private,
      InheritedField => ast::inherited,
870
      _ => fail!()
871 872 873
    }
}

874
pub fn get_struct_fields(intr: @ident_interner, cdata: cmd, id: ast::node_id)
875
    -> ~[ty::field_ty] {
T
Tim Chevalier 已提交
876
    let data = cdata.data;
877
    let item = lookup_item(id, data);
878
    let mut result = ~[];
879
    for reader::tagged_docs(item, tag_item_field) |an_item| {
880 881 882 883 884 885 886 887 888 889 890 891
        let f = item_family(an_item);
        if f == PublicField || f == PrivateField || f == InheritedField {
            let name = item_name(intr, an_item);
            let did = item_def_id(an_item, cdata);
            let mt = field_mutability(an_item);
            result.push(ty::field_ty {
                ident: name,
                id: did, vis:
                family_to_visibility(f),
                mutability: mt,
            });
        }
T
Tim Chevalier 已提交
892
    }
893 894 895 896 897 898 899 900 901
    for reader::tagged_docs(item, tag_item_unnamed_field) |an_item| {
        let did = item_def_id(an_item, cdata);
        result.push(ty::field_ty {
            ident: special_idents::unnamed_field,
            id: did,
            vis: ast::inherited,
            mutability: ast::struct_immutable,
        });
    }
T
Tim Chevalier 已提交
902 903 904
    result
}

905 906 907 908 909
fn family_has_type_params(fam: Family) -> bool {
    match fam {
      Const | ForeignType | Mod | ForeignMod | PublicField | PrivateField
      | ForeignFn => false,
      _           => true
910
    }
911 912
}

913 914
fn family_names_type(fam: Family) -> bool {
    match fam { Type | Mod | Trait => true, _ => false }
915 916
}

917
fn read_path(d: ebml::Doc) -> {path: ~str, pos: uint} {
918
    let desc = reader::doc_data(d);
919
    let pos = io::u64_from_be_bytes(desc, 0u, 4u) as uint;
920
    let pathbytes = vec::slice::<u8>(desc, 4u, vec::len::<u8>(desc));
921
    let path = str::from_bytes(pathbytes);
B
Brian Anderson 已提交
922
    return {path: path, pos: pos};
923 924
}

925
fn describe_def(items: ebml::Doc, id: ast::def_id) -> ~str {
B
Brian Anderson 已提交
926
    if id.crate != ast::local_crate { return ~"external"; }
927
    let it = match maybe_find_item(id.node, items) {
B
Brian Anderson 已提交
928
        Some(it) => it,
929
        None => fail!(fmt!("describe_def: item not found %?", id))
930
    };
B
Brian Anderson 已提交
931
    return item_family_to_str(item_family(it));
932 933
}

934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955
fn item_family_to_str(fam: Family) -> ~str {
    match fam {
      Const => ~"const",
      Fn => ~"fn",
      UnsafeFn => ~"unsafe fn",
      PureFn => ~"pure fn",
      StaticMethod => ~"static method",
      UnsafeStaticMethod => ~"unsafe static method",
      PureStaticMethod => ~"pure static method",
      ForeignFn => ~"foreign fn",
      Type => ~"type",
      ForeignType => ~"foreign type",
      Mod => ~"mod",
      ForeignMod => ~"foreign mod",
      Enum => ~"enum",
      Variant => ~"variant",
      Impl => ~"impl",
      Trait => ~"trait",
      Struct => ~"struct",
      PublicField => ~"public field",
      PrivateField => ~"private field",
      InheritedField => ~"inherited field",
956 957 958
    }
}

959
fn get_meta_items(md: ebml::Doc) -> ~[@ast::meta_item] {
960
    let mut items: ~[@ast::meta_item] = ~[];
961 962 963
    for reader::tagged_docs(md, tag_meta_item_word) |meta_item_doc| {
        let nd = reader::get_doc(meta_item_doc, tag_meta_item_name);
        let n = str::from_bytes(reader::doc_data(nd));
964
        items.push(attr::mk_word_item(n));
965
    };
966 967 968 969 970
    for reader::tagged_docs(md, tag_meta_item_name_value) |meta_item_doc| {
        let nd = reader::get_doc(meta_item_doc, tag_meta_item_name);
        let vd = reader::get_doc(meta_item_doc, tag_meta_item_value);
        let n = str::from_bytes(reader::doc_data(nd));
        let v = str::from_bytes(reader::doc_data(vd));
971 972
        // FIXME (#623): Should be able to decode meta_name_value variants,
        // but currently the encoder just drops them
973
        items.push(attr::mk_name_value_item_str(n, v));
974
    };
975 976 977
    for reader::tagged_docs(md, tag_meta_item_list) |meta_item_doc| {
        let nd = reader::get_doc(meta_item_doc, tag_meta_item_name);
        let n = str::from_bytes(reader::doc_data(nd));
M
Marijn Haverbeke 已提交
978
        let subitems = get_meta_items(meta_item_doc);
979
        items.push(attr::mk_list_item(n, subitems));
980
    };
B
Brian Anderson 已提交
981
    return items;
982 983
}

984
fn get_attributes(md: ebml::Doc) -> ~[ast::attribute] {
985
    let mut attrs: ~[ast::attribute] = ~[];
986
    match reader::maybe_get_doc(md, tag_attributes) {
B
Brian Anderson 已提交
987
      option::Some(attrs_d) => {
988
        for reader::tagged_docs(attrs_d, tag_attribute) |attr_doc| {
M
Marijn Haverbeke 已提交
989 990 991
            let meta_items = get_meta_items(attr_doc);
            // Currently it's only possible to have a single meta item on
            // an attribute
B
Brian Anderson 已提交
992
            assert (vec::len(meta_items) == 1u);
B
Brian Anderson 已提交
993
            let meta_item = meta_items[0];
994
            attrs.push(
J
John Clements 已提交
995
                codemap::spanned {
996 997 998 999 1000
                    node: ast::attribute_ {
                        style: ast::attr_outer,
                        value: /*bad*/copy *meta_item,
                        is_sugared_doc: false,
                    },
J
John Clements 已提交
1001
                    span: codemap::dummy_sp()
1002
                });
1003
        };
M
Marijn Haverbeke 已提交
1004
      }
B
Brian Anderson 已提交
1005
      option::None => ()
1006
    }
B
Brian Anderson 已提交
1007
    return attrs;
1008 1009
}

E
Erick Tryzelaar 已提交
1010
fn list_meta_items(intr: @ident_interner,
1011
                   meta_items: ebml::Doc, out: io::Writer) {
B
Brian Anderson 已提交
1012
    for get_meta_items(meta_items).each |mi| {
1013
        out.write_str(fmt!("%s\n", pprust::meta_item_to_str(*mi, intr)));
1014 1015 1016
    }
}

1017
fn list_crate_attributes(intr: @ident_interner, md: ebml::Doc, hash: ~str,
P
Paul Stansifer 已提交
1018
                         out: io::Writer) {
P
Paul Stansifer 已提交
1019
    out.write_str(fmt!("=Crate Attributes (%s)=\n", hash));
1020

B
Brian Anderson 已提交
1021
    for get_attributes(md).each |attr| {
1022
        out.write_str(fmt!("%s\n", pprust::attribute_to_str(*attr, intr)));
1023 1024
    }

1025
    out.write_str(~"\n\n");
1026 1027
}

1028
pub fn get_crate_attributes(data: @~[u8]) -> ~[ast::attribute] {
1029
    return get_attributes(reader::Doc(data));
1030 1031
}

1032 1033
pub type crate_dep = {cnum: ast::crate_num, name: ast::ident,
                      vers: ~str, hash: ~str};
M
Marijn Haverbeke 已提交
1034

1035
pub fn get_crate_deps(intr: @ident_interner, data: @~[u8]) -> ~[crate_dep] {
1036
    let mut deps: ~[crate_dep] = ~[];
1037 1038
    let cratedoc = reader::Doc(data);
    let depsdoc = reader::get_doc(cratedoc, tag_crate_deps);
1039
    let mut crate_num = 1;
1040
    fn docstr(doc: ebml::Doc, tag_: uint) -> ~str {
1041
        str::from_bytes(reader::doc_data(reader::get_doc(doc, tag_)))
1042
    }
1043
    for reader::tagged_docs(depsdoc, tag_crate_dep) |depdoc| {
1044
        deps.push({cnum: crate_num,
P
Paul Stansifer 已提交
1045 1046 1047
                  name: intr.intern(@docstr(depdoc, tag_crate_dep_name)),
                  vers: docstr(depdoc, tag_crate_dep_vers),
                  hash: docstr(depdoc, tag_crate_dep_hash)});
1048
        crate_num += 1;
1049
    };
B
Brian Anderson 已提交
1050
    return deps;
1051 1052
}

E
Erick Tryzelaar 已提交
1053
fn list_crate_deps(intr: @ident_interner, data: @~[u8], out: io::Writer) {
1054
    out.write_str(~"=External Dependencies=\n");
1055

P
Paul Stansifer 已提交
1056 1057
    for get_crate_deps(intr, data).each |dep| {
        out.write_str(
P
Paul Stansifer 已提交
1058 1059
            fmt!("%d %s-%s-%s\n",
                 dep.cnum, *intr.get(dep.name), dep.hash, dep.vers));
1060 1061
    }

1062
    out.write_str(~"\n");
1063 1064
}

1065
pub fn get_crate_hash(data: @~[u8]) -> ~str {
1066 1067 1068
    let cratedoc = reader::Doc(data);
    let hashdoc = reader::get_doc(cratedoc, tag_crate_hash);
    return str::from_bytes(reader::doc_data(hashdoc));
H
Haitao Li 已提交
1069 1070
}

1071
pub fn get_crate_vers(data: @~[u8]) -> ~str {
1072
    let attrs = decoder::get_crate_attributes(data);
1073
    return match attr::last_meta_item_value_str_by_name(
1074
        attr::find_linkage_metas(attrs), ~"vers") {
1075
      Some(ref ver) => (/*bad*/copy *ver),
B
Brian Anderson 已提交
1076
      None => ~"0.0"
1077 1078 1079
    };
}

1080 1081
fn iter_crate_items(intr: @ident_interner, cdata: cmd,
                    get_crate_data: GetCrateDataCb,
1082 1083 1084
                    proc: fn(path: &str, ast::def_id)) {
    for each_path(intr, cdata, get_crate_data) |path_string, def_like| {
        match def_like {
1085 1086
            dl_impl(*) | dl_field => {}
            dl_def(def) => {
1087
                proc(path_string,
1088
                     ast_util::def_id_of_def(def))
1089 1090
            }
        }
1091 1092 1093
    }
}

1094 1095
pub fn list_crate_metadata(intr: @ident_interner, bytes: @~[u8],
                           out: io::Writer) {
H
Haitao Li 已提交
1096
    let hash = get_crate_hash(bytes);
1097
    let md = reader::Doc(bytes);
P
Paul Stansifer 已提交
1098 1099
    list_crate_attributes(intr, md, hash, out);
    list_crate_deps(intr, bytes, out);
1100 1101
}

1102 1103 1104 1105 1106
// Translates a def_id from an external crate to a def_id for the current
// compilation environment. We use this when trying to load types from
// external crates - if those types further refer to types in other crates
// then we must translate the crate number from that encoded in the external
// crate to the correct local crate number.
1107
pub fn translate_def_id(cdata: cmd, did: ast::def_id) -> ast::def_id {
1108
    if did.crate == ast::local_crate {
1109
        return ast::def_id { crate: cdata.cnum, node: did.node };
1110 1111
    }

1112
    match cdata.cnum_map.find(&did.crate) {
1113
      option::Some(n) => ast::def_id { crate: n, node: did.node },
1114
      option::None => fail!(~"didn't find a crate in the cnum_map")
1115 1116 1117
    }
}

1118 1119 1120 1121 1122 1123 1124
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End: