mod.rs 79.1 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
//! This module contains the "cleaned" pieces of the AST, and the functions
//! that clean them.

S
Steven Fackler 已提交
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
pub use self::ImplMethod::*;
pub use self::Type::*;
pub use self::PrimitiveType::*;
pub use self::TypeKind::*;
pub use self::StructField::*;
pub use self::VariantKind::*;
pub use self::Mutability::*;
pub use self::ViewItemInner::*;
pub use self::ViewPath::*;
pub use self::ItemEnum::*;
pub use self::Attribute::*;
pub use self::TyParamBound::*;
pub use self::SelfTy::*;
pub use self::FunctionRetTy::*;
pub use self::TraitMethod::*;

C
Corey Richardson 已提交
30 31
use syntax;
use syntax::ast;
32
use syntax::ast_util;
33
use syntax::ast_util::PostExpansionMethod;
34
use syntax::attr;
35
use syntax::attr::{AttributeMethods, AttrMetaMethods};
36
use syntax::codemap::{DUMMY_SP, Pos, Spanned};
37
use syntax::parse::token::{self, InternedString, special_idents};
38
use syntax::ptr::P;
C
Corey Richardson 已提交
39

40
use rustc_trans::back::link;
41 42 43
use rustc::metadata::cstore;
use rustc::metadata::csearch;
use rustc::metadata::decoder;
44
use rustc::middle::def;
45
use rustc::middle::subst::{self, ParamSpace, VecPerParamSpace};
46
use rustc::middle::ty;
47
use rustc::middle::stability;
48
use rustc::session::config;
49

50
use std::rc::Rc;
51
use std::u32;
S
Steven Fackler 已提交
52
use std::str::Str as StrTrait; // Conflicts with Str variant
53
use std::path::Path as FsPath; // Conflicts with Path struct
54

55
use core::DocContext;
C
Corey Richardson 已提交
56 57 58
use doctree;
use visit_ast;

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

63 64
mod inline;

65 66 67
// extract the stability index for a node from tcx, if possible
fn get_stability(cx: &DocContext, def_id: ast::DefId) -> Option<Stability> {
    cx.tcx_opt().and_then(|tcx| stability::lookup(tcx, def_id)).clean(cx)
68 69
}

C
Corey Richardson 已提交
70
pub trait Clean<T> {
71
    fn clean(&self, cx: &DocContext) -> T;
C
Corey Richardson 已提交
72 73
}

74
impl<T: Clean<U>, U> Clean<Vec<U>> for Vec<T> {
75 76
    fn clean(&self, cx: &DocContext) -> Vec<U> {
        self.iter().map(|x| x.clean(cx)).collect()
77 78 79
    }
}

80
impl<T: Clean<U>, U> Clean<VecPerParamSpace<U>> for VecPerParamSpace<T> {
81 82
    fn clean(&self, cx: &DocContext) -> VecPerParamSpace<U> {
        self.map(|x| x.clean(cx))
83 84 85
    }
}

86
impl<T: Clean<U>, U> Clean<U> for P<T> {
87 88
    fn clean(&self, cx: &DocContext) -> U {
        (**self).clean(cx)
C
Corey Richardson 已提交
89 90 91
    }
}

92
impl<T: Clean<U>, U> Clean<U> for Rc<T> {
93 94
    fn clean(&self, cx: &DocContext) -> U {
        (**self).clean(cx)
95 96 97
    }
}

C
Corey Richardson 已提交
98
impl<T: Clean<U>, U> Clean<Option<U>> for Option<T> {
99
    fn clean(&self, cx: &DocContext) -> Option<U> {
C
Corey Richardson 已提交
100 101
        match self {
            &None => None,
102
            &Some(ref v) => Some(v.clean(cx))
C
Corey Richardson 已提交
103 104 105 106
        }
    }
}

107
impl<T: Clean<U>, U> Clean<Vec<U>> for syntax::owned_slice::OwnedSlice<T> {
108 109
    fn clean(&self, cx: &DocContext) -> Vec<U> {
        self.iter().map(|x| x.clean(cx)).collect()
C
Corey Richardson 已提交
110 111 112
    }
}

113
#[derive(Clone, RustcEncodable, RustcDecodable)]
C
Corey Richardson 已提交
114
pub struct Crate {
115
    pub name: String,
116
    pub src: FsPath,
117 118
    pub module: Option<Item>,
    pub externs: Vec<(ast::CrateNum, ExternalCrate)>,
119
    pub primitives: Vec<PrimitiveType>,
C
Corey Richardson 已提交
120 121
}

122 123
impl<'a, 'tcx> Clean<Crate> for visit_ast::RustdocVisitor<'a, 'tcx> {
    fn clean(&self, cx: &DocContext) -> Crate {
124
        let mut externs = Vec::new();
E
Eduard Burtescu 已提交
125
        cx.sess().cstore.iter_crate_data(|n, meta| {
126
            externs.push((n, meta.clean(cx)));
127
        });
128
        externs.sort_by(|&(a, _), &(b, _)| a.cmp(&b));
C
Corey Richardson 已提交
129

130
        // Figure out the name of this crate
131
        let input = config::Input::File(cx.src.clone());
132
        let name = link::find_crate_name(None, self.attrs.as_slice(), &input);
133

134
        // Clean the crate, translating the entire libsyntax AST to one that is
135
        // understood by rustdoc.
136
        let mut module = self.module.clean(cx);
137 138 139

        // Collect all inner modules which are tagged as implementations of
        // primitives.
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
        //
        // 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.
155 156 157 158 159 160 161
        let mut primitives = Vec::new();
        {
            let m = match module.inner {
                ModuleItem(ref mut m) => m,
                _ => unreachable!(),
            };
            let mut tmp = Vec::new();
A
Aaron Turon 已提交
162
            for child in m.items.iter_mut() {
163 164
                match child.inner {
                    ModuleItem(..) => {}
165
                    _ => continue,
166
                }
167
                let prim = match PrimitiveType::find(child.attrs.as_slice()) {
168 169 170 171
                    Some(prim) => prim,
                    None => continue,
                };
                primitives.push(prim);
172
                tmp.push(Item {
173 174
                    source: Span::empty(),
                    name: Some(prim.to_url_str().to_string()),
175 176
                    attrs: child.attrs.clone(),
                    visibility: Some(ast::Public),
177
                    stability: None,
178 179
                    def_id: ast_util::local_def(prim.to_node_id()),
                    inner: PrimitiveItem(prim),
180
                });
181
            }
A
Aaron Turon 已提交
182
            m.items.extend(tmp.into_iter());
183 184
        }

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

195
#[derive(Clone, RustcEncodable, RustcDecodable)]
196
pub struct ExternalCrate {
197
    pub name: String,
198
    pub attrs: Vec<Attribute>,
199
    pub primitives: Vec<PrimitiveType>,
200 201 202
}

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

/// 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.
228
#[derive(Clone, RustcEncodable, RustcDecodable)]
C
Corey Richardson 已提交
229 230
pub struct Item {
    /// Stringified span
231
    pub source: Span,
C
Corey Richardson 已提交
232
    /// Not everything has a name. E.g., impls
233
    pub name: Option<String>,
234 235 236
    pub attrs: Vec<Attribute> ,
    pub inner: ItemEnum,
    pub visibility: Option<Visibility>,
237
    pub def_id: ast::DefId,
238
    pub stability: Option<Stability>,
C
Corey Richardson 已提交
239 240
}

241 242 243 244 245 246
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 {
247
                List(ref x, ref list) if "doc" == *x => {
248 249
                    return Some(list.as_slice());
                }
250 251 252 253 254 255 256 257 258 259 260
                _ => {}
            }
        }
        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 {
261
                NameValue(ref x, ref v) if "doc" == *x => {
262 263
                    return Some(v.as_slice());
                }
264 265 266 267 268 269
                _ => {}
            }
        }
        return None;
    }

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

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

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

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

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

        // determine if we should display the inner contents or
        // the outer `mod` item for the source code.
370
        let whence = {
371
            let cm = cx.sess().codemap();
372 373 374 375 376 377 378 379 380 381 382
            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 已提交
383 384
        Item {
            name: Some(name),
385 386 387 388
            attrs: self.attrs.clean(cx),
            source: whence.clean(cx),
            visibility: self.vis.clean(cx),
            stability: self.stab.clean(cx),
389
            def_id: ast_util::local_def(self.id),
C
Corey Richardson 已提交
390
            inner: ModuleItem(Module {
391
               is_crate: self.is_crate,
392 393 394
               items: items.iter()
                           .flat_map(|x| x.iter().map(|x| (*x).clone()))
                           .collect(),
C
Corey Richardson 已提交
395 396 397 398 399
            })
        }
    }
}

400
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Show)]
C
Corey Richardson 已提交
401
pub enum Attribute {
402 403 404
    Word(String),
    List(String, Vec<Attribute> ),
    NameValue(String, String)
C
Corey Richardson 已提交
405 406 407
}

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

impl Clean<Attribute> for ast::Attribute {
422
    fn clean(&self, cx: &DocContext) -> Attribute {
423
        self.with_desugared_doc(|a| a.node.value.clean(cx))
C
Corey Richardson 已提交
424 425 426
    }
}

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

437
    fn value_str(&self) -> Option<InternedString> {
438
        match *self {
439 440 441
            NameValue(_, ref v) => {
                Some(token::intern_and_get_ident(v.as_slice()))
            }
442 443 444
            _ => None,
        }
    }
445
    fn meta_item_list<'a>(&'a self) -> Option<&'a [P<ast::MetaItem>]> { None }
446
}
447 448 449
impl<'a> attr::AttrMetaMethods for &'a Attribute {
    fn name(&self) -> InternedString { (**self).name() }
    fn value_str(&self) -> Option<InternedString> { (**self).value_str() }
N
Niko Matsakis 已提交
450
    fn meta_item_list(&self) -> Option<&[P<ast::MetaItem>]> { None }
451
}
452

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

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

472
impl<'tcx> Clean<TyParam> for ty::TypeParameterDef<'tcx> {
473 474
    fn clean(&self, cx: &DocContext) -> TyParam {
        cx.external_typarams.borrow_mut().as_mut().unwrap()
475
          .insert(self.def_id, self.name.clean(cx));
N
Nick Cameron 已提交
476
        let bounds = self.bounds.clean(cx);
477
        TyParam {
478
            name: self.name.clean(cx),
479
            did: self.def_id,
480 481
            bounds: bounds,
            default: self.default.clean(cx),
482 483 484 485
        }
    }
}

486
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Show)]
C
Corey Richardson 已提交
487
pub enum TyParamBound {
488
    RegionBound(Lifetime),
N
Nick Cameron 已提交
489
    TraitBound(PolyTrait, ast::TraitBoundModifier)
C
Corey Richardson 已提交
490 491 492
}

impl Clean<TyParamBound> for ast::TyParamBound {
493
    fn clean(&self, cx: &DocContext) -> TyParamBound {
C
Corey Richardson 已提交
494
        match *self {
495
            ast::RegionTyParamBound(lt) => RegionBound(lt.clean(cx)),
N
Nick Cameron 已提交
496
            ast::TraitTyParamBound(ref t, modifier) => TraitBound(t.clean(cx), modifier),
C
Corey Richardson 已提交
497 498 499 500
        }
    }
}

501
impl<'tcx> Clean<Vec<TyParamBound>> for ty::ExistentialBounds<'tcx> {
502
    fn clean(&self, cx: &DocContext) -> Vec<TyParamBound> {
503 504
        let mut vec = vec![];
        self.region_bound.clean(cx).map(|b| vec.push(RegionBound(b)));
505
        for bb in self.builtin_bounds.iter() {
506
            vec.push(bb.clean(cx));
507
        }
N
Niko Matsakis 已提交
508 509 510

        // FIXME(#20299) -- should do something with projection bounds

511 512 513 514
        vec
    }
}

515 516 517
fn external_path_params(cx: &DocContext, trait_did: Option<ast::DefId>,
                        substs: &subst::Substs) -> PathParameters {
    use rustc::middle::ty::sty;
518
    let lifetimes = substs.regions().get_slice(subst::TypeSpace)
519
                    .iter()
520
                    .filter_map(|v| v.clean(cx))
521
                    .collect();
522
    let types = substs.types.get_slice(subst::TypeSpace).to_vec();
523 524 525 526 527 528 529 530 531 532

    match (trait_did, cx.tcx_opt()) {
        // Attempt to sugar an external path like Fn<(A, B,), C> to Fn(A, B) -> C
        (Some(did), Some(ref tcx)) if tcx.lang_items.fn_trait_kind(did).is_some() => {
            assert_eq!(types.len(), 2);
            let inputs = match types[0].sty {
                sty::ty_tup(ref tys) => tys.iter().map(|t| t.clean(cx)).collect(),
                _ => {
                    return PathParameters::AngleBracketed {
                        lifetimes: lifetimes,
533 534
                        types: types.clean(cx),
                        bindings: vec![]
535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550
                    }
                }
            };
            let output = match types[1].sty {
                sty::ty_tup(ref v) if v.is_empty() => None, // -> ()
                _ => Some(types[1].clean(cx))
            };
            PathParameters::Parenthesized {
                inputs: inputs,
                output: output
            }
        },
        (_, _) => {
            PathParameters::AngleBracketed {
                lifetimes: lifetimes,
                types: types.clean(cx),
551
                bindings: vec![] // FIXME(#20646)
552 553 554 555 556 557 558 559 560
            }
        }
    }
}

// trait_did should be set to a trait's DefId if called on a TraitRef, in order to sugar
// from Fn<(A, B,), C> to Fn(A, B) -> C
fn external_path(cx: &DocContext, name: &str, trait_did: Option<ast::DefId>,
                 substs: &subst::Substs) -> Path {
561 562 563
    Path {
        global: false,
        segments: vec![PathSegment {
564
            name: name.to_string(),
565
            params: external_path_params(cx, trait_did, substs)
566
        }],
567 568 569 570
    }
}

impl Clean<TyParamBound> for ty::BuiltinBound {
571 572 573
    fn clean(&self, cx: &DocContext) -> TyParamBound {
        let tcx = match cx.tcx_opt() {
            Some(tcx) => tcx,
574
            None => return RegionBound(Lifetime::statik())
575
        };
576
        let empty = subst::Substs::empty();
577 578
        let (did, path) = match *self {
            ty::BoundSend =>
579
                (tcx.lang_items.send_trait().unwrap(),
580
                 external_path(cx, "Send", None, &empty)),
581
            ty::BoundSized =>
582
                (tcx.lang_items.sized_trait().unwrap(),
583
                 external_path(cx, "Sized", None, &empty)),
584
            ty::BoundCopy =>
585
                (tcx.lang_items.copy_trait().unwrap(),
586
                 external_path(cx, "Copy", None, &empty)),
A
Alex Crichton 已提交
587 588
            ty::BoundSync =>
                (tcx.lang_items.sync_trait().unwrap(),
589
                 external_path(cx, "Sync", None, &empty)),
590 591
        };
        let fqn = csearch::get_item_path(tcx, did);
A
Aaron Turon 已提交
592
        let fqn = fqn.into_iter().map(|i| i.to_string()).collect();
593 594
        cx.external_paths.borrow_mut().as_mut().unwrap().insert(did,
                                                                (fqn, TypeTrait));
595 596 597 598 599 600 601
        TraitBound(PolyTrait {
            trait_: ResolvedPath {
                path: path,
                typarams: None,
                did: did,
            },
            lifetimes: vec![]
N
Nick Cameron 已提交
602
        }, ast::TraitBoundModifier::None)
603 604 605
    }
}

606 607
impl<'tcx> Clean<TyParamBound> for ty::PolyTraitRef<'tcx> {
    fn clean(&self, cx: &DocContext) -> TyParamBound {
608
        self.0.clean(cx)
609 610 611
    }
}

612
impl<'tcx> Clean<TyParamBound> for ty::TraitRef<'tcx> {
613 614 615
    fn clean(&self, cx: &DocContext) -> TyParamBound {
        let tcx = match cx.tcx_opt() {
            Some(tcx) => tcx,
616
            None => return RegionBound(Lifetime::statik())
617 618
        };
        let fqn = csearch::get_item_path(tcx, self.def_id);
A
Aaron Turon 已提交
619
        let fqn = fqn.into_iter().map(|i| i.to_string())
620
                     .collect::<Vec<String>>();
621
        let path = external_path(cx, fqn.last().unwrap().as_slice(),
H
Huon Wilson 已提交
622
                                 Some(self.def_id), self.substs);
623
        cx.external_paths.borrow_mut().as_mut().unwrap().insert(self.def_id,
624
                                                            (fqn, TypeTrait));
625

626
        debug!("ty::TraitRef\n  substs.types(TypeSpace): {:?}\n",
627 628 629 630 631 632 633 634 635
               self.substs.types.get_slice(ParamSpace::TypeSpace));

        // collect any late bound regions
        let mut late_bounds = vec![];
        for &ty_s in self.substs.types.get_slice(ParamSpace::TypeSpace).iter() {
            use rustc::middle::ty::{Region, sty};
            if let sty::ty_tup(ref ts) = ty_s.sty {
                for &ty_s in ts.iter() {
                    if let sty::ty_rptr(ref reg, _) = ty_s.sty {
H
Huon Wilson 已提交
636
                        if let &Region::ReLateBound(_, _) = *reg {
637
                            debug!("  hit an ReLateBound {:?}", reg);
638 639 640 641 642 643 644 645 646 647 648 649
                            if let Some(lt) = reg.clean(cx) {
                                late_bounds.push(lt)
                            }
                        }
                    }
                }
            }
        }

        TraitBound(PolyTrait {
            trait_: ResolvedPath { path: path, typarams: None, did: self.def_id, },
            lifetimes: late_bounds
N
Nick Cameron 已提交
650
        }, ast::TraitBoundModifier::None)
651 652 653
    }
}

N
Nick Cameron 已提交
654 655
impl<'tcx> Clean<Vec<TyParamBound>> for ty::ParamBounds<'tcx> {
    fn clean(&self, cx: &DocContext) -> Vec<TyParamBound> {
656 657
        let mut v = Vec::new();
        for t in self.trait_bounds.iter() {
658
            v.push(t.clean(cx));
659
        }
660 661 662
        for r in self.region_bounds.iter().filter_map(|r| r.clean(cx)) {
            v.push(RegionBound(r));
        }
N
Nick Cameron 已提交
663
        v
664 665 666
    }
}

667
impl<'tcx> Clean<Option<Vec<TyParamBound>>> for subst::Substs<'tcx> {
668
    fn clean(&self, cx: &DocContext) -> Option<Vec<TyParamBound>> {
669
        let mut v = Vec::new();
670
        v.extend(self.regions().iter().filter_map(|r| r.clean(cx)).map(RegionBound));
671 672 673
        v.extend(self.types.iter().map(|t| TraitBound(PolyTrait {
            trait_: t.clean(cx),
            lifetimes: vec![]
N
Nick Cameron 已提交
674
        }, ast::TraitBoundModifier::None)));
675 676 677 678
        if v.len() > 0 {Some(v)} else {None}
    }
}

679
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Show)]
680
pub struct Lifetime(String);
C
Corey Richardson 已提交
681

682 683 684
impl Lifetime {
    pub fn get_ref<'a>(&'a self) -> &'a str {
        let Lifetime(ref s) = *self;
685
        let s: &'a str = s.as_slice();
686 687
        return s;
    }
688 689 690 691

    pub fn statik() -> Lifetime {
        Lifetime("'static".to_string())
    }
692 693
}

C
Corey Richardson 已提交
694
impl Clean<Lifetime> for ast::Lifetime {
695
    fn clean(&self, _: &DocContext) -> Lifetime {
696
        Lifetime(token::get_name(self.name).get().to_string())
C
Corey Richardson 已提交
697 698 699
    }
}

700
impl Clean<Lifetime> for ast::LifetimeDef {
701
    fn clean(&self, _: &DocContext) -> Lifetime {
702 703 704 705
        Lifetime(token::get_name(self.lifetime.name).get().to_string())
    }
}

706
impl Clean<Lifetime> for ty::RegionParameterDef {
707
    fn clean(&self, _: &DocContext) -> Lifetime {
708
        Lifetime(token::get_name(self.name).get().to_string())
709 710 711 712
    }
}

impl Clean<Option<Lifetime>> for ty::Region {
713
    fn clean(&self, cx: &DocContext) -> Option<Lifetime> {
714
        match *self {
715
            ty::ReStatic => Some(Lifetime::statik()),
716
            ty::ReLateBound(_, ty::BrNamed(_, name)) =>
717
                Some(Lifetime(token::get_name(name).get().to_string())),
718
            ty::ReEarlyBound(_, _, _, name) => Some(Lifetime(name.clean(cx))),
719 720 721 722 723 724 725 726 727 728

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

729
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Show)]
730 731 732 733 734
pub enum WherePredicate {
    BoundPredicate { ty: Type, bounds: Vec<TyParamBound> },
    RegionPredicate { lifetime: Lifetime, bounds: Vec<Lifetime>},
    // FIXME (#20041)
    EqPredicate
735 736 737 738
}

impl Clean<WherePredicate> for ast::WherePredicate {
    fn clean(&self, cx: &DocContext) -> WherePredicate {
N
Nick Cameron 已提交
739 740
        match *self {
            ast::WherePredicate::BoundPredicate(ref wbp) => {
741
                WherePredicate::BoundPredicate {
742
                    ty: wbp.bounded_ty.clean(cx),
N
Nick Cameron 已提交
743 744 745
                    bounds: wbp.bounds.clean(cx)
                }
            }
746 747 748 749 750 751 752 753 754 755

            ast::WherePredicate::RegionPredicate(ref wrp) => {
                WherePredicate::RegionPredicate {
                    lifetime: wrp.lifetime.clean(cx),
                    bounds: wrp.bounds.clean(cx)
                }
            }

            ast::WherePredicate::EqPredicate(_) => {
                WherePredicate::EqPredicate
N
Nick Cameron 已提交
756
            }
757 758 759 760
        }
    }
}

C
Corey Richardson 已提交
761
// maybe use a Generic enum and use ~[Generic]?
762
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Show)]
C
Corey Richardson 已提交
763
pub struct Generics {
764 765
    pub lifetimes: Vec<Lifetime>,
    pub type_params: Vec<TyParam>,
766
    pub where_predicates: Vec<WherePredicate>
767
}
C
Corey Richardson 已提交
768 769

impl Clean<Generics> for ast::Generics {
770
    fn clean(&self, cx: &DocContext) -> Generics {
C
Corey Richardson 已提交
771
        Generics {
772 773
            lifetimes: self.lifetimes.clean(cx),
            type_params: self.ty_params.clean(cx),
774
            where_predicates: self.where_clause.predicates.clean(cx)
C
Corey Richardson 已提交
775 776 777 778
        }
    }
}

779
impl<'a, 'tcx> Clean<Generics> for (&'a ty::Generics<'tcx>, subst::ParamSpace) {
780
    fn clean(&self, cx: &DocContext) -> Generics {
781
        let (me, space) = *self;
782
        Generics {
783 784
            type_params: me.types.get_slice(space).to_vec().clean(cx),
            lifetimes: me.regions.get_slice(space).to_vec().clean(cx),
785
            where_predicates: vec![]
786 787 788 789
        }
    }
}

790
#[derive(Clone, RustcEncodable, RustcDecodable)]
C
Corey Richardson 已提交
791
pub struct Method {
792 793
    pub generics: Generics,
    pub self_: SelfTy,
N
Niko Matsakis 已提交
794
    pub unsafety: ast::Unsafety,
795
    pub decl: FnDecl,
C
Corey Richardson 已提交
796 797
}

798
impl Clean<Item> for ast::Method {
799
    fn clean(&self, cx: &DocContext) -> Item {
800 801 802
        let all_inputs = &self.pe_fn_decl().inputs;
        let inputs = match self.pe_explicit_self().node {
            ast::SelfStatic => all_inputs.as_slice(),
J
Jorge Aparicio 已提交
803
            _ => &all_inputs[1..]
804 805
        };
        let decl = FnDecl {
806
            inputs: Arguments {
807
                values: inputs.iter().map(|x| x.clean(cx)).collect(),
808
            },
809
            output: self.pe_fn_decl().output.clean(cx),
810
            attrs: Vec::new()
811
        };
C
Corey Richardson 已提交
812
        Item {
813 814 815
            name: Some(self.pe_ident().clean(cx)),
            attrs: self.attrs.clean(cx),
            source: self.span.clean(cx),
816
            def_id: ast_util::local_def(self.id),
817 818
            visibility: self.pe_vis().clean(cx),
            stability: get_stability(cx, ast_util::local_def(self.id)),
C
Corey Richardson 已提交
819
            inner: MethodItem(Method {
820 821
                generics: self.pe_generics().clean(cx),
                self_: self.pe_explicit_self().node.clean(cx),
N
Niko Matsakis 已提交
822
                unsafety: self.pe_unsafety().clone(),
823
                decl: decl,
C
Corey Richardson 已提交
824 825 826 827 828
            }),
        }
    }
}

829
#[derive(Clone, RustcEncodable, RustcDecodable)]
C
Corey Richardson 已提交
830
pub struct TyMethod {
N
Niko Matsakis 已提交
831
    pub unsafety: ast::Unsafety,
832 833 834
    pub decl: FnDecl,
    pub generics: Generics,
    pub self_: SelfTy,
C
Corey Richardson 已提交
835 836 837
}

impl Clean<Item> for ast::TypeMethod {
838
    fn clean(&self, cx: &DocContext) -> Item {
839 840
        let inputs = match self.explicit_self.node {
            ast::SelfStatic => self.decl.inputs.as_slice(),
J
Jorge Aparicio 已提交
841
            _ => &self.decl.inputs[1..]
842 843
        };
        let decl = FnDecl {
844
            inputs: Arguments {
845
                values: inputs.iter().map(|x| x.clean(cx)).collect(),
846
            },
847
            output: self.decl.output.clean(cx),
848
            attrs: Vec::new()
849
        };
C
Corey Richardson 已提交
850
        Item {
851 852 853
            name: Some(self.ident.clean(cx)),
            attrs: self.attrs.clean(cx),
            source: self.span.clean(cx),
854
            def_id: ast_util::local_def(self.id),
C
Corey Richardson 已提交
855
            visibility: None,
856
            stability: get_stability(cx, ast_util::local_def(self.id)),
C
Corey Richardson 已提交
857
            inner: TyMethodItem(TyMethod {
N
Niko Matsakis 已提交
858
                unsafety: self.unsafety.clone(),
859
                decl: decl,
860 861
                self_: self.explicit_self.node.clean(cx),
                generics: self.generics.clean(cx),
C
Corey Richardson 已提交
862 863 864 865 866
            }),
        }
    }
}

867
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq)]
C
Corey Richardson 已提交
868 869 870 871
pub enum SelfTy {
    SelfStatic,
    SelfValue,
    SelfBorrowed(Option<Lifetime>, Mutability),
872
    SelfExplicit(Type),
C
Corey Richardson 已提交
873 874
}

875
impl Clean<SelfTy> for ast::ExplicitSelf_ {
876
    fn clean(&self, cx: &DocContext) -> SelfTy {
877
        match *self {
878
            ast::SelfStatic => SelfStatic,
879
            ast::SelfValue(_) => SelfValue,
880
            ast::SelfRegion(ref lt, ref mt, _) => {
881
                SelfBorrowed(lt.clean(cx), mt.clean(cx))
882
            }
883
            ast::SelfExplicit(ref typ, _) => SelfExplicit(typ.clean(cx)),
C
Corey Richardson 已提交
884 885 886 887
        }
    }
}

888
#[derive(Clone, RustcEncodable, RustcDecodable)]
C
Corey Richardson 已提交
889
pub struct Function {
890 891
    pub decl: FnDecl,
    pub generics: Generics,
N
Niko Matsakis 已提交
892
    pub unsafety: ast::Unsafety,
C
Corey Richardson 已提交
893 894 895
}

impl Clean<Item> for doctree::Function {
896
    fn clean(&self, cx: &DocContext) -> Item {
C
Corey Richardson 已提交
897
        Item {
898 899 900 901 902
            name: Some(self.name.clean(cx)),
            attrs: self.attrs.clean(cx),
            source: self.whence.clean(cx),
            visibility: self.vis.clean(cx),
            stability: self.stab.clean(cx),
903
            def_id: ast_util::local_def(self.id),
C
Corey Richardson 已提交
904
            inner: FunctionItem(Function {
905 906
                decl: self.decl.clean(cx),
                generics: self.generics.clean(cx),
N
Niko Matsakis 已提交
907
                unsafety: self.unsafety,
C
Corey Richardson 已提交
908 909 910 911 912
            }),
        }
    }
}

913
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Show)]
C
Corey Richardson 已提交
914
pub struct ClosureDecl {
915 916 917
    pub lifetimes: Vec<Lifetime>,
    pub decl: FnDecl,
    pub onceness: ast::Onceness,
N
Niko Matsakis 已提交
918
    pub unsafety: ast::Unsafety,
919 920
    pub bounds: Vec<TyParamBound>,
}
C
Corey Richardson 已提交
921

922
impl Clean<ClosureDecl> for ast::ClosureTy {
923
    fn clean(&self, cx: &DocContext) -> ClosureDecl {
C
Corey Richardson 已提交
924
        ClosureDecl {
925 926
            lifetimes: self.lifetimes.clean(cx),
            decl: self.decl.clean(cx),
C
Corey Richardson 已提交
927
            onceness: self.onceness,
N
Niko Matsakis 已提交
928
            unsafety: self.unsafety,
929
            bounds: self.bounds.clean(cx)
C
Corey Richardson 已提交
930 931 932 933
        }
    }
}

934
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Show)]
C
Corey Richardson 已提交
935
pub struct FnDecl {
936
    pub inputs: Arguments,
937
    pub output: FunctionRetTy,
938 939
    pub attrs: Vec<Attribute>,
}
C
Corey Richardson 已提交
940

941
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Show)]
942
pub struct Arguments {
943
    pub values: Vec<Argument>,
944 945
}

946
impl Clean<FnDecl> for ast::FnDecl {
947
    fn clean(&self, cx: &DocContext) -> FnDecl {
C
Corey Richardson 已提交
948
        FnDecl {
949
            inputs: Arguments {
950
                values: self.inputs.clean(cx),
951
            },
952
            output: self.output.clean(cx),
953
            attrs: Vec::new()
C
Corey Richardson 已提交
954 955 956 957
        }
    }
}

958
impl<'tcx> Clean<Type> for ty::FnOutput<'tcx> {
J
Jakub Bukaj 已提交
959 960 961 962 963 964 965 966
    fn clean(&self, cx: &DocContext) -> Type {
        match *self {
            ty::FnConverging(ty) => ty.clean(cx),
            ty::FnDiverging => Bottom
        }
    }
}

967
impl<'a, 'tcx> Clean<FnDecl> for (ast::DefId, &'a ty::PolyFnSig<'tcx>) {
968
    fn clean(&self, cx: &DocContext) -> FnDecl {
969 970
        let (did, sig) = *self;
        let mut names = if did.node != 0 {
A
Aaron Turon 已提交
971
            csearch::get_method_arg_names(&cx.tcx().sess.cstore, did).into_iter()
972
        } else {
A
Aaron Turon 已提交
973
            Vec::new().into_iter()
974 975 976 977
        }.peekable();
        if names.peek().map(|s| s.as_slice()) == Some("self") {
            let _ = names.next();
        }
978
        FnDecl {
979
            output: Return(sig.0.output.clean(cx)),
980
            attrs: Vec::new(),
981
            inputs: Arguments {
982
                values: sig.0.inputs.iter().map(|t| {
983
                    Argument {
984
                        type_: t.clean(cx),
985
                        id: 0,
986
                        name: names.next().unwrap_or("".to_string()),
987 988 989 990 991 992 993
                    }
                }).collect(),
            },
        }
    }
}

994
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Show)]
C
Corey Richardson 已提交
995
pub struct Argument {
996
    pub type_: Type,
997
    pub name: String,
998
    pub id: ast::NodeId,
C
Corey Richardson 已提交
999 1000
}

1001
impl Clean<Argument> for ast::Arg {
1002
    fn clean(&self, cx: &DocContext) -> Argument {
C
Corey Richardson 已提交
1003
        Argument {
1004
            name: name_from_pat(&*self.pat),
1005
            type_: (self.ty.clean(cx)),
C
Corey Richardson 已提交
1006 1007 1008 1009 1010
            id: self.id
        }
    }
}

1011
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Show)]
1012 1013 1014
pub enum FunctionRetTy {
    Return(Type),
    NoReturn
C
Corey Richardson 已提交
1015 1016
}

1017 1018
impl Clean<FunctionRetTy> for ast::FunctionRetTy {
    fn clean(&self, cx: &DocContext) -> FunctionRetTy {
C
Corey Richardson 已提交
1019
        match *self {
1020 1021
            ast::Return(ref typ) => Return(typ.clean(cx)),
            ast::NoReturn(_) => NoReturn
C
Corey Richardson 已提交
1022 1023 1024 1025
        }
    }
}

1026
#[derive(Clone, RustcEncodable, RustcDecodable)]
C
Corey Richardson 已提交
1027
pub struct Trait {
1028
    pub unsafety: ast::Unsafety,
1029
    pub items: Vec<TraitMethod>,
1030
    pub generics: Generics,
1031
    pub bounds: Vec<TyParamBound>,
C
Corey Richardson 已提交
1032 1033 1034
}

impl Clean<Item> for doctree::Trait {
1035
    fn clean(&self, cx: &DocContext) -> Item {
C
Corey Richardson 已提交
1036
        Item {
1037 1038 1039
            name: Some(self.name.clean(cx)),
            attrs: self.attrs.clean(cx),
            source: self.whence.clean(cx),
1040
            def_id: ast_util::local_def(self.id),
1041 1042
            visibility: self.vis.clean(cx),
            stability: self.stab.clean(cx),
C
Corey Richardson 已提交
1043
            inner: TraitItem(Trait {
1044
                unsafety: self.unsafety,
1045 1046 1047
                items: self.items.clean(cx),
                generics: self.generics.clean(cx),
                bounds: self.bounds.clean(cx),
C
Corey Richardson 已提交
1048 1049 1050 1051 1052
            }),
        }
    }
}

1053
impl Clean<Type> for ast::TraitRef {
1054
    fn clean(&self, cx: &DocContext) -> Type {
N
Niko Matsakis 已提交
1055
        resolve_type(cx, self.path.clean(cx), self.ref_id)
C
Corey Richardson 已提交
1056 1057 1058
    }
}

1059 1060 1061 1062 1063 1064
impl Clean<PolyTrait> for ast::PolyTraitRef {
    fn clean(&self, cx: &DocContext) -> PolyTrait {
        PolyTrait {
            trait_: self.trait_ref.clean(cx),
            lifetimes: self.bound_lifetimes.clean(cx)
        }
N
Niko Matsakis 已提交
1065 1066 1067
    }
}

1068 1069
/// An item belonging to a trait, whether a method or associated. Could be named
/// TraitItem except that's already taken by an exported enum variant.
1070
#[derive(Clone, RustcEncodable, RustcDecodable)]
1071
pub enum TraitMethod {
1072 1073
    RequiredMethod(Item),
    ProvidedMethod(Item),
1074
    TypeTraitItem(Item),
C
Corey Richardson 已提交
1075 1076
}

1077
impl TraitMethod {
1078
    pub fn is_req(&self) -> bool {
C
Corey Richardson 已提交
1079
        match self {
1080
            &RequiredMethod(..) => true,
C
Corey Richardson 已提交
1081 1082 1083
            _ => false,
        }
    }
1084
    pub fn is_def(&self) -> bool {
C
Corey Richardson 已提交
1085
        match self {
1086
            &ProvidedMethod(..) => true,
C
Corey Richardson 已提交
1087 1088 1089
            _ => false,
        }
    }
1090 1091 1092 1093 1094 1095
    pub fn is_type(&self) -> bool {
        match self {
            &TypeTraitItem(..) => true,
            _ => false,
        }
    }
1096 1097
    pub fn item<'a>(&'a self) -> &'a Item {
        match *self {
1098 1099
            RequiredMethod(ref item) => item,
            ProvidedMethod(ref item) => item,
1100
            TypeTraitItem(ref item) => item,
1101 1102
        }
    }
C
Corey Richardson 已提交
1103 1104
}

1105 1106
impl Clean<TraitMethod> for ast::TraitItem {
    fn clean(&self, cx: &DocContext) -> TraitMethod {
C
Corey Richardson 已提交
1107
        match self {
1108 1109
            &ast::RequiredMethod(ref t) => RequiredMethod(t.clean(cx)),
            &ast::ProvidedMethod(ref t) => ProvidedMethod(t.clean(cx)),
1110
            &ast::TypeTraitItem(ref t) => TypeTraitItem(t.clean(cx)),
1111 1112 1113 1114
        }
    }
}

1115
#[derive(Clone, RustcEncodable, RustcDecodable)]
1116
pub enum ImplMethod {
1117
    MethodImplItem(Item),
1118
    TypeImplItem(Item),
1119 1120
}

1121 1122
impl Clean<ImplMethod> for ast::ImplItem {
    fn clean(&self, cx: &DocContext) -> ImplMethod {
1123
        match self {
1124
            &ast::MethodImplItem(ref t) => MethodImplItem(t.clean(cx)),
1125
            &ast::TypeImplItem(ref t) => TypeImplItem(t.clean(cx)),
C
Corey Richardson 已提交
1126 1127 1128 1129
        }
    }
}

1130
impl<'tcx> Clean<Item> for ty::Method<'tcx> {
1131
    fn clean(&self, cx: &DocContext) -> Item {
1132
        let (self_, sig) = match self.explicit_self {
1133
            ty::StaticExplicitSelfCategory => (ast::SelfStatic.clean(cx),
A
Alex Crichton 已提交
1134
                                               self.fty.sig.clone()),
1135
            s => {
1136
                let sig = ty::Binder(ty::FnSig {
J
Jorge Aparicio 已提交
1137
                    inputs: self.fty.sig.0.inputs[1..].to_vec(),
1138 1139
                    ..self.fty.sig.0.clone()
                });
1140
                let s = match s {
A
Alex Crichton 已提交
1141
                    ty::ByValueExplicitSelfCategory => SelfValue,
1142
                    ty::ByReferenceExplicitSelfCategory(..) => {
1143
                        match self.fty.sig.0.inputs[0].sty {
1144
                            ty::ty_rptr(r, mt) => {
1145
                                SelfBorrowed(r.clean(cx), mt.mutbl.clean(cx))
1146
                            }
A
Alex Crichton 已提交
1147
                            _ => unreachable!(),
1148 1149
                        }
                    }
A
Alex Crichton 已提交
1150
                    ty::ByBoxExplicitSelfCategory => {
1151
                        SelfExplicit(self.fty.sig.0.inputs[0].clean(cx))
1152
                    }
A
Alex Crichton 已提交
1153
                    ty::StaticExplicitSelfCategory => unreachable!(),
1154 1155 1156 1157
                };
                (s, sig)
            }
        };
1158

1159
        Item {
1160
            name: Some(self.name.clean(cx)),
1161
            visibility: Some(ast::Inherited),
1162
            stability: get_stability(cx, self.def_id),
1163
            def_id: self.def_id,
1164
            attrs: inline::load_attrs(cx, cx.tcx(), self.def_id),
1165
            source: Span::empty(),
1166
            inner: TyMethodItem(TyMethod {
N
Niko Matsakis 已提交
1167
                unsafety: self.fty.unsafety,
1168
                generics: (&self.generics, subst::FnSpace).clean(cx),
1169
                self_: self_,
1170
                decl: (self.def_id, &sig).clean(cx),
1171
            })
1172
        }
1173 1174 1175
    }
}

1176
impl<'tcx> Clean<Item> for ty::ImplOrTraitItem<'tcx> {
1177
    fn clean(&self, cx: &DocContext) -> Item {
1178
        match *self {
1179
            ty::MethodTraitItem(ref mti) => mti.clean(cx),
1180
            ty::TypeTraitItem(ref tti) => tti.clean(cx),
1181 1182 1183 1184
        }
    }
}

1185
/// A trait reference, which may have higher ranked lifetimes.
1186
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Show)]
1187 1188 1189 1190 1191
pub struct PolyTrait {
    pub trait_: Type,
    pub lifetimes: Vec<Lifetime>
}

C
Corey Richardson 已提交
1192 1193 1194
/// 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.
1195
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Show)]
C
Corey Richardson 已提交
1196
pub enum Type {
1197
    /// structs/enums/traits (anything that'd be an ast::TyPath)
1198
    ResolvedPath {
S
Steven Fackler 已提交
1199 1200 1201
        path: Path,
        typarams: Option<Vec<TyParamBound>>,
        did: ast::DefId,
1202
    },
C
Corey Richardson 已提交
1203 1204
    // I have no idea how to usefully use this.
    TyParamBinder(ast::NodeId),
1205 1206 1207
    /// For parameterized types, so the consumer of the JSON don't go
    /// looking for types which don't exist anywhere.
    Generic(String),
C
Corey Richardson 已提交
1208
    /// Primitives are just the fixed-size numeric types (plus int/uint/float), and char.
1209
    Primitive(PrimitiveType),
1210
    Closure(Box<ClosureDecl>),
1211
    Proc(Box<ClosureDecl>),
C
Corey Richardson 已提交
1212
    /// extern "ABI" fn
1213
    BareFunction(Box<BareFunctionDecl>),
1214
    Tuple(Vec<Type>),
1215
    Vector(Box<Type>),
1216
    FixedVector(Box<Type>, String),
1217
    /// aka TyBot
C
Corey Richardson 已提交
1218
    Bottom,
1219 1220
    Unique(Box<Type>),
    RawPointer(Mutability, Box<Type>),
1221
    BorrowedRef {
S
Steven Fackler 已提交
1222 1223 1224
        lifetime: Option<Lifetime>,
        mutability: Mutability,
        type_: Box<Type>,
1225
    },
1226 1227

    // <Type as Trait>::Name
T
Tom Jakubowski 已提交
1228 1229 1230 1231 1232
    QPath {
        name: String,
        self_type: Box<Type>,
        trait_: Box<Type>
    },
1233 1234 1235 1236 1237 1238

    // _
    Infer,

    // for<'a> Foo(&'a)
    PolyTraitRef(Vec<TyParamBound>),
C
Corey Richardson 已提交
1239 1240
}

1241
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Copy, Show)]
1242
pub enum PrimitiveType {
1243 1244
    Isize, I8, I16, I32, I64,
    Usize, U8, U16, U32, U64,
1245
    F32, F64,
1246 1247 1248 1249 1250 1251 1252
    Char,
    Bool,
    Str,
    Slice,
    PrimitiveTuple,
}

1253
#[derive(Clone, RustcEncodable, RustcDecodable, Copy)]
1254 1255 1256
pub enum TypeKind {
    TypeEnum,
    TypeFunction,
1257
    TypeModule,
1258
    TypeConst,
1259 1260 1261 1262
    TypeStatic,
    TypeStruct,
    TypeTrait,
    TypeVariant,
1263
    TypeTypedef,
1264 1265
}

1266 1267
impl PrimitiveType {
    fn from_str(s: &str) -> Option<PrimitiveType> {
1268
        match s.as_slice() {
1269
            "isize" | "int" => Some(Isize),
1270 1271 1272 1273
            "i8" => Some(I8),
            "i16" => Some(I16),
            "i32" => Some(I32),
            "i64" => Some(I64),
1274
            "usize" | "uint" => Some(Usize),
1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289
            "u8" => Some(U8),
            "u16" => Some(U16),
            "u32" => Some(U32),
            "u64" => Some(U64),
            "bool" => Some(Bool),
            "char" => Some(Char),
            "str" => Some(Str),
            "f32" => Some(F32),
            "f64" => Some(F64),
            "slice" => Some(Slice),
            "tuple" => Some(PrimitiveTuple),
            _ => None,
        }
    }

1290
    fn find(attrs: &[Attribute]) -> Option<PrimitiveType> {
1291 1292
        for attr in attrs.iter() {
            let list = match *attr {
1293
                List(ref k, ref l) if *k == "doc" => l,
1294 1295 1296 1297 1298
                _ => continue,
            };
            for sub_attr in list.iter() {
                let value = match *sub_attr {
                    NameValue(ref k, ref v)
1299
                        if *k == "primitive" => v.as_slice(),
1300 1301
                    _ => continue,
                };
1302
                match PrimitiveType::from_str(value) {
1303 1304 1305 1306 1307 1308 1309 1310
                    Some(p) => return Some(p),
                    None => {}
                }
            }
        }
        return None
    }

1311
    pub fn to_string(&self) -> &'static str {
1312
        match *self {
1313
            Isize => "isize",
1314 1315 1316 1317
            I8 => "i8",
            I16 => "i16",
            I32 => "i32",
            I64 => "i64",
1318
            Usize => "usize",
1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333
            U8 => "u8",
            U16 => "u16",
            U32 => "u32",
            U64 => "u64",
            F32 => "f32",
            F64 => "f64",
            Str => "str",
            Bool => "bool",
            Char => "char",
            Slice => "slice",
            PrimitiveTuple => "tuple",
        }
    }

    pub fn to_url_str(&self) -> &'static str {
1334
        self.to_string()
1335 1336 1337 1338 1339 1340 1341 1342 1343 1344
    }

    /// 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 已提交
1345
impl Clean<Type> for ast::Ty {
1346
    fn clean(&self, cx: &DocContext) -> Type {
C
Corey Richardson 已提交
1347
        use syntax::ast::*;
1348
        match self.node {
1349
            TyPtr(ref m) => RawPointer(m.mutbl.clean(cx), box m.ty.clean(cx)),
1350
            TyRptr(ref l, ref m) =>
1351 1352
                BorrowedRef {lifetime: l.clean(cx), mutability: m.mutbl.clean(cx),
                             type_: box m.ty.clean(cx)},
1353 1354 1355
            TyVec(ref ty) => Vector(box ty.clean(cx)),
            TyFixedLengthVec(ref ty, ref e) => FixedVector(box ty.clean(cx),
                                                           e.span.to_src(cx)),
1356
            TyTup(ref tys) => Tuple(tys.clean(cx)),
N
Niko Matsakis 已提交
1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369
            TyPath(ref p, id) => {
                resolve_type(cx, p.clean(cx), id)
            }
            TyObjectSum(ref lhs, ref bounds) => {
                let lhs_ty = lhs.clean(cx);
                match lhs_ty {
                    ResolvedPath { path, typarams: None, did } => {
                        ResolvedPath { path: path, typarams: Some(bounds.clean(cx)), did: did}
                    }
                    _ => {
                        lhs_ty // shouldn't happen
                    }
                }
1370
            }
1371 1372
            TyBareFn(ref barefn) => BareFunction(box barefn.clean(cx)),
            TyParen(ref ty) => ty.clean(cx),
T
Tom Jakubowski 已提交
1373
            TyQPath(ref qp) => qp.clean(cx),
1374 1375 1376 1377 1378 1379 1380
            TyPolyTraitRef(ref bounds) => {
                PolyTraitRef(bounds.clean(cx))
            },
            TyInfer(..) => {
                Infer
            },
            TyTypeof(..) => {
1381
                panic!("Unimplemented type {:?}", self.node)
1382
            },
1383
        }
C
Corey Richardson 已提交
1384 1385 1386
    }
}

1387
impl<'tcx> Clean<Type> for ty::Ty<'tcx> {
1388
    fn clean(&self, cx: &DocContext) -> Type {
1389
        match self.sty {
1390 1391
            ty::ty_bool => Primitive(Bool),
            ty::ty_char => Primitive(Char),
1392
            ty::ty_int(ast::TyIs(_)) => Primitive(Isize),
1393 1394 1395 1396
            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),
1397
            ty::ty_uint(ast::TyUs(_)) => Primitive(Usize),
1398 1399 1400 1401 1402 1403 1404
            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 已提交
1405
            ty::ty_uniq(t) => {
1406
                let box_did = cx.tcx_opt().and_then(|tcx| {
A
Alex Crichton 已提交
1407 1408
                    tcx.lang_items.owned_box()
                });
1409
                lang_struct(cx, box_did, t, "Box", Unique)
A
Alex Crichton 已提交
1410
            }
1411 1412
            ty::ty_vec(ty, None) => Vector(box ty.clean(cx)),
            ty::ty_vec(ty, Some(i)) => FixedVector(box ty.clean(cx),
A
Alex Crichton 已提交
1413
                                                   format!("{}", i)),
1414
            ty::ty_ptr(mt) => RawPointer(mt.mutbl.clean(cx), box mt.ty.clean(cx)),
1415
            ty::ty_rptr(r, mt) => BorrowedRef {
1416 1417 1418
                lifetime: r.clean(cx),
                mutability: mt.mutbl.clean(cx),
                type_: box mt.ty.clean(cx),
1419
            },
1420
            ty::ty_bare_fn(_, ref fty) => BareFunction(box BareFunctionDecl {
N
Niko Matsakis 已提交
1421
                unsafety: fty.unsafety,
1422
                generics: Generics {
1423 1424 1425
                    lifetimes: Vec::new(),
                    type_params: Vec::new(),
                    where_predicates: Vec::new()
1426
                },
1427
                decl: (ast_util::local_def(0), &fty.sig).clean(cx),
1428
                abi: fty.abi.to_string(),
1429
            }),
H
Huon Wilson 已提交
1430
            ty::ty_struct(did, substs) |
1431
            ty::ty_enum(did, substs) => {
1432
                let fqn = csearch::get_item_path(cx.tcx(), did);
1433
                let fqn: Vec<_> = fqn.into_iter().map(|i| i.to_string()).collect();
1434
                let kind = match self.sty {
1435 1436 1437
                    ty::ty_struct(..) => TypeStruct,
                    _ => TypeEnum,
                };
1438
                let path = external_path(cx, fqn.last().unwrap().to_string().as_slice(),
1439
                                         None, substs);
1440
                cx.external_paths.borrow_mut().as_mut().unwrap().insert(did, (fqn, kind));
1441
                ResolvedPath {
1442
                    path: path,
1443 1444 1445 1446
                    typarams: None,
                    did: did,
                }
            }
1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459
            ty::ty_trait(box ty::TyTrait { ref principal, ref bounds }) => {
                let did = principal.def_id();
                let fqn = csearch::get_item_path(cx.tcx(), did);
                let fqn: Vec<_> = fqn.into_iter().map(|i| i.to_string()).collect();
                let path = external_path(cx, fqn.last().unwrap().to_string().as_slice(),
                                         Some(did), principal.substs());
                cx.external_paths.borrow_mut().as_mut().unwrap().insert(did, (fqn, TypeTrait));
                ResolvedPath {
                    path: path,
                    typarams: Some(bounds.clean(cx)),
                    did: did,
                }
            }
1460
            ty::ty_tup(ref t) => Tuple(t.clean(cx)),
1461

1462 1463
            ty::ty_projection(ref data) => {
                let trait_ref = match data.trait_ref.clean(cx) {
N
Niko Matsakis 已提交
1464
                    TyParamBound::TraitBound(t, _) => t.trait_,
1465 1466 1467 1468 1469 1470 1471 1472 1473
                    TyParamBound::RegionBound(_) => panic!("cleaning a trait got a region??"),
                };
                Type::QPath {
                    name: data.item_name.clean(cx),
                    self_type: box data.trait_ref.self_ty().clean(cx),
                    trait_: box trait_ref,
                }
            }

1474
            ty::ty_param(ref p) => Generic(token::get_name(p.name).to_string()),
1475

1476
            ty::ty_unboxed_closure(..) => Tuple(vec![]), // FIXME(pcwalton)
1477

S
Steve Klabnik 已提交
1478 1479 1480
            ty::ty_infer(..) => panic!("ty_infer"),
            ty::ty_open(..) => panic!("ty_open"),
            ty::ty_err => panic!("ty_err"),
1481 1482 1483 1484
        }
    }
}

T
Tom Jakubowski 已提交
1485 1486 1487 1488 1489 1490 1491 1492 1493 1494
impl Clean<Type> for ast::QPath {
    fn clean(&self, cx: &DocContext) -> Type {
        Type::QPath {
            name: self.item_name.clean(cx),
            self_type: box self.self_type.clean(cx),
            trait_: box self.trait_ref.clean(cx)
        }
    }
}

1495
#[derive(Clone, RustcEncodable, RustcDecodable)]
1496
pub enum StructField {
1497
    HiddenStructField, // inserted later by strip passes
1498
    TypedStructField(Type),
C
Corey Richardson 已提交
1499 1500
}

1501
impl Clean<Item> for ast::StructField {
1502
    fn clean(&self, cx: &DocContext) -> Item {
C
Corey Richardson 已提交
1503
        let (name, vis) = match self.node.kind {
1504 1505
            ast::NamedField(id, vis) => (Some(id), vis),
            ast::UnnamedField(vis) => (None, vis)
C
Corey Richardson 已提交
1506 1507
        };
        Item {
1508 1509 1510
            name: name.clean(cx),
            attrs: self.node.attrs.clean(cx),
            source: self.span.clean(cx),
1511
            visibility: Some(vis),
1512
            stability: get_stability(cx, ast_util::local_def(self.node.id)),
1513
            def_id: ast_util::local_def(self.node.id),
1514
            inner: StructFieldItem(TypedStructField(self.node.ty.clean(cx))),
C
Corey Richardson 已提交
1515 1516 1517 1518
        }
    }
}

1519
impl Clean<Item> for ty::field_ty {
1520
    fn clean(&self, cx: &DocContext) -> Item {
1521
        use syntax::parse::token::special_idents::unnamed_field;
1522 1523 1524 1525
        use rustc::metadata::csearch;

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

1526 1527
        let (name, attrs) = if self.name == unnamed_field.name {
            (None, None)
1528
        } else {
1529
            (Some(self.name), Some(attr_map.get(&self.id.node).unwrap()))
1530
        };
1531

1532
        let ty = ty::lookup_item_type(cx.tcx(), self.id);
1533

1534
        Item {
1535 1536
            name: name.clean(cx),
            attrs: attrs.unwrap_or(&Vec::new()).clean(cx),
1537 1538
            source: Span::empty(),
            visibility: Some(self.vis),
1539
            stability: get_stability(cx, self.id),
1540
            def_id: self.id,
1541
            inner: StructFieldItem(TypedStructField(ty.ty.clean(cx))),
1542 1543 1544 1545
        }
    }
}

1546
pub type Visibility = ast::Visibility;
C
Corey Richardson 已提交
1547

1548
impl Clean<Option<Visibility>> for ast::Visibility {
1549
    fn clean(&self, _: &DocContext) -> Option<Visibility> {
C
Corey Richardson 已提交
1550 1551 1552 1553
        Some(*self)
    }
}

1554
#[derive(Clone, RustcEncodable, RustcDecodable)]
C
Corey Richardson 已提交
1555
pub struct Struct {
1556 1557 1558 1559
    pub struct_type: doctree::StructType,
    pub generics: Generics,
    pub fields: Vec<Item>,
    pub fields_stripped: bool,
C
Corey Richardson 已提交
1560 1561 1562
}

impl Clean<Item> for doctree::Struct {
1563
    fn clean(&self, cx: &DocContext) -> Item {
C
Corey Richardson 已提交
1564
        Item {
1565 1566 1567
            name: Some(self.name.clean(cx)),
            attrs: self.attrs.clean(cx),
            source: self.whence.clean(cx),
1568
            def_id: ast_util::local_def(self.id),
1569 1570
            visibility: self.vis.clean(cx),
            stability: self.stab.clean(cx),
C
Corey Richardson 已提交
1571 1572
            inner: StructItem(Struct {
                struct_type: self.struct_type,
1573 1574
                generics: self.generics.clean(cx),
                fields: self.fields.clean(cx),
S
Steven Fackler 已提交
1575
                fields_stripped: false,
C
Corey Richardson 已提交
1576 1577 1578 1579 1580
            }),
        }
    }
}

1581
/// This is a more limited form of the standard Struct, different in that
C
Corey Richardson 已提交
1582 1583
/// it lacks the things most items have (name, id, parameterization). Found
/// only as a variant in an enum.
1584
#[derive(Clone, RustcEncodable, RustcDecodable)]
C
Corey Richardson 已提交
1585
pub struct VariantStruct {
1586 1587 1588
    pub struct_type: doctree::StructType,
    pub fields: Vec<Item>,
    pub fields_stripped: bool,
C
Corey Richardson 已提交
1589 1590
}

1591
impl Clean<VariantStruct> for syntax::ast::StructDef {
1592
    fn clean(&self, cx: &DocContext) -> VariantStruct {
C
Corey Richardson 已提交
1593 1594
        VariantStruct {
            struct_type: doctree::struct_type_from_def(self),
1595
            fields: self.fields.clean(cx),
S
Steven Fackler 已提交
1596
            fields_stripped: false,
C
Corey Richardson 已提交
1597 1598 1599 1600
        }
    }
}

1601
#[derive(Clone, RustcEncodable, RustcDecodable)]
C
Corey Richardson 已提交
1602
pub struct Enum {
1603 1604 1605
    pub variants: Vec<Item>,
    pub generics: Generics,
    pub variants_stripped: bool,
C
Corey Richardson 已提交
1606 1607 1608
}

impl Clean<Item> for doctree::Enum {
1609
    fn clean(&self, cx: &DocContext) -> Item {
C
Corey Richardson 已提交
1610
        Item {
1611 1612 1613
            name: Some(self.name.clean(cx)),
            attrs: self.attrs.clean(cx),
            source: self.whence.clean(cx),
1614
            def_id: ast_util::local_def(self.id),
1615 1616
            visibility: self.vis.clean(cx),
            stability: self.stab.clean(cx),
C
Corey Richardson 已提交
1617
            inner: EnumItem(Enum {
1618 1619
                variants: self.variants.clean(cx),
                generics: self.generics.clean(cx),
S
Steven Fackler 已提交
1620
                variants_stripped: false,
C
Corey Richardson 已提交
1621 1622 1623 1624 1625
            }),
        }
    }
}

1626
#[derive(Clone, RustcEncodable, RustcDecodable)]
C
Corey Richardson 已提交
1627
pub struct Variant {
1628
    pub kind: VariantKind,
C
Corey Richardson 已提交
1629 1630 1631
}

impl Clean<Item> for doctree::Variant {
1632
    fn clean(&self, cx: &DocContext) -> Item {
C
Corey Richardson 已提交
1633
        Item {
1634 1635 1636 1637 1638
            name: Some(self.name.clean(cx)),
            attrs: self.attrs.clean(cx),
            source: self.whence.clean(cx),
            visibility: self.vis.clean(cx),
            stability: self.stab.clean(cx),
1639
            def_id: ast_util::local_def(self.id),
C
Corey Richardson 已提交
1640
            inner: VariantItem(Variant {
1641
                kind: self.kind.clean(cx),
C
Corey Richardson 已提交
1642 1643 1644 1645 1646
            }),
        }
    }
}

1647
impl<'tcx> Clean<Item> for ty::VariantInfo<'tcx> {
1648
    fn clean(&self, cx: &DocContext) -> Item {
1649 1650 1651 1652
        // use syntax::parse::token::special_idents::unnamed_field;
        let kind = match self.arg_names.as_ref().map(|s| s.as_slice()) {
            None | Some([]) if self.args.len() == 0 => CLikeVariant,
            None | Some([]) => {
1653
                TupleVariant(self.args.clean(cx))
1654 1655 1656 1657 1658 1659 1660 1661
            }
            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(),
1662
                            name: Some(name.clean(cx)),
1663 1664
                            attrs: Vec::new(),
                            visibility: Some(ast::Public),
1665 1666
                            // FIXME: this is not accurate, we need an id for
                            //        the specific field but we're using the id
A
Aaron Turon 已提交
1667 1668 1669 1670 1671
                            //        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.
1672
                            def_id: self.id,
1673
                            stability: get_stability(cx, self.id),
1674
                            inner: StructFieldItem(
1675
                                TypedStructField(ty.clean(cx))
1676 1677 1678 1679 1680 1681 1682
                            )
                        }
                    }).collect()
                })
            }
        };
        Item {
1683 1684
            name: Some(self.name.clean(cx)),
            attrs: inline::load_attrs(cx, cx.tcx(), self.id),
1685 1686 1687 1688
            source: Span::empty(),
            visibility: Some(ast::Public),
            def_id: self.id,
            inner: VariantItem(Variant { kind: kind }),
1689
            stability: get_stability(cx, self.id),
1690 1691 1692 1693
        }
    }
}

1694
#[derive(Clone, RustcEncodable, RustcDecodable)]
C
Corey Richardson 已提交
1695 1696
pub enum VariantKind {
    CLikeVariant,
1697
    TupleVariant(Vec<Type>),
C
Corey Richardson 已提交
1698 1699 1700
    StructVariant(VariantStruct),
}

1701
impl Clean<VariantKind> for ast::VariantKind {
1702
    fn clean(&self, cx: &DocContext) -> VariantKind {
C
Corey Richardson 已提交
1703
        match self {
1704
            &ast::TupleVariantKind(ref args) => {
C
Corey Richardson 已提交
1705 1706 1707
                if args.len() == 0 {
                    CLikeVariant
                } else {
1708
                    TupleVariant(args.iter().map(|x| x.ty.clean(cx)).collect())
C
Corey Richardson 已提交
1709 1710
                }
            },
1711
            &ast::StructVariantKind(ref sd) => StructVariant(sd.clean(cx)),
C
Corey Richardson 已提交
1712 1713 1714 1715
        }
    }
}

1716
#[derive(Clone, RustcEncodable, RustcDecodable, Show)]
1717
pub struct Span {
1718
    pub filename: String,
1719 1720 1721 1722
    pub loline: uint,
    pub locol: uint,
    pub hiline: uint,
    pub hicol: uint,
1723 1724
}

1725 1726 1727
impl Span {
    fn empty() -> Span {
        Span {
1728
            filename: "".to_string(),
1729 1730 1731 1732 1733 1734
            loline: 0, locol: 0,
            hiline: 0, hicol: 0,
        }
    }
}

1735
impl Clean<Span> for syntax::codemap::Span {
1736 1737
    fn clean(&self, cx: &DocContext) -> Span {
        let cm = cx.sess().codemap();
1738 1739 1740 1741
        let filename = cm.span_to_filename(*self);
        let lo = cm.lookup_char_pos(self.lo);
        let hi = cm.lookup_char_pos(self.hi);
        Span {
1742
            filename: filename.to_string(),
1743
            loline: lo.line,
1744
            locol: lo.col.to_uint(),
1745
            hiline: hi.line,
1746
            hicol: hi.col.to_uint(),
1747
        }
C
Corey Richardson 已提交
1748 1749 1750
    }
}

1751
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Show)]
C
Corey Richardson 已提交
1752
pub struct Path {
1753 1754
    pub global: bool,
    pub segments: Vec<PathSegment>,
C
Corey Richardson 已提交
1755 1756 1757
}

impl Clean<Path> for ast::Path {
1758
    fn clean(&self, cx: &DocContext) -> Path {
C
Corey Richardson 已提交
1759
        Path {
1760
            global: self.global,
1761
            segments: self.segments.clean(cx),
1762 1763 1764 1765
        }
    }
}

1766
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Show)]
1767 1768 1769 1770
pub enum PathParameters {
    AngleBracketed {
        lifetimes: Vec<Lifetime>,
        types: Vec<Type>,
1771
        bindings: Vec<TypeBinding>
1772 1773 1774 1775 1776
    },
    Parenthesized {
        inputs: Vec<Type>,
        output: Option<Type>
    }
1777 1778
}

1779 1780 1781
impl Clean<PathParameters> for ast::PathParameters {
    fn clean(&self, cx: &DocContext) -> PathParameters {
        match *self {
1782
            ast::AngleBracketedParameters(ref data) => {
1783 1784
                PathParameters::AngleBracketed {
                    lifetimes: data.lifetimes.clean(cx),
1785 1786
                    types: data.types.clean(cx),
                    bindings: data.bindings.clean(cx)
1787
                }
1788 1789 1790
            }

            ast::ParenthesizedParameters(ref data) => {
1791 1792 1793 1794
                PathParameters::Parenthesized {
                    inputs: data.inputs.clean(cx),
                    output: data.output.clean(cx)
                }
1795
            }
1796 1797 1798
        }
    }
}
1799

1800
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Show)]
1801 1802 1803 1804 1805 1806 1807
pub struct PathSegment {
    pub name: String,
    pub params: PathParameters
}

impl Clean<PathSegment> for ast::PathSegment {
    fn clean(&self, cx: &DocContext) -> PathSegment {
1808
        PathSegment {
1809
            name: self.identifier.clean(cx),
1810
            params: self.parameters.clean(cx)
C
Corey Richardson 已提交
1811 1812 1813 1814
        }
    }
}

1815
fn path_to_string(p: &ast::Path) -> String {
1816
    let mut s = String::new();
C
Corey Richardson 已提交
1817
    let mut first = true;
1818
    for i in p.segments.iter().map(|x| token::get_ident(x.identifier)) {
C
Corey Richardson 已提交
1819 1820 1821 1822 1823
        if !first || p.global {
            s.push_str("::");
        } else {
            first = false;
        }
1824
        s.push_str(i.get());
C
Corey Richardson 已提交
1825
    }
1826
    s
C
Corey Richardson 已提交
1827 1828
}

1829
impl Clean<String> for ast::Ident {
1830
    fn clean(&self, _: &DocContext) -> String {
1831
        token::get_ident(*self).get().to_string()
C
Corey Richardson 已提交
1832 1833 1834
    }
}

1835
impl Clean<String> for ast::Name {
1836
    fn clean(&self, _: &DocContext) -> String {
1837
        token::get_name(*self).get().to_string()
1838 1839 1840
    }
}

1841
#[derive(Clone, RustcEncodable, RustcDecodable)]
C
Corey Richardson 已提交
1842
pub struct Typedef {
1843 1844
    pub type_: Type,
    pub generics: Generics,
C
Corey Richardson 已提交
1845 1846 1847
}

impl Clean<Item> for doctree::Typedef {
1848
    fn clean(&self, cx: &DocContext) -> Item {
C
Corey Richardson 已提交
1849
        Item {
1850 1851 1852
            name: Some(self.name.clean(cx)),
            attrs: self.attrs.clean(cx),
            source: self.whence.clean(cx),
1853
            def_id: ast_util::local_def(self.id.clone()),
1854 1855
            visibility: self.vis.clean(cx),
            stability: self.stab.clean(cx),
C
Corey Richardson 已提交
1856
            inner: TypedefItem(Typedef {
1857 1858
                type_: self.ty.clean(cx),
                generics: self.gen.clean(cx),
C
Corey Richardson 已提交
1859 1860 1861 1862 1863
            }),
        }
    }
}

1864
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Show)]
C
Corey Richardson 已提交
1865
pub struct BareFunctionDecl {
N
Niko Matsakis 已提交
1866
    pub unsafety: ast::Unsafety,
1867 1868
    pub generics: Generics,
    pub decl: FnDecl,
1869
    pub abi: String,
C
Corey Richardson 已提交
1870 1871
}

1872
impl Clean<BareFunctionDecl> for ast::BareFnTy {
1873
    fn clean(&self, cx: &DocContext) -> BareFunctionDecl {
C
Corey Richardson 已提交
1874
        BareFunctionDecl {
N
Niko Matsakis 已提交
1875
            unsafety: self.unsafety,
C
Corey Richardson 已提交
1876
            generics: Generics {
1877
                lifetimes: self.lifetimes.clean(cx),
1878
                type_params: Vec::new(),
1879
                where_predicates: Vec::new()
C
Corey Richardson 已提交
1880
            },
1881
            decl: self.decl.clean(cx),
1882
            abi: self.abi.to_string(),
C
Corey Richardson 已提交
1883 1884 1885 1886
        }
    }
}

1887
#[derive(Clone, RustcEncodable, RustcDecodable, Show)]
C
Corey Richardson 已提交
1888
pub struct Static {
1889 1890
    pub type_: Type,
    pub mutability: Mutability,
C
Corey Richardson 已提交
1891 1892 1893
    /// 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.
1894
    pub expr: String,
C
Corey Richardson 已提交
1895 1896 1897
}

impl Clean<Item> for doctree::Static {
1898
    fn clean(&self, cx: &DocContext) -> Item {
1899
        debug!("cleaning static {}: {:?}", self.name.clean(cx), self);
C
Corey Richardson 已提交
1900
        Item {
1901 1902 1903
            name: Some(self.name.clean(cx)),
            attrs: self.attrs.clean(cx),
            source: self.whence.clean(cx),
1904
            def_id: ast_util::local_def(self.id),
1905 1906
            visibility: self.vis.clean(cx),
            stability: self.stab.clean(cx),
C
Corey Richardson 已提交
1907
            inner: StaticItem(Static {
1908 1909 1910
                type_: self.type_.clean(cx),
                mutability: self.mutability.clean(cx),
                expr: self.expr.span.to_src(cx),
C
Corey Richardson 已提交
1911 1912 1913 1914 1915
            }),
        }
    }
}

1916
#[derive(Clone, RustcEncodable, RustcDecodable, Show)]
1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938
pub struct Constant {
    pub type_: Type,
    pub expr: String,
}

impl Clean<Item> for doctree::Constant {
    fn clean(&self, cx: &DocContext) -> Item {
        Item {
            name: Some(self.name.clean(cx)),
            attrs: self.attrs.clean(cx),
            source: self.whence.clean(cx),
            def_id: ast_util::local_def(self.id),
            visibility: self.vis.clean(cx),
            stability: self.stab.clean(cx),
            inner: ConstantItem(Constant {
                type_: self.type_.clean(cx),
                expr: self.expr.span.to_src(cx),
            }),
        }
    }
}

1939
#[derive(Show, Clone, RustcEncodable, RustcDecodable, PartialEq, Copy)]
C
Corey Richardson 已提交
1940 1941 1942 1943 1944
pub enum Mutability {
    Mutable,
    Immutable,
}

1945
impl Clean<Mutability> for ast::Mutability {
1946
    fn clean(&self, _: &DocContext) -> Mutability {
C
Corey Richardson 已提交
1947
        match self {
1948 1949
            &ast::MutMutable => Mutable,
            &ast::MutImmutable => Immutable,
C
Corey Richardson 已提交
1950 1951 1952 1953
        }
    }
}

1954
#[derive(Clone, RustcEncodable, RustcDecodable)]
C
Corey Richardson 已提交
1955
pub struct Impl {
1956 1957 1958
    pub generics: Generics,
    pub trait_: Option<Type>,
    pub for_: Type,
1959
    pub items: Vec<Item>,
1960
    pub derived: bool,
C
Corey Richardson 已提交
1961 1962
}

1963
fn detect_derived<M: AttrMetaMethods>(attrs: &[M]) -> bool {
1964
    attr::contains_name(attrs, "automatically_derived")
1965 1966
}

C
Corey Richardson 已提交
1967
impl Clean<Item> for doctree::Impl {
1968
    fn clean(&self, cx: &DocContext) -> Item {
C
Corey Richardson 已提交
1969 1970
        Item {
            name: None,
1971 1972
            attrs: self.attrs.clean(cx),
            source: self.whence.clean(cx),
1973
            def_id: ast_util::local_def(self.id),
1974 1975
            visibility: self.vis.clean(cx),
            stability: self.stab.clean(cx),
C
Corey Richardson 已提交
1976
            inner: ImplItem(Impl {
1977 1978 1979
                generics: self.generics.clean(cx),
                trait_: self.trait_.clean(cx),
                for_: self.for_.clean(cx),
A
Aaron Turon 已提交
1980
                items: self.items.clean(cx).into_iter().map(|ti| {
1981 1982
                        match ti {
                            MethodImplItem(i) => i,
1983
                            TypeImplItem(i) => i,
1984 1985
                        }
                    }).collect(),
1986
                derived: detect_derived(self.attrs.as_slice()),
C
Corey Richardson 已提交
1987 1988 1989 1990 1991
            }),
        }
    }
}

1992
#[derive(Clone, RustcEncodable, RustcDecodable)]
C
Corey Richardson 已提交
1993
pub struct ViewItem {
1994
    pub inner: ViewItemInner,
C
Corey Richardson 已提交
1995 1996
}

1997
impl Clean<Vec<Item>> for ast::ViewItem {
1998
    fn clean(&self, cx: &DocContext) -> Vec<Item> {
J
Joseph Crail 已提交
1999
        // We consider inlining the documentation of `pub use` statements, but we
2000 2001
        // forcefully don't inline if this is not public or if the
        // #[doc(no_inline)] attribute is present.
2002 2003
        let denied = self.vis != ast::Public || self.attrs.iter().any(|a| {
            a.name().get() == "doc" && match a.meta_item_list() {
2004
                Some(l) => attr::contains_name(l, "no_inline"),
2005 2006 2007
                None => false,
            }
        });
2008
        let convert = |&: node: &ast::ViewItem_| {
2009 2010
            Item {
                name: None,
2011 2012
                attrs: self.attrs.clean(cx),
                source: self.span.clean(cx),
2013
                def_id: ast_util::local_def(0),
2014
                visibility: self.vis.clean(cx),
2015
                stability: None,
2016
                inner: ViewItemItem(ViewItem { inner: node.clean(cx) }),
2017 2018 2019 2020 2021 2022 2023 2024
            }
        };
        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) => {
2025 2026 2027
                        // Attempt to inline all reexported items, but be sure
                        // to keep any non-inlineable reexports so they can be
                        // listed in the documentation.
2028
                        let remaining = list.iter().filter(|path| {
2029
                            match inline::try_inline(cx, path.node.id(), None) {
2030
                                Some(items) => {
A
Aaron Turon 已提交
2031
                                    ret.extend(items.into_iter()); false
2032
                                }
2033 2034
                                None => true,
                            }
J
Jakub Wieczorek 已提交
2035
                        }).map(|a| a.clone()).collect::<Vec<ast::PathListItem>>();
2036 2037 2038 2039 2040
                        if remaining.len() > 0 {
                            let path = ast::ViewPathList(a.clone(),
                                                         remaining,
                                                         b.clone());
                            let path = syntax::codemap::dummy_spanned(path);
2041
                            ret.push(convert(&ast::ViewItemUse(P(path))));
2042 2043
                        }
                    }
2044
                    ast::ViewPathSimple(ident, _, id) => {
2045
                        match inline::try_inline(cx, id, Some(ident)) {
A
Aaron Turon 已提交
2046
                            Some(items) => ret.extend(items.into_iter()),
2047 2048 2049 2050 2051 2052
                            None => ret.push(convert(&self.node)),
                        }
                    }
                }
            }
            ref n => ret.push(convert(n)),
C
Corey Richardson 已提交
2053
        }
2054
        return ret;
C
Corey Richardson 已提交
2055 2056 2057
    }
}

2058
#[derive(Clone, RustcEncodable, RustcDecodable)]
C
Corey Richardson 已提交
2059
pub enum ViewItemInner {
2060
    ExternCrate(String, Option<String>, ast::NodeId),
2061
    Import(ViewPath)
C
Corey Richardson 已提交
2062 2063
}

2064
impl Clean<ViewItemInner> for ast::ViewItem_ {
2065
    fn clean(&self, cx: &DocContext) -> ViewItemInner {
C
Corey Richardson 已提交
2066
        match self {
2067
            &ast::ViewItemExternCrate(ref i, ref p, ref id) => {
P
Patrick Walton 已提交
2068 2069
                let string = match *p {
                    None => None,
2070
                    Some((ref x, _)) => Some(x.get().to_string()),
P
Patrick Walton 已提交
2071
                };
2072
                ExternCrate(i.clean(cx), string, *id)
P
Patrick Walton 已提交
2073
            }
2074
            &ast::ViewItemUse(ref vp) => {
2075
                Import(vp.clean(cx))
2076
            }
C
Corey Richardson 已提交
2077 2078 2079 2080
        }
    }
}

2081
#[derive(Clone, RustcEncodable, RustcDecodable)]
C
Corey Richardson 已提交
2082
pub enum ViewPath {
2083
    // use source as str;
2084
    SimpleImport(String, ImportSource),
A
Alex Crichton 已提交
2085 2086 2087
    // use source::*;
    GlobImport(ImportSource),
    // use source::{a, b, c};
2088
    ImportList(ImportSource, Vec<ViewListIdent>),
A
Alex Crichton 已提交
2089 2090
}

2091
#[derive(Clone, RustcEncodable, RustcDecodable)]
A
Alex Crichton 已提交
2092
pub struct ImportSource {
2093 2094
    pub path: Path,
    pub did: Option<ast::DefId>,
C
Corey Richardson 已提交
2095 2096
}

2097
impl Clean<ViewPath> for ast::ViewPath {
2098
    fn clean(&self, cx: &DocContext) -> ViewPath {
C
Corey Richardson 已提交
2099
        match self.node {
2100
            ast::ViewPathSimple(ref i, ref p, id) =>
2101
                SimpleImport(i.clean(cx), resolve_use_source(cx, p.clean(cx), id)),
2102
            ast::ViewPathGlob(ref p, id) =>
2103
                GlobImport(resolve_use_source(cx, p.clean(cx), id)),
2104
            ast::ViewPathList(ref p, ref pl, id) => {
2105 2106
                ImportList(resolve_use_source(cx, p.clean(cx), id),
                           pl.clean(cx))
2107
            }
C
Corey Richardson 已提交
2108 2109 2110 2111
        }
    }
}

2112
#[derive(Clone, RustcEncodable, RustcDecodable)]
A
Alex Crichton 已提交
2113
pub struct ViewListIdent {
2114
    pub name: String,
2115
    pub source: Option<ast::DefId>,
A
Alex Crichton 已提交
2116
}
C
Corey Richardson 已提交
2117

J
Jakub Wieczorek 已提交
2118
impl Clean<ViewListIdent> for ast::PathListItem {
2119
    fn clean(&self, cx: &DocContext) -> ViewListIdent {
J
Jakub Wieczorek 已提交
2120 2121
        match self.node {
            ast::PathListIdent { id, name } => ViewListIdent {
2122 2123
                name: name.clean(cx),
                source: resolve_def(cx, id)
J
Jakub Wieczorek 已提交
2124 2125 2126
            },
            ast::PathListMod { id } => ViewListIdent {
                name: "mod".to_string(),
2127
                source: resolve_def(cx, id)
J
Jakub Wieczorek 已提交
2128
            }
A
Alex Crichton 已提交
2129
        }
C
Corey Richardson 已提交
2130 2131 2132
    }
}

2133
impl Clean<Vec<Item>> for ast::ForeignMod {
2134 2135
    fn clean(&self, cx: &DocContext) -> Vec<Item> {
        self.items.clean(cx)
2136 2137 2138
    }
}

2139
impl Clean<Item> for ast::ForeignItem {
2140
    fn clean(&self, cx: &DocContext) -> Item {
2141
        let inner = match self.node {
2142
            ast::ForeignItemFn(ref decl, ref generics) => {
2143
                ForeignFunctionItem(Function {
2144 2145
                    decl: decl.clean(cx),
                    generics: generics.clean(cx),
N
Niko Matsakis 已提交
2146
                    unsafety: ast::Unsafety::Unsafe,
2147 2148
                })
            }
2149
            ast::ForeignItemStatic(ref ty, mutbl) => {
2150
                ForeignStaticItem(Static {
2151
                    type_: ty.clean(cx),
2152
                    mutability: if mutbl {Mutable} else {Immutable},
2153
                    expr: "".to_string(),
2154 2155 2156 2157
                })
            }
        };
        Item {
2158 2159 2160
            name: Some(self.ident.clean(cx)),
            attrs: self.attrs.clean(cx),
            source: self.span.clean(cx),
2161
            def_id: ast_util::local_def(self.id),
2162 2163
            visibility: self.vis.clean(cx),
            stability: get_stability(cx, ast_util::local_def(self.id)),
2164 2165 2166 2167 2168
            inner: inner,
        }
    }
}

C
Corey Richardson 已提交
2169 2170 2171
// Utilities

trait ToSource {
2172
    fn to_src(&self, cx: &DocContext) -> String;
C
Corey Richardson 已提交
2173 2174
}

2175
impl ToSource for syntax::codemap::Span {
2176
    fn to_src(&self, cx: &DocContext) -> String {
2177
        debug!("converting span {:?} to snippet", self.clean(cx));
2178
        let sn = match cx.sess().codemap().span_to_snippet(*self) {
2179 2180
            Some(x) => x.to_string(),
            None    => "".to_string()
C
Corey Richardson 已提交
2181
        };
2182
        debug!("got snippet {}", sn);
C
Corey Richardson 已提交
2183 2184 2185 2186
        sn
    }
}

2187
fn lit_to_string(lit: &ast::Lit) -> String {
C
Corey Richardson 已提交
2188
    match lit.node {
2189
        ast::LitStr(ref st, _) => st.get().to_string(),
2190
        ast::LitBinary(ref data) => format!("{:?}", data),
2191 2192
        ast::LitByte(b) => {
            let mut res = String::from_str("b'");
2193
            for c in (b as char).escape_default() {
2194
                res.push(c);
2195
            }
2196
            res.push('\'');
2197 2198
            res
        },
A
Alex Crichton 已提交
2199
        ast::LitChar(c) => format!("'{}'", c),
2200
        ast::LitInt(i, _t) => i.to_string(),
2201 2202
        ast::LitFloat(ref f, _t) => f.get().to_string(),
        ast::LitFloatUnsuffixed(ref f) => f.get().to_string(),
2203
        ast::LitBool(b) => b.to_string(),
C
Corey Richardson 已提交
2204 2205 2206
    }
}

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

C
Corey Richardson 已提交
2211
    match p.node {
2212 2213
        PatWild(PatWildSingle) => "_".to_string(),
        PatWild(PatWildMulti) => "..".to_string(),
2214
        PatIdent(_, ref p, _) => token::get_ident(p.node).get().to_string(),
2215
        PatEnum(ref p, _) => path_to_string(p),
2216 2217
        PatStruct(ref name, ref fields, etc) => {
            format!("{} {{ {}{} }}", path_to_string(name),
2218
                fields.iter().map(|&Spanned { node: ref fp, .. }|
2219 2220 2221 2222 2223 2224 2225
                                  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(", ")),
2226
        PatBox(ref p) => name_from_pat(&**p),
2227
        PatRegion(ref p, _) => name_from_pat(&**p),
2228 2229 2230
        PatLit(..) => {
            warn!("tried to get argument name from PatLit, \
                  which is silly in function arguments");
2231
            "()".to_string()
2232
        },
S
Steve Klabnik 已提交
2233
        PatRange(..) => panic!("tried to get argument name from PatRange, \
2234
                              which is not allowed in function arguments"),
2235 2236 2237 2238 2239 2240
        PatVec(ref begin, ref mid, ref end) => {
            let begin = begin.iter().map(|p| name_from_pat(&**p));
            let mid = mid.as_ref().map(|p| format!("..{}", name_from_pat(&**p))).into_iter();
            let end = end.iter().map(|p| name_from_pat(&**p));
            format!("[{}]", begin.chain(mid).chain(end).collect::<Vec<_>>().connect(", "))
        },
2241 2242 2243 2244 2245
        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 已提交
2246 2247 2248 2249
    }
}

/// Given a Type, resolve it using the def_map
N
Niko Matsakis 已提交
2250 2251
fn resolve_type(cx: &DocContext,
                path: Path,
2252
                id: ast::NodeId) -> Type {
2253 2254
    let tcx = match cx.tcx_opt() {
        Some(tcx) => tcx,
2255
        // If we're extracting tests, this return value doesn't matter.
2256
        None => return Primitive(Bool),
2257
    };
L
Luqman Aden 已提交
2258
    debug!("searching for {} in defmap", id);
2259
    let def = match tcx.def_map.borrow().get(&id) {
2260
        Some(&k) => k,
S
Steve Klabnik 已提交
2261
        None => panic!("unresolved id not in defmap")
C
Corey Richardson 已提交
2262 2263
    };

2264
    match def {
2265 2266 2267
        def::DefSelfTy(..) => {
            return Generic(token::get_name(special_idents::type_self.name).to_string());
        }
2268
        def::DefPrimTy(p) => match p {
2269 2270 2271
            ast::TyStr => return Primitive(Str),
            ast::TyBool => return Primitive(Bool),
            ast::TyChar => return Primitive(Char),
2272
            ast::TyInt(ast::TyIs(_)) => return Primitive(Isize),
2273 2274 2275 2276
            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),
2277
            ast::TyUint(ast::TyUs(_)) => return Primitive(Usize),
2278 2279 2280 2281 2282 2283
            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 已提交
2284
        },
2285
        def::DefTyParam(_, _, _, n) => return Generic(token::get_name(n).to_string()),
2286
        def::DefTyParamBinder(i) => return TyParamBinder(i),
2287 2288
        _ => {}
    };
2289
    let did = register_def(&*cx, def);
N
Niko Matsakis 已提交
2290
    ResolvedPath { path: path, typarams: None, did: did }
2291 2292
}

2293
fn register_def(cx: &DocContext, def: def::Def) -> ast::DefId {
2294
    let (did, kind) = match def {
N
Nick Cameron 已提交
2295
        def::DefFn(i, _) => (i, TypeFunction),
2296 2297
        def::DefTy(i, false) => (i, TypeTypedef),
        def::DefTy(i, true) => (i, TypeEnum),
2298 2299 2300 2301 2302 2303
        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 已提交
2304
    };
2305
    if ast_util::is_local(did) { return did }
2306 2307 2308
    let tcx = match cx.tcx_opt() {
        Some(tcx) => tcx,
        None => return did
2309
    };
2310
    inline::record_extern_fqn(cx, did, kind);
2311 2312 2313
    if let TypeTrait = kind {
        let t = inline::build_external_trait(cx, tcx, did);
        cx.external_traits.borrow_mut().as_mut().unwrap().insert(did, t);
2314
    }
2315
    return did;
C
Corey Richardson 已提交
2316
}
A
Alex Crichton 已提交
2317

2318
fn resolve_use_source(cx: &DocContext, path: Path, id: ast::NodeId) -> ImportSource {
A
Alex Crichton 已提交
2319 2320
    ImportSource {
        path: path,
2321
        did: resolve_def(cx, id),
A
Alex Crichton 已提交
2322 2323 2324
    }
}

2325 2326
fn resolve_def(cx: &DocContext, id: ast::NodeId) -> Option<ast::DefId> {
    cx.tcx_opt().and_then(|tcx| {
2327
        tcx.def_map.borrow().get(&id).map(|&def| register_def(cx, def))
2328
    })
A
Alex Crichton 已提交
2329
}
2330

2331
#[derive(Clone, RustcEncodable, RustcDecodable)]
2332
pub struct Macro {
2333
    pub source: String,
2334 2335 2336
}

impl Clean<Item> for doctree::Macro {
2337
    fn clean(&self, cx: &DocContext) -> Item {
2338
        Item {
2339 2340 2341 2342 2343
            name: Some(format!("{}!", self.name.clean(cx))),
            attrs: self.attrs.clean(cx),
            source: self.whence.clean(cx),
            visibility: ast::Public.clean(cx),
            stability: self.stab.clean(cx),
2344
            def_id: ast_util::local_def(self.id),
2345
            inner: MacroItem(Macro {
2346
                source: self.whence.to_src(cx),
2347 2348 2349 2350
            }),
        }
    }
}
2351

2352
#[derive(Clone, RustcEncodable, RustcDecodable)]
2353 2354 2355 2356 2357 2358
pub struct Stability {
    pub level: attr::StabilityLevel,
    pub text: String
}

impl Clean<Stability> for attr::Stability {
2359
    fn clean(&self, _: &DocContext) -> Stability {
2360 2361 2362 2363 2364 2365 2366
        Stability {
            level: self.level,
            text: self.text.as_ref().map_or("".to_string(),
                                            |interned| interned.get().to_string()),
        }
    }
}
A
Alex Crichton 已提交
2367

2368 2369 2370
impl Clean<Item> for ast::AssociatedType {
    fn clean(&self, cx: &DocContext) -> Item {
        Item {
2371 2372
            source: self.ty_param.span.clean(cx),
            name: Some(self.ty_param.ident.clean(cx)),
2373
            attrs: self.attrs.clean(cx),
2374
            inner: AssociatedTypeItem(self.ty_param.clean(cx)),
2375
            visibility: None,
2376
            def_id: ast_util::local_def(self.ty_param.id),
2377 2378 2379 2380 2381 2382 2383 2384 2385
            stability: None,
        }
    }
}

impl Clean<Item> for ty::AssociatedType {
    fn clean(&self, cx: &DocContext) -> Item {
        Item {
            source: DUMMY_SP.clean(cx),
2386
            name: Some(self.name.clean(cx)),
2387
            attrs: Vec::new(),
2388 2389 2390 2391 2392 2393 2394 2395 2396
            // FIXME(#18048): this is wrong, but cross-crate associated types are broken
            // anyway, for the time being.
            inner: AssociatedTypeItem(TyParam {
                name: self.name.clean(cx),
                did: ast::DefId {
                    krate: 0,
                    node: ast::DUMMY_NODE_ID
                },
                bounds: vec![],
2397
                default: None,
2398
            }),
2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416
            visibility: None,
            def_id: self.def_id,
            stability: None,
        }
    }
}

impl Clean<Item> for ast::Typedef {
    fn clean(&self, cx: &DocContext) -> Item {
        Item {
            source: self.span.clean(cx),
            name: Some(self.ident.clean(cx)),
            attrs: self.attrs.clean(cx),
            inner: TypedefItem(Typedef {
                type_: self.typ.clean(cx),
                generics: Generics {
                    lifetimes: Vec::new(),
                    type_params: Vec::new(),
2417
                    where_predicates: Vec::new()
2418 2419 2420 2421 2422 2423 2424 2425 2426
                },
            }),
            visibility: None,
            def_id: ast_util::local_def(self.id),
            stability: None,
        }
    }
}

2427
fn lang_struct(cx: &DocContext, did: Option<ast::DefId>,
2428
               t: ty::Ty, name: &str,
A
Alex Crichton 已提交
2429 2430 2431
               fallback: fn(Box<Type>) -> Type) -> Type {
    let did = match did {
        Some(did) => did,
2432
        None => return fallback(box t.clean(cx)),
A
Alex Crichton 已提交
2433
    };
2434
    let fqn = csearch::get_item_path(cx.tcx(), did);
A
Aaron Turon 已提交
2435
    let fqn: Vec<String> = fqn.into_iter().map(|i| {
A
Alex Crichton 已提交
2436 2437
        i.to_string()
    }).collect();
2438
    cx.external_paths.borrow_mut().as_mut().unwrap().insert(did, (fqn, TypeStruct));
A
Alex Crichton 已提交
2439 2440 2441 2442 2443 2444 2445
    ResolvedPath {
        typarams: None,
        did: did,
        path: Path {
            global: false,
            segments: vec![PathSegment {
                name: name.to_string(),
2446 2447 2448
                params: PathParameters::AngleBracketed {
                    lifetimes: vec![],
                    types: vec![t.clean(cx)],
2449
                    bindings: vec![]
2450
                }
A
Alex Crichton 已提交
2451 2452 2453 2454
            }],
        },
    }
}
2455 2456

/// An equality constraint on an associated type, e.g. `A=Bar` in `Foo<A=Bar>`
A
Alex Crichton 已提交
2457
#[derive(Clone, PartialEq, RustcDecodable, RustcEncodable, Show)]
2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470
pub struct TypeBinding {
    pub name: String,
    pub ty: Type
}

impl Clean<TypeBinding> for ast::TypeBinding {
    fn clean(&self, cx: &DocContext) -> TypeBinding {
        TypeBinding {
            name: self.ident.clean(cx),
            ty: self.ty.clean(cx)
        }
    }
}