decoder.rs 38.2 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
use metadata::cstore::crate_metadata;
17 18 19 20 21
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
use metadata::tydecode::{parse_ty_data, parse_def_id, parse_bounds_data};
use metadata::tydecode::{parse_ident};
27
use middle::{ty, resolve};
28 29
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
type cmd = @crate_metadata;

52 53 54 55 56
// 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 已提交
57

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

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

76 77
pub type GetCrateDataCb = &fn(ast::crate_num) -> cmd;

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

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

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

103
#[deriving_eq]
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
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
}

127
fn item_family(item: ebml::Doc) -> Family {
128 129
    let fam = reader::get_doc(item, tag_items_data_item_family);
    match reader::doc_as_u8(fam) as char {
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
      '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,
150
       c => fail!(fmt!("unexpected family char: %c", c))
151
    }
152 153
}

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

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

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

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

181 182 183
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");
184
    ast::def_id { crate: cnum, node: trait_did.node }
185 186
}

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

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

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

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

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

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

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

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

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

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

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

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

281 282
    let len_doc = reader::get_doc(path_doc, tag_path_len);
    let len = reader::doc_as_u32(len_doc) as uint;
283

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

B
Brian Anderson 已提交
297
    return result;
298 299
}

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

305
fn item_to_def_like(item: ebml::Doc, did: ast::def_id, cnum: ast::crate_num)
306 307
    -> def_like
{
308 309
    let fam = item_family(item);
    match fam {
310
        Const     => dl_def(ast::def_const(did)),
311
        Struct    => dl_def(ast::def_struct(did)),
312 313 314 315 316
        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 => {
317 318
            let trait_did_opt = translated_parent_item_opt(cnum, item);
            dl_def(ast::def_static_method(did, trait_did_opt, ast::unsafe_fn))
319 320
        }
        StaticMethod => {
321 322
            let trait_did_opt = translated_parent_item_opt(cnum, item);
            dl_def(ast::def_static_method(did, trait_did_opt, ast::impure_fn))
323 324
        }
        PureStaticMethod => {
325 326
            let trait_did_opt = translated_parent_item_opt(cnum, item);
            dl_def(ast::def_static_method(did, trait_did_opt, ast::pure_fn))
327 328 329 330 331 332 333 334 335 336 337
        }
        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,
338
    }
339 340
}

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

349
pub fn get_type(cdata: cmd, id: ast::node_id, tcx: ty::ctxt)
350
    -> ty::ty_param_bounds_and_ty {
351

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

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

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

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

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

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

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

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

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

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

431
/// Iterates over the language items in the given crate.
432
pub fn each_lang_item(cdata: cmd, f: &fn(ast::node_id, uint) -> bool) {
433 434 435 436 437 438 439 440 441 442 443 444 445 446 447
    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;
        }
    }
}

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

    let mut broken = false;

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

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

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

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

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

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

501 502 503 504 505
                    // 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);
506 507
                        let root = reader::Doc(crate_data.data);
                        reader::get_doc(root, tag_items)
508 509
                    };

510
                    // Get the item.
511
                    match maybe_find_item(def_id.node, other_crates_items) {
B
Brian Anderson 已提交
512 513
                        None => {}
                        Some(item_doc) => {
514 515 516 517 518 519 520 521 522
                            // 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);

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

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

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

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

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

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

607
fn get_self_ty(item: ebml::Doc) -> ast::self_ty_ {
608
    fn get_mutability(ch: u8) -> ast::mutability {
609
        match ch as char {
610 611 612 613
            'i' => { ast::m_imm }
            'm' => { ast::m_mutbl }
            'c' => { ast::m_const }
            _ => {
614
                fail!(fmt!("unknown mutability character: `%c`", ch as char))
615 616 617 618
            }
        }
    }

619 620
    let self_type_doc = reader::get_doc(item, tag_item_trait_method_self_ty);
    let string = reader::doc_as_str(self_type_doc);
621 622

    let self_ty_kind = string[0];
623
    match self_ty_kind as char {
624
        's' => { return ast::sty_static; }
B
Brian Anderson 已提交
625 626 627 628
        '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])); }
629
        '&' => { return ast::sty_region(get_mutability(string[1])); }
630
        _ => {
631
            fail!(fmt!("unknown self type code: `%c`", self_ty_kind as char));
632 633 634 635
        }
    }
}

636
fn item_impl_methods(intr: @ident_interner, cdata: cmd, item: ebml::Doc,
637
                     base_tps: uint) -> ~[@resolve::MethodInfo] {
638
    let mut rslt = ~[];
639 640
    for reader::tagged_docs(item, tag_item_impl_method) |doc| {
        let m_did = reader::with_doc_data(doc, |d| parse_def_id(d));
641
        let mth_item = lookup_item(m_did.node, cdata.data);
642
        let self_ty = get_self_ty(mth_item);
643 644 645 646 647
        rslt.push(@resolve::MethodInfo {
                    did: translate_def_id(cdata, m_did),
                    n_tps: item_ty_param_count(mth_item) - base_tps,
                    ident: item_name(intr, mth_item),
                    self_type: self_ty});
648 649 650 651
    }
    rslt
}

652 653 654 655 656
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)
657
                      -> @~[@resolve::Impl] {
658
    let data = cdata.data;
659
    let mod_item = lookup_item(m_id, data);
660
    let mut result = ~[];
661 662
    for reader::tagged_docs(mod_item, tag_mod_impl) |doc| {
        let did = reader::with_doc_data(doc, |d| parse_def_id(d));
663
        let local_did = translate_def_id(cdata, did);
P
Paul Stansifer 已提交
664 665
        debug!("(get impls for mod) getting did %? for '%?'",
               local_did, name);
666 667
          // The impl may be defined in a different crate. Ask the caller
          // to give us the metadata
668 669 670
        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 已提交
671
        let nm = item_name(intr, item);
B
Brian Anderson 已提交
672
        if match name { Some(n) => { n == nm } None => { true } } {
673
           let base_tps = item_ty_param_count(item);
674
           result.push(@resolve::Impl {
675
                did: local_did, ident: nm,
P
Paul Stansifer 已提交
676
                methods: item_impl_methods(intr, impl_cdata, item, base_tps)
677
            });
678
        };
679 680 681 682
    }
    @result
}

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

715 716
pub fn get_provided_trait_methods(intr: @ident_interner, cdata: cmd,
                                  id: ast::node_id, tcx: ty::ctxt) ->
717 718 719 720 721
        ~[ProvidedTraitMethodInfo] {
    let data = cdata.data;
    let item = lookup_item(id, data);
    let mut result = ~[];

722
    for reader::tagged_docs(item, tag_item_trait_method) |mth| {
723 724 725 726 727 728 729 730
        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);

731 732
        let fty = match ty::get(ty).sty {
            ty::ty_bare_fn(ref f) => copy *f,
733 734 735 736
            _ => {
                tcx.diag.handler().bug(~"get_provided_trait_methods(): id \
                                         has non-function type");
            }
737
        };
738 739

        let self_ty = get_self_ty(mth);
740 741 742 743 744 745 746 747
        let ty_method = ty::method {
            ident: name,
            tps: bounds,
            fty: fty,
            self_ty: self_ty,
            vis: ast::public,
            def_id: did
        };
748 749 750 751 752
        let provided_trait_method_info = ProvidedTraitMethodInfo {
            ty: ty_method,
            def_id: did
        };

L
Luqman Aden 已提交
753
        vec::push(&mut result, provided_trait_method_info);
754 755
    }

L
Luqman Aden 已提交
756
    return result;
757 758
}

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

770 771 772
// 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.
773 774 775
pub fn get_method_names_if_trait(intr: @ident_interner, cdata: cmd,
                                 node_id: ast::node_id)
                              -> Option<@DVec<(ast::ident, ast::self_ty_)>> {
776 777

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

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

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

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

    return None;
}

805 806 807 808
pub fn get_static_methods_if_impl(intr: @ident_interner,
                                  cdata: cmd,
                                  node_id: ast::node_id)
                               -> Option<~[StaticMethodInfo]> {
809 810 811 812 813 814
    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.
815
    for reader::tagged_docs(item, tag_impl_trait) |_doc| {
816 817 818 819
        return None;
    }

    let impl_method_ids = DVec();
820 821
    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)));
822 823 824 825 826 827 828 829 830 831 832 833 834
    }

    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,
835
                    _ => fail!()
836 837 838 839 840 841 842 843 844 845 846 847
                }

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

L
Luqman Aden 已提交
848
    return Some(dvec::unwrap(static_impl_methods));
849 850
}

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

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

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

872
pub fn get_struct_fields(intr: @ident_interner, cdata: cmd, id: ast::node_id)
873
    -> ~[ty::field_ty] {
T
Tim Chevalier 已提交
874
    let data = cdata.data;
875
    let item = lookup_item(id, data);
876
    let mut result = ~[];
877
    for reader::tagged_docs(item, tag_item_field) |an_item| {
878 879 880 881 882 883 884 885 886 887 888 889
        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 已提交
890
    }
891 892 893 894 895 896 897 898 899
    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 已提交
900 901 902
    result
}

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

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

915
fn read_path(d: ebml::Doc) -> (~str, uint) {
916
    let desc = reader::doc_data(d);
917
    let pos = io::u64_from_be_bytes(desc, 0u, 4u) as uint;
918
    let pathbytes = vec::slice::<u8>(desc, 4u, vec::len::<u8>(desc));
919
    let path = str::from_bytes(pathbytes);
920 921

    (path, pos)
922 923
}

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

933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954
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",
955 956 957
    }
}

958
fn get_meta_items(md: ebml::Doc) -> ~[@ast::meta_item] {
959
    let mut items: ~[@ast::meta_item] = ~[];
960 961 962
    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));
963
        items.push(attr::mk_word_item(@n));
964
    };
965 966 967 968 969
    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));
970 971
        // FIXME (#623): Should be able to decode meta_name_value variants,
        // but currently the encoder just drops them
972
        items.push(attr::mk_name_value_item_str(@n, @v));
973
    };
974 975 976
    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 已提交
977
        let subitems = get_meta_items(meta_item_doc);
978
        items.push(attr::mk_list_item(@n, subitems));
979
    };
B
Brian Anderson 已提交
980
    return items;
981 982
}

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

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

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

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

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

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

1031 1032 1033 1034 1035 1036
pub struct crate_dep {
    cnum: ast::crate_num,
    name: ast::ident,
    vers: @~str,
    hash: @~str
}
M
Marijn Haverbeke 已提交
1037

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

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

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

1065
    out.write_str(~"\n");
1066 1067
}

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

1074
pub fn get_crate_vers(data: @~[u8]) -> @~str {
1075
    let attrs = decoder::get_crate_attributes(data);
E
Erick Tryzelaar 已提交
1076 1077 1078
    let linkage_attrs = attr::find_linkage_metas(attrs);

    match attr::last_meta_item_value_str_by_name(linkage_attrs, ~"vers") {
1079 1080
        Some(ver) => ver,
        None => @~"0.0"
E
Erick Tryzelaar 已提交
1081
    }
1082 1083
}

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

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

1106 1107 1108 1109 1110
// 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.
1111
pub fn translate_def_id(cdata: cmd, did: ast::def_id) -> ast::def_id {
1112
    if did.crate == ast::local_crate {
1113
        return ast::def_id { crate: cdata.cnum, node: did.node };
1114 1115
    }

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

1122 1123 1124 1125 1126 1127 1128
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End: