mod.rs 100.6 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
pub use self::Type::*;
pub use self::TypeKind::*;
pub use self::VariantKind::*;
pub use self::Mutability::*;
18
pub use self::Import::*;
S
Steven Fackler 已提交
19 20 21 22 23
pub use self::ItemEnum::*;
pub use self::Attribute::*;
pub use self::TyParamBound::*;
pub use self::SelfTy::*;
pub use self::FunctionRetTy::*;
J
Jeffrey Seyfried 已提交
24
pub use self::Visibility::*;
S
Steven Fackler 已提交
25

26
use syntax::abi::Abi;
C
Corey Richardson 已提交
27
use syntax::ast;
28
use syntax::attr;
29
use syntax::codemap::Spanned;
30
use syntax::parse::token::keywords;
31
use syntax::ptr::P;
32
use syntax::print::pprust as syntax_pprust;
33
use syntax_pos::{self, DUMMY_SP, Pos};
C
Corey Richardson 已提交
34

35
use rustc_trans::back::link;
36
use rustc::middle::cstore;
M
mitaa 已提交
37
use rustc::middle::privacy::AccessLevels;
38
use rustc::middle::resolve_lifetime::DefRegion::*;
39
use rustc::hir::def::Def;
M
mitaa 已提交
40
use rustc::hir::def_id::{DefId, DefIndex, CRATE_DEF_INDEX};
41
use rustc::hir::fold::Folder;
42
use rustc::hir::print as pprust;
43
use rustc::ty::subst::Substs;
44
use rustc::ty;
45
use rustc::middle::stability;
46
use rustc::util::nodemap::{FnvHashMap, FnvHashSet};
47

48
use rustc::hir;
49

50
use std::path::PathBuf;
51
use std::rc::Rc;
M
mitaa 已提交
52
use std::sync::Arc;
53
use std::u32;
54
use std::env::current_dir;
M
mitaa 已提交
55
use std::mem;
56

57
use core::DocContext;
C
Corey Richardson 已提交
58 59
use doctree;
use visit_ast;
60
use html::item_type::ItemType;
C
Corey Richardson 已提交
61

62
pub mod inline;
63
mod simplify;
64

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

70
fn get_deprecation(cx: &DocContext, def_id: DefId) -> Option<Deprecation> {
71
    cx.tcx_opt().and_then(|tcx| tcx.lookup_deprecation(def_id)).clean(cx)
72 73
}

C
Corey Richardson 已提交
74
pub trait Clean<T> {
75
    fn clean(&self, cx: &DocContext) -> T;
C
Corey Richardson 已提交
76 77
}

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

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

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

C
Corey Richardson 已提交
96
impl<T: Clean<U>, U> Clean<Option<U>> for Option<T> {
97
    fn clean(&self, cx: &DocContext) -> Option<U> {
M
mitaa 已提交
98
        self.as_ref().map(|v| v.clean(cx))
C
Corey Richardson 已提交
99 100 101
    }
}

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

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

M
mitaa 已提交
114
#[derive(Clone, Debug)]
C
Corey Richardson 已提交
115
pub struct Crate {
116
    pub name: String,
A
Alex Crichton 已提交
117
    pub src: PathBuf,
118 119
    pub module: Option<Item>,
    pub externs: Vec<(ast::CrateNum, ExternalCrate)>,
120
    pub primitives: Vec<PrimitiveType>,
M
mitaa 已提交
121 122 123
    pub access_levels: Arc<AccessLevels<DefId>>,
    // These are later on moved into `CACHEKEY`, leaving the map empty.
    // Only here so that they can be filtered through the rustdoc passes.
124
    pub external_traits: FnvHashMap<DefId, Trait>,
C
Corey Richardson 已提交
125 126
}

A
Ariel Ben-Yehuda 已提交
127 128
struct CrateNum(ast::CrateNum);

129 130
impl<'a, 'tcx> Clean<Crate> for visit_ast::RustdocVisitor<'a, 'tcx> {
    fn clean(&self, cx: &DocContext) -> Crate {
131
        use rustc::session::config::Input;
M
mitaa 已提交
132
        use ::visit_lib::LibEmbargoVisitor;
133

134 135
        if let Some(t) = cx.tcx_opt() {
            cx.deref_trait_did.set(t.lang_items.deref_trait());
M
mitaa 已提交
136
            cx.renderinfo.borrow_mut().deref_trait_did = cx.deref_trait_did.get();
137 138
        }

139
        let mut externs = Vec::new();
A
Ariel Ben-Yehuda 已提交
140 141
        for cnum in cx.sess().cstore.crates() {
            externs.push((cnum, CrateNum(cnum).clean(cx)));
M
mitaa 已提交
142 143 144 145
            if cx.tcx_opt().is_some() {
                // Analyze doc-reachability for extern items
                LibEmbargoVisitor::new(cx).visit_lib(cnum);
            }
A
Ariel Ben-Yehuda 已提交
146
        }
147
        externs.sort_by(|&(a, _), &(b, _)| a.cmp(&b));
C
Corey Richardson 已提交
148

149
        // Figure out the name of this crate
150
        let input = &cx.input;
151
        let name = link::find_crate_name(None, &self.attrs, input);
152

153
        // Clean the crate, translating the entire libsyntax AST to one that is
154
        // understood by rustdoc.
155
        let mut module = self.module.clean(cx);
156 157 158

        // Collect all inner modules which are tagged as implementations of
        // primitives.
159 160 161
        //
        // Note that this loop only searches the top-level items of the crate,
        // and this is intentional. If we were to search the entire crate for an
162
        // item tagged with `#[doc(primitive)]` then we would also have to
163 164 165 166 167 168 169 170 171 172 173
        // 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.
174 175 176 177 178 179 180
        let mut primitives = Vec::new();
        {
            let m = match module.inner {
                ModuleItem(ref mut m) => m,
                _ => unreachable!(),
            };
            let mut tmp = Vec::new();
181
            for child in &mut m.items {
M
mitaa 已提交
182 183
                if !child.is_mod() {
                    continue;
184
                }
185
                let prim = match PrimitiveType::find(&child.attrs) {
186 187 188 189
                    Some(prim) => prim,
                    None => continue,
                };
                primitives.push(prim);
190
                tmp.push(Item {
191 192
                    source: Span::empty(),
                    name: Some(prim.to_url_str().to_string()),
193
                    attrs: child.attrs.clone(),
J
Jeffrey Seyfried 已提交
194
                    visibility: Some(Public),
195
                    stability: None,
196
                    deprecation: None,
197
                    def_id: DefId::local(prim.to_def_index()),
198
                    inner: PrimitiveItem(prim),
199
                });
200
            }
201
            m.items.extend(tmp);
202 203
        }

204
        let src = match cx.input {
205 206 207 208 209 210 211
            Input::File(ref path) => {
                if path.is_absolute() {
                    path.clone()
                } else {
                    current_dir().unwrap().join(path)
                }
            },
212
            Input::Str { ref name, .. } => PathBuf::from(name.clone()),
213 214
        };

M
mitaa 已提交
215 216 217
        let mut access_levels = cx.access_levels.borrow_mut();
        let mut external_traits = cx.external_traits.borrow_mut();

C
Corey Richardson 已提交
218
        Crate {
219
            name: name.to_string(),
220
            src: src,
221
            module: Some(module),
222
            externs: externs,
223
            primitives: primitives,
M
mitaa 已提交
224 225
            access_levels: Arc::new(mem::replace(&mut access_levels, Default::default())),
            external_traits: mem::replace(&mut external_traits, Default::default()),
226 227 228 229
        }
    }
}

J
Jorge Aparicio 已提交
230
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
231
pub struct ExternalCrate {
232
    pub name: String,
233
    pub attrs: Vec<Attribute>,
234
    pub primitives: Vec<PrimitiveType>,
235 236
}

A
Ariel Ben-Yehuda 已提交
237
impl Clean<ExternalCrate> for CrateNum {
238
    fn clean(&self, cx: &DocContext) -> ExternalCrate {
239
        let mut primitives = Vec::new();
240
        cx.tcx_opt().map(|tcx| {
A
Ariel Ben-Yehuda 已提交
241 242
            for item in tcx.sess.cstore.crate_top_level_items(self.0) {
                let did = match item.def {
243
                    cstore::DlDef(Def::Mod(did)) => did,
A
Ariel Ben-Yehuda 已提交
244
                    _ => continue
245
                };
246
                let attrs = inline::load_attrs(cx, tcx, did);
247
                PrimitiveType::find(&attrs).map(|prim| primitives.push(prim));
A
Ariel Ben-Yehuda 已提交
248
            }
249
        });
250
        ExternalCrate {
251
            name: (&cx.sess().cstore.crate_name(self.0)[..]).to_owned(),
A
Ariel Ben-Yehuda 已提交
252
            attrs: cx.sess().cstore.crate_attrs(self.0).clean(cx),
253
            primitives: primitives,
C
Corey Richardson 已提交
254 255 256 257 258 259 260
        }
    }
}

/// Anything with a source location and set of attributes and, optionally, a
/// name. That is, anything that can be documented. This doesn't correspond
/// directly to the AST's concept of an item; it's a strict superset.
J
Jorge Aparicio 已提交
261
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
262 263
pub struct Item {
    /// Stringified span
264
    pub source: Span,
C
Corey Richardson 已提交
265
    /// Not everything has a name. E.g., impls
266
    pub name: Option<String>,
M
mitaa 已提交
267
    pub attrs: Vec<Attribute>,
268 269
    pub inner: ItemEnum,
    pub visibility: Option<Visibility>,
N
Niko Matsakis 已提交
270
    pub def_id: DefId,
271
    pub stability: Option<Stability>,
272
    pub deprecation: Option<Deprecation>,
C
Corey Richardson 已提交
273 274
}

275 276 277 278
impl Item {
    /// Finds the `doc` attribute as a NameValue and returns the corresponding
    /// value found.
    pub fn doc_value<'a>(&'a self) -> Option<&'a str> {
M
mitaa 已提交
279
        self.attrs.value("doc")
280
    }
M
mitaa 已提交
281 282
    pub fn is_crate(&self) -> bool {
        match self.inner {
283 284 285
            StrippedItem(box ModuleItem(Module { is_crate: true, ..})) |
            ModuleItem(Module { is_crate: true, ..}) => true,
            _ => false,
M
mitaa 已提交
286 287
        }
    }
288
    pub fn is_mod(&self) -> bool {
289
        ItemType::from(self) == ItemType::Module
290 291
    }
    pub fn is_trait(&self) -> bool {
292
        ItemType::from(self) == ItemType::Trait
293 294
    }
    pub fn is_struct(&self) -> bool {
295
        ItemType::from(self) == ItemType::Struct
296 297
    }
    pub fn is_enum(&self) -> bool {
298
        ItemType::from(self) == ItemType::Module
299 300
    }
    pub fn is_fn(&self) -> bool {
301
        ItemType::from(self) == ItemType::Function
302
    }
M
mitaa 已提交
303
    pub fn is_associated_type(&self) -> bool {
304
        ItemType::from(self) == ItemType::AssociatedType
M
mitaa 已提交
305 306
    }
    pub fn is_associated_const(&self) -> bool {
307
        ItemType::from(self) == ItemType::AssociatedConst
M
mitaa 已提交
308 309
    }
    pub fn is_method(&self) -> bool {
310
        ItemType::from(self) == ItemType::Method
M
mitaa 已提交
311 312
    }
    pub fn is_ty_method(&self) -> bool {
313
        ItemType::from(self) == ItemType::TyMethod
314
    }
315
    pub fn is_primitive(&self) -> bool {
316
        ItemType::from(self) == ItemType::Primitive
317
    }
318 319
    pub fn is_stripped(&self) -> bool {
        match self.inner { StrippedItem(..) => true, _ => false }
M
mitaa 已提交
320
    }
321 322 323
    pub fn has_stripped_fields(&self) -> Option<bool> {
        match self.inner {
            StructItem(ref _struct) => Some(_struct.fields_stripped),
V
Vadim Petrochenkov 已提交
324
            UnionItem(ref union) => Some(union.fields_stripped),
325 326 327 328 329 330
            VariantItem(Variant { kind: StructVariant(ref vstruct)} ) => {
                Some(vstruct.fields_stripped)
            },
            _ => None,
        }
    }
331 332

    pub fn stability_class(&self) -> String {
M
mitaa 已提交
333 334 335 336 337 338 339
        self.stability.as_ref().map(|ref s| {
            let mut base = match s.level {
                stability::Unstable => "unstable".to_string(),
                stability::Stable => String::new(),
            };
            if !s.deprecated_since.is_empty() {
                base.push_str(" deprecated");
340
            }
M
mitaa 已提交
341 342
            base
        }).unwrap_or(String::new())
343
    }
344 345

    pub fn stable_since(&self) -> Option<&str> {
M
mitaa 已提交
346
        self.stability.as_ref().map(|s| &s.since[..])
347
    }
348 349
}

J
Jorge Aparicio 已提交
350
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
351
pub enum ItemEnum {
352 353
    ExternCrateItem(String, Option<String>),
    ImportItem(Import),
C
Corey Richardson 已提交
354
    StructItem(Struct),
V
Vadim Petrochenkov 已提交
355
    UnionItem(Union),
C
Corey Richardson 已提交
356 357 358
    EnumItem(Enum),
    FunctionItem(Function),
    ModuleItem(Module),
359
    TypedefItem(Typedef, bool /* is associated type */),
C
Corey Richardson 已提交
360
    StaticItem(Static),
361
    ConstantItem(Constant),
C
Corey Richardson 已提交
362 363
    TraitItem(Trait),
    ImplItem(Impl),
364 365
    /// A method signature only. Used for required methods in traits (ie,
    /// non-default-methods).
C
Corey Richardson 已提交
366
    TyMethodItem(TyMethod),
367
    /// A method with a body.
C
Corey Richardson 已提交
368
    MethodItem(Method),
369
    StructFieldItem(Type),
C
Corey Richardson 已提交
370
    VariantItem(Variant),
371
    /// `fn`s from an extern block
372
    ForeignFunctionItem(Function),
373
    /// `static`s from an extern block
374
    ForeignStaticItem(Static),
375
    MacroItem(Macro),
376
    PrimitiveItem(PrimitiveType),
377
    AssociatedConstItem(Type, Option<String>),
378
    AssociatedTypeItem(Vec<TyParamBound>, Option<Type>),
379
    DefaultImplItem(DefaultImpl),
380 381
    /// An item that has been stripped by a rustdoc pass
    StrippedItem(Box<ItemEnum>),
C
Corey Richardson 已提交
382 383
}

384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400
impl ItemEnum {
    pub fn generics(&self) -> Option<&Generics> {
        Some(match *self {
            ItemEnum::StructItem(ref s) => &s.generics,
            ItemEnum::EnumItem(ref e) => &e.generics,
            ItemEnum::FunctionItem(ref f) => &f.generics,
            ItemEnum::TypedefItem(ref t, _) => &t.generics,
            ItemEnum::TraitItem(ref t) => &t.generics,
            ItemEnum::ImplItem(ref i) => &i.generics,
            ItemEnum::TyMethodItem(ref i) => &i.generics,
            ItemEnum::MethodItem(ref i) => &i.generics,
            ItemEnum::ForeignFunctionItem(ref f) => &f.generics,
            _ => return None,
        })
    }
}

J
Jorge Aparicio 已提交
401
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
402
pub struct Module {
403 404
    pub items: Vec<Item>,
    pub is_crate: bool,
C
Corey Richardson 已提交
405 406 407
}

impl Clean<Item> for doctree::Module {
408
    fn clean(&self, cx: &DocContext) -> Item {
C
Corey Richardson 已提交
409
        let name = if self.name.is_some() {
410
            self.name.unwrap().clean(cx)
C
Corey Richardson 已提交
411
        } else {
412
            "".to_string()
C
Corey Richardson 已提交
413
        };
414 415 416

        let mut items: Vec<Item> = vec![];
        items.extend(self.extern_crates.iter().map(|x| x.clean(cx)));
417
        items.extend(self.imports.iter().flat_map(|x| x.clean(cx)));
418
        items.extend(self.structs.iter().map(|x| x.clean(cx)));
V
Vadim Petrochenkov 已提交
419
        items.extend(self.unions.iter().map(|x| x.clean(cx)));
420 421
        items.extend(self.enums.iter().map(|x| x.clean(cx)));
        items.extend(self.fns.iter().map(|x| x.clean(cx)));
422
        items.extend(self.foreigns.iter().flat_map(|x| x.clean(cx)));
423 424 425 426 427
        items.extend(self.mods.iter().map(|x| x.clean(cx)));
        items.extend(self.typedefs.iter().map(|x| x.clean(cx)));
        items.extend(self.statics.iter().map(|x| x.clean(cx)));
        items.extend(self.constants.iter().map(|x| x.clean(cx)));
        items.extend(self.traits.iter().map(|x| x.clean(cx)));
428
        items.extend(self.impls.iter().flat_map(|x| x.clean(cx)));
429
        items.extend(self.macros.iter().map(|x| x.clean(cx)));
430
        items.extend(self.def_traits.iter().map(|x| x.clean(cx)));
431 432 433

        // determine if we should display the inner contents or
        // the outer `mod` item for the source code.
434
        let whence = {
435
            let cm = cx.sess().codemap();
436 437 438 439 440 441 442 443 444 445 446
            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 已提交
447 448
        Item {
            name: Some(name),
449 450 451 452
            attrs: self.attrs.clean(cx),
            source: whence.clean(cx),
            visibility: self.vis.clean(cx),
            stability: self.stab.clean(cx),
453
            deprecation: self.depr.clean(cx),
454
            def_id: cx.map.local_def_id(self.id),
C
Corey Richardson 已提交
455
            inner: ModuleItem(Module {
456
               is_crate: self.is_crate,
457
               items: items
C
Corey Richardson 已提交
458 459 460 461 462
            })
        }
    }
}

M
mitaa 已提交
463 464 465
pub trait Attributes {
    fn has_word(&self, &str) -> bool;
    fn value<'a>(&'a self, &str) -> Option<&'a str>;
466
    fn list<'a>(&'a self, &str) -> &'a [Attribute];
M
mitaa 已提交
467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494
}

impl Attributes for [Attribute] {
    /// Returns whether the attribute list contains a specific `Word`
    fn has_word(&self, word: &str) -> bool {
        for attr in self {
            if let Word(ref w) = *attr {
                if word == *w {
                    return true;
                }
            }
        }
        false
    }

    /// Finds an attribute as NameValue and returns the corresponding value found.
    fn value<'a>(&'a self, name: &str) -> Option<&'a str> {
        for attr in self {
            if let NameValue(ref x, ref v) = *attr {
                if name == *x {
                    return Some(v);
                }
            }
        }
        None
    }

    /// Finds an attribute as List and returns the list of attributes nested inside.
495
    fn list<'a>(&'a self, name: &str) -> &'a [Attribute] {
M
mitaa 已提交
496 497 498 499 500 501 502 503 504 505 506
        for attr in self {
            if let List(ref x, ref list) = *attr {
                if name == *x {
                    return &list[..];
                }
            }
        }
        &[]
    }
}

507
/// This is a flattened version of the AST's Attribute + MetaItem.
J
Jorge Aparicio 已提交
508
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
C
Corey Richardson 已提交
509
pub enum Attribute {
510
    Word(String),
M
mitaa 已提交
511
    List(String, Vec<Attribute>),
512 513 514 515 516 517 518 519 520 521 522 523 524
    NameValue(String, String),
    Literal(String),
}

impl Clean<Attribute> for ast::NestedMetaItem {
    fn clean(&self, cx: &DocContext) -> Attribute {
        if let Some(mi) = self.meta_item() {
            mi.clean(cx)
        } else { // must be a literal
            let lit = self.literal().unwrap();
            Literal(syntax_pprust::lit_to_string(lit))
        }
    }
C
Corey Richardson 已提交
525 526
}

527
impl Clean<Attribute> for ast::MetaItem {
528
    fn clean(&self, cx: &DocContext) -> Attribute {
529 530 531 532 533 534
        if self.is_word() {
            Word(self.name().to_string())
        } else if let Some(v) = self.value_str() {
            NameValue(self.name().to_string(), v.to_string())
        } else { // must be a list
            let l = self.meta_item_list().unwrap();
C
cgswords 已提交
535
            List(self.name().to_string(), l.clean(cx))
536
       }
C
Corey Richardson 已提交
537 538 539
    }
}

540
impl Clean<Attribute> for ast::Attribute {
541
    fn clean(&self, cx: &DocContext) -> Attribute {
542
        self.with_desugared_doc(|a| a.meta().clean(cx))
C
Corey Richardson 已提交
543 544 545
    }
}

J
Jorge Aparicio 已提交
546
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
C
Corey Richardson 已提交
547
pub struct TyParam {
548
    pub name: String,
N
Niko Matsakis 已提交
549
    pub did: DefId,
550
    pub bounds: Vec<TyParamBound>,
551
    pub default: Option<Type>,
552
}
C
Corey Richardson 已提交
553

554
impl Clean<TyParam> for hir::TyParam {
555
    fn clean(&self, cx: &DocContext) -> TyParam {
C
Corey Richardson 已提交
556
        TyParam {
557
            name: self.name.clean(cx),
558
            did: cx.map.local_def_id(self.id),
559
            bounds: self.bounds.clean(cx),
560
            default: self.default.clean(cx),
C
Corey Richardson 已提交
561 562 563 564
        }
    }
}

565
impl<'tcx> Clean<TyParam> for ty::TypeParameterDef<'tcx> {
566
    fn clean(&self, cx: &DocContext) -> TyParam {
M
mitaa 已提交
567
        cx.renderinfo.borrow_mut().external_typarams.insert(self.def_id, self.name.clean(cx));
568
        TyParam {
569
            name: self.name.clean(cx),
570
            did: self.def_id,
571
            bounds: vec![], // these are filled in from the where-clauses
572
            default: self.default.clean(cx),
573 574 575 576
        }
    }
}

J
Jorge Aparicio 已提交
577
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
C
Corey Richardson 已提交
578
pub enum TyParamBound {
579
    RegionBound(Lifetime),
580
    TraitBound(PolyTrait, hir::TraitBoundModifier)
C
Corey Richardson 已提交
581 582
}

583 584
impl TyParamBound {
    fn maybe_sized(cx: &DocContext) -> TyParamBound {
585
        use rustc::hir::TraitBoundModifier as TBM;
586
        let mut sized_bound = ty::BoundSized.clean(cx);
587 588 589 590 591 592 593
        if let TyParamBound::TraitBound(_, ref mut tbm) = sized_bound {
            *tbm = TBM::Maybe
        };
        sized_bound
    }

    fn is_sized_bound(&self, cx: &DocContext) -> bool {
594
        use rustc::hir::TraitBoundModifier as TBM;
595
        if let Some(tcx) = cx.tcx_opt() {
596 597 598
            if let TyParamBound::TraitBound(PolyTrait { ref trait_, .. }, TBM::None) = *self {
                if trait_.def_id() == tcx.lang_items.sized_trait() {
                    return true;
599 600 601 602 603 604 605
                }
            }
        }
        false
    }
}

606
impl Clean<TyParamBound> for hir::TyParamBound {
607
    fn clean(&self, cx: &DocContext) -> TyParamBound {
C
Corey Richardson 已提交
608
        match *self {
609 610
            hir::RegionTyParamBound(lt) => RegionBound(lt.clean(cx)),
            hir::TraitTyParamBound(ref t, modifier) => TraitBound(t.clean(cx), modifier),
C
Corey Richardson 已提交
611 612 613 614
        }
    }
}

615
fn external_path_params(cx: &DocContext, trait_did: Option<DefId>, has_self: bool,
616
                        bindings: Vec<TypeBinding>, substs: &Substs) -> PathParameters {
617
    let lifetimes = substs.regions().filter_map(|v| v.clean(cx)).collect();
618
    let types = substs.types().skip(has_self as usize).collect::<Vec<_>>();
619 620 621 622

    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() => {
623
            assert_eq!(types.len(), 1);
624
            let inputs = match types[0].sty {
625
                ty::TyTuple(ref tys) => tys.iter().map(|t| t.clean(cx)).collect(),
626 627 628
                _ => {
                    return PathParameters::AngleBracketed {
                        lifetimes: lifetimes,
629
                        types: types.clean(cx),
630
                        bindings: bindings
631 632 633
                    }
                }
            };
634 635 636
            let output = None;
            // FIXME(#20299) return type comes from a projection now
            // match types[1].sty {
637
            //     ty::TyTuple(ref v) if v.is_empty() => None, // -> ()
638 639
            //     _ => Some(types[1].clean(cx))
            // };
640 641 642 643 644 645 646 647 648
            PathParameters::Parenthesized {
                inputs: inputs,
                output: output
            }
        },
        (_, _) => {
            PathParameters::AngleBracketed {
                lifetimes: lifetimes,
                types: types.clean(cx),
649
                bindings: bindings
650 651 652 653 654 655 656
            }
        }
    }
}

// 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
657
fn external_path(cx: &DocContext, name: &str, trait_did: Option<DefId>, has_self: bool,
658
                 bindings: Vec<TypeBinding>, substs: &Substs) -> Path {
659 660 661
    Path {
        global: false,
        segments: vec![PathSegment {
662
            name: name.to_string(),
663
            params: external_path_params(cx, trait_did, has_self, bindings, substs)
664
        }],
665 666 667 668
    }
}

impl Clean<TyParamBound> for ty::BuiltinBound {
669 670 671
    fn clean(&self, cx: &DocContext) -> TyParamBound {
        let tcx = match cx.tcx_opt() {
            Some(tcx) => tcx,
672
            None => return RegionBound(Lifetime::statik())
673
        };
674
        let empty = Substs::empty(tcx);
675 676
        let (did, path) = match *self {
            ty::BoundSend =>
677
                (tcx.lang_items.send_trait().unwrap(),
678
                 external_path(cx, "Send", None, false, vec![], empty)),
679
            ty::BoundSized =>
680
                (tcx.lang_items.sized_trait().unwrap(),
681
                 external_path(cx, "Sized", None, false, vec![], empty)),
682
            ty::BoundCopy =>
683
                (tcx.lang_items.copy_trait().unwrap(),
684
                 external_path(cx, "Copy", None, false, vec![], empty)),
A
Alex Crichton 已提交
685 686
            ty::BoundSync =>
                (tcx.lang_items.sync_trait().unwrap(),
687
                 external_path(cx, "Sync", None, false, vec![], empty)),
688
        };
M
mitaa 已提交
689
        inline::record_extern_fqn(cx, did, TypeTrait);
690 691 692 693 694
        TraitBound(PolyTrait {
            trait_: ResolvedPath {
                path: path,
                typarams: None,
                did: did,
695
                is_generic: false,
696 697
            },
            lifetimes: vec![]
698
        }, hir::TraitBoundModifier::None)
699 700 701
    }
}

702
impl<'tcx> Clean<TyParamBound> for ty::TraitRef<'tcx> {
703 704 705
    fn clean(&self, cx: &DocContext) -> TyParamBound {
        let tcx = match cx.tcx_opt() {
            Some(tcx) => tcx,
706
            None => return RegionBound(Lifetime::statik())
707
        };
M
mitaa 已提交
708 709
        inline::record_extern_fqn(cx, self.def_id, TypeTrait);
        let path = external_path(cx, &tcx.item_name(self.def_id).as_str(),
710
                                 Some(self.def_id), true, vec![], self.substs);
711

712
        debug!("ty::TraitRef\n  subst: {:?}\n", self.substs);
713 714 715

        // collect any late bound regions
        let mut late_bounds = vec![];
716
        for ty_s in self.input_types().skip(1) {
717
            if let ty::TyTuple(ts) = ty_s.sty {
718
                for &ty_s in ts {
719 720
                    if let ty::TyRef(ref reg, _) = ty_s.sty {
                        if let &ty::Region::ReLateBound(_, _) = *reg {
721
                            debug!("  hit an ReLateBound {:?}", reg);
722
                            if let Some(lt) = reg.clean(cx) {
M
mitaa 已提交
723
                                late_bounds.push(lt);
724 725 726 727 728 729 730
                            }
                        }
                    }
                }
            }
        }

731 732 733 734 735 736 737 738 739
        TraitBound(
            PolyTrait {
                trait_: ResolvedPath {
                    path: path,
                    typarams: None,
                    did: self.def_id,
                    is_generic: false,
                },
                lifetimes: late_bounds,
740
            },
741 742
            hir::TraitBoundModifier::None
        )
743 744 745
    }
}

746
impl<'tcx> Clean<Option<Vec<TyParamBound>>> for Substs<'tcx> {
747
    fn clean(&self, cx: &DocContext) -> Option<Vec<TyParamBound>> {
748
        let mut v = Vec::new();
749
        v.extend(self.regions().filter_map(|r| r.clean(cx))
750
                     .map(RegionBound));
751
        v.extend(self.types().map(|t| TraitBound(PolyTrait {
752 753
            trait_: t.clean(cx),
            lifetimes: vec![]
754
        }, hir::TraitBoundModifier::None)));
755
        if !v.is_empty() {Some(v)} else {None}
756 757 758
    }
}

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

762 763 764
impl Lifetime {
    pub fn get_ref<'a>(&'a self) -> &'a str {
        let Lifetime(ref s) = *self;
765
        let s: &'a str = s;
766 767
        return s;
    }
768 769 770 771

    pub fn statik() -> Lifetime {
        Lifetime("'static".to_string())
    }
772 773
}

774
impl Clean<Lifetime> for hir::Lifetime {
775
    fn clean(&self, _: &DocContext) -> Lifetime {
776
        Lifetime(self.name.to_string())
C
Corey Richardson 已提交
777 778 779
    }
}

780
impl Clean<Lifetime> for hir::LifetimeDef {
781
    fn clean(&self, _: &DocContext) -> Lifetime {
782 783 784 785 786 787 788 789 790 791 792
        if self.bounds.len() > 0 {
            let mut s = format!("{}: {}",
                                self.lifetime.name.to_string(),
                                self.bounds[0].name.to_string());
            for bound in self.bounds.iter().skip(1) {
                s.push_str(&format!(" + {}", bound.name.to_string()));
            }
            Lifetime(s)
        } else {
            Lifetime(self.lifetime.name.to_string())
        }
793 794 795
    }
}

796
impl<'tcx> Clean<Lifetime> for ty::RegionParameterDef<'tcx> {
797
    fn clean(&self, _: &DocContext) -> Lifetime {
798
        Lifetime(self.name.to_string())
799 800 801 802
    }
}

impl Clean<Option<Lifetime>> for ty::Region {
803
    fn clean(&self, cx: &DocContext) -> Option<Lifetime> {
804
        match *self {
805
            ty::ReStatic => Some(Lifetime::statik()),
806
            ty::ReLateBound(_, ty::BrNamed(_, name, _)) => Some(Lifetime(name.to_string())),
N
Niko Matsakis 已提交
807
            ty::ReEarlyBound(ref data) => Some(Lifetime(data.name.clean(cx))),
808 809 810 811

            ty::ReLateBound(..) |
            ty::ReFree(..) |
            ty::ReScope(..) |
812 813
            ty::ReVar(..) |
            ty::ReSkolemized(..) |
814 815
            ty::ReEmpty |
            ty::ReErased => None
816 817 818 819
        }
    }
}

J
Jorge Aparicio 已提交
820
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
821 822 823
pub enum WherePredicate {
    BoundPredicate { ty: Type, bounds: Vec<TyParamBound> },
    RegionPredicate { lifetime: Lifetime, bounds: Vec<Lifetime>},
824
    EqPredicate { lhs: Type, rhs: Type }
825 826
}

827
impl Clean<WherePredicate> for hir::WherePredicate {
828
    fn clean(&self, cx: &DocContext) -> WherePredicate {
N
Nick Cameron 已提交
829
        match *self {
830
            hir::WherePredicate::BoundPredicate(ref wbp) => {
831
                WherePredicate::BoundPredicate {
832
                    ty: wbp.bounded_ty.clean(cx),
N
Nick Cameron 已提交
833 834 835
                    bounds: wbp.bounds.clean(cx)
                }
            }
836

837
            hir::WherePredicate::RegionPredicate(ref wrp) => {
838 839 840 841 842 843
                WherePredicate::RegionPredicate {
                    lifetime: wrp.lifetime.clean(cx),
                    bounds: wrp.bounds.clean(cx)
                }
            }

844
            hir::WherePredicate::EqPredicate(_) => {
845
                unimplemented!() // FIXME(#20041)
N
Nick Cameron 已提交
846
            }
847 848 849 850
        }
    }
}

851 852
impl<'a> Clean<WherePredicate> for ty::Predicate<'a> {
    fn clean(&self, cx: &DocContext) -> WherePredicate {
853
        use rustc::ty::Predicate;
854 855 856 857 858 859

        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),
860 861 862
            Predicate::Projection(ref pred) => pred.clean(cx),
            Predicate::WellFormed(_) => panic!("not user writable"),
            Predicate::ObjectSafe(_) => panic!("not user writable"),
863
            Predicate::ClosureKind(..) => panic!("not user writable"),
864 865 866 867 868 869 870
        }
    }
}

impl<'a> Clean<WherePredicate> for ty::TraitPredicate<'a> {
    fn clean(&self, cx: &DocContext) -> WherePredicate {
        WherePredicate::BoundPredicate {
871
            ty: self.trait_ref.self_ty().clean(cx),
872 873 874 875 876 877 878 879 880 881 882 883 884 885 886
            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)
        }
    }
}

887
impl<'tcx> Clean<WherePredicate> for ty::OutlivesPredicate<&'tcx ty::Region, &'tcx ty::Region> {
888 889 890 891 892 893 894 895 896
    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()]
        }
    }
}

897
impl<'tcx> Clean<WherePredicate> for ty::OutlivesPredicate<ty::Ty<'tcx>, &'tcx ty::Region> {
898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920
    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_,
921 922 923
            TyParamBound::RegionBound(_) => {
                panic!("cleaning a trait got a region")
            }
924 925 926 927 928 929 930 931 932
        };
        Type::QPath {
            name: self.item_name.clean(cx),
            self_type: box self.trait_ref.self_ty().clean(cx),
            trait_: box trait_
        }
    }
}

933
// maybe use a Generic enum and use Vec<Generic>?
J
Jorge Aparicio 已提交
934
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
C
Corey Richardson 已提交
935
pub struct Generics {
936 937
    pub lifetimes: Vec<Lifetime>,
    pub type_params: Vec<TyParam>,
938
    pub where_predicates: Vec<WherePredicate>
939
}
C
Corey Richardson 已提交
940

941
impl Clean<Generics> for hir::Generics {
942
    fn clean(&self, cx: &DocContext) -> Generics {
C
Corey Richardson 已提交
943
        Generics {
944 945
            lifetimes: self.lifetimes.clean(cx),
            type_params: self.ty_params.clean(cx),
946
            where_predicates: self.where_clause.predicates.clean(cx)
C
Corey Richardson 已提交
947 948 949 950
        }
    }
}

951
impl<'a, 'tcx> Clean<Generics> for (&'a ty::Generics<'tcx>,
952
                                    &'a ty::GenericPredicates<'tcx>) {
953
    fn clean(&self, cx: &DocContext) -> Generics {
954 955
        use self::WherePredicate as WP;

956
        let (gens, preds) = *self;
957

958 959 960
        // Bounds in the type_params and lifetimes fields are repeated in the
        // predicates field (see rustc_typeck::collect::ty_generics), so remove
        // them.
961
        let stripped_typarams = gens.types.iter().filter_map(|tp| {
962 963 964 965 966 967
            if tp.name == keywords::SelfType.name() {
                assert_eq!(tp.index, 0);
                None
            } else {
                Some(tp.clean(cx))
            }
968
        }).collect::<Vec<_>>();
969
        let stripped_lifetimes = gens.regions.iter().map(|rp| {
970 971 972 973 974
            let mut srp = rp.clone();
            srp.bounds = Vec::new();
            srp.clean(cx)
        }).collect::<Vec<_>>();

975
        let mut where_predicates = preds.predicates.to_vec().clean(cx);
976

977
        // Type parameters and have a Sized bound by default unless removed with
978 979
        // ?Sized.  Scan through the predicates and mark any type parameter with
        // a Sized bound, removing the bounds as we find them.
980 981
        //
        // Note that associated types also have a sized bound by default, but we
982
        // don't actually know the set of associated types right here so that's
983
        // handled in cleaning associated types
984
        let mut sized_params = FnvHashSet();
985 986 987 988 989 990 991 992 993
        where_predicates.retain(|pred| {
            match *pred {
                WP::BoundPredicate { ty: Generic(ref g), ref bounds } => {
                    if bounds.iter().any(|b| b.is_sized_bound(cx)) {
                        sized_params.insert(g.clone());
                        false
                    } else {
                        true
                    }
994
                }
995
                _ => true,
996
            }
997
        });
998

999
        // Run through the type parameters again and insert a ?Sized
1000
        // unbound for any we didn't find to be Sized.
1001
        for tp in &stripped_typarams {
1002 1003 1004
            if !sized_params.contains(&tp.name) {
                where_predicates.push(WP::BoundPredicate {
                    ty: Type::Generic(tp.name.clone()),
1005
                    bounds: vec![TyParamBound::maybe_sized(cx)],
1006 1007 1008 1009 1010 1011 1012 1013
                })
            }
        }

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

1014
        Generics {
1015
            type_params: simplify::ty_params(stripped_typarams),
1016
            lifetimes: stripped_lifetimes,
1017
            where_predicates: simplify::where_clauses(cx, where_predicates),
1018 1019 1020 1021
        }
    }
}

J
Jorge Aparicio 已提交
1022
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
1023
pub struct Method {
1024
    pub generics: Generics,
1025 1026
    pub unsafety: hir::Unsafety,
    pub constness: hir::Constness,
1027
    pub decl: FnDecl,
1028
    pub abi: Abi,
C
Corey Richardson 已提交
1029 1030
}

1031
impl Clean<Method> for hir::MethodSig {
1032
    fn clean(&self, cx: &DocContext) -> Method {
1033
        let decl = FnDecl {
1034
            inputs: Arguments {
1035
                values: self.decl.inputs.clean(cx),
1036
            },
1037
            output: self.decl.output.clean(cx),
1038
            variadic: false,
1039
            attrs: Vec::new()
1040
        };
1041
        Method {
1042
            generics: self.generics.clean(cx),
1043 1044
            unsafety: self.unsafety,
            constness: self.constness,
1045
            decl: decl,
1046
            abi: self.abi
C
Corey Richardson 已提交
1047 1048 1049 1050
        }
    }
}

J
Jorge Aparicio 已提交
1051
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
1052
pub struct TyMethod {
1053
    pub unsafety: hir::Unsafety,
1054 1055
    pub decl: FnDecl,
    pub generics: Generics,
1056
    pub abi: Abi,
C
Corey Richardson 已提交
1057 1058
}

1059
impl Clean<TyMethod> for hir::MethodSig {
1060
    fn clean(&self, cx: &DocContext) -> TyMethod {
1061
        let decl = FnDecl {
1062
            inputs: Arguments {
1063
                values: self.decl.inputs.clean(cx),
1064
            },
1065
            output: self.decl.output.clean(cx),
1066
            variadic: false,
1067
            attrs: Vec::new()
1068
        };
1069 1070 1071 1072 1073
        TyMethod {
            unsafety: self.unsafety.clone(),
            decl: decl,
            generics: self.generics.clean(cx),
            abi: self.abi
C
Corey Richardson 已提交
1074 1075 1076 1077
        }
    }
}

J
Jorge Aparicio 已提交
1078
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
1079
pub struct Function {
1080 1081
    pub decl: FnDecl,
    pub generics: Generics,
1082 1083
    pub unsafety: hir::Unsafety,
    pub constness: hir::Constness,
1084
    pub abi: Abi,
C
Corey Richardson 已提交
1085 1086 1087
}

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

J
Jorge Aparicio 已提交
1108
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
C
Corey Richardson 已提交
1109
pub struct FnDecl {
1110
    pub inputs: Arguments,
1111
    pub output: FunctionRetTy,
1112
    pub variadic: bool,
1113 1114
    pub attrs: Vec<Attribute>,
}
C
Corey Richardson 已提交
1115

1116 1117 1118 1119 1120 1121
impl FnDecl {
    pub fn has_self(&self) -> bool {
        return self.inputs.values.len() > 0 && self.inputs.values[0].name == "self";
    }
}

J
Jorge Aparicio 已提交
1122
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
1123
pub struct Arguments {
1124
    pub values: Vec<Argument>,
1125 1126
}

1127
impl Clean<FnDecl> for hir::FnDecl {
1128
    fn clean(&self, cx: &DocContext) -> FnDecl {
C
Corey Richardson 已提交
1129
        FnDecl {
1130
            inputs: Arguments {
1131
                values: self.inputs.clean(cx),
1132
            },
1133
            output: self.output.clean(cx),
1134
            variadic: self.variadic,
1135
            attrs: Vec::new()
C
Corey Richardson 已提交
1136 1137 1138 1139
        }
    }
}

N
Niko Matsakis 已提交
1140
impl<'a, 'tcx> Clean<FnDecl> for (DefId, &'a ty::PolyFnSig<'tcx>) {
1141
    fn clean(&self, cx: &DocContext) -> FnDecl {
1142
        let (did, sig) = *self;
M
mitaa 已提交
1143
        let mut names = if cx.map.as_local_node_id(did).is_some() {
1144
            vec![].into_iter()
1145
        } else {
A
Ariel Ben-Yehuda 已提交
1146
            cx.tcx().sess.cstore.method_arg_names(did).into_iter()
1147
        }.peekable();
1148
        FnDecl {
1149
            output: Return(sig.0.output.clean(cx)),
1150
            attrs: Vec::new(),
1151
            variadic: sig.0.variadic,
1152
            inputs: Arguments {
1153
                values: sig.0.inputs.iter().map(|t| {
1154
                    Argument {
1155
                        type_: t.clean(cx),
1156
                        id: 0,
1157
                        name: names.next().unwrap_or("".to_string()),
1158 1159 1160 1161 1162 1163 1164
                    }
                }).collect(),
            },
        }
    }
}

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

1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
pub enum SelfTy {
    SelfValue,
    SelfBorrowed(Option<Lifetime>, Mutability),
    SelfExplicit(Type),
}

impl Argument {
    pub fn to_self(&self) -> Option<SelfTy> {
        if self.name == "self" {
            match self.type_ {
                Infer => Some(SelfValue),
                BorrowedRef{ref lifetime, mutability, ref type_} if **type_ == Infer => {
                    Some(SelfBorrowed(lifetime.clone(), mutability))
                }
                _ => Some(SelfExplicit(self.type_.clone()))
            }
        } else {
            None
        }
    }
}

1195
impl Clean<Argument> for hir::Arg {
1196
    fn clean(&self, cx: &DocContext) -> Argument {
C
Corey Richardson 已提交
1197
        Argument {
1198
            name: name_from_pat(&*self.pat),
1199
            type_: (self.ty.clean(cx)),
C
Corey Richardson 已提交
1200 1201 1202 1203 1204
            id: self.id
        }
    }
}

J
Jorge Aparicio 已提交
1205
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
1206 1207
pub enum FunctionRetTy {
    Return(Type),
1208
    DefaultReturn,
C
Corey Richardson 已提交
1209 1210
}

1211
impl Clean<FunctionRetTy> for hir::FunctionRetTy {
1212
    fn clean(&self, cx: &DocContext) -> FunctionRetTy {
C
Corey Richardson 已提交
1213
        match *self {
1214 1215
            hir::Return(ref typ) => Return(typ.clean(cx)),
            hir::DefaultReturn(..) => DefaultReturn,
C
Corey Richardson 已提交
1216 1217 1218 1219
        }
    }
}

J
Jorge Aparicio 已提交
1220
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
1221
pub struct Trait {
1222
    pub unsafety: hir::Unsafety,
1223
    pub items: Vec<Item>,
1224
    pub generics: Generics,
1225
    pub bounds: Vec<TyParamBound>,
C
Corey Richardson 已提交
1226 1227 1228
}

impl Clean<Item> for doctree::Trait {
1229
    fn clean(&self, cx: &DocContext) -> Item {
C
Corey Richardson 已提交
1230
        Item {
1231 1232 1233
            name: Some(self.name.clean(cx)),
            attrs: self.attrs.clean(cx),
            source: self.whence.clean(cx),
1234
            def_id: cx.map.local_def_id(self.id),
1235 1236
            visibility: self.vis.clean(cx),
            stability: self.stab.clean(cx),
1237
            deprecation: self.depr.clean(cx),
C
Corey Richardson 已提交
1238
            inner: TraitItem(Trait {
1239
                unsafety: self.unsafety,
1240 1241 1242
                items: self.items.clean(cx),
                generics: self.generics.clean(cx),
                bounds: self.bounds.clean(cx),
C
Corey Richardson 已提交
1243 1244 1245 1246 1247
            }),
        }
    }
}

1248
impl Clean<Type> for hir::TraitRef {
1249
    fn clean(&self, cx: &DocContext) -> Type {
N
Niko Matsakis 已提交
1250
        resolve_type(cx, self.path.clean(cx), self.ref_id)
C
Corey Richardson 已提交
1251 1252 1253
    }
}

1254
impl Clean<PolyTrait> for hir::PolyTraitRef {
1255 1256 1257 1258 1259
    fn clean(&self, cx: &DocContext) -> PolyTrait {
        PolyTrait {
            trait_: self.trait_ref.clean(cx),
            lifetimes: self.bound_lifetimes.clean(cx)
        }
N
Niko Matsakis 已提交
1260 1261 1262
    }
}

1263
impl Clean<Item> for hir::TraitItem {
1264 1265
    fn clean(&self, cx: &DocContext) -> Item {
        let inner = match self.node {
1266
            hir::ConstTraitItem(ref ty, ref default) => {
1267
                AssociatedConstItem(ty.clean(cx),
1268
                                    default.as_ref().map(|e| pprust::expr_to_string(&e)))
1269
            }
1270
            hir::MethodTraitItem(ref sig, Some(_)) => {
1271 1272
                MethodItem(sig.clean(cx))
            }
1273
            hir::MethodTraitItem(ref sig, None) => {
1274 1275
                TyMethodItem(sig.clean(cx))
            }
1276
            hir::TypeTraitItem(ref bounds, ref default) => {
1277 1278 1279 1280
                AssociatedTypeItem(bounds.clean(cx), default.clean(cx))
            }
        };
        Item {
V
Vadim Petrochenkov 已提交
1281
            name: Some(self.name.clean(cx)),
1282 1283
            attrs: self.attrs.clean(cx),
            source: self.span.clean(cx),
1284
            def_id: cx.map.local_def_id(self.id),
1285
            visibility: None,
1286
            stability: get_stability(cx, cx.map.local_def_id(self.id)),
1287
            deprecation: get_deprecation(cx, cx.map.local_def_id(self.id)),
1288
            inner: inner
1289 1290 1291 1292
        }
    }
}

1293
impl Clean<Item> for hir::ImplItem {
1294 1295
    fn clean(&self, cx: &DocContext) -> Item {
        let inner = match self.node {
1296
            hir::ImplItemKind::Const(ref ty, ref expr) => {
1297
                AssociatedConstItem(ty.clean(cx),
1298
                                    Some(pprust::expr_to_string(expr)))
1299
            }
1300
            hir::ImplItemKind::Method(ref sig, _) => {
1301 1302
                MethodItem(sig.clean(cx))
            }
1303
            hir::ImplItemKind::Type(ref ty) => TypedefItem(Typedef {
1304 1305 1306 1307 1308 1309
                type_: ty.clean(cx),
                generics: Generics {
                    lifetimes: Vec::new(),
                    type_params: Vec::new(),
                    where_predicates: Vec::new()
                },
1310
            }, true),
1311 1312
        };
        Item {
V
Vadim Petrochenkov 已提交
1313
            name: Some(self.name.clean(cx)),
1314 1315
            source: self.span.clean(cx),
            attrs: self.attrs.clean(cx),
1316
            def_id: cx.map.local_def_id(self.id),
1317
            visibility: self.vis.clean(cx),
1318
            stability: get_stability(cx, cx.map.local_def_id(self.id)),
1319
            deprecation: get_deprecation(cx, cx.map.local_def_id(self.id)),
1320
            inner: inner
C
Corey Richardson 已提交
1321 1322 1323 1324
        }
    }
}

1325
impl<'tcx> Clean<Item> for ty::Method<'tcx> {
1326
    fn clean(&self, cx: &DocContext) -> Item {
1327
        let generics = (self.generics, &self.predicates).clean(cx);
1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340
        let mut decl = (self.def_id, &self.fty.sig).clean(cx);
        match self.explicit_self {
            ty::ExplicitSelfCategory::ByValue => {
                decl.inputs.values[0].type_ = Infer;
            }
            ty::ExplicitSelfCategory::ByReference(..) => {
                match decl.inputs.values[0].type_ {
                    BorrowedRef{ref mut type_, ..} => **type_ = Infer,
                    _ => unreachable!(),
                }
            }
            _ => {}
        }
1341 1342 1343
        let provided = match self.container {
            ty::ImplContainer(..) => false,
            ty::TraitContainer(did) => {
1344
                cx.tcx().provided_trait_methods(did).iter().any(|m| {
1345 1346 1347 1348 1349 1350 1351 1352 1353
                    m.def_id == self.def_id
                })
            }
        };
        let inner = if provided {
            MethodItem(Method {
                unsafety: self.fty.unsafety,
                generics: generics,
                decl: decl,
N
Niko Matsakis 已提交
1354 1355 1356
                abi: self.fty.abi,

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

1368
        Item {
1369
            name: Some(self.name.clean(cx)),
J
Jeffrey Seyfried 已提交
1370
            visibility: Some(Inherited),
1371
            stability: get_stability(cx, self.def_id),
1372
            deprecation: get_deprecation(cx, self.def_id),
1373
            def_id: self.def_id,
1374
            attrs: inline::load_attrs(cx, cx.tcx(), self.def_id),
1375
            source: Span::empty(),
1376
            inner: inner,
1377
        }
1378 1379 1380
    }
}

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

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

C
Corey Richardson 已提交
1398
/// A representation of a Type suitable for hyperlinking purposes. Ideally one can get the original
1399
/// type out of the AST/TyCtxt given one of these, if more information is needed. Most importantly
C
Corey Richardson 已提交
1400
/// it does not preserve mutability or boxes.
J
Jorge Aparicio 已提交
1401
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
C
Corey Richardson 已提交
1402
pub enum Type {
1403
    /// structs/enums/traits (most that'd be an hir::TyPath)
1404
    ResolvedPath {
S
Steven Fackler 已提交
1405 1406
        path: Path,
        typarams: Option<Vec<TyParamBound>>,
N
Niko Matsakis 已提交
1407
        did: DefId,
1408 1409
        /// true if is a `T::Name` path for associated types
        is_generic: bool,
1410
    },
1411 1412 1413
    /// For parameterized types, so the consumer of the JSON don't go
    /// looking for types which don't exist anywhere.
    Generic(String),
1414
    /// Primitives are the fixed-size numeric types (plus int/usize/float), char,
1415
    /// arrays, slices, and tuples.
1416
    Primitive(PrimitiveType),
C
Corey Richardson 已提交
1417
    /// extern "ABI" fn
1418
    BareFunction(Box<BareFunctionDecl>),
1419
    Tuple(Vec<Type>),
1420
    Vector(Box<Type>),
1421
    FixedVector(Box<Type>, String),
A
Andrew Cann 已提交
1422
    Never,
1423 1424
    Unique(Box<Type>),
    RawPointer(Mutability, Box<Type>),
1425
    BorrowedRef {
S
Steven Fackler 已提交
1426 1427 1428
        lifetime: Option<Lifetime>,
        mutability: Mutability,
        type_: Box<Type>,
1429
    },
1430 1431

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

    // _
    Infer,

    // for<'a> Foo(&'a)
    PolyTraitRef(Vec<TyParamBound>),
1443 1444 1445

    // impl TraitA+TraitB
    ImplTrait(Vec<TyParamBound>),
C
Corey Richardson 已提交
1446 1447
}

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

J
Jorge Aparicio 已提交
1462
#[derive(Clone, RustcEncodable, RustcDecodable, Copy, Debug)]
1463 1464 1465
pub enum TypeKind {
    TypeEnum,
    TypeFunction,
1466
    TypeModule,
1467
    TypeConst,
1468 1469
    TypeStatic,
    TypeStruct,
V
Vadim Petrochenkov 已提交
1470
    TypeUnion,
1471 1472
    TypeTrait,
    TypeVariant,
1473
    TypeTypedef,
1474 1475
}

1476 1477 1478 1479 1480 1481 1482 1483 1484 1485
pub trait GetDefId {
    fn def_id(&self) -> Option<DefId>;
}

impl<T: GetDefId> GetDefId for Option<T> {
    fn def_id(&self) -> Option<DefId> {
        self.as_ref().and_then(|d| d.def_id())
    }
}

1486 1487 1488 1489
impl Type {
    pub fn primitive_type(&self) -> Option<PrimitiveType> {
        match *self {
            Primitive(p) | BorrowedRef { type_: box Primitive(p), ..} => Some(p),
1490
            Vector(..) | BorrowedRef{ type_: box Vector(..), ..  } => Some(PrimitiveType::Slice),
1491
            FixedVector(..) | BorrowedRef { type_: box FixedVector(..), .. } => {
1492
                Some(PrimitiveType::Array)
1493
            }
1494 1495
            Tuple(..) => Some(PrimitiveType::Tuple),
            RawPointer(..) => Some(PrimitiveType::RawPointer),
1496 1497 1498
            _ => None,
        }
    }
1499

1500 1501 1502 1503 1504 1505
    pub fn is_generic(&self) -> bool {
        match *self {
            ResolvedPath { is_generic, .. } => is_generic,
            _ => false,
        }
    }
1506
}
1507

1508
impl GetDefId for Type {
1509 1510 1511 1512 1513 1514
    fn def_id(&self) -> Option<DefId> {
        match *self {
            ResolvedPath { did, .. } => Some(did),
            _ => None,
        }
    }
1515 1516
}

1517 1518
impl PrimitiveType {
    fn from_str(s: &str) -> Option<PrimitiveType> {
1519
        match s {
1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536
            "isize" => Some(PrimitiveType::Isize),
            "i8" => Some(PrimitiveType::I8),
            "i16" => Some(PrimitiveType::I16),
            "i32" => Some(PrimitiveType::I32),
            "i64" => Some(PrimitiveType::I64),
            "usize" => Some(PrimitiveType::Usize),
            "u8" => Some(PrimitiveType::U8),
            "u16" => Some(PrimitiveType::U16),
            "u32" => Some(PrimitiveType::U32),
            "u64" => Some(PrimitiveType::U64),
            "bool" => Some(PrimitiveType::Bool),
            "char" => Some(PrimitiveType::Char),
            "str" => Some(PrimitiveType::Str),
            "f32" => Some(PrimitiveType::F32),
            "f64" => Some(PrimitiveType::F64),
            "array" => Some(PrimitiveType::Array),
            "slice" => Some(PrimitiveType::Slice),
1537 1538
            "tuple" => Some(PrimitiveType::Tuple),
            "pointer" => Some(PrimitiveType::RawPointer),
1539 1540 1541 1542
            _ => None,
        }
    }

1543
    fn find(attrs: &[Attribute]) -> Option<PrimitiveType> {
1544
        for attr in attrs.list("doc") {
M
mitaa 已提交
1545 1546 1547 1548 1549
            if let NameValue(ref k, ref v) = *attr {
                if "primitive" == *k {
                    if let ret@Some(..) = PrimitiveType::from_str(v) {
                        return ret;
                    }
1550 1551 1552
                }
            }
        }
M
mitaa 已提交
1553
        None
1554 1555
    }

1556
    pub fn to_string(&self) -> &'static str {
1557
        match *self {
1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574
            PrimitiveType::Isize => "isize",
            PrimitiveType::I8 => "i8",
            PrimitiveType::I16 => "i16",
            PrimitiveType::I32 => "i32",
            PrimitiveType::I64 => "i64",
            PrimitiveType::Usize => "usize",
            PrimitiveType::U8 => "u8",
            PrimitiveType::U16 => "u16",
            PrimitiveType::U32 => "u32",
            PrimitiveType::U64 => "u64",
            PrimitiveType::F32 => "f32",
            PrimitiveType::F64 => "f64",
            PrimitiveType::Str => "str",
            PrimitiveType::Bool => "bool",
            PrimitiveType::Char => "char",
            PrimitiveType::Array => "array",
            PrimitiveType::Slice => "slice",
1575 1576
            PrimitiveType::Tuple => "tuple",
            PrimitiveType::RawPointer => "pointer",
1577 1578 1579 1580
        }
    }

    pub fn to_url_str(&self) -> &'static str {
1581
        self.to_string()
1582 1583 1584 1585 1586
    }

    /// Creates a rustdoc-specific node id for primitive types.
    ///
    /// These node ids are generally never used by the AST itself.
1587 1588 1589
    pub fn to_def_index(&self) -> DefIndex {
        let x = u32::MAX - 1 - (*self as u32);
        DefIndex::new(x as usize)
1590 1591 1592
    }
}

1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603
impl From<ast::IntTy> for PrimitiveType {
    fn from(int_ty: ast::IntTy) -> PrimitiveType {
        match int_ty {
            ast::IntTy::Is => PrimitiveType::Isize,
            ast::IntTy::I8 => PrimitiveType::I8,
            ast::IntTy::I16 => PrimitiveType::I16,
            ast::IntTy::I32 => PrimitiveType::I32,
            ast::IntTy::I64 => PrimitiveType::I64,
        }
    }
}
1604

1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616
impl From<ast::UintTy> for PrimitiveType {
    fn from(uint_ty: ast::UintTy) -> PrimitiveType {
        match uint_ty {
            ast::UintTy::Us => PrimitiveType::Usize,
            ast::UintTy::U8 => PrimitiveType::U8,
            ast::UintTy::U16 => PrimitiveType::U16,
            ast::UintTy::U32 => PrimitiveType::U32,
            ast::UintTy::U64 => PrimitiveType::U64,
        }
    }
}

1617 1618 1619 1620 1621 1622 1623 1624 1625
impl From<ast::FloatTy> for PrimitiveType {
    fn from(float_ty: ast::FloatTy) -> PrimitiveType {
        match float_ty {
            ast::FloatTy::F32 => PrimitiveType::F32,
            ast::FloatTy::F64 => PrimitiveType::F64,
        }
    }
}

1626 1627 1628 1629 1630
// Poor man's type parameter substitution at HIR level.
// Used to replace private type aliases in public signatures with their aliased types.
struct SubstAlias<'a, 'tcx: 'a> {
    tcx: &'a ty::TyCtxt<'a, 'tcx, 'tcx>,
    // Table type parameter definition -> substituted type
1631
    ty_substs: FnvHashMap<Def, hir::Ty>,
1632
    // Table node id of lifetime parameter definition -> substituted lifetime
1633
    lt_substs: FnvHashMap<ast::NodeId, hir::Lifetime>,
1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648
}

impl<'a, 'tcx: 'a, 'b: 'tcx> Folder for SubstAlias<'a, 'tcx> {
    fn fold_ty(&mut self, ty: P<hir::Ty>) -> P<hir::Ty> {
        if let hir::TyPath(..) = ty.node {
            let def = self.tcx.expect_def(ty.id);
            if let Some(new_ty) = self.ty_substs.get(&def).cloned() {
                return P(new_ty);
            }
        }
        hir::fold::noop_fold_ty(ty, self)
    }
    fn fold_lifetime(&mut self, lt: hir::Lifetime) -> hir::Lifetime {
        let def = self.tcx.named_region_map.defs.get(&lt.id).cloned();
        match def {
1649
            Some(DefEarlyBoundRegion(_, node_id)) |
1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661
            Some(DefLateBoundRegion(_, node_id)) |
            Some(DefFreeRegion(_, node_id)) => {
                if let Some(lt) = self.lt_substs.get(&node_id).cloned() {
                    return lt;
                }
            }
            _ => {}
        }
        hir::fold::noop_fold_lifetime(lt, self)
    }
}

1662
impl Clean<Type> for hir::Ty {
1663
    fn clean(&self, cx: &DocContext) -> Type {
1664
        use rustc::hir::*;
1665
        match self.node {
A
Andrew Cann 已提交
1666
            TyNever => Never,
1667
            TyPtr(ref m) => RawPointer(m.mutbl.clean(cx), box m.ty.clean(cx)),
1668
            TyRptr(ref l, ref m) =>
1669 1670
                BorrowedRef {lifetime: l.clean(cx), mutability: m.mutbl.clean(cx),
                             type_: box m.ty.clean(cx)},
1671
            TyVec(ref ty) => Vector(box ty.clean(cx)),
1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690
            TyFixedLengthVec(ref ty, ref e) => {
                let n = if let Some(tcx) = cx.tcx_opt() {
                    use rustc_const_math::{ConstInt, ConstUsize};
                    use rustc_const_eval::eval_const_expr;
                    use rustc::middle::const_val::ConstVal;
                    match eval_const_expr(tcx, e) {
                        ConstVal::Integral(ConstInt::Usize(u)) => match u {
                            ConstUsize::Us16(u) => u.to_string(),
                            ConstUsize::Us32(u) => u.to_string(),
                            ConstUsize::Us64(u) => u.to_string(),
                        },
                        // after type checking this can't fail
                        _ => unreachable!(),
                    }
                } else {
                    pprust::expr_to_string(e)
                };
                FixedVector(box ty.clean(cx), n)
            },
1691
            TyTup(ref tys) => Tuple(tys.clean(cx)),
1692 1693 1694 1695 1696 1697 1698 1699 1700 1701
            TyPath(None, ref path) => {
                if let Some(tcx) = cx.tcx_opt() {
                    // Substitute private type aliases
                    let def = tcx.expect_def(self.id);
                    if let Def::TyAlias(def_id) = def {
                        if let Some(node_id) = tcx.map.as_local_node_id(def_id) {
                            if !cx.access_levels.borrow().is_exported(def_id) {
                                let item = tcx.map.expect_item(node_id);
                                if let hir::ItemTy(ref ty, ref generics) = item.node {
                                    let provided_params = &path.segments.last().unwrap().parameters;
1702 1703
                                    let mut ty_substs = FnvHashMap();
                                    let mut lt_substs = FnvHashMap();
1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731
                                    for (i, ty_param) in generics.ty_params.iter().enumerate() {
                                        let ty_param_def = tcx.expect_def(ty_param.id);
                                        if let Some(ty) = provided_params.types().get(i).cloned()
                                                                                        .cloned() {
                                            ty_substs.insert(ty_param_def, ty.unwrap());
                                        } else if let Some(default) = ty_param.default.clone() {
                                            ty_substs.insert(ty_param_def, default.unwrap());
                                        }
                                    }
                                    for (i, lt_param) in generics.lifetimes.iter().enumerate() {
                                        if let Some(lt) = provided_params.lifetimes().get(i)
                                                                                     .cloned()
                                                                                     .cloned() {
                                            lt_substs.insert(lt_param.lifetime.id, lt);
                                        }
                                    }
                                    let mut subst_alias = SubstAlias {
                                        tcx: &tcx,
                                        ty_substs: ty_substs,
                                        lt_substs: lt_substs
                                    };
                                    return subst_alias.fold_ty(ty.clone()).clean(cx);
                                }
                            }
                        }
                    }
                }
                resolve_type(cx, path.clean(cx), self.id)
N
Niko Matsakis 已提交
1732
            }
1733
            TyPath(Some(ref qself), ref p) => {
1734 1735 1736 1737 1738 1739 1740
                let mut segments: Vec<_> = p.segments.clone().into();
                segments.pop();
                let trait_path = hir::Path {
                    span: p.span,
                    global: p.global,
                    segments: segments.into(),
                };
1741
                Type::QPath {
V
Vadim Petrochenkov 已提交
1742
                    name: p.segments.last().unwrap().name.clean(cx),
1743
                    self_type: box qself.ty.clean(cx),
1744
                    trait_: box resolve_type(cx, trait_path.clean(cx), self.id)
1745 1746
                }
            }
N
Niko Matsakis 已提交
1747 1748 1749
            TyObjectSum(ref lhs, ref bounds) => {
                let lhs_ty = lhs.clean(cx);
                match lhs_ty {
1750 1751 1752 1753 1754 1755 1756
                    ResolvedPath { path, typarams: None, did, is_generic } => {
                        ResolvedPath {
                            path: path,
                            typarams: Some(bounds.clean(cx)),
                            did: did,
                            is_generic: is_generic,
                        }
N
Niko Matsakis 已提交
1757 1758 1759 1760 1761
                    }
                    _ => {
                        lhs_ty // shouldn't happen
                    }
                }
1762
            }
1763
            TyBareFn(ref barefn) => BareFunction(box barefn.clean(cx)),
M
mitaa 已提交
1764
            TyPolyTraitRef(ref bounds) => PolyTraitRef(bounds.clean(cx)),
1765
            TyImplTrait(ref bounds) => ImplTrait(bounds.clean(cx)),
M
mitaa 已提交
1766 1767
            TyInfer => Infer,
            TyTypeof(..) => panic!("Unimplemented type {:?}", self.node),
1768
        }
C
Corey Richardson 已提交
1769 1770 1771
    }
}

1772
impl<'tcx> Clean<Type> for ty::Ty<'tcx> {
1773
    fn clean(&self, cx: &DocContext) -> Type {
1774
        match self.sty {
A
Andrew Cann 已提交
1775
            ty::TyNever => Never,
1776 1777
            ty::TyBool => Primitive(PrimitiveType::Bool),
            ty::TyChar => Primitive(PrimitiveType::Char),
1778
            ty::TyInt(int_ty) => Primitive(int_ty.into()),
1779
            ty::TyUint(uint_ty) => Primitive(uint_ty.into()),
1780
            ty::TyFloat(float_ty) => Primitive(float_ty.into()),
1781
            ty::TyStr => Primitive(PrimitiveType::Str),
1782
            ty::TyBox(t) => {
1783
                let box_did = cx.tcx_opt().and_then(|tcx| {
A
Alex Crichton 已提交
1784 1785
                    tcx.lang_items.owned_box()
                });
1786
                lang_struct(cx, box_did, t, "Box", Unique)
A
Alex Crichton 已提交
1787
            }
1788 1789 1790
            ty::TySlice(ty) => Vector(box ty.clean(cx)),
            ty::TyArray(ty, i) => FixedVector(box ty.clean(cx),
                                              format!("{}", i)),
1791 1792
            ty::TyRawPtr(mt) => RawPointer(mt.mutbl.clean(cx), box mt.ty.clean(cx)),
            ty::TyRef(r, mt) => BorrowedRef {
1793 1794 1795
                lifetime: r.clean(cx),
                mutability: mt.mutbl.clean(cx),
                type_: box mt.ty.clean(cx),
1796
            },
1797
            ty::TyFnDef(_, _, ref fty) |
1798
            ty::TyFnPtr(ref fty) => BareFunction(box BareFunctionDecl {
N
Niko Matsakis 已提交
1799
                unsafety: fty.unsafety,
1800
                generics: Generics {
1801 1802 1803
                    lifetimes: Vec::new(),
                    type_params: Vec::new(),
                    where_predicates: Vec::new()
1804
                },
1805
                decl: (cx.map.local_def_id(0), &fty.sig).clean(cx),
1806
                abi: fty.abi,
1807
            }),
1808
            ty::TyStruct(def, substs) |
V
Vadim Petrochenkov 已提交
1809
            ty::TyUnion(def, substs) |
1810 1811
            ty::TyEnum(def, substs) => {
                let did = def.did;
1812
                let kind = match self.sty {
1813
                    ty::TyStruct(..) => TypeStruct,
V
Vadim Petrochenkov 已提交
1814
                    ty::TyUnion(..) => TypeUnion,
1815 1816
                    _ => TypeEnum,
                };
M
mitaa 已提交
1817 1818
                inline::record_extern_fqn(cx, did, kind);
                let path = external_path(cx, &cx.tcx().item_name(did).as_str(),
1819
                                         None, false, vec![], substs);
1820
                ResolvedPath {
1821
                    path: path,
1822 1823
                    typarams: None,
                    did: did,
1824
                    is_generic: false,
1825 1826
                }
            }
1827 1828
            ty::TyTrait(ref obj) => {
                let did = obj.principal.def_id();
M
mitaa 已提交
1829
                inline::record_extern_fqn(cx, did, TypeTrait);
1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844

                let mut typarams = vec![];
                obj.region_bound.clean(cx).map(|b| typarams.push(RegionBound(b)));
                for bb in &obj.builtin_bounds {
                    typarams.push(bb.clean(cx));
                }

                let mut bindings = vec![];
                for &ty::Binder(ref pb) in &obj.projection_bounds {
                    bindings.push(TypeBinding {
                        name: pb.item_name.clean(cx),
                        ty: pb.ty.clean(cx)
                    });
                }

M
mitaa 已提交
1845
                let path = external_path(cx, &cx.tcx().item_name(did).as_str(),
1846
                                         Some(did), false, bindings, obj.principal.0.substs);
1847 1848
                ResolvedPath {
                    path: path,
1849
                    typarams: Some(typarams),
1850
                    did: did,
1851
                    is_generic: false,
1852 1853
                }
            }
1854
            ty::TyTuple(ref t) => Tuple(t.clean(cx)),
1855

1856
            ty::TyProjection(ref data) => data.clean(cx),
1857

1858
            ty::TyParam(ref p) => Generic(p.name.to_string()),
1859

1860 1861 1862 1863 1864 1865
            ty::TyAnon(def_id, substs) => {
                // Grab the "TraitA + TraitB" from `impl TraitA + TraitB`,
                // by looking up the projections associated with the def_id.
                let item_predicates = cx.tcx().lookup_predicates(def_id);
                let substs = cx.tcx().lift(&substs).unwrap();
                let bounds = item_predicates.instantiate(cx.tcx(), substs);
1866
                ImplTrait(bounds.predicates.into_iter().filter_map(|predicate| {
1867 1868 1869 1870
                    predicate.to_opt_poly_trait_ref().clean(cx)
                }).collect())
            }

1871
            ty::TyClosure(..) => Tuple(vec![]), // FIXME(pcwalton)
1872

1873 1874
            ty::TyInfer(..) => panic!("TyInfer"),
            ty::TyError => panic!("TyError"),
1875 1876 1877 1878
        }
    }
}

1879
impl Clean<Item> for hir::StructField {
1880
    fn clean(&self, cx: &DocContext) -> Item {
C
Corey Richardson 已提交
1881
        Item {
1882 1883
            name: Some(self.name).clean(cx),
            attrs: self.attrs.clean(cx),
1884
            source: self.span.clean(cx),
1885
            visibility: self.vis.clean(cx),
1886 1887 1888
            stability: get_stability(cx, cx.map.local_def_id(self.id)),
            deprecation: get_deprecation(cx, cx.map.local_def_id(self.id)),
            def_id: cx.map.local_def_id(self.id),
1889
            inner: StructFieldItem(self.ty.clean(cx)),
C
Corey Richardson 已提交
1890 1891 1892 1893
        }
    }
}

A
Ariel Ben-Yehuda 已提交
1894
impl<'tcx> Clean<Item> for ty::FieldDefData<'tcx, 'static> {
1895
    fn clean(&self, cx: &DocContext) -> Item {
A
Ariel Ben-Yehuda 已提交
1896
        // FIXME: possible O(n^2)-ness! Not my fault.
1897
        let attr_map = cx.tcx().sess.cstore.crate_struct_field_attrs(self.did.krate);
1898
        Item {
1899 1900
            name: Some(self.name).clean(cx),
            attrs: attr_map.get(&self.did).unwrap_or(&Vec::new()).clean(cx),
1901
            source: Span::empty(),
1902
            visibility: self.vis.clean(cx),
1903
            stability: get_stability(cx, self.did),
1904
            deprecation: get_deprecation(cx, self.did),
1905
            def_id: self.did,
1906
            inner: StructFieldItem(self.unsubst_ty().clean(cx)),
1907 1908 1909 1910
        }
    }
}

J
Jeffrey Seyfried 已提交
1911 1912 1913 1914 1915
#[derive(Clone, PartialEq, Eq, RustcDecodable, RustcEncodable, Debug)]
pub enum Visibility {
    Public,
    Inherited,
}
C
Corey Richardson 已提交
1916

1917
impl Clean<Option<Visibility>> for hir::Visibility {
1918
    fn clean(&self, _: &DocContext) -> Option<Visibility> {
J
Jeffrey Seyfried 已提交
1919
        Some(if *self == hir::Visibility::Public { Public } else { Inherited })
1920 1921 1922 1923 1924
    }
}

impl Clean<Option<Visibility>> for ty::Visibility {
    fn clean(&self, _: &DocContext) -> Option<Visibility> {
J
Jeffrey Seyfried 已提交
1925
        Some(if *self == ty::Visibility::Public { Public } else { Inherited })
C
Corey Richardson 已提交
1926 1927 1928
    }
}

J
Jorge Aparicio 已提交
1929
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
1930
pub struct Struct {
1931 1932 1933 1934
    pub struct_type: doctree::StructType,
    pub generics: Generics,
    pub fields: Vec<Item>,
    pub fields_stripped: bool,
C
Corey Richardson 已提交
1935 1936
}

V
Vadim Petrochenkov 已提交
1937 1938 1939 1940 1941 1942 1943 1944
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
pub struct Union {
    pub struct_type: doctree::StructType,
    pub generics: Generics,
    pub fields: Vec<Item>,
    pub fields_stripped: bool,
}

C
Corey Richardson 已提交
1945
impl Clean<Item> for doctree::Struct {
1946
    fn clean(&self, cx: &DocContext) -> Item {
C
Corey Richardson 已提交
1947
        Item {
1948 1949 1950
            name: Some(self.name.clean(cx)),
            attrs: self.attrs.clean(cx),
            source: self.whence.clean(cx),
1951
            def_id: cx.map.local_def_id(self.id),
1952 1953
            visibility: self.vis.clean(cx),
            stability: self.stab.clean(cx),
1954
            deprecation: self.depr.clean(cx),
C
Corey Richardson 已提交
1955 1956
            inner: StructItem(Struct {
                struct_type: self.struct_type,
1957 1958
                generics: self.generics.clean(cx),
                fields: self.fields.clean(cx),
S
Steven Fackler 已提交
1959
                fields_stripped: false,
C
Corey Richardson 已提交
1960 1961 1962 1963 1964
            }),
        }
    }
}

V
Vadim Petrochenkov 已提交
1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984
impl Clean<Item> for doctree::Union {
    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: cx.map.local_def_id(self.id),
            visibility: self.vis.clean(cx),
            stability: self.stab.clean(cx),
            deprecation: self.depr.clean(cx),
            inner: UnionItem(Union {
                struct_type: self.struct_type,
                generics: self.generics.clean(cx),
                fields: self.fields.clean(cx),
                fields_stripped: false,
            }),
        }
    }
}

1985
/// This is a more limited form of the standard Struct, different in that
C
Corey Richardson 已提交
1986 1987
/// it lacks the things most items have (name, id, parameterization). Found
/// only as a variant in an enum.
J
Jorge Aparicio 已提交
1988
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
1989
pub struct VariantStruct {
1990 1991 1992
    pub struct_type: doctree::StructType,
    pub fields: Vec<Item>,
    pub fields_stripped: bool,
C
Corey Richardson 已提交
1993 1994
}

1995
impl Clean<VariantStruct> for ::rustc::hir::VariantData {
1996
    fn clean(&self, cx: &DocContext) -> VariantStruct {
C
Corey Richardson 已提交
1997 1998
        VariantStruct {
            struct_type: doctree::struct_type_from_def(self),
1999
            fields: self.fields().iter().map(|x| x.clean(cx)).collect(),
S
Steven Fackler 已提交
2000
            fields_stripped: false,
C
Corey Richardson 已提交
2001 2002 2003 2004
        }
    }
}

J
Jorge Aparicio 已提交
2005
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
2006
pub struct Enum {
2007 2008 2009
    pub variants: Vec<Item>,
    pub generics: Generics,
    pub variants_stripped: bool,
C
Corey Richardson 已提交
2010 2011 2012
}

impl Clean<Item> for doctree::Enum {
2013
    fn clean(&self, cx: &DocContext) -> Item {
C
Corey Richardson 已提交
2014
        Item {
2015 2016 2017
            name: Some(self.name.clean(cx)),
            attrs: self.attrs.clean(cx),
            source: self.whence.clean(cx),
2018
            def_id: cx.map.local_def_id(self.id),
2019 2020
            visibility: self.vis.clean(cx),
            stability: self.stab.clean(cx),
2021
            deprecation: self.depr.clean(cx),
C
Corey Richardson 已提交
2022
            inner: EnumItem(Enum {
2023 2024
                variants: self.variants.clean(cx),
                generics: self.generics.clean(cx),
S
Steven Fackler 已提交
2025
                variants_stripped: false,
C
Corey Richardson 已提交
2026 2027 2028 2029 2030
            }),
        }
    }
}

J
Jorge Aparicio 已提交
2031
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
2032
pub struct Variant {
2033
    pub kind: VariantKind,
C
Corey Richardson 已提交
2034 2035 2036
}

impl Clean<Item> for doctree::Variant {
2037
    fn clean(&self, cx: &DocContext) -> Item {
C
Corey Richardson 已提交
2038
        Item {
2039 2040 2041
            name: Some(self.name.clean(cx)),
            attrs: self.attrs.clean(cx),
            source: self.whence.clean(cx),
2042
            visibility: None,
2043
            stability: self.stab.clean(cx),
2044
            deprecation: self.depr.clean(cx),
2045
            def_id: cx.map.local_def_id(self.def.id()),
C
Corey Richardson 已提交
2046
            inner: VariantItem(Variant {
2047
                kind: struct_def_to_variant_kind(&self.def, cx),
C
Corey Richardson 已提交
2048 2049 2050 2051 2052
            }),
        }
    }
}

A
Ariel Ben-Yehuda 已提交
2053
impl<'tcx> Clean<Item> for ty::VariantDefData<'tcx, 'static> {
2054
    fn clean(&self, cx: &DocContext) -> Item {
2055
        let kind = match self.kind {
2056 2057 2058 2059 2060
            ty::VariantKind::Unit => CLikeVariant,
            ty::VariantKind::Tuple => {
                TupleVariant(
                    self.fields.iter().map(|f| f.unsubst_ty().clean(cx)).collect()
                )
2061
            }
2062
            ty::VariantKind::Struct => {
2063 2064 2065
                StructVariant(VariantStruct {
                    struct_type: doctree::Plain,
                    fields_stripped: false,
2066
                    fields: self.fields.iter().map(|field| {
2067 2068
                        Item {
                            source: Span::empty(),
2069
                            name: Some(field.name.clean(cx)),
2070
                            attrs: cx.tcx().get_attrs(field.did).clean(cx),
2071
                            visibility: field.vis.clean(cx),
2072 2073 2074
                            def_id: field.did,
                            stability: get_stability(cx, field.did),
                            deprecation: get_deprecation(cx, field.did),
2075
                            inner: StructFieldItem(field.unsubst_ty().clean(cx))
2076 2077 2078 2079 2080 2081
                        }
                    }).collect()
                })
            }
        };
        Item {
2082
            name: Some(self.name.clean(cx)),
2083
            attrs: inline::load_attrs(cx, cx.tcx(), self.did),
2084
            source: Span::empty(),
J
Jeffrey Seyfried 已提交
2085
            visibility: Some(Inherited),
2086
            def_id: self.did,
2087
            inner: VariantItem(Variant { kind: kind }),
2088
            stability: get_stability(cx, self.did),
2089
            deprecation: get_deprecation(cx, self.did),
2090 2091 2092 2093
        }
    }
}

J
Jorge Aparicio 已提交
2094
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
2095 2096
pub enum VariantKind {
    CLikeVariant,
2097
    TupleVariant(Vec<Type>),
C
Corey Richardson 已提交
2098 2099 2100
    StructVariant(VariantStruct),
}

2101
fn struct_def_to_variant_kind(struct_def: &hir::VariantData, cx: &DocContext) -> VariantKind {
2102
    if struct_def.is_struct() {
2103
        StructVariant(struct_def.clean(cx))
2104
    } else if struct_def.is_unit() {
2105 2106
        CLikeVariant
    } else {
2107
        TupleVariant(struct_def.fields().iter().map(|x| x.ty.clean(cx)).collect())
2108 2109 2110
    }
}

J
Jorge Aparicio 已提交
2111
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
2112
pub struct Span {
2113
    pub filename: String,
2114 2115 2116 2117
    pub loline: usize,
    pub locol: usize,
    pub hiline: usize,
    pub hicol: usize,
2118 2119
}

2120 2121 2122
impl Span {
    fn empty() -> Span {
        Span {
2123
            filename: "".to_string(),
2124 2125 2126 2127 2128 2129
            loline: 0, locol: 0,
            hiline: 0, hicol: 0,
        }
    }
}

2130
impl Clean<Span> for syntax_pos::Span {
2131
    fn clean(&self, cx: &DocContext) -> Span {
2132 2133 2134 2135
        if *self == DUMMY_SP {
            return Span::empty();
        }

2136
        let cm = cx.sess().codemap();
2137 2138 2139 2140
        let filename = cm.span_to_filename(*self);
        let lo = cm.lookup_char_pos(self.lo);
        let hi = cm.lookup_char_pos(self.hi);
        Span {
2141
            filename: filename.to_string(),
2142
            loline: lo.line,
2143
            locol: lo.col.to_usize(),
2144
            hiline: hi.line,
2145
            hicol: hi.col.to_usize(),
2146
        }
C
Corey Richardson 已提交
2147 2148 2149
    }
}

J
Jorge Aparicio 已提交
2150
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
C
Corey Richardson 已提交
2151
pub struct Path {
2152 2153
    pub global: bool,
    pub segments: Vec<PathSegment>,
C
Corey Richardson 已提交
2154 2155
}

2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169
impl Path {
    pub fn singleton(name: String) -> Path {
        Path {
            global: false,
            segments: vec![PathSegment {
                name: name,
                params: PathParameters::AngleBracketed {
                    lifetimes: Vec::new(),
                    types: Vec::new(),
                    bindings: Vec::new()
                }
            }]
        }
    }
2170 2171 2172 2173

    pub fn last_name(&self) -> String {
        self.segments.last().unwrap().name.clone()
    }
2174 2175
}

2176
impl Clean<Path> for hir::Path {
2177
    fn clean(&self, cx: &DocContext) -> Path {
C
Corey Richardson 已提交
2178
        Path {
2179
            global: self.global,
2180
            segments: self.segments.clean(cx),
2181 2182 2183 2184
        }
    }
}

J
Jorge Aparicio 已提交
2185
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
2186 2187 2188 2189
pub enum PathParameters {
    AngleBracketed {
        lifetimes: Vec<Lifetime>,
        types: Vec<Type>,
2190
        bindings: Vec<TypeBinding>
2191 2192 2193 2194 2195
    },
    Parenthesized {
        inputs: Vec<Type>,
        output: Option<Type>
    }
2196 2197
}

2198
impl Clean<PathParameters> for hir::PathParameters {
2199 2200
    fn clean(&self, cx: &DocContext) -> PathParameters {
        match *self {
2201
            hir::AngleBracketedParameters(ref data) => {
2202 2203
                PathParameters::AngleBracketed {
                    lifetimes: data.lifetimes.clean(cx),
2204 2205
                    types: data.types.clean(cx),
                    bindings: data.bindings.clean(cx)
2206
                }
2207 2208
            }

2209
            hir::ParenthesizedParameters(ref data) => {
2210 2211 2212 2213
                PathParameters::Parenthesized {
                    inputs: data.inputs.clean(cx),
                    output: data.output.clean(cx)
                }
2214
            }
2215 2216 2217
        }
    }
}
2218

J
Jorge Aparicio 已提交
2219
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
2220 2221 2222 2223 2224
pub struct PathSegment {
    pub name: String,
    pub params: PathParameters
}

2225
impl Clean<PathSegment> for hir::PathSegment {
2226
    fn clean(&self, cx: &DocContext) -> PathSegment {
2227
        PathSegment {
V
Vadim Petrochenkov 已提交
2228
            name: self.name.clean(cx),
2229
            params: self.parameters.clean(cx)
C
Corey Richardson 已提交
2230 2231 2232 2233
        }
    }
}

2234
fn path_to_string(p: &hir::Path) -> String {
2235
    let mut s = String::new();
C
Corey Richardson 已提交
2236
    let mut first = true;
V
Vadim Petrochenkov 已提交
2237
    for i in p.segments.iter().map(|x| x.name.as_str()) {
C
Corey Richardson 已提交
2238 2239 2240 2241 2242
        if !first || p.global {
            s.push_str("::");
        } else {
            first = false;
        }
G
GuillaumeGomez 已提交
2243
        s.push_str(&i);
C
Corey Richardson 已提交
2244
    }
2245
    s
C
Corey Richardson 已提交
2246 2247
}

2248
impl Clean<String> for ast::Name {
2249
    fn clean(&self, _: &DocContext) -> String {
2250
        self.to_string()
2251 2252 2253
    }
}

J
Jorge Aparicio 已提交
2254
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
2255
pub struct Typedef {
2256 2257
    pub type_: Type,
    pub generics: Generics,
C
Corey Richardson 已提交
2258 2259 2260
}

impl Clean<Item> for doctree::Typedef {
2261
    fn clean(&self, cx: &DocContext) -> Item {
C
Corey Richardson 已提交
2262
        Item {
2263 2264 2265
            name: Some(self.name.clean(cx)),
            attrs: self.attrs.clean(cx),
            source: self.whence.clean(cx),
2266
            def_id: cx.map.local_def_id(self.id.clone()),
2267 2268
            visibility: self.vis.clean(cx),
            stability: self.stab.clean(cx),
2269
            deprecation: self.depr.clean(cx),
C
Corey Richardson 已提交
2270
            inner: TypedefItem(Typedef {
2271 2272
                type_: self.ty.clean(cx),
                generics: self.gen.clean(cx),
2273
            }, false),
C
Corey Richardson 已提交
2274 2275 2276 2277
        }
    }
}

J
Jorge Aparicio 已提交
2278
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
C
Corey Richardson 已提交
2279
pub struct BareFunctionDecl {
2280
    pub unsafety: hir::Unsafety,
2281 2282
    pub generics: Generics,
    pub decl: FnDecl,
2283
    pub abi: Abi,
C
Corey Richardson 已提交
2284 2285
}

2286
impl Clean<BareFunctionDecl> for hir::BareFnTy {
2287
    fn clean(&self, cx: &DocContext) -> BareFunctionDecl {
C
Corey Richardson 已提交
2288
        BareFunctionDecl {
N
Niko Matsakis 已提交
2289
            unsafety: self.unsafety,
C
Corey Richardson 已提交
2290
            generics: Generics {
2291
                lifetimes: self.lifetimes.clean(cx),
2292
                type_params: Vec::new(),
2293
                where_predicates: Vec::new()
C
Corey Richardson 已提交
2294
            },
2295
            decl: self.decl.clean(cx),
2296
            abi: self.abi,
C
Corey Richardson 已提交
2297 2298 2299 2300
        }
    }
}

J
Jorge Aparicio 已提交
2301
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
2302
pub struct Static {
2303 2304
    pub type_: Type,
    pub mutability: Mutability,
C
Corey Richardson 已提交
2305 2306 2307
    /// 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.
2308
    pub expr: String,
C
Corey Richardson 已提交
2309 2310 2311
}

impl Clean<Item> for doctree::Static {
2312
    fn clean(&self, cx: &DocContext) -> Item {
2313
        debug!("cleaning static {}: {:?}", self.name.clean(cx), self);
C
Corey Richardson 已提交
2314
        Item {
2315 2316 2317
            name: Some(self.name.clean(cx)),
            attrs: self.attrs.clean(cx),
            source: self.whence.clean(cx),
2318
            def_id: cx.map.local_def_id(self.id),
2319 2320
            visibility: self.vis.clean(cx),
            stability: self.stab.clean(cx),
2321
            deprecation: self.depr.clean(cx),
C
Corey Richardson 已提交
2322
            inner: StaticItem(Static {
2323 2324
                type_: self.type_.clean(cx),
                mutability: self.mutability.clean(cx),
2325
                expr: pprust::expr_to_string(&self.expr),
C
Corey Richardson 已提交
2326 2327 2328 2329 2330
            }),
        }
    }
}

J
Jorge Aparicio 已提交
2331
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342
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),
2343
            def_id: cx.map.local_def_id(self.id),
2344 2345
            visibility: self.vis.clean(cx),
            stability: self.stab.clean(cx),
2346
            deprecation: self.depr.clean(cx),
2347 2348
            inner: ConstantItem(Constant {
                type_: self.type_.clean(cx),
2349
                expr: pprust::expr_to_string(&self.expr),
2350 2351 2352 2353 2354
            }),
        }
    }
}

J
Jorge Aparicio 已提交
2355
#[derive(Debug, Clone, RustcEncodable, RustcDecodable, PartialEq, Copy)]
C
Corey Richardson 已提交
2356 2357 2358 2359 2360
pub enum Mutability {
    Mutable,
    Immutable,
}

2361
impl Clean<Mutability> for hir::Mutability {
2362
    fn clean(&self, _: &DocContext) -> Mutability {
C
Corey Richardson 已提交
2363
        match self {
2364 2365
            &hir::MutMutable => Mutable,
            &hir::MutImmutable => Immutable,
C
Corey Richardson 已提交
2366 2367 2368 2369
        }
    }
}

J
Jorge Aparicio 已提交
2370
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Copy, Debug)]
2371 2372 2373 2374 2375
pub enum ImplPolarity {
    Positive,
    Negative,
}

2376
impl Clean<ImplPolarity> for hir::ImplPolarity {
2377 2378
    fn clean(&self, _: &DocContext) -> ImplPolarity {
        match self {
2379 2380
            &hir::ImplPolarity::Positive => ImplPolarity::Positive,
            &hir::ImplPolarity::Negative => ImplPolarity::Negative,
2381 2382 2383 2384
        }
    }
}

J
Jorge Aparicio 已提交
2385
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
2386
pub struct Impl {
2387
    pub unsafety: hir::Unsafety,
2388
    pub generics: Generics,
2389
    pub provided_trait_methods: FnvHashSet<String>,
2390 2391
    pub trait_: Option<Type>,
    pub for_: Type,
2392
    pub items: Vec<Item>,
2393
    pub polarity: Option<ImplPolarity>,
C
Corey Richardson 已提交
2394 2395
}

2396 2397 2398 2399 2400 2401 2402 2403
impl Clean<Vec<Item>> for doctree::Impl {
    fn clean(&self, cx: &DocContext) -> Vec<Item> {
        let mut ret = Vec::new();
        let trait_ = self.trait_.clean(cx);
        let items = self.items.clean(cx);

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

2408 2409 2410 2411 2412 2413 2414
        let provided = trait_.def_id().and_then(|did| {
            cx.tcx_opt().map(|tcx| {
                tcx.provided_trait_methods(did)
                   .into_iter()
                   .map(|meth| meth.name.to_string())
                   .collect()
            })
2415
        }).unwrap_or(FnvHashSet());
2416

2417
        ret.push(Item {
C
Corey Richardson 已提交
2418
            name: None,
2419 2420
            attrs: self.attrs.clean(cx),
            source: self.whence.clean(cx),
2421
            def_id: cx.map.local_def_id(self.id),
2422 2423
            visibility: self.vis.clean(cx),
            stability: self.stab.clean(cx),
2424
            deprecation: self.depr.clean(cx),
C
Corey Richardson 已提交
2425
            inner: ImplItem(Impl {
2426
                unsafety: self.unsafety,
2427
                generics: self.generics.clean(cx),
2428
                provided_trait_methods: provided,
2429
                trait_: trait_,
2430
                for_: self.for_.clean(cx),
2431
                items: items,
2432
                polarity: Some(self.polarity.clean(cx)),
C
Corey Richardson 已提交
2433
            }),
2434
        });
M
mitaa 已提交
2435
        ret
2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448
    }
}

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

    for item in items {
        let target = match item.inner {
2449
            TypedefItem(ref t, true) => &t.type_,
2450 2451 2452
            _ => continue,
        };
        let primitive = match *target {
N
Niko Matsakis 已提交
2453
            ResolvedPath { did, .. } if did.is_local() => continue,
2454 2455 2456 2457 2458 2459 2460 2461 2462 2463
            ResolvedPath { did, .. } => {
                ret.extend(inline::build_impls(cx, tcx, did));
                continue
            }
            _ => match target.primitive_type() {
                Some(prim) => prim,
                None => continue,
            }
        };
        let did = match primitive {
2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480
            PrimitiveType::Isize => tcx.lang_items.isize_impl(),
            PrimitiveType::I8 => tcx.lang_items.i8_impl(),
            PrimitiveType::I16 => tcx.lang_items.i16_impl(),
            PrimitiveType::I32 => tcx.lang_items.i32_impl(),
            PrimitiveType::I64 => tcx.lang_items.i64_impl(),
            PrimitiveType::Usize => tcx.lang_items.usize_impl(),
            PrimitiveType::U8 => tcx.lang_items.u8_impl(),
            PrimitiveType::U16 => tcx.lang_items.u16_impl(),
            PrimitiveType::U32 => tcx.lang_items.u32_impl(),
            PrimitiveType::U64 => tcx.lang_items.u64_impl(),
            PrimitiveType::F32 => tcx.lang_items.f32_impl(),
            PrimitiveType::F64 => tcx.lang_items.f64_impl(),
            PrimitiveType::Char => tcx.lang_items.char_impl(),
            PrimitiveType::Bool => None,
            PrimitiveType::Str => tcx.lang_items.str_impl(),
            PrimitiveType::Slice => tcx.lang_items.slice_impl(),
            PrimitiveType::Array => tcx.lang_items.slice_impl(),
2481 2482
            PrimitiveType::Tuple => None,
            PrimitiveType::RawPointer => tcx.lang_items.const_ptr_impl(),
2483 2484
        };
        if let Some(did) = did {
N
Niko Matsakis 已提交
2485
            if !did.is_local() {
2486 2487
                inline::build_impl(cx, tcx, did, ret);
            }
C
Corey Richardson 已提交
2488 2489 2490 2491
        }
    }
}

2492 2493
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
pub struct DefaultImpl {
2494
    pub unsafety: hir::Unsafety,
2495 2496 2497 2498 2499 2500 2501 2502 2503
    pub trait_: Type,
}

impl Clean<Item> for doctree::DefaultImpl {
    fn clean(&self, cx: &DocContext) -> Item {
        Item {
            name: None,
            attrs: self.attrs.clean(cx),
            source: self.whence.clean(cx),
2504
            def_id: cx.map.local_def_id(self.id),
J
Jeffrey Seyfried 已提交
2505
            visibility: Some(Public),
2506
            stability: None,
2507
            deprecation: None,
2508 2509 2510 2511 2512 2513 2514 2515
            inner: DefaultImplItem(DefaultImpl {
                unsafety: self.unsafety,
                trait_: self.trait_.clean(cx),
            }),
        }
    }
}

2516 2517 2518 2519 2520 2521
impl Clean<Item> for doctree::ExternCrate {
    fn clean(&self, cx: &DocContext) -> Item {
        Item {
            name: None,
            attrs: self.attrs.clean(cx),
            source: self.whence.clean(cx),
M
mitaa 已提交
2522
            def_id: DefId { krate: self.cnum, index: CRATE_DEF_INDEX },
2523 2524
            visibility: self.vis.clean(cx),
            stability: None,
2525
            deprecation: None,
2526 2527 2528
            inner: ExternCrateItem(self.name.clean(cx), self.path.clone())
        }
    }
C
Corey Richardson 已提交
2529 2530
}

2531
impl Clean<Vec<Item>> for doctree::Import {
2532
    fn clean(&self, cx: &DocContext) -> Vec<Item> {
J
Joseph Crail 已提交
2533
        // We consider inlining the documentation of `pub use` statements, but we
2534 2535
        // forcefully don't inline if this is not public or if the
        // #[doc(no_inline)] attribute is present.
2536
        // Don't inline doc(hidden) imports so they can be stripped at a later stage.
2537
        let denied = self.vis != hir::Public || self.attrs.iter().any(|a| {
2538
            &a.name()[..] == "doc" && match a.meta_item_list() {
2539 2540
                Some(l) => attr::list_contains_name(l, "no_inline") ||
                           attr::list_contains_name(l, "hidden"),
2541 2542 2543
                None => false,
            }
        });
2544
        let (mut ret, inner) = match self.node {
2545
            hir::ViewPathGlob(ref p) => {
2546
                (vec![], GlobImport(resolve_use_source(cx, p.clean(cx), self.id)))
2547
            }
2548
            hir::ViewPathList(ref p, ref list) => {
2549 2550 2551 2552 2553 2554
                // Attempt to inline all reexported items, but be sure
                // to keep any non-inlineable reexports so they can be
                // listed in the documentation.
                let mut ret = vec![];
                let remaining = if !denied {
                    let mut remaining = vec![];
2555
                    for path in list {
J
Jeffrey Seyfried 已提交
2556
                        match inline::try_inline(cx, path.node.id, path.node.rename) {
2557
                            Some(items) => {
2558
                                ret.extend(items);
2559 2560 2561
                            }
                            None => {
                                remaining.push(path.clean(cx));
2562 2563 2564
                            }
                        }
                    }
2565 2566 2567
                    remaining
                } else {
                    list.clean(cx)
P
Patrick Walton 已提交
2568
                };
2569 2570 2571 2572 2573
                if remaining.is_empty() {
                    return ret;
                }
                (ret, ImportList(resolve_use_source(cx, p.clean(cx), self.id),
                                 remaining))
P
Patrick Walton 已提交
2574
            }
2575
            hir::ViewPathSimple(name, ref p) => {
2576
                if !denied {
M
mitaa 已提交
2577 2578
                    if let Some(items) = inline::try_inline(cx, self.id, Some(name)) {
                        return items;
2579 2580
                    }
                }
2581
                (vec![], SimpleImport(name.clean(cx),
2582
                                      resolve_use_source(cx, p.clean(cx), self.id)))
2583
            }
2584 2585 2586 2587 2588
        };
        ret.push(Item {
            name: None,
            attrs: self.attrs.clean(cx),
            source: self.whence.clean(cx),
2589
            def_id: cx.map.local_def_id(0),
2590 2591
            visibility: self.vis.clean(cx),
            stability: None,
2592
            deprecation: None,
2593 2594 2595
            inner: ImportItem(inner)
        });
        ret
C
Corey Richardson 已提交
2596 2597 2598
    }
}

J
Jorge Aparicio 已提交
2599
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
2600
pub enum Import {
2601
    // use source as str;
2602
    SimpleImport(String, ImportSource),
A
Alex Crichton 已提交
2603 2604 2605
    // use source::*;
    GlobImport(ImportSource),
    // use source::{a, b, c};
2606
    ImportList(ImportSource, Vec<ViewListIdent>),
A
Alex Crichton 已提交
2607 2608
}

J
Jorge Aparicio 已提交
2609
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
A
Alex Crichton 已提交
2610
pub struct ImportSource {
2611
    pub path: Path,
N
Niko Matsakis 已提交
2612
    pub did: Option<DefId>,
C
Corey Richardson 已提交
2613 2614
}

J
Jorge Aparicio 已提交
2615
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
A
Alex Crichton 已提交
2616
pub struct ViewListIdent {
2617
    pub name: String,
2618
    pub rename: Option<String>,
N
Niko Matsakis 已提交
2619
    pub source: Option<DefId>,
A
Alex Crichton 已提交
2620
}
C
Corey Richardson 已提交
2621

2622
impl Clean<ViewListIdent> for hir::PathListItem {
2623
    fn clean(&self, cx: &DocContext) -> ViewListIdent {
J
Jeffrey Seyfried 已提交
2624 2625 2626 2627
        ViewListIdent {
            name: self.node.name.clean(cx),
            rename: self.node.rename.map(|r| r.clean(cx)),
            source: resolve_def(cx, self.node.id)
A
Alex Crichton 已提交
2628
        }
C
Corey Richardson 已提交
2629 2630 2631
    }
}

2632
impl Clean<Vec<Item>> for hir::ForeignMod {
2633
    fn clean(&self, cx: &DocContext) -> Vec<Item> {
2634 2635
        let mut items = self.items.clean(cx);
        for item in &mut items {
M
mitaa 已提交
2636 2637
            if let ForeignFunctionItem(ref mut f) = item.inner {
                f.abi = self.abi;
2638 2639 2640
            }
        }
        items
2641 2642 2643
    }
}

2644
impl Clean<Item> for hir::ForeignItem {
2645
    fn clean(&self, cx: &DocContext) -> Item {
2646
        let inner = match self.node {
2647
            hir::ForeignItemFn(ref decl, ref generics) => {
2648
                ForeignFunctionItem(Function {
2649 2650
                    decl: decl.clean(cx),
                    generics: generics.clean(cx),
2651
                    unsafety: hir::Unsafety::Unsafe,
2652
                    abi: Abi::Rust,
2653
                    constness: hir::Constness::NotConst,
2654 2655
                })
            }
2656
            hir::ForeignItemStatic(ref ty, mutbl) => {
2657
                ForeignStaticItem(Static {
2658
                    type_: ty.clean(cx),
2659
                    mutability: if mutbl {Mutable} else {Immutable},
2660
                    expr: "".to_string(),
2661 2662 2663 2664
                })
            }
        };
        Item {
V
Vadim Petrochenkov 已提交
2665
            name: Some(self.name.clean(cx)),
2666 2667
            attrs: self.attrs.clean(cx),
            source: self.span.clean(cx),
2668
            def_id: cx.map.local_def_id(self.id),
2669
            visibility: self.vis.clean(cx),
2670
            stability: get_stability(cx, cx.map.local_def_id(self.id)),
2671
            deprecation: get_deprecation(cx, cx.map.local_def_id(self.id)),
2672 2673 2674 2675 2676
            inner: inner,
        }
    }
}

C
Corey Richardson 已提交
2677 2678 2679
// Utilities

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

2683
impl ToSource for syntax_pos::Span {
2684
    fn to_src(&self, cx: &DocContext) -> String {
2685
        debug!("converting span {:?} to snippet", self.clean(cx));
2686
        let sn = match cx.sess().codemap().span_to_snippet(*self) {
2687 2688
            Ok(x) => x.to_string(),
            Err(_) => "".to_string()
C
Corey Richardson 已提交
2689
        };
2690
        debug!("got snippet {}", sn);
C
Corey Richardson 已提交
2691 2692 2693 2694
        sn
    }
}

2695
fn name_from_pat(p: &hir::Pat) -> String {
2696
    use rustc::hir::*;
2697
    debug!("Trying to get a name from pattern: {:?}", p);
2698

C
Corey Richardson 已提交
2699
    match p.node {
2700
        PatKind::Wild => "_".to_string(),
2701
        PatKind::Binding(_, ref p, _) => p.node.to_string(),
2702 2703 2704
        PatKind::TupleStruct(ref p, _, _) | PatKind::Path(None, ref p) => path_to_string(p),
        PatKind::Path(..) => panic!("tried to get argument name from qualified PatKind::Path, \
                                     which is not allowed in function arguments"),
2705
        PatKind::Struct(ref name, ref fields, etc) => {
2706
            format!("{} {{ {}{} }}", path_to_string(name),
2707
                fields.iter().map(|&Spanned { node: ref fp, .. }|
2708
                                  format!("{}: {}", fp.name, name_from_pat(&*fp.pat)))
2709
                             .collect::<Vec<String>>().join(", "),
2710 2711 2712
                if etc { ", ..." } else { "" }
            )
        },
2713
        PatKind::Tuple(ref elts, _) => format!("({})", elts.iter().map(|p| name_from_pat(&**p))
2714
                                            .collect::<Vec<String>>().join(", ")),
2715 2716 2717 2718
        PatKind::Box(ref p) => name_from_pat(&**p),
        PatKind::Ref(ref p, _) => name_from_pat(&**p),
        PatKind::Lit(..) => {
            warn!("tried to get argument name from PatKind::Lit, \
2719
                  which is silly in function arguments");
2720
            "()".to_string()
2721
        },
2722
        PatKind::Range(..) => panic!("tried to get argument name from PatKind::Range, \
2723
                              which is not allowed in function arguments"),
2724
        PatKind::Vec(ref begin, ref mid, ref end) => {
2725 2726 2727
            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));
2728
            format!("[{}]", begin.chain(mid).chain(end).collect::<Vec<_>>().join(", "))
2729
        },
C
Corey Richardson 已提交
2730 2731 2732 2733
    }
}

/// Given a Type, resolve it using the def_map
N
Niko Matsakis 已提交
2734 2735
fn resolve_type(cx: &DocContext,
                path: Path,
2736
                id: ast::NodeId) -> Type {
2737
    debug!("resolve_type({:?},{:?})", path, id);
2738 2739
    let tcx = match cx.tcx_opt() {
        Some(tcx) => tcx,
2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751
        // If we're extracting tests, this return value's accuracy is not
        // important, all we want is a string representation to help people
        // figure out what doctests are failing.
        None => {
            let did = DefId::local(DefIndex::from_u32(0));
            return ResolvedPath {
                path: path,
                typarams: None,
                did: did,
                is_generic: false
            };
        }
2752
    };
2753
    let def = tcx.expect_def(id);
2754 2755
    debug!("resolve_type: def={:?}", def);

2756
    let is_generic = match def {
2757
        Def::PrimTy(p) => match p {
2758 2759 2760
            hir::TyStr => return Primitive(PrimitiveType::Str),
            hir::TyBool => return Primitive(PrimitiveType::Bool),
            hir::TyChar => return Primitive(PrimitiveType::Char),
2761
            hir::TyInt(int_ty) => return Primitive(int_ty.into()),
2762
            hir::TyUint(uint_ty) => return Primitive(uint_ty.into()),
2763
            hir::TyFloat(float_ty) => return Primitive(float_ty.into()),
C
Corey Richardson 已提交
2764
        },
2765
        Def::SelfTy(..) if path.segments.len() == 1 => {
2766
            return Generic(keywords::SelfType.name().to_string());
2767
        }
2768
        Def::SelfTy(..) | Def::TyParam(..) | Def::AssociatedTy(..) => true,
2769
        _ => false,
2770
    };
2771
    let did = register_def(&*cx, def);
2772
    ResolvedPath { path: path, typarams: None, did: did, is_generic: is_generic }
2773 2774
}

2775
fn register_def(cx: &DocContext, def: Def) -> DefId {
2776 2777
    debug!("register_def({:?})", def);

2778
    let (did, kind) = match def {
2779 2780 2781 2782 2783
        Def::Fn(i) => (i, TypeFunction),
        Def::TyAlias(i) => (i, TypeTypedef),
        Def::Enum(i) => (i, TypeEnum),
        Def::Trait(i) => (i, TypeTrait),
        Def::Struct(i) => (i, TypeStruct),
V
Vadim Petrochenkov 已提交
2784
        Def::Union(i) => (i, TypeUnion),
2785 2786 2787 2788
        Def::Mod(i) => (i, TypeModule),
        Def::Static(i, _) => (i, TypeStatic),
        Def::Variant(i, _) => (i, TypeEnum),
        Def::SelfTy(Some(def_id), _) => (def_id, TypeTrait),
2789 2790 2791 2792 2793 2794
        Def::SelfTy(_, Some(impl_id)) => {
            // For Def::SelfTy() values inlined from another crate, the
            // impl_id will be DUMMY_NODE_ID, which would cause problems.
            // But we should never run into an impl from another crate here.
            return cx.map.local_def_id(impl_id)
        }
2795
        _ => return def.def_id()
C
Corey Richardson 已提交
2796
    };
N
Niko Matsakis 已提交
2797
    if did.is_local() { return did }
2798 2799 2800
    let tcx = match cx.tcx_opt() {
        Some(tcx) => tcx,
        None => return did
2801
    };
2802
    inline::record_extern_fqn(cx, did, kind);
2803 2804
    if let TypeTrait = kind {
        let t = inline::build_external_trait(cx, tcx, did);
M
mitaa 已提交
2805
        cx.external_traits.borrow_mut().insert(did, t);
2806
    }
M
mitaa 已提交
2807
    did
C
Corey Richardson 已提交
2808
}
A
Alex Crichton 已提交
2809

2810
fn resolve_use_source(cx: &DocContext, path: Path, id: ast::NodeId) -> ImportSource {
A
Alex Crichton 已提交
2811 2812
    ImportSource {
        path: path,
2813
        did: resolve_def(cx, id),
A
Alex Crichton 已提交
2814 2815 2816
    }
}

N
Niko Matsakis 已提交
2817
fn resolve_def(cx: &DocContext, id: ast::NodeId) -> Option<DefId> {
2818
    cx.tcx_opt().and_then(|tcx| {
2819
        tcx.expect_def_or_none(id).map(|def| register_def(cx, def))
2820
    })
A
Alex Crichton 已提交
2821
}
2822

J
Jorge Aparicio 已提交
2823
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
2824
pub struct Macro {
2825
    pub source: String,
2826
    pub imported_from: Option<String>,
2827 2828 2829
}

impl Clean<Item> for doctree::Macro {
2830
    fn clean(&self, cx: &DocContext) -> Item {
2831
        let name = self.name.clean(cx);
2832
        Item {
2833
            name: Some(name.clone()),
2834 2835
            attrs: self.attrs.clean(cx),
            source: self.whence.clean(cx),
J
Jeffrey Seyfried 已提交
2836
            visibility: Some(Public),
2837
            stability: self.stab.clean(cx),
2838
            deprecation: self.depr.clean(cx),
2839
            def_id: cx.map.local_def_id(self.id),
2840
            inner: MacroItem(Macro {
2841
                source: format!("macro_rules! {} {{\n{}}}",
2842 2843 2844 2845
                                name,
                                self.matchers.iter().map(|span| {
                                    format!("    {} => {{ ... }};\n", span.to_src(cx))
                                }).collect::<String>()),
2846
                imported_from: self.imported_from.clean(cx),
2847 2848 2849 2850
            }),
        }
    }
}
2851

J
Jorge Aparicio 已提交
2852
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
2853
pub struct Stability {
V
Vadim Petrochenkov 已提交
2854
    pub level: stability::StabilityLevel,
2855 2856
    pub feature: String,
    pub since: String,
2857
    pub deprecated_since: String,
2858 2859
    pub reason: String,
    pub issue: Option<u32>
2860 2861
}

2862 2863 2864 2865 2866 2867
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
pub struct Deprecation {
    pub since: String,
    pub note: String,
}

2868
impl Clean<Stability> for attr::Stability {
2869 2870
    fn clean(&self, _: &DocContext) -> Stability {
        Stability {
V
Vadim Petrochenkov 已提交
2871
            level: stability::StabilityLevel::from_attr_level(&self.level),
2872
            feature: self.feature.to_string(),
V
Vadim Petrochenkov 已提交
2873 2874 2875 2876
            since: match self.level {
                attr::Stable {ref since} => since.to_string(),
                _ => "".to_string(),
            },
2877 2878
            deprecated_since: match self.rustc_depr {
                Some(attr::RustcDeprecation {ref since, ..}) => since.to_string(),
V
Vadim Petrochenkov 已提交
2879 2880
                _=> "".to_string(),
            },
2881
            reason: {
M
mitaa 已提交
2882 2883 2884 2885
                match (&self.rustc_depr, &self.level) {
                    (&Some(ref depr), _) => depr.reason.to_string(),
                    (&None, &attr::Unstable {reason: Some(ref reason), ..}) => reason.to_string(),
                    _ => "".to_string(),
2886
                }
V
Vadim Petrochenkov 已提交
2887 2888 2889 2890 2891
            },
            issue: match self.level {
                attr::Unstable {issue, ..} => Some(issue),
                _ => None,
            }
2892 2893 2894 2895 2896
        }
    }
}

impl<'a> Clean<Stability> for &'a attr::Stability {
V
Vadim Petrochenkov 已提交
2897 2898
    fn clean(&self, dc: &DocContext) -> Stability {
        (**self).clean(dc)
2899 2900
    }
}
A
Alex Crichton 已提交
2901

2902 2903 2904 2905 2906 2907 2908 2909 2910
impl Clean<Deprecation> for attr::Deprecation {
    fn clean(&self, _: &DocContext) -> Deprecation {
        Deprecation {
            since: self.since.as_ref().map_or("".to_string(), |s| s.to_string()),
            note: self.note.as_ref().map_or("".to_string(), |s| s.to_string()),
        }
    }
}

2911 2912 2913 2914 2915 2916 2917 2918 2919 2920
impl<'tcx> Clean<Item> for ty::AssociatedConst<'tcx> {
    fn clean(&self, cx: &DocContext) -> Item {
        Item {
            source: DUMMY_SP.clean(cx),
            name: Some(self.name.clean(cx)),
            attrs: Vec::new(),
            inner: AssociatedConstItem(self.ty.clean(cx), None),
            visibility: None,
            def_id: self.def_id,
            stability: None,
2921
            deprecation: None,
2922 2923 2924 2925
        }
    }
}

2926
impl<'tcx> Clean<Item> for ty::AssociatedType<'tcx> {
2927
    fn clean(&self, cx: &DocContext) -> Item {
2928
        let my_name = self.name.clean(cx);
2929 2930 2931 2932 2933 2934

        let mut bounds = if let ty::TraitContainer(did) = self.container {
            // When loading a cross-crate associated type, the bounds for this type
            // are actually located on the trait/impl itself, so we need to load
            // all of the generics from there and then look for bounds that are
            // applied to this associated type in question.
2935 2936
            let def = cx.tcx().lookup_trait_def(did);
            let predicates = cx.tcx().lookup_predicates(did);
2937
            let generics = (def.generics, &predicates).clean(cx);
2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959
            generics.where_predicates.iter().filter_map(|pred| {
                let (name, self_type, trait_, bounds) = match *pred {
                    WherePredicate::BoundPredicate {
                        ty: QPath { ref name, ref self_type, ref trait_ },
                        ref bounds
                    } => (name, self_type, trait_, bounds),
                    _ => return None,
                };
                if *name != my_name { return None }
                match **trait_ {
                    ResolvedPath { did, .. } if did == self.container.id() => {}
                    _ => return None,
                }
                match **self_type {
                    Generic(ref s) if *s == "Self" => {}
                    _ => return None,
                }
                Some(bounds)
            }).flat_map(|i| i.iter().cloned()).collect::<Vec<_>>()
        } else {
            vec![]
        };
2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970

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

2971 2972
        Item {
            source: DUMMY_SP.clean(cx),
2973
            name: Some(self.name.clean(cx)),
2974
            attrs: inline::load_attrs(cx, cx.tcx(), self.def_id),
2975
            inner: AssociatedTypeItem(bounds, self.ty.clean(cx)),
2976
            visibility: self.vis.clean(cx),
2977
            def_id: self.def_id,
2978 2979
            stability: cx.tcx().lookup_stability(self.def_id).clean(cx),
            deprecation: cx.tcx().lookup_deprecation(self.def_id).clean(cx),
2980 2981 2982 2983
        }
    }
}

N
Niko Matsakis 已提交
2984
fn lang_struct(cx: &DocContext, did: Option<DefId>,
2985
               t: ty::Ty, name: &str,
A
Alex Crichton 已提交
2986 2987 2988
               fallback: fn(Box<Type>) -> Type) -> Type {
    let did = match did {
        Some(did) => did,
2989
        None => return fallback(box t.clean(cx)),
A
Alex Crichton 已提交
2990
    };
M
mitaa 已提交
2991
    inline::record_extern_fqn(cx, did, TypeStruct);
A
Alex Crichton 已提交
2992 2993 2994 2995 2996 2997 2998
    ResolvedPath {
        typarams: None,
        did: did,
        path: Path {
            global: false,
            segments: vec![PathSegment {
                name: name.to_string(),
2999 3000 3001
                params: PathParameters::AngleBracketed {
                    lifetimes: vec![],
                    types: vec![t.clean(cx)],
3002
                    bindings: vec![]
3003
                }
A
Alex Crichton 已提交
3004 3005
            }],
        },
3006
        is_generic: false,
A
Alex Crichton 已提交
3007 3008
    }
}
3009 3010

/// An equality constraint on an associated type, e.g. `A=Bar` in `Foo<A=Bar>`
J
Jorge Aparicio 已提交
3011
#[derive(Clone, PartialEq, RustcDecodable, RustcEncodable, Debug)]
3012 3013 3014 3015 3016
pub struct TypeBinding {
    pub name: String,
    pub ty: Type
}

3017
impl Clean<TypeBinding> for hir::TypeBinding {
3018 3019
    fn clean(&self, cx: &DocContext) -> TypeBinding {
        TypeBinding {
3020
            name: self.name.clean(cx),
3021 3022 3023 3024
            ty: self.ty.clean(cx)
        }
    }
}