mod.rs 67.0 KB
Newer Older
1 2 3 4 5 6 7 8 9 10
// Copyright 2012-2013 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.

C
Corey Richardson 已提交
11 12 13 14 15
//! This module contains the "cleaned" pieces of the AST, and the functions
//! that clean them.

use syntax;
use syntax::ast;
16
use syntax::ast_util;
17
use syntax::ast_util::PostExpansionMethod;
18
use syntax::attr;
19
use syntax::attr::{AttributeMethods, AttrMetaMethods};
20
use syntax::codemap::Pos;
21 22
use syntax::parse::token::InternedString;
use syntax::parse::token;
C
Corey Richardson 已提交
23

24 25
use rustc::back::link;
use rustc::driver::driver;
26 27 28
use rustc::metadata::cstore;
use rustc::metadata::csearch;
use rustc::metadata::decoder;
29
use rustc::middle::def;
30
use rustc::middle::subst;
31
use rustc::middle::subst::VecPerParamSpace;
32
use rustc::middle::ty;
33
use rustc::middle::stability;
34

35
use std::rc::Rc;
36
use std::u32;
37
use std::gc::{Gc, GC};
38

E
Eduard Burtescu 已提交
39
use core;
C
Corey Richardson 已提交
40 41 42
use doctree;
use visit_ast;

43 44
/// A stable identifier to the particular version of JSON output.
/// Increment this when the `Crate` and related structures change.
45
pub static SCHEMA_VERSION: &'static str = "0.8.3";
46

47 48
mod inline;

49 50 51 52 53 54 55 56 57 58 59
// load the current DocContext from TLD
fn get_cx() -> Gc<core::DocContext> {
    *super::ctxtkey.get().unwrap()
}

// extract the stability index for a node from TLD, if possible
fn get_stability(def_id: ast::DefId) -> Option<Stability> {
    get_cx().tcx_opt().and_then(|tcx| stability::lookup(tcx, def_id))
            .map(|stab| stab.clean())
}

C
Corey Richardson 已提交
60 61 62 63
pub trait Clean<T> {
    fn clean(&self) -> T;
}

64 65 66 67 68 69
impl<T: Clean<U>, U> Clean<Vec<U>> for Vec<T> {
    fn clean(&self) -> Vec<U> {
        self.iter().map(|x| x.clean()).collect()
    }
}

70 71 72 73 74 75
impl<T: Clean<U>, U> Clean<VecPerParamSpace<U>> for VecPerParamSpace<T> {
    fn clean(&self) -> VecPerParamSpace<U> {
        self.map(|x| x.clean())
    }
}

76
impl<T: 'static + Clean<U>, U> Clean<U> for Gc<T> {
C
Corey Richardson 已提交
77 78 79 80 81
    fn clean(&self) -> U {
        (**self).clean()
    }
}

82 83 84 85 86 87
impl<T: Clean<U>, U> Clean<U> for Rc<T> {
    fn clean(&self) -> U {
        (**self).clean()
    }
}

C
Corey Richardson 已提交
88 89 90 91 92 93 94 95 96
impl<T: Clean<U>, U> Clean<Option<U>> for Option<T> {
    fn clean(&self) -> Option<U> {
        match self {
            &None => None,
            &Some(ref v) => Some(v.clean())
        }
    }
}

97
impl<T: Clean<U>, U> Clean<Vec<U>> for syntax::owned_slice::OwnedSlice<T> {
98
    fn clean(&self) -> Vec<U> {
99
        self.iter().map(|x| x.clean()).collect()
C
Corey Richardson 已提交
100 101 102 103 104
    }
}

#[deriving(Clone, Encodable, Decodable)]
pub struct Crate {
105
    pub name: String,
106 107
    pub module: Option<Item>,
    pub externs: Vec<(ast::CrateNum, ExternalCrate)>,
108
    pub primitives: Vec<Primitive>,
C
Corey Richardson 已提交
109 110
}

A
Alex Crichton 已提交
111
impl<'a> Clean<Crate> for visit_ast::RustdocVisitor<'a> {
C
Corey Richardson 已提交
112
    fn clean(&self) -> Crate {
113
        let cx = get_cx();
114

115
        let mut externs = Vec::new();
E
Eduard Burtescu 已提交
116
        cx.sess().cstore.iter_crate_data(|n, meta| {
117
            externs.push((n, meta.clean()));
118
        });
119
        externs.sort_by(|&(a, _), &(b, _)| a.cmp(&b));
C
Corey Richardson 已提交
120

121
        // Figure out the name of this crate
122
        let input = driver::FileInput(cx.src.clone());
123
        let name = link::find_crate_name(None, self.attrs.as_slice(), &input);
124

125
        // Clean the crate, translating the entire libsyntax AST to one that is
126 127 128 129 130
        // understood by rustdoc.
        let mut module = self.module.clean();

        // Collect all inner modules which are tagged as implementations of
        // primitives.
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
        //
        // Note that this loop only searches the top-level items of the crate,
        // and this is intentional. If we were to search the entire crate for an
        // item tagged with `#[doc(primitive)]` then we we would also have to
        // search the entirety of external modules for items tagged
        // `#[doc(primitive)]`, which is a pretty inefficient process (decoding
        // all that metadata unconditionally).
        //
        // In order to keep the metadata load under control, the
        // `#[doc(primitive)]` feature is explicitly designed to only allow the
        // primitive tags to show up as the top level items in a crate.
        //
        // Also note that this does not attempt to deal with modules tagged
        // duplicately for the same primitive. This is handled later on when
        // rendering by delegating everything to a hash map.
146 147 148 149 150 151 152
        let mut primitives = Vec::new();
        {
            let m = match module.inner {
                ModuleItem(ref mut m) => m,
                _ => unreachable!(),
            };
            let mut tmp = Vec::new();
153 154 155
            for child in m.items.mut_iter() {
                let inner = match child.inner {
                    ModuleItem(ref mut m) => m,
156
                    _ => continue,
157
                };
158 159 160 161 162
                let prim = match Primitive::find(child.attrs.as_slice()) {
                    Some(prim) => prim,
                    None => continue,
                };
                primitives.push(prim);
163
                let mut i = Item {
164 165
                    source: Span::empty(),
                    name: Some(prim.to_url_str().to_string()),
166 167
                    attrs: Vec::new(),
                    visibility: None,
168
                    stability: None,
169 170
                    def_id: ast_util::local_def(prim.to_node_id()),
                    inner: PrimitiveItem(prim),
171 172 173 174 175 176 177 178 179 180
                };
                // Push one copy to get indexed for the whole crate, and push a
                // another copy in the proper location which will actually get
                // documented. The first copy will also serve as a redirect to
                // the other copy.
                tmp.push(i.clone());
                i.visibility = Some(ast::Public);
                i.attrs = child.attrs.clone();
                inner.items.push(i);

181 182 183 184
            }
            m.items.extend(tmp.move_iter());
        }

C
Corey Richardson 已提交
185
        Crate {
186
            name: name.to_string(),
187
            module: Some(module),
188
            externs: externs,
189
            primitives: primitives,
190 191 192 193 194 195
        }
    }
}

#[deriving(Clone, Encodable, Decodable)]
pub struct ExternalCrate {
196
    pub name: String,
197
    pub attrs: Vec<Attribute>,
198
    pub primitives: Vec<Primitive>,
199 200 201 202
}

impl Clean<ExternalCrate> for cstore::crate_metadata {
    fn clean(&self) -> ExternalCrate {
203
        let mut primitives = Vec::new();
204 205 206 207 208 209 210 211 212 213 214 215
        get_cx().tcx_opt().map(|tcx| {
            csearch::each_top_level_item_of_crate(&tcx.sess.cstore,
                                                  self.cnum,
                                                  |def, _, _| {
                let did = match def {
                    decoder::DlDef(def::DefMod(did)) => did,
                    _ => return
                };
                let attrs = inline::load_attrs(tcx, did);
                Primitive::find(attrs.as_slice()).map(|prim| primitives.push(prim));
            })
        });
216
        ExternalCrate {
217
            name: self.name.to_string(),
218 219
            attrs: decoder::get_crate_attributes(self.data()).clean(),
            primitives: primitives,
C
Corey Richardson 已提交
220 221 222 223 224 225 226 227 228 229
        }
    }
}

/// Anything with a source location and set of attributes and, optionally, a
/// name. That is, anything that can be documented. This doesn't correspond
/// directly to the AST's concept of an item; it's a strict superset.
#[deriving(Clone, Encodable, Decodable)]
pub struct Item {
    /// Stringified span
230
    pub source: Span,
C
Corey Richardson 已提交
231
    /// Not everything has a name. E.g., impls
232
    pub name: Option<String>,
233 234 235
    pub attrs: Vec<Attribute> ,
    pub inner: ItemEnum,
    pub visibility: Option<Visibility>,
236
    pub def_id: ast::DefId,
237
    pub stability: Option<Stability>,
C
Corey Richardson 已提交
238 239
}

240 241 242 243 244 245
impl Item {
    /// Finds the `doc` attribute as a List and returns the list of attributes
    /// nested inside.
    pub fn doc_list<'a>(&'a self) -> Option<&'a [Attribute]> {
        for attr in self.attrs.iter() {
            match *attr {
246 247 248
                List(ref x, ref list) if "doc" == x.as_slice() => {
                    return Some(list.as_slice());
                }
249 250 251 252 253 254 255 256 257 258 259
                _ => {}
            }
        }
        return None;
    }

    /// Finds the `doc` attribute as a NameValue and returns the corresponding
    /// value found.
    pub fn doc_value<'a>(&'a self) -> Option<&'a str> {
        for attr in self.attrs.iter() {
            match *attr {
260 261 262
                NameValue(ref x, ref v) if "doc" == x.as_slice() => {
                    return Some(v.as_slice());
                }
263 264 265 266 267 268
                _ => {}
            }
        }
        return None;
    }

269 270 271 272 273
    pub fn is_hidden_from_doc(&self) -> bool {
        match self.doc_list() {
            Some(ref l) => {
                for innerattr in l.iter() {
                    match *innerattr {
274 275 276
                        Word(ref s) if "hidden" == s.as_slice() => {
                            return true
                        }
277 278 279 280 281 282 283 284 285
                        _ => (),
                    }
                }
            },
            None => ()
        }
        return false;
    }

286
    pub fn is_mod(&self) -> bool {
A
Alex Crichton 已提交
287
        match self.inner { ModuleItem(..) => true, _ => false }
288 289
    }
    pub fn is_trait(&self) -> bool {
A
Alex Crichton 已提交
290
        match self.inner { TraitItem(..) => true, _ => false }
291 292
    }
    pub fn is_struct(&self) -> bool {
A
Alex Crichton 已提交
293
        match self.inner { StructItem(..) => true, _ => false }
294 295
    }
    pub fn is_enum(&self) -> bool {
A
Alex Crichton 已提交
296
        match self.inner { EnumItem(..) => true, _ => false }
297 298
    }
    pub fn is_fn(&self) -> bool {
A
Alex Crichton 已提交
299
        match self.inner { FunctionItem(..) => true, _ => false }
300 301 302
    }
}

C
Corey Richardson 已提交
303 304 305 306 307 308 309 310 311 312
#[deriving(Clone, Encodable, Decodable)]
pub enum ItemEnum {
    StructItem(Struct),
    EnumItem(Enum),
    FunctionItem(Function),
    ModuleItem(Module),
    TypedefItem(Typedef),
    StaticItem(Static),
    TraitItem(Trait),
    ImplItem(Impl),
313
    /// `use` and `extern crate`
C
Corey Richardson 已提交
314
    ViewItemItem(ViewItem),
315 316
    /// A method signature only. Used for required methods in traits (ie,
    /// non-default-methods).
C
Corey Richardson 已提交
317
    TyMethodItem(TyMethod),
318
    /// A method with a body.
C
Corey Richardson 已提交
319 320 321
    MethodItem(Method),
    StructFieldItem(StructField),
    VariantItem(Variant),
322
    /// `fn`s from an extern block
323
    ForeignFunctionItem(Function),
324
    /// `static`s from an extern block
325
    ForeignStaticItem(Static),
326
    MacroItem(Macro),
327
    PrimitiveItem(Primitive),
C
Corey Richardson 已提交
328 329 330 331
}

#[deriving(Clone, Encodable, Decodable)]
pub struct Module {
332 333
    pub items: Vec<Item>,
    pub is_crate: bool,
C
Corey Richardson 已提交
334 335 336 337 338 339 340
}

impl Clean<Item> for doctree::Module {
    fn clean(&self) -> Item {
        let name = if self.name.is_some() {
            self.name.unwrap().clean()
        } else {
341
            "".to_string()
C
Corey Richardson 已提交
342
        };
343
        let mut foreigns = Vec::new();
344 345 346 347 348
        for subforeigns in self.foreigns.clean().move_iter() {
            for foreign in subforeigns.move_iter() {
                foreigns.push(foreign)
            }
        }
349
        let items: Vec<Vec<Item> > = vec!(
350 351 352
            self.structs.clean(),
            self.enums.clean(),
            self.fns.clean(),
353
            foreigns,
354 355 356 357 358
            self.mods.clean(),
            self.typedefs.clean(),
            self.statics.clean(),
            self.traits.clean(),
            self.impls.clean(),
359 360
            self.view_items.clean().move_iter()
                           .flat_map(|s| s.move_iter()).collect(),
361
            self.macros.clean(),
362
        );
363 364 365

        // determine if we should display the inner contents or
        // the outer `mod` item for the source code.
366
        let whence = {
367
            let ctxt = super::ctxtkey.get().unwrap();
368 369 370 371 372 373 374 375 376 377 378 379
            let cm = ctxt.sess().codemap();
            let outer = cm.lookup_char_pos(self.where_outer.lo);
            let inner = cm.lookup_char_pos(self.where_inner.lo);
            if outer.file.start_pos == inner.file.start_pos {
                // mod foo { ... }
                self.where_outer
            } else {
                // mod foo; (and a separate FileMap for the contents)
                self.where_inner
            }
        };

C
Corey Richardson 已提交
380 381 382
        Item {
            name: Some(name),
            attrs: self.attrs.clean(),
383
            source: whence.clean(),
C
Corey Richardson 已提交
384
            visibility: self.vis.clean(),
385
            stability: self.stab.clean(),
386
            def_id: ast_util::local_def(self.id),
C
Corey Richardson 已提交
387
            inner: ModuleItem(Module {
388
               is_crate: self.is_crate,
389 390 391
               items: items.iter()
                           .flat_map(|x| x.iter().map(|x| (*x).clone()))
                           .collect(),
C
Corey Richardson 已提交
392 393 394 395 396
            })
        }
    }
}

397
#[deriving(Clone, Encodable, Decodable, PartialEq)]
C
Corey Richardson 已提交
398
pub enum Attribute {
399 400 401
    Word(String),
    List(String, Vec<Attribute> ),
    NameValue(String, String)
C
Corey Richardson 已提交
402 403 404 405 406
}

impl Clean<Attribute> for ast::MetaItem {
    fn clean(&self) -> Attribute {
        match self.node {
407
            ast::MetaWord(ref s) => Word(s.get().to_string()),
408
            ast::MetaList(ref s, ref l) => {
409
                List(s.get().to_string(), l.clean())
410 411
            }
            ast::MetaNameValue(ref s, ref v) => {
412
                NameValue(s.get().to_string(), lit_to_string(v))
413
            }
C
Corey Richardson 已提交
414 415 416 417 418 419
        }
    }
}

impl Clean<Attribute> for ast::Attribute {
    fn clean(&self) -> Attribute {
420
        self.desugar_doc().node.value.clean()
C
Corey Richardson 已提交
421 422 423
    }
}

424
// This is a rough approximation that gets us what we want.
425
impl attr::AttrMetaMethods for Attribute {
426
    fn name(&self) -> InternedString {
427
        match *self {
428
            Word(ref n) | List(ref n, _) | NameValue(ref n, _) => {
429
                token::intern_and_get_ident(n.as_slice())
430
            }
431 432 433
        }
    }

434
    fn value_str(&self) -> Option<InternedString> {
435
        match *self {
436 437 438
            NameValue(_, ref v) => {
                Some(token::intern_and_get_ident(v.as_slice()))
            }
439 440 441
            _ => None,
        }
    }
442
    fn meta_item_list<'a>(&'a self) -> Option<&'a [Gc<ast::MetaItem>]> { None }
443
}
444 445 446
impl<'a> attr::AttrMetaMethods for &'a Attribute {
    fn name(&self) -> InternedString { (**self).name() }
    fn value_str(&self) -> Option<InternedString> { (**self).value_str() }
447
    fn meta_item_list<'a>(&'a self) -> Option<&'a [Gc<ast::MetaItem>]> { None }
448
}
449

450
#[deriving(Clone, Encodable, Decodable, PartialEq)]
C
Corey Richardson 已提交
451
pub struct TyParam {
452
    pub name: String,
453
    pub did: ast::DefId,
454
    pub bounds: Vec<TyParamBound>,
455
    pub default: Option<Type>
456
}
C
Corey Richardson 已提交
457 458 459 460 461

impl Clean<TyParam> for ast::TyParam {
    fn clean(&self) -> TyParam {
        TyParam {
            name: self.ident.clean(),
462
            did: ast::DefId { krate: ast::LOCAL_CRATE, node: self.id },
463
            bounds: self.bounds.clean(),
464
            default: self.default.clean()
C
Corey Richardson 已提交
465 466 467 468
        }
    }
}

469 470
impl Clean<TyParam> for ty::TypeParameterDef {
    fn clean(&self) -> TyParam {
471 472
        get_cx().external_typarams.borrow_mut().get_mut_ref()
                .insert(self.def_id, self.ident.clean());
473 474 475 476
        TyParam {
            name: self.ident.clean(),
            did: self.def_id,
            bounds: self.bounds.clean(),
477
            default: self.default.clean()
478 479 480 481
        }
    }
}

482
#[deriving(Clone, Encodable, Decodable, PartialEq)]
C
Corey Richardson 已提交
483 484 485 486 487 488 489 490
pub enum TyParamBound {
    RegionBound,
    TraitBound(Type)
}

impl Clean<TyParamBound> for ast::TyParamBound {
    fn clean(&self) -> TyParamBound {
        match *self {
491 492
            ast::StaticRegionTyParamBound => RegionBound,
            ast::OtherRegionTyParamBound(_) => RegionBound,
493 494 495 496
            ast::UnboxedFnTyParamBound(_) => {
                // FIXME(pcwalton): Wrong.
                RegionBound
            }
C
Corey Richardson 已提交
497 498 499 500 501
            ast::TraitTyParamBound(ref t) => TraitBound(t.clean()),
        }
    }
}

502
fn external_path(name: &str, substs: &subst::Substs) -> Path {
503
    let lifetimes = substs.regions().get_slice(subst::TypeSpace)
504 505 506
                    .iter()
                    .filter_map(|v| v.clean())
                    .collect();
507 508
    let types = Vec::from_slice(substs.types.get_slice(subst::TypeSpace));
    let types = types.clean();
509 510 511
    Path {
        global: false,
        segments: vec![PathSegment {
512
            name: name.to_string(),
513 514
            lifetimes: lifetimes,
            types: types,
515
        }],
516 517 518 519 520
    }
}

impl Clean<TyParamBound> for ty::BuiltinBound {
    fn clean(&self) -> TyParamBound {
521
        let cx = get_cx();
522 523 524 525
        let tcx = match cx.maybe_typed {
            core::Typed(ref tcx) => tcx,
            core::NotTyped(_) => return RegionBound,
        };
526
        let empty = subst::Substs::empty();
527 528 529
        let (did, path) = match *self {
            ty::BoundStatic => return RegionBound,
            ty::BoundSend =>
530 531
                (tcx.lang_items.send_trait().unwrap(),
                 external_path("Send", &empty)),
532
            ty::BoundSized =>
533 534
                (tcx.lang_items.sized_trait().unwrap(),
                 external_path("Sized", &empty)),
535
            ty::BoundCopy =>
536 537
                (tcx.lang_items.copy_trait().unwrap(),
                 external_path("Copy", &empty)),
A
Alex Crichton 已提交
538 539 540
            ty::BoundSync =>
                (tcx.lang_items.sync_trait().unwrap(),
                 external_path("Sync", &empty)),
541 542
        };
        let fqn = csearch::get_item_path(tcx, did);
543
        let fqn = fqn.move_iter().map(|i| i.to_string()).collect();
544 545 546 547 548 549 550 551 552 553 554 555
        cx.external_paths.borrow_mut().get_mut_ref().insert(did,
                                                            (fqn, TypeTrait));
        TraitBound(ResolvedPath {
            path: path,
            typarams: None,
            did: did,
        })
    }
}

impl Clean<TyParamBound> for ty::TraitRef {
    fn clean(&self) -> TyParamBound {
556
        let cx = get_cx();
557 558 559 560 561
        let tcx = match cx.maybe_typed {
            core::Typed(ref tcx) => tcx,
            core::NotTyped(_) => return RegionBound,
        };
        let fqn = csearch::get_item_path(tcx, self.def_id);
562
        let fqn = fqn.move_iter().map(|i| i.to_string())
563
                     .collect::<Vec<String>>();
564 565
        let path = external_path(fqn.last().unwrap().as_slice(),
                                 &self.substs);
566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590
        cx.external_paths.borrow_mut().get_mut_ref().insert(self.def_id,
                                                            (fqn, TypeTrait));
        TraitBound(ResolvedPath {
            path: path,
            typarams: None,
            did: self.def_id,
        })
    }
}

impl Clean<Vec<TyParamBound>> for ty::ParamBounds {
    fn clean(&self) -> Vec<TyParamBound> {
        let mut v = Vec::new();
        for b in self.builtin_bounds.iter() {
            if b != ty::BoundSized {
                v.push(b.clean());
            }
        }
        for t in self.trait_bounds.iter() {
            v.push(t.clean());
        }
        return v;
    }
}

591
impl Clean<Option<Vec<TyParamBound>>> for subst::Substs {
592 593
    fn clean(&self) -> Option<Vec<TyParamBound>> {
        let mut v = Vec::new();
594 595
        v.extend(self.regions().iter().map(|_| RegionBound));
        v.extend(self.types.iter().map(|t| TraitBound(t.clean())));
596 597 598 599
        if v.len() > 0 {Some(v)} else {None}
    }
}

600
#[deriving(Clone, Encodable, Decodable, PartialEq)]
601
pub struct Lifetime(String);
C
Corey Richardson 已提交
602

603 604 605
impl Lifetime {
    pub fn get_ref<'a>(&'a self) -> &'a str {
        let Lifetime(ref s) = *self;
606
        let s: &'a str = s.as_slice();
607 608 609 610
        return s;
    }
}

C
Corey Richardson 已提交
611 612
impl Clean<Lifetime> for ast::Lifetime {
    fn clean(&self) -> Lifetime {
613
        Lifetime(token::get_name(self.name).get().to_string())
C
Corey Richardson 已提交
614 615 616
    }
}

617 618 619 620 621 622
impl Clean<Lifetime> for ast::LifetimeDef {
    fn clean(&self) -> Lifetime {
        Lifetime(token::get_name(self.lifetime.name).get().to_string())
    }
}

623 624
impl Clean<Lifetime> for ty::RegionParameterDef {
    fn clean(&self) -> Lifetime {
625
        Lifetime(token::get_name(self.name).get().to_string())
626 627 628 629 630 631
    }
}

impl Clean<Option<Lifetime>> for ty::Region {
    fn clean(&self) -> Option<Lifetime> {
        match *self {
P
P1start 已提交
632
            ty::ReStatic => Some(Lifetime("'static".to_string())),
633
            ty::ReLateBound(_, ty::BrNamed(_, name)) =>
634
                Some(Lifetime(token::get_name(name).get().to_string())),
635
            ty::ReEarlyBound(_, _, _, name) => Some(Lifetime(name.clean())),
636 637 638 639 640 641 642 643 644 645

            ty::ReLateBound(..) |
            ty::ReFree(..) |
            ty::ReScope(..) |
            ty::ReInfer(..) |
            ty::ReEmpty(..) => None
        }
    }
}

C
Corey Richardson 已提交
646
// maybe use a Generic enum and use ~[Generic]?
647
#[deriving(Clone, Encodable, Decodable, PartialEq)]
C
Corey Richardson 已提交
648
pub struct Generics {
649 650 651
    pub lifetimes: Vec<Lifetime>,
    pub type_params: Vec<TyParam>,
}
C
Corey Richardson 已提交
652 653 654 655

impl Clean<Generics> for ast::Generics {
    fn clean(&self) -> Generics {
        Generics {
656 657
            lifetimes: self.lifetimes.clean(),
            type_params: self.ty_params.clean(),
C
Corey Richardson 已提交
658 659 660 661
        }
    }
}

662
impl<'a> Clean<Generics> for (&'a ty::Generics, subst::ParamSpace) {
663
    fn clean(&self) -> Generics {
664
        let (me, space) = *self;
665
        Generics {
666 667
            type_params: Vec::from_slice(me.types.get_slice(space)).clean(),
            lifetimes: Vec::from_slice(me.regions.get_slice(space)).clean(),
668 669 670 671
        }
    }
}

C
Corey Richardson 已提交
672 673
#[deriving(Clone, Encodable, Decodable)]
pub struct Method {
674 675
    pub generics: Generics,
    pub self_: SelfTy,
676
    pub fn_style: ast::FnStyle,
677
    pub decl: FnDecl,
C
Corey Richardson 已提交
678 679
}

680
impl Clean<Item> for ast::Method {
C
Corey Richardson 已提交
681
    fn clean(&self) -> Item {
682 683 684 685
        let all_inputs = &self.pe_fn_decl().inputs;
        let inputs = match self.pe_explicit_self().node {
            ast::SelfStatic => all_inputs.as_slice(),
            _ => all_inputs.slice_from(1)
686 687
        };
        let decl = FnDecl {
688 689 690
            inputs: Arguments {
                values: inputs.iter().map(|x| x.clean()).collect(),
            },
691 692
            output: (self.pe_fn_decl().output.clean()),
            cf: self.pe_fn_decl().cf.clean(),
693
            attrs: Vec::new()
694
        };
C
Corey Richardson 已提交
695
        Item {
696
            name: Some(self.pe_ident().clean()),
697
            attrs: self.attrs.clean(),
C
Corey Richardson 已提交
698
            source: self.span.clean(),
699
            def_id: ast_util::local_def(self.id),
700
            visibility: self.pe_vis().clean(),
701
            stability: get_stability(ast_util::local_def(self.id)),
C
Corey Richardson 已提交
702
            inner: MethodItem(Method {
703 704 705
                generics: self.pe_generics().clean(),
                self_: self.pe_explicit_self().node.clean(),
                fn_style: self.pe_fn_style().clone(),
706
                decl: decl,
C
Corey Richardson 已提交
707 708 709 710 711 712 713
            }),
        }
    }
}

#[deriving(Clone, Encodable, Decodable)]
pub struct TyMethod {
714
    pub fn_style: ast::FnStyle,
715 716 717
    pub decl: FnDecl,
    pub generics: Generics,
    pub self_: SelfTy,
C
Corey Richardson 已提交
718 719 720 721
}

impl Clean<Item> for ast::TypeMethod {
    fn clean(&self) -> Item {
722 723 724 725 726
        let inputs = match self.explicit_self.node {
            ast::SelfStatic => self.decl.inputs.as_slice(),
            _ => self.decl.inputs.slice_from(1)
        };
        let decl = FnDecl {
727 728 729
            inputs: Arguments {
                values: inputs.iter().map(|x| x.clean()).collect(),
            },
730 731
            output: (self.decl.output.clean()),
            cf: self.decl.cf.clean(),
732
            attrs: Vec::new()
733
        };
C
Corey Richardson 已提交
734 735
        Item {
            name: Some(self.ident.clean()),
736
            attrs: self.attrs.clean(),
C
Corey Richardson 已提交
737
            source: self.span.clean(),
738
            def_id: ast_util::local_def(self.id),
C
Corey Richardson 已提交
739
            visibility: None,
740
            stability: get_stability(ast_util::local_def(self.id)),
C
Corey Richardson 已提交
741
            inner: TyMethodItem(TyMethod {
742
                fn_style: self.fn_style.clone(),
743
                decl: decl,
744
                self_: self.explicit_self.node.clean(),
C
Corey Richardson 已提交
745 746 747 748 749 750
                generics: self.generics.clean(),
            }),
        }
    }
}

751
#[deriving(Clone, Encodable, Decodable, PartialEq)]
C
Corey Richardson 已提交
752 753 754 755
pub enum SelfTy {
    SelfStatic,
    SelfValue,
    SelfBorrowed(Option<Lifetime>, Mutability),
756
    SelfExplicit(Type),
C
Corey Richardson 已提交
757 758
}

759
impl Clean<SelfTy> for ast::ExplicitSelf_ {
C
Corey Richardson 已提交
760
    fn clean(&self) -> SelfTy {
761
        match *self {
762
            ast::SelfStatic => SelfStatic,
763
            ast::SelfValue(_) => SelfValue,
764 765 766 767
            ast::SelfRegion(lt, mt, _) => {
                SelfBorrowed(lt.clean(), mt.clean())
            }
            ast::SelfExplicit(typ, _) => SelfExplicit(typ.clean()),
C
Corey Richardson 已提交
768 769 770 771 772 773
        }
    }
}

#[deriving(Clone, Encodable, Decodable)]
pub struct Function {
774 775
    pub decl: FnDecl,
    pub generics: Generics,
776
    pub fn_style: ast::FnStyle,
C
Corey Richardson 已提交
777 778 779 780 781 782 783
}

impl Clean<Item> for doctree::Function {
    fn clean(&self) -> Item {
        Item {
            name: Some(self.name.clean()),
            attrs: self.attrs.clean(),
784
            source: self.whence.clean(),
C
Corey Richardson 已提交
785
            visibility: self.vis.clean(),
786
            stability: self.stab.clean(),
787
            def_id: ast_util::local_def(self.id),
C
Corey Richardson 已提交
788 789 790
            inner: FunctionItem(Function {
                decl: self.decl.clean(),
                generics: self.generics.clean(),
791
                fn_style: self.fn_style,
C
Corey Richardson 已提交
792 793 794 795 796
            }),
        }
    }
}

797
#[deriving(Clone, Encodable, Decodable, PartialEq)]
C
Corey Richardson 已提交
798
pub struct ClosureDecl {
799 800 801
    pub lifetimes: Vec<Lifetime>,
    pub decl: FnDecl,
    pub onceness: ast::Onceness,
802
    pub fn_style: ast::FnStyle,
803 804
    pub bounds: Vec<TyParamBound>,
}
C
Corey Richardson 已提交
805

806
impl Clean<ClosureDecl> for ast::ClosureTy {
C
Corey Richardson 已提交
807 808
    fn clean(&self) -> ClosureDecl {
        ClosureDecl {
809
            lifetimes: self.lifetimes.clean(),
C
Corey Richardson 已提交
810 811
            decl: self.decl.clean(),
            onceness: self.onceness,
812
            fn_style: self.fn_style,
C
Corey Richardson 已提交
813
            bounds: match self.bounds {
814
                Some(ref x) => x.clean(),
815
                None        => Vec::new()
C
Corey Richardson 已提交
816 817 818 819 820
            },
        }
    }
}

821
#[deriving(Clone, Encodable, Decodable, PartialEq)]
C
Corey Richardson 已提交
822
pub struct FnDecl {
823 824 825 826 827
    pub inputs: Arguments,
    pub output: Type,
    pub cf: RetStyle,
    pub attrs: Vec<Attribute>,
}
C
Corey Richardson 已提交
828

829
#[deriving(Clone, Encodable, Decodable, PartialEq)]
830
pub struct Arguments {
831
    pub values: Vec<Argument>,
832 833
}

834
impl Clean<FnDecl> for ast::FnDecl {
C
Corey Richardson 已提交
835 836
    fn clean(&self) -> FnDecl {
        FnDecl {
837 838 839
            inputs: Arguments {
                values: self.inputs.iter().map(|x| x.clean()).collect(),
            },
C
Corey Richardson 已提交
840 841
            output: (self.output.clean()),
            cf: self.cf.clean(),
842
            attrs: Vec::new()
C
Corey Richardson 已提交
843 844 845 846
        }
    }
}

847
impl<'a> Clean<FnDecl> for (ast::DefId, &'a ty::FnSig) {
848
    fn clean(&self) -> FnDecl {
849
        let cx = get_cx();
850 851
        let (did, sig) = *self;
        let mut names = if did.node != 0 {
852
            csearch::get_method_arg_names(&cx.tcx().sess.cstore, did).move_iter()
853 854 855 856 857 858
        } else {
            Vec::new().move_iter()
        }.peekable();
        if names.peek().map(|s| s.as_slice()) == Some("self") {
            let _ = names.next();
        }
859
        FnDecl {
860
            output: sig.output.clean(),
861
            cf: Return,
862
            attrs: Vec::new(),
863
            inputs: Arguments {
864
                values: sig.inputs.iter().map(|t| {
865 866 867
                    Argument {
                        type_: t.clean(),
                        id: 0,
868
                        name: names.next().unwrap_or("".to_string()),
869 870 871 872 873 874 875
                    }
                }).collect(),
            },
        }
    }
}

876
#[deriving(Clone, Encodable, Decodable, PartialEq)]
C
Corey Richardson 已提交
877
pub struct Argument {
878
    pub type_: Type,
879
    pub name: String,
880
    pub id: ast::NodeId,
C
Corey Richardson 已提交
881 882
}

883
impl Clean<Argument> for ast::Arg {
C
Corey Richardson 已提交
884 885
    fn clean(&self) -> Argument {
        Argument {
886
            name: name_from_pat(&*self.pat),
C
Corey Richardson 已提交
887 888 889 890 891 892
            type_: (self.ty.clean()),
            id: self.id
        }
    }
}

893
#[deriving(Clone, Encodable, Decodable, PartialEq)]
C
Corey Richardson 已提交
894 895 896 897 898
pub enum RetStyle {
    NoReturn,
    Return
}

899
impl Clean<RetStyle> for ast::RetStyle {
C
Corey Richardson 已提交
900 901
    fn clean(&self) -> RetStyle {
        match *self {
902 903
            ast::Return => Return,
            ast::NoReturn => NoReturn
C
Corey Richardson 已提交
904 905 906 907 908 909
        }
    }
}

#[deriving(Clone, Encodable, Decodable)]
pub struct Trait {
910
    pub items: Vec<TraitItem>,
911 912
    pub generics: Generics,
    pub parents: Vec<Type>,
C
Corey Richardson 已提交
913 914 915 916 917 918 919
}

impl Clean<Item> for doctree::Trait {
    fn clean(&self) -> Item {
        Item {
            name: Some(self.name.clean()),
            attrs: self.attrs.clean(),
920
            source: self.whence.clean(),
921
            def_id: ast_util::local_def(self.id),
C
Corey Richardson 已提交
922
            visibility: self.vis.clean(),
923
            stability: self.stab.clean(),
C
Corey Richardson 已提交
924
            inner: TraitItem(Trait {
925
                items: self.items.clean(),
C
Corey Richardson 已提交
926 927 928 929 930 931 932
                generics: self.generics.clean(),
                parents: self.parents.clean(),
            }),
        }
    }
}

933
impl Clean<Type> for ast::TraitRef {
C
Corey Richardson 已提交
934
    fn clean(&self) -> Type {
935
        resolve_type(self.path.clean(), None, self.ref_id)
C
Corey Richardson 已提交
936 937 938 939
    }
}

#[deriving(Clone, Encodable, Decodable)]
940 941 942
pub enum TraitItem {
    RequiredMethod(Item),
    ProvidedMethod(Item),
C
Corey Richardson 已提交
943 944
}

945
impl TraitItem {
946
    pub fn is_req(&self) -> bool {
C
Corey Richardson 已提交
947
        match self {
948
            &RequiredMethod(..) => true,
C
Corey Richardson 已提交
949 950 951
            _ => false,
        }
    }
952
    pub fn is_def(&self) -> bool {
C
Corey Richardson 已提交
953
        match self {
954
            &ProvidedMethod(..) => true,
C
Corey Richardson 已提交
955 956 957
            _ => false,
        }
    }
958 959
    pub fn item<'a>(&'a self) -> &'a Item {
        match *self {
960 961
            RequiredMethod(ref item) => item,
            ProvidedMethod(ref item) => item,
962 963
        }
    }
C
Corey Richardson 已提交
964 965
}

966 967
impl Clean<TraitItem> for ast::TraitItem {
    fn clean(&self) -> TraitItem {
C
Corey Richardson 已提交
968
        match self {
969 970 971 972 973 974 975 976 977 978 979 980 981 982 983
            &ast::RequiredMethod(ref t) => RequiredMethod(t.clean()),
            &ast::ProvidedMethod(ref t) => ProvidedMethod(t.clean()),
        }
    }
}

#[deriving(Clone, Encodable, Decodable)]
pub enum ImplItem {
    MethodImplItem(Item),
}

impl Clean<ImplItem> for ast::ImplItem {
    fn clean(&self) -> ImplItem {
        match self {
            &ast::MethodImplItem(ref t) => MethodImplItem(t.clean()),
C
Corey Richardson 已提交
984 985 986 987
        }
    }
}

988 989
impl Clean<Item> for ty::Method {
    fn clean(&self) -> Item {
990
        let cx = get_cx();
991
        let (self_, sig) = match self.explicit_self {
A
Alex Crichton 已提交
992 993
            ty::StaticExplicitSelfCategory => (ast::SelfStatic.clean(),
                                               self.fty.sig.clone()),
994 995 996 997 998 999
            s => {
                let sig = ty::FnSig {
                    inputs: Vec::from_slice(self.fty.sig.inputs.slice_from(1)),
                    ..self.fty.sig.clone()
                };
                let s = match s {
A
Alex Crichton 已提交
1000
                    ty::ByValueExplicitSelfCategory => SelfValue,
1001
                    ty::ByReferenceExplicitSelfCategory(..) => {
1002
                        match ty::get(self.fty.sig.inputs[0]).sty {
1003 1004 1005
                            ty::ty_rptr(r, mt) => {
                                SelfBorrowed(r.clean(), mt.mutbl.clean())
                            }
A
Alex Crichton 已提交
1006
                            _ => unreachable!(),
1007 1008
                        }
                    }
A
Alex Crichton 已提交
1009 1010
                    ty::ByBoxExplicitSelfCategory => {
                        SelfExplicit(self.fty.sig.inputs[0].clean())
1011
                    }
A
Alex Crichton 已提交
1012
                    ty::StaticExplicitSelfCategory => unreachable!(),
1013 1014 1015 1016
                };
                (s, sig)
            }
        };
1017

1018
        Item {
1019 1020
            name: Some(self.ident.clean()),
            visibility: Some(ast::Inherited),
1021
            stability: get_stability(self.def_id),
1022
            def_id: self.def_id,
1023
            attrs: inline::load_attrs(cx.tcx(), self.def_id),
1024
            source: Span::empty(),
1025 1026
            inner: TyMethodItem(TyMethod {
                fn_style: self.fty.fn_style,
1027
                generics: (&self.generics, subst::FnSpace).clean(),
1028
                self_: self_,
1029
                decl: (self.def_id, &sig).clean(),
1030
            })
1031
        }
1032 1033 1034
    }
}

1035 1036 1037 1038 1039 1040 1041 1042
impl Clean<Item> for ty::ImplOrTraitItem {
    fn clean(&self) -> Item {
        match *self {
            ty::MethodTraitItem(ref mti) => mti.clean(),
        }
    }
}

C
Corey Richardson 已提交
1043 1044 1045
/// A representation of a Type suitable for hyperlinking purposes. Ideally one can get the original
/// type out of the AST/ty::ctxt given one of these, if more information is needed. Most importantly
/// it does not preserve mutability or boxes.
1046
#[deriving(Clone, Encodable, Decodable, PartialEq)]
C
Corey Richardson 已提交
1047
pub enum Type {
1048
    /// structs/enums/traits (anything that'd be an ast::TyPath)
1049
    ResolvedPath {
1050 1051
        pub path: Path,
        pub typarams: Option<Vec<TyParamBound>>,
1052
        pub did: ast::DefId,
1053
    },
C
Corey Richardson 已提交
1054 1055 1056 1057
    // I have no idea how to usefully use this.
    TyParamBinder(ast::NodeId),
    /// For parameterized types, so the consumer of the JSON don't go looking
    /// for types which don't exist anywhere.
1058
    Generic(ast::DefId),
C
Corey Richardson 已提交
1059
    /// For references to self
1060
    Self(ast::DefId),
C
Corey Richardson 已提交
1061
    /// Primitives are just the fixed-size numeric types (plus int/uint/float), and char.
1062
    Primitive(Primitive),
1063 1064
    Closure(Box<ClosureDecl>, Option<Lifetime>),
    Proc(Box<ClosureDecl>),
C
Corey Richardson 已提交
1065
    /// extern "ABI" fn
1066
    BareFunction(Box<BareFunctionDecl>),
1067
    Tuple(Vec<Type>),
1068
    Vector(Box<Type>),
1069
    FixedVector(Box<Type>, String),
1070
    /// aka TyBot
C
Corey Richardson 已提交
1071
    Bottom,
1072 1073 1074
    Unique(Box<Type>),
    Managed(Box<Type>),
    RawPointer(Mutability, Box<Type>),
1075 1076 1077
    BorrowedRef {
        pub lifetime: Option<Lifetime>,
        pub mutability: Mutability,
1078
        pub type_: Box<Type>,
1079
    },
C
Corey Richardson 已提交
1080 1081 1082
    // region, raw, other boxes, mutable
}

1083
#[deriving(Clone, Encodable, Decodable, PartialEq, Eq, Hash)]
1084 1085 1086
pub enum Primitive {
    Int, I8, I16, I32, I64,
    Uint, U8, U16, U32, U64,
1087
    F32, F64,
1088 1089
    Char,
    Bool,
H
Huon Wilson 已提交
1090
    Unit,
1091 1092 1093 1094 1095
    Str,
    Slice,
    PrimitiveTuple,
}

1096 1097 1098 1099
#[deriving(Clone, Encodable, Decodable)]
pub enum TypeKind {
    TypeEnum,
    TypeFunction,
1100 1101 1102 1103 1104
    TypeModule,
    TypeStatic,
    TypeStruct,
    TypeTrait,
    TypeVariant,
1105 1106
}

1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120
impl Primitive {
    fn from_str(s: &str) -> Option<Primitive> {
        match s.as_slice() {
            "int" => Some(Int),
            "i8" => Some(I8),
            "i16" => Some(I16),
            "i32" => Some(I32),
            "i64" => Some(I64),
            "uint" => Some(Uint),
            "u8" => Some(U8),
            "u16" => Some(U16),
            "u32" => Some(U32),
            "u64" => Some(U64),
            "bool" => Some(Bool),
H
Huon Wilson 已提交
1121
            "unit" => Some(Unit),
1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152
            "char" => Some(Char),
            "str" => Some(Str),
            "f32" => Some(F32),
            "f64" => Some(F64),
            "slice" => Some(Slice),
            "tuple" => Some(PrimitiveTuple),
            _ => None,
        }
    }

    fn find(attrs: &[Attribute]) -> Option<Primitive> {
        for attr in attrs.iter() {
            let list = match *attr {
                List(ref k, ref l) if k.as_slice() == "doc" => l,
                _ => continue,
            };
            for sub_attr in list.iter() {
                let value = match *sub_attr {
                    NameValue(ref k, ref v)
                        if k.as_slice() == "primitive" => v.as_slice(),
                    _ => continue,
                };
                match Primitive::from_str(value) {
                    Some(p) => return Some(p),
                    None => {}
                }
            }
        }
        return None
    }

1153
    pub fn to_string(&self) -> &'static str {
1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169
        match *self {
            Int => "int",
            I8 => "i8",
            I16 => "i16",
            I32 => "i32",
            I64 => "i64",
            Uint => "uint",
            U8 => "u8",
            U16 => "u16",
            U32 => "u32",
            U64 => "u64",
            F32 => "f32",
            F64 => "f64",
            Str => "str",
            Bool => "bool",
            Char => "char",
H
Huon Wilson 已提交
1170
            Unit => "()",
1171 1172 1173 1174 1175 1176 1177
            Slice => "slice",
            PrimitiveTuple => "tuple",
        }
    }

    pub fn to_url_str(&self) -> &'static str {
        match *self {
H
Huon Wilson 已提交
1178
            Unit => "unit",
1179
            other => other.to_string(),
1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190
        }
    }

    /// Creates a rustdoc-specific node id for primitive types.
    ///
    /// These node ids are generally never used by the AST itself.
    pub fn to_node_id(&self) -> ast::NodeId {
        u32::MAX - 1 - (*self as u32)
    }
}

C
Corey Richardson 已提交
1191 1192 1193
impl Clean<Type> for ast::Ty {
    fn clean(&self) -> Type {
        use syntax::ast::*;
1194
        match self.node {
H
Huon Wilson 已提交
1195
            TyNil => Primitive(Unit),
1196
            TyPtr(ref m) => RawPointer(m.mutbl.clean(), box m.ty.clean()),
1197
            TyRptr(ref l, ref m) =>
C
Corey Richardson 已提交
1198
                BorrowedRef {lifetime: l.clean(), mutability: m.mutbl.clean(),
1199 1200 1201 1202 1203
                             type_: box m.ty.clean()},
            TyBox(ty) => Managed(box ty.clean()),
            TyUniq(ty) => Unique(box ty.clean()),
            TyVec(ty) => Vector(box ty.clean()),
            TyFixedLengthVec(ty, ref e) => FixedVector(box ty.clean(),
1204 1205
                                                       e.span.to_src()),
            TyTup(ref tys) => Tuple(tys.iter().map(|x| x.clean()).collect()),
1206 1207
            TyPath(ref p, ref tpbs, id) => {
                resolve_type(p.clean(),
1208
                             tpbs.clean().map(|x| x),
1209 1210
                             id)
            }
1211 1212 1213
            TyClosure(ref c, region) => Closure(box c.clean(), region.clean()),
            TyProc(ref c) => Proc(box c.clean()),
            TyBareFn(ref barefn) => BareFunction(box barefn.clean()),
1214
            TyParen(ref ty) => ty.clean(),
1215
            TyBot => Bottom,
1216
            ref x => fail!("Unimplemented type {:?}", x),
1217
        }
C
Corey Richardson 已提交
1218 1219 1220
    }
}

1221 1222 1223 1224
impl Clean<Type> for ty::t {
    fn clean(&self) -> Type {
        match ty::get(*self).sty {
            ty::ty_bot => Bottom,
H
Huon Wilson 已提交
1225
            ty::ty_nil => Primitive(Unit),
1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240
            ty::ty_bool => Primitive(Bool),
            ty::ty_char => Primitive(Char),
            ty::ty_int(ast::TyI) => Primitive(Int),
            ty::ty_int(ast::TyI8) => Primitive(I8),
            ty::ty_int(ast::TyI16) => Primitive(I16),
            ty::ty_int(ast::TyI32) => Primitive(I32),
            ty::ty_int(ast::TyI64) => Primitive(I64),
            ty::ty_uint(ast::TyU) => Primitive(Uint),
            ty::ty_uint(ast::TyU8) => Primitive(U8),
            ty::ty_uint(ast::TyU16) => Primitive(U16),
            ty::ty_uint(ast::TyU32) => Primitive(U32),
            ty::ty_uint(ast::TyU64) => Primitive(U64),
            ty::ty_float(ast::TyF32) => Primitive(F32),
            ty::ty_float(ast::TyF64) => Primitive(F64),
            ty::ty_str => Primitive(Str),
A
Alex Crichton 已提交
1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252
            ty::ty_box(t) => {
                let gc_did = get_cx().tcx_opt().and_then(|tcx| {
                    tcx.lang_items.gc()
                });
                lang_struct(gc_did, t, "Gc", Managed)
            }
            ty::ty_uniq(t) => {
                let box_did = get_cx().tcx_opt().and_then(|tcx| {
                    tcx.lang_items.owned_box()
                });
                lang_struct(box_did, t, "Box", Unique)
            }
N
Nick Cameron 已提交
1253 1254
            ty::ty_vec(ty, None) => Vector(box ty.clean()),
            ty::ty_vec(ty, Some(i)) => FixedVector(box ty.clean(),
A
Alex Crichton 已提交
1255
                                                   format!("{}", i)),
1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266
            ty::ty_ptr(mt) => RawPointer(mt.mutbl.clean(), box mt.ty.clean()),
            ty::ty_rptr(r, mt) => BorrowedRef {
                lifetime: r.clean(),
                mutability: mt.mutbl.clean(),
                type_: box mt.ty.clean(),
            },
            ty::ty_bare_fn(ref fty) => BareFunction(box BareFunctionDecl {
                fn_style: fty.fn_style,
                generics: Generics {
                    lifetimes: Vec::new(), type_params: Vec::new()
                },
1267
                decl: (ast_util::local_def(0), &fty.sig).clean(),
1268
                abi: fty.abi.to_string(),
1269 1270 1271 1272
            }),
            ty::ty_closure(ref fty) => {
                let decl = box ClosureDecl {
                    lifetimes: Vec::new(), // FIXME: this looks wrong...
1273
                    decl: (ast_util::local_def(0), &fty.sig).clean(),
1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285
                    onceness: fty.onceness,
                    fn_style: fty.fn_style,
                    bounds: fty.bounds.iter().map(|i| i.clean()).collect(),
                };
                match fty.store {
                    ty::UniqTraitStore => Proc(decl),
                    ty::RegionTraitStore(ref r, _) => Closure(decl, r.clean()),
                }
            }
            ty::ty_struct(did, ref substs) |
            ty::ty_enum(did, ref substs) |
            ty::ty_trait(box ty::TyTrait { def_id: did, ref substs, .. }) => {
1286
                let fqn = csearch::get_item_path(get_cx().tcx(), did);
1287
                let fqn: Vec<String> = fqn.move_iter().map(|i| {
1288
                    i.to_string()
1289 1290 1291 1292 1293 1294
                }).collect();
                let kind = match ty::get(*self).sty {
                    ty::ty_struct(..) => TypeStruct,
                    ty::ty_trait(..) => TypeTrait,
                    _ => TypeEnum,
                };
1295
                let path = external_path(fqn.last().unwrap().to_string().as_slice(),
1296
                                         substs);
1297 1298
                get_cx().external_paths.borrow_mut().get_mut_ref()
                                       .insert(did, (fqn, kind));
1299
                ResolvedPath {
1300
                    path: path,
1301 1302 1303 1304 1305 1306
                    typarams: None,
                    did: did,
                }
            }
            ty::ty_tup(ref t) => Tuple(t.iter().map(|t| t.clean()).collect()),

1307 1308 1309 1310 1311 1312 1313
            ty::ty_param(ref p) => {
                if p.space == subst::SelfSpace {
                    Self(p.def_id)
                } else {
                    Generic(p.def_id)
                }
            }
1314

1315 1316
            ty::ty_unboxed_closure(..) => Primitive(Unit), // FIXME(pcwalton)

1317
            ty::ty_infer(..) => fail!("ty_infer"),
N
Nick Cameron 已提交
1318
            ty::ty_open(..) => fail!("ty_open"),
1319 1320 1321 1322 1323
            ty::ty_err => fail!("ty_err"),
        }
    }
}

C
Corey Richardson 已提交
1324
#[deriving(Clone, Encodable, Decodable)]
1325
pub enum StructField {
1326
    HiddenStructField, // inserted later by strip passes
1327
    TypedStructField(Type),
C
Corey Richardson 已提交
1328 1329
}

1330
impl Clean<Item> for ast::StructField {
C
Corey Richardson 已提交
1331 1332
    fn clean(&self) -> Item {
        let (name, vis) = match self.node.kind {
1333 1334
            ast::NamedField(id, vis) => (Some(id), vis),
            ast::UnnamedField(vis) => (None, vis)
C
Corey Richardson 已提交
1335 1336 1337
        };
        Item {
            name: name.clean(),
1338
            attrs: self.node.attrs.clean(),
C
Corey Richardson 已提交
1339
            source: self.span.clean(),
1340
            visibility: Some(vis),
1341
            stability: get_stability(ast_util::local_def(self.node.id)),
1342
            def_id: ast_util::local_def(self.node.id),
1343
            inner: StructFieldItem(TypedStructField(self.node.ty.clean())),
C
Corey Richardson 已提交
1344 1345 1346 1347
        }
    }
}

1348 1349 1350
impl Clean<Item> for ty::field_ty {
    fn clean(&self) -> Item {
        use syntax::parse::token::special_idents::unnamed_field;
1351 1352 1353 1354 1355 1356 1357
        use rustc::metadata::csearch;

        let cx = get_cx();
        let attrs;

        let attr_map = csearch::get_struct_field_attrs(&cx.tcx().sess.cstore, self.id);

1358
        let name = if self.name == unnamed_field.name {
1359
            attrs = None;
1360 1361
            None
        } else {
1362
            attrs = Some(attr_map.find(&self.id.node).unwrap());
1363 1364
            Some(self.name)
        };
1365

1366
        let ty = ty::lookup_item_type(cx.tcx(), self.id);
1367

1368 1369
        Item {
            name: name.clean(),
1370
            attrs: attrs.unwrap_or(&Vec::new()).clean(),
1371 1372
            source: Span::empty(),
            visibility: Some(self.vis),
1373
            stability: get_stability(self.id),
1374 1375 1376 1377 1378 1379
            def_id: self.id,
            inner: StructFieldItem(TypedStructField(ty.ty.clean())),
        }
    }
}

1380
pub type Visibility = ast::Visibility;
C
Corey Richardson 已提交
1381

1382
impl Clean<Option<Visibility>> for ast::Visibility {
C
Corey Richardson 已提交
1383 1384 1385 1386 1387 1388 1389
    fn clean(&self) -> Option<Visibility> {
        Some(*self)
    }
}

#[deriving(Clone, Encodable, Decodable)]
pub struct Struct {
1390 1391 1392 1393
    pub struct_type: doctree::StructType,
    pub generics: Generics,
    pub fields: Vec<Item>,
    pub fields_stripped: bool,
C
Corey Richardson 已提交
1394 1395 1396 1397 1398 1399 1400
}

impl Clean<Item> for doctree::Struct {
    fn clean(&self) -> Item {
        Item {
            name: Some(self.name.clean()),
            attrs: self.attrs.clean(),
1401
            source: self.whence.clean(),
1402
            def_id: ast_util::local_def(self.id),
C
Corey Richardson 已提交
1403
            visibility: self.vis.clean(),
1404
            stability: self.stab.clean(),
C
Corey Richardson 已提交
1405 1406 1407 1408
            inner: StructItem(Struct {
                struct_type: self.struct_type,
                generics: self.generics.clean(),
                fields: self.fields.clean(),
S
Steven Fackler 已提交
1409
                fields_stripped: false,
C
Corey Richardson 已提交
1410 1411 1412 1413 1414
            }),
        }
    }
}

1415
/// This is a more limited form of the standard Struct, different in that
C
Corey Richardson 已提交
1416 1417 1418 1419
/// it lacks the things most items have (name, id, parameterization). Found
/// only as a variant in an enum.
#[deriving(Clone, Encodable, Decodable)]
pub struct VariantStruct {
1420 1421 1422
    pub struct_type: doctree::StructType,
    pub fields: Vec<Item>,
    pub fields_stripped: bool,
C
Corey Richardson 已提交
1423 1424
}

1425
impl Clean<VariantStruct> for syntax::ast::StructDef {
C
Corey Richardson 已提交
1426 1427 1428
    fn clean(&self) -> VariantStruct {
        VariantStruct {
            struct_type: doctree::struct_type_from_def(self),
1429
            fields: self.fields.clean(),
S
Steven Fackler 已提交
1430
            fields_stripped: false,
C
Corey Richardson 已提交
1431 1432 1433 1434 1435 1436
        }
    }
}

#[deriving(Clone, Encodable, Decodable)]
pub struct Enum {
1437 1438 1439
    pub variants: Vec<Item>,
    pub generics: Generics,
    pub variants_stripped: bool,
C
Corey Richardson 已提交
1440 1441 1442 1443 1444 1445 1446
}

impl Clean<Item> for doctree::Enum {
    fn clean(&self) -> Item {
        Item {
            name: Some(self.name.clean()),
            attrs: self.attrs.clean(),
1447
            source: self.whence.clean(),
1448
            def_id: ast_util::local_def(self.id),
C
Corey Richardson 已提交
1449
            visibility: self.vis.clean(),
1450
            stability: self.stab.clean(),
C
Corey Richardson 已提交
1451 1452 1453
            inner: EnumItem(Enum {
                variants: self.variants.clean(),
                generics: self.generics.clean(),
S
Steven Fackler 已提交
1454
                variants_stripped: false,
C
Corey Richardson 已提交
1455 1456 1457 1458 1459 1460 1461
            }),
        }
    }
}

#[deriving(Clone, Encodable, Decodable)]
pub struct Variant {
1462
    pub kind: VariantKind,
C
Corey Richardson 已提交
1463 1464 1465 1466 1467 1468 1469
}

impl Clean<Item> for doctree::Variant {
    fn clean(&self) -> Item {
        Item {
            name: Some(self.name.clean()),
            attrs: self.attrs.clean(),
1470
            source: self.whence.clean(),
C
Corey Richardson 已提交
1471
            visibility: self.vis.clean(),
1472
            stability: self.stab.clean(),
1473
            def_id: ast_util::local_def(self.id),
C
Corey Richardson 已提交
1474 1475 1476 1477 1478 1479 1480
            inner: VariantItem(Variant {
                kind: self.kind.clean(),
            }),
        }
    }
}

1481 1482 1483
impl Clean<Item> for ty::VariantInfo {
    fn clean(&self) -> Item {
        // use syntax::parse::token::special_idents::unnamed_field;
1484
        let cx = get_cx();
1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499
        let kind = match self.arg_names.as_ref().map(|s| s.as_slice()) {
            None | Some([]) if self.args.len() == 0 => CLikeVariant,
            None | Some([]) => {
                TupleVariant(self.args.iter().map(|t| t.clean()).collect())
            }
            Some(s) => {
                StructVariant(VariantStruct {
                    struct_type: doctree::Plain,
                    fields_stripped: false,
                    fields: s.iter().zip(self.args.iter()).map(|(name, ty)| {
                        Item {
                            source: Span::empty(),
                            name: Some(name.clean()),
                            attrs: Vec::new(),
                            visibility: Some(ast::Public),
1500 1501
                            // FIXME: this is not accurate, we need an id for
                            //        the specific field but we're using the id
A
Aaron Turon 已提交
1502 1503 1504 1505 1506
                            //        for the whole variant. Thus we read the
                            //        stability from the whole variant as well.
                            //        Struct variants are experimental and need
                            //        more infrastructure work before we can get
                            //        at the needed information here.
1507
                            def_id: self.id,
A
Aaron Turon 已提交
1508
                            stability: get_stability(self.id),
1509 1510 1511 1512 1513 1514 1515 1516 1517 1518
                            inner: StructFieldItem(
                                TypedStructField(ty.clean())
                            )
                        }
                    }).collect()
                })
            }
        };
        Item {
            name: Some(self.name.clean()),
1519
            attrs: inline::load_attrs(cx.tcx(), self.id),
1520 1521 1522 1523
            source: Span::empty(),
            visibility: Some(ast::Public),
            def_id: self.id,
            inner: VariantItem(Variant { kind: kind }),
A
Aaron Turon 已提交
1524
            stability: get_stability(self.id),
1525 1526 1527 1528
        }
    }
}

C
Corey Richardson 已提交
1529 1530 1531
#[deriving(Clone, Encodable, Decodable)]
pub enum VariantKind {
    CLikeVariant,
1532
    TupleVariant(Vec<Type>),
C
Corey Richardson 已提交
1533 1534 1535
    StructVariant(VariantStruct),
}

1536
impl Clean<VariantKind> for ast::VariantKind {
C
Corey Richardson 已提交
1537 1538
    fn clean(&self) -> VariantKind {
        match self {
1539
            &ast::TupleVariantKind(ref args) => {
C
Corey Richardson 已提交
1540 1541 1542 1543 1544 1545
                if args.len() == 0 {
                    CLikeVariant
                } else {
                    TupleVariant(args.iter().map(|x| x.ty.clean()).collect())
                }
            },
1546
            &ast::StructVariantKind(ref sd) => StructVariant(sd.clean()),
C
Corey Richardson 已提交
1547 1548 1549 1550
        }
    }
}

1551 1552
#[deriving(Clone, Encodable, Decodable)]
pub struct Span {
1553
    pub filename: String,
1554 1555 1556 1557
    pub loline: uint,
    pub locol: uint,
    pub hiline: uint,
    pub hicol: uint,
1558 1559
}

1560 1561 1562
impl Span {
    fn empty() -> Span {
        Span {
1563
            filename: "".to_string(),
1564 1565 1566 1567 1568 1569
            loline: 0, locol: 0,
            hiline: 0, hicol: 0,
        }
    }
}

1570 1571
impl Clean<Span> for syntax::codemap::Span {
    fn clean(&self) -> Span {
1572
        let ctxt = super::ctxtkey.get().unwrap();
N
Niko Matsakis 已提交
1573
        let cm = ctxt.sess().codemap();
1574 1575 1576 1577
        let filename = cm.span_to_filename(*self);
        let lo = cm.lookup_char_pos(self.lo);
        let hi = cm.lookup_char_pos(self.hi);
        Span {
1578
            filename: filename.to_string(),
1579
            loline: lo.line,
1580
            locol: lo.col.to_uint(),
1581
            hiline: hi.line,
1582
            hicol: hi.col.to_uint(),
1583
        }
C
Corey Richardson 已提交
1584 1585 1586
    }
}

1587
#[deriving(Clone, Encodable, Decodable, PartialEq)]
C
Corey Richardson 已提交
1588
pub struct Path {
1589 1590
    pub global: bool,
    pub segments: Vec<PathSegment>,
C
Corey Richardson 已提交
1591 1592 1593 1594 1595
}

impl Clean<Path> for ast::Path {
    fn clean(&self) -> Path {
        Path {
1596
            global: self.global,
1597
            segments: self.segments.clean(),
1598 1599 1600 1601
        }
    }
}

1602
#[deriving(Clone, Encodable, Decodable, PartialEq)]
1603
pub struct PathSegment {
1604
    pub name: String,
1605 1606
    pub lifetimes: Vec<Lifetime>,
    pub types: Vec<Type>,
1607 1608 1609 1610 1611 1612
}

impl Clean<PathSegment> for ast::PathSegment {
    fn clean(&self) -> PathSegment {
        PathSegment {
            name: self.identifier.clean(),
1613 1614
            lifetimes: self.lifetimes.clean(),
            types: self.types.clean(),
C
Corey Richardson 已提交
1615 1616 1617 1618
        }
    }
}

1619
fn path_to_string(p: &ast::Path) -> String {
1620
    let mut s = String::new();
C
Corey Richardson 已提交
1621
    let mut first = true;
1622
    for i in p.segments.iter().map(|x| token::get_ident(x.identifier)) {
C
Corey Richardson 已提交
1623 1624 1625 1626 1627
        if !first || p.global {
            s.push_str("::");
        } else {
            first = false;
        }
1628
        s.push_str(i.get());
C
Corey Richardson 已提交
1629
    }
1630
    s
C
Corey Richardson 已提交
1631 1632
}

1633 1634
impl Clean<String> for ast::Ident {
    fn clean(&self) -> String {
1635
        token::get_ident(*self).get().to_string()
C
Corey Richardson 已提交
1636 1637 1638
    }
}

1639 1640
impl Clean<String> for ast::Name {
    fn clean(&self) -> String {
1641
        token::get_name(*self).get().to_string()
1642 1643 1644
    }
}

C
Corey Richardson 已提交
1645 1646
#[deriving(Clone, Encodable, Decodable)]
pub struct Typedef {
1647 1648
    pub type_: Type,
    pub generics: Generics,
C
Corey Richardson 已提交
1649 1650 1651 1652 1653 1654 1655
}

impl Clean<Item> for doctree::Typedef {
    fn clean(&self) -> Item {
        Item {
            name: Some(self.name.clean()),
            attrs: self.attrs.clean(),
1656
            source: self.whence.clean(),
1657
            def_id: ast_util::local_def(self.id.clone()),
C
Corey Richardson 已提交
1658
            visibility: self.vis.clean(),
1659
            stability: self.stab.clean(),
C
Corey Richardson 已提交
1660 1661 1662 1663 1664 1665 1666 1667
            inner: TypedefItem(Typedef {
                type_: self.ty.clean(),
                generics: self.gen.clean(),
            }),
        }
    }
}

1668
#[deriving(Clone, Encodable, Decodable, PartialEq)]
C
Corey Richardson 已提交
1669
pub struct BareFunctionDecl {
1670
    pub fn_style: ast::FnStyle,
1671 1672
    pub generics: Generics,
    pub decl: FnDecl,
1673
    pub abi: String,
C
Corey Richardson 已提交
1674 1675
}

1676
impl Clean<BareFunctionDecl> for ast::BareFnTy {
C
Corey Richardson 已提交
1677 1678
    fn clean(&self) -> BareFunctionDecl {
        BareFunctionDecl {
1679
            fn_style: self.fn_style,
C
Corey Richardson 已提交
1680
            generics: Generics {
1681
                lifetimes: self.lifetimes.clean(),
1682
                type_params: Vec::new(),
C
Corey Richardson 已提交
1683 1684
            },
            decl: self.decl.clean(),
1685
            abi: self.abi.to_string(),
C
Corey Richardson 已提交
1686 1687 1688 1689 1690 1691
        }
    }
}

#[deriving(Clone, Encodable, Decodable)]
pub struct Static {
1692 1693
    pub type_: Type,
    pub mutability: Mutability,
C
Corey Richardson 已提交
1694 1695 1696
    /// It's useful to have the value of a static documented, but I have no
    /// desire to represent expressions (that'd basically be all of the AST,
    /// which is huge!). So, have a string.
1697
    pub expr: String,
C
Corey Richardson 已提交
1698 1699 1700 1701
}

impl Clean<Item> for doctree::Static {
    fn clean(&self) -> Item {
1702
        debug!("claning static {}: {:?}", self.name.clean(), self);
C
Corey Richardson 已提交
1703 1704 1705
        Item {
            name: Some(self.name.clean()),
            attrs: self.attrs.clean(),
1706
            source: self.whence.clean(),
1707
            def_id: ast_util::local_def(self.id),
C
Corey Richardson 已提交
1708
            visibility: self.vis.clean(),
1709
            stability: self.stab.clean(),
C
Corey Richardson 已提交
1710 1711 1712 1713 1714 1715 1716 1717 1718
            inner: StaticItem(Static {
                type_: self.type_.clean(),
                mutability: self.mutability.clean(),
                expr: self.expr.span.to_src(),
            }),
        }
    }
}

1719
#[deriving(Show, Clone, Encodable, Decodable, PartialEq)]
C
Corey Richardson 已提交
1720 1721 1722 1723 1724
pub enum Mutability {
    Mutable,
    Immutable,
}

1725
impl Clean<Mutability> for ast::Mutability {
C
Corey Richardson 已提交
1726 1727
    fn clean(&self) -> Mutability {
        match self {
1728 1729
            &ast::MutMutable => Mutable,
            &ast::MutImmutable => Immutable,
C
Corey Richardson 已提交
1730 1731 1732 1733 1734 1735
        }
    }
}

#[deriving(Clone, Encodable, Decodable)]
pub struct Impl {
1736 1737 1738
    pub generics: Generics,
    pub trait_: Option<Type>,
    pub for_: Type,
1739
    pub items: Vec<Item>,
1740
    pub derived: bool,
C
Corey Richardson 已提交
1741 1742
}

1743
fn detect_derived<M: AttrMetaMethods>(attrs: &[M]) -> bool {
1744
    attr::contains_name(attrs, "automatically_derived")
1745 1746
}

C
Corey Richardson 已提交
1747 1748 1749 1750 1751
impl Clean<Item> for doctree::Impl {
    fn clean(&self) -> Item {
        Item {
            name: None,
            attrs: self.attrs.clean(),
1752
            source: self.whence.clean(),
1753
            def_id: ast_util::local_def(self.id),
C
Corey Richardson 已提交
1754
            visibility: self.vis.clean(),
1755
            stability: self.stab.clean(),
C
Corey Richardson 已提交
1756 1757 1758 1759
            inner: ImplItem(Impl {
                generics: self.generics.clean(),
                trait_: self.trait_.clean(),
                for_: self.for_.clean(),
1760 1761 1762 1763 1764
                items: self.items.clean().move_iter().map(|ti| {
                        match ti {
                            MethodImplItem(i) => i,
                        }
                    }).collect(),
1765
                derived: detect_derived(self.attrs.as_slice()),
C
Corey Richardson 已提交
1766 1767 1768 1769 1770 1771 1772
            }),
        }
    }
}

#[deriving(Clone, Encodable, Decodable)]
pub struct ViewItem {
1773
    pub inner: ViewItemInner,
C
Corey Richardson 已提交
1774 1775
}

1776 1777
impl Clean<Vec<Item>> for ast::ViewItem {
    fn clean(&self) -> Vec<Item> {
J
Joseph Crail 已提交
1778
        // We consider inlining the documentation of `pub use` statements, but we
1779 1780
        // forcefully don't inline if this is not public or if the
        // #[doc(no_inline)] attribute is present.
1781 1782
        let denied = self.vis != ast::Public || self.attrs.iter().any(|a| {
            a.name().get() == "doc" && match a.meta_item_list() {
1783
                Some(l) => attr::contains_name(l, "no_inline"),
1784 1785 1786 1787 1788 1789
                None => false,
            }
        });
        let convert = |node: &ast::ViewItem_| {
            Item {
                name: None,
1790
                attrs: self.attrs.clean(),
1791 1792 1793
                source: self.span.clean(),
                def_id: ast_util::local_def(0),
                visibility: self.vis.clean(),
1794
                stability: None,
1795 1796 1797 1798 1799 1800 1801 1802 1803
                inner: ViewItemItem(ViewItem { inner: node.clean() }),
            }
        };
        let mut ret = Vec::new();
        match self.node {
            ast::ViewItemUse(ref path) if !denied => {
                match path.node {
                    ast::ViewPathGlob(..) => ret.push(convert(&self.node)),
                    ast::ViewPathList(ref a, ref list, ref b) => {
1804 1805 1806
                        // Attempt to inline all reexported items, but be sure
                        // to keep any non-inlineable reexports so they can be
                        // listed in the documentation.
1807
                        let remaining = list.iter().filter(|path| {
1808
                            match inline::try_inline(path.node.id(), None) {
1809 1810 1811
                                Some(items) => {
                                    ret.extend(items.move_iter()); false
                                }
1812 1813
                                None => true,
                            }
J
Jakub Wieczorek 已提交
1814
                        }).map(|a| a.clone()).collect::<Vec<ast::PathListItem>>();
1815 1816 1817 1818 1819
                        if remaining.len() > 0 {
                            let path = ast::ViewPathList(a.clone(),
                                                         remaining,
                                                         b.clone());
                            let path = syntax::codemap::dummy_spanned(path);
1820
                            ret.push(convert(&ast::ViewItemUse(box(GC) path)));
1821 1822
                        }
                    }
1823 1824
                    ast::ViewPathSimple(ident, _, id) => {
                        match inline::try_inline(id, Some(ident)) {
1825
                            Some(items) => ret.extend(items.move_iter()),
1826 1827 1828 1829 1830 1831
                            None => ret.push(convert(&self.node)),
                        }
                    }
                }
            }
            ref n => ret.push(convert(n)),
C
Corey Richardson 已提交
1832
        }
1833
        return ret;
C
Corey Richardson 已提交
1834 1835 1836 1837 1838
    }
}

#[deriving(Clone, Encodable, Decodable)]
pub enum ViewItemInner {
1839
    ExternCrate(String, Option<String>, ast::NodeId),
1840
    Import(ViewPath)
C
Corey Richardson 已提交
1841 1842
}

1843
impl Clean<ViewItemInner> for ast::ViewItem_ {
C
Corey Richardson 已提交
1844 1845
    fn clean(&self) -> ViewItemInner {
        match self {
1846
            &ast::ViewItemExternCrate(ref i, ref p, ref id) => {
P
Patrick Walton 已提交
1847 1848
                let string = match *p {
                    None => None,
1849
                    Some((ref x, _)) => Some(x.get().to_string()),
P
Patrick Walton 已提交
1850
                };
1851
                ExternCrate(i.clean(), string, *id)
P
Patrick Walton 已提交
1852
            }
1853
            &ast::ViewItemUse(ref vp) => {
1854
                Import(vp.clean())
1855
            }
C
Corey Richardson 已提交
1856 1857 1858 1859 1860 1861
        }
    }
}

#[deriving(Clone, Encodable, Decodable)]
pub enum ViewPath {
A
Alex Crichton 已提交
1862
    // use str = source;
1863
    SimpleImport(String, ImportSource),
A
Alex Crichton 已提交
1864 1865 1866
    // use source::*;
    GlobImport(ImportSource),
    // use source::{a, b, c};
1867
    ImportList(ImportSource, Vec<ViewListIdent>),
A
Alex Crichton 已提交
1868 1869 1870 1871
}

#[deriving(Clone, Encodable, Decodable)]
pub struct ImportSource {
1872 1873
    pub path: Path,
    pub did: Option<ast::DefId>,
C
Corey Richardson 已提交
1874 1875
}

1876
impl Clean<ViewPath> for ast::ViewPath {
C
Corey Richardson 已提交
1877 1878
    fn clean(&self) -> ViewPath {
        match self.node {
1879
            ast::ViewPathSimple(ref i, ref p, id) =>
A
Alex Crichton 已提交
1880
                SimpleImport(i.clean(), resolve_use_source(p.clean(), id)),
1881
            ast::ViewPathGlob(ref p, id) =>
A
Alex Crichton 已提交
1882
                GlobImport(resolve_use_source(p.clean(), id)),
1883 1884
            ast::ViewPathList(ref p, ref pl, id) => {
                ImportList(resolve_use_source(p.clean(), id),
1885
                           pl.clean())
1886
            }
C
Corey Richardson 已提交
1887 1888 1889 1890
        }
    }
}

A
Alex Crichton 已提交
1891 1892
#[deriving(Clone, Encodable, Decodable)]
pub struct ViewListIdent {
1893
    pub name: String,
1894
    pub source: Option<ast::DefId>,
A
Alex Crichton 已提交
1895
}
C
Corey Richardson 已提交
1896

J
Jakub Wieczorek 已提交
1897
impl Clean<ViewListIdent> for ast::PathListItem {
C
Corey Richardson 已提交
1898
    fn clean(&self) -> ViewListIdent {
J
Jakub Wieczorek 已提交
1899 1900 1901 1902 1903 1904 1905 1906 1907
        match self.node {
            ast::PathListIdent { id, name } => ViewListIdent {
                name: name.clean(),
                source: resolve_def(id)
            },
            ast::PathListMod { id } => ViewListIdent {
                name: "mod".to_string(),
                source: resolve_def(id)
            }
A
Alex Crichton 已提交
1908
        }
C
Corey Richardson 已提交
1909 1910 1911
    }
}

1912 1913
impl Clean<Vec<Item>> for ast::ForeignMod {
    fn clean(&self) -> Vec<Item> {
1914 1915 1916 1917
        self.items.clean()
    }
}

1918
impl Clean<Item> for ast::ForeignItem {
1919 1920
    fn clean(&self) -> Item {
        let inner = match self.node {
1921
            ast::ForeignItemFn(ref decl, ref generics) => {
1922 1923 1924
                ForeignFunctionItem(Function {
                    decl: decl.clean(),
                    generics: generics.clean(),
1925
                    fn_style: ast::UnsafeFn,
1926 1927
                })
            }
1928
            ast::ForeignItemStatic(ref ty, mutbl) => {
1929 1930 1931
                ForeignStaticItem(Static {
                    type_: ty.clean(),
                    mutability: if mutbl {Mutable} else {Immutable},
1932
                    expr: "".to_string(),
1933 1934 1935 1936 1937
                })
            }
        };
        Item {
            name: Some(self.ident.clean()),
1938
            attrs: self.attrs.clean(),
1939
            source: self.span.clean(),
1940
            def_id: ast_util::local_def(self.id),
1941
            visibility: self.vis.clean(),
A
Aaron Turon 已提交
1942
            stability: get_stability(ast_util::local_def(self.id)),
1943 1944 1945 1946 1947
            inner: inner,
        }
    }
}

C
Corey Richardson 已提交
1948 1949 1950
// Utilities

trait ToSource {
1951
    fn to_src(&self) -> String;
C
Corey Richardson 已提交
1952 1953
}

1954
impl ToSource for syntax::codemap::Span {
1955
    fn to_src(&self) -> String {
1956
        debug!("converting span {:?} to snippet", self.clean());
1957
        let ctxt = super::ctxtkey.get().unwrap();
N
Niko Matsakis 已提交
1958
        let cm = ctxt.sess().codemap().clone();
C
Corey Richardson 已提交
1959
        let sn = match cm.span_to_snippet(*self) {
1960 1961
            Some(x) => x.to_string(),
            None    => "".to_string()
C
Corey Richardson 已提交
1962
        };
1963
        debug!("got snippet {}", sn);
C
Corey Richardson 已提交
1964 1965 1966 1967
        sn
    }
}

1968
fn lit_to_string(lit: &ast::Lit) -> String {
C
Corey Richardson 已提交
1969
    match lit.node {
1970
        ast::LitStr(ref st, _) => st.get().to_string(),
A
Alex Crichton 已提交
1971
        ast::LitBinary(ref data) => format!("{:?}", data.as_slice()),
1972 1973 1974 1975 1976 1977 1978 1979
        ast::LitByte(b) => {
            let mut res = String::from_str("b'");
            (b as char).escape_default(|c| {
                res.push_char(c);
            });
            res.push_char('\'');
            res
        },
A
Alex Crichton 已提交
1980
        ast::LitChar(c) => format!("'{}'", c),
1981
        ast::LitInt(i, _t) => i.to_string(),
1982 1983
        ast::LitFloat(ref f, _t) => f.get().to_string(),
        ast::LitFloatUnsuffixed(ref f) => f.get().to_string(),
1984
        ast::LitBool(b) => b.to_string(),
1985
        ast::LitNil => "".to_string(),
C
Corey Richardson 已提交
1986 1987 1988
    }
}

1989
fn name_from_pat(p: &ast::Pat) -> String {
C
Corey Richardson 已提交
1990
    use syntax::ast::*;
1991 1992
    debug!("Trying to get a name from pattern: {:?}", p);

C
Corey Richardson 已提交
1993
    match p.node {
1994 1995
        PatWild(PatWildSingle) => "_".to_string(),
        PatWild(PatWildMulti) => "..".to_string(),
1996
        PatIdent(_, ref p, _) => token::get_ident(p.node).get().to_string(),
1997
        PatEnum(ref p, _) => path_to_string(p),
1998 1999 2000 2001 2002 2003 2004 2005 2006 2007
        PatStruct(ref name, ref fields, etc) => {
            format!("{} {{ {}{} }}", path_to_string(name),
                fields.iter().map(|fp|
                                  format!("{}: {}", fp.ident.as_str(), name_from_pat(&*fp.pat)))
                             .collect::<Vec<String>>().connect(", "),
                if etc { ", ..." } else { "" }
            )
        },
        PatTup(ref elts) => format!("({})", elts.iter().map(|p| name_from_pat(&**p))
                                            .collect::<Vec<String>>().connect(", ")),
2008 2009
        PatBox(p) => name_from_pat(&*p),
        PatRegion(p) => name_from_pat(&*p),
2010 2011 2012
        PatLit(..) => {
            warn!("tried to get argument name from PatLit, \
                  which is silly in function arguments");
2013
            "()".to_string()
2014 2015
        },
        PatRange(..) => fail!("tried to get argument name from PatRange, \
2016
                              which is not allowed in function arguments"),
A
Alex Crichton 已提交
2017
        PatVec(..) => fail!("tried to get argument name from pat_vec, \
2018 2019 2020 2021 2022 2023
                             which is not allowed in function arguments"),
        PatMac(..) => {
            warn!("can't document the name of a function argument \
                   produced by a pattern macro");
            "(argument produced by macro)".to_string()
        }
C
Corey Richardson 已提交
2024 2025 2026 2027
    }
}

/// Given a Type, resolve it using the def_map
2028
fn resolve_type(path: Path, tpbs: Option<Vec<TyParamBound>>,
2029
                id: ast::NodeId) -> Type {
2030
    let cx = get_cx();
E
Eduard Burtescu 已提交
2031 2032
    let tycx = match cx.maybe_typed {
        core::Typed(ref tycx) => tycx,
2033
        // If we're extracting tests, this return value doesn't matter.
2034
        core::NotTyped(_) => return Primitive(Bool),
2035
    };
2036
    debug!("searching for {:?} in defmap", id);
2037
    let def = match tycx.def_map.borrow().find(&id) {
2038
        Some(&k) => k,
2039
        None => fail!("unresolved id not in defmap")
C
Corey Richardson 已提交
2040 2041
    };

2042
    match def {
2043 2044
        def::DefSelfTy(i) => return Self(ast_util::local_def(i)),
        def::DefPrimTy(p) => match p {
2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059
            ast::TyStr => return Primitive(Str),
            ast::TyBool => return Primitive(Bool),
            ast::TyChar => return Primitive(Char),
            ast::TyInt(ast::TyI) => return Primitive(Int),
            ast::TyInt(ast::TyI8) => return Primitive(I8),
            ast::TyInt(ast::TyI16) => return Primitive(I16),
            ast::TyInt(ast::TyI32) => return Primitive(I32),
            ast::TyInt(ast::TyI64) => return Primitive(I64),
            ast::TyUint(ast::TyU) => return Primitive(Uint),
            ast::TyUint(ast::TyU8) => return Primitive(U8),
            ast::TyUint(ast::TyU16) => return Primitive(U16),
            ast::TyUint(ast::TyU32) => return Primitive(U32),
            ast::TyUint(ast::TyU64) => return Primitive(U64),
            ast::TyFloat(ast::TyF32) => return Primitive(F32),
            ast::TyFloat(ast::TyF64) => return Primitive(F64),
C
Corey Richardson 已提交
2060
        },
2061
        def::DefTyParam(_, i, _) => return Generic(i),
2062
        def::DefTyParamBinder(i) => return TyParamBinder(i),
2063 2064
        _ => {}
    };
2065
    let did = register_def(&*cx, def);
2066 2067 2068
    ResolvedPath { path: path, typarams: tpbs, did: did }
}

2069
fn register_def(cx: &core::DocContext, def: def::Def) -> ast::DefId {
2070
    let (did, kind) = match def {
2071 2072 2073 2074 2075 2076 2077 2078
        def::DefFn(i, _) => (i, TypeFunction),
        def::DefTy(i) => (i, TypeEnum),
        def::DefTrait(i) => (i, TypeTrait),
        def::DefStruct(i) => (i, TypeStruct),
        def::DefMod(i) => (i, TypeModule),
        def::DefStatic(i, _) => (i, TypeStatic),
        def::DefVariant(i, _, _) => (i, TypeEnum),
        _ => return def.def_id()
C
Corey Richardson 已提交
2079
    };
2080 2081 2082 2083 2084
    if ast_util::is_local(did) { return did }
    let tcx = match cx.maybe_typed {
        core::Typed(ref t) => t,
        core::NotTyped(_) => return did
    };
2085
    inline::record_extern_fqn(cx, did, kind);
2086 2087
    match kind {
        TypeTrait => {
2088
            let t = inline::build_external_trait(tcx, did);
2089 2090 2091 2092
            cx.external_traits.borrow_mut().get_mut_ref().insert(did, t);
        }
        _ => {}
    }
2093
    return did;
C
Corey Richardson 已提交
2094
}
A
Alex Crichton 已提交
2095 2096 2097 2098 2099 2100 2101 2102 2103

fn resolve_use_source(path: Path, id: ast::NodeId) -> ImportSource {
    ImportSource {
        path: path,
        did: resolve_def(id),
    }
}

fn resolve_def(id: ast::NodeId) -> Option<ast::DefId> {
2104 2105 2106
    get_cx().tcx_opt().and_then(|tcx| {
        tcx.def_map.borrow().find(&id).map(|&def| register_def(&*get_cx(), def))
    })
A
Alex Crichton 已提交
2107
}
2108 2109 2110

#[deriving(Clone, Encodable, Decodable)]
pub struct Macro {
2111
    pub source: String,
2112 2113 2114 2115 2116
}

impl Clean<Item> for doctree::Macro {
    fn clean(&self) -> Item {
        Item {
A
Alex Crichton 已提交
2117
            name: Some(format!("{}!", self.name.clean())),
2118
            attrs: self.attrs.clean(),
2119
            source: self.whence.clean(),
2120
            visibility: ast::Public.clean(),
2121
            stability: self.stab.clean(),
2122
            def_id: ast_util::local_def(self.id),
2123
            inner: MacroItem(Macro {
2124
                source: self.whence.to_src(),
2125 2126 2127 2128
            }),
        }
    }
}
2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144

#[deriving(Clone, Encodable, Decodable)]
pub struct Stability {
    pub level: attr::StabilityLevel,
    pub text: String
}

impl Clean<Stability> for attr::Stability {
    fn clean(&self) -> Stability {
        Stability {
            level: self.level,
            text: self.text.as_ref().map_or("".to_string(),
                                            |interned| interned.get().to_string()),
        }
    }
}
A
Alex Crichton 已提交
2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170

fn lang_struct(did: Option<ast::DefId>, t: ty::t, name: &str,
               fallback: fn(Box<Type>) -> Type) -> Type {
    let did = match did {
        Some(did) => did,
        None => return fallback(box t.clean()),
    };
    let fqn = csearch::get_item_path(get_cx().tcx(), did);
    let fqn: Vec<String> = fqn.move_iter().map(|i| {
        i.to_string()
    }).collect();
    get_cx().external_paths.borrow_mut().get_mut_ref()
                           .insert(did, (fqn, TypeStruct));
    ResolvedPath {
        typarams: None,
        did: did,
        path: Path {
            global: false,
            segments: vec![PathSegment {
                name: name.to_string(),
                lifetimes: vec![],
                types: vec![t.clean()],
            }],
        },
    }
}