mod.rs 84.9 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;
S
Steven Fackler 已提交
51
use std::str::Str as StrTrait; // Conflicts with Str variant
52
use std::path::Path as FsPath; // Conflicts with Path struct
53

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

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

62 63
mod inline;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        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)));
373 374 375

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

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

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

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

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

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

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

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

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

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

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

507 508 509 510
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)));
511
        for bb in &self.builtin_bounds {
512
            tp_bounds.push(bb.clean(cx));
513
        }
N
Niko Matsakis 已提交
514

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

523
        (tp_bounds, bindings)
524 525 526
    }
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

            ast::WherePredicate::EqPredicate(_) => {
762
                unimplemented!() // FIXME(#20041)
N
Nick Cameron 已提交
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 844
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 已提交
845
// maybe use a Generic enum and use ~[Generic]?
J
Jorge Aparicio 已提交
846
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
C
Corey Richardson 已提交
847
pub struct Generics {
848 849
    pub lifetimes: Vec<Lifetime>,
    pub type_params: Vec<TyParam>,
850
    pub where_predicates: Vec<WherePredicate>
851
}
C
Corey Richardson 已提交
852 853

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

863
impl<'a, 'tcx> Clean<Generics> for (&'a ty::Generics<'tcx>, subst::ParamSpace) {
864
    fn clean(&self, cx: &DocContext) -> Generics {
865 866 867 868 869 870 871 872 873 874
        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
                };
875
                for bound in bounds {
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 917
                    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.
918
        for tp in &stripped_typarams {
919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934
            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`

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    // _
    Infer,

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

J
Jorge Aparicio 已提交
2049
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071
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 已提交
2072
#[derive(Debug, Clone, RustcEncodable, RustcDecodable, PartialEq, Copy)]
C
Corey Richardson 已提交
2073 2074 2075 2076 2077
pub enum Mutability {
    Mutable,
    Immutable,
}

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

J
Jorge Aparicio 已提交
2087
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Copy, Debug)]
2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101
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 已提交
2102
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
2103
pub struct Impl {
2104 2105 2106
    pub generics: Generics,
    pub trait_: Option<Type>,
    pub for_: Type,
2107
    pub items: Vec<Item>,
2108
    pub derived: bool,
2109
    pub polarity: Option<ImplPolarity>,
C
Corey Richardson 已提交
2110 2111
}

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

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

2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153
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 已提交
2154 2155
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2558 2559 2560 2561 2562 2563 2564 2565 2566 2567
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)
        }
    }
}

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

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