mod.rs 84.4 KB
Newer Older
1 2 3 4 5 6 7 8 9 10
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

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

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

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

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

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

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

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

63 64
mod inline;

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

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

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

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

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

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

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

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

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

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

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

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

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

        // Collect all inner modules which are tagged as implementations of
        // primitives.
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160
        //
        // Note that this loop only searches the top-level items of the crate,
        // and this is intentional. If we were to search the entire crate for an
        // item tagged with `#[doc(primitive)]` then we we would also have to
        // search the entirety of external modules for items tagged
        // `#[doc(primitive)]`, which is a pretty inefficient process (decoding
        // all that metadata unconditionally).
        //
        // In order to keep the metadata load under control, the
        // `#[doc(primitive)]` feature is explicitly designed to only allow the
        // primitive tags to show up as the top level items in a crate.
        //
        // Also note that this does not attempt to deal with modules tagged
        // duplicately for the same primitive. This is handled later on when
        // rendering by delegating everything to a hash map.
161 162 163 164 165 166 167
        let mut primitives = Vec::new();
        {
            let m = match module.inner {
                ModuleItem(ref mut m) => m,
                _ => unreachable!(),
            };
            let mut tmp = Vec::new();
A
Aaron Turon 已提交
168
            for child in m.items.iter_mut() {
169 170
                match child.inner {
                    ModuleItem(..) => {}
171
                    _ => continue,
172
                }
173
                let prim = match PrimitiveType::find(child.attrs.as_slice()) {
174 175 176 177
                    Some(prim) => prim,
                    None => continue,
                };
                primitives.push(prim);
178
                tmp.push(Item {
179 180
                    source: Span::empty(),
                    name: Some(prim.to_url_str().to_string()),
181 182
                    attrs: child.attrs.clone(),
                    visibility: Some(ast::Public),
183
                    stability: None,
184 185
                    def_id: ast_util::local_def(prim.to_node_id()),
                    inner: PrimitiveItem(prim),
186
                });
187
            }
A
Aaron Turon 已提交
188
            m.items.extend(tmp.into_iter());
189 190
        }

C
Corey Richardson 已提交
191
        Crate {
192
            name: name.to_string(),
193
            src: cx.src.clone(),
194
            module: Some(module),
195
            externs: externs,
196
            primitives: primitives,
197 198 199 200
        }
    }
}

201
#[derive(Clone, RustcEncodable, RustcDecodable)]
202
pub struct ExternalCrate {
203
    pub name: String,
204
    pub attrs: Vec<Attribute>,
205
    pub primitives: Vec<PrimitiveType>,
206 207 208
}

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

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

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

    /// Finds the `doc` attribute as a NameValue and returns the corresponding
    /// value found.
    pub fn doc_value<'a>(&'a self) -> Option<&'a str> {
        for attr in self.attrs.iter() {
            match *attr {
267
                NameValue(ref x, ref v) if "doc" == *x => {
268 269
                    return Some(v.as_slice());
                }
270 271 272 273 274 275
                _ => {}
            }
        }
        return None;
    }

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

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

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

339
#[derive(Clone, RustcEncodable, RustcDecodable)]
C
Corey Richardson 已提交
340
pub struct Module {
341 342
    pub items: Vec<Item>,
    pub is_crate: bool,
C
Corey Richardson 已提交
343 344 345
}

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

        // determine if we should display the inner contents or
        // the outer `mod` item for the source code.
376
        let whence = {
377
            let cm = cx.sess().codemap();
378 379 380 381 382 383 384 385 386 387 388
            let outer = cm.lookup_char_pos(self.where_outer.lo);
            let inner = cm.lookup_char_pos(self.where_inner.lo);
            if outer.file.start_pos == inner.file.start_pos {
                // mod foo { ... }
                self.where_outer
            } else {
                // mod foo; (and a separate FileMap for the contents)
                self.where_inner
            }
        };

C
Corey Richardson 已提交
389 390
        Item {
            name: Some(name),
391 392 393 394
            attrs: self.attrs.clean(cx),
            source: whence.clean(cx),
            visibility: self.vis.clean(cx),
            stability: self.stab.clean(cx),
395
            def_id: ast_util::local_def(self.id),
C
Corey Richardson 已提交
396
            inner: ModuleItem(Module {
397
               is_crate: self.is_crate,
398 399 400
               items: items.iter()
                           .flat_map(|x| x.iter().map(|x| (*x).clone()))
                           .collect(),
C
Corey Richardson 已提交
401 402 403 404 405
            })
        }
    }
}

406
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Show)]
C
Corey Richardson 已提交
407
pub enum Attribute {
408 409 410
    Word(String),
    List(String, Vec<Attribute> ),
    NameValue(String, String)
C
Corey Richardson 已提交
411 412 413
}

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

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

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

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

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

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

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

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

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

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

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

523
        (tp_bounds, bindings)
524 525 526
    }
}

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

    match (trait_did, cx.tcx_opt()) {
        // Attempt to sugar an external path like Fn<(A, B,), C> to Fn(A, B) -> C
        (Some(did), Some(ref tcx)) if tcx.lang_items.fn_trait_kind(did).is_some() => {
            assert_eq!(types.len(), 2);
            let inputs = match types[0].sty {
                sty::ty_tup(ref tys) => tys.iter().map(|t| t.clean(cx)).collect(),
                _ => {
                    return PathParameters::AngleBracketed {
                        lifetimes: lifetimes,
545
                        types: types.clean(cx),
546
                        bindings: bindings
547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562
                    }
                }
            };
            let output = match types[1].sty {
                sty::ty_tup(ref v) if v.is_empty() => None, // -> ()
                _ => Some(types[1].clean(cx))
            };
            PathParameters::Parenthesized {
                inputs: inputs,
                output: output
            }
        },
        (_, _) => {
            PathParameters::AngleBracketed {
                lifetimes: lifetimes,
                types: types.clean(cx),
563
                bindings: bindings
564 565 566 567 568 569 570 571
            }
        }
    }
}

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

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

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

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

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

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

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

685
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Show)]
686
pub struct Lifetime(String);
C
Corey Richardson 已提交
687

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

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

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

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

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

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

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

735
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Show)]
736 737 738
pub enum WherePredicate {
    BoundPredicate { ty: Type, bounds: Vec<TyParamBound> },
    RegionPredicate { lifetime: Lifetime, bounds: Vec<Lifetime>},
739
    EqPredicate { lhs: Type, rhs: Type }
740 741 742 743
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

861
impl<'a, 'tcx> Clean<Generics> for (&'a ty::Generics<'tcx>, subst::ParamSpace) {
862
    fn clean(&self, cx: &DocContext) -> Generics {
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 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932
        use std::collections::HashSet;
        use syntax::ast::TraitBoundModifier as TBM;
        use self::WherePredicate as WP;

        fn has_sized_bound(bounds: &[TyParamBound], cx: &DocContext) -> bool {
            if let Some(tcx) = cx.tcx_opt() {
                let sized_did = match tcx.lang_items.sized_trait() {
                    Some(did) => did,
                    None => return false
                };
                for bound in bounds.iter() {
                    if let TyParamBound::TraitBound(PolyTrait {
                        trait_: Type::ResolvedPath { did, .. }, ..
                    }, TBM::None) = *bound {
                        if did == sized_did {
                            return true
                        }
                    }
                }
            }
            false
        }

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

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

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

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

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

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

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

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

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

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

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

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

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

1071
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Show)]
1072
pub struct Arguments {
1073
    pub values: Vec<Argument>,
1074 1075
}

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

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

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

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

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

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

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

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

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

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

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

1200 1201
/// An item belonging to a trait, whether a method or associated. Could be named
/// TraitItem except that's already taken by an exported enum variant.
1202
#[derive(Clone, RustcEncodable, RustcDecodable)]
1203
pub enum TraitMethod {
1204 1205
    RequiredMethod(Item),
    ProvidedMethod(Item),
1206
    TypeTraitItem(Item),
C
Corey Richardson 已提交
1207 1208
}

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

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

1247
#[derive(Clone, RustcEncodable, RustcDecodable)]
1248
pub enum ImplMethod {
1249
    MethodImplItem(Item),
1250
    TypeImplItem(Item),
1251 1252
}

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

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

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

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

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

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

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

    // _
    Infer,

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

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

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

1396 1397
impl PrimitiveType {
    fn from_str(s: &str) -> Option<PrimitiveType> {
1398
        match s.as_slice() {
1399
            "isize" | "int" => Some(Isize),
1400 1401 1402 1403
            "i8" => Some(I8),
            "i16" => Some(I16),
            "i32" => Some(I32),
            "i64" => Some(I64),
1404
            "usize" | "uint" => Some(Usize),
1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419
            "u8" => Some(U8),
            "u16" => Some(U16),
            "u32" => Some(U32),
            "u64" => Some(U64),
            "bool" => Some(Bool),
            "char" => Some(Char),
            "str" => Some(Str),
            "f32" => Some(F32),
            "f64" => Some(F64),
            "slice" => Some(Slice),
            "tuple" => Some(PrimitiveTuple),
            _ => None,
        }
    }

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

1441
    pub fn to_string(&self) -> &'static str {
1442
        match *self {
1443
            Isize => "isize",
1444 1445 1446 1447
            I8 => "i8",
            I16 => "i16",
            I32 => "i32",
            I64 => "i64",
1448
            Usize => "usize",
1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463
            U8 => "u8",
            U16 => "u16",
            U32 => "u32",
            U64 => "u64",
            F32 => "f32",
            F64 => "f64",
            Str => "str",
            Bool => "bool",
            Char => "char",
            Slice => "slice",
            PrimitiveTuple => "tuple",
        }
    }

    pub fn to_url_str(&self) -> &'static str {
1464
        self.to_string()
1465 1466 1467 1468 1469 1470 1471 1472 1473 1474
    }

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

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

1593 1594
            ty::ty_projection(ref data) => {
                let trait_ref = match data.trait_ref.clean(cx) {
N
Niko Matsakis 已提交
1595
                    TyParamBound::TraitBound(t, _) => t.trait_,
1596 1597 1598 1599 1600 1601 1602 1603 1604
                    TyParamBound::RegionBound(_) => panic!("cleaning a trait got a region??"),
                };
                Type::QPath {
                    name: data.item_name.clean(cx),
                    self_type: box data.trait_ref.self_ty().clean(cx),
                    trait_: box trait_ref,
                }
            }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1847
#[derive(Clone, RustcEncodable, RustcDecodable, Show)]
1848
pub struct Span {
1849
    pub filename: String,
1850 1851 1852 1853
    pub loline: uint,
    pub locol: uint,
    pub hiline: uint,
    pub hicol: uint,
1854 1855
}

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

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

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

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

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

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

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

1931
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Show)]
1932 1933 1934 1935 1936 1937 1938
pub struct PathSegment {
    pub name: String,
    pub params: PathParameters
}

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

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

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

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

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

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

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

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

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

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

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

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

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

2085
#[derive(Clone, RustcEncodable, RustcDecodable)]
C
Corey Richardson 已提交
2086
pub struct Impl {
2087 2088 2089
    pub generics: Generics,
    pub trait_: Option<Type>,
    pub for_: Type,
2090
    pub items: Vec<Item>,
2091
    pub derived: bool,
C
Corey Richardson 已提交
2092 2093
}

2094
fn detect_derived<M: AttrMetaMethods>(attrs: &[M]) -> bool {
2095
    attr::contains_name(attrs, "automatically_derived")
2096 2097
}

C
Corey Richardson 已提交
2098
impl Clean<Item> for doctree::Impl {
2099
    fn clean(&self, cx: &DocContext) -> Item {
C
Corey Richardson 已提交
2100 2101
        Item {
            name: None,
2102 2103
            attrs: self.attrs.clean(cx),
            source: self.whence.clean(cx),
2104
            def_id: ast_util::local_def(self.id),
2105 2106
            visibility: self.vis.clean(cx),
            stability: self.stab.clean(cx),
C
Corey Richardson 已提交
2107
            inner: ImplItem(Impl {
2108 2109 2110
                generics: self.generics.clean(cx),
                trait_: self.trait_.clean(cx),
                for_: self.for_.clean(cx),
A
Aaron Turon 已提交
2111
                items: self.items.clean(cx).into_iter().map(|ti| {
2112 2113
                        match ti {
                            MethodImplItem(i) => i,
2114
                            TypeImplItem(i) => i,
2115 2116
                        }
                    }).collect(),
2117
                derived: detect_derived(self.attrs.as_slice()),
C
Corey Richardson 已提交
2118 2119 2120 2121 2122
            }),
        }
    }
}

2123
#[derive(Clone, RustcEncodable, RustcDecodable)]
C
Corey Richardson 已提交
2124
pub struct ViewItem {
2125
    pub inner: ViewItemInner,
C
Corey Richardson 已提交
2126 2127
}

2128
impl Clean<Vec<Item>> for ast::ViewItem {
2129
    fn clean(&self, cx: &DocContext) -> Vec<Item> {
J
Joseph Crail 已提交
2130
        // We consider inlining the documentation of `pub use` statements, but we
2131 2132
        // forcefully don't inline if this is not public or if the
        // #[doc(no_inline)] attribute is present.
2133 2134
        let denied = self.vis != ast::Public || self.attrs.iter().any(|a| {
            a.name().get() == "doc" && match a.meta_item_list() {
2135
                Some(l) => attr::contains_name(l, "no_inline"),
2136 2137 2138
                None => false,
            }
        });
2139
        let convert = |&: node: &ast::ViewItem_| {
2140 2141
            Item {
                name: None,
2142 2143
                attrs: self.attrs.clean(cx),
                source: self.span.clean(cx),
2144
                def_id: ast_util::local_def(0),
2145
                visibility: self.vis.clean(cx),
2146
                stability: None,
2147
                inner: ViewItemItem(ViewItem { inner: node.clean(cx) }),
2148 2149 2150 2151 2152 2153 2154 2155
            }
        };
        let mut ret = Vec::new();
        match self.node {
            ast::ViewItemUse(ref path) if !denied => {
                match path.node {
                    ast::ViewPathGlob(..) => ret.push(convert(&self.node)),
                    ast::ViewPathList(ref a, ref list, ref b) => {
2156 2157 2158
                        // Attempt to inline all reexported items, but be sure
                        // to keep any non-inlineable reexports so they can be
                        // listed in the documentation.
2159
                        let remaining = list.iter().filter(|path| {
2160
                            match inline::try_inline(cx, path.node.id(), None) {
2161
                                Some(items) => {
A
Aaron Turon 已提交
2162
                                    ret.extend(items.into_iter()); false
2163
                                }
2164 2165
                                None => true,
                            }
J
Jakub Wieczorek 已提交
2166
                        }).map(|a| a.clone()).collect::<Vec<ast::PathListItem>>();
2167 2168 2169 2170 2171
                        if remaining.len() > 0 {
                            let path = ast::ViewPathList(a.clone(),
                                                         remaining,
                                                         b.clone());
                            let path = syntax::codemap::dummy_spanned(path);
2172
                            ret.push(convert(&ast::ViewItemUse(P(path))));
2173 2174
                        }
                    }
2175
                    ast::ViewPathSimple(ident, _, id) => {
2176
                        match inline::try_inline(cx, id, Some(ident)) {
A
Aaron Turon 已提交
2177
                            Some(items) => ret.extend(items.into_iter()),
2178 2179 2180 2181 2182 2183
                            None => ret.push(convert(&self.node)),
                        }
                    }
                }
            }
            ref n => ret.push(convert(n)),
C
Corey Richardson 已提交
2184
        }
2185
        return ret;
C
Corey Richardson 已提交
2186 2187 2188
    }
}

2189
#[derive(Clone, RustcEncodable, RustcDecodable)]
C
Corey Richardson 已提交
2190
pub enum ViewItemInner {
2191
    ExternCrate(String, Option<String>, ast::NodeId),
2192
    Import(ViewPath)
C
Corey Richardson 已提交
2193 2194
}

2195
impl Clean<ViewItemInner> for ast::ViewItem_ {
2196
    fn clean(&self, cx: &DocContext) -> ViewItemInner {
C
Corey Richardson 已提交
2197
        match self {
2198
            &ast::ViewItemExternCrate(ref i, ref p, ref id) => {
P
Patrick Walton 已提交
2199 2200
                let string = match *p {
                    None => None,
2201
                    Some((ref x, _)) => Some(x.get().to_string()),
P
Patrick Walton 已提交
2202
                };
2203
                ExternCrate(i.clean(cx), string, *id)
P
Patrick Walton 已提交
2204
            }
2205
            &ast::ViewItemUse(ref vp) => {
2206
                Import(vp.clean(cx))
2207
            }
C
Corey Richardson 已提交
2208 2209 2210 2211
        }
    }
}

2212
#[derive(Clone, RustcEncodable, RustcDecodable)]
C
Corey Richardson 已提交
2213
pub enum ViewPath {
2214
    // use source as str;
2215
    SimpleImport(String, ImportSource),
A
Alex Crichton 已提交
2216 2217 2218
    // use source::*;
    GlobImport(ImportSource),
    // use source::{a, b, c};
2219
    ImportList(ImportSource, Vec<ViewListIdent>),
A
Alex Crichton 已提交
2220 2221
}

2222
#[derive(Clone, RustcEncodable, RustcDecodable)]
A
Alex Crichton 已提交
2223
pub struct ImportSource {
2224 2225
    pub path: Path,
    pub did: Option<ast::DefId>,
C
Corey Richardson 已提交
2226 2227
}

2228
impl Clean<ViewPath> for ast::ViewPath {
2229
    fn clean(&self, cx: &DocContext) -> ViewPath {
C
Corey Richardson 已提交
2230
        match self.node {
2231
            ast::ViewPathSimple(ref i, ref p, id) =>
2232
                SimpleImport(i.clean(cx), resolve_use_source(cx, p.clean(cx), id)),
2233
            ast::ViewPathGlob(ref p, id) =>
2234
                GlobImport(resolve_use_source(cx, p.clean(cx), id)),
2235
            ast::ViewPathList(ref p, ref pl, id) => {
2236 2237
                ImportList(resolve_use_source(cx, p.clean(cx), id),
                           pl.clean(cx))
2238
            }
C
Corey Richardson 已提交
2239 2240 2241 2242
        }
    }
}

2243
#[derive(Clone, RustcEncodable, RustcDecodable)]
A
Alex Crichton 已提交
2244
pub struct ViewListIdent {
2245
    pub name: String,
2246
    pub source: Option<ast::DefId>,
A
Alex Crichton 已提交
2247
}
C
Corey Richardson 已提交
2248

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

2264
impl Clean<Vec<Item>> for ast::ForeignMod {
2265 2266
    fn clean(&self, cx: &DocContext) -> Vec<Item> {
        self.items.clean(cx)
2267 2268 2269
    }
}

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

C
Corey Richardson 已提交
2300 2301 2302
// Utilities

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

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

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

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

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

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

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

2424
fn register_def(cx: &DocContext, def: def::Def) -> ast::DefId {
2425
    let (did, kind) = match def {
N
Nick Cameron 已提交
2426
        def::DefFn(i, _) => (i, TypeFunction),
2427 2428
        def::DefTy(i, false) => (i, TypeTypedef),
        def::DefTy(i, true) => (i, TypeEnum),
2429 2430 2431 2432 2433 2434
        def::DefTrait(i) => (i, TypeTrait),
        def::DefStruct(i) => (i, TypeStruct),
        def::DefMod(i) => (i, TypeModule),
        def::DefStatic(i, _) => (i, TypeStatic),
        def::DefVariant(i, _, _) => (i, TypeEnum),
        _ => return def.def_id()
C
Corey Richardson 已提交
2435
    };
2436
    if ast_util::is_local(did) { return did }
2437 2438 2439
    let tcx = match cx.tcx_opt() {
        Some(tcx) => tcx,
        None => return did
2440
    };
2441
    inline::record_extern_fqn(cx, did, kind);
2442 2443 2444
    if let TypeTrait = kind {
        let t = inline::build_external_trait(cx, tcx, did);
        cx.external_traits.borrow_mut().as_mut().unwrap().insert(did, t);
2445
    }
2446
    return did;
C
Corey Richardson 已提交
2447
}
A
Alex Crichton 已提交
2448

2449
fn resolve_use_source(cx: &DocContext, path: Path, id: ast::NodeId) -> ImportSource {
A
Alex Crichton 已提交
2450 2451
    ImportSource {
        path: path,
2452
        did: resolve_def(cx, id),
A
Alex Crichton 已提交
2453 2454 2455
    }
}

2456 2457
fn resolve_def(cx: &DocContext, id: ast::NodeId) -> Option<ast::DefId> {
    cx.tcx_opt().and_then(|tcx| {
2458
        tcx.def_map.borrow().get(&id).map(|&def| register_def(cx, def))
2459
    })
A
Alex Crichton 已提交
2460
}
2461

2462
#[derive(Clone, RustcEncodable, RustcDecodable)]
2463
pub struct Macro {
2464
    pub source: String,
2465 2466 2467
}

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

2483
#[derive(Clone, RustcEncodable, RustcDecodable)]
2484 2485 2486 2487 2488 2489
pub struct Stability {
    pub level: attr::StabilityLevel,
    pub text: String
}

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

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

impl Clean<Item> for ty::AssociatedType {
    fn clean(&self, cx: &DocContext) -> Item {
        Item {
            source: DUMMY_SP.clean(cx),
2517
            name: Some(self.name.clean(cx)),
2518
            attrs: Vec::new(),
2519 2520 2521 2522 2523 2524 2525 2526 2527
            // FIXME(#18048): this is wrong, but cross-crate associated types are broken
            // anyway, for the time being.
            inner: AssociatedTypeItem(TyParam {
                name: self.name.clean(cx),
                did: ast::DefId {
                    krate: 0,
                    node: ast::DUMMY_NODE_ID
                },
                bounds: vec![],
2528
                default: None,
2529
            }),
2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547
            visibility: None,
            def_id: self.def_id,
            stability: None,
        }
    }
}

impl Clean<Item> for ast::Typedef {
    fn clean(&self, cx: &DocContext) -> Item {
        Item {
            source: self.span.clean(cx),
            name: Some(self.ident.clean(cx)),
            attrs: self.attrs.clean(cx),
            inner: TypedefItem(Typedef {
                type_: self.typ.clean(cx),
                generics: Generics {
                    lifetimes: Vec::new(),
                    type_params: Vec::new(),
2548
                    where_predicates: Vec::new()
2549 2550 2551 2552 2553 2554 2555 2556 2557
                },
            }),
            visibility: None,
            def_id: ast_util::local_def(self.id),
            stability: None,
        }
    }
}

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

/// An equality constraint on an associated type, e.g. `A=Bar` in `Foo<A=Bar>`
A
Alex Crichton 已提交
2588
#[derive(Clone, PartialEq, RustcDecodable, RustcEncodable, Show)]
2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601
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)
        }
    }
}