mod.rs 84.7 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
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::*;
21
pub use self::Import::*;
S
Steven Fackler 已提交
22 23 24 25 26 27 28
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 已提交
29 30
use syntax;
use syntax::ast;
31
use syntax::ast_util;
32
use syntax::ast_util::PostExpansionMethod;
33
use syntax::attr;
34
use syntax::attr::{AttributeMethods, AttrMetaMethods};
35
use syntax::codemap;
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

49
use std::rc::Rc;
50
use std::u32;
A
Aaron Turon 已提交
51
use std::old_path::Path as FsPath; // Conflicts with Path struct
52

53
use core::DocContext;
C
Corey Richardson 已提交
54 55 56
use doctree;
use visit_ast;

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

61 62
mod inline;

63 64 65
// 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)
66 67
}

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

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

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

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

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

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

105 106 107 108 109 110
impl<T, U> Clean<U> for ty::Binder<T> where T: Clean<U> {
    fn clean(&self, cx: &DocContext) -> U {
        self.0.clean(cx)
    }
}

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

J
Jorge Aparicio 已提交
117
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
118
pub struct Crate {
119
    pub name: String,
120
    pub src: FsPath,
121 122
    pub module: Option<Item>,
    pub externs: Vec<(ast::CrateNum, ExternalCrate)>,
123
    pub primitives: Vec<PrimitiveType>,
C
Corey Richardson 已提交
124 125
}

126 127
impl<'a, 'tcx> Clean<Crate> for visit_ast::RustdocVisitor<'a, 'tcx> {
    fn clean(&self, cx: &DocContext) -> Crate {
128 129
        use rustc::session::config::Input;

130
        let mut externs = Vec::new();
E
Eduard Burtescu 已提交
131
        cx.sess().cstore.iter_crate_data(|n, meta| {
132
            externs.push((n, meta.clean(cx)));
133
        });
134
        externs.sort_by(|&(a, _), &(b, _)| a.cmp(&b));
C
Corey Richardson 已提交
135

136
        // Figure out the name of this crate
137
        let input = &cx.input;
138
        let name = link::find_crate_name(None, &self.attrs, input);
139

140
        // Clean the crate, translating the entire libsyntax AST to one that is
141
        // understood by rustdoc.
142
        let mut module = self.module.clean(cx);
143 144 145

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

191 192 193 194 195
        let src = match cx.input {
            Input::File(ref path) => path.clone(),
            Input::Str(_) => FsPath::new("") // FIXME: this is wrong
        };

C
Corey Richardson 已提交
196
        Crate {
197
            name: name.to_string(),
198
            src: src,
199
            module: Some(module),
200
            externs: externs,
201
            primitives: primitives,
202 203 204 205
        }
    }
}

J
Jorge Aparicio 已提交
206
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
207
pub struct ExternalCrate {
208
    pub name: String,
209
    pub attrs: Vec<Attribute>,
210
    pub primitives: Vec<PrimitiveType>,
211 212 213
}

impl Clean<ExternalCrate> for cstore::crate_metadata {
214
    fn clean(&self, cx: &DocContext) -> ExternalCrate {
215
        let mut primitives = Vec::new();
216
        cx.tcx_opt().map(|tcx| {
217 218 219 220 221 222 223
            csearch::each_top_level_item_of_crate(&tcx.sess.cstore,
                                                  self.cnum,
                                                  |def, _, _| {
                let did = match def {
                    decoder::DlDef(def::DefMod(did)) => did,
                    _ => return
                };
224
                let attrs = inline::load_attrs(cx, tcx, did);
225
                PrimitiveType::find(&attrs).map(|prim| primitives.push(prim));
226 227
            })
        });
228
        ExternalCrate {
229
            name: self.name.to_string(),
230
            attrs: decoder::get_crate_attributes(self.data()).clean(cx),
231
            primitives: primitives,
C
Corey Richardson 已提交
232 233 234 235 236 237 238
        }
    }
}

/// 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.
J
Jorge Aparicio 已提交
239
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
240 241
pub struct Item {
    /// Stringified span
242
    pub source: Span,
C
Corey Richardson 已提交
243
    /// Not everything has a name. E.g., impls
244
    pub name: Option<String>,
245 246 247
    pub attrs: Vec<Attribute> ,
    pub inner: ItemEnum,
    pub visibility: Option<Visibility>,
248
    pub def_id: ast::DefId,
249
    pub stability: Option<Stability>,
C
Corey Richardson 已提交
250 251
}

252 253 254 255
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]> {
256
        for attr in &self.attrs {
257
            match *attr {
258
                List(ref x, ref list) if "doc" == *x => {
259
                    return Some(list);
260
                }
261 262 263 264 265 266 267 268 269
                _ => {}
            }
        }
        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> {
270
        for attr in &self.attrs {
271
            match *attr {
272
                NameValue(ref x, ref v) if "doc" == *x => {
273
                    return Some(v);
274
                }
275 276 277 278 279 280
                _ => {}
            }
        }
        return None;
    }

281 282
    pub fn is_hidden_from_doc(&self) -> bool {
        match self.doc_list() {
283 284
            Some(l) => {
                for innerattr in l {
285
                    match *innerattr {
286
                        Word(ref s) if "hidden" == *s => {
287 288
                            return true
                        }
289 290 291 292 293 294 295 296 297
                        _ => (),
                    }
                }
            },
            None => ()
        }
        return false;
    }

298
    pub fn is_mod(&self) -> bool {
A
Alex Crichton 已提交
299
        match self.inner { ModuleItem(..) => true, _ => false }
300 301
    }
    pub fn is_trait(&self) -> bool {
A
Alex Crichton 已提交
302
        match self.inner { TraitItem(..) => true, _ => false }
303 304
    }
    pub fn is_struct(&self) -> bool {
A
Alex Crichton 已提交
305
        match self.inner { StructItem(..) => true, _ => false }
306 307
    }
    pub fn is_enum(&self) -> bool {
A
Alex Crichton 已提交
308
        match self.inner { EnumItem(..) => true, _ => false }
309 310
    }
    pub fn is_fn(&self) -> bool {
A
Alex Crichton 已提交
311
        match self.inner { FunctionItem(..) => true, _ => false }
312 313 314
    }
}

J
Jorge Aparicio 已提交
315
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
316
pub enum ItemEnum {
317 318
    ExternCrateItem(String, Option<String>),
    ImportItem(Import),
C
Corey Richardson 已提交
319 320 321 322 323 324
    StructItem(Struct),
    EnumItem(Enum),
    FunctionItem(Function),
    ModuleItem(Module),
    TypedefItem(Typedef),
    StaticItem(Static),
325
    ConstantItem(Constant),
C
Corey Richardson 已提交
326 327
    TraitItem(Trait),
    ImplItem(Impl),
328 329
    /// A method signature only. Used for required methods in traits (ie,
    /// non-default-methods).
C
Corey Richardson 已提交
330
    TyMethodItem(TyMethod),
331
    /// A method with a body.
C
Corey Richardson 已提交
332 333 334
    MethodItem(Method),
    StructFieldItem(StructField),
    VariantItem(Variant),
335
    /// `fn`s from an extern block
336
    ForeignFunctionItem(Function),
337
    /// `static`s from an extern block
338
    ForeignStaticItem(Static),
339
    MacroItem(Macro),
340
    PrimitiveItem(PrimitiveType),
341
    AssociatedTypeItem(TyParam),
C
Corey Richardson 已提交
342 343
}

J
Jorge Aparicio 已提交
344
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
345
pub struct Module {
346 347
    pub items: Vec<Item>,
    pub is_crate: bool,
C
Corey Richardson 已提交
348 349 350
}

impl Clean<Item> for doctree::Module {
351
    fn clean(&self, cx: &DocContext) -> Item {
C
Corey Richardson 已提交
352
        let name = if self.name.is_some() {
353
            self.name.unwrap().clean(cx)
C
Corey Richardson 已提交
354
        } else {
355
            "".to_string()
C
Corey Richardson 已提交
356
        };
357 358 359 360 361 362 363 364 365 366 367 368 369 370 371

        let mut items: Vec<Item> = vec![];
        items.extend(self.extern_crates.iter().map(|x| x.clean(cx)));
        items.extend(self.imports.iter().flat_map(|x| x.clean(cx).into_iter()));
        items.extend(self.structs.iter().map(|x| x.clean(cx)));
        items.extend(self.enums.iter().map(|x| x.clean(cx)));
        items.extend(self.fns.iter().map(|x| x.clean(cx)));
        items.extend(self.foreigns.iter().flat_map(|x| x.clean(cx).into_iter()));
        items.extend(self.mods.iter().map(|x| x.clean(cx)));
        items.extend(self.typedefs.iter().map(|x| x.clean(cx)));
        items.extend(self.statics.iter().map(|x| x.clean(cx)));
        items.extend(self.constants.iter().map(|x| x.clean(cx)));
        items.extend(self.traits.iter().map(|x| x.clean(cx)));
        items.extend(self.impls.iter().map(|x| x.clean(cx)));
        items.extend(self.macros.iter().map(|x| x.clean(cx)));
372 373 374

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

J
Jorge Aparicio 已提交
403
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
C
Corey Richardson 已提交
404
pub enum Attribute {
405 406 407
    Word(String),
    List(String, Vec<Attribute> ),
    NameValue(String, String)
C
Corey Richardson 已提交
408 409 410
}

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

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

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

440
    fn value_str(&self) -> Option<InternedString> {
441
        match *self {
442
            NameValue(_, ref v) => {
443
                Some(token::intern_and_get_ident(v))
444
            }
445 446 447
            _ => None,
        }
    }
448
    fn meta_item_list<'a>(&'a self) -> Option<&'a [P<ast::MetaItem>]> { None }
449
    fn span(&self) -> codemap::Span { unimplemented!() }
450
}
451 452 453
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 已提交
454
    fn meta_item_list(&self) -> Option<&[P<ast::MetaItem>]> { None }
455
    fn span(&self) -> codemap::Span { unimplemented!() }
456
}
457

J
Jorge Aparicio 已提交
458
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
C
Corey Richardson 已提交
459
pub struct TyParam {
460
    pub name: String,
461
    pub did: ast::DefId,
462
    pub bounds: Vec<TyParamBound>,
463
    pub default: Option<Type>,
464
}
C
Corey Richardson 已提交
465 466

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

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

J
Jorge Aparicio 已提交
491
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
C
Corey Richardson 已提交
492
pub enum TyParamBound {
493
    RegionBound(Lifetime),
N
Nick Cameron 已提交
494
    TraitBound(PolyTrait, ast::TraitBoundModifier)
C
Corey Richardson 已提交
495 496 497
}

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

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

514
        let mut bindings = vec![];
515
        for &ty::Binder(ref pb) in &self.projection_bounds {
516 517 518 519 520
            bindings.push(TypeBinding {
                name: pb.projection_ty.item_name.clean(cx),
                ty: pb.ty.clean(cx)
            });
        }
N
Niko Matsakis 已提交
521

522
        (tp_bounds, bindings)
523 524 525
    }
}

526
fn external_path_params(cx: &DocContext, trait_did: Option<ast::DefId>,
527
                        bindings: Vec<TypeBinding>, substs: &subst::Substs) -> PathParameters {
528
    use rustc::middle::ty::sty;
529
    let lifetimes = substs.regions().get_slice(subst::TypeSpace)
530
                    .iter()
531
                    .filter_map(|v| v.clean(cx))
532
                    .collect();
533
    let types = substs.types.get_slice(subst::TypeSpace).to_vec();
534 535 536 537

    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() => {
538
            assert_eq!(types.len(), 1);
539 540 541 542 543
            let inputs = match types[0].sty {
                sty::ty_tup(ref tys) => tys.iter().map(|t| t.clean(cx)).collect(),
                _ => {
                    return PathParameters::AngleBracketed {
                        lifetimes: lifetimes,
544
                        types: types.clean(cx),
545
                        bindings: bindings
546 547 548
                    }
                }
            };
549 550 551 552 553 554
            let output = None;
            // FIXME(#20299) return type comes from a projection now
            // match types[1].sty {
            //     sty::ty_tup(ref v) if v.is_empty() => None, // -> ()
            //     _ => Some(types[1].clean(cx))
            // };
555 556 557 558 559 560 561 562 563
            PathParameters::Parenthesized {
                inputs: inputs,
                output: output
            }
        },
        (_, _) => {
            PathParameters::AngleBracketed {
                lifetimes: lifetimes,
                types: types.clean(cx),
564
                bindings: bindings
565 566 567 568 569 570 571 572
            }
        }
    }
}

// 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>,
573
                 bindings: Vec<TypeBinding>, substs: &subst::Substs) -> Path {
574 575 576
    Path {
        global: false,
        segments: vec![PathSegment {
577
            name: name.to_string(),
578
            params: external_path_params(cx, trait_did, bindings, substs)
579
        }],
580 581 582 583
    }
}

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

619
impl<'tcx> Clean<TyParamBound> for ty::TraitRef<'tcx> {
620 621 622
    fn clean(&self, cx: &DocContext) -> TyParamBound {
        let tcx = match cx.tcx_opt() {
            Some(tcx) => tcx,
623
            None => return RegionBound(Lifetime::statik())
624 625
        };
        let fqn = csearch::get_item_path(tcx, self.def_id);
A
Aaron Turon 已提交
626
        let fqn = fqn.into_iter().map(|i| i.to_string())
627
                     .collect::<Vec<String>>();
628
        let path = external_path(cx, fqn.last().unwrap(),
629
                                 Some(self.def_id), vec![], self.substs);
630
        cx.external_paths.borrow_mut().as_mut().unwrap().insert(self.def_id,
631
                                                            (fqn, TypeTrait));
632

633
        debug!("ty::TraitRef\n  substs.types(TypeSpace): {:?}\n",
634 635 636 637
               self.substs.types.get_slice(ParamSpace::TypeSpace));

        // collect any late bound regions
        let mut late_bounds = vec![];
638
        for &ty_s in self.substs.types.get_slice(ParamSpace::TypeSpace) {
639 640
            use rustc::middle::ty::{Region, sty};
            if let sty::ty_tup(ref ts) = ty_s.sty {
641
                for &ty_s in ts {
642
                    if let sty::ty_rptr(ref reg, _) = ty_s.sty {
H
Huon Wilson 已提交
643
                        if let &Region::ReLateBound(_, _) = *reg {
644
                            debug!("  hit an ReLateBound {:?}", reg);
645 646 647 648 649 650 651 652 653 654 655 656
                            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 已提交
657
        }, ast::TraitBoundModifier::None)
658 659 660
    }
}

N
Nick Cameron 已提交
661 662
impl<'tcx> Clean<Vec<TyParamBound>> for ty::ParamBounds<'tcx> {
    fn clean(&self, cx: &DocContext) -> Vec<TyParamBound> {
663
        let mut v = Vec::new();
664
        for t in &self.trait_bounds {
665
            v.push(t.clean(cx));
666
        }
667 668 669
        for r in self.region_bounds.iter().filter_map(|r| r.clean(cx)) {
            v.push(RegionBound(r));
        }
N
Nick Cameron 已提交
670
        v
671 672 673
    }
}

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

J
Jorge Aparicio 已提交
686
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
687
pub struct Lifetime(String);
C
Corey Richardson 已提交
688

689 690 691
impl Lifetime {
    pub fn get_ref<'a>(&'a self) -> &'a str {
        let Lifetime(ref s) = *self;
692
        let s: &'a str = s;
693 694
        return s;
    }
695 696 697 698

    pub fn statik() -> Lifetime {
        Lifetime("'static".to_string())
    }
699 700
}

C
Corey Richardson 已提交
701
impl Clean<Lifetime> for ast::Lifetime {
702
    fn clean(&self, _: &DocContext) -> Lifetime {
703
        Lifetime(token::get_name(self.name).get().to_string())
C
Corey Richardson 已提交
704 705 706
    }
}

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

713
impl Clean<Lifetime> for ty::RegionParameterDef {
714
    fn clean(&self, _: &DocContext) -> Lifetime {
715
        Lifetime(token::get_name(self.name).get().to_string())
716 717 718 719
    }
}

impl Clean<Option<Lifetime>> for ty::Region {
720
    fn clean(&self, cx: &DocContext) -> Option<Lifetime> {
721
        match *self {
722
            ty::ReStatic => Some(Lifetime::statik()),
723
            ty::ReLateBound(_, ty::BrNamed(_, name)) =>
724
                Some(Lifetime(token::get_name(name).get().to_string())),
725
            ty::ReEarlyBound(_, _, _, name) => Some(Lifetime(name.clean(cx))),
726 727 728 729 730 731 732 733 734 735

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

J
Jorge Aparicio 已提交
736
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
737 738 739
pub enum WherePredicate {
    BoundPredicate { ty: Type, bounds: Vec<TyParamBound> },
    RegionPredicate { lifetime: Lifetime, bounds: Vec<Lifetime>},
740
    EqPredicate { lhs: Type, rhs: Type }
741 742 743 744
}

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

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

            ast::WherePredicate::EqPredicate(_) => {
761
                unimplemented!() // FIXME(#20041)
N
Nick Cameron 已提交
762
            }
763 764 765 766
        }
    }
}

767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843
impl<'a> Clean<WherePredicate> for ty::Predicate<'a> {
    fn clean(&self, cx: &DocContext) -> WherePredicate {
        use rustc::middle::ty::Predicate;

        match *self {
            Predicate::Trait(ref pred) => pred.clean(cx),
            Predicate::Equate(ref pred) => pred.clean(cx),
            Predicate::RegionOutlives(ref pred) => pred.clean(cx),
            Predicate::TypeOutlives(ref pred) => pred.clean(cx),
            Predicate::Projection(ref pred) => pred.clean(cx)
        }
    }
}

impl<'a> Clean<WherePredicate> for ty::TraitPredicate<'a> {
    fn clean(&self, cx: &DocContext) -> WherePredicate {
        WherePredicate::BoundPredicate {
            ty: self.trait_ref.substs.self_ty().clean(cx).unwrap(),
            bounds: vec![self.trait_ref.clean(cx)]
        }
    }
}

impl<'tcx> Clean<WherePredicate> for ty::EquatePredicate<'tcx> {
    fn clean(&self, cx: &DocContext) -> WherePredicate {
        let ty::EquatePredicate(ref lhs, ref rhs) = *self;
        WherePredicate::EqPredicate {
            lhs: lhs.clean(cx),
            rhs: rhs.clean(cx)
        }
    }
}

impl Clean<WherePredicate> for ty::OutlivesPredicate<ty::Region, ty::Region> {
    fn clean(&self, cx: &DocContext) -> WherePredicate {
        let ty::OutlivesPredicate(ref a, ref b) = *self;
        WherePredicate::RegionPredicate {
            lifetime: a.clean(cx).unwrap(),
            bounds: vec![b.clean(cx).unwrap()]
        }
    }
}

impl<'tcx> Clean<WherePredicate> for ty::OutlivesPredicate<ty::Ty<'tcx>, ty::Region> {
    fn clean(&self, cx: &DocContext) -> WherePredicate {
        let ty::OutlivesPredicate(ref ty, ref lt) = *self;

        WherePredicate::BoundPredicate {
            ty: ty.clean(cx),
            bounds: vec![TyParamBound::RegionBound(lt.clean(cx).unwrap())]
        }
    }
}

impl<'tcx> Clean<WherePredicate> for ty::ProjectionPredicate<'tcx> {
    fn clean(&self, cx: &DocContext) -> WherePredicate {
        WherePredicate::EqPredicate {
            lhs: self.projection_ty.clean(cx),
            rhs: self.ty.clean(cx)
        }
    }
}

impl<'tcx> Clean<Type> for ty::ProjectionTy<'tcx> {
    fn clean(&self, cx: &DocContext) -> Type {
        let trait_ = match self.trait_ref.clean(cx) {
            TyParamBound::TraitBound(t, _) => t.trait_,
            TyParamBound::RegionBound(_) => panic!("cleaning a trait got a region??"),
        };
        Type::QPath {
            name: self.item_name.clean(cx),
            self_type: box self.trait_ref.self_ty().clean(cx),
            trait_: box trait_
        }
    }
}

C
Corey Richardson 已提交
844
// maybe use a Generic enum and use ~[Generic]?
J
Jorge Aparicio 已提交
845
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
C
Corey Richardson 已提交
846
pub struct Generics {
847 848
    pub lifetimes: Vec<Lifetime>,
    pub type_params: Vec<TyParam>,
849
    pub where_predicates: Vec<WherePredicate>
850
}
C
Corey Richardson 已提交
851 852

impl Clean<Generics> for ast::Generics {
853
    fn clean(&self, cx: &DocContext) -> Generics {
C
Corey Richardson 已提交
854
        Generics {
855 856
            lifetimes: self.lifetimes.clean(cx),
            type_params: self.ty_params.clean(cx),
857
            where_predicates: self.where_clause.predicates.clean(cx)
C
Corey Richardson 已提交
858 859 860 861
        }
    }
}

862
impl<'a, 'tcx> Clean<Generics> for (&'a ty::Generics<'tcx>, subst::ParamSpace) {
863
    fn clean(&self, cx: &DocContext) -> Generics {
864 865 866 867 868 869 870 871 872 873
        use std::collections::HashSet;
        use syntax::ast::TraitBoundModifier as TBM;
        use self::WherePredicate as WP;

        fn has_sized_bound(bounds: &[TyParamBound], cx: &DocContext) -> bool {
            if let Some(tcx) = cx.tcx_opt() {
                let sized_did = match tcx.lang_items.sized_trait() {
                    Some(did) => did,
                    None => return false
                };
874
                for bound in bounds {
875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916
                    if let TyParamBound::TraitBound(PolyTrait {
                        trait_: Type::ResolvedPath { did, .. }, ..
                    }, TBM::None) = *bound {
                        if did == sized_did {
                            return true
                        }
                    }
                }
            }
            false
        }

        let (gens, space) = *self;
        // Bounds in the type_params and lifetimes fields are repeated in the predicates
        // field (see rustc_typeck::collect::ty_generics), so remove them.
        let stripped_typarams = gens.types.get_slice(space).iter().map(|tp| {
            let mut stp = tp.clone();
            stp.bounds = ty::ParamBounds::empty();
            stp.clean(cx)
        }).collect::<Vec<_>>();
        let stripped_lifetimes = gens.regions.get_slice(space).iter().map(|rp| {
            let mut srp = rp.clone();
            srp.bounds = Vec::new();
            srp.clean(cx)
        }).collect::<Vec<_>>();

        let where_predicates = gens.predicates.get_slice(space).to_vec().clean(cx);
        // Type parameters have a Sized bound by default unless removed with ?Sized.
        // Scan through the predicates and mark any type parameter with a Sized
        // bound, removing the bounds as we find them.
        let mut sized_params = HashSet::new();
        let mut where_predicates = where_predicates.into_iter().filter_map(|pred| {
            if let WP::BoundPredicate { ty: Type::Generic(ref g), ref bounds } = pred {
                if has_sized_bound(&**bounds, cx) {
                    sized_params.insert(g.clone());
                    return None
                }
            }
            Some(pred)
        }).collect::<Vec<_>>();
        // Finally, run through the type parameters again and insert a ?Sized unbound for
        // any we didn't find to be Sized.
917
        for tp in &stripped_typarams {
918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933
            if !sized_params.contains(&tp.name) {
                let mut sized_bound = ty::BuiltinBound::BoundSized.clean(cx);
                if let TyParamBound::TraitBound(_, ref mut tbm) = sized_bound {
                    *tbm = TBM::Maybe
                };
                where_predicates.push(WP::BoundPredicate {
                    ty: Type::Generic(tp.name.clone()),
                    bounds: vec![sized_bound]
                })
            }
        }

        // It would be nice to collect all of the bounds on a type and recombine
        // them if possible, to avoid e.g. `where T: Foo, T: Bar, T: Sized, T: 'a`
        // and instead see `where T: Foo + Bar + Sized + 'a`

934
        Generics {
935 936 937
            type_params: stripped_typarams,
            lifetimes: stripped_lifetimes,
            where_predicates: where_predicates
938 939 940 941
        }
    }
}

J
Jorge Aparicio 已提交
942
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
943
pub struct Method {
944 945
    pub generics: Generics,
    pub self_: SelfTy,
N
Niko Matsakis 已提交
946
    pub unsafety: ast::Unsafety,
947
    pub decl: FnDecl,
C
Corey Richardson 已提交
948 949
}

950
impl Clean<Item> for ast::Method {
951
    fn clean(&self, cx: &DocContext) -> Item {
952 953
        let all_inputs = &self.pe_fn_decl().inputs;
        let inputs = match self.pe_explicit_self().node {
954
            ast::SelfStatic => &**all_inputs,
J
Jorge Aparicio 已提交
955
            _ => &all_inputs[1..]
956 957
        };
        let decl = FnDecl {
958
            inputs: Arguments {
959
                values: inputs.iter().map(|x| x.clean(cx)).collect(),
960
            },
961
            output: self.pe_fn_decl().output.clean(cx),
962
            attrs: Vec::new()
963
        };
C
Corey Richardson 已提交
964
        Item {
965 966 967
            name: Some(self.pe_ident().clean(cx)),
            attrs: self.attrs.clean(cx),
            source: self.span.clean(cx),
968
            def_id: ast_util::local_def(self.id),
969 970
            visibility: self.pe_vis().clean(cx),
            stability: get_stability(cx, ast_util::local_def(self.id)),
C
Corey Richardson 已提交
971
            inner: MethodItem(Method {
972 973
                generics: self.pe_generics().clean(cx),
                self_: self.pe_explicit_self().node.clean(cx),
N
Niko Matsakis 已提交
974
                unsafety: self.pe_unsafety().clone(),
975
                decl: decl,
C
Corey Richardson 已提交
976 977 978 979 980
            }),
        }
    }
}

J
Jorge Aparicio 已提交
981
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
982
pub struct TyMethod {
N
Niko Matsakis 已提交
983
    pub unsafety: ast::Unsafety,
984 985 986
    pub decl: FnDecl,
    pub generics: Generics,
    pub self_: SelfTy,
C
Corey Richardson 已提交
987 988 989
}

impl Clean<Item> for ast::TypeMethod {
990
    fn clean(&self, cx: &DocContext) -> Item {
991
        let inputs = match self.explicit_self.node {
992
            ast::SelfStatic => &*self.decl.inputs,
J
Jorge Aparicio 已提交
993
            _ => &self.decl.inputs[1..]
994 995
        };
        let decl = FnDecl {
996
            inputs: Arguments {
997
                values: inputs.iter().map(|x| x.clean(cx)).collect(),
998
            },
999
            output: self.decl.output.clean(cx),
1000
            attrs: Vec::new()
1001
        };
C
Corey Richardson 已提交
1002
        Item {
1003 1004 1005
            name: Some(self.ident.clean(cx)),
            attrs: self.attrs.clean(cx),
            source: self.span.clean(cx),
1006
            def_id: ast_util::local_def(self.id),
C
Corey Richardson 已提交
1007
            visibility: None,
1008
            stability: get_stability(cx, ast_util::local_def(self.id)),
C
Corey Richardson 已提交
1009
            inner: TyMethodItem(TyMethod {
N
Niko Matsakis 已提交
1010
                unsafety: self.unsafety.clone(),
1011
                decl: decl,
1012 1013
                self_: self.explicit_self.node.clean(cx),
                generics: self.generics.clean(cx),
C
Corey Richardson 已提交
1014 1015 1016 1017 1018
            }),
        }
    }
}

J
Jorge Aparicio 已提交
1019
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
C
Corey Richardson 已提交
1020 1021 1022 1023
pub enum SelfTy {
    SelfStatic,
    SelfValue,
    SelfBorrowed(Option<Lifetime>, Mutability),
1024
    SelfExplicit(Type),
C
Corey Richardson 已提交
1025 1026
}

1027
impl Clean<SelfTy> for ast::ExplicitSelf_ {
1028
    fn clean(&self, cx: &DocContext) -> SelfTy {
1029
        match *self {
1030
            ast::SelfStatic => SelfStatic,
1031
            ast::SelfValue(_) => SelfValue,
1032
            ast::SelfRegion(ref lt, ref mt, _) => {
1033
                SelfBorrowed(lt.clean(cx), mt.clean(cx))
1034
            }
1035
            ast::SelfExplicit(ref typ, _) => SelfExplicit(typ.clean(cx)),
C
Corey Richardson 已提交
1036 1037 1038 1039
        }
    }
}

J
Jorge Aparicio 已提交
1040
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
1041
pub struct Function {
1042 1043
    pub decl: FnDecl,
    pub generics: Generics,
N
Niko Matsakis 已提交
1044
    pub unsafety: ast::Unsafety,
C
Corey Richardson 已提交
1045 1046 1047
}

impl Clean<Item> for doctree::Function {
1048
    fn clean(&self, cx: &DocContext) -> Item {
C
Corey Richardson 已提交
1049
        Item {
1050 1051 1052 1053 1054
            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),
1055
            def_id: ast_util::local_def(self.id),
C
Corey Richardson 已提交
1056
            inner: FunctionItem(Function {
1057 1058
                decl: self.decl.clean(cx),
                generics: self.generics.clean(cx),
N
Niko Matsakis 已提交
1059
                unsafety: self.unsafety,
C
Corey Richardson 已提交
1060 1061 1062 1063 1064
            }),
        }
    }
}

J
Jorge Aparicio 已提交
1065
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
C
Corey Richardson 已提交
1066
pub struct FnDecl {
1067
    pub inputs: Arguments,
1068
    pub output: FunctionRetTy,
1069 1070
    pub attrs: Vec<Attribute>,
}
C
Corey Richardson 已提交
1071

J
Jorge Aparicio 已提交
1072
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
1073
pub struct Arguments {
1074
    pub values: Vec<Argument>,
1075 1076
}

1077
impl Clean<FnDecl> for ast::FnDecl {
1078
    fn clean(&self, cx: &DocContext) -> FnDecl {
C
Corey Richardson 已提交
1079
        FnDecl {
1080
            inputs: Arguments {
1081
                values: self.inputs.clean(cx),
1082
            },
1083
            output: self.output.clean(cx),
1084
            attrs: Vec::new()
C
Corey Richardson 已提交
1085 1086 1087 1088
        }
    }
}

1089
impl<'tcx> Clean<Type> for ty::FnOutput<'tcx> {
J
Jakub Bukaj 已提交
1090 1091 1092 1093 1094 1095 1096 1097
    fn clean(&self, cx: &DocContext) -> Type {
        match *self {
            ty::FnConverging(ty) => ty.clean(cx),
            ty::FnDiverging => Bottom
        }
    }
}

1098
impl<'a, 'tcx> Clean<FnDecl> for (ast::DefId, &'a ty::PolyFnSig<'tcx>) {
1099
    fn clean(&self, cx: &DocContext) -> FnDecl {
1100 1101
        let (did, sig) = *self;
        let mut names = if did.node != 0 {
A
Aaron Turon 已提交
1102
            csearch::get_method_arg_names(&cx.tcx().sess.cstore, did).into_iter()
1103
        } else {
A
Aaron Turon 已提交
1104
            Vec::new().into_iter()
1105
        }.peekable();
1106
        if names.peek().map(|s| &**s) == Some("self") {
1107 1108
            let _ = names.next();
        }
1109
        FnDecl {
1110
            output: Return(sig.0.output.clean(cx)),
1111
            attrs: Vec::new(),
1112
            inputs: Arguments {
1113
                values: sig.0.inputs.iter().map(|t| {
1114
                    Argument {
1115
                        type_: t.clean(cx),
1116
                        id: 0,
1117
                        name: names.next().unwrap_or("".to_string()),
1118 1119 1120 1121 1122 1123 1124
                    }
                }).collect(),
            },
        }
    }
}

J
Jorge Aparicio 已提交
1125
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
C
Corey Richardson 已提交
1126
pub struct Argument {
1127
    pub type_: Type,
1128
    pub name: String,
1129
    pub id: ast::NodeId,
C
Corey Richardson 已提交
1130 1131
}

1132
impl Clean<Argument> for ast::Arg {
1133
    fn clean(&self, cx: &DocContext) -> Argument {
C
Corey Richardson 已提交
1134
        Argument {
1135
            name: name_from_pat(&*self.pat),
1136
            type_: (self.ty.clean(cx)),
C
Corey Richardson 已提交
1137 1138 1139 1140 1141
            id: self.id
        }
    }
}

J
Jorge Aparicio 已提交
1142
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
1143 1144
pub enum FunctionRetTy {
    Return(Type),
1145
    DefaultReturn,
1146
    NoReturn
C
Corey Richardson 已提交
1147 1148
}

1149 1150
impl Clean<FunctionRetTy> for ast::FunctionRetTy {
    fn clean(&self, cx: &DocContext) -> FunctionRetTy {
C
Corey Richardson 已提交
1151
        match *self {
1152
            ast::Return(ref typ) => Return(typ.clean(cx)),
1153 1154
            ast::DefaultReturn(..) => DefaultReturn,
            ast::NoReturn(..) => NoReturn
C
Corey Richardson 已提交
1155 1156 1157 1158
        }
    }
}

J
Jorge Aparicio 已提交
1159
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
1160
pub struct Trait {
1161
    pub unsafety: ast::Unsafety,
1162
    pub items: Vec<TraitMethod>,
1163
    pub generics: Generics,
1164
    pub bounds: Vec<TyParamBound>,
C
Corey Richardson 已提交
1165 1166 1167
}

impl Clean<Item> for doctree::Trait {
1168
    fn clean(&self, cx: &DocContext) -> Item {
C
Corey Richardson 已提交
1169
        Item {
1170 1171 1172
            name: Some(self.name.clean(cx)),
            attrs: self.attrs.clean(cx),
            source: self.whence.clean(cx),
1173
            def_id: ast_util::local_def(self.id),
1174 1175
            visibility: self.vis.clean(cx),
            stability: self.stab.clean(cx),
C
Corey Richardson 已提交
1176
            inner: TraitItem(Trait {
1177
                unsafety: self.unsafety,
1178 1179 1180
                items: self.items.clean(cx),
                generics: self.generics.clean(cx),
                bounds: self.bounds.clean(cx),
C
Corey Richardson 已提交
1181 1182 1183 1184 1185
            }),
        }
    }
}

1186
impl Clean<Type> for ast::TraitRef {
1187
    fn clean(&self, cx: &DocContext) -> Type {
N
Niko Matsakis 已提交
1188
        resolve_type(cx, self.path.clean(cx), self.ref_id)
C
Corey Richardson 已提交
1189 1190 1191
    }
}

1192 1193 1194 1195 1196 1197
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 已提交
1198 1199 1200
    }
}

1201 1202
/// 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.
J
Jorge Aparicio 已提交
1203
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
1204
pub enum TraitMethod {
1205 1206
    RequiredMethod(Item),
    ProvidedMethod(Item),
1207
    TypeTraitItem(Item), // an associated type
C
Corey Richardson 已提交
1208 1209
}

1210
impl TraitMethod {
1211
    pub fn is_req(&self) -> bool {
C
Corey Richardson 已提交
1212
        match self {
1213
            &RequiredMethod(..) => true,
C
Corey Richardson 已提交
1214 1215 1216
            _ => false,
        }
    }
1217
    pub fn is_def(&self) -> bool {
C
Corey Richardson 已提交
1218
        match self {
1219
            &ProvidedMethod(..) => true,
C
Corey Richardson 已提交
1220 1221 1222
            _ => false,
        }
    }
1223 1224 1225 1226 1227 1228
    pub fn is_type(&self) -> bool {
        match self {
            &TypeTraitItem(..) => true,
            _ => false,
        }
    }
1229 1230
    pub fn item<'a>(&'a self) -> &'a Item {
        match *self {
1231 1232
            RequiredMethod(ref item) => item,
            ProvidedMethod(ref item) => item,
1233
            TypeTraitItem(ref item) => item,
1234 1235
        }
    }
C
Corey Richardson 已提交
1236 1237
}

1238 1239
impl Clean<TraitMethod> for ast::TraitItem {
    fn clean(&self, cx: &DocContext) -> TraitMethod {
C
Corey Richardson 已提交
1240
        match self {
1241 1242
            &ast::RequiredMethod(ref t) => RequiredMethod(t.clean(cx)),
            &ast::ProvidedMethod(ref t) => ProvidedMethod(t.clean(cx)),
1243
            &ast::TypeTraitItem(ref t) => TypeTraitItem(t.clean(cx)),
1244 1245 1246 1247
        }
    }
}

J
Jorge Aparicio 已提交
1248
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
1249
pub enum ImplMethod {
1250
    MethodImplItem(Item),
1251
    TypeImplItem(Item),
1252 1253
}

1254 1255
impl Clean<ImplMethod> for ast::ImplItem {
    fn clean(&self, cx: &DocContext) -> ImplMethod {
1256
        match self {
1257
            &ast::MethodImplItem(ref t) => MethodImplItem(t.clean(cx)),
1258
            &ast::TypeImplItem(ref t) => TypeImplItem(t.clean(cx)),
C
Corey Richardson 已提交
1259 1260 1261 1262
        }
    }
}

1263
impl<'tcx> Clean<Item> for ty::Method<'tcx> {
1264
    fn clean(&self, cx: &DocContext) -> Item {
1265
        let (self_, sig) = match self.explicit_self {
1266
            ty::StaticExplicitSelfCategory => (ast::SelfStatic.clean(cx),
A
Alex Crichton 已提交
1267
                                               self.fty.sig.clone()),
1268
            s => {
1269
                let sig = ty::Binder(ty::FnSig {
J
Jorge Aparicio 已提交
1270
                    inputs: self.fty.sig.0.inputs[1..].to_vec(),
1271 1272
                    ..self.fty.sig.0.clone()
                });
1273
                let s = match s {
A
Alex Crichton 已提交
1274
                    ty::ByValueExplicitSelfCategory => SelfValue,
1275
                    ty::ByReferenceExplicitSelfCategory(..) => {
1276
                        match self.fty.sig.0.inputs[0].sty {
1277
                            ty::ty_rptr(r, mt) => {
1278
                                SelfBorrowed(r.clean(cx), mt.mutbl.clean(cx))
1279
                            }
A
Alex Crichton 已提交
1280
                            _ => unreachable!(),
1281 1282
                        }
                    }
A
Alex Crichton 已提交
1283
                    ty::ByBoxExplicitSelfCategory => {
1284
                        SelfExplicit(self.fty.sig.0.inputs[0].clean(cx))
1285
                    }
A
Alex Crichton 已提交
1286
                    ty::StaticExplicitSelfCategory => unreachable!(),
1287 1288 1289 1290
                };
                (s, sig)
            }
        };
1291

1292
        Item {
1293
            name: Some(self.name.clean(cx)),
1294
            visibility: Some(ast::Inherited),
1295
            stability: get_stability(cx, self.def_id),
1296
            def_id: self.def_id,
1297
            attrs: inline::load_attrs(cx, cx.tcx(), self.def_id),
1298
            source: Span::empty(),
1299
            inner: TyMethodItem(TyMethod {
N
Niko Matsakis 已提交
1300
                unsafety: self.fty.unsafety,
1301
                generics: (&self.generics, subst::FnSpace).clean(cx),
1302
                self_: self_,
1303
                decl: (self.def_id, &sig).clean(cx),
1304
            })
1305
        }
1306 1307 1308
    }
}

1309
impl<'tcx> Clean<Item> for ty::ImplOrTraitItem<'tcx> {
1310
    fn clean(&self, cx: &DocContext) -> Item {
1311
        match *self {
1312
            ty::MethodTraitItem(ref mti) => mti.clean(cx),
1313
            ty::TypeTraitItem(ref tti) => tti.clean(cx),
1314 1315 1316 1317
        }
    }
}

1318
/// A trait reference, which may have higher ranked lifetimes.
J
Jorge Aparicio 已提交
1319
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
1320 1321 1322 1323 1324
pub struct PolyTrait {
    pub trait_: Type,
    pub lifetimes: Vec<Lifetime>
}

C
Corey Richardson 已提交
1325 1326 1327
/// 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.
J
Jorge Aparicio 已提交
1328
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
C
Corey Richardson 已提交
1329
pub enum Type {
1330
    /// structs/enums/traits (anything that'd be an ast::TyPath)
1331
    ResolvedPath {
S
Steven Fackler 已提交
1332 1333 1334
        path: Path,
        typarams: Option<Vec<TyParamBound>>,
        did: ast::DefId,
1335
    },
C
Corey Richardson 已提交
1336 1337
    // I have no idea how to usefully use this.
    TyParamBinder(ast::NodeId),
1338 1339 1340
    /// 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 已提交
1341
    /// Primitives are just the fixed-size numeric types (plus int/uint/float), and char.
1342
    Primitive(PrimitiveType),
C
Corey Richardson 已提交
1343
    /// extern "ABI" fn
1344
    BareFunction(Box<BareFunctionDecl>),
1345
    Tuple(Vec<Type>),
1346
    Vector(Box<Type>),
1347
    FixedVector(Box<Type>, String),
1348
    /// aka TyBot
C
Corey Richardson 已提交
1349
    Bottom,
1350 1351
    Unique(Box<Type>),
    RawPointer(Mutability, Box<Type>),
1352
    BorrowedRef {
S
Steven Fackler 已提交
1353 1354 1355
        lifetime: Option<Lifetime>,
        mutability: Mutability,
        type_: Box<Type>,
1356
    },
1357 1358

    // <Type as Trait>::Name
T
Tom Jakubowski 已提交
1359 1360 1361 1362 1363
    QPath {
        name: String,
        self_type: Box<Type>,
        trait_: Box<Type>
    },
1364 1365 1366 1367 1368 1369

    // _
    Infer,

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

J
Jorge Aparicio 已提交
1372
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Copy, Debug)]
1373
pub enum PrimitiveType {
1374 1375
    Isize, I8, I16, I32, I64,
    Usize, U8, U16, U32, U64,
1376
    F32, F64,
1377 1378 1379 1380 1381 1382 1383
    Char,
    Bool,
    Str,
    Slice,
    PrimitiveTuple,
}

J
Jorge Aparicio 已提交
1384
#[derive(Clone, RustcEncodable, RustcDecodable, Copy, Debug)]
1385 1386 1387
pub enum TypeKind {
    TypeEnum,
    TypeFunction,
1388
    TypeModule,
1389
    TypeConst,
1390 1391 1392 1393
    TypeStatic,
    TypeStruct,
    TypeTrait,
    TypeVariant,
1394
    TypeTypedef,
1395 1396
}

1397 1398
impl PrimitiveType {
    fn from_str(s: &str) -> Option<PrimitiveType> {
1399
        match s {
1400
            "isize" | "int" => Some(Isize),
1401 1402 1403 1404
            "i8" => Some(I8),
            "i16" => Some(I16),
            "i32" => Some(I32),
            "i64" => Some(I64),
1405
            "usize" | "uint" => Some(Usize),
1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420
            "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,
        }
    }

1421
    fn find(attrs: &[Attribute]) -> Option<PrimitiveType> {
1422
        for attr in attrs {
1423
            let list = match *attr {
1424
                List(ref k, ref l) if *k == "doc" => l,
1425 1426
                _ => continue,
            };
1427
            for sub_attr in list {
1428 1429
                let value = match *sub_attr {
                    NameValue(ref k, ref v)
1430
                        if *k == "primitive" => v,
1431 1432
                    _ => continue,
                };
1433
                match PrimitiveType::from_str(value) {
1434 1435 1436 1437 1438 1439 1440 1441
                    Some(p) => return Some(p),
                    None => {}
                }
            }
        }
        return None
    }

1442
    pub fn to_string(&self) -> &'static str {
1443
        match *self {
1444
            Isize => "isize",
1445 1446 1447 1448
            I8 => "i8",
            I16 => "i16",
            I32 => "i32",
            I64 => "i64",
1449
            Usize => "usize",
1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464
            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 {
1465
        self.to_string()
1466 1467 1468 1469 1470 1471 1472 1473 1474 1475
    }

    /// 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 已提交
1476
impl Clean<Type> for ast::Ty {
1477
    fn clean(&self, cx: &DocContext) -> Type {
C
Corey Richardson 已提交
1478
        use syntax::ast::*;
1479
        match self.node {
1480
            TyPtr(ref m) => RawPointer(m.mutbl.clean(cx), box m.ty.clean(cx)),
1481
            TyRptr(ref l, ref m) =>
1482 1483
                BorrowedRef {lifetime: l.clean(cx), mutability: m.mutbl.clean(cx),
                             type_: box m.ty.clean(cx)},
1484 1485 1486
            TyVec(ref ty) => Vector(box ty.clean(cx)),
            TyFixedLengthVec(ref ty, ref e) => FixedVector(box ty.clean(cx),
                                                           e.span.to_src(cx)),
1487
            TyTup(ref tys) => Tuple(tys.clean(cx)),
N
Niko Matsakis 已提交
1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500
            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
                    }
                }
1501
            }
1502 1503
            TyBareFn(ref barefn) => BareFunction(box barefn.clean(cx)),
            TyParen(ref ty) => ty.clean(cx),
T
Tom Jakubowski 已提交
1504
            TyQPath(ref qp) => qp.clean(cx),
1505 1506 1507 1508 1509 1510 1511
            TyPolyTraitRef(ref bounds) => {
                PolyTraitRef(bounds.clean(cx))
            },
            TyInfer(..) => {
                Infer
            },
            TyTypeof(..) => {
1512
                panic!("Unimplemented type {:?}", self.node)
1513
            },
1514
        }
C
Corey Richardson 已提交
1515 1516 1517
    }
}

1518
impl<'tcx> Clean<Type> for ty::Ty<'tcx> {
1519
    fn clean(&self, cx: &DocContext) -> Type {
1520
        match self.sty {
1521 1522
            ty::ty_bool => Primitive(Bool),
            ty::ty_char => Primitive(Char),
1523
            ty::ty_int(ast::TyIs(_)) => Primitive(Isize),
1524 1525 1526 1527
            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),
1528
            ty::ty_uint(ast::TyUs(_)) => Primitive(Usize),
1529 1530 1531 1532 1533 1534 1535
            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 已提交
1536
            ty::ty_uniq(t) => {
1537
                let box_did = cx.tcx_opt().and_then(|tcx| {
A
Alex Crichton 已提交
1538 1539
                    tcx.lang_items.owned_box()
                });
1540
                lang_struct(cx, box_did, t, "Box", Unique)
A
Alex Crichton 已提交
1541
            }
1542 1543
            ty::ty_vec(ty, None) => Vector(box ty.clean(cx)),
            ty::ty_vec(ty, Some(i)) => FixedVector(box ty.clean(cx),
A
Alex Crichton 已提交
1544
                                                   format!("{}", i)),
1545
            ty::ty_ptr(mt) => RawPointer(mt.mutbl.clean(cx), box mt.ty.clean(cx)),
1546
            ty::ty_rptr(r, mt) => BorrowedRef {
1547 1548 1549
                lifetime: r.clean(cx),
                mutability: mt.mutbl.clean(cx),
                type_: box mt.ty.clean(cx),
1550
            },
1551
            ty::ty_bare_fn(_, ref fty) => BareFunction(box BareFunctionDecl {
N
Niko Matsakis 已提交
1552
                unsafety: fty.unsafety,
1553
                generics: Generics {
1554 1555 1556
                    lifetimes: Vec::new(),
                    type_params: Vec::new(),
                    where_predicates: Vec::new()
1557
                },
1558
                decl: (ast_util::local_def(0), &fty.sig).clean(cx),
1559
                abi: fty.abi.to_string(),
1560
            }),
H
Huon Wilson 已提交
1561
            ty::ty_struct(did, substs) |
1562
            ty::ty_enum(did, substs) => {
1563
                let fqn = csearch::get_item_path(cx.tcx(), did);
1564
                let fqn: Vec<_> = fqn.into_iter().map(|i| i.to_string()).collect();
1565
                let kind = match self.sty {
1566 1567 1568
                    ty::ty_struct(..) => TypeStruct,
                    _ => TypeEnum,
                };
1569
                let path = external_path(cx, &fqn.last().unwrap().to_string(),
1570
                                         None, vec![], substs);
1571
                cx.external_paths.borrow_mut().as_mut().unwrap().insert(did, (fqn, kind));
1572
                ResolvedPath {
1573
                    path: path,
1574 1575 1576 1577
                    typarams: None,
                    did: did,
                }
            }
1578 1579 1580 1581
            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();
1582
                let (typarams, bindings) = bounds.clean(cx);
1583
                let path = external_path(cx, &fqn.last().unwrap().to_string(),
1584
                                         Some(did), bindings, principal.substs());
1585 1586 1587
                cx.external_paths.borrow_mut().as_mut().unwrap().insert(did, (fqn, TypeTrait));
                ResolvedPath {
                    path: path,
1588
                    typarams: Some(typarams),
1589 1590 1591
                    did: did,
                }
            }
1592
            ty::ty_tup(ref t) => Tuple(t.clean(cx)),
1593

1594 1595
            ty::ty_projection(ref data) => {
                let trait_ref = match data.trait_ref.clean(cx) {
N
Niko Matsakis 已提交
1596
                    TyParamBound::TraitBound(t, _) => t.trait_,
1597 1598 1599 1600 1601 1602 1603 1604 1605
                    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,
                }
            }

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

1608
            ty::ty_closure(..) => Tuple(vec![]), // FIXME(pcwalton)
1609

S
Steve Klabnik 已提交
1610 1611 1612
            ty::ty_infer(..) => panic!("ty_infer"),
            ty::ty_open(..) => panic!("ty_open"),
            ty::ty_err => panic!("ty_err"),
1613 1614 1615 1616
        }
    }
}

T
Tom Jakubowski 已提交
1617 1618 1619
impl Clean<Type> for ast::QPath {
    fn clean(&self, cx: &DocContext) -> Type {
        Type::QPath {
1620
            name: self.item_path.identifier.clean(cx),
T
Tom Jakubowski 已提交
1621 1622 1623 1624 1625 1626
            self_type: box self.self_type.clean(cx),
            trait_: box self.trait_ref.clean(cx)
        }
    }
}

J
Jorge Aparicio 已提交
1627
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
1628
pub enum StructField {
1629
    HiddenStructField, // inserted later by strip passes
1630
    TypedStructField(Type),
C
Corey Richardson 已提交
1631 1632
}

1633
impl Clean<Item> for ast::StructField {
1634
    fn clean(&self, cx: &DocContext) -> Item {
C
Corey Richardson 已提交
1635
        let (name, vis) = match self.node.kind {
1636 1637
            ast::NamedField(id, vis) => (Some(id), vis),
            ast::UnnamedField(vis) => (None, vis)
C
Corey Richardson 已提交
1638 1639
        };
        Item {
1640 1641 1642
            name: name.clean(cx),
            attrs: self.node.attrs.clean(cx),
            source: self.span.clean(cx),
1643
            visibility: Some(vis),
1644
            stability: get_stability(cx, ast_util::local_def(self.node.id)),
1645
            def_id: ast_util::local_def(self.node.id),
1646
            inner: StructFieldItem(TypedStructField(self.node.ty.clean(cx))),
C
Corey Richardson 已提交
1647 1648 1649 1650
        }
    }
}

1651
impl Clean<Item> for ty::field_ty {
1652
    fn clean(&self, cx: &DocContext) -> Item {
1653
        use syntax::parse::token::special_idents::unnamed_field;
1654 1655 1656 1657
        use rustc::metadata::csearch;

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

1658 1659
        let (name, attrs) = if self.name == unnamed_field.name {
            (None, None)
1660
        } else {
1661
            (Some(self.name), Some(attr_map.get(&self.id.node).unwrap()))
1662
        };
1663

1664
        let ty = ty::lookup_item_type(cx.tcx(), self.id);
1665

1666
        Item {
1667 1668
            name: name.clean(cx),
            attrs: attrs.unwrap_or(&Vec::new()).clean(cx),
1669 1670
            source: Span::empty(),
            visibility: Some(self.vis),
1671
            stability: get_stability(cx, self.id),
1672
            def_id: self.id,
1673
            inner: StructFieldItem(TypedStructField(ty.ty.clean(cx))),
1674 1675 1676 1677
        }
    }
}

1678
pub type Visibility = ast::Visibility;
C
Corey Richardson 已提交
1679

1680
impl Clean<Option<Visibility>> for ast::Visibility {
1681
    fn clean(&self, _: &DocContext) -> Option<Visibility> {
C
Corey Richardson 已提交
1682 1683 1684 1685
        Some(*self)
    }
}

J
Jorge Aparicio 已提交
1686
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
1687
pub struct Struct {
1688 1689 1690 1691
    pub struct_type: doctree::StructType,
    pub generics: Generics,
    pub fields: Vec<Item>,
    pub fields_stripped: bool,
C
Corey Richardson 已提交
1692 1693 1694
}

impl Clean<Item> for doctree::Struct {
1695
    fn clean(&self, cx: &DocContext) -> Item {
C
Corey Richardson 已提交
1696
        Item {
1697 1698 1699
            name: Some(self.name.clean(cx)),
            attrs: self.attrs.clean(cx),
            source: self.whence.clean(cx),
1700
            def_id: ast_util::local_def(self.id),
1701 1702
            visibility: self.vis.clean(cx),
            stability: self.stab.clean(cx),
C
Corey Richardson 已提交
1703 1704
            inner: StructItem(Struct {
                struct_type: self.struct_type,
1705 1706
                generics: self.generics.clean(cx),
                fields: self.fields.clean(cx),
S
Steven Fackler 已提交
1707
                fields_stripped: false,
C
Corey Richardson 已提交
1708 1709 1710 1711 1712
            }),
        }
    }
}

1713
/// This is a more limited form of the standard Struct, different in that
C
Corey Richardson 已提交
1714 1715
/// it lacks the things most items have (name, id, parameterization). Found
/// only as a variant in an enum.
J
Jorge Aparicio 已提交
1716
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
1717
pub struct VariantStruct {
1718 1719 1720
    pub struct_type: doctree::StructType,
    pub fields: Vec<Item>,
    pub fields_stripped: bool,
C
Corey Richardson 已提交
1721 1722
}

1723
impl Clean<VariantStruct> for syntax::ast::StructDef {
1724
    fn clean(&self, cx: &DocContext) -> VariantStruct {
C
Corey Richardson 已提交
1725 1726
        VariantStruct {
            struct_type: doctree::struct_type_from_def(self),
1727
            fields: self.fields.clean(cx),
S
Steven Fackler 已提交
1728
            fields_stripped: false,
C
Corey Richardson 已提交
1729 1730 1731 1732
        }
    }
}

J
Jorge Aparicio 已提交
1733
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
1734
pub struct Enum {
1735 1736 1737
    pub variants: Vec<Item>,
    pub generics: Generics,
    pub variants_stripped: bool,
C
Corey Richardson 已提交
1738 1739 1740
}

impl Clean<Item> for doctree::Enum {
1741
    fn clean(&self, cx: &DocContext) -> Item {
C
Corey Richardson 已提交
1742
        Item {
1743 1744 1745
            name: Some(self.name.clean(cx)),
            attrs: self.attrs.clean(cx),
            source: self.whence.clean(cx),
1746
            def_id: ast_util::local_def(self.id),
1747 1748
            visibility: self.vis.clean(cx),
            stability: self.stab.clean(cx),
C
Corey Richardson 已提交
1749
            inner: EnumItem(Enum {
1750 1751
                variants: self.variants.clean(cx),
                generics: self.generics.clean(cx),
S
Steven Fackler 已提交
1752
                variants_stripped: false,
C
Corey Richardson 已提交
1753 1754 1755 1756 1757
            }),
        }
    }
}

J
Jorge Aparicio 已提交
1758
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
1759
pub struct Variant {
1760
    pub kind: VariantKind,
C
Corey Richardson 已提交
1761 1762 1763
}

impl Clean<Item> for doctree::Variant {
1764
    fn clean(&self, cx: &DocContext) -> Item {
C
Corey Richardson 已提交
1765
        Item {
1766 1767 1768 1769 1770
            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),
1771
            def_id: ast_util::local_def(self.id),
C
Corey Richardson 已提交
1772
            inner: VariantItem(Variant {
1773
                kind: self.kind.clean(cx),
C
Corey Richardson 已提交
1774 1775 1776 1777 1778
            }),
        }
    }
}

1779
impl<'tcx> Clean<Item> for ty::VariantInfo<'tcx> {
1780
    fn clean(&self, cx: &DocContext) -> Item {
1781
        // use syntax::parse::token::special_idents::unnamed_field;
1782
        let kind = match self.arg_names.as_ref().map(|s| &**s) {
1783 1784
            None | Some([]) if self.args.len() == 0 => CLikeVariant,
            None | Some([]) => {
1785
                TupleVariant(self.args.clean(cx))
1786 1787 1788 1789 1790 1791 1792 1793
            }
            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(),
1794
                            name: Some(name.clean(cx)),
1795 1796
                            attrs: Vec::new(),
                            visibility: Some(ast::Public),
1797 1798
                            // FIXME: this is not accurate, we need an id for
                            //        the specific field but we're using the id
A
Aaron Turon 已提交
1799 1800 1801 1802 1803
                            //        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.
1804
                            def_id: self.id,
1805
                            stability: get_stability(cx, self.id),
1806
                            inner: StructFieldItem(
1807
                                TypedStructField(ty.clean(cx))
1808 1809 1810 1811 1812 1813 1814
                            )
                        }
                    }).collect()
                })
            }
        };
        Item {
1815 1816
            name: Some(self.name.clean(cx)),
            attrs: inline::load_attrs(cx, cx.tcx(), self.id),
1817 1818 1819 1820
            source: Span::empty(),
            visibility: Some(ast::Public),
            def_id: self.id,
            inner: VariantItem(Variant { kind: kind }),
1821
            stability: get_stability(cx, self.id),
1822 1823 1824 1825
        }
    }
}

J
Jorge Aparicio 已提交
1826
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
1827 1828
pub enum VariantKind {
    CLikeVariant,
1829
    TupleVariant(Vec<Type>),
C
Corey Richardson 已提交
1830 1831 1832
    StructVariant(VariantStruct),
}

1833
impl Clean<VariantKind> for ast::VariantKind {
1834
    fn clean(&self, cx: &DocContext) -> VariantKind {
C
Corey Richardson 已提交
1835
        match self {
1836
            &ast::TupleVariantKind(ref args) => {
C
Corey Richardson 已提交
1837 1838 1839
                if args.len() == 0 {
                    CLikeVariant
                } else {
1840
                    TupleVariant(args.iter().map(|x| x.ty.clean(cx)).collect())
C
Corey Richardson 已提交
1841 1842
                }
            },
1843
            &ast::StructVariantKind(ref sd) => StructVariant(sd.clean(cx)),
C
Corey Richardson 已提交
1844 1845 1846 1847
        }
    }
}

J
Jorge Aparicio 已提交
1848
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
1849
pub struct Span {
1850
    pub filename: String,
1851 1852 1853 1854
    pub loline: uint,
    pub locol: uint,
    pub hiline: uint,
    pub hicol: uint,
1855 1856
}

1857 1858 1859
impl Span {
    fn empty() -> Span {
        Span {
1860
            filename: "".to_string(),
1861 1862 1863 1864 1865 1866
            loline: 0, locol: 0,
            hiline: 0, hicol: 0,
        }
    }
}

1867
impl Clean<Span> for syntax::codemap::Span {
1868 1869
    fn clean(&self, cx: &DocContext) -> Span {
        let cm = cx.sess().codemap();
1870 1871 1872 1873
        let filename = cm.span_to_filename(*self);
        let lo = cm.lookup_char_pos(self.lo);
        let hi = cm.lookup_char_pos(self.hi);
        Span {
1874
            filename: filename.to_string(),
1875
            loline: lo.line,
1876
            locol: lo.col.to_usize(),
1877
            hiline: hi.line,
1878
            hicol: hi.col.to_usize(),
1879
        }
C
Corey Richardson 已提交
1880 1881 1882
    }
}

J
Jorge Aparicio 已提交
1883
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
C
Corey Richardson 已提交
1884
pub struct Path {
1885 1886
    pub global: bool,
    pub segments: Vec<PathSegment>,
C
Corey Richardson 已提交
1887 1888 1889
}

impl Clean<Path> for ast::Path {
1890
    fn clean(&self, cx: &DocContext) -> Path {
C
Corey Richardson 已提交
1891
        Path {
1892
            global: self.global,
1893
            segments: self.segments.clean(cx),
1894 1895 1896 1897
        }
    }
}

J
Jorge Aparicio 已提交
1898
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
1899 1900 1901 1902
pub enum PathParameters {
    AngleBracketed {
        lifetimes: Vec<Lifetime>,
        types: Vec<Type>,
1903
        bindings: Vec<TypeBinding>
1904 1905 1906 1907 1908
    },
    Parenthesized {
        inputs: Vec<Type>,
        output: Option<Type>
    }
1909 1910
}

1911 1912 1913
impl Clean<PathParameters> for ast::PathParameters {
    fn clean(&self, cx: &DocContext) -> PathParameters {
        match *self {
1914
            ast::AngleBracketedParameters(ref data) => {
1915 1916
                PathParameters::AngleBracketed {
                    lifetimes: data.lifetimes.clean(cx),
1917 1918
                    types: data.types.clean(cx),
                    bindings: data.bindings.clean(cx)
1919
                }
1920 1921 1922
            }

            ast::ParenthesizedParameters(ref data) => {
1923 1924 1925 1926
                PathParameters::Parenthesized {
                    inputs: data.inputs.clean(cx),
                    output: data.output.clean(cx)
                }
1927
            }
1928 1929 1930
        }
    }
}
1931

J
Jorge Aparicio 已提交
1932
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
1933 1934 1935 1936 1937 1938 1939
pub struct PathSegment {
    pub name: String,
    pub params: PathParameters
}

impl Clean<PathSegment> for ast::PathSegment {
    fn clean(&self, cx: &DocContext) -> PathSegment {
1940
        PathSegment {
1941
            name: self.identifier.clean(cx),
1942
            params: self.parameters.clean(cx)
C
Corey Richardson 已提交
1943 1944 1945 1946
        }
    }
}

1947
fn path_to_string(p: &ast::Path) -> String {
1948
    let mut s = String::new();
C
Corey Richardson 已提交
1949
    let mut first = true;
1950
    for i in p.segments.iter().map(|x| token::get_ident(x.identifier)) {
C
Corey Richardson 已提交
1951 1952 1953 1954 1955
        if !first || p.global {
            s.push_str("::");
        } else {
            first = false;
        }
1956
        s.push_str(i.get());
C
Corey Richardson 已提交
1957
    }
1958
    s
C
Corey Richardson 已提交
1959 1960
}

1961
impl Clean<String> for ast::Ident {
1962
    fn clean(&self, _: &DocContext) -> String {
1963
        token::get_ident(*self).get().to_string()
C
Corey Richardson 已提交
1964 1965 1966
    }
}

1967
impl Clean<String> for ast::Name {
1968
    fn clean(&self, _: &DocContext) -> String {
1969
        token::get_name(*self).get().to_string()
1970 1971 1972
    }
}

J
Jorge Aparicio 已提交
1973
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
1974
pub struct Typedef {
1975 1976
    pub type_: Type,
    pub generics: Generics,
C
Corey Richardson 已提交
1977 1978 1979
}

impl Clean<Item> for doctree::Typedef {
1980
    fn clean(&self, cx: &DocContext) -> Item {
C
Corey Richardson 已提交
1981
        Item {
1982 1983 1984
            name: Some(self.name.clean(cx)),
            attrs: self.attrs.clean(cx),
            source: self.whence.clean(cx),
1985
            def_id: ast_util::local_def(self.id.clone()),
1986 1987
            visibility: self.vis.clean(cx),
            stability: self.stab.clean(cx),
C
Corey Richardson 已提交
1988
            inner: TypedefItem(Typedef {
1989 1990
                type_: self.ty.clean(cx),
                generics: self.gen.clean(cx),
C
Corey Richardson 已提交
1991 1992 1993 1994 1995
            }),
        }
    }
}

J
Jorge Aparicio 已提交
1996
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
C
Corey Richardson 已提交
1997
pub struct BareFunctionDecl {
N
Niko Matsakis 已提交
1998
    pub unsafety: ast::Unsafety,
1999 2000
    pub generics: Generics,
    pub decl: FnDecl,
2001
    pub abi: String,
C
Corey Richardson 已提交
2002 2003
}

2004
impl Clean<BareFunctionDecl> for ast::BareFnTy {
2005
    fn clean(&self, cx: &DocContext) -> BareFunctionDecl {
C
Corey Richardson 已提交
2006
        BareFunctionDecl {
N
Niko Matsakis 已提交
2007
            unsafety: self.unsafety,
C
Corey Richardson 已提交
2008
            generics: Generics {
2009
                lifetimes: self.lifetimes.clean(cx),
2010
                type_params: Vec::new(),
2011
                where_predicates: Vec::new()
C
Corey Richardson 已提交
2012
            },
2013
            decl: self.decl.clean(cx),
2014
            abi: self.abi.to_string(),
C
Corey Richardson 已提交
2015 2016 2017 2018
        }
    }
}

J
Jorge Aparicio 已提交
2019
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
2020
pub struct Static {
2021 2022
    pub type_: Type,
    pub mutability: Mutability,
C
Corey Richardson 已提交
2023 2024 2025
    /// 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.
2026
    pub expr: String,
C
Corey Richardson 已提交
2027 2028 2029
}

impl Clean<Item> for doctree::Static {
2030
    fn clean(&self, cx: &DocContext) -> Item {
2031
        debug!("cleaning static {}: {:?}", self.name.clean(cx), self);
C
Corey Richardson 已提交
2032
        Item {
2033 2034 2035
            name: Some(self.name.clean(cx)),
            attrs: self.attrs.clean(cx),
            source: self.whence.clean(cx),
2036
            def_id: ast_util::local_def(self.id),
2037 2038
            visibility: self.vis.clean(cx),
            stability: self.stab.clean(cx),
C
Corey Richardson 已提交
2039
            inner: StaticItem(Static {
2040 2041 2042
                type_: self.type_.clean(cx),
                mutability: self.mutability.clean(cx),
                expr: self.expr.span.to_src(cx),
C
Corey Richardson 已提交
2043 2044 2045 2046 2047
            }),
        }
    }
}

J
Jorge Aparicio 已提交
2048
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070
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),
            }),
        }
    }
}

J
Jorge Aparicio 已提交
2071
#[derive(Debug, Clone, RustcEncodable, RustcDecodable, PartialEq, Copy)]
C
Corey Richardson 已提交
2072 2073 2074 2075 2076
pub enum Mutability {
    Mutable,
    Immutable,
}

2077
impl Clean<Mutability> for ast::Mutability {
2078
    fn clean(&self, _: &DocContext) -> Mutability {
C
Corey Richardson 已提交
2079
        match self {
2080 2081
            &ast::MutMutable => Mutable,
            &ast::MutImmutable => Immutable,
C
Corey Richardson 已提交
2082 2083 2084 2085
        }
    }
}

J
Jorge Aparicio 已提交
2086
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Copy, Debug)]
2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100
pub enum ImplPolarity {
    Positive,
    Negative,
}

impl Clean<ImplPolarity> for ast::ImplPolarity {
    fn clean(&self, _: &DocContext) -> ImplPolarity {
        match self {
            &ast::ImplPolarity::Positive => ImplPolarity::Positive,
            &ast::ImplPolarity::Negative => ImplPolarity::Negative,
        }
    }
}

J
Jorge Aparicio 已提交
2101
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
2102
pub struct Impl {
2103 2104 2105
    pub generics: Generics,
    pub trait_: Option<Type>,
    pub for_: Type,
2106
    pub items: Vec<Item>,
2107
    pub derived: bool,
2108
    pub polarity: Option<ImplPolarity>,
C
Corey Richardson 已提交
2109 2110
}

2111
fn detect_derived<M: AttrMetaMethods>(attrs: &[M]) -> bool {
2112
    attr::contains_name(attrs, "automatically_derived")
2113 2114
}

C
Corey Richardson 已提交
2115
impl Clean<Item> for doctree::Impl {
2116
    fn clean(&self, cx: &DocContext) -> Item {
C
Corey Richardson 已提交
2117 2118
        Item {
            name: None,
2119 2120
            attrs: self.attrs.clean(cx),
            source: self.whence.clean(cx),
2121
            def_id: ast_util::local_def(self.id),
2122 2123
            visibility: self.vis.clean(cx),
            stability: self.stab.clean(cx),
C
Corey Richardson 已提交
2124
            inner: ImplItem(Impl {
2125 2126 2127
                generics: self.generics.clean(cx),
                trait_: self.trait_.clean(cx),
                for_: self.for_.clean(cx),
A
Aaron Turon 已提交
2128
                items: self.items.clean(cx).into_iter().map(|ti| {
2129 2130
                        match ti {
                            MethodImplItem(i) => i,
2131
                            TypeImplItem(i) => i,
2132 2133
                        }
                    }).collect(),
2134
                derived: detect_derived(&self.attrs),
2135
                polarity: Some(self.polarity.clean(cx)),
C
Corey Richardson 已提交
2136 2137 2138 2139 2140
            }),
        }
    }
}

2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152
impl Clean<Item> for doctree::ExternCrate {
    fn clean(&self, cx: &DocContext) -> Item {
        Item {
            name: None,
            attrs: self.attrs.clean(cx),
            source: self.whence.clean(cx),
            def_id: ast_util::local_def(0),
            visibility: self.vis.clean(cx),
            stability: None,
            inner: ExternCrateItem(self.name.clean(cx), self.path.clone())
        }
    }
C
Corey Richardson 已提交
2153 2154
}

2155
impl Clean<Vec<Item>> for doctree::Import {
2156
    fn clean(&self, cx: &DocContext) -> Vec<Item> {
J
Joseph Crail 已提交
2157
        // We consider inlining the documentation of `pub use` statements, but we
2158 2159
        // forcefully don't inline if this is not public or if the
        // #[doc(no_inline)] attribute is present.
2160 2161
        let denied = self.vis != ast::Public || self.attrs.iter().any(|a| {
            a.name().get() == "doc" && match a.meta_item_list() {
2162
                Some(l) => attr::contains_name(l, "no_inline"),
2163 2164 2165
                None => false,
            }
        });
2166 2167 2168
        let (mut ret, inner) = match self.node {
            ast::ViewPathGlob(ref p) => {
                (vec![], GlobImport(resolve_use_source(cx, p.clean(cx), self.id)))
2169
            }
2170 2171 2172 2173 2174 2175 2176
            ast::ViewPathList(ref p, ref list) => {
                // Attempt to inline all reexported items, but be sure
                // to keep any non-inlineable reexports so they can be
                // listed in the documentation.
                let mut ret = vec![];
                let remaining = if !denied {
                    let mut remaining = vec![];
2177
                    for path in list {
2178 2179 2180 2181 2182 2183
                        match inline::try_inline(cx, path.node.id(), None) {
                            Some(items) => {
                                ret.extend(items.into_iter());
                            }
                            None => {
                                remaining.push(path.clean(cx));
2184 2185 2186
                            }
                        }
                    }
2187 2188 2189
                    remaining
                } else {
                    list.clean(cx)
P
Patrick Walton 已提交
2190
                };
2191 2192 2193 2194 2195
                if remaining.is_empty() {
                    return ret;
                }
                (ret, ImportList(resolve_use_source(cx, p.clean(cx), self.id),
                                 remaining))
P
Patrick Walton 已提交
2196
            }
2197 2198 2199 2200 2201 2202 2203 2204 2205
            ast::ViewPathSimple(i, ref p) => {
                if !denied {
                    match inline::try_inline(cx, self.id, Some(i)) {
                        Some(items) => return items,
                        None => {}
                    }
                }
                (vec![], SimpleImport(i.clean(cx),
                                      resolve_use_source(cx, p.clean(cx), self.id)))
2206
            }
2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217
        };
        ret.push(Item {
            name: None,
            attrs: self.attrs.clean(cx),
            source: self.whence.clean(cx),
            def_id: ast_util::local_def(0),
            visibility: self.vis.clean(cx),
            stability: None,
            inner: ImportItem(inner)
        });
        ret
C
Corey Richardson 已提交
2218 2219 2220
    }
}

J
Jorge Aparicio 已提交
2221
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
2222
pub enum Import {
2223
    // use source as str;
2224
    SimpleImport(String, ImportSource),
A
Alex Crichton 已提交
2225 2226 2227
    // use source::*;
    GlobImport(ImportSource),
    // use source::{a, b, c};
2228
    ImportList(ImportSource, Vec<ViewListIdent>),
A
Alex Crichton 已提交
2229 2230
}

J
Jorge Aparicio 已提交
2231
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
A
Alex Crichton 已提交
2232
pub struct ImportSource {
2233 2234
    pub path: Path,
    pub did: Option<ast::DefId>,
C
Corey Richardson 已提交
2235 2236
}

J
Jorge Aparicio 已提交
2237
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
A
Alex Crichton 已提交
2238
pub struct ViewListIdent {
2239
    pub name: String,
2240
    pub source: Option<ast::DefId>,
A
Alex Crichton 已提交
2241
}
C
Corey Richardson 已提交
2242

J
Jakub Wieczorek 已提交
2243
impl Clean<ViewListIdent> for ast::PathListItem {
2244
    fn clean(&self, cx: &DocContext) -> ViewListIdent {
J
Jakub Wieczorek 已提交
2245 2246
        match self.node {
            ast::PathListIdent { id, name } => ViewListIdent {
2247 2248
                name: name.clean(cx),
                source: resolve_def(cx, id)
J
Jakub Wieczorek 已提交
2249 2250
            },
            ast::PathListMod { id } => ViewListIdent {
2251
                name: "self".to_string(),
2252
                source: resolve_def(cx, id)
J
Jakub Wieczorek 已提交
2253
            }
A
Alex Crichton 已提交
2254
        }
C
Corey Richardson 已提交
2255 2256 2257
    }
}

2258
impl Clean<Vec<Item>> for ast::ForeignMod {
2259 2260
    fn clean(&self, cx: &DocContext) -> Vec<Item> {
        self.items.clean(cx)
2261 2262 2263
    }
}

2264
impl Clean<Item> for ast::ForeignItem {
2265
    fn clean(&self, cx: &DocContext) -> Item {
2266
        let inner = match self.node {
2267
            ast::ForeignItemFn(ref decl, ref generics) => {
2268
                ForeignFunctionItem(Function {
2269 2270
                    decl: decl.clean(cx),
                    generics: generics.clean(cx),
N
Niko Matsakis 已提交
2271
                    unsafety: ast::Unsafety::Unsafe,
2272 2273
                })
            }
2274
            ast::ForeignItemStatic(ref ty, mutbl) => {
2275
                ForeignStaticItem(Static {
2276
                    type_: ty.clean(cx),
2277
                    mutability: if mutbl {Mutable} else {Immutable},
2278
                    expr: "".to_string(),
2279 2280 2281 2282
                })
            }
        };
        Item {
2283 2284 2285
            name: Some(self.ident.clean(cx)),
            attrs: self.attrs.clean(cx),
            source: self.span.clean(cx),
2286
            def_id: ast_util::local_def(self.id),
2287 2288
            visibility: self.vis.clean(cx),
            stability: get_stability(cx, ast_util::local_def(self.id)),
2289 2290 2291 2292 2293
            inner: inner,
        }
    }
}

C
Corey Richardson 已提交
2294 2295 2296
// Utilities

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

2300
impl ToSource for syntax::codemap::Span {
2301
    fn to_src(&self, cx: &DocContext) -> String {
2302
        debug!("converting span {:?} to snippet", self.clean(cx));
2303
        let sn = match cx.sess().codemap().span_to_snippet(*self) {
2304 2305
            Some(x) => x.to_string(),
            None    => "".to_string()
C
Corey Richardson 已提交
2306
        };
2307
        debug!("got snippet {}", sn);
C
Corey Richardson 已提交
2308 2309 2310 2311
        sn
    }
}

2312
fn lit_to_string(lit: &ast::Lit) -> String {
C
Corey Richardson 已提交
2313
    match lit.node {
2314
        ast::LitStr(ref st, _) => st.get().to_string(),
2315
        ast::LitBinary(ref data) => format!("{:?}", data),
2316 2317
        ast::LitByte(b) => {
            let mut res = String::from_str("b'");
2318
            for c in (b as char).escape_default() {
2319
                res.push(c);
2320
            }
2321
            res.push('\'');
2322 2323
            res
        },
A
Alex Crichton 已提交
2324
        ast::LitChar(c) => format!("'{}'", c),
2325
        ast::LitInt(i, _t) => i.to_string(),
2326 2327
        ast::LitFloat(ref f, _t) => f.get().to_string(),
        ast::LitFloatUnsuffixed(ref f) => f.get().to_string(),
2328
        ast::LitBool(b) => b.to_string(),
C
Corey Richardson 已提交
2329 2330 2331
    }
}

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

C
Corey Richardson 已提交
2336
    match p.node {
2337 2338
        PatWild(PatWildSingle) => "_".to_string(),
        PatWild(PatWildMulti) => "..".to_string(),
2339
        PatIdent(_, ref p, _) => token::get_ident(p.node).get().to_string(),
2340
        PatEnum(ref p, _) => path_to_string(p),
2341 2342
        PatStruct(ref name, ref fields, etc) => {
            format!("{} {{ {}{} }}", path_to_string(name),
2343
                fields.iter().map(|&Spanned { node: ref fp, .. }|
2344 2345 2346 2347 2348 2349 2350
                                  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(", ")),
2351
        PatBox(ref p) => name_from_pat(&**p),
2352
        PatRegion(ref p, _) => name_from_pat(&**p),
2353 2354 2355
        PatLit(..) => {
            warn!("tried to get argument name from PatLit, \
                  which is silly in function arguments");
2356
            "()".to_string()
2357
        },
S
Steve Klabnik 已提交
2358
        PatRange(..) => panic!("tried to get argument name from PatRange, \
2359
                              which is not allowed in function arguments"),
2360 2361 2362 2363 2364 2365
        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(", "))
        },
2366 2367 2368 2369 2370
        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 已提交
2371 2372 2373 2374
    }
}

/// Given a Type, resolve it using the def_map
N
Niko Matsakis 已提交
2375 2376
fn resolve_type(cx: &DocContext,
                path: Path,
2377
                id: ast::NodeId) -> Type {
2378 2379
    let tcx = match cx.tcx_opt() {
        Some(tcx) => tcx,
2380
        // If we're extracting tests, this return value doesn't matter.
2381
        None => return Primitive(Bool),
2382
    };
L
Luqman Aden 已提交
2383
    debug!("searching for {} in defmap", id);
2384
    let def = match tcx.def_map.borrow().get(&id) {
2385
        Some(&k) => k,
S
Steve Klabnik 已提交
2386
        None => panic!("unresolved id not in defmap")
C
Corey Richardson 已提交
2387 2388
    };

2389
    match def {
2390 2391 2392
        def::DefSelfTy(..) => {
            return Generic(token::get_name(special_idents::type_self.name).to_string());
        }
2393
        def::DefPrimTy(p) => match p {
2394 2395 2396
            ast::TyStr => return Primitive(Str),
            ast::TyBool => return Primitive(Bool),
            ast::TyChar => return Primitive(Char),
2397
            ast::TyInt(ast::TyIs(_)) => return Primitive(Isize),
2398 2399 2400 2401
            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),
2402
            ast::TyUint(ast::TyUs(_)) => return Primitive(Usize),
2403 2404 2405 2406 2407 2408
            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 已提交
2409
        },
2410
        def::DefTyParam(_, _, _, n) => return Generic(token::get_name(n).to_string()),
2411
        def::DefTyParamBinder(i) => return TyParamBinder(i),
2412 2413
        _ => {}
    };
2414
    let did = register_def(&*cx, def);
N
Niko Matsakis 已提交
2415
    ResolvedPath { path: path, typarams: None, did: did }
2416 2417
}

2418
fn register_def(cx: &DocContext, def: def::Def) -> ast::DefId {
2419
    let (did, kind) = match def {
N
Nick Cameron 已提交
2420
        def::DefFn(i, _) => (i, TypeFunction),
2421 2422
        def::DefTy(i, false) => (i, TypeTypedef),
        def::DefTy(i, true) => (i, TypeEnum),
2423 2424 2425 2426 2427 2428
        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 已提交
2429
    };
2430
    if ast_util::is_local(did) { return did }
2431 2432 2433
    let tcx = match cx.tcx_opt() {
        Some(tcx) => tcx,
        None => return did
2434
    };
2435
    inline::record_extern_fqn(cx, did, kind);
2436 2437 2438
    if let TypeTrait = kind {
        let t = inline::build_external_trait(cx, tcx, did);
        cx.external_traits.borrow_mut().as_mut().unwrap().insert(did, t);
2439
    }
2440
    return did;
C
Corey Richardson 已提交
2441
}
A
Alex Crichton 已提交
2442

2443
fn resolve_use_source(cx: &DocContext, path: Path, id: ast::NodeId) -> ImportSource {
A
Alex Crichton 已提交
2444 2445
    ImportSource {
        path: path,
2446
        did: resolve_def(cx, id),
A
Alex Crichton 已提交
2447 2448 2449
    }
}

2450 2451
fn resolve_def(cx: &DocContext, id: ast::NodeId) -> Option<ast::DefId> {
    cx.tcx_opt().and_then(|tcx| {
2452
        tcx.def_map.borrow().get(&id).map(|&def| register_def(cx, def))
2453
    })
A
Alex Crichton 已提交
2454
}
2455

J
Jorge Aparicio 已提交
2456
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
2457
pub struct Macro {
2458
    pub source: String,
2459 2460 2461
}

impl Clean<Item> for doctree::Macro {
2462
    fn clean(&self, cx: &DocContext) -> Item {
2463
        Item {
2464 2465 2466 2467 2468
            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),
2469
            def_id: ast_util::local_def(self.id),
2470
            inner: MacroItem(Macro {
2471
                source: self.whence.to_src(cx),
2472 2473 2474 2475
            }),
        }
    }
}
2476

J
Jorge Aparicio 已提交
2477
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
2478 2479
pub struct Stability {
    pub level: attr::StabilityLevel,
2480 2481 2482
    pub feature: String,
    pub since: String,
    pub reason: String
2483 2484 2485
}

impl Clean<Stability> for attr::Stability {
2486
    fn clean(&self, _: &DocContext) -> Stability {
2487 2488
        Stability {
            level: self.level,
2489
            feature: self.feature.get().to_string(),
2490 2491
            since: self.since.as_ref().map_or("".to_string(),
                                              |interned| interned.get().to_string()),
2492 2493
            reason: self.reason.as_ref().map_or("".to_string(),
                                                |interned| interned.get().to_string()),
2494 2495 2496
        }
    }
}
A
Alex Crichton 已提交
2497

2498 2499 2500
impl Clean<Item> for ast::AssociatedType {
    fn clean(&self, cx: &DocContext) -> Item {
        Item {
2501 2502
            source: self.ty_param.span.clean(cx),
            name: Some(self.ty_param.ident.clean(cx)),
2503
            attrs: self.attrs.clean(cx),
2504
            inner: AssociatedTypeItem(self.ty_param.clean(cx)),
2505
            visibility: None,
2506
            def_id: ast_util::local_def(self.ty_param.id),
2507 2508 2509 2510 2511 2512 2513 2514 2515
            stability: None,
        }
    }
}

impl Clean<Item> for ty::AssociatedType {
    fn clean(&self, cx: &DocContext) -> Item {
        Item {
            source: DUMMY_SP.clean(cx),
2516
            name: Some(self.name.clean(cx)),
2517
            attrs: Vec::new(),
2518 2519 2520 2521 2522 2523
            inner: AssociatedTypeItem(TyParam {
                name: self.name.clean(cx),
                did: ast::DefId {
                    krate: 0,
                    node: ast::DUMMY_NODE_ID
                },
2524 2525
                // FIXME(#20727): bounds are missing and need to be filled in from the
                // predicates on the trait itself
2526
                bounds: vec![],
2527
                default: None,
2528
            }),
2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546
            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(),
2547
                    where_predicates: Vec::new()
2548 2549 2550 2551 2552 2553 2554 2555 2556
                },
            }),
            visibility: None,
            def_id: ast_util::local_def(self.id),
            stability: None,
        }
    }
}

2557 2558 2559 2560 2561 2562 2563 2564 2565 2566
impl<'a> Clean<Typedef> for (ty::TypeScheme<'a>, ParamSpace) {
    fn clean(&self, cx: &DocContext) -> Typedef {
        let (ref ty_scheme, ps) = *self;
        Typedef {
            type_: ty_scheme.ty.clean(cx),
            generics: (&ty_scheme.generics, ps).clean(cx)
        }
    }
}

2567
fn lang_struct(cx: &DocContext, did: Option<ast::DefId>,
2568
               t: ty::Ty, name: &str,
A
Alex Crichton 已提交
2569 2570 2571
               fallback: fn(Box<Type>) -> Type) -> Type {
    let did = match did {
        Some(did) => did,
2572
        None => return fallback(box t.clean(cx)),
A
Alex Crichton 已提交
2573
    };
2574
    let fqn = csearch::get_item_path(cx.tcx(), did);
A
Aaron Turon 已提交
2575
    let fqn: Vec<String> = fqn.into_iter().map(|i| {
A
Alex Crichton 已提交
2576 2577
        i.to_string()
    }).collect();
2578
    cx.external_paths.borrow_mut().as_mut().unwrap().insert(did, (fqn, TypeStruct));
A
Alex Crichton 已提交
2579 2580 2581 2582 2583 2584 2585
    ResolvedPath {
        typarams: None,
        did: did,
        path: Path {
            global: false,
            segments: vec![PathSegment {
                name: name.to_string(),
2586 2587 2588
                params: PathParameters::AngleBracketed {
                    lifetimes: vec![],
                    types: vec![t.clean(cx)],
2589
                    bindings: vec![]
2590
                }
A
Alex Crichton 已提交
2591 2592 2593 2594
            }],
        },
    }
}
2595 2596

/// An equality constraint on an associated type, e.g. `A=Bar` in `Foo<A=Bar>`
J
Jorge Aparicio 已提交
2597
#[derive(Clone, PartialEq, RustcDecodable, RustcEncodable, Debug)]
2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610
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)
        }
    }
}