mod.rs 92.3 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
pub use self::Type::*;
pub use self::PrimitiveType::*;
pub use self::TypeKind::*;
pub use self::StructField::*;
pub use self::VariantKind::*;
pub use self::Mutability::*;
20
pub use self::Import::*;
S
Steven Fackler 已提交
21 22 23 24 25 26
pub use self::ItemEnum::*;
pub use self::Attribute::*;
pub use self::TyParamBound::*;
pub use self::SelfTy::*;
pub use self::FunctionRetTy::*;

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

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

47 48
use std::collections::HashMap;
use std::path::PathBuf;
49
use std::rc::Rc;
50
use std::u32;
51

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

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

60
mod inline;
61
mod simplify;
62

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

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

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

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

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

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

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

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

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

J
Jorge Aparicio 已提交
117
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
118
pub struct Crate {
119
    pub name: String,
A
Alex Crichton 已提交
120
    pub src: PathBuf,
121 122
    pub module: Option<Item>,
    pub externs: Vec<(ast::CrateNum, ExternalCrate)>,
123
    pub primitives: Vec<PrimitiveType>,
124
    pub external_traits: HashMap<ast::DefId, Trait>,
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 132 133 134
        if let Some(t) = cx.tcx_opt() {
            cx.deref_trait_did.set(t.lang_items.deref_trait());
        }

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

141
        // Figure out the name of this crate
142
        let input = &cx.input;
143
        let name = link::find_crate_name(None, &self.attrs, input);
144

145
        // Clean the crate, translating the entire libsyntax AST to one that is
146
        // understood by rustdoc.
147
        let mut module = self.module.clean(cx);
148 149 150

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

196 197
        let src = match cx.input {
            Input::File(ref path) => path.clone(),
A
Aaron Turon 已提交
198
            Input::Str(_) => PathBuf::new() // FIXME: this is wrong
199 200
        };

C
Corey Richardson 已提交
201
        Crate {
202
            name: name.to_string(),
203
            src: src,
204
            module: Some(module),
205
            externs: externs,
206
            primitives: primitives,
207 208
            external_traits: cx.external_traits.borrow_mut().take()
                               .unwrap_or(HashMap::new()),
209 210 211 212
        }
    }
}

J
Jorge Aparicio 已提交
213
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
214
pub struct ExternalCrate {
215
    pub name: String,
216
    pub attrs: Vec<Attribute>,
217
    pub primitives: Vec<PrimitiveType>,
218 219 220
}

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

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

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

288 289
    pub fn is_hidden_from_doc(&self) -> bool {
        match self.doc_list() {
290 291
            Some(l) => {
                for innerattr in l {
292
                    match *innerattr {
293
                        Word(ref s) if "hidden" == *s => {
294 295
                            return true
                        }
296 297 298 299 300 301 302 303 304
                        _ => (),
                    }
                }
            },
            None => ()
        }
        return false;
    }

305
    pub fn is_mod(&self) -> bool {
A
Alex Crichton 已提交
306
        match self.inner { ModuleItem(..) => true, _ => false }
307 308
    }
    pub fn is_trait(&self) -> bool {
A
Alex Crichton 已提交
309
        match self.inner { TraitItem(..) => true, _ => false }
310 311
    }
    pub fn is_struct(&self) -> bool {
A
Alex Crichton 已提交
312
        match self.inner { StructItem(..) => true, _ => false }
313 314
    }
    pub fn is_enum(&self) -> bool {
A
Alex Crichton 已提交
315
        match self.inner { EnumItem(..) => true, _ => false }
316 317
    }
    pub fn is_fn(&self) -> bool {
A
Alex Crichton 已提交
318
        match self.inner { FunctionItem(..) => true, _ => false }
319
    }
320 321 322 323 324 325 326 327

    pub fn stability_class(&self) -> String {
        match self.stability {
            Some(ref s) => {
                let mut base = match s.level {
                    attr::Unstable => "unstable".to_string(),
                    attr::Stable => String::new(),
                };
328
                if !s.deprecated_since.is_empty() {
329 330 331 332 333 334 335
                    base.push_str(" deprecated");
                }
                base
            }
            _ => String::new(),
        }
    }
336 337
}

J
Jorge Aparicio 已提交
338
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
339
pub enum ItemEnum {
340 341
    ExternCrateItem(String, Option<String>),
    ImportItem(Import),
C
Corey Richardson 已提交
342 343 344 345 346 347
    StructItem(Struct),
    EnumItem(Enum),
    FunctionItem(Function),
    ModuleItem(Module),
    TypedefItem(Typedef),
    StaticItem(Static),
348
    ConstantItem(Constant),
C
Corey Richardson 已提交
349 350
    TraitItem(Trait),
    ImplItem(Impl),
351 352
    /// A method signature only. Used for required methods in traits (ie,
    /// non-default-methods).
C
Corey Richardson 已提交
353
    TyMethodItem(TyMethod),
354
    /// A method with a body.
C
Corey Richardson 已提交
355 356 357
    MethodItem(Method),
    StructFieldItem(StructField),
    VariantItem(Variant),
358
    /// `fn`s from an extern block
359
    ForeignFunctionItem(Function),
360
    /// `static`s from an extern block
361
    ForeignStaticItem(Static),
362
    MacroItem(Macro),
363
    PrimitiveItem(PrimitiveType),
364
    AssociatedConstItem(Type, Option<String>),
365
    AssociatedTypeItem(Vec<TyParamBound>, Option<Type>),
366
    DefaultImplItem(DefaultImpl),
C
Corey Richardson 已提交
367 368
}

J
Jorge Aparicio 已提交
369
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
370
pub struct Module {
371 372
    pub items: Vec<Item>,
    pub is_crate: bool,
C
Corey Richardson 已提交
373 374 375
}

impl Clean<Item> for doctree::Module {
376
    fn clean(&self, cx: &DocContext) -> Item {
C
Corey Richardson 已提交
377
        let name = if self.name.is_some() {
378
            self.name.unwrap().clean(cx)
C
Corey Richardson 已提交
379
        } else {
380
            "".to_string()
C
Corey Richardson 已提交
381
        };
382 383 384 385 386 387 388 389 390 391 392 393 394

        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)));
395
        items.extend(self.impls.iter().flat_map(|x| x.clean(cx).into_iter()));
396
        items.extend(self.macros.iter().map(|x| x.clean(cx)));
397
        items.extend(self.def_traits.iter().map(|x| x.clean(cx)));
398 399 400

        // determine if we should display the inner contents or
        // the outer `mod` item for the source code.
401
        let whence = {
402
            let cm = cx.sess().codemap();
403 404 405 406 407 408 409 410 411 412 413
            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 已提交
414 415
        Item {
            name: Some(name),
416 417 418 419
            attrs: self.attrs.clean(cx),
            source: whence.clean(cx),
            visibility: self.vis.clean(cx),
            stability: self.stab.clean(cx),
420
            def_id: ast_util::local_def(self.id),
C
Corey Richardson 已提交
421
            inner: ModuleItem(Module {
422
               is_crate: self.is_crate,
423
               items: items
C
Corey Richardson 已提交
424 425 426 427 428
            })
        }
    }
}

J
Jorge Aparicio 已提交
429
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
C
Corey Richardson 已提交
430
pub enum Attribute {
431 432 433
    Word(String),
    List(String, Vec<Attribute> ),
    NameValue(String, String)
C
Corey Richardson 已提交
434 435 436
}

impl Clean<Attribute> for ast::MetaItem {
437
    fn clean(&self, cx: &DocContext) -> Attribute {
C
Corey Richardson 已提交
438
        match self.node {
G
GuillaumeGomez 已提交
439
            ast::MetaWord(ref s) => Word(s.to_string()),
440
            ast::MetaList(ref s, ref l) => {
G
GuillaumeGomez 已提交
441
                List(s.to_string(), l.clean(cx))
442 443
            }
            ast::MetaNameValue(ref s, ref v) => {
G
GuillaumeGomez 已提交
444
                NameValue(s.to_string(), lit_to_string(v))
445
            }
C
Corey Richardson 已提交
446 447 448 449 450
        }
    }
}

impl Clean<Attribute> for ast::Attribute {
451
    fn clean(&self, cx: &DocContext) -> Attribute {
452
        self.with_desugared_doc(|a| a.node.value.clean(cx))
C
Corey Richardson 已提交
453 454 455
    }
}

456
// This is a rough approximation that gets us what we want.
457
impl attr::AttrMetaMethods for Attribute {
458
    fn name(&self) -> InternedString {
459
        match *self {
460
            Word(ref n) | List(ref n, _) | NameValue(ref n, _) => {
461
                token::intern_and_get_ident(n)
462
            }
463 464 465
        }
    }

466
    fn value_str(&self) -> Option<InternedString> {
467
        match *self {
468
            NameValue(_, ref v) => {
469
                Some(token::intern_and_get_ident(v))
470
            }
471 472 473
            _ => None,
        }
    }
474
    fn meta_item_list<'a>(&'a self) -> Option<&'a [P<ast::MetaItem>]> { None }
475
    fn span(&self) -> codemap::Span { unimplemented!() }
476
}
477 478 479
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 已提交
480
    fn meta_item_list(&self) -> Option<&[P<ast::MetaItem>]> { None }
481
    fn span(&self) -> codemap::Span { unimplemented!() }
482
}
483

J
Jorge Aparicio 已提交
484
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
C
Corey Richardson 已提交
485
pub struct TyParam {
486
    pub name: String,
487
    pub did: ast::DefId,
488
    pub bounds: Vec<TyParamBound>,
489
    pub default: Option<Type>,
490
}
C
Corey Richardson 已提交
491 492

impl Clean<TyParam> for ast::TyParam {
493
    fn clean(&self, cx: &DocContext) -> TyParam {
C
Corey Richardson 已提交
494
        TyParam {
495
            name: self.ident.clean(cx),
496
            did: ast::DefId { krate: ast::LOCAL_CRATE, node: self.id },
497
            bounds: self.bounds.clean(cx),
498
            default: self.default.clean(cx),
C
Corey Richardson 已提交
499 500 501 502
        }
    }
}

503
impl<'tcx> Clean<TyParam> for ty::TypeParameterDef<'tcx> {
504 505
    fn clean(&self, cx: &DocContext) -> TyParam {
        cx.external_typarams.borrow_mut().as_mut().unwrap()
506
          .insert(self.def_id, self.name.clean(cx));
507
        TyParam {
508
            name: self.name.clean(cx),
509
            did: self.def_id,
510
            bounds: vec![], // these are filled in from the where-clauses
511
            default: self.default.clean(cx),
512 513 514 515
        }
    }
}

J
Jorge Aparicio 已提交
516
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
C
Corey Richardson 已提交
517
pub enum TyParamBound {
518
    RegionBound(Lifetime),
N
Nick Cameron 已提交
519
    TraitBound(PolyTrait, ast::TraitBoundModifier)
C
Corey Richardson 已提交
520 521
}

522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550
impl TyParamBound {
    fn maybe_sized(cx: &DocContext) -> TyParamBound {
        use syntax::ast::TraitBoundModifier as TBM;
        let mut sized_bound = ty::BuiltinBound::BoundSized.clean(cx);
        if let TyParamBound::TraitBound(_, ref mut tbm) = sized_bound {
            *tbm = TBM::Maybe
        };
        sized_bound
    }

    fn is_sized_bound(&self, cx: &DocContext) -> bool {
        use syntax::ast::TraitBoundModifier as TBM;
        if let Some(tcx) = cx.tcx_opt() {
            let sized_did = match tcx.lang_items.sized_trait() {
                Some(did) => did,
                None => return false
            };
            if let TyParamBound::TraitBound(PolyTrait {
                trait_: Type::ResolvedPath { did, .. }, ..
            }, TBM::None) = *self {
                if did == sized_did {
                    return true
                }
            }
        }
        false
    }
}

C
Corey Richardson 已提交
551
impl Clean<TyParamBound> for ast::TyParamBound {
552
    fn clean(&self, cx: &DocContext) -> TyParamBound {
C
Corey Richardson 已提交
553
        match *self {
554
            ast::RegionTyParamBound(lt) => RegionBound(lt.clean(cx)),
N
Nick Cameron 已提交
555
            ast::TraitTyParamBound(ref t, modifier) => TraitBound(t.clean(cx), modifier),
C
Corey Richardson 已提交
556 557 558 559
        }
    }
}

560 561 562 563
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)));
564
        for bb in &self.builtin_bounds {
565
            tp_bounds.push(bb.clean(cx));
566
        }
N
Niko Matsakis 已提交
567

568
        let mut bindings = vec![];
569
        for &ty::Binder(ref pb) in &self.projection_bounds {
570 571 572 573 574
            bindings.push(TypeBinding {
                name: pb.projection_ty.item_name.clean(cx),
                ty: pb.ty.clean(cx)
            });
        }
N
Niko Matsakis 已提交
575

576
        (tp_bounds, bindings)
577 578 579
    }
}

580
fn external_path_params(cx: &DocContext, trait_did: Option<ast::DefId>,
581
                        bindings: Vec<TypeBinding>, substs: &subst::Substs) -> PathParameters {
582
    use rustc::middle::ty::sty;
583
    let lifetimes = substs.regions().get_slice(subst::TypeSpace)
584
                    .iter()
585
                    .filter_map(|v| v.clean(cx))
586
                    .collect();
587
    let types = substs.types.get_slice(subst::TypeSpace).to_vec();
588 589 590 591

    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() => {
592
            assert_eq!(types.len(), 1);
593 594 595 596 597
            let inputs = match types[0].sty {
                sty::ty_tup(ref tys) => tys.iter().map(|t| t.clean(cx)).collect(),
                _ => {
                    return PathParameters::AngleBracketed {
                        lifetimes: lifetimes,
598
                        types: types.clean(cx),
599
                        bindings: bindings
600 601 602
                    }
                }
            };
603 604 605 606 607 608
            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))
            // };
609 610 611 612 613 614 615 616 617
            PathParameters::Parenthesized {
                inputs: inputs,
                output: output
            }
        },
        (_, _) => {
            PathParameters::AngleBracketed {
                lifetimes: lifetimes,
                types: types.clean(cx),
618
                bindings: bindings
619 620 621 622 623 624 625 626
            }
        }
    }
}

// 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>,
627
                 bindings: Vec<TypeBinding>, substs: &subst::Substs) -> Path {
628 629 630
    Path {
        global: false,
        segments: vec![PathSegment {
631
            name: name.to_string(),
632
            params: external_path_params(cx, trait_did, bindings, substs)
633
        }],
634 635 636 637
    }
}

impl Clean<TyParamBound> for ty::BuiltinBound {
638 639 640
    fn clean(&self, cx: &DocContext) -> TyParamBound {
        let tcx = match cx.tcx_opt() {
            Some(tcx) => tcx,
641
            None => return RegionBound(Lifetime::statik())
642
        };
643
        let empty = subst::Substs::empty();
644 645
        let (did, path) = match *self {
            ty::BoundSend =>
646
                (tcx.lang_items.send_trait().unwrap(),
647
                 external_path(cx, "Send", None, vec![], &empty)),
648
            ty::BoundSized =>
649
                (tcx.lang_items.sized_trait().unwrap(),
650
                 external_path(cx, "Sized", None, vec![], &empty)),
651
            ty::BoundCopy =>
652
                (tcx.lang_items.copy_trait().unwrap(),
653
                 external_path(cx, "Copy", None, vec![], &empty)),
A
Alex Crichton 已提交
654 655
            ty::BoundSync =>
                (tcx.lang_items.sync_trait().unwrap(),
656
                 external_path(cx, "Sync", None, vec![], &empty)),
657 658
        };
        let fqn = csearch::get_item_path(tcx, did);
A
Aaron Turon 已提交
659
        let fqn = fqn.into_iter().map(|i| i.to_string()).collect();
660 661
        cx.external_paths.borrow_mut().as_mut().unwrap().insert(did,
                                                                (fqn, TypeTrait));
662 663 664 665 666 667 668
        TraitBound(PolyTrait {
            trait_: ResolvedPath {
                path: path,
                typarams: None,
                did: did,
            },
            lifetimes: vec![]
N
Nick Cameron 已提交
669
        }, ast::TraitBoundModifier::None)
670 671 672
    }
}

673
impl<'tcx> Clean<TyParamBound> for ty::TraitRef<'tcx> {
674 675 676
    fn clean(&self, cx: &DocContext) -> TyParamBound {
        let tcx = match cx.tcx_opt() {
            Some(tcx) => tcx,
677
            None => return RegionBound(Lifetime::statik())
678 679
        };
        let fqn = csearch::get_item_path(tcx, self.def_id);
A
Aaron Turon 已提交
680
        let fqn = fqn.into_iter().map(|i| i.to_string())
681
                     .collect::<Vec<String>>();
682
        let path = external_path(cx, fqn.last().unwrap(),
683
                                 Some(self.def_id), vec![], self.substs);
684
        cx.external_paths.borrow_mut().as_mut().unwrap().insert(self.def_id,
685
                                                            (fqn, TypeTrait));
686

687
        debug!("ty::TraitRef\n  substs.types(TypeSpace): {:?}\n",
688 689 690 691
               self.substs.types.get_slice(ParamSpace::TypeSpace));

        // collect any late bound regions
        let mut late_bounds = vec![];
692
        for &ty_s in self.substs.types.get_slice(ParamSpace::TypeSpace) {
693 694
            use rustc::middle::ty::{Region, sty};
            if let sty::ty_tup(ref ts) = ty_s.sty {
695
                for &ty_s in ts {
696
                    if let sty::ty_rptr(ref reg, _) = ty_s.sty {
H
Huon Wilson 已提交
697
                        if let &Region::ReLateBound(_, _) = *reg {
698
                            debug!("  hit an ReLateBound {:?}", reg);
699 700 701 702 703 704 705 706 707 708 709 710
                            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 已提交
711
        }, ast::TraitBoundModifier::None)
712 713 714
    }
}

N
Nick Cameron 已提交
715 716
impl<'tcx> Clean<Vec<TyParamBound>> for ty::ParamBounds<'tcx> {
    fn clean(&self, cx: &DocContext) -> Vec<TyParamBound> {
717
        let mut v = Vec::new();
718
        for t in &self.trait_bounds {
719
            v.push(t.clean(cx));
720
        }
721 722 723
        for r in self.region_bounds.iter().filter_map(|r| r.clean(cx)) {
            v.push(RegionBound(r));
        }
N
Nick Cameron 已提交
724
        v
725 726 727
    }
}

728
impl<'tcx> Clean<Option<Vec<TyParamBound>>> for subst::Substs<'tcx> {
729
    fn clean(&self, cx: &DocContext) -> Option<Vec<TyParamBound>> {
730
        let mut v = Vec::new();
731
        v.extend(self.regions().iter().filter_map(|r| r.clean(cx)).map(RegionBound));
732 733 734
        v.extend(self.types.iter().map(|t| TraitBound(PolyTrait {
            trait_: t.clean(cx),
            lifetimes: vec![]
N
Nick Cameron 已提交
735
        }, ast::TraitBoundModifier::None)));
736
        if !v.is_empty() {Some(v)} else {None}
737 738 739
    }
}

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

743 744 745
impl Lifetime {
    pub fn get_ref<'a>(&'a self) -> &'a str {
        let Lifetime(ref s) = *self;
746
        let s: &'a str = s;
747 748
        return s;
    }
749 750 751 752

    pub fn statik() -> Lifetime {
        Lifetime("'static".to_string())
    }
753 754
}

C
Corey Richardson 已提交
755
impl Clean<Lifetime> for ast::Lifetime {
756
    fn clean(&self, _: &DocContext) -> Lifetime {
G
GuillaumeGomez 已提交
757
        Lifetime(token::get_name(self.name).to_string())
C
Corey Richardson 已提交
758 759 760
    }
}

761
impl Clean<Lifetime> for ast::LifetimeDef {
762
    fn clean(&self, _: &DocContext) -> Lifetime {
G
GuillaumeGomez 已提交
763
        Lifetime(token::get_name(self.lifetime.name).to_string())
764 765 766
    }
}

767
impl Clean<Lifetime> for ty::RegionParameterDef {
768
    fn clean(&self, _: &DocContext) -> Lifetime {
G
GuillaumeGomez 已提交
769
        Lifetime(token::get_name(self.name).to_string())
770 771 772 773
    }
}

impl Clean<Option<Lifetime>> for ty::Region {
774
    fn clean(&self, cx: &DocContext) -> Option<Lifetime> {
775
        match *self {
776
            ty::ReStatic => Some(Lifetime::statik()),
777
            ty::ReLateBound(_, ty::BrNamed(_, name)) =>
G
GuillaumeGomez 已提交
778
                Some(Lifetime(token::get_name(name).to_string())),
N
Niko Matsakis 已提交
779
            ty::ReEarlyBound(ref data) => Some(Lifetime(data.name.clean(cx))),
780 781 782 783 784 785 786 787 788 789

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

J
Jorge Aparicio 已提交
790
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
791 792 793
pub enum WherePredicate {
    BoundPredicate { ty: Type, bounds: Vec<TyParamBound> },
    RegionPredicate { lifetime: Lifetime, bounds: Vec<Lifetime>},
794
    EqPredicate { lhs: Type, rhs: Type }
795 796 797 798
}

impl Clean<WherePredicate> for ast::WherePredicate {
    fn clean(&self, cx: &DocContext) -> WherePredicate {
N
Nick Cameron 已提交
799 800
        match *self {
            ast::WherePredicate::BoundPredicate(ref wbp) => {
801
                WherePredicate::BoundPredicate {
802
                    ty: wbp.bounded_ty.clean(cx),
N
Nick Cameron 已提交
803 804 805
                    bounds: wbp.bounds.clean(cx)
                }
            }
806 807 808 809 810 811 812 813 814

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

            ast::WherePredicate::EqPredicate(_) => {
815
                unimplemented!() // FIXME(#20041)
N
Nick Cameron 已提交
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 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887
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_,
888 889 890
            TyParamBound::RegionBound(_) => {
                panic!("cleaning a trait got a region")
            }
891 892 893 894 895 896 897 898 899
        };
        Type::QPath {
            name: self.item_name.clean(cx),
            self_type: box self.trait_ref.self_ty().clean(cx),
            trait_: box trait_
        }
    }
}

900
// maybe use a Generic enum and use Vec<Generic>?
J
Jorge Aparicio 已提交
901
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
C
Corey Richardson 已提交
902
pub struct Generics {
903 904
    pub lifetimes: Vec<Lifetime>,
    pub type_params: Vec<TyParam>,
905
    pub where_predicates: Vec<WherePredicate>
906
}
C
Corey Richardson 已提交
907 908

impl Clean<Generics> for ast::Generics {
909
    fn clean(&self, cx: &DocContext) -> Generics {
C
Corey Richardson 已提交
910
        Generics {
911 912
            lifetimes: self.lifetimes.clean(cx),
            type_params: self.ty_params.clean(cx),
913
            where_predicates: self.where_clause.predicates.clean(cx)
C
Corey Richardson 已提交
914 915 916 917
        }
    }
}

918 919 920
impl<'a, 'tcx> Clean<Generics> for (&'a ty::Generics<'tcx>,
                                    &'a ty::GenericPredicates<'tcx>,
                                    subst::ParamSpace) {
921
    fn clean(&self, cx: &DocContext) -> Generics {
922 923 924
        use std::collections::HashSet;
        use self::WherePredicate as WP;

925 926
        let (gens, preds, space) = *self;

927 928 929
        // Bounds in the type_params and lifetimes fields are repeated in the
        // predicates field (see rustc_typeck::collect::ty_generics), so remove
        // them.
930
        let stripped_typarams = gens.types.get_slice(space).iter().map(|tp| {
931
            tp.clean(cx)
932 933 934 935 936 937 938
        }).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<_>>();

939 940
        let mut where_predicates = preds.predicates.get_slice(space)
                                                   .to_vec().clean(cx);
941

942
        // Type parameters and have a Sized bound by default unless removed with
943 944
        // ?Sized.  Scan through the predicates and mark any type parameter with
        // a Sized bound, removing the bounds as we find them.
945 946
        //
        // Note that associated types also have a sized bound by default, but we
947
        // don't actually know the set of associated types right here so that's
948
        // handled in cleaning associated types
949
        let mut sized_params = HashSet::new();
950 951 952 953 954 955 956 957 958
        where_predicates.retain(|pred| {
            match *pred {
                WP::BoundPredicate { ty: Generic(ref g), ref bounds } => {
                    if bounds.iter().any(|b| b.is_sized_bound(cx)) {
                        sized_params.insert(g.clone());
                        false
                    } else {
                        true
                    }
959
                }
960
                _ => true,
961
            }
962
        });
963

964
        // Run through the type parameters again and insert a ?Sized
965
        // unbound for any we didn't find to be Sized.
966
        for tp in &stripped_typarams {
967 968 969
            if !sized_params.contains(&tp.name) {
                where_predicates.push(WP::BoundPredicate {
                    ty: Type::Generic(tp.name.clone()),
970
                    bounds: vec![TyParamBound::maybe_sized(cx)],
971 972 973 974 975 976 977 978
                })
            }
        }

        // 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`

979
        Generics {
980
            type_params: simplify::ty_params(stripped_typarams),
981
            lifetimes: stripped_lifetimes,
982
            where_predicates: simplify::where_clauses(cx, where_predicates),
983 984 985 986
        }
    }
}

J
Jorge Aparicio 已提交
987
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
988
pub struct Method {
989 990
    pub generics: Generics,
    pub self_: SelfTy,
N
Niko Matsakis 已提交
991
    pub unsafety: ast::Unsafety,
992
    pub constness: ast::Constness,
993
    pub decl: FnDecl,
994
    pub abi: abi::Abi
C
Corey Richardson 已提交
995 996
}

997
impl Clean<Method> for ast::MethodSig {
998
    fn clean(&self, cx: &DocContext) -> Method {
999 1000
        let all_inputs = &self.decl.inputs;
        let inputs = match self.explicit_self.node {
1001
            ast::SelfStatic => &**all_inputs,
J
Jorge Aparicio 已提交
1002
            _ => &all_inputs[1..]
1003 1004
        };
        let decl = FnDecl {
1005
            inputs: Arguments {
1006
                values: inputs.clean(cx),
1007
            },
1008
            output: self.decl.output.clean(cx),
1009
            attrs: Vec::new()
1010
        };
1011
        Method {
1012 1013
            generics: self.generics.clean(cx),
            self_: self.explicit_self.node.clean(cx),
1014 1015
            unsafety: self.unsafety,
            constness: self.constness,
1016
            decl: decl,
1017
            abi: self.abi
C
Corey Richardson 已提交
1018 1019 1020 1021
        }
    }
}

J
Jorge Aparicio 已提交
1022
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
1023
pub struct TyMethod {
N
Niko Matsakis 已提交
1024
    pub unsafety: ast::Unsafety,
1025 1026 1027
    pub decl: FnDecl,
    pub generics: Generics,
    pub self_: SelfTy,
1028
    pub abi: abi::Abi
C
Corey Richardson 已提交
1029 1030
}

1031
impl Clean<TyMethod> for ast::MethodSig {
1032
    fn clean(&self, cx: &DocContext) -> TyMethod {
1033
        let inputs = match self.explicit_self.node {
1034
            ast::SelfStatic => &*self.decl.inputs,
J
Jorge Aparicio 已提交
1035
            _ => &self.decl.inputs[1..]
1036 1037
        };
        let decl = FnDecl {
1038
            inputs: Arguments {
1039
                values: inputs.clean(cx),
1040
            },
1041
            output: self.decl.output.clean(cx),
1042
            attrs: Vec::new()
1043
        };
1044 1045 1046 1047 1048 1049
        TyMethod {
            unsafety: self.unsafety.clone(),
            decl: decl,
            self_: self.explicit_self.node.clean(cx),
            generics: self.generics.clean(cx),
            abi: self.abi
C
Corey Richardson 已提交
1050 1051 1052 1053
        }
    }
}

J
Jorge Aparicio 已提交
1054
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
C
Corey Richardson 已提交
1055 1056 1057 1058
pub enum SelfTy {
    SelfStatic,
    SelfValue,
    SelfBorrowed(Option<Lifetime>, Mutability),
1059
    SelfExplicit(Type),
C
Corey Richardson 已提交
1060 1061
}

1062
impl Clean<SelfTy> for ast::ExplicitSelf_ {
1063
    fn clean(&self, cx: &DocContext) -> SelfTy {
1064
        match *self {
1065
            ast::SelfStatic => SelfStatic,
1066
            ast::SelfValue(_) => SelfValue,
1067
            ast::SelfRegion(ref lt, ref mt, _) => {
1068
                SelfBorrowed(lt.clean(cx), mt.clean(cx))
1069
            }
1070
            ast::SelfExplicit(ref typ, _) => SelfExplicit(typ.clean(cx)),
C
Corey Richardson 已提交
1071 1072 1073 1074
        }
    }
}

J
Jorge Aparicio 已提交
1075
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
1076
pub struct Function {
1077 1078
    pub decl: FnDecl,
    pub generics: Generics,
N
Niko Matsakis 已提交
1079
    pub unsafety: ast::Unsafety,
1080 1081
    pub constness: ast::Constness,
    pub abi: abi::Abi,
C
Corey Richardson 已提交
1082 1083 1084
}

impl Clean<Item> for doctree::Function {
1085
    fn clean(&self, cx: &DocContext) -> Item {
C
Corey Richardson 已提交
1086
        Item {
1087 1088 1089 1090 1091
            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),
1092
            def_id: ast_util::local_def(self.id),
C
Corey Richardson 已提交
1093
            inner: FunctionItem(Function {
1094 1095
                decl: self.decl.clean(cx),
                generics: self.generics.clean(cx),
N
Niko Matsakis 已提交
1096
                unsafety: self.unsafety,
1097
                constness: self.constness,
1098
                abi: self.abi,
C
Corey Richardson 已提交
1099 1100 1101 1102 1103
            }),
        }
    }
}

J
Jorge Aparicio 已提交
1104
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
C
Corey Richardson 已提交
1105
pub struct FnDecl {
1106
    pub inputs: Arguments,
1107
    pub output: FunctionRetTy,
1108 1109
    pub attrs: Vec<Attribute>,
}
C
Corey Richardson 已提交
1110

J
Jorge Aparicio 已提交
1111
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
1112
pub struct Arguments {
1113
    pub values: Vec<Argument>,
1114 1115
}

1116
impl Clean<FnDecl> for ast::FnDecl {
1117
    fn clean(&self, cx: &DocContext) -> FnDecl {
C
Corey Richardson 已提交
1118
        FnDecl {
1119
            inputs: Arguments {
1120
                values: self.inputs.clean(cx),
1121
            },
1122
            output: self.output.clean(cx),
1123
            attrs: Vec::new()
C
Corey Richardson 已提交
1124 1125 1126 1127
        }
    }
}

1128
impl<'tcx> Clean<Type> for ty::FnOutput<'tcx> {
J
Jakub Bukaj 已提交
1129 1130 1131 1132 1133 1134 1135 1136
    fn clean(&self, cx: &DocContext) -> Type {
        match *self {
            ty::FnConverging(ty) => ty.clean(cx),
            ty::FnDiverging => Bottom
        }
    }
}

1137
impl<'a, 'tcx> Clean<FnDecl> for (ast::DefId, &'a ty::PolyFnSig<'tcx>) {
1138
    fn clean(&self, cx: &DocContext) -> FnDecl {
1139 1140
        let (did, sig) = *self;
        let mut names = if did.node != 0 {
A
Aaron Turon 已提交
1141
            csearch::get_method_arg_names(&cx.tcx().sess.cstore, did).into_iter()
1142
        } else {
A
Aaron Turon 已提交
1143
            Vec::new().into_iter()
1144
        }.peekable();
1145
        if names.peek().map(|s| &**s) == Some("self") {
1146 1147
            let _ = names.next();
        }
1148
        FnDecl {
1149
            output: Return(sig.0.output.clean(cx)),
1150
            attrs: Vec::new(),
1151
            inputs: Arguments {
1152
                values: sig.0.inputs.iter().map(|t| {
1153
                    Argument {
1154
                        type_: t.clean(cx),
1155
                        id: 0,
1156
                        name: names.next().unwrap_or("".to_string()),
1157 1158 1159 1160 1161 1162 1163
                    }
                }).collect(),
            },
        }
    }
}

J
Jorge Aparicio 已提交
1164
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
C
Corey Richardson 已提交
1165
pub struct Argument {
1166
    pub type_: Type,
1167
    pub name: String,
1168
    pub id: ast::NodeId,
C
Corey Richardson 已提交
1169 1170
}

1171
impl Clean<Argument> for ast::Arg {
1172
    fn clean(&self, cx: &DocContext) -> Argument {
C
Corey Richardson 已提交
1173
        Argument {
1174
            name: name_from_pat(&*self.pat),
1175
            type_: (self.ty.clean(cx)),
C
Corey Richardson 已提交
1176 1177 1178 1179 1180
            id: self.id
        }
    }
}

J
Jorge Aparicio 已提交
1181
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
1182 1183
pub enum FunctionRetTy {
    Return(Type),
1184
    DefaultReturn,
1185
    NoReturn
C
Corey Richardson 已提交
1186 1187
}

1188 1189
impl Clean<FunctionRetTy> for ast::FunctionRetTy {
    fn clean(&self, cx: &DocContext) -> FunctionRetTy {
C
Corey Richardson 已提交
1190
        match *self {
1191
            ast::Return(ref typ) => Return(typ.clean(cx)),
1192 1193
            ast::DefaultReturn(..) => DefaultReturn,
            ast::NoReturn(..) => NoReturn
C
Corey Richardson 已提交
1194 1195 1196 1197
        }
    }
}

J
Jorge Aparicio 已提交
1198
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
1199
pub struct Trait {
1200
    pub unsafety: ast::Unsafety,
1201
    pub items: Vec<Item>,
1202
    pub generics: Generics,
1203
    pub bounds: Vec<TyParamBound>,
C
Corey Richardson 已提交
1204 1205 1206
}

impl Clean<Item> for doctree::Trait {
1207
    fn clean(&self, cx: &DocContext) -> Item {
C
Corey Richardson 已提交
1208
        Item {
1209 1210 1211
            name: Some(self.name.clean(cx)),
            attrs: self.attrs.clean(cx),
            source: self.whence.clean(cx),
1212
            def_id: ast_util::local_def(self.id),
1213 1214
            visibility: self.vis.clean(cx),
            stability: self.stab.clean(cx),
C
Corey Richardson 已提交
1215
            inner: TraitItem(Trait {
1216
                unsafety: self.unsafety,
1217 1218 1219
                items: self.items.clean(cx),
                generics: self.generics.clean(cx),
                bounds: self.bounds.clean(cx),
C
Corey Richardson 已提交
1220 1221 1222 1223 1224
            }),
        }
    }
}

1225
impl Clean<Type> for ast::TraitRef {
1226
    fn clean(&self, cx: &DocContext) -> Type {
N
Niko Matsakis 已提交
1227
        resolve_type(cx, self.path.clean(cx), self.ref_id)
C
Corey Richardson 已提交
1228 1229 1230
    }
}

1231 1232 1233 1234 1235 1236
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 已提交
1237 1238 1239
    }
}

1240 1241 1242
impl Clean<Item> for ast::TraitItem {
    fn clean(&self, cx: &DocContext) -> Item {
        let inner = match self.node {
1243 1244 1245 1246 1247
            ast::ConstTraitItem(ref ty, ref default) => {
                AssociatedConstItem(ty.clean(cx),
                                    default.as_ref().map(|expr|
                                                         expr.span.to_src(cx)))
            }
1248 1249 1250 1251 1252 1253
            ast::MethodTraitItem(ref sig, Some(_)) => {
                MethodItem(sig.clean(cx))
            }
            ast::MethodTraitItem(ref sig, None) => {
                TyMethodItem(sig.clean(cx))
            }
1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265
            ast::TypeTraitItem(ref bounds, ref default) => {
                AssociatedTypeItem(bounds.clean(cx), default.clean(cx))
            }
        };
        Item {
            name: Some(self.ident.clean(cx)),
            attrs: self.attrs.clean(cx),
            source: self.span.clean(cx),
            def_id: ast_util::local_def(self.id),
            visibility: None,
            stability: get_stability(cx, ast_util::local_def(self.id)),
            inner: inner
1266 1267 1268 1269
        }
    }
}

1270 1271 1272
impl Clean<Item> for ast::ImplItem {
    fn clean(&self, cx: &DocContext) -> Item {
        let inner = match self.node {
1273 1274 1275 1276 1277 1278
            ast::ConstImplItem(ref ty, ref expr) => {
                ConstantItem(Constant{
                    type_: ty.clean(cx),
                    expr: expr.span.to_src(cx),
                })
            }
1279 1280 1281
            ast::MethodImplItem(ref sig, _) => {
                MethodItem(sig.clean(cx))
            }
1282 1283 1284 1285 1286 1287 1288 1289
            ast::TypeImplItem(ref ty) => TypedefItem(Typedef {
                type_: ty.clean(cx),
                generics: Generics {
                    lifetimes: Vec::new(),
                    type_params: Vec::new(),
                    where_predicates: Vec::new()
                },
            }),
1290 1291 1292
            ast::MacImplItem(_) => {
                MacroItem(Macro {
                    source: self.span.to_src(cx),
1293
                    imported_from: None,
1294 1295
                })
            }
1296 1297 1298 1299 1300 1301 1302 1303 1304
        };
        Item {
            name: Some(self.ident.clean(cx)),
            source: self.span.clean(cx),
            attrs: self.attrs.clean(cx),
            def_id: ast_util::local_def(self.id),
            visibility: self.vis.clean(cx),
            stability: get_stability(cx, ast_util::local_def(self.id)),
            inner: inner
C
Corey Richardson 已提交
1305 1306 1307 1308
        }
    }
}

1309
impl<'tcx> Clean<Item> for ty::Method<'tcx> {
1310
    fn clean(&self, cx: &DocContext) -> Item {
1311
        let (self_, sig) = match self.explicit_self {
1312
            ty::StaticExplicitSelfCategory => (ast::SelfStatic.clean(cx),
A
Alex Crichton 已提交
1313
                                               self.fty.sig.clone()),
1314
            s => {
1315
                let sig = ty::Binder(ty::FnSig {
J
Jorge Aparicio 已提交
1316
                    inputs: self.fty.sig.0.inputs[1..].to_vec(),
1317 1318
                    ..self.fty.sig.0.clone()
                });
1319
                let s = match s {
A
Alex Crichton 已提交
1320
                    ty::ByValueExplicitSelfCategory => SelfValue,
1321
                    ty::ByReferenceExplicitSelfCategory(..) => {
1322
                        match self.fty.sig.0.inputs[0].sty {
1323
                            ty::ty_rptr(r, mt) => {
1324
                                SelfBorrowed(r.clean(cx), mt.mutbl.clean(cx))
1325
                            }
A
Alex Crichton 已提交
1326
                            _ => unreachable!(),
1327 1328
                        }
                    }
A
Alex Crichton 已提交
1329
                    ty::ByBoxExplicitSelfCategory => {
1330
                        SelfExplicit(self.fty.sig.0.inputs[0].clean(cx))
1331
                    }
A
Alex Crichton 已提交
1332
                    ty::StaticExplicitSelfCategory => unreachable!(),
1333 1334 1335 1336
                };
                (s, sig)
            }
        };
1337

1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354
        let generics = (&self.generics, &self.predicates,
                        subst::FnSpace).clean(cx);
        let decl = (self.def_id, &sig).clean(cx);
        let provided = match self.container {
            ty::ImplContainer(..) => false,
            ty::TraitContainer(did) => {
                ty::provided_trait_methods(cx.tcx(), did).iter().any(|m| {
                    m.def_id == self.def_id
                })
            }
        };
        let inner = if provided {
            MethodItem(Method {
                unsafety: self.fty.unsafety,
                generics: generics,
                self_: self_,
                decl: decl,
N
Niko Matsakis 已提交
1355 1356 1357 1358
                abi: self.fty.abi,

                // trait methods canot (currently, at least) be const
                constness: ast::Constness::NotConst,
1359 1360 1361 1362 1363 1364 1365
            })
        } else {
            TyMethodItem(TyMethod {
                unsafety: self.fty.unsafety,
                generics: generics,
                self_: self_,
                decl: decl,
N
Niko Matsakis 已提交
1366
                abi: self.fty.abi,
1367 1368 1369
            })
        };

1370
        Item {
1371
            name: Some(self.name.clean(cx)),
1372
            visibility: Some(ast::Inherited),
1373
            stability: get_stability(cx, self.def_id),
1374
            def_id: self.def_id,
1375
            attrs: inline::load_attrs(cx, cx.tcx(), self.def_id),
1376
            source: Span::empty(),
1377
            inner: inner,
1378
        }
1379 1380 1381
    }
}

1382
impl<'tcx> Clean<Item> for ty::ImplOrTraitItem<'tcx> {
1383
    fn clean(&self, cx: &DocContext) -> Item {
1384
        match *self {
1385
            ty::ConstTraitItem(ref cti) => cti.clean(cx),
1386
            ty::MethodTraitItem(ref mti) => mti.clean(cx),
1387
            ty::TypeTraitItem(ref tti) => tti.clean(cx),
1388 1389 1390 1391
        }
    }
}

1392
/// A trait reference, which may have higher ranked lifetimes.
J
Jorge Aparicio 已提交
1393
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
1394 1395 1396 1397 1398
pub struct PolyTrait {
    pub trait_: Type,
    pub lifetimes: Vec<Lifetime>
}

C
Corey Richardson 已提交
1399 1400 1401
/// 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 已提交
1402
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
C
Corey Richardson 已提交
1403
pub enum Type {
1404
    /// structs/enums/traits (anything that'd be an ast::TyPath)
1405
    ResolvedPath {
S
Steven Fackler 已提交
1406 1407 1408
        path: Path,
        typarams: Option<Vec<TyParamBound>>,
        did: ast::DefId,
1409
    },
1410 1411 1412
    /// For parameterized types, so the consumer of the JSON don't go
    /// looking for types which don't exist anywhere.
    Generic(String),
1413
    /// Primitives are the fixed-size numeric types (plus int/usize/float), char,
1414
    /// arrays, slices, and tuples.
1415
    Primitive(PrimitiveType),
C
Corey Richardson 已提交
1416
    /// extern "ABI" fn
1417
    BareFunction(Box<BareFunctionDecl>),
1418
    Tuple(Vec<Type>),
1419
    Vector(Box<Type>),
1420
    FixedVector(Box<Type>, String),
1421
    /// aka TyBot
C
Corey Richardson 已提交
1422
    Bottom,
1423 1424
    Unique(Box<Type>),
    RawPointer(Mutability, Box<Type>),
1425
    BorrowedRef {
S
Steven Fackler 已提交
1426 1427 1428
        lifetime: Option<Lifetime>,
        mutability: Mutability,
        type_: Box<Type>,
1429
    },
1430 1431

    // <Type as Trait>::Name
T
Tom Jakubowski 已提交
1432 1433 1434 1435 1436
    QPath {
        name: String,
        self_type: Box<Type>,
        trait_: Box<Type>
    },
1437 1438 1439 1440 1441 1442

    // _
    Infer,

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

J
Jorge Aparicio 已提交
1445
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Copy, Debug)]
1446
pub enum PrimitiveType {
1447 1448
    Isize, I8, I16, I32, I64,
    Usize, U8, U16, U32, U64,
1449
    F32, F64,
1450 1451 1452 1453
    Char,
    Bool,
    Str,
    Slice,
1454
    Array,
1455
    PrimitiveTuple,
1456
    PrimitiveRawPointer,
1457 1458
}

J
Jorge Aparicio 已提交
1459
#[derive(Clone, RustcEncodable, RustcDecodable, Copy, Debug)]
1460 1461 1462
pub enum TypeKind {
    TypeEnum,
    TypeFunction,
1463
    TypeModule,
1464
    TypeConst,
1465 1466 1467 1468
    TypeStatic,
    TypeStruct,
    TypeTrait,
    TypeVariant,
1469
    TypeTypedef,
1470 1471
}

1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486
impl Type {
    pub fn primitive_type(&self) -> Option<PrimitiveType> {
        match *self {
            Primitive(p) | BorrowedRef { type_: box Primitive(p), ..} => Some(p),
            Vector(..) | BorrowedRef{ type_: box Vector(..), ..  } => Some(Slice),
            FixedVector(..) | BorrowedRef { type_: box FixedVector(..), .. } => {
                Some(Array)
            }
            Tuple(..) => Some(PrimitiveTuple),
            RawPointer(..) => Some(PrimitiveRawPointer),
            _ => None,
        }
    }
}

1487 1488
impl PrimitiveType {
    fn from_str(s: &str) -> Option<PrimitiveType> {
1489
        match s {
1490
            "isize" => Some(Isize),
1491 1492 1493 1494
            "i8" => Some(I8),
            "i16" => Some(I16),
            "i32" => Some(I32),
            "i64" => Some(I64),
1495
            "usize" => Some(Usize),
1496 1497 1498 1499 1500 1501 1502 1503 1504
            "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),
1505
            "array" => Some(Array),
1506 1507
            "slice" => Some(Slice),
            "tuple" => Some(PrimitiveTuple),
1508
            "pointer" => Some(PrimitiveRawPointer),
1509 1510 1511 1512
            _ => None,
        }
    }

1513
    fn find(attrs: &[Attribute]) -> Option<PrimitiveType> {
1514
        for attr in attrs {
1515
            let list = match *attr {
1516
                List(ref k, ref l) if *k == "doc" => l,
1517 1518
                _ => continue,
            };
1519
            for sub_attr in list {
1520 1521
                let value = match *sub_attr {
                    NameValue(ref k, ref v)
1522
                        if *k == "primitive" => v,
1523 1524
                    _ => continue,
                };
1525
                match PrimitiveType::from_str(value) {
1526 1527 1528 1529 1530 1531 1532 1533
                    Some(p) => return Some(p),
                    None => {}
                }
            }
        }
        return None
    }

1534
    pub fn to_string(&self) -> &'static str {
1535
        match *self {
1536
            Isize => "isize",
1537 1538 1539 1540
            I8 => "i8",
            I16 => "i16",
            I32 => "i32",
            I64 => "i64",
1541
            Usize => "usize",
1542 1543 1544 1545 1546 1547 1548 1549 1550
            U8 => "u8",
            U16 => "u16",
            U32 => "u32",
            U64 => "u64",
            F32 => "f32",
            F64 => "f64",
            Str => "str",
            Bool => "bool",
            Char => "char",
1551
            Array => "array",
1552 1553
            Slice => "slice",
            PrimitiveTuple => "tuple",
1554
            PrimitiveRawPointer => "pointer",
1555 1556 1557 1558
        }
    }

    pub fn to_url_str(&self) -> &'static str {
1559
        self.to_string()
1560 1561 1562 1563 1564 1565 1566 1567 1568 1569
    }

    /// 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 已提交
1570
impl Clean<Type> for ast::Ty {
1571
    fn clean(&self, cx: &DocContext) -> Type {
C
Corey Richardson 已提交
1572
        use syntax::ast::*;
1573
        match self.node {
1574
            TyPtr(ref m) => RawPointer(m.mutbl.clean(cx), box m.ty.clean(cx)),
1575
            TyRptr(ref l, ref m) =>
1576 1577
                BorrowedRef {lifetime: l.clean(cx), mutability: m.mutbl.clean(cx),
                             type_: box m.ty.clean(cx)},
1578 1579 1580
            TyVec(ref ty) => Vector(box ty.clean(cx)),
            TyFixedLengthVec(ref ty, ref e) => FixedVector(box ty.clean(cx),
                                                           e.span.to_src(cx)),
1581
            TyTup(ref tys) => Tuple(tys.clean(cx)),
1582
            TyPath(None, ref p) => {
1583
                resolve_type(cx, p.clean(cx), self.id)
N
Niko Matsakis 已提交
1584
            }
1585 1586
            TyPath(Some(ref qself), ref p) => {
                let mut trait_path = p.clone();
1587
                trait_path.segments.pop();
1588
                Type::QPath {
1589 1590
                    name: p.segments.last().unwrap().identifier.clean(cx),
                    self_type: box qself.ty.clean(cx),
1591
                    trait_: box resolve_type(cx, trait_path.clean(cx), self.id)
1592 1593
                }
            }
N
Niko Matsakis 已提交
1594 1595 1596 1597 1598 1599 1600 1601 1602 1603
            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
                    }
                }
1604
            }
1605 1606
            TyBareFn(ref barefn) => BareFunction(box barefn.clean(cx)),
            TyParen(ref ty) => ty.clean(cx),
1607 1608 1609 1610 1611 1612 1613
            TyPolyTraitRef(ref bounds) => {
                PolyTraitRef(bounds.clean(cx))
            },
            TyInfer(..) => {
                Infer
            },
            TyTypeof(..) => {
1614
                panic!("Unimplemented type {:?}", self.node)
1615
            },
1616
        }
C
Corey Richardson 已提交
1617 1618 1619
    }
}

1620
impl<'tcx> Clean<Type> for ty::Ty<'tcx> {
1621
    fn clean(&self, cx: &DocContext) -> Type {
1622
        match self.sty {
1623 1624
            ty::ty_bool => Primitive(Bool),
            ty::ty_char => Primitive(Char),
1625
            ty::ty_int(ast::TyIs) => Primitive(Isize),
1626 1627 1628 1629
            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),
1630
            ty::ty_uint(ast::TyUs) => Primitive(Usize),
1631 1632 1633 1634 1635 1636 1637
            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 已提交
1638
            ty::ty_uniq(t) => {
1639
                let box_did = cx.tcx_opt().and_then(|tcx| {
A
Alex Crichton 已提交
1640 1641
                    tcx.lang_items.owned_box()
                });
1642
                lang_struct(cx, box_did, t, "Box", Unique)
A
Alex Crichton 已提交
1643
            }
1644 1645
            ty::ty_vec(ty, None) => Vector(box ty.clean(cx)),
            ty::ty_vec(ty, Some(i)) => FixedVector(box ty.clean(cx),
A
Alex Crichton 已提交
1646
                                                   format!("{}", i)),
1647
            ty::ty_ptr(mt) => RawPointer(mt.mutbl.clean(cx), box mt.ty.clean(cx)),
1648
            ty::ty_rptr(r, mt) => BorrowedRef {
1649 1650 1651
                lifetime: r.clean(cx),
                mutability: mt.mutbl.clean(cx),
                type_: box mt.ty.clean(cx),
1652
            },
1653
            ty::ty_bare_fn(_, ref fty) => BareFunction(box BareFunctionDecl {
N
Niko Matsakis 已提交
1654
                unsafety: fty.unsafety,
1655
                generics: Generics {
1656 1657 1658
                    lifetimes: Vec::new(),
                    type_params: Vec::new(),
                    where_predicates: Vec::new()
1659
                },
1660
                decl: (ast_util::local_def(0), &fty.sig).clean(cx),
1661
                abi: fty.abi.to_string(),
1662
            }),
H
Huon Wilson 已提交
1663
            ty::ty_struct(did, substs) |
1664
            ty::ty_enum(did, substs) => {
1665
                let fqn = csearch::get_item_path(cx.tcx(), did);
1666
                let fqn: Vec<_> = fqn.into_iter().map(|i| i.to_string()).collect();
1667
                let kind = match self.sty {
1668 1669 1670
                    ty::ty_struct(..) => TypeStruct,
                    _ => TypeEnum,
                };
1671
                let path = external_path(cx, &fqn.last().unwrap().to_string(),
1672
                                         None, vec![], substs);
1673
                cx.external_paths.borrow_mut().as_mut().unwrap().insert(did, (fqn, kind));
1674
                ResolvedPath {
1675
                    path: path,
1676 1677 1678 1679
                    typarams: None,
                    did: did,
                }
            }
1680 1681 1682 1683
            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();
1684
                let (typarams, bindings) = bounds.clean(cx);
1685
                let path = external_path(cx, &fqn.last().unwrap().to_string(),
1686
                                         Some(did), bindings, principal.substs());
1687 1688 1689
                cx.external_paths.borrow_mut().as_mut().unwrap().insert(did, (fqn, TypeTrait));
                ResolvedPath {
                    path: path,
1690
                    typarams: Some(typarams),
1691 1692 1693
                    did: did,
                }
            }
1694
            ty::ty_tup(ref t) => Tuple(t.clean(cx)),
1695

1696
            ty::ty_projection(ref data) => data.clean(cx),
1697

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

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

S
Steve Klabnik 已提交
1702 1703
            ty::ty_infer(..) => panic!("ty_infer"),
            ty::ty_err => panic!("ty_err"),
1704 1705 1706 1707
        }
    }
}

J
Jorge Aparicio 已提交
1708
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
1709
pub enum StructField {
1710
    HiddenStructField, // inserted later by strip passes
1711
    TypedStructField(Type),
C
Corey Richardson 已提交
1712 1713
}

1714
impl Clean<Item> for ast::StructField {
1715
    fn clean(&self, cx: &DocContext) -> Item {
C
Corey Richardson 已提交
1716
        let (name, vis) = match self.node.kind {
1717 1718
            ast::NamedField(id, vis) => (Some(id), vis),
            ast::UnnamedField(vis) => (None, vis)
C
Corey Richardson 已提交
1719 1720
        };
        Item {
1721 1722 1723
            name: name.clean(cx),
            attrs: self.node.attrs.clean(cx),
            source: self.span.clean(cx),
1724
            visibility: Some(vis),
1725
            stability: get_stability(cx, ast_util::local_def(self.node.id)),
1726
            def_id: ast_util::local_def(self.node.id),
1727
            inner: StructFieldItem(TypedStructField(self.node.ty.clean(cx))),
C
Corey Richardson 已提交
1728 1729 1730 1731
        }
    }
}

1732
impl Clean<Item> for ty::field_ty {
1733
    fn clean(&self, cx: &DocContext) -> Item {
1734
        use syntax::parse::token::special_idents::unnamed_field;
1735 1736 1737 1738
        use rustc::metadata::csearch;

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

1739 1740
        let (name, attrs) = if self.name == unnamed_field.name {
            (None, None)
1741
        } else {
1742
            (Some(self.name), Some(attr_map.get(&self.id.node).unwrap()))
1743
        };
1744

1745
        let ty = ty::lookup_item_type(cx.tcx(), self.id);
1746

1747
        Item {
1748 1749
            name: name.clean(cx),
            attrs: attrs.unwrap_or(&Vec::new()).clean(cx),
1750 1751
            source: Span::empty(),
            visibility: Some(self.vis),
1752
            stability: get_stability(cx, self.id),
1753
            def_id: self.id,
1754
            inner: StructFieldItem(TypedStructField(ty.ty.clean(cx))),
1755 1756 1757 1758
        }
    }
}

1759
pub type Visibility = ast::Visibility;
C
Corey Richardson 已提交
1760

1761
impl Clean<Option<Visibility>> for ast::Visibility {
1762
    fn clean(&self, _: &DocContext) -> Option<Visibility> {
C
Corey Richardson 已提交
1763 1764 1765 1766
        Some(*self)
    }
}

J
Jorge Aparicio 已提交
1767
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
1768
pub struct Struct {
1769 1770 1771 1772
    pub struct_type: doctree::StructType,
    pub generics: Generics,
    pub fields: Vec<Item>,
    pub fields_stripped: bool,
C
Corey Richardson 已提交
1773 1774 1775
}

impl Clean<Item> for doctree::Struct {
1776
    fn clean(&self, cx: &DocContext) -> Item {
C
Corey Richardson 已提交
1777
        Item {
1778 1779 1780
            name: Some(self.name.clean(cx)),
            attrs: self.attrs.clean(cx),
            source: self.whence.clean(cx),
1781
            def_id: ast_util::local_def(self.id),
1782 1783
            visibility: self.vis.clean(cx),
            stability: self.stab.clean(cx),
C
Corey Richardson 已提交
1784 1785
            inner: StructItem(Struct {
                struct_type: self.struct_type,
1786 1787
                generics: self.generics.clean(cx),
                fields: self.fields.clean(cx),
S
Steven Fackler 已提交
1788
                fields_stripped: false,
C
Corey Richardson 已提交
1789 1790 1791 1792 1793
            }),
        }
    }
}

1794
/// This is a more limited form of the standard Struct, different in that
C
Corey Richardson 已提交
1795 1796
/// it lacks the things most items have (name, id, parameterization). Found
/// only as a variant in an enum.
J
Jorge Aparicio 已提交
1797
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
1798
pub struct VariantStruct {
1799 1800 1801
    pub struct_type: doctree::StructType,
    pub fields: Vec<Item>,
    pub fields_stripped: bool,
C
Corey Richardson 已提交
1802 1803
}

1804
impl Clean<VariantStruct> for syntax::ast::StructDef {
1805
    fn clean(&self, cx: &DocContext) -> VariantStruct {
C
Corey Richardson 已提交
1806 1807
        VariantStruct {
            struct_type: doctree::struct_type_from_def(self),
1808
            fields: self.fields.clean(cx),
S
Steven Fackler 已提交
1809
            fields_stripped: false,
C
Corey Richardson 已提交
1810 1811 1812 1813
        }
    }
}

J
Jorge Aparicio 已提交
1814
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
1815
pub struct Enum {
1816 1817 1818
    pub variants: Vec<Item>,
    pub generics: Generics,
    pub variants_stripped: bool,
C
Corey Richardson 已提交
1819 1820 1821
}

impl Clean<Item> for doctree::Enum {
1822
    fn clean(&self, cx: &DocContext) -> Item {
C
Corey Richardson 已提交
1823
        Item {
1824 1825 1826
            name: Some(self.name.clean(cx)),
            attrs: self.attrs.clean(cx),
            source: self.whence.clean(cx),
1827
            def_id: ast_util::local_def(self.id),
1828 1829
            visibility: self.vis.clean(cx),
            stability: self.stab.clean(cx),
C
Corey Richardson 已提交
1830
            inner: EnumItem(Enum {
1831 1832
                variants: self.variants.clean(cx),
                generics: self.generics.clean(cx),
S
Steven Fackler 已提交
1833
                variants_stripped: false,
C
Corey Richardson 已提交
1834 1835 1836 1837 1838
            }),
        }
    }
}

J
Jorge Aparicio 已提交
1839
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
1840
pub struct Variant {
1841
    pub kind: VariantKind,
C
Corey Richardson 已提交
1842 1843 1844
}

impl Clean<Item> for doctree::Variant {
1845
    fn clean(&self, cx: &DocContext) -> Item {
C
Corey Richardson 已提交
1846
        Item {
1847 1848 1849 1850 1851
            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),
1852
            def_id: ast_util::local_def(self.id),
C
Corey Richardson 已提交
1853
            inner: VariantItem(Variant {
1854
                kind: self.kind.clean(cx),
C
Corey Richardson 已提交
1855 1856 1857 1858 1859
            }),
        }
    }
}

1860
impl<'tcx> Clean<Item> for ty::VariantInfo<'tcx> {
1861
    fn clean(&self, cx: &DocContext) -> Item {
1862
        // use syntax::parse::token::special_idents::unnamed_field;
1863
        let kind = match self.arg_names.as_ref().map(|s| &**s) {
1864
            None | Some([]) if self.args.is_empty() => CLikeVariant,
1865
            None | Some([]) => {
1866
                TupleVariant(self.args.clean(cx))
1867 1868 1869 1870 1871 1872 1873 1874
            }
            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(),
1875
                            name: Some(name.clean(cx)),
1876 1877
                            attrs: Vec::new(),
                            visibility: Some(ast::Public),
1878 1879
                            // FIXME: this is not accurate, we need an id for
                            //        the specific field but we're using the id
A
Aaron Turon 已提交
1880 1881 1882 1883 1884
                            //        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.
1885
                            def_id: self.id,
1886
                            stability: get_stability(cx, self.id),
1887
                            inner: StructFieldItem(
1888
                                TypedStructField(ty.clean(cx))
1889 1890 1891 1892 1893 1894 1895
                            )
                        }
                    }).collect()
                })
            }
        };
        Item {
1896 1897
            name: Some(self.name.clean(cx)),
            attrs: inline::load_attrs(cx, cx.tcx(), self.id),
1898 1899 1900 1901
            source: Span::empty(),
            visibility: Some(ast::Public),
            def_id: self.id,
            inner: VariantItem(Variant { kind: kind }),
1902
            stability: get_stability(cx, self.id),
1903 1904 1905 1906
        }
    }
}

J
Jorge Aparicio 已提交
1907
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
1908 1909
pub enum VariantKind {
    CLikeVariant,
1910
    TupleVariant(Vec<Type>),
C
Corey Richardson 已提交
1911 1912 1913
    StructVariant(VariantStruct),
}

1914
impl Clean<VariantKind> for ast::VariantKind {
1915
    fn clean(&self, cx: &DocContext) -> VariantKind {
C
Corey Richardson 已提交
1916
        match self {
1917
            &ast::TupleVariantKind(ref args) => {
1918
                if args.is_empty() {
C
Corey Richardson 已提交
1919 1920
                    CLikeVariant
                } else {
1921
                    TupleVariant(args.iter().map(|x| x.ty.clean(cx)).collect())
C
Corey Richardson 已提交
1922 1923
                }
            },
1924
            &ast::StructVariantKind(ref sd) => StructVariant(sd.clean(cx)),
C
Corey Richardson 已提交
1925 1926 1927 1928
        }
    }
}

J
Jorge Aparicio 已提交
1929
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
1930
pub struct Span {
1931
    pub filename: String,
1932 1933 1934 1935
    pub loline: usize,
    pub locol: usize,
    pub hiline: usize,
    pub hicol: usize,
1936 1937
}

1938 1939 1940
impl Span {
    fn empty() -> Span {
        Span {
1941
            filename: "".to_string(),
1942 1943 1944 1945 1946 1947
            loline: 0, locol: 0,
            hiline: 0, hicol: 0,
        }
    }
}

1948
impl Clean<Span> for syntax::codemap::Span {
1949 1950
    fn clean(&self, cx: &DocContext) -> Span {
        let cm = cx.sess().codemap();
1951 1952 1953 1954
        let filename = cm.span_to_filename(*self);
        let lo = cm.lookup_char_pos(self.lo);
        let hi = cm.lookup_char_pos(self.hi);
        Span {
1955
            filename: filename.to_string(),
1956
            loline: lo.line,
1957
            locol: lo.col.to_usize(),
1958
            hiline: hi.line,
1959
            hicol: hi.col.to_usize(),
1960
        }
C
Corey Richardson 已提交
1961 1962 1963
    }
}

J
Jorge Aparicio 已提交
1964
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
C
Corey Richardson 已提交
1965
pub struct Path {
1966 1967
    pub global: bool,
    pub segments: Vec<PathSegment>,
C
Corey Richardson 已提交
1968 1969
}

1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985
impl Path {
    pub fn singleton(name: String) -> Path {
        Path {
            global: false,
            segments: vec![PathSegment {
                name: name,
                params: PathParameters::AngleBracketed {
                    lifetimes: Vec::new(),
                    types: Vec::new(),
                    bindings: Vec::new()
                }
            }]
        }
    }
}

C
Corey Richardson 已提交
1986
impl Clean<Path> for ast::Path {
1987
    fn clean(&self, cx: &DocContext) -> Path {
C
Corey Richardson 已提交
1988
        Path {
1989
            global: self.global,
1990
            segments: self.segments.clean(cx),
1991 1992 1993 1994
        }
    }
}

J
Jorge Aparicio 已提交
1995
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
1996 1997 1998 1999
pub enum PathParameters {
    AngleBracketed {
        lifetimes: Vec<Lifetime>,
        types: Vec<Type>,
2000
        bindings: Vec<TypeBinding>
2001 2002 2003 2004 2005
    },
    Parenthesized {
        inputs: Vec<Type>,
        output: Option<Type>
    }
2006 2007
}

2008 2009 2010
impl Clean<PathParameters> for ast::PathParameters {
    fn clean(&self, cx: &DocContext) -> PathParameters {
        match *self {
2011
            ast::AngleBracketedParameters(ref data) => {
2012 2013
                PathParameters::AngleBracketed {
                    lifetimes: data.lifetimes.clean(cx),
2014 2015
                    types: data.types.clean(cx),
                    bindings: data.bindings.clean(cx)
2016
                }
2017 2018 2019
            }

            ast::ParenthesizedParameters(ref data) => {
2020 2021 2022 2023
                PathParameters::Parenthesized {
                    inputs: data.inputs.clean(cx),
                    output: data.output.clean(cx)
                }
2024
            }
2025 2026 2027
        }
    }
}
2028

J
Jorge Aparicio 已提交
2029
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
2030 2031 2032 2033 2034 2035 2036
pub struct PathSegment {
    pub name: String,
    pub params: PathParameters
}

impl Clean<PathSegment> for ast::PathSegment {
    fn clean(&self, cx: &DocContext) -> PathSegment {
2037
        PathSegment {
2038
            name: self.identifier.clean(cx),
2039
            params: self.parameters.clean(cx)
C
Corey Richardson 已提交
2040 2041 2042 2043
        }
    }
}

2044
fn path_to_string(p: &ast::Path) -> String {
2045
    let mut s = String::new();
C
Corey Richardson 已提交
2046
    let mut first = true;
2047
    for i in p.segments.iter().map(|x| token::get_ident(x.identifier)) {
C
Corey Richardson 已提交
2048 2049 2050 2051 2052
        if !first || p.global {
            s.push_str("::");
        } else {
            first = false;
        }
G
GuillaumeGomez 已提交
2053
        s.push_str(&i);
C
Corey Richardson 已提交
2054
    }
2055
    s
C
Corey Richardson 已提交
2056 2057
}

2058
impl Clean<String> for ast::Ident {
2059
    fn clean(&self, _: &DocContext) -> String {
G
GuillaumeGomez 已提交
2060
        token::get_ident(*self).to_string()
C
Corey Richardson 已提交
2061 2062 2063
    }
}

2064
impl Clean<String> for ast::Name {
2065
    fn clean(&self, _: &DocContext) -> String {
G
GuillaumeGomez 已提交
2066
        token::get_name(*self).to_string()
2067 2068 2069
    }
}

J
Jorge Aparicio 已提交
2070
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
2071
pub struct Typedef {
2072 2073
    pub type_: Type,
    pub generics: Generics,
C
Corey Richardson 已提交
2074 2075 2076
}

impl Clean<Item> for doctree::Typedef {
2077
    fn clean(&self, cx: &DocContext) -> Item {
C
Corey Richardson 已提交
2078
        Item {
2079 2080 2081
            name: Some(self.name.clean(cx)),
            attrs: self.attrs.clean(cx),
            source: self.whence.clean(cx),
2082
            def_id: ast_util::local_def(self.id.clone()),
2083 2084
            visibility: self.vis.clean(cx),
            stability: self.stab.clean(cx),
C
Corey Richardson 已提交
2085
            inner: TypedefItem(Typedef {
2086 2087
                type_: self.ty.clean(cx),
                generics: self.gen.clean(cx),
C
Corey Richardson 已提交
2088 2089 2090 2091 2092
            }),
        }
    }
}

J
Jorge Aparicio 已提交
2093
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
C
Corey Richardson 已提交
2094
pub struct BareFunctionDecl {
N
Niko Matsakis 已提交
2095
    pub unsafety: ast::Unsafety,
2096 2097
    pub generics: Generics,
    pub decl: FnDecl,
2098
    pub abi: String,
C
Corey Richardson 已提交
2099 2100
}

2101
impl Clean<BareFunctionDecl> for ast::BareFnTy {
2102
    fn clean(&self, cx: &DocContext) -> BareFunctionDecl {
C
Corey Richardson 已提交
2103
        BareFunctionDecl {
N
Niko Matsakis 已提交
2104
            unsafety: self.unsafety,
C
Corey Richardson 已提交
2105
            generics: Generics {
2106
                lifetimes: self.lifetimes.clean(cx),
2107
                type_params: Vec::new(),
2108
                where_predicates: Vec::new()
C
Corey Richardson 已提交
2109
            },
2110
            decl: self.decl.clean(cx),
2111
            abi: self.abi.to_string(),
C
Corey Richardson 已提交
2112 2113 2114 2115
        }
    }
}

J
Jorge Aparicio 已提交
2116
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
2117
pub struct Static {
2118 2119
    pub type_: Type,
    pub mutability: Mutability,
C
Corey Richardson 已提交
2120 2121 2122
    /// 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.
2123
    pub expr: String,
C
Corey Richardson 已提交
2124 2125 2126
}

impl Clean<Item> for doctree::Static {
2127
    fn clean(&self, cx: &DocContext) -> Item {
2128
        debug!("cleaning static {}: {:?}", self.name.clean(cx), self);
C
Corey Richardson 已提交
2129
        Item {
2130 2131 2132
            name: Some(self.name.clean(cx)),
            attrs: self.attrs.clean(cx),
            source: self.whence.clean(cx),
2133
            def_id: ast_util::local_def(self.id),
2134 2135
            visibility: self.vis.clean(cx),
            stability: self.stab.clean(cx),
C
Corey Richardson 已提交
2136
            inner: StaticItem(Static {
2137 2138 2139
                type_: self.type_.clean(cx),
                mutability: self.mutability.clean(cx),
                expr: self.expr.span.to_src(cx),
C
Corey Richardson 已提交
2140 2141 2142 2143 2144
            }),
        }
    }
}

J
Jorge Aparicio 已提交
2145
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167
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 已提交
2168
#[derive(Debug, Clone, RustcEncodable, RustcDecodable, PartialEq, Copy)]
C
Corey Richardson 已提交
2169 2170 2171 2172 2173
pub enum Mutability {
    Mutable,
    Immutable,
}

2174
impl Clean<Mutability> for ast::Mutability {
2175
    fn clean(&self, _: &DocContext) -> Mutability {
C
Corey Richardson 已提交
2176
        match self {
2177 2178
            &ast::MutMutable => Mutable,
            &ast::MutImmutable => Immutable,
C
Corey Richardson 已提交
2179 2180 2181 2182
        }
    }
}

J
Jorge Aparicio 已提交
2183
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Copy, Debug)]
2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197
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 已提交
2198
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
2199
pub struct Impl {
2200
    pub unsafety: ast::Unsafety,
2201 2202 2203
    pub generics: Generics,
    pub trait_: Option<Type>,
    pub for_: Type,
2204
    pub items: Vec<Item>,
2205
    pub derived: bool,
2206
    pub polarity: Option<ImplPolarity>,
C
Corey Richardson 已提交
2207 2208
}

2209
fn detect_derived<M: AttrMetaMethods>(attrs: &[M]) -> bool {
2210
    attr::contains_name(attrs, "automatically_derived")
2211 2212
}

2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227
impl Clean<Vec<Item>> for doctree::Impl {
    fn clean(&self, cx: &DocContext) -> Vec<Item> {
        let mut ret = Vec::new();
        let trait_ = self.trait_.clean(cx);
        let items = self.items.clean(cx);

        // If this impl block is an implementation of the Deref trait, then we
        // need to try inlining the target's inherent impl blocks as well.
        if let Some(ResolvedPath { did, .. }) = trait_ {
            if Some(did) == cx.deref_trait_did.get() {
                build_deref_target_impls(cx, &items, &mut ret);
            }
        }

        ret.push(Item {
C
Corey Richardson 已提交
2228
            name: None,
2229 2230
            attrs: self.attrs.clean(cx),
            source: self.whence.clean(cx),
2231
            def_id: ast_util::local_def(self.id),
2232 2233
            visibility: self.vis.clean(cx),
            stability: self.stab.clean(cx),
C
Corey Richardson 已提交
2234
            inner: ImplItem(Impl {
2235
                unsafety: self.unsafety,
2236
                generics: self.generics.clean(cx),
2237
                trait_: trait_,
2238
                for_: self.for_.clean(cx),
2239
                items: items,
2240
                derived: detect_derived(&self.attrs),
2241
                polarity: Some(self.polarity.clean(cx)),
C
Corey Richardson 已提交
2242
            }),
2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296
        });
        return ret;
    }
}

fn build_deref_target_impls(cx: &DocContext,
                            items: &[Item],
                            ret: &mut Vec<Item>) {
    let tcx = match cx.tcx_opt() {
        Some(t) => t,
        None => return,
    };

    for item in items {
        let target = match item.inner {
            TypedefItem(ref t) => &t.type_,
            _ => continue,
        };
        let primitive = match *target {
            ResolvedPath { did, .. } if ast_util::is_local(did) => continue,
            ResolvedPath { did, .. } => {
                ret.extend(inline::build_impls(cx, tcx, did));
                continue
            }
            _ => match target.primitive_type() {
                Some(prim) => prim,
                None => continue,
            }
        };
        let did = match primitive {
            Isize => tcx.lang_items.isize_impl(),
            I8 => tcx.lang_items.i8_impl(),
            I16 => tcx.lang_items.i16_impl(),
            I32 => tcx.lang_items.i32_impl(),
            I64 => tcx.lang_items.i64_impl(),
            Usize => tcx.lang_items.usize_impl(),
            U8 => tcx.lang_items.u8_impl(),
            U16 => tcx.lang_items.u16_impl(),
            U32 => tcx.lang_items.u32_impl(),
            U64 => tcx.lang_items.u64_impl(),
            F32 => tcx.lang_items.f32_impl(),
            F64 => tcx.lang_items.f64_impl(),
            Char => tcx.lang_items.char_impl(),
            Bool => None,
            Str => tcx.lang_items.str_impl(),
            Slice => tcx.lang_items.slice_impl(),
            Array => tcx.lang_items.slice_impl(),
            PrimitiveTuple => None,
            PrimitiveRawPointer => tcx.lang_items.const_ptr_impl(),
        };
        if let Some(did) = did {
            if !ast_util::is_local(did) {
                inline::build_impl(cx, tcx, did, ret);
            }
C
Corey Richardson 已提交
2297 2298 2299 2300
        }
    }
}

2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
pub struct DefaultImpl {
    pub unsafety: ast::Unsafety,
    pub trait_: Type,
}

impl Clean<Item> for doctree::DefaultImpl {
    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(self.id),
            visibility: Some(ast::Public),
            stability: None,
            inner: DefaultImplItem(DefaultImpl {
                unsafety: self.unsafety,
                trait_: self.trait_.clean(cx),
            }),
        }
    }
}

2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335
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 已提交
2336 2337
}

2338
impl Clean<Vec<Item>> for doctree::Import {
2339
    fn clean(&self, cx: &DocContext) -> Vec<Item> {
J
Joseph Crail 已提交
2340
        // We consider inlining the documentation of `pub use` statements, but we
2341 2342
        // forcefully don't inline if this is not public or if the
        // #[doc(no_inline)] attribute is present.
2343
        let denied = self.vis != ast::Public || self.attrs.iter().any(|a| {
2344
            &a.name()[..] == "doc" && match a.meta_item_list() {
2345
                Some(l) => attr::contains_name(l, "no_inline"),
2346 2347 2348
                None => false,
            }
        });
2349 2350 2351
        let (mut ret, inner) = match self.node {
            ast::ViewPathGlob(ref p) => {
                (vec![], GlobImport(resolve_use_source(cx, p.clean(cx), self.id)))
2352
            }
2353 2354 2355 2356 2357 2358 2359
            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![];
2360
                    for path in list {
2361 2362 2363 2364 2365 2366
                        match inline::try_inline(cx, path.node.id(), None) {
                            Some(items) => {
                                ret.extend(items.into_iter());
                            }
                            None => {
                                remaining.push(path.clean(cx));
2367 2368 2369
                            }
                        }
                    }
2370 2371 2372
                    remaining
                } else {
                    list.clean(cx)
P
Patrick Walton 已提交
2373
                };
2374 2375 2376 2377 2378
                if remaining.is_empty() {
                    return ret;
                }
                (ret, ImportList(resolve_use_source(cx, p.clean(cx), self.id),
                                 remaining))
P
Patrick Walton 已提交
2379
            }
2380 2381 2382 2383 2384 2385 2386 2387 2388
            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)))
2389
            }
2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400
        };
        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 已提交
2401 2402 2403
    }
}

J
Jorge Aparicio 已提交
2404
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
2405
pub enum Import {
2406
    // use source as str;
2407
    SimpleImport(String, ImportSource),
A
Alex Crichton 已提交
2408 2409 2410
    // use source::*;
    GlobImport(ImportSource),
    // use source::{a, b, c};
2411
    ImportList(ImportSource, Vec<ViewListIdent>),
A
Alex Crichton 已提交
2412 2413
}

J
Jorge Aparicio 已提交
2414
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
A
Alex Crichton 已提交
2415
pub struct ImportSource {
2416 2417
    pub path: Path,
    pub did: Option<ast::DefId>,
C
Corey Richardson 已提交
2418 2419
}

J
Jorge Aparicio 已提交
2420
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
A
Alex Crichton 已提交
2421
pub struct ViewListIdent {
2422
    pub name: String,
2423
    pub source: Option<ast::DefId>,
A
Alex Crichton 已提交
2424
}
C
Corey Richardson 已提交
2425

J
Jakub Wieczorek 已提交
2426
impl Clean<ViewListIdent> for ast::PathListItem {
2427
    fn clean(&self, cx: &DocContext) -> ViewListIdent {
J
Jakub Wieczorek 已提交
2428 2429
        match self.node {
            ast::PathListIdent { id, name } => ViewListIdent {
2430 2431
                name: name.clean(cx),
                source: resolve_def(cx, id)
J
Jakub Wieczorek 已提交
2432 2433
            },
            ast::PathListMod { id } => ViewListIdent {
2434
                name: "self".to_string(),
2435
                source: resolve_def(cx, id)
J
Jakub Wieczorek 已提交
2436
            }
A
Alex Crichton 已提交
2437
        }
C
Corey Richardson 已提交
2438 2439 2440
    }
}

2441
impl Clean<Vec<Item>> for ast::ForeignMod {
2442
    fn clean(&self, cx: &DocContext) -> Vec<Item> {
2443 2444 2445 2446 2447 2448 2449 2450
        let mut items = self.items.clean(cx);
        for item in &mut items {
            match item.inner {
                ForeignFunctionItem(ref mut f) => f.abi = self.abi,
                _ => {}
            }
        }
        items
2451 2452 2453
    }
}

2454
impl Clean<Item> for ast::ForeignItem {
2455
    fn clean(&self, cx: &DocContext) -> Item {
2456
        let inner = match self.node {
2457
            ast::ForeignItemFn(ref decl, ref generics) => {
2458
                ForeignFunctionItem(Function {
2459 2460
                    decl: decl.clean(cx),
                    generics: generics.clean(cx),
N
Niko Matsakis 已提交
2461
                    unsafety: ast::Unsafety::Unsafe,
2462
                    abi: abi::Rust,
2463
                    constness: ast::Constness::NotConst,
2464 2465
                })
            }
2466
            ast::ForeignItemStatic(ref ty, mutbl) => {
2467
                ForeignStaticItem(Static {
2468
                    type_: ty.clean(cx),
2469
                    mutability: if mutbl {Mutable} else {Immutable},
2470
                    expr: "".to_string(),
2471 2472 2473 2474
                })
            }
        };
        Item {
2475 2476 2477
            name: Some(self.ident.clean(cx)),
            attrs: self.attrs.clean(cx),
            source: self.span.clean(cx),
2478
            def_id: ast_util::local_def(self.id),
2479 2480
            visibility: self.vis.clean(cx),
            stability: get_stability(cx, ast_util::local_def(self.id)),
2481 2482 2483 2484 2485
            inner: inner,
        }
    }
}

C
Corey Richardson 已提交
2486 2487 2488
// Utilities

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

2492
impl ToSource for syntax::codemap::Span {
2493
    fn to_src(&self, cx: &DocContext) -> String {
2494
        debug!("converting span {:?} to snippet", self.clean(cx));
2495
        let sn = match cx.sess().codemap().span_to_snippet(*self) {
2496 2497
            Ok(x) => x.to_string(),
            Err(_) => "".to_string()
C
Corey Richardson 已提交
2498
        };
2499
        debug!("got snippet {}", sn);
C
Corey Richardson 已提交
2500 2501 2502 2503
        sn
    }
}

2504
fn lit_to_string(lit: &ast::Lit) -> String {
C
Corey Richardson 已提交
2505
    match lit.node {
G
GuillaumeGomez 已提交
2506
        ast::LitStr(ref st, _) => st.to_string(),
2507
        ast::LitBinary(ref data) => format!("{:?}", data),
2508 2509
        ast::LitByte(b) => {
            let mut res = String::from_str("b'");
2510
            for c in (b as char).escape_default() {
2511
                res.push(c);
2512
            }
2513
            res.push('\'');
2514 2515
            res
        },
A
Alex Crichton 已提交
2516
        ast::LitChar(c) => format!("'{}'", c),
2517
        ast::LitInt(i, _t) => i.to_string(),
G
GuillaumeGomez 已提交
2518 2519
        ast::LitFloat(ref f, _t) => f.to_string(),
        ast::LitFloatUnsuffixed(ref f) => f.to_string(),
2520
        ast::LitBool(b) => b.to_string(),
C
Corey Richardson 已提交
2521 2522 2523
    }
}

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

C
Corey Richardson 已提交
2528
    match p.node {
2529 2530
        PatWild(PatWildSingle) => "_".to_string(),
        PatWild(PatWildMulti) => "..".to_string(),
G
GuillaumeGomez 已提交
2531
        PatIdent(_, ref p, _) => token::get_ident(p.node).to_string(),
2532
        PatEnum(ref p, _) => path_to_string(p),
2533 2534
        PatQPath(..) => panic!("tried to get argument name from PatQPath, \
                                which is not allowed in function arguments"),
2535 2536
        PatStruct(ref name, ref fields, etc) => {
            format!("{} {{ {}{} }}", path_to_string(name),
2537
                fields.iter().map(|&Spanned { node: ref fp, .. }|
2538 2539 2540 2541 2542 2543 2544
                                  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(", ")),
2545
        PatBox(ref p) => name_from_pat(&**p),
2546
        PatRegion(ref p, _) => name_from_pat(&**p),
2547 2548 2549
        PatLit(..) => {
            warn!("tried to get argument name from PatLit, \
                  which is silly in function arguments");
2550
            "()".to_string()
2551
        },
S
Steve Klabnik 已提交
2552
        PatRange(..) => panic!("tried to get argument name from PatRange, \
2553
                              which is not allowed in function arguments"),
2554 2555 2556 2557 2558 2559
        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(", "))
        },
2560 2561 2562 2563 2564
        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 已提交
2565 2566 2567 2568
    }
}

/// Given a Type, resolve it using the def_map
N
Niko Matsakis 已提交
2569 2570
fn resolve_type(cx: &DocContext,
                path: Path,
2571
                id: ast::NodeId) -> Type {
2572 2573
    let tcx = match cx.tcx_opt() {
        Some(tcx) => tcx,
2574
        // If we're extracting tests, this return value doesn't matter.
2575
        None => return Primitive(Bool),
2576
    };
L
Luqman Aden 已提交
2577
    debug!("searching for {} in defmap", id);
2578
    let def = match tcx.def_map.borrow().get(&id) {
2579
        Some(k) => k.full_def(),
S
Steve Klabnik 已提交
2580
        None => panic!("unresolved id not in defmap")
C
Corey Richardson 已提交
2581 2582
    };

2583
    match def {
2584
        def::DefSelfTy(..) if path.segments.len() == 1 => {
2585 2586
            return Generic(token::get_name(special_idents::type_self.name).to_string());
        }
2587
        def::DefPrimTy(p) => match p {
2588 2589 2590
            ast::TyStr => return Primitive(Str),
            ast::TyBool => return Primitive(Bool),
            ast::TyChar => return Primitive(Char),
2591
            ast::TyInt(ast::TyIs) => return Primitive(Isize),
2592 2593 2594 2595
            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),
2596
            ast::TyUint(ast::TyUs) => return Primitive(Usize),
2597 2598 2599 2600 2601 2602
            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 已提交
2603
        },
2604 2605 2606
        def::DefTyParam(_, _, _, n) => {
            return Generic(token::get_name(n).to_string())
        }
2607 2608
        _ => {}
    };
2609
    let did = register_def(&*cx, def);
N
Niko Matsakis 已提交
2610
    ResolvedPath { path: path, typarams: None, did: did }
2611 2612
}

2613
fn register_def(cx: &DocContext, def: def::Def) -> ast::DefId {
2614
    let (did, kind) = match def {
N
Nick Cameron 已提交
2615
        def::DefFn(i, _) => (i, TypeFunction),
2616 2617
        def::DefTy(i, false) => (i, TypeTypedef),
        def::DefTy(i, true) => (i, TypeEnum),
2618
        def::DefTrait(i) => (i, TypeTrait),
2619 2620 2621 2622 2623
        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 已提交
2624
    };
2625
    if ast_util::is_local(did) { return did }
2626 2627 2628
    let tcx = match cx.tcx_opt() {
        Some(tcx) => tcx,
        None => return did
2629
    };
2630
    inline::record_extern_fqn(cx, did, kind);
2631 2632 2633
    if let TypeTrait = kind {
        let t = inline::build_external_trait(cx, tcx, did);
        cx.external_traits.borrow_mut().as_mut().unwrap().insert(did, t);
2634
    }
2635
    return did;
C
Corey Richardson 已提交
2636
}
A
Alex Crichton 已提交
2637

2638
fn resolve_use_source(cx: &DocContext, path: Path, id: ast::NodeId) -> ImportSource {
A
Alex Crichton 已提交
2639 2640
    ImportSource {
        path: path,
2641
        did: resolve_def(cx, id),
A
Alex Crichton 已提交
2642 2643 2644
    }
}

2645 2646
fn resolve_def(cx: &DocContext, id: ast::NodeId) -> Option<ast::DefId> {
    cx.tcx_opt().and_then(|tcx| {
2647
        tcx.def_map.borrow().get(&id).map(|d| register_def(cx, d.full_def()))
2648
    })
A
Alex Crichton 已提交
2649
}
2650

J
Jorge Aparicio 已提交
2651
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
2652
pub struct Macro {
2653
    pub source: String,
2654
    pub imported_from: Option<String>,
2655 2656 2657
}

impl Clean<Item> for doctree::Macro {
2658
    fn clean(&self, cx: &DocContext) -> Item {
2659
        Item {
2660 2661 2662 2663 2664
            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),
2665
            def_id: ast_util::local_def(self.id),
2666
            inner: MacroItem(Macro {
2667
                source: self.whence.to_src(cx),
2668
                imported_from: self.imported_from.clean(cx),
2669 2670 2671 2672
            }),
        }
    }
}
2673

J
Jorge Aparicio 已提交
2674
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
2675 2676
pub struct Stability {
    pub level: attr::StabilityLevel,
2677 2678
    pub feature: String,
    pub since: String,
2679
    pub deprecated_since: String,
2680
    pub reason: String
2681 2682 2683
}

impl Clean<Stability> for attr::Stability {
2684
    fn clean(&self, _: &DocContext) -> Stability {
2685 2686
        Stability {
            level: self.level,
G
GuillaumeGomez 已提交
2687
            feature: self.feature.to_string(),
2688
            since: self.since.as_ref().map_or("".to_string(),
G
GuillaumeGomez 已提交
2689
                                              |interned| interned.to_string()),
2690 2691
            deprecated_since: self.deprecated_since.as_ref().map_or("".to_string(),
                                                                    |istr| istr.to_string()),
2692
            reason: self.reason.as_ref().map_or("".to_string(),
G
GuillaumeGomez 已提交
2693
                                                |interned| interned.to_string()),
2694 2695 2696
        }
    }
}
A
Alex Crichton 已提交
2697

2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711
impl<'tcx> Clean<Item> for ty::AssociatedConst<'tcx> {
    fn clean(&self, cx: &DocContext) -> Item {
        Item {
            source: DUMMY_SP.clean(cx),
            name: Some(self.name.clean(cx)),
            attrs: Vec::new(),
            inner: AssociatedConstItem(self.ty.clean(cx), None),
            visibility: None,
            def_id: self.def_id,
            stability: None,
        }
    }
}

2712 2713
impl Clean<Item> for ty::AssociatedType {
    fn clean(&self, cx: &DocContext) -> Item {
2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759
        // When loading a cross-crate associated type, the bounds for this type
        // are actually located on the trait/impl itself, so we need to load
        // all of the generics from there and then look for bounds that are
        // applied to this associated type in question.
        let predicates = ty::lookup_predicates(cx.tcx(), self.container.id());
        let generics = match self.container {
            ty::TraitContainer(did) => {
                let def = ty::lookup_trait_def(cx.tcx(), did);
                (&def.generics, &predicates, subst::TypeSpace).clean(cx)
            }
            ty::ImplContainer(did) => {
                let ty = ty::lookup_item_type(cx.tcx(), did);
                (&ty.generics, &predicates, subst::TypeSpace).clean(cx)
            }
        };
        let my_name = self.name.clean(cx);
        let mut bounds = generics.where_predicates.iter().filter_map(|pred| {
            let (name, self_type, trait_, bounds) = match *pred {
                WherePredicate::BoundPredicate {
                    ty: QPath { ref name, ref self_type, ref trait_ },
                    ref bounds
                } => (name, self_type, trait_, bounds),
                _ => return None,
            };
            if *name != my_name { return None }
            match **trait_ {
                ResolvedPath { did, .. } if did == self.container.id() => {}
                _ => return None,
            }
            match **self_type {
                Generic(ref s) if *s == "Self" => {}
                _ => return None,
            }
            Some(bounds)
        }).flat_map(|i| i.iter().cloned()).collect::<Vec<_>>();

        // Our Sized/?Sized bound didn't get handled when creating the generics
        // because we didn't actually get our whole set of bounds until just now
        // (some of them may have come from the trait). If we do have a sized
        // bound, we remove it, and if we don't then we add the `?Sized` bound
        // at the end.
        match bounds.iter().position(|b| b.is_sized_bound(cx)) {
            Some(i) => { bounds.remove(i); }
            None => bounds.push(TyParamBound::maybe_sized(cx)),
        }

2760 2761
        Item {
            source: DUMMY_SP.clean(cx),
2762
            name: Some(self.name.clean(cx)),
2763 2764 2765
            attrs: inline::load_attrs(cx, cx.tcx(), self.def_id),
            inner: AssociatedTypeItem(bounds, None),
            visibility: self.vis.clean(cx),
2766
            def_id: self.def_id,
2767
            stability: stability::lookup(cx.tcx(), self.def_id).clean(cx),
2768 2769 2770 2771
        }
    }
}

2772 2773
impl<'a> Clean<Typedef> for (ty::TypeScheme<'a>, ty::GenericPredicates<'a>,
                             ParamSpace) {
2774
    fn clean(&self, cx: &DocContext) -> Typedef {
2775
        let (ref ty_scheme, ref predicates, ps) = *self;
2776 2777
        Typedef {
            type_: ty_scheme.ty.clean(cx),
2778
            generics: (&ty_scheme.generics, predicates, ps).clean(cx)
2779 2780 2781 2782
        }
    }
}

2783
fn lang_struct(cx: &DocContext, did: Option<ast::DefId>,
2784
               t: ty::Ty, name: &str,
A
Alex Crichton 已提交
2785 2786 2787
               fallback: fn(Box<Type>) -> Type) -> Type {
    let did = match did {
        Some(did) => did,
2788
        None => return fallback(box t.clean(cx)),
A
Alex Crichton 已提交
2789
    };
2790
    let fqn = csearch::get_item_path(cx.tcx(), did);
A
Aaron Turon 已提交
2791
    let fqn: Vec<String> = fqn.into_iter().map(|i| {
A
Alex Crichton 已提交
2792 2793
        i.to_string()
    }).collect();
2794
    cx.external_paths.borrow_mut().as_mut().unwrap().insert(did, (fqn, TypeStruct));
A
Alex Crichton 已提交
2795 2796 2797 2798 2799 2800 2801
    ResolvedPath {
        typarams: None,
        did: did,
        path: Path {
            global: false,
            segments: vec![PathSegment {
                name: name.to_string(),
2802 2803 2804
                params: PathParameters::AngleBracketed {
                    lifetimes: vec![],
                    types: vec![t.clean(cx)],
2805
                    bindings: vec![]
2806
                }
A
Alex Crichton 已提交
2807 2808 2809 2810
            }],
        },
    }
}
2811 2812

/// An equality constraint on an associated type, e.g. `A=Bar` in `Foo<A=Bar>`
J
Jorge Aparicio 已提交
2813
#[derive(Clone, PartialEq, RustcDecodable, RustcEncodable, Debug)]
2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826
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)
        }
    }
}