decoder.rs 38.9 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
use metadata::common::*;
use metadata::csearch::{ProvidedTraitMethodInfo, StaticMethodInfo};
19 20 21
use metadata::csearch;
use metadata::cstore;
use metadata::decoder;
22
use metadata::tydecode::{parse_ty_data, parse_def_id, parse_bounds_data};
23
use middle::{ty, resolve};
24

25
use core::hash::{Hash, HashUtil};
26
use core::int;
27
use core::io::WriterUtil;
28 29 30 31 32
use core::io;
use core::option;
use core::str;
use core::vec;
use std::ebml::reader;
33
use std::ebml;
34
use std::serialize::Decodable;
P
Patrick Walton 已提交
35
use syntax::ast_map;
36
use syntax::attr;
P
Patrick Walton 已提交
37
use syntax::diagnostic::span_handler;
38
use syntax::parse::token::{ident_interner, special_idents};
39 40
use syntax::print::pprust;
use syntax::{ast, ast_util};
J
John Clements 已提交
41
use syntax::codemap;
42

43 44
type cmd = @crate_metadata;

45 46 47 48 49
// 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 已提交
50

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

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

69
pub type GetCrateDataCb = &self/fn(ast::crate_num) -> cmd;
70

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

82
fn find_item(item_id: int, items: ebml::Doc) -> ebml::Doc {
B
Brian Anderson 已提交
83
    return maybe_find_item(item_id, items).get();
84 85
}

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

96
#[deriving_eq]
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
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
}

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

147 148 149 150 151 152 153 154 155 156
fn item_visibility(item: ebml::Doc) -> ast::visibility {
    let visibility = reader::get_doc(item, tag_items_data_item_visibility);
    match reader::doc_as_u8(visibility) as char {
        'y' => ast::public,
        'n' => ast::private,
        'i' => ast::inherited,
        _ => fail!(~"unknown visibility character"),
    }
}

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 365 366
    ty::ty_param_bounds_and_ty {
        bounds: tp_bounds,
        region_param: rp,
        ty: t
    }
367 368
}

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

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

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

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

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

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

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

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

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

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

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

    let mut broken = false;

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

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

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

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

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

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

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

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

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

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

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

547
pub type decode_inlined_item = &self/fn(
548
    cdata: @cstore::crate_metadata,
549 550
    tcx: ty::ctxt,
    path: ast_map::path,
551
    par_doc: ebml::Doc) -> Option<ast::inlined_item>;
552

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

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

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

624 625
    let self_type_doc = reader::get_doc(item, tag_item_trait_method_self_ty);
    let string = reader::doc_as_str(self_type_doc);
626 627

    let self_ty_kind = string[0];
628
    match self_ty_kind as char {
629
        's' => { return ast::sty_static; }
B
Brian Anderson 已提交
630 631 632 633
        '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])); }
634 635 636 637
        '&' => {
            // FIXME(#4846) expl. region
            return ast::sty_region(None, get_mutability(string[1]));
        }
638
        _ => {
639
            fail!(fmt!("unknown self type code: `%c`", self_ty_kind as char));
640 641 642 643
        }
    }
}

644
fn item_impl_methods(intr: @ident_interner, cdata: cmd, item: ebml::Doc,
645
                     base_tps: uint) -> ~[@resolve::MethodInfo] {
646
    let mut rslt = ~[];
647 648
    for reader::tagged_docs(item, tag_item_impl_method) |doc| {
        let m_did = reader::with_doc_data(doc, |d| parse_def_id(d));
649
        let mth_item = lookup_item(m_did.node, cdata.data);
650
        let self_ty = get_self_ty(mth_item);
651 652 653 654 655
        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});
656 657 658 659
    }
    rslt
}

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

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

        let self_ty = get_self_ty(mth);
748 749 750 751 752 753 754 755
        let ty_method = ty::method {
            ident: name,
            tps: bounds,
            fty: fty,
            self_ty: self_ty,
            vis: ast::public,
            def_id: did
        };
756 757 758 759 760
        let provided_trait_method_info = ProvidedTraitMethodInfo {
            ty: ty_method,
            def_id: did
        };

L
Luqman Aden 已提交
761
        vec::push(&mut result, provided_trait_method_info);
762 763
    }

L
Luqman Aden 已提交
764
    return result;
765 766
}

767
/// Returns the supertraits of the given trait.
768 769
pub fn get_supertraits(cdata: cmd, id: ast::node_id, tcx: ty::ctxt)
                    -> ~[ty::t] {
A
Alex Crichton 已提交
770
    let mut results = ~[];
771
    let item_doc = lookup_item(id, cdata.data);
772
    for reader::tagged_docs(item_doc, tag_impl_trait) |trait_doc| {
773 774
        results.push(doc_type(trait_doc, tcx, cdata));
    }
A
Alex Crichton 已提交
775
    return results;
776 777
}

778 779 780
// 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.
781 782
pub fn get_method_names_if_trait(intr: @ident_interner, cdata: cmd,
                                 node_id: ast::node_id)
A
Alex Crichton 已提交
783
                              -> Option<~[(ast::ident, ast::self_ty_)]> {
784 785

    let item = lookup_item(node_id, cdata.data);
786
    if item_family(item) != Trait {
B
Brian Anderson 已提交
787
        return None;
788 789
    }

A
Alex Crichton 已提交
790
    let mut resulting_methods = ~[];
791
    for reader::tagged_docs(item, tag_item_trait_method) |method| {
792
        resulting_methods.push(
P
Paul Stansifer 已提交
793
            (item_name(intr, method), get_self_ty(method)));
794
    }
B
Brian Anderson 已提交
795
    return Some(resulting_methods);
796 797
}

798 799 800
pub fn get_type_name_if_impl(intr: @ident_interner,
                             cdata: cmd,
                             node_id: ast::node_id) -> Option<ast::ident> {
801 802 803 804 805
    let item = lookup_item(node_id, cdata.data);
    if item_family(item) != Impl {
        return None;
    }

806 807
    for reader::tagged_docs(item, tag_item_impl_type_basename) |doc| {
        return Some(intr.intern(@str::from_bytes(reader::doc_data(doc))));
808 809 810 811 812
    }

    return None;
}

813 814 815 816
pub fn get_static_methods_if_impl(intr: @ident_interner,
                                  cdata: cmd,
                                  node_id: ast::node_id)
                               -> Option<~[StaticMethodInfo]> {
817 818 819 820 821 822
    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.
823
    for reader::tagged_docs(item, tag_impl_trait) |_doc| {
824 825 826
        return None;
    }

A
Alex Crichton 已提交
827
    let mut impl_method_ids = ~[];
828 829
    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)));
830 831
    }

A
Alex Crichton 已提交
832
    let mut static_impl_methods = ~[];
833 834 835 836 837 838 839 840 841 842
    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,
843
                    _ => fail!()
844 845 846 847 848 849 850 851 852 853 854 855
                }

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

A
Alex Crichton 已提交
856
    return Some(static_impl_methods);
857 858
}

859 860
pub fn get_item_attrs(cdata: cmd,
                      node_id: ast::node_id,
861
                      f: &fn(~[@ast::meta_item])) {
862 863

    let item = lookup_item(node_id, cdata.data);
864 865
    for reader::tagged_docs(item, tag_attributes) |attributes| {
        for reader::tagged_docs(attributes, tag_attribute) |attribute| {
866 867 868 869 870
            f(get_meta_items(attribute));
        }
    }
}

871
pure fn struct_field_family_to_visibility(family: Family) -> ast::visibility {
872 873 874 875
    match family {
      PublicField => ast::public,
      PrivateField => ast::private,
      InheritedField => ast::inherited,
876
      _ => fail!()
877 878 879
    }
}

880
pub fn get_struct_fields(intr: @ident_interner, cdata: cmd, id: ast::node_id)
881
    -> ~[ty::field_ty] {
T
Tim Chevalier 已提交
882
    let data = cdata.data;
883
    let item = lookup_item(id, data);
884
    let mut result = ~[];
885
    for reader::tagged_docs(item, tag_item_field) |an_item| {
886 887 888 889 890 891 892 893
        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:
894
                struct_field_family_to_visibility(f),
895 896 897
                mutability: mt,
            });
        }
T
Tim Chevalier 已提交
898
    }
899 900 901 902 903 904 905 906 907
    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 已提交
908 909 910
    result
}

911 912 913 914 915
pub fn get_method_visibility(cdata: cmd, id: ast::node_id)
                          -> ast::visibility {
    item_visibility(lookup_item(id, cdata.data))
}

916 917 918 919 920
fn family_has_type_params(fam: Family) -> bool {
    match fam {
      Const | ForeignType | Mod | ForeignMod | PublicField | PrivateField
      | ForeignFn => false,
      _           => true
921
    }
922 923
}

924 925
fn family_names_type(fam: Family) -> bool {
    match fam { Type | Mod | Trait => true, _ => false }
926 927
}

928
fn read_path(d: ebml::Doc) -> (~str, uint) {
929
    let desc = reader::doc_data(d);
930
    let pos = io::u64_from_be_bytes(desc, 0u, 4u) as uint;
931
    let pathbytes = vec::slice::<u8>(desc, 4u, vec::len::<u8>(desc));
932
    let path = str::from_bytes(pathbytes);
933 934

    (path, pos)
935 936
}

937
fn describe_def(items: ebml::Doc, id: ast::def_id) -> ~str {
B
Brian Anderson 已提交
938
    if id.crate != ast::local_crate { return ~"external"; }
939
    let it = match maybe_find_item(id.node, items) {
B
Brian Anderson 已提交
940
        Some(it) => it,
941
        None => fail!(fmt!("describe_def: item not found %?", id))
942
    };
B
Brian Anderson 已提交
943
    return item_family_to_str(item_family(it));
944 945
}

946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967
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",
968 969 970
    }
}

971
fn get_meta_items(md: ebml::Doc) -> ~[@ast::meta_item] {
972
    let mut items: ~[@ast::meta_item] = ~[];
973 974 975
    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));
976
        items.push(attr::mk_word_item(@n));
977
    };
978 979 980 981 982
    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));
983 984
        // FIXME (#623): Should be able to decode meta_name_value variants,
        // but currently the encoder just drops them
985
        items.push(attr::mk_name_value_item_str(@n, @v));
986
    };
987 988 989
    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 已提交
990
        let subitems = get_meta_items(meta_item_doc);
991
        items.push(attr::mk_list_item(@n, subitems));
992
    };
B
Brian Anderson 已提交
993
    return items;
994 995
}

996
fn get_attributes(md: ebml::Doc) -> ~[ast::attribute] {
997
    let mut attrs: ~[ast::attribute] = ~[];
998
    match reader::maybe_get_doc(md, tag_attributes) {
B
Brian Anderson 已提交
999
      option::Some(attrs_d) => {
1000
        for reader::tagged_docs(attrs_d, tag_attribute) |attr_doc| {
M
Marijn Haverbeke 已提交
1001 1002 1003
            let meta_items = get_meta_items(attr_doc);
            // Currently it's only possible to have a single meta item on
            // an attribute
1004
            fail_unless!((vec::len(meta_items) == 1u));
B
Brian Anderson 已提交
1005
            let meta_item = meta_items[0];
1006
            attrs.push(
J
John Clements 已提交
1007
                codemap::spanned {
1008 1009
                    node: ast::attribute_ {
                        style: ast::attr_outer,
1010
                        value: meta_item,
1011 1012
                        is_sugared_doc: false,
                    },
J
John Clements 已提交
1013
                    span: codemap::dummy_sp()
1014
                });
1015
        };
M
Marijn Haverbeke 已提交
1016
      }
B
Brian Anderson 已提交
1017
      option::None => ()
1018
    }
B
Brian Anderson 已提交
1019
    return attrs;
1020 1021
}

E
Erick Tryzelaar 已提交
1022
fn list_meta_items(intr: @ident_interner,
1023 1024
                   meta_items: ebml::Doc,
                   out: @io::Writer) {
B
Brian Anderson 已提交
1025
    for get_meta_items(meta_items).each |mi| {
1026
        out.write_str(fmt!("%s\n", pprust::meta_item_to_str(*mi, intr)));
1027 1028 1029
    }
}

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

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

1038
    out.write_str(~"\n\n");
1039 1040
}

1041
pub fn get_crate_attributes(data: @~[u8]) -> ~[ast::attribute] {
1042
    return get_attributes(reader::Doc(data));
1043 1044
}

1045 1046 1047 1048 1049 1050
pub struct crate_dep {
    cnum: ast::crate_num,
    name: ast::ident,
    vers: @~str,
    hash: @~str
}
M
Marijn Haverbeke 已提交
1051

1052
pub fn get_crate_deps(intr: @ident_interner, data: @~[u8]) -> ~[crate_dep] {
1053
    let mut deps: ~[crate_dep] = ~[];
1054 1055
    let cratedoc = reader::Doc(data);
    let depsdoc = reader::get_doc(cratedoc, tag_crate_deps);
1056
    let mut crate_num = 1;
1057
    fn docstr(doc: ebml::Doc, tag_: uint) -> ~str {
1058
        str::from_bytes(reader::doc_data(reader::get_doc(doc, tag_)))
1059
    }
1060
    for reader::tagged_docs(depsdoc, tag_crate_dep) |depdoc| {
1061
        deps.push(crate_dep {cnum: crate_num,
P
Paul Stansifer 已提交
1062
                  name: intr.intern(@docstr(depdoc, tag_crate_dep_name)),
1063 1064
                  vers: @docstr(depdoc, tag_crate_dep_vers),
                  hash: @docstr(depdoc, tag_crate_dep_hash)});
1065
        crate_num += 1;
1066
    };
B
Brian Anderson 已提交
1067
    return deps;
1068 1069
}

1070
fn list_crate_deps(intr: @ident_interner, data: @~[u8], out: @io::Writer) {
1071
    out.write_str(~"=External Dependencies=\n");
1072

P
Paul Stansifer 已提交
1073 1074
    for get_crate_deps(intr, data).each |dep| {
        out.write_str(
P
Paul Stansifer 已提交
1075
            fmt!("%d %s-%s-%s\n",
1076
                 dep.cnum, *intr.get(dep.name), *dep.hash, *dep.vers));
1077 1078
    }

1079
    out.write_str(~"\n");
1080 1081
}

1082
pub fn get_crate_hash(data: @~[u8]) -> @~str {
1083 1084
    let cratedoc = reader::Doc(data);
    let hashdoc = reader::get_doc(cratedoc, tag_crate_hash);
1085
    @str::from_bytes(reader::doc_data(hashdoc))
H
Haitao Li 已提交
1086 1087
}

1088
pub fn get_crate_vers(data: @~[u8]) -> @~str {
1089
    let attrs = decoder::get_crate_attributes(data);
E
Erick Tryzelaar 已提交
1090 1091 1092
    let linkage_attrs = attr::find_linkage_metas(attrs);

    match attr::last_meta_item_value_str_by_name(linkage_attrs, ~"vers") {
1093 1094
        Some(ver) => ver,
        None => @~"0.0"
E
Erick Tryzelaar 已提交
1095
    }
1096 1097
}

1098 1099
fn iter_crate_items(intr: @ident_interner, cdata: cmd,
                    get_crate_data: GetCrateDataCb,
1100
                    proc: &fn(path: &str, ast::def_id)) {
1101 1102
    for each_path(intr, cdata, get_crate_data) |path_string, def_like| {
        match def_like {
1103 1104
            dl_impl(*) | dl_field => {}
            dl_def(def) => {
1105
                proc(path_string,
1106
                     ast_util::def_id_of_def(def))
1107 1108
            }
        }
1109 1110 1111
    }
}

1112
pub fn list_crate_metadata(intr: @ident_interner, bytes: @~[u8],
1113
                           out: @io::Writer) {
H
Haitao Li 已提交
1114
    let hash = get_crate_hash(bytes);
1115
    let md = reader::Doc(bytes);
1116
    list_crate_attributes(intr, md, *hash, out);
P
Paul Stansifer 已提交
1117
    list_crate_deps(intr, bytes, out);
1118 1119
}

1120 1121 1122 1123 1124
// 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.
1125
pub fn translate_def_id(cdata: cmd, did: ast::def_id) -> ast::def_id {
1126
    if did.crate == ast::local_crate {
1127
        return ast::def_id { crate: cdata.cnum, node: did.node };
1128 1129
    }

1130
    match cdata.cnum_map.find(&did.crate) {
1131
      option::Some(n) => ast::def_id { crate: n, node: did.node },
1132
      option::None => fail!(~"didn't find a crate in the cnum_map")
1133 1134 1135
    }
}

1136 1137 1138 1139 1140 1141 1142 1143 1144
pub fn get_link_args_for_crate(cdata: cmd) -> ~[~str] {
    let link_args = reader::get_doc(reader::Doc(cdata.data), tag_link_args);
    let mut result = ~[];
    for reader::tagged_docs(link_args, tag_link_args_arg) |arg_doc| {
        result.push(reader::doc_as_str(arg_doc));
    }
    result
}

1145 1146 1147 1148 1149 1150 1151
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End: