mod.rs 160.7 KB
Newer Older
C
Corey Richardson 已提交
1 2 3
//! This module contains the "cleaned" pieces of the AST, and the functions
//! that clean them.

4 5 6 7 8 9
pub mod inline;
pub mod cfg;
mod simplify;
mod auto_trait;
mod blanket_impl;
pub mod def_ctor;
S
Steven Fackler 已提交
10

11 12
use rustc_data_structures::indexed_vec::{IndexVec, Idx};
use rustc_data_structures::sync::Lrc;
13
use rustc_target::spec::abi::Abi;
14 15
use rustc_typeck::hir_ty_to_ty;
use rustc::infer::region_constraints::{RegionConstraintData, Constraint};
16
use rustc::middle::resolve_lifetime as rl;
17
use rustc::middle::lang_items;
18
use rustc::middle::stability;
O
Oliver Scherer 已提交
19
use rustc::mir::interpret::{GlobalId, ConstValue};
V
varkor 已提交
20
use rustc::hir::{self, HirVec};
21
use rustc::hir::def::{self, Def, CtorKind};
22
use rustc::hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
23
use rustc::hir::map::DisambiguatedDefPathData;
24
use rustc::ty::subst::{Kind, InternalSubsts, SubstsRef, UnpackedKind};
25
use rustc::ty::{self, DefIdTree, TyCtxt, Region, RegionVid, Ty, AdtKind};
26
use rustc::ty::fold::TypeFolder;
27
use rustc::ty::layout::VariantIdx;
28
use rustc::util::nodemap::{FxHashMap, FxHashSet};
29 30 31 32 33 34 35 36
use syntax::ast::{self, AttrStyle, Ident};
use syntax::attr;
use syntax::ext::base::MacroKind;
use syntax::source_map::{dummy_spanned, Spanned};
use syntax::ptr::P;
use syntax::symbol::keywords::{self, Keyword};
use syntax::symbol::InternedString;
use syntax_pos::{self, DUMMY_SP, Pos, FileName};
37

38 39
use std::collections::hash_map::Entry;
use std::fmt;
40
use std::hash::{Hash, Hasher};
41
use std::default::Default;
M
Manish Goregaokar 已提交
42
use std::{mem, slice, vec};
43
use std::iter::{FromIterator, once};
44
use std::rc::Rc;
G
Guillaume Gomez 已提交
45
use std::str::FromStr;
46
use std::cell::RefCell;
M
mitaa 已提交
47
use std::sync::Arc;
48
use std::u32;
49

50 51
use parking_lot::ReentrantMutex;

52 53 54 55 56 57
use crate::core::{self, DocContext};
use crate::doctree;
use crate::visit_ast;
use crate::html::render::{cache, ExternalLocation};
use crate::html::item_type::ItemType;

C
Corey Richardson 已提交
58

K
kennytm 已提交
59
use self::cfg::Cfg;
60
use self::auto_trait::AutoTraitFinder;
G
Guillaume Gomez 已提交
61
use self::blanket_impl::BlanketImplFinder;
62

63 64 65 66 67 68 69
pub use self::Type::*;
pub use self::Mutability::*;
pub use self::ItemEnum::*;
pub use self::SelfTy::*;
pub use self::FunctionRetTy::*;
pub use self::Visibility::{Public, Inherited};

70
thread_local!(pub static MAX_DEF_ID: RefCell<FxHashMap<CrateNum, DefId>> = Default::default());
71 72

const FN_OUTPUT_NAME: &'static str = "Output";
K
kennytm 已提交
73

74
// extract the stability index for a node from tcx, if possible
75
fn get_stability(cx: &DocContext<'_>, def_id: DefId) -> Option<Stability> {
76
    cx.tcx.lookup_stability(def_id).clean(cx)
77 78
}

79
fn get_deprecation(cx: &DocContext<'_>, def_id: DefId) -> Option<Deprecation> {
80
    cx.tcx.lookup_deprecation(def_id).clean(cx)
81 82
}

C
Corey Richardson 已提交
83
pub trait Clean<T> {
84
    fn clean(&self, cx: &DocContext<'_>) -> T;
C
Corey Richardson 已提交
85 86
}

87
impl<T: Clean<U>, U> Clean<Vec<U>> for [T] {
88
    fn clean(&self, cx: &DocContext<'_>) -> Vec<U> {
89
        self.iter().map(|x| x.clean(cx)).collect()
90 91 92
    }
}

93
impl<T: Clean<U>, U, V: Idx> Clean<IndexVec<V, U>> for IndexVec<V, T> {
94
    fn clean(&self, cx: &DocContext<'_>) -> IndexVec<V, U> {
95 96 97 98
        self.iter().map(|x| x.clean(cx)).collect()
    }
}

99
impl<T: Clean<U>, U> Clean<U> for P<T> {
100
    fn clean(&self, cx: &DocContext<'_>) -> U {
101
        (**self).clean(cx)
C
Corey Richardson 已提交
102 103 104
    }
}

105
impl<T: Clean<U>, U> Clean<U> for Rc<T> {
106
    fn clean(&self, cx: &DocContext<'_>) -> U {
107
        (**self).clean(cx)
108 109 110
    }
}

C
Corey Richardson 已提交
111
impl<T: Clean<U>, U> Clean<Option<U>> for Option<T> {
112
    fn clean(&self, cx: &DocContext<'_>) -> Option<U> {
M
mitaa 已提交
113
        self.as_ref().map(|v| v.clean(cx))
C
Corey Richardson 已提交
114 115 116
    }
}

117
impl<T, U> Clean<U> for ty::Binder<T> where T: Clean<U> {
118
    fn clean(&self, cx: &DocContext<'_>) -> U {
119
        self.skip_binder().clean(cx)
120 121 122
    }
}

123
impl<T: Clean<U>, U> Clean<Vec<U>> for P<[T]> {
124
    fn clean(&self, cx: &DocContext<'_>) -> Vec<U> {
125
        self.iter().map(|x| x.clean(cx)).collect()
C
Corey Richardson 已提交
126 127 128
    }
}

M
mitaa 已提交
129
#[derive(Clone, Debug)]
C
Corey Richardson 已提交
130
pub struct Crate {
131
    pub name: String,
132
    pub version: Option<String>,
133
    pub src: FileName,
134
    pub module: Option<Item>,
135 136
    pub externs: Vec<(CrateNum, ExternalCrate)>,
    pub primitives: Vec<(DefId, PrimitiveType, Attributes)>,
M
mitaa 已提交
137 138
    // These are later on moved into `CACHEKEY`, leaving the map empty.
    // Only here so that they can be filtered through the rustdoc passes.
139
    pub external_traits: Arc<ReentrantMutex<RefCell<FxHashMap<DefId, Trait>>>>,
140
    pub masked_crates: FxHashSet<CrateNum>,
C
Corey Richardson 已提交
141 142
}

143 144
impl<'a, 'tcx> Clean<Crate> for visit_ast::RustdocVisitor<'a, 'tcx> {
    fn clean(&self, cx: &DocContext<'_>) -> Crate {
145
        use crate::visit_lib::LibEmbargoVisitor;
146

147 148
        {
            let mut r = cx.renderinfo.borrow_mut();
149 150 151
            r.deref_trait_did = cx.tcx.lang_items().deref_trait();
            r.deref_mut_trait_did = cx.tcx.lang_items().deref_mut_trait();
            r.owned_box_did = cx.tcx.lang_items().owned_box();
152 153
        }

154
        let mut externs = Vec::new();
155
        for &cnum in cx.tcx.crates().iter() {
156
            externs.push((cnum, cnum.clean(cx)));
157 158
            // Analyze doc-reachability for extern items
            LibEmbargoVisitor::new(cx).visit_lib(cnum);
A
Ariel Ben-Yehuda 已提交
159
        }
160
        externs.sort_by(|&(a, _), &(b, _)| a.cmp(&b));
C
Corey Richardson 已提交
161

162
        // Clean the crate, translating the entire libsyntax AST to one that is
163
        // understood by rustdoc.
164
        let mut module = self.module.clean(cx);
165
        let mut masked_crates = FxHashSet::default();
166 167 168 169

        match module.inner {
            ModuleItem(ref module) => {
                for it in &module.items {
A
Andy Russell 已提交
170 171 172 173 174 175
                    // `compiler_builtins` should be masked too, but we can't apply
                    // `#[doc(masked)]` to the injected `extern crate` because it's unstable.
                    if it.is_extern_crate()
                        && (it.attrs.has_doc_flag("masked")
                            || self.cx.tcx.is_compiler_builtins(it.def_id.krate))
                    {
176 177 178 179 180 181
                        masked_crates.insert(it.def_id.krate);
                    }
                }
            }
            _ => unreachable!(),
        }
182

G
Guillaume Gomez 已提交
183
        let ExternalCrate { name, src, primitives, keywords, .. } = LOCAL_CRATE.clean(cx);
184 185 186 187 188
        {
            let m = match module.inner {
                ModuleItem(ref mut m) => m,
                _ => unreachable!(),
            };
189 190
            m.items.extend(primitives.iter().map(|&(def_id, prim, ref attrs)| {
                Item {
191 192
                    source: Span::empty(),
                    name: Some(prim.to_url_str().to_string()),
193
                    attrs: attrs.clone(),
J
Jeffrey Seyfried 已提交
194
                    visibility: Some(Public),
195 196
                    stability: get_stability(cx, def_id),
                    deprecation: get_deprecation(cx, def_id),
197
                    def_id,
198
                    inner: PrimitiveItem(prim),
199
                }
200
            }));
G
Guillaume Gomez 已提交
201
            m.items.extend(keywords.into_iter().map(|(def_id, kw, attrs)| {
G
Guillaume Gomez 已提交
202 203 204
                Item {
                    source: Span::empty(),
                    name: Some(kw.clone()),
G
Guillaume Gomez 已提交
205
                    attrs: attrs,
G
Guillaume Gomez 已提交
206 207 208 209
                    visibility: Some(Public),
                    stability: get_stability(cx, def_id),
                    deprecation: get_deprecation(cx, def_id),
                    def_id,
G
Guillaume Gomez 已提交
210
                    inner: KeywordItem(kw),
G
Guillaume Gomez 已提交
211 212
                }
            }));
213
        }
214

C
Corey Richardson 已提交
215
        Crate {
216
            name,
217
            version: None,
218
            src,
219
            module: Some(module),
220 221
            externs,
            primitives,
222
            external_traits: cx.external_traits.clone(),
223
            masked_crates,
224 225 226 227
        }
    }
}

J
Jorge Aparicio 已提交
228
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
229
pub struct ExternalCrate {
230
    pub name: String,
231
    pub src: FileName,
232
    pub attrs: Attributes,
233
    pub primitives: Vec<(DefId, PrimitiveType, Attributes)>,
G
Guillaume Gomez 已提交
234
    pub keywords: Vec<(DefId, String, Attributes)>,
235 236
}

A
Ariel Ben-Yehuda 已提交
237
impl Clean<ExternalCrate> for CrateNum {
238
    fn clean(&self, cx: &DocContext<'_>) -> ExternalCrate {
239 240
        let root = DefId { krate: *self, index: CRATE_DEF_INDEX };
        let krate_span = cx.tcx.def_span(root);
D
Donato Sciarra 已提交
241
        let krate_src = cx.sess().source_map().span_to_filename(krate_span);
242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270

        // Collect all inner modules which are tagged as implementations of
        // primitives.
        //
        // Note that this loop only searches the top-level items of the crate,
        // and this is intentional. If we were to search the entire crate for an
        // item tagged with `#[doc(primitive)]` then we would also have to
        // search the entirety of external modules for items tagged
        // `#[doc(primitive)]`, which is a pretty inefficient process (decoding
        // all that metadata unconditionally).
        //
        // In order to keep the metadata load under control, the
        // `#[doc(primitive)]` feature is explicitly designed to only allow the
        // primitive tags to show up as the top level items in a crate.
        //
        // Also note that this does not attempt to deal with modules tagged
        // duplicately for the same primitive. This is handled later on when
        // rendering by delegating everything to a hash map.
        let as_primitive = |def: Def| {
            if let Def::Mod(def_id) = def {
                let attrs = cx.tcx.get_attrs(def_id).clean(cx);
                let mut prim = None;
                for attr in attrs.lists("doc") {
                    if let Some(v) = attr.value_str() {
                        if attr.check_name("primitive") {
                            prim = PrimitiveType::from_str(&v.as_str());
                            if prim.is_some() {
                                break;
                            }
271
                            // FIXME: should warn on unknown primitives?
272 273 274 275 276 277 278 279
                        }
                    }
                }
                return prim.map(|p| (def_id, p, attrs));
            }
            None
        };
        let primitives = if root.is_local() {
280
            cx.tcx.hir().krate().module.item_ids.iter().filter_map(|&id| {
281
                let item = cx.tcx.hir().expect_item_by_hir_id(id.id);
282
                match item.node {
C
csmoe 已提交
283
                    hir::ItemKind::Mod(_) => {
284
                        as_primitive(Def::Mod(cx.tcx.hir().local_def_id_from_hir_id(id.id)))
285
                    }
C
csmoe 已提交
286
                    hir::ItemKind::Use(ref path, hir::UseKind::Single)
287
                    if item.vis.node.is_pub() => {
288 289
                        as_primitive(path.def).map(|(_, prim, attrs)| {
                            // Pretend the primitive is local.
290
                            (cx.tcx.hir().local_def_id_from_hir_id(id.id), prim, attrs)
291 292 293 294 295 296
                        })
                    }
                    _ => None
                }
            }).collect()
        } else {
297
            cx.tcx.item_children(root).iter().map(|item| item.def)
298 299 300
              .filter_map(as_primitive).collect()
        };

G
Guillaume Gomez 已提交
301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321
        let as_keyword = |def: Def| {
            if let Def::Mod(def_id) = def {
                let attrs = cx.tcx.get_attrs(def_id).clean(cx);
                let mut keyword = None;
                for attr in attrs.lists("doc") {
                    if let Some(v) = attr.value_str() {
                        if attr.check_name("keyword") {
                            keyword = Keyword::from_str(&v.as_str()).ok()
                                                                    .map(|x| x.name().to_string());
                            if keyword.is_some() {
                                break
                            }
                            // FIXME: should warn on unknown keywords?
                        }
                    }
                }
                return keyword.map(|p| (def_id, p, attrs));
            }
            None
        };
        let keywords = if root.is_local() {
322
            cx.tcx.hir().krate().module.item_ids.iter().filter_map(|&id| {
323
                let item = cx.tcx.hir().expect_item_by_hir_id(id.id);
G
Guillaume Gomez 已提交
324
                match item.node {
C
csmoe 已提交
325
                    hir::ItemKind::Mod(_) => {
326
                        as_keyword(Def::Mod(cx.tcx.hir().local_def_id_from_hir_id(id.id)))
G
Guillaume Gomez 已提交
327
                    }
C
csmoe 已提交
328
                    hir::ItemKind::Use(ref path, hir::UseKind::Single)
329
                    if item.vis.node.is_pub() => {
G
Guillaume Gomez 已提交
330
                        as_keyword(path.def).map(|(_, prim, attrs)| {
331
                            (cx.tcx.hir().local_def_id_from_hir_id(id.id), prim, attrs)
G
Guillaume Gomez 已提交
332 333 334 335 336 337 338 339 340 341
                        })
                    }
                    _ => None
                }
            }).collect()
        } else {
            cx.tcx.item_children(root).iter().map(|item| item.def)
              .filter_map(as_keyword).collect()
        };

342
        ExternalCrate {
343
            name: cx.tcx.crate_name(*self).to_string(),
344
            src: krate_src,
345
            attrs: cx.tcx.get_attrs(root).clean(cx),
346
            primitives,
G
Guillaume Gomez 已提交
347
            keywords,
C
Corey Richardson 已提交
348 349 350 351 352 353 354
        }
    }
}

/// 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.
355
#[derive(Clone, RustcEncodable, RustcDecodable)]
C
Corey Richardson 已提交
356 357
pub struct Item {
    /// Stringified span
358
    pub source: Span,
C
Corey Richardson 已提交
359
    /// Not everything has a name. E.g., impls
360
    pub name: Option<String>,
361
    pub attrs: Attributes,
362 363
    pub inner: ItemEnum,
    pub visibility: Option<Visibility>,
N
Niko Matsakis 已提交
364
    pub def_id: DefId,
365
    pub stability: Option<Stability>,
366
    pub deprecation: Option<Deprecation>,
C
Corey Richardson 已提交
367 368
}

369
impl fmt::Debug for Item {
370
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
371 372 373

        let fake = MAX_DEF_ID.with(|m| m.borrow().get(&self.def_id.krate)
                                   .map(|id| self.def_id >= *id).unwrap_or(false));
T
Tatsuyuki Ishi 已提交
374
        let def_id: &dyn fmt::Debug = if fake { &"**FAKE**" } else { &self.def_id };
375 376 377 378 379 380 381 382 383 384 385 386 387 388

        fmt.debug_struct("Item")
            .field("source", &self.source)
            .field("name", &self.name)
            .field("attrs", &self.attrs)
            .field("inner", &self.inner)
            .field("visibility", &self.visibility)
            .field("def_id", def_id)
            .field("stability", &self.stability)
            .field("deprecation", &self.deprecation)
            .finish()
    }
}

389 390 391 392
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> {
393
        self.attrs.doc_value()
394
    }
395 396 397 398 399
    /// Finds all `doc` attributes as NameValues and returns their corresponding values, joined
    /// with newlines.
    pub fn collapsed_doc_value(&self) -> Option<String> {
        self.attrs.collapsed_doc_value()
    }
400 401

    pub fn links(&self) -> Vec<(String, String)> {
G
Guillaume Gomez 已提交
402
        self.attrs.links(&self.def_id.krate)
403 404
    }

M
mitaa 已提交
405 406
    pub fn is_crate(&self) -> bool {
        match self.inner {
407 408 409
            StrippedItem(box ModuleItem(Module { is_crate: true, ..})) |
            ModuleItem(Module { is_crate: true, ..}) => true,
            _ => false,
M
mitaa 已提交
410 411
        }
    }
412
    pub fn is_mod(&self) -> bool {
413
        self.type_() == ItemType::Module
414 415
    }
    pub fn is_trait(&self) -> bool {
416
        self.type_() == ItemType::Trait
417 418
    }
    pub fn is_struct(&self) -> bool {
419
        self.type_() == ItemType::Struct
420 421
    }
    pub fn is_enum(&self) -> bool {
422
        self.type_() == ItemType::Enum
423
    }
424 425 426
    pub fn is_variant(&self) -> bool {
        self.type_() == ItemType::Variant
    }
M
mitaa 已提交
427
    pub fn is_associated_type(&self) -> bool {
428
        self.type_() == ItemType::AssociatedType
M
mitaa 已提交
429 430
    }
    pub fn is_associated_const(&self) -> bool {
431
        self.type_() == ItemType::AssociatedConst
M
mitaa 已提交
432 433
    }
    pub fn is_method(&self) -> bool {
434
        self.type_() == ItemType::Method
M
mitaa 已提交
435 436
    }
    pub fn is_ty_method(&self) -> bool {
437
        self.type_() == ItemType::TyMethod
438
    }
439 440 441
    pub fn is_typedef(&self) -> bool {
        self.type_() == ItemType::Typedef
    }
442
    pub fn is_primitive(&self) -> bool {
443
        self.type_() == ItemType::Primitive
444
    }
445 446 447
    pub fn is_union(&self) -> bool {
        self.type_() == ItemType::Union
    }
G
Guillaume Gomez 已提交
448 449 450
    pub fn is_import(&self) -> bool {
        self.type_() == ItemType::Import
    }
451 452 453
    pub fn is_extern_crate(&self) -> bool {
        self.type_() == ItemType::ExternCrate
    }
G
Guillaume Gomez 已提交
454 455 456
    pub fn is_keyword(&self) -> bool {
        self.type_() == ItemType::Keyword
    }
G
Guillaume Gomez 已提交
457

458 459
    pub fn is_stripped(&self) -> bool {
        match self.inner { StrippedItem(..) => true, _ => false }
M
mitaa 已提交
460
    }
461 462 463
    pub fn has_stripped_fields(&self) -> Option<bool> {
        match self.inner {
            StructItem(ref _struct) => Some(_struct.fields_stripped),
V
Vadim Petrochenkov 已提交
464
            UnionItem(ref union) => Some(union.fields_stripped),
465
            VariantItem(Variant { kind: VariantKind::Struct(ref vstruct)} ) => {
466 467 468 469 470
                Some(vstruct.fields_stripped)
            },
            _ => None,
        }
    }
471

472
    pub fn stability_class(&self) -> Option<String> {
473 474
        self.stability.as_ref().and_then(|ref s| {
            let mut classes = Vec::with_capacity(2);
475

476 477 478
            if s.level == stability::Unstable {
                classes.push("unstable");
            }
479

480
            if s.deprecation.is_some() {
481 482
                classes.push("deprecated");
            }
483

484 485 486 487
            if classes.len() != 0 {
                Some(classes.join(" "))
            } else {
                None
488
            }
489
        })
490
    }
491 492

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

496 497
    pub fn is_non_exhaustive(&self) -> bool {
        self.attrs.other_attrs.iter()
498
            .any(|a| a.check_name("non_exhaustive"))
499 500
    }

501 502 503 504
    /// Returns a documentation-level item type from the item.
    pub fn type_(&self) -> ItemType {
        ItemType::from(self)
    }
505 506 507 508 509 510 511 512 513

    /// Returns the info in the item's `#[deprecated]` or `#[rustc_deprecated]` attributes.
    ///
    /// If the item is not deprecated, returns `None`.
    pub fn deprecation(&self) -> Option<&Deprecation> {
        self.deprecation
            .as_ref()
            .or_else(|| self.stability.as_ref().and_then(|s| s.deprecation.as_ref()))
    }
514 515 516 517 518 519 520 521 522 523 524 525
    pub fn is_default(&self) -> bool {
        match self.inner {
            ItemEnum::MethodItem(ref meth) => {
                if let Some(defaultness) = meth.defaultness {
                    defaultness.has_value() && !defaultness.is_final()
                } else {
                    false
                }
            }
            _ => false,
        }
    }
526 527
}

J
Jorge Aparicio 已提交
528
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
529
pub enum ItemEnum {
530 531
    ExternCrateItem(String, Option<String>),
    ImportItem(Import),
C
Corey Richardson 已提交
532
    StructItem(Struct),
V
Vadim Petrochenkov 已提交
533
    UnionItem(Union),
C
Corey Richardson 已提交
534 535 536
    EnumItem(Enum),
    FunctionItem(Function),
    ModuleItem(Module),
537
    TypedefItem(Typedef, bool /* is associated type */),
O
Oliver Schneider 已提交
538
    ExistentialItem(Existential, bool /* is associated type */),
C
Corey Richardson 已提交
539
    StaticItem(Static),
540
    ConstantItem(Constant),
C
Corey Richardson 已提交
541
    TraitItem(Trait),
542
    TraitAliasItem(TraitAlias),
C
Corey Richardson 已提交
543
    ImplItem(Impl),
544 545
    /// A method signature only. Used for required methods in traits (ie,
    /// non-default-methods).
C
Corey Richardson 已提交
546
    TyMethodItem(TyMethod),
547
    /// A method with a body.
C
Corey Richardson 已提交
548
    MethodItem(Method),
549
    StructFieldItem(Type),
C
Corey Richardson 已提交
550
    VariantItem(Variant),
551
    /// `fn`s from an extern block
552
    ForeignFunctionItem(Function),
553
    /// `static`s from an extern block
554
    ForeignStaticItem(Static),
P
Paul Lietar 已提交
555 556
    /// `type`s from an extern block
    ForeignTypeItem,
557
    MacroItem(Macro),
558
    ProcMacroItem(ProcMacro),
559
    PrimitiveItem(PrimitiveType),
560
    AssociatedConstItem(Type, Option<String>),
V
varkor 已提交
561
    AssociatedTypeItem(Vec<GenericBound>, Option<Type>),
562 563
    /// An item that has been stripped by a rustdoc pass
    StrippedItem(Box<ItemEnum>),
G
Guillaume Gomez 已提交
564
    KeywordItem(String),
C
Corey Richardson 已提交
565 566
}

567 568 569 570 571 572 573
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,
O
Oliver Schneider 已提交
574
            ItemEnum::ExistentialItem(ref t, _) => &t.generics,
575 576 577 578 579
            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,
580
            ItemEnum::TraitAliasItem(ref ta) => &ta.generics,
581 582 583
            _ => return None,
        })
    }
G
Guillaume Gomez 已提交
584 585 586 587 588 589 590 591

    pub fn is_associated(&self) -> bool {
        match *self {
            ItemEnum::TypedefItem(_, _) |
            ItemEnum::AssociatedTypeItem(_, _) => true,
            _ => false,
        }
    }
592 593
}

J
Jorge Aparicio 已提交
594
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
595
pub struct Module {
596 597
    pub items: Vec<Item>,
    pub is_crate: bool,
C
Corey Richardson 已提交
598 599 600
}

impl Clean<Item> for doctree::Module {
601
    fn clean(&self, cx: &DocContext<'_>) -> Item {
C
Corey Richardson 已提交
602
        let name = if self.name.is_some() {
G
Guillaume Gomez 已提交
603
            self.name.expect("No name provided").clean(cx)
C
Corey Richardson 已提交
604
        } else {
605
            String::new()
C
Corey Richardson 已提交
606
        };
607

608 609 610
        // maintain a stack of mod ids, for doc comment path resolution
        // but we also need to resolve the module's own docs based on whether its docs were written
        // inside or outside the module, so check for that
611
        let attrs = self.attrs.clean(cx);
M
Manish Goregaokar 已提交
612

613
        let mut items: Vec<Item> = vec![];
D
DebugSteven 已提交
614
        items.extend(self.extern_crates.iter().flat_map(|x| x.clean(cx)));
615
        items.extend(self.imports.iter().flat_map(|x| x.clean(cx)));
616 617 618
        items.extend(self.structs.iter().map(|x| x.clean(cx)));
        items.extend(self.unions.iter().map(|x| x.clean(cx)));
        items.extend(self.enums.iter().map(|x| x.clean(cx)));
619
        items.extend(self.fns.iter().map(|x| x.clean(cx)));
620
        items.extend(self.foreigns.iter().flat_map(|x| x.clean(cx)));
621 622
        items.extend(self.mods.iter().map(|x| x.clean(cx)));
        items.extend(self.typedefs.iter().map(|x| x.clean(cx)));
O
Oliver Schneider 已提交
623
        items.extend(self.existentials.iter().map(|x| x.clean(cx)));
624 625 626
        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)));
627
        items.extend(self.impls.iter().flat_map(|x| x.clean(cx)));
628
        items.extend(self.macros.iter().map(|x| x.clean(cx)));
629
        items.extend(self.proc_macros.iter().map(|x| x.clean(cx)));
630
        items.extend(self.trait_aliases.iter().map(|x| x.clean(cx)));
631 632 633

        // determine if we should display the inner contents or
        // the outer `mod` item for the source code.
634
        let whence = {
D
Donato Sciarra 已提交
635
            let cm = cx.sess().source_map();
636 637
            let outer = cm.lookup_char_pos(self.where_outer.lo());
            let inner = cm.lookup_char_pos(self.where_inner.lo());
638 639 640 641
            if outer.file.start_pos == inner.file.start_pos {
                // mod foo { ... }
                self.where_outer
            } else {
D
Donato Sciarra 已提交
642
                // mod foo; (and a separate SourceFile for the contents)
643 644 645 646
                self.where_inner
            }
        };

C
Corey Richardson 已提交
647 648
        Item {
            name: Some(name),
649
            attrs,
650 651 652
            source: whence.clean(cx),
            visibility: self.vis.clean(cx),
            stability: self.stab.clean(cx),
653
            deprecation: self.depr.clean(cx),
654
            def_id: cx.tcx.hir().local_def_id(self.id),
C
Corey Richardson 已提交
655
            inner: ModuleItem(Module {
656
               is_crate: self.is_crate,
657
               items,
C
Corey Richardson 已提交
658 659 660 661 662
            })
        }
    }
}

663 664
pub struct ListAttributesIter<'a> {
    attrs: slice::Iter<'a, ast::Attribute>,
665
    current_list: vec::IntoIter<ast::NestedMetaItem>,
666
    name: &'a str
M
mitaa 已提交
667 668
}

669
impl<'a> Iterator for ListAttributesIter<'a> {
670
    type Item = ast::NestedMetaItem;
671 672 673 674

    fn next(&mut self) -> Option<Self::Item> {
        if let Some(nested) = self.current_list.next() {
            return Some(nested);
M
mitaa 已提交
675 676
        }

677
        for attr in &mut self.attrs {
678
            if let Some(list) = attr.meta_item_list() {
679
                if attr.check_name(self.name) {
680
                    self.current_list = list.into_iter();
681 682 683
                    if let Some(nested) = self.current_list.next() {
                        return Some(nested);
                    }
M
mitaa 已提交
684 685 686
                }
            }
        }
687

M
mitaa 已提交
688 689
        None
    }
690 691 692 693 694

    fn size_hint(&self) -> (usize, Option<usize>) {
        let lower = self.current_list.len();
        (lower, None)
    }
695
}
M
mitaa 已提交
696

697
pub trait AttributesExt {
M
mitaa 已提交
698
    /// Finds an attribute as List and returns the list of attributes nested inside.
E
est31 已提交
699
    fn lists<'a>(&'a self, name: &'a str) -> ListAttributesIter<'a>;
700 701 702 703 704 705
}

impl AttributesExt for [ast::Attribute] {
    fn lists<'a>(&'a self, name: &'a str) -> ListAttributesIter<'a> {
        ListAttributesIter {
            attrs: self.iter(),
706
            current_list: Vec::new().into_iter(),
707
            name,
M
mitaa 已提交
708 709 710 711
        }
    }
}

712
pub trait NestedAttributesExt {
A
Alexander Regueiro 已提交
713
    /// Returns `true` if the attribute list contains a specific `Word`
E
est31 已提交
714
    fn has_word(self, word: &str) -> bool;
715 716
}

717
impl<I: IntoIterator<Item=ast::NestedMetaItem>> NestedAttributesExt for I {
718 719 720 721 722
    fn has_word(self, word: &str) -> bool {
        self.into_iter().any(|attr| attr.is_word() && attr.check_name(word))
    }
}

723 724 725 726 727 728 729 730
/// A portion of documentation, extracted from a `#[doc]` attribute.
///
/// Each variant contains the line number within the complete doc-comment where the fragment
/// starts, as well as the Span where the corresponding doc comment or attribute is located.
///
/// Included files are kept separate from inline doc comments so that proper line-number
/// information can be given when a doctest fails. Sugared doc comments and "raw" doc comments are
/// kept separate because of issue #42760.
731
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)]
732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780
pub enum DocFragment {
    /// A doc fragment created from a `///` or `//!` doc comment.
    SugaredDoc(usize, syntax_pos::Span, String),
    /// A doc fragment created from a "raw" `#[doc=""]` attribute.
    RawDoc(usize, syntax_pos::Span, String),
    /// A doc fragment created from a `#[doc(include="filename")]` attribute. Contains both the
    /// given filename and the file contents.
    Include(usize, syntax_pos::Span, String, String),
}

impl DocFragment {
    pub fn as_str(&self) -> &str {
        match *self {
            DocFragment::SugaredDoc(_, _, ref s) => &s[..],
            DocFragment::RawDoc(_, _, ref s) => &s[..],
            DocFragment::Include(_, _, _, ref s) => &s[..],
        }
    }

    pub fn span(&self) -> syntax_pos::Span {
        match *self {
            DocFragment::SugaredDoc(_, span, _) |
                DocFragment::RawDoc(_, span, _) |
                DocFragment::Include(_, span, _, _) => span,
        }
    }
}

impl<'a> FromIterator<&'a DocFragment> for String {
    fn from_iter<T>(iter: T) -> Self
    where
        T: IntoIterator<Item = &'a DocFragment>
    {
        iter.into_iter().fold(String::new(), |mut acc, frag| {
            if !acc.is_empty() {
                acc.push('\n');
            }
            match *frag {
                DocFragment::SugaredDoc(_, _, ref docs)
                    | DocFragment::RawDoc(_, _, ref docs)
                    | DocFragment::Include(_, _, _, ref docs) =>
                    acc.push_str(docs),
            }

            acc
        })
    }
}

781
#[derive(Clone, RustcEncodable, RustcDecodable, Debug, Default)]
782
pub struct Attributes {
783
    pub doc_strings: Vec<DocFragment>,
784
    pub other_attrs: Vec<ast::Attribute>,
J
John Kåre Alsaker 已提交
785
    pub cfg: Option<Arc<Cfg>>,
786
    pub span: Option<syntax_pos::Span>,
M
Manish Goregaokar 已提交
787
    /// map from Rust paths to resolved defs and potential URL fragments
G
Guillaume Gomez 已提交
788
    pub links: Vec<(String, Option<DefId>, Option<String>)>,
789
    pub inner_docs: bool,
790 791 792
}

impl Attributes {
K
kennytm 已提交
793 794
    /// Extracts the content from an attribute `#[doc(cfg(content))]`.
    fn extract_cfg(mi: &ast::MetaItem) -> Option<&ast::MetaItem> {
795
        use syntax::ast::NestedMetaItem::MetaItem;
K
kennytm 已提交
796 797 798

        if let ast::MetaItemKind::List(ref nmis) = mi.node {
            if nmis.len() == 1 {
799
                if let MetaItem(ref cfg_mi) = nmis[0] {
K
kennytm 已提交
800 801 802
                    if cfg_mi.check_name("cfg") {
                        if let ast::MetaItemKind::List(ref cfg_nmis) = cfg_mi.node {
                            if cfg_nmis.len() == 1 {
803
                                if let MetaItem(ref content_mi) = cfg_nmis[0] {
K
kennytm 已提交
804 805 806 807 808 809 810 811 812 813 814 815
                                    return Some(content_mi);
                                }
                            }
                        }
                    }
                }
            }
        }

        None
    }

816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856
    /// Reads a `MetaItem` from within an attribute, looks for whether it is a
    /// `#[doc(include="file")]`, and returns the filename and contents of the file as loaded from
    /// its expansion.
    fn extract_include(mi: &ast::MetaItem)
        -> Option<(String, String)>
    {
        mi.meta_item_list().and_then(|list| {
            for meta in list {
                if meta.check_name("include") {
                    // the actual compiled `#[doc(include="filename")]` gets expanded to
                    // `#[doc(include(file="filename", contents="file contents")]` so we need to
                    // look for that instead
                    return meta.meta_item_list().and_then(|list| {
                        let mut filename: Option<String> = None;
                        let mut contents: Option<String> = None;

                        for it in list {
                            if it.check_name("file") {
                                if let Some(name) = it.value_str() {
                                    filename = Some(name.to_string());
                                }
                            } else if it.check_name("contents") {
                                if let Some(docs) = it.value_str() {
                                    contents = Some(docs.to_string());
                                }
                            }
                        }

                        if let (Some(filename), Some(contents)) = (filename, contents) {
                            Some((filename, contents))
                        } else {
                            None
                        }
                    });
                }
            }

            None
        })
    }

857
    pub fn has_doc_flag(&self, flag: &str) -> bool {
858 859 860 861
        for attr in &self.other_attrs {
            if !attr.check_name("doc") { continue; }

            if let Some(items) = attr.meta_item_list() {
862
                if items.iter().filter_map(|i| i.meta_item()).any(|it| it.check_name(flag)) {
863 864 865 866 867 868 869 870
                    return true;
                }
            }
        }

        false
    }

871 872
    pub fn from_ast(diagnostic: &::errors::Handler,
                    attrs: &[ast::Attribute]) -> Attributes {
873
        let mut doc_strings = vec![];
874
        let mut sp = None;
K
kennytm 已提交
875
        let mut cfg = Cfg::True;
876
        let mut doc_line = 0;
K
kennytm 已提交
877

878 879
        let other_attrs = attrs.iter().filter_map(|attr| {
            attr.with_desugared_doc(|attr| {
K
kennytm 已提交
880 881 882 883
                if attr.check_name("doc") {
                    if let Some(mi) = attr.meta() {
                        if let Some(value) = mi.value_str() {
                            // Extracted #[doc = "..."]
884 885 886 887 888 889 890 891 892 893
                            let value = value.to_string();
                            let line = doc_line;
                            doc_line += value.lines().count();

                            if attr.is_sugared_doc {
                                doc_strings.push(DocFragment::SugaredDoc(line, attr.span, value));
                            } else {
                                doc_strings.push(DocFragment::RawDoc(line, attr.span, value));
                            }

K
kennytm 已提交
894 895 896 897 898 899 900 901 902 903 904
                            if sp.is_none() {
                                sp = Some(attr.span);
                            }
                            return None;
                        } else if let Some(cfg_mi) = Attributes::extract_cfg(&mi) {
                            // Extracted #[doc(cfg(...))]
                            match Cfg::parse(cfg_mi) {
                                Ok(new_cfg) => cfg &= new_cfg,
                                Err(e) => diagnostic.span_err(e.span, e.msg),
                            }
                            return None;
905 906 907 908 909 910 911 912
                        } else if let Some((filename, contents)) = Attributes::extract_include(&mi)
                        {
                            let line = doc_line;
                            doc_line += contents.lines().count();
                            doc_strings.push(DocFragment::Include(line,
                                                                  attr.span,
                                                                  filename,
                                                                  contents));
913
                        }
914 915 916 917 918
                    }
                }
                Some(attr.clone())
            })
        }).collect();
919

920 921 922 923 924
        // treat #[target_feature(enable = "feat")] attributes as if they were
        // #[doc(cfg(target_feature = "feat"))] attributes as well
        for attr in attrs.lists("target_feature") {
            if attr.check_name("enable") {
                if let Some(feat) = attr.value_str() {
925 926
                    let meta = attr::mk_name_value_item_str(Ident::from_str("target_feature"),
                                                            dummy_spanned(feat));
927 928 929 930 931 932 933
                    if let Ok(feat_cfg) = Cfg::parse(&meta) {
                        cfg &= feat_cfg;
                    }
                }
            }
        }

934 935 936 937 938
        let inner_docs = attrs.iter()
                              .filter(|a| a.check_name("doc"))
                              .next()
                              .map_or(true, |a| a.style == AttrStyle::Inner);

939
        Attributes {
K
kennytm 已提交
940 941
            doc_strings,
            other_attrs,
J
John Kåre Alsaker 已提交
942
            cfg: if cfg == Cfg::True { None } else { Some(Arc::new(cfg)) },
943
            span: sp,
944
            links: vec![],
945
            inner_docs,
946 947
        }
    }
948 949 950 951

    /// Finds the `doc` attribute as a NameValue and returns the corresponding
    /// value found.
    pub fn doc_value<'a>(&'a self) -> Option<&'a str> {
952 953 954 955 956 957 958 959 960 961 962
        self.doc_strings.first().map(|s| s.as_str())
    }

    /// Finds all `doc` attributes as NameValues and returns their corresponding values, joined
    /// with newlines.
    pub fn collapsed_doc_value(&self) -> Option<String> {
        if !self.doc_strings.is_empty() {
            Some(self.doc_strings.iter().collect())
        } else {
            None
        }
963
    }
964

A
Alexander Regueiro 已提交
965
    /// Gets links as a vector
966 967
    ///
    /// Cache must be populated before call
G
Guillaume Gomez 已提交
968
    pub fn links(&self, krate: &CrateNum) -> Vec<(String, String)> {
969 970
        use crate::html::format::href;

M
Manish Goregaokar 已提交
971
        self.links.iter().filter_map(|&(ref s, did, ref fragment)| {
G
Guillaume Gomez 已提交
972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994
            match did {
                Some(did) => {
                    if let Some((mut href, ..)) = href(did) {
                        if let Some(ref fragment) = *fragment {
                            href.push_str("#");
                            href.push_str(fragment);
                        }
                        Some((s.clone(), href))
                    } else {
                        None
                    }
                }
                None => {
                    if let Some(ref fragment) = *fragment {
                        let cache = cache();
                        let url = match cache.extern_locations.get(krate) {
                            Some(&(_, ref src, ExternalLocation::Local)) =>
                                src.to_str().expect("invalid file path"),
                            Some(&(_, _, ExternalLocation::Remote(ref s))) => s,
                            Some(&(_, _, ExternalLocation::Unknown)) | None =>
                                "https://doc.rust-lang.org/nightly",
                        };
                        // This is a primitive so the url is done "by hand".
995
                        let tail = fragment.find('#').unwrap_or_else(|| fragment.len());
G
Guillaume Gomez 已提交
996
                        Some((s.clone(),
997
                              format!("{}{}std/primitive.{}.html{}",
G
Guillaume Gomez 已提交
998 999
                                      url,
                                      if !url.ends_with('/') { "/" } else { "" },
1000 1001
                                      &fragment[..tail],
                                      &fragment[tail..])))
G
Guillaume Gomez 已提交
1002 1003 1004
                    } else {
                        panic!("This isn't a primitive?!");
                    }
M
Manish Goregaokar 已提交
1005
                }
1006 1007 1008
            }
        }).collect()
    }
C
Corey Richardson 已提交
1009 1010
}

1011 1012 1013 1014 1015 1016
impl PartialEq for Attributes {
    fn eq(&self, rhs: &Self) -> bool {
        self.doc_strings == rhs.doc_strings &&
        self.cfg == rhs.cfg &&
        self.span == rhs.span &&
        self.links == rhs.links &&
1017
        self.other_attrs.iter().map(|attr| attr.id).eq(rhs.other_attrs.iter().map(|attr| attr.id))
1018 1019 1020 1021 1022
    }
}

impl Eq for Attributes {}

1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034
impl Hash for Attributes {
    fn hash<H: Hasher>(&self, hasher: &mut H) {
        self.doc_strings.hash(hasher);
        self.cfg.hash(hasher);
        self.span.hash(hasher);
        self.links.hash(hasher);
        for attr in &self.other_attrs {
            attr.id.hash(hasher);
        }
    }
}

1035 1036 1037
impl AttributesExt for Attributes {
    fn lists<'a>(&'a self, name: &'a str) -> ListAttributesIter<'a> {
        self.other_attrs.lists(name)
C
Corey Richardson 已提交
1038 1039 1040
    }
}

1041
impl Clean<Attributes> for [ast::Attribute] {
1042
    fn clean(&self, cx: &DocContext<'_>) -> Attributes {
1043
        Attributes::from_ast(cx.sess().diagnostic(), self)
C
Corey Richardson 已提交
1044 1045 1046
    }
}

1047
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)]
V
varkor 已提交
1048
pub enum GenericBound {
V
varkor 已提交
1049 1050
    TraitBound(PolyTrait, hir::TraitBoundModifier),
    Outlives(Lifetime),
C
Corey Richardson 已提交
1051 1052
}

V
varkor 已提交
1053
impl GenericBound {
1054
    fn maybe_sized(cx: &DocContext<'_>) -> GenericBound {
1055
        let did = cx.tcx.require_lang_item(lang_items::SizedTraitLangItem);
1056
        let empty = cx.tcx.intern_substs(&[]);
1057
        let path = external_path(cx, &cx.tcx.item_name(did).as_str(),
1058 1059
            Some(did), false, vec![], empty);
        inline::record_extern_fqn(cx, did, TypeKind::Trait);
V
varkor 已提交
1060
        GenericBound::TraitBound(PolyTrait {
1061
            trait_: ResolvedPath {
1062
                path,
1063
                param_names: None,
1064
                did,
1065 1066
                is_generic: false,
            },
1067
            generic_params: Vec::new(),
1068
        }, hir::TraitBoundModifier::Maybe)
1069 1070
    }

1071
    fn is_sized_bound(&self, cx: &DocContext<'_>) -> bool {
1072
        use rustc::hir::TraitBoundModifier as TBM;
V
varkor 已提交
1073
        if let GenericBound::TraitBound(PolyTrait { ref trait_, .. }, TBM::None) = *self {
1074
            if trait_.def_id() == cx.tcx.lang_items().sized_trait() {
1075
                return true;
1076 1077 1078 1079
            }
        }
        false
    }
1080 1081

    fn get_poly_trait(&self) -> Option<PolyTrait> {
V
varkor 已提交
1082
        if let GenericBound::TraitBound(ref p, _) = *self {
1083 1084 1085 1086 1087 1088
            return Some(p.clone())
        }
        None
    }

    fn get_trait_type(&self) -> Option<Type> {
V
varkor 已提交
1089
        if let GenericBound::TraitBound(PolyTrait { ref trait_, .. }, _) = *self {
1090 1091 1092
            Some(trait_.clone())
        } else {
            None
1093 1094
        }
    }
1095 1096
}

V
varkor 已提交
1097
impl Clean<GenericBound> for hir::GenericBound {
1098
    fn clean(&self, cx: &DocContext<'_>) -> GenericBound {
C
Corey Richardson 已提交
1099
        match *self {
V
varkor 已提交
1100 1101 1102 1103
            hir::GenericBound::Outlives(lt) => GenericBound::Outlives(lt.clean(cx)),
            hir::GenericBound::Trait(ref t, modifier) => {
                GenericBound::TraitBound(t.clean(cx), modifier)
            }
C
Corey Richardson 已提交
1104 1105 1106 1107
        }
    }
}

1108 1109 1110 1111 1112 1113 1114 1115
fn external_generic_args(
    cx: &DocContext<'_>,
    trait_did: Option<DefId>,
    has_self: bool,
    bindings: Vec<TypeBinding>,
    substs: SubstsRef<'_>,
) -> GenericArgs {
    let mut skip_self = has_self;
V
varkor 已提交
1116
    let mut ty_sty = None;
1117 1118 1119 1120 1121 1122 1123 1124 1125
    let args: Vec<_> = substs.iter().filter_map(|kind| match kind.unpack() {
        UnpackedKind::Lifetime(lt) => {
            lt.clean(cx).and_then(|lt| Some(GenericArg::Lifetime(lt)))
        }
        UnpackedKind::Type(_) if skip_self => {
            skip_self = false;
            None
        }
        UnpackedKind::Type(ty) => {
V
varkor 已提交
1126
            ty_sty = Some(&ty.sty);
1127 1128 1129 1130
            Some(GenericArg::Type(ty.clean(cx)))
        }
        UnpackedKind::Const(ct) => Some(GenericArg::Const(ct.clean(cx))),
    }).collect();
1131

1132
    match trait_did {
1133
        // Attempt to sugar an external path like Fn<(A, B,), C> to Fn(A, B) -> C
1134
        Some(did) if cx.tcx.lang_items().fn_trait_kind(did).is_some() => {
V
varkor 已提交
1135 1136
            assert!(ty_sty.is_some());
            let inputs = match ty_sty {
1137 1138
                Some(ty::Tuple(ref tys)) => tys.iter().map(|t| t.clean(cx)).collect(),
                _ => return GenericArgs::AngleBracketed { args, bindings },
1139
            };
1140 1141 1142
            let output = None;
            // FIXME(#20299) return type comes from a projection now
            // match types[1].sty {
V
varkor 已提交
1143
            //     ty::Tuple(ref v) if v.is_empty() => None, // -> ()
1144 1145
            //     _ => Some(types[1].clean(cx))
            // };
1146
            GenericArgs::Parenthesized { inputs, output }
1147
        },
1148
        _ => {
1149
            GenericArgs::AngleBracketed { args, bindings }
1150 1151 1152 1153 1154 1155
        }
    }
}

// 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
1156
fn external_path(cx: &DocContext<'_>, name: &str, trait_did: Option<DefId>, has_self: bool,
C
csmoe 已提交
1157
                 bindings: Vec<TypeBinding>, substs: SubstsRef<'_>) -> Path {
1158 1159
    Path {
        global: false,
1160
        def: Def::Err,
1161
        segments: vec![PathSegment {
1162
            name: name.to_string(),
V
varkor 已提交
1163
            args: external_generic_args(cx, trait_did, has_self, bindings, substs)
1164
        }],
1165 1166 1167
    }
}

V
varkor 已提交
1168
impl<'a, 'tcx> Clean<GenericBound> for (&'a ty::TraitRef<'tcx>, Vec<TypeBinding>) {
1169
    fn clean(&self, cx: &DocContext<'_>) -> GenericBound {
1170 1171
        let (trait_ref, ref bounds) = *self;
        inline::record_extern_fqn(cx, trait_ref.def_id, TypeKind::Trait);
1172
        let path = external_path(cx, &cx.tcx.item_name(trait_ref.def_id).as_str(),
1173
                                 Some(trait_ref.def_id), true, bounds.clone(), trait_ref.substs);
1174

1175
        debug!("ty::TraitRef\n  subst: {:?}\n", trait_ref.substs);
1176 1177 1178

        // collect any late bound regions
        let mut late_bounds = vec![];
1179
        for ty_s in trait_ref.input_types().skip(1) {
V
varkor 已提交
1180
            if let ty::Tuple(ts) = ty_s.sty {
1181
                for &ty_s in ts {
V
varkor 已提交
1182
                    if let ty::Ref(ref reg, _, _) = ty_s.sty {
N
Niko Matsakis 已提交
1183
                        if let &ty::RegionKind::ReLateBound(..) = *reg {
1184
                            debug!("  hit an ReLateBound {:?}", reg);
1185 1186 1187 1188 1189
                            if let Some(Lifetime(name)) = reg.clean(cx) {
                                late_bounds.push(GenericParamDef {
                                    name,
                                    kind: GenericParamDefKind::Lifetime,
                                });
1190 1191 1192 1193 1194 1195 1196
                            }
                        }
                    }
                }
            }
        }

V
varkor 已提交
1197
        GenericBound::TraitBound(
1198 1199
            PolyTrait {
                trait_: ResolvedPath {
1200
                    path,
V
varkor 已提交
1201
                    param_names: None,
1202
                    did: trait_ref.def_id,
1203 1204
                    is_generic: false,
                },
1205
                generic_params: late_bounds,
1206
            },
1207 1208
            hir::TraitBoundModifier::None
        )
1209 1210 1211
    }
}

V
varkor 已提交
1212
impl<'tcx> Clean<GenericBound> for ty::TraitRef<'tcx> {
1213
    fn clean(&self, cx: &DocContext<'_>) -> GenericBound {
1214 1215 1216 1217
        (self, vec![]).clean(cx)
    }
}

C
csmoe 已提交
1218
impl<'tcx> Clean<Option<Vec<GenericBound>>> for InternalSubsts<'tcx> {
1219
    fn clean(&self, cx: &DocContext<'_>) -> Option<Vec<GenericBound>> {
1220
        let mut v = Vec::new();
V
varkor 已提交
1221 1222
        v.extend(self.regions().filter_map(|r| r.clean(cx)).map(GenericBound::Outlives));
        v.extend(self.types().map(|t| GenericBound::TraitBound(PolyTrait {
1223
            trait_: t.clean(cx),
1224
            generic_params: Vec::new(),
1225
        }, hir::TraitBoundModifier::None)));
1226
        if !v.is_empty() {Some(v)} else {None}
1227 1228 1229
    }
}

1230
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)]
1231
pub struct Lifetime(String);
C
Corey Richardson 已提交
1232

1233 1234 1235
impl Lifetime {
    pub fn get_ref<'a>(&'a self) -> &'a str {
        let Lifetime(ref s) = *self;
1236
        let s: &'a str = s;
C
Corey Farwell 已提交
1237
        s
1238
    }
1239 1240 1241 1242

    pub fn statik() -> Lifetime {
        Lifetime("'static".to_string())
    }
1243 1244
}

1245
impl Clean<Lifetime> for hir::Lifetime {
1246
    fn clean(&self, cx: &DocContext<'_>) -> Lifetime {
L
ljedrz 已提交
1247
        if self.hir_id != hir::DUMMY_HIR_ID {
1248
            let def = cx.tcx.named_region(self.hir_id);
1249 1250 1251 1252 1253 1254 1255
            match def {
                Some(rl::Region::EarlyBound(_, node_id, _)) |
                Some(rl::Region::LateBound(_, node_id, _)) |
                Some(rl::Region::Free(_, node_id)) => {
                    if let Some(lt) = cx.lt_substs.borrow().get(&node_id).cloned() {
                        return lt;
                    }
E
Eduard Burtescu 已提交
1256
                }
1257
                _ => {}
E
Eduard Burtescu 已提交
1258 1259
            }
        }
1260
        Lifetime(self.name.ident().to_string())
C
Corey Richardson 已提交
1261 1262 1263
    }
}

V
varkor 已提交
1264
impl Clean<Lifetime> for hir::GenericParam {
1265
    fn clean(&self, _: &DocContext<'_>) -> Lifetime {
V
varkor 已提交
1266
        match self.kind {
V
varkor 已提交
1267 1268 1269
            hir::GenericParamKind::Lifetime { .. } => {
                if self.bounds.len() > 0 {
                    let mut bounds = self.bounds.iter().map(|bound| match bound {
V
varkor 已提交
1270
                        hir::GenericBound::Outlives(lt) => lt,
V
varkor 已提交
1271 1272
                        _ => panic!(),
                    });
G
Guillaume Gomez 已提交
1273
                    let name = bounds.next().expect("no more bounds").name.ident();
1274
                    let mut s = format!("{}: {}", self.name.ident(), name);
V
varkor 已提交
1275
                    for bound in bounds {
1276
                        s.push_str(&format!(" + {}", bound.name.ident()));
V
varkor 已提交
1277 1278 1279
                    }
                    Lifetime(s)
                } else {
1280
                    Lifetime(self.name.ident().to_string())
V
varkor 已提交
1281
                }
1282
            }
V
varkor 已提交
1283
            _ => panic!(),
1284
        }
1285 1286 1287
    }
}

V
varkor 已提交
1288
impl Clean<Constant> for hir::ConstArg {
1289
    fn clean(&self, cx: &DocContext<'_>) -> Constant {
V
varkor 已提交
1290 1291 1292 1293 1294 1295 1296
        Constant {
            type_: cx.tcx.type_of(cx.tcx.hir().body_owner_def_id(self.value.body)).clean(cx),
            expr: print_const_expr(cx, self.value.body),
        }
    }
}

1297
impl<'tcx> Clean<Lifetime> for ty::GenericParamDef {
1298
    fn clean(&self, _cx: &DocContext<'_>) -> Lifetime {
1299
        Lifetime(self.name.to_string())
1300 1301 1302
    }
}

1303
impl Clean<Option<Lifetime>> for ty::RegionKind {
1304
    fn clean(&self, cx: &DocContext<'_>) -> Option<Lifetime> {
1305
        match *self {
1306
            ty::ReStatic => Some(Lifetime::statik()),
1307
            ty::ReLateBound(_, ty::BrNamed(_, name)) => Some(Lifetime(name.to_string())),
N
Niko Matsakis 已提交
1308
            ty::ReEarlyBound(ref data) => Some(Lifetime(data.name.clean(cx))),
1309 1310 1311 1312

            ty::ReLateBound(..) |
            ty::ReFree(..) |
            ty::ReScope(..) |
1313
            ty::ReVar(..) |
N
Niko Matsakis 已提交
1314
            ty::RePlaceholder(..) |
1315
            ty::ReEmpty |
1316
            ty::ReClosureBound(_) |
1317 1318 1319 1320
            ty::ReErased => {
                debug!("Cannot clean region {:?}", self);
                None
            }
1321 1322 1323 1324
        }
    }
}

1325
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)]
1326
pub enum WherePredicate {
V
varkor 已提交
1327 1328
    BoundPredicate { ty: Type, bounds: Vec<GenericBound> },
    RegionPredicate { lifetime: Lifetime, bounds: Vec<GenericBound> },
1329
    EqPredicate { lhs: Type, rhs: Type },
1330 1331
}

1332 1333 1334 1335 1336 1337 1338 1339 1340 1341
impl WherePredicate {
    pub fn get_bounds(&self) -> Option<&[GenericBound]> {
        match *self {
            WherePredicate::BoundPredicate { ref bounds, .. } => Some(bounds),
            WherePredicate::RegionPredicate { ref bounds, .. } => Some(bounds),
            _ => None,
        }
    }
}

1342
impl Clean<WherePredicate> for hir::WherePredicate {
1343
    fn clean(&self, cx: &DocContext<'_>) -> WherePredicate {
N
Nick Cameron 已提交
1344
        match *self {
1345
            hir::WherePredicate::BoundPredicate(ref wbp) => {
1346
                WherePredicate::BoundPredicate {
1347
                    ty: wbp.bounded_ty.clean(cx),
N
Nick Cameron 已提交
1348 1349 1350
                    bounds: wbp.bounds.clean(cx)
                }
            }
1351

1352
            hir::WherePredicate::RegionPredicate(ref wrp) => {
1353 1354 1355 1356 1357 1358
                WherePredicate::RegionPredicate {
                    lifetime: wrp.lifetime.clean(cx),
                    bounds: wrp.bounds.clean(cx)
                }
            }

1359 1360 1361 1362 1363
            hir::WherePredicate::EqPredicate(ref wrp) => {
                WherePredicate::EqPredicate {
                    lhs: wrp.lhs_ty.clean(cx),
                    rhs: wrp.rhs_ty.clean(cx)
                }
N
Nick Cameron 已提交
1364
            }
1365 1366 1367 1368
        }
    }
}

1369
impl<'a> Clean<Option<WherePredicate>> for ty::Predicate<'a> {
1370
    fn clean(&self, cx: &DocContext<'_>) -> Option<WherePredicate> {
1371
        use rustc::ty::Predicate;
1372 1373

        match *self {
1374 1375
            Predicate::Trait(ref pred) => Some(pred.clean(cx)),
            Predicate::Subtype(ref pred) => Some(pred.clean(cx)),
1376 1377
            Predicate::RegionOutlives(ref pred) => pred.clean(cx),
            Predicate::TypeOutlives(ref pred) => pred.clean(cx),
1378
            Predicate::Projection(ref pred) => Some(pred.clean(cx)),
1379 1380 1381 1382

            Predicate::WellFormed(..) |
            Predicate::ObjectSafe(..) |
            Predicate::ClosureKind(..) |
1383
            Predicate::ConstEvaluatable(..) => panic!("not user writable"),
1384 1385 1386 1387 1388
        }
    }
}

impl<'a> Clean<WherePredicate> for ty::TraitPredicate<'a> {
1389
    fn clean(&self, cx: &DocContext<'_>) -> WherePredicate {
1390
        WherePredicate::BoundPredicate {
1391
            ty: self.trait_ref.self_ty().clean(cx),
1392 1393 1394 1395 1396
            bounds: vec![self.trait_ref.clean(cx)]
        }
    }
}

N
Niko Matsakis 已提交
1397
impl<'tcx> Clean<WherePredicate> for ty::SubtypePredicate<'tcx> {
1398
    fn clean(&self, _cx: &DocContext<'_>) -> WherePredicate {
1399 1400
        panic!("subtype predicates are an internal rustc artifact \
                and should not be seen by rustdoc")
N
Niko Matsakis 已提交
1401 1402 1403
    }
}

1404 1405 1406
impl<'tcx> Clean<Option<WherePredicate>> for
    ty::OutlivesPredicate<ty::Region<'tcx>,ty::Region<'tcx>> {

1407
    fn clean(&self, cx: &DocContext<'_>) -> Option<WherePredicate> {
1408
        let ty::OutlivesPredicate(ref a, ref b) = *self;
1409 1410 1411 1412 1413 1414 1415 1416 1417

        match (a, b) {
            (ty::ReEmpty, ty::ReEmpty) => {
                return None;
            },
            _ => {}
        }

        Some(WherePredicate::RegionPredicate {
G
Guillaume Gomez 已提交
1418 1419
            lifetime: a.clean(cx).expect("failed to clean lifetime"),
            bounds: vec![GenericBound::Outlives(b.clean(cx).expect("failed to clean bounds"))]
1420
        })
1421 1422 1423
    }
}

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

1428 1429 1430 1431 1432 1433
        match lt {
            ty::ReEmpty => return None,
            _ => {}
        }

        Some(WherePredicate::BoundPredicate {
1434
            ty: ty.clean(cx),
G
Guillaume Gomez 已提交
1435
            bounds: vec![GenericBound::Outlives(lt.clean(cx).expect("failed to clean lifetimes"))]
1436
        })
1437 1438 1439 1440
    }
}

impl<'tcx> Clean<WherePredicate> for ty::ProjectionPredicate<'tcx> {
1441
    fn clean(&self, cx: &DocContext<'_>) -> WherePredicate {
1442 1443 1444 1445 1446 1447 1448 1449
        WherePredicate::EqPredicate {
            lhs: self.projection_ty.clean(cx),
            rhs: self.ty.clean(cx)
        }
    }
}

impl<'tcx> Clean<Type> for ty::ProjectionTy<'tcx> {
1450
    fn clean(&self, cx: &DocContext<'_>) -> Type {
1451
        let trait_ = match self.trait_ref(cx.tcx).clean(cx) {
V
varkor 已提交
1452 1453
            GenericBound::TraitBound(t, _) => t.trait_,
            GenericBound::Outlives(_) => panic!("cleaning a trait got a lifetime"),
1454 1455
        };
        Type::QPath {
1456
            name: cx.tcx.associated_item(self.item_def_id).ident.name.clean(cx),
1457
            self_type: box self.self_ty().clean(cx),
1458 1459 1460 1461 1462
            trait_: box trait_
        }
    }
}

V
Vadim Petrochenkov 已提交
1463
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)]
1464 1465 1466 1467
pub enum GenericParamDefKind {
    Lifetime,
    Type {
        did: DefId,
V
varkor 已提交
1468
        bounds: Vec<GenericBound>,
1469 1470 1471
        default: Option<Type>,
        synthetic: Option<hir::SyntheticTyParamKind>,
    },
V
varkor 已提交
1472 1473 1474 1475
    Const {
        did: DefId,
        ty: Type,
    },
1476 1477
}

1478 1479 1480 1481 1482 1483 1484 1485
impl GenericParamDefKind {
    pub fn is_type(&self) -> bool {
        match *self {
            GenericParamDefKind::Type { .. } => true,
            _ => false,
        }
    }

G
cleanup  
Guillaume Gomez 已提交
1486
    pub fn get_type(&self, cx: &DocContext<'_>) -> Option<Type> {
1487 1488 1489 1490 1491 1492 1493 1494 1495 1496
        match *self {
            GenericParamDefKind::Type { did, .. } => {
                rustc_typeck::checked_type_of(cx.tcx, did, false).map(|t| t.clean(cx))
            }
            GenericParamDefKind::Const { ref ty, .. } => Some(ty.clone()),
            GenericParamDefKind::Lifetime => None,
        }
    }
}

1497 1498 1499 1500 1501
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)]
pub struct GenericParamDef {
    pub name: String,

    pub kind: GenericParamDefKind,
1502 1503
}

V
varkor 已提交
1504
impl GenericParamDef {
1505
    pub fn is_synthetic_type_param(&self) -> bool {
1506
        match self.kind {
V
varkor 已提交
1507
            GenericParamDefKind::Lifetime |
1508
            GenericParamDefKind::Const { .. } => false,
1509 1510 1511
            GenericParamDefKind::Type { ref synthetic, .. } => synthetic.is_some(),
        }
    }
1512 1513 1514 1515 1516

    pub fn is_type(&self) -> bool {
        self.kind.is_type()
    }

G
cleanup  
Guillaume Gomez 已提交
1517
    pub fn get_type(&self, cx: &DocContext<'_>) -> Option<Type> {
1518 1519 1520 1521 1522 1523 1524 1525 1526
        self.kind.get_type(cx)
    }

    pub fn get_bounds(&self) -> Option<&[GenericBound]> {
        match self.kind {
            GenericParamDefKind::Type { ref bounds, .. } => Some(bounds),
            _ => None,
        }
    }
1527 1528
}

1529
impl Clean<GenericParamDef> for ty::GenericParamDef {
1530
    fn clean(&self, cx: &DocContext<'_>) -> GenericParamDef {
1531 1532 1533 1534 1535
        let (name, kind) = match self.kind {
            ty::GenericParamDefKind::Lifetime => {
                (self.name.to_string(), GenericParamDefKind::Lifetime)
            }
            ty::GenericParamDefKind::Type { has_default, .. } => {
1536
                cx.renderinfo.borrow_mut().external_param_names
1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549
                             .insert(self.def_id, self.name.clean(cx));
                let default = if has_default {
                    Some(cx.tcx.type_of(self.def_id).clean(cx))
                } else {
                    None
                };
                (self.name.clean(cx), GenericParamDefKind::Type {
                    did: self.def_id,
                    bounds: vec![], // These are filled in from the where-clauses.
                    default,
                    synthetic: None,
                })
            }
1550
            ty::GenericParamDefKind::Const { .. } => {
1551 1552 1553 1554
                (self.name.clean(cx), GenericParamDefKind::Const {
                    did: self.def_id,
                    ty: cx.tcx.type_of(self.def_id).clean(cx),
                })
1555
            }
1556 1557 1558 1559 1560
        };

        GenericParamDef {
            name,
            kind,
1561 1562 1563 1564
        }
    }
}

V
varkor 已提交
1565
impl Clean<GenericParamDef> for hir::GenericParam {
1566
    fn clean(&self, cx: &DocContext<'_>) -> GenericParamDef {
1567
        let (name, kind) = match self.kind {
V
varkor 已提交
1568 1569 1570
            hir::GenericParamKind::Lifetime { .. } => {
                let name = if self.bounds.len() > 0 {
                    let mut bounds = self.bounds.iter().map(|bound| match bound {
V
varkor 已提交
1571
                        hir::GenericBound::Outlives(lt) => lt,
V
varkor 已提交
1572 1573
                        _ => panic!(),
                    });
G
Guillaume Gomez 已提交
1574
                    let name = bounds.next().expect("no more bounds").name.ident();
V
Vadim Petrochenkov 已提交
1575
                    let mut s = format!("{}: {}", self.name.ident(), name);
V
varkor 已提交
1576
                    for bound in bounds {
V
Vadim Petrochenkov 已提交
1577
                        s.push_str(&format!(" + {}", bound.name.ident()));
1578 1579 1580
                    }
                    s
                } else {
V
Vadim Petrochenkov 已提交
1581
                    self.name.ident().to_string()
1582 1583 1584
                };
                (name, GenericParamDefKind::Lifetime)
            }
V
varkor 已提交
1585
            hir::GenericParamKind::Type { ref default, synthetic } => {
V
Vadim Petrochenkov 已提交
1586
                (self.name.ident().name.clean(cx), GenericParamDefKind::Type {
L
ljedrz 已提交
1587
                    did: cx.tcx.hir().local_def_id_from_hir_id(self.hir_id),
V
varkor 已提交
1588
                    bounds: self.bounds.clean(cx),
1589 1590 1591
                    default: default.clean(cx),
                    synthetic: synthetic,
                })
V
varkor 已提交
1592
            }
V
varkor 已提交
1593 1594
            hir::GenericParamKind::Const { ref ty } => {
                (self.name.ident().name.clean(cx), GenericParamDefKind::Const {
L
ljedrz 已提交
1595
                    did: cx.tcx.hir().local_def_id_from_hir_id(self.hir_id),
V
varkor 已提交
1596 1597 1598
                    ty: ty.clean(cx),
                })
            }
1599 1600 1601 1602 1603
        };

        GenericParamDef {
            name,
            kind,
1604 1605 1606 1607
        }
    }
}

1608 1609
// maybe use a Generic enum and use Vec<Generic>?
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Default, Hash)]
C
Corey Richardson 已提交
1610
pub struct Generics {
V
varkor 已提交
1611
    pub params: Vec<GenericParamDef>,
1612
    pub where_predicates: Vec<WherePredicate>,
1613
}
C
Corey Richardson 已提交
1614

1615
impl Clean<Generics> for hir::Generics {
1616
    fn clean(&self, cx: &DocContext<'_>) -> Generics {
1617 1618 1619 1620
        // Synthetic type-parameters are inserted after normal ones.
        // In order for normal parameters to be able to refer to synthetic ones,
        // scans them first.
        fn is_impl_trait(param: &hir::GenericParam) -> bool {
V
varkor 已提交
1621 1622 1623 1624 1625
            match param.kind {
                hir::GenericParamKind::Type { synthetic, .. } => {
                    synthetic == Some(hir::SyntheticTyParamKind::ImplTrait)
                }
                _ => false,
1626 1627 1628 1629
            }
        }
        let impl_trait_params = self.params
            .iter()
1630 1631 1632 1633 1634 1635 1636 1637
            .filter(|param| is_impl_trait(param))
            .map(|param| {
                let param: GenericParamDef = param.clean(cx);
                match param.kind {
                    GenericParamDefKind::Lifetime => unreachable!(),
                    GenericParamDefKind::Type { did, ref bounds, .. } => {
                        cx.impl_trait_bounds.borrow_mut().insert(did, bounds.clone());
                    }
V
varkor 已提交
1638
                    GenericParamDefKind::Const { .. } => unreachable!(),
1639
                }
1640
                param
1641 1642 1643
            })
            .collect::<Vec<_>>();

1644
        let mut params = Vec::with_capacity(self.params.len());
1645
        for p in self.params.iter().filter(|p| !is_impl_trait(p)) {
1646 1647 1648
            let p = p.clean(cx);
            params.push(p);
        }
1649 1650
        params.extend(impl_trait_params);

1651
        let mut generics = Generics {
1652
            params,
1653
            where_predicates: self.where_clause.predicates.clean(cx),
1654 1655 1656 1657 1658
        };

        // Some duplicates are generated for ?Sized bounds between type params and where
        // predicates. The point in here is to move the bounds definitions from type params
        // to where predicates when such cases occur.
1659
        for where_pred in &mut generics.where_predicates {
1660 1661 1662
            match *where_pred {
                WherePredicate::BoundPredicate { ty: Generic(ref name), ref mut bounds } => {
                    if bounds.is_empty() {
1663 1664 1665 1666 1667 1668 1669 1670
                        for param in &mut generics.params {
                            match param.kind {
                                GenericParamDefKind::Lifetime => {}
                                GenericParamDefKind::Type { bounds: ref mut ty_bounds, .. } => {
                                    if &param.name == name {
                                        mem::swap(bounds, ty_bounds);
                                        break
                                    }
1671
                                }
V
varkor 已提交
1672
                                GenericParamDefKind::Const { .. } => {}
1673 1674 1675 1676 1677 1678
                            }
                        }
                    }
                }
                _ => continue,
            }
C
Corey Richardson 已提交
1679
        }
1680
        generics
C
Corey Richardson 已提交
1681 1682 1683
    }
}

1684
impl<'a, 'tcx> Clean<Generics> for (&'a ty::Generics,
1685
                                    &'a Lrc<ty::GenericPredicates<'tcx>>) {
1686
    fn clean(&self, cx: &DocContext<'_>) -> Generics {
1687 1688
        use self::WherePredicate as WP;

1689
        let (gens, preds) = *self;
1690

1691 1692 1693
        // Bounds in the type_params and lifetimes fields are repeated in the
        // predicates field (see rustc_typeck::collect::ty_generics), so remove
        // them.
1694 1695 1696
        let stripped_typarams = gens.params.iter().filter_map(|param| match param.kind {
            ty::GenericParamDefKind::Lifetime => None,
            ty::GenericParamDefKind::Type { .. } => {
V
Vadim Petrochenkov 已提交
1697
                if param.name == keywords::SelfUpper.name().as_str() {
1698
                    assert_eq!(param.index, 0);
1699
                    return None;
V
varkor 已提交
1700
                }
1701
                Some(param.clean(cx))
1702
            }
1703 1704 1705
            ty::GenericParamDefKind::Const { .. } => {
                unimplemented!() // FIXME(const_generics)
            }
1706
        }).collect::<Vec<GenericParamDef>>();
1707

1708
        let mut where_predicates = preds.predicates.iter()
1709
            .flat_map(|(p, _)| p.clean(cx))
1710
            .collect::<Vec<_>>();
1711

1712
        // Type parameters and have a Sized bound by default unless removed with
1713
        // ?Sized. Scan through the predicates and mark any type parameter with
1714
        // a Sized bound, removing the bounds as we find them.
1715 1716
        //
        // Note that associated types also have a sized bound by default, but we
1717
        // don't actually know the set of associated types right here so that's
1718
        // handled in cleaning associated types
1719
        let mut sized_params = FxHashSet::default();
1720 1721 1722 1723 1724 1725 1726 1727 1728
        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
                    }
1729
                }
1730
                _ => true,
1731
            }
1732
        });
1733

1734
        // Run through the type parameters again and insert a ?Sized
1735
        // unbound for any we didn't find to be Sized.
1736
        for tp in &stripped_typarams {
1737 1738 1739
            if !sized_params.contains(&tp.name) {
                where_predicates.push(WP::BoundPredicate {
                    ty: Type::Generic(tp.name.clone()),
V
varkor 已提交
1740
                    bounds: vec![GenericBound::maybe_sized(cx)],
1741 1742 1743 1744 1745
                })
            }
        }

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

1749
        Generics {
V
varkor 已提交
1750 1751
            params: gens.params
                        .iter()
1752
                        .flat_map(|param| match param.kind {
1753
                            ty::GenericParamDefKind::Lifetime => Some(param.clean(cx)),
1754
                            ty::GenericParamDefKind::Type { .. } => None,
1755
                            ty::GenericParamDefKind::Const { .. } => Some(param.clean(cx)),
1756
                        }).chain(simplify::ty_params(stripped_typarams).into_iter())
V
varkor 已提交
1757
                        .collect(),
1758
            where_predicates: simplify::where_clauses(cx, where_predicates),
1759 1760 1761 1762
        }
    }
}

G
cleanup  
Guillaume Gomez 已提交
1763 1764 1765 1766 1767
/// The point of this function is to replace bounds with types.
///
/// i.e. `[T, U]` when you have the following bounds: `T: Display, U: Option<T>` will return
/// `[Display, Option]` (we just returns the list of the types, we don't care about the
/// wrapped types in here).
1768
fn get_real_types(
1769 1770
    generics: &Generics,
    arg: &Type,
G
cleanup  
Guillaume Gomez 已提交
1771
    cx: &DocContext<'_>,
G
Guillaume Gomez 已提交
1772
    recurse: i32,
G
cleanup  
Guillaume Gomez 已提交
1773
) -> FxHashSet<Type> {
1774
    let arg_s = arg.to_string();
G
Guillaume Gomez 已提交
1775
    let mut res = FxHashSet::default();
G
Guillaume Gomez 已提交
1776 1777 1778
    if recurse >= 10 { // FIXME: remove this whole recurse thing when the recursion bug is fixed
        return res;
    }
1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794
    if arg.is_full_generic() {
        if let Some(where_pred) = generics.where_predicates.iter().find(|g| {
            match g {
                &WherePredicate::BoundPredicate { ref ty, .. } => ty.def_id() == arg.def_id(),
                _ => false,
            }
        }) {
            let bounds = where_pred.get_bounds().unwrap_or_else(|| &[]);
            for bound in bounds.iter() {
                match *bound {
                    GenericBound::TraitBound(ref poly_trait, _) => {
                        for x in poly_trait.generic_params.iter() {
                            if !x.is_type() {
                                continue
                            }
                            if let Some(ty) = x.get_type(cx) {
G
Guillaume Gomez 已提交
1795
                                let adds = get_real_types(generics, &ty, cx, recurse + 1);
1796
                                if !adds.is_empty() {
G
cleanup  
Guillaume Gomez 已提交
1797
                                    res.extend(adds);
1798
                                } else if !ty.is_full_generic() {
G
Guillaume Gomez 已提交
1799
                                    res.insert(ty);
1800
                                }
1801 1802 1803
                            }
                        }
                    }
1804
                    _ => {}
1805 1806 1807 1808 1809 1810 1811 1812
                }
            }
        }
        if let Some(bound) = generics.params.iter().find(|g| {
            g.is_type() && g.name == arg_s
        }) {
            for bound in bound.get_bounds().unwrap_or_else(|| &[]) {
                if let Some(ty) = bound.get_trait_type() {
G
Guillaume Gomez 已提交
1813
                    let adds = get_real_types(generics, &ty, cx, recurse + 1);
1814
                    if !adds.is_empty() {
G
cleanup  
Guillaume Gomez 已提交
1815
                        res.extend(adds);
1816
                    } else if !ty.is_full_generic() {
G
Guillaume Gomez 已提交
1817
                        res.insert(ty.clone());
1818 1819 1820
                    }
                }
            }
1821 1822
        }
    } else {
G
Guillaume Gomez 已提交
1823
        res.insert(arg.clone());
1824
        if let Some(gens) = arg.generics() {
1825 1826
            for gen in gens.iter() {
                if gen.is_full_generic() {
G
Guillaume Gomez 已提交
1827
                    let adds = get_real_types(generics, gen, cx, recurse + 1);
1828
                    if !adds.is_empty() {
G
cleanup  
Guillaume Gomez 已提交
1829
                        res.extend(adds);
1830 1831
                    }
                } else {
G
Guillaume Gomez 已提交
1832
                    res.insert(gen.clone());
1833 1834 1835 1836
                }
            }
        }
    }
1837
    res
1838 1839
}

G
cleanup  
Guillaume Gomez 已提交
1840 1841 1842 1843
/// Return the full list of types when bounds have been resolved.
///
/// i.e. `fn foo<A: Display, B: Option<A>>(x: u32, y: B)` will return
/// `[u32, Display, Option]`.
1844 1845 1846
pub fn get_all_types(
    generics: &Generics,
    decl: &FnDecl,
G
cleanup  
Guillaume Gomez 已提交
1847
    cx: &DocContext<'_>,
1848
) -> (Vec<Type>, Vec<Type>) {
G
Guillaume Gomez 已提交
1849
    let mut all_types = FxHashSet::default();
1850 1851 1852 1853
    for arg in decl.inputs.values.iter() {
        if arg.type_.is_self_type() {
            continue;
        }
G
Guillaume Gomez 已提交
1854
        let args = get_real_types(generics, &arg.type_, cx, 0);
1855
        if !args.is_empty() {
G
cleanup  
Guillaume Gomez 已提交
1856
            all_types.extend(args);
1857
        } else {
G
Guillaume Gomez 已提交
1858
            all_types.insert(arg.type_.clone());
1859 1860
        }
    }
1861

G
Guillaume Gomez 已提交
1862
    let ret_types = match decl.output {
1863
        FunctionRetTy::Return(ref return_type) => {
G
Guillaume Gomez 已提交
1864
            let mut ret = get_real_types(generics, &return_type, cx, 0);
1865
            if ret.is_empty() {
G
Guillaume Gomez 已提交
1866
                ret.insert(return_type.clone());
1867
            }
G
Guillaume Gomez 已提交
1868
            ret.into_iter().collect()
1869 1870 1871
        }
        _ => Vec::new(),
    };
G
Guillaume Gomez 已提交
1872
    (all_types.into_iter().collect(), ret_types)
1873 1874
}

J
Jorge Aparicio 已提交
1875
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
1876
pub struct Method {
1877 1878
    pub generics: Generics,
    pub decl: FnDecl,
W
Without Boats 已提交
1879
    pub header: hir::FnHeader,
1880
    pub defaultness: Option<hir::Defaultness>,
1881
    pub all_types: Vec<Type>,
1882
    pub ret_types: Vec<Type>,
C
Corey Richardson 已提交
1883 1884
}

1885 1886
impl<'a> Clean<Method> for (&'a hir::MethodSig, &'a hir::Generics, hir::BodyId,
                            Option<hir::Defaultness>) {
1887
    fn clean(&self, cx: &DocContext<'_>) -> Method {
1888 1889 1890
        let (generics, decl) = enter_impl_trait(cx, || {
            (self.1.clean(cx), (&*self.0.decl, self.2).clean(cx))
        });
1891
        let (all_types, ret_types) = get_all_types(&generics, &decl, cx);
1892
        Method {
1893
            decl,
1894
            generics,
W
Without Boats 已提交
1895
            header: self.0.header,
1896
            defaultness: self.3,
1897
            all_types,
1898
            ret_types,
C
Corey Richardson 已提交
1899 1900 1901 1902
        }
    }
}

J
Jorge Aparicio 已提交
1903
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
1904
pub struct TyMethod {
W
Without Boats 已提交
1905
    pub header: hir::FnHeader,
1906 1907
    pub decl: FnDecl,
    pub generics: Generics,
1908
    pub all_types: Vec<Type>,
1909
    pub ret_types: Vec<Type>,
C
Corey Richardson 已提交
1910 1911
}

J
Jorge Aparicio 已提交
1912
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
1913
pub struct Function {
1914 1915
    pub decl: FnDecl,
    pub generics: Generics,
W
Without Boats 已提交
1916
    pub header: hir::FnHeader,
1917
    pub all_types: Vec<Type>,
1918
    pub ret_types: Vec<Type>,
C
Corey Richardson 已提交
1919 1920 1921
}

impl Clean<Item> for doctree::Function {
1922
    fn clean(&self, cx: &DocContext<'_>) -> Item {
1923 1924 1925
        let (generics, decl) = enter_impl_trait(cx, || {
            (self.generics.clean(cx), (&self.decl, self.body).clean(cx))
        });
G
Guillaume Gomez 已提交
1926

L
ljedrz 已提交
1927
        let did = cx.tcx.hir().local_def_id_from_hir_id(self.id);
G
Guillaume Gomez 已提交
1928 1929 1930 1931 1932
        let constness = if cx.tcx.is_min_const_fn(did) {
            hir::Constness::Const
        } else {
            hir::Constness::NotConst
        };
1933
        let (all_types, ret_types) = get_all_types(&generics, &decl, cx);
C
Corey Richardson 已提交
1934
        Item {
1935 1936 1937 1938 1939
            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),
1940
            deprecation: self.depr.clean(cx),
G
Guillaume Gomez 已提交
1941
            def_id: did,
C
Corey Richardson 已提交
1942
            inner: FunctionItem(Function {
1943 1944
                decl,
                generics,
G
Guillaume Gomez 已提交
1945
                header: hir::FnHeader { constness, ..self.header },
1946
                all_types,
1947
                ret_types,
C
Corey Richardson 已提交
1948 1949 1950 1951 1952
            }),
        }
    }
}

1953
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)]
C
Corey Richardson 已提交
1954
pub struct FnDecl {
1955
    pub inputs: Arguments,
1956
    pub output: FunctionRetTy,
1957
    pub attrs: Attributes,
1958
}
C
Corey Richardson 已提交
1959

1960
impl FnDecl {
1961 1962 1963
    pub fn self_type(&self) -> Option<SelfTy> {
        self.inputs.values.get(0).and_then(|v| v.to_self())
    }
1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987

    /// Returns the sugared return type for an async function.
    ///
    /// For example, if the return type is `impl std::future::Future<Output = i32>`, this function
    /// will return `i32`.
    ///
    /// # Panics
    ///
    /// This function will panic if the return type does not match the expected sugaring for async
    /// functions.
    pub fn sugared_async_return_type(&self) -> FunctionRetTy {
        match &self.output {
            FunctionRetTy::Return(Type::ImplTrait(bounds)) => {
                match &bounds[0] {
                    GenericBound::TraitBound(PolyTrait { trait_, .. }, ..) => {
                        let bindings = trait_.bindings().unwrap();
                        FunctionRetTy::Return(bindings[0].ty.clone())
                    }
                    _ => panic!("unexpected desugaring of async function"),
                }
            }
            _ => panic!("unexpected desugaring of async function"),
        }
    }
1988 1989
}

1990
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)]
1991
pub struct Arguments {
1992
    pub values: Vec<Argument>,
1993 1994
}

1995
impl<'a> Clean<Arguments> for (&'a [hir::Ty], &'a [ast::Ident]) {
1996
    fn clean(&self, cx: &DocContext<'_>) -> Arguments {
1997 1998
        Arguments {
            values: self.0.iter().enumerate().map(|(i, ty)| {
1999
                let mut name = self.1.get(i).map(|ident| ident.to_string())
2000 2001 2002 2003 2004
                                            .unwrap_or(String::new());
                if name.is_empty() {
                    name = "_".to_string();
                }
                Argument {
2005
                    name,
2006 2007 2008 2009 2010 2011 2012
                    type_: ty.clean(cx),
                }
            }).collect()
        }
    }
}

O
Oliver Schneider 已提交
2013
impl<'a> Clean<Arguments> for (&'a [hir::Ty], hir::BodyId) {
2014
    fn clean(&self, cx: &DocContext<'_>) -> Arguments {
2015
        let body = cx.tcx.hir().body(self.1);
2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028

        Arguments {
            values: self.0.iter().enumerate().map(|(i, ty)| {
                Argument {
                    name: name_from_pat(&body.arguments[i].pat),
                    type_: ty.clean(cx),
                }
            }).collect()
        }
    }
}

impl<'a, A: Copy> Clean<FnDecl> for (&'a hir::FnDecl, A)
O
Oliver Schneider 已提交
2029
    where (&'a [hir::Ty], A): Clean<Arguments>
2030
{
2031
    fn clean(&self, cx: &DocContext<'_>) -> FnDecl {
C
Corey Richardson 已提交
2032
        FnDecl {
2033 2034
            inputs: (&self.0.inputs[..], self.1).clean(cx),
            output: self.0.output.clean(cx),
2035
            attrs: Attributes::default(),
C
Corey Richardson 已提交
2036 2037 2038 2039
        }
    }
}

2040
impl<'a, 'tcx> Clean<FnDecl> for (DefId, ty::PolyFnSig<'tcx>) {
2041
    fn clean(&self, cx: &DocContext<'_>) -> FnDecl {
2042
        let (did, sig) = *self;
2043
        let mut names = if cx.tcx.hir().as_local_hir_id(did).is_some() {
2044
            vec![].into_iter()
2045
        } else {
A
achernyak 已提交
2046
            cx.tcx.fn_arg_names(did).into_iter()
S
Cleanup  
Shotaro Yamada 已提交
2047 2048
        };

2049
        FnDecl {
2050
            output: Return(sig.skip_binder().output().clean(cx)),
2051
            attrs: Attributes::default(),
2052
            inputs: Arguments {
2053
                values: sig.skip_binder().inputs().iter().map(|t| {
2054
                    Argument {
2055
                        type_: t.clean(cx),
2056
                        name: names.next().map_or(String::new(), |name| name.to_string()),
2057 2058 2059 2060 2061 2062 2063
                    }
                }).collect(),
            },
        }
    }
}

2064
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)]
C
Corey Richardson 已提交
2065
pub struct Argument {
2066
    pub type_: Type,
2067
    pub name: String,
C
Corey Richardson 已提交
2068 2069
}

2070 2071 2072 2073 2074 2075 2076 2077 2078
#[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> {
2079 2080 2081 2082 2083 2084 2085 2086 2087
        if self.name != "self" {
            return None;
        }
        if self.type_.is_self_type() {
            return Some(SelfValue);
        }
        match self.type_ {
            BorrowedRef{ref lifetime, mutability, ref type_} if type_.is_self_type() => {
                Some(SelfBorrowed(lifetime.clone(), mutability))
2088
            }
2089
            _ => Some(SelfExplicit(self.type_.clone()))
2090 2091 2092 2093
        }
    }
}

2094
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)]
2095 2096
pub enum FunctionRetTy {
    Return(Type),
2097
    DefaultReturn,
C
Corey Richardson 已提交
2098 2099
}

2100
impl Clean<FunctionRetTy> for hir::FunctionRetTy {
2101
    fn clean(&self, cx: &DocContext<'_>) -> FunctionRetTy {
C
Corey Richardson 已提交
2102
        match *self {
2103 2104
            hir::Return(ref typ) => Return(typ.clean(cx)),
            hir::DefaultReturn(..) => DefaultReturn,
C
Corey Richardson 已提交
2105 2106 2107 2108
        }
    }
}

2109 2110 2111 2112 2113 2114 2115 2116 2117
impl GetDefId for FunctionRetTy {
    fn def_id(&self) -> Option<DefId> {
        match *self {
            Return(ref ty) => ty.def_id(),
            DefaultReturn => None,
        }
    }
}

J
Jorge Aparicio 已提交
2118
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
2119
pub struct Trait {
2120
    pub auto: bool,
2121
    pub unsafety: hir::Unsafety,
2122
    pub items: Vec<Item>,
2123
    pub generics: Generics,
V
varkor 已提交
2124
    pub bounds: Vec<GenericBound>,
2125
    pub is_spotlight: bool,
2126
    pub is_auto: bool,
C
Corey Richardson 已提交
2127 2128 2129
}

impl Clean<Item> for doctree::Trait {
2130
    fn clean(&self, cx: &DocContext<'_>) -> Item {
2131 2132
        let attrs = self.attrs.clean(cx);
        let is_spotlight = attrs.has_doc_flag("spotlight");
C
Corey Richardson 已提交
2133
        Item {
2134
            name: Some(self.name.clean(cx)),
2135
            attrs: attrs,
2136
            source: self.whence.clean(cx),
L
ljedrz 已提交
2137
            def_id: cx.tcx.hir().local_def_id_from_hir_id(self.id),
2138 2139
            visibility: self.vis.clean(cx),
            stability: self.stab.clean(cx),
2140
            deprecation: self.depr.clean(cx),
C
Corey Richardson 已提交
2141
            inner: TraitItem(Trait {
2142
                auto: self.is_auto.clean(cx),
2143
                unsafety: self.unsafety,
2144 2145 2146
                items: self.items.clean(cx),
                generics: self.generics.clean(cx),
                bounds: self.bounds.clean(cx),
2147
                is_spotlight,
2148
                is_auto: self.is_auto.clean(cx),
C
Corey Richardson 已提交
2149 2150 2151 2152 2153
            }),
        }
    }
}

2154 2155 2156 2157 2158 2159 2160
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
pub struct TraitAlias {
    pub generics: Generics,
    pub bounds: Vec<GenericBound>,
}

impl Clean<Item> for doctree::TraitAlias {
2161
    fn clean(&self, cx: &DocContext<'_>) -> Item {
2162 2163 2164 2165 2166
        let attrs = self.attrs.clean(cx);
        Item {
            name: Some(self.name.clean(cx)),
            attrs,
            source: self.whence.clean(cx),
L
ljedrz 已提交
2167
            def_id: cx.tcx.hir().local_def_id_from_hir_id(self.id),
2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178
            visibility: self.vis.clean(cx),
            stability: self.stab.clean(cx),
            deprecation: self.depr.clean(cx),
            inner: TraitAliasItem(TraitAlias {
                generics: self.generics.clean(cx),
                bounds: self.bounds.clean(cx),
            }),
        }
    }
}

2179
impl Clean<bool> for hir::IsAuto {
2180
    fn clean(&self, _: &DocContext<'_>) -> bool {
2181 2182 2183 2184 2185 2186 2187
        match *self {
            hir::IsAuto::Yes => true,
            hir::IsAuto::No => false,
        }
    }
}

2188
impl Clean<Type> for hir::TraitRef {
2189
    fn clean(&self, cx: &DocContext<'_>) -> Type {
L
ljedrz 已提交
2190
        resolve_type(cx, self.path.clean(cx), self.hir_ref_id)
C
Corey Richardson 已提交
2191 2192 2193
    }
}

2194
impl Clean<PolyTrait> for hir::PolyTraitRef {
2195
    fn clean(&self, cx: &DocContext<'_>) -> PolyTrait {
2196 2197
        PolyTrait {
            trait_: self.trait_ref.clean(cx),
2198
            generic_params: self.bound_generic_params.clean(cx)
2199
        }
N
Niko Matsakis 已提交
2200 2201 2202
    }
}

2203
impl Clean<Item> for hir::TraitItem {
2204
    fn clean(&self, cx: &DocContext<'_>) -> Item {
2205
        let inner = match self.node {
2206
            hir::TraitItemKind::Const(ref ty, default) => {
2207
                AssociatedConstItem(ty.clean(cx),
2208
                                    default.map(|e| print_const_expr(cx, e)))
2209
            }
2210
            hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Provided(body)) => {
2211
                MethodItem((sig, &self.generics, body, None).clean(cx))
2212
            }
2213
            hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Required(ref names)) => {
2214 2215 2216
                let (generics, decl) = enter_impl_trait(cx, || {
                    (self.generics.clean(cx), (&*sig.decl, &names[..]).clean(cx))
                });
2217
                let (all_types, ret_types) = get_all_types(&generics, &decl, cx);
2218
                TyMethodItem(TyMethod {
W
Without Boats 已提交
2219
                    header: sig.header,
2220
                    decl,
2221
                    generics,
2222
                    all_types,
2223
                    ret_types,
2224
                })
2225
            }
2226
            hir::TraitItemKind::Type(ref bounds, ref default) => {
2227 2228 2229
                AssociatedTypeItem(bounds.clean(cx), default.clean(cx))
            }
        };
L
ljedrz 已提交
2230
        let local_did = cx.tcx.hir().local_def_id_from_hir_id(self.hir_id);
2231
        Item {
2232
            name: Some(self.ident.name.clean(cx)),
2233 2234
            attrs: self.attrs.clean(cx),
            source: self.span.clean(cx),
L
ljedrz 已提交
2235
            def_id: local_did,
2236
            visibility: None,
L
ljedrz 已提交
2237 2238
            stability: get_stability(cx, local_did),
            deprecation: get_deprecation(cx, local_did),
2239
            inner,
2240 2241 2242 2243
        }
    }
}

2244
impl Clean<Item> for hir::ImplItem {
2245
    fn clean(&self, cx: &DocContext<'_>) -> Item {
2246
        let inner = match self.node {
2247
            hir::ImplItemKind::Const(ref ty, expr) => {
2248
                AssociatedConstItem(ty.clean(cx),
2249
                                    Some(print_const_expr(cx, expr)))
2250
            }
2251
            hir::ImplItemKind::Method(ref sig, body) => {
2252
                MethodItem((sig, &self.generics, body, Some(self.defaultness)).clean(cx))
2253
            }
2254
            hir::ImplItemKind::Type(ref ty) => TypedefItem(Typedef {
2255
                type_: ty.clean(cx),
2256
                generics: Generics::default(),
2257
            }, true),
O
Oliver Schneider 已提交
2258 2259 2260 2261
            hir::ImplItemKind::Existential(ref bounds) => ExistentialItem(Existential {
                bounds: bounds.clean(cx),
                generics: Generics::default(),
            }, true),
2262
        };
L
ljedrz 已提交
2263
        let local_did = cx.tcx.hir().local_def_id_from_hir_id(self.hir_id);
2264
        Item {
2265
            name: Some(self.ident.name.clean(cx)),
2266 2267
            source: self.span.clean(cx),
            attrs: self.attrs.clean(cx),
L
ljedrz 已提交
2268
            def_id: local_did,
2269
            visibility: self.vis.clean(cx),
L
ljedrz 已提交
2270 2271
            stability: get_stability(cx, local_did),
            deprecation: get_deprecation(cx, local_did),
2272
            inner,
C
Corey Richardson 已提交
2273 2274 2275 2276
        }
    }
}

2277
impl<'tcx> Clean<Item> for ty::AssociatedItem {
2278
    fn clean(&self, cx: &DocContext<'_>) -> Item {
2279 2280
        let inner = match self.kind {
            ty::AssociatedKind::Const => {
2281
                let ty = cx.tcx.type_of(self.def_id);
2282 2283 2284 2285 2286 2287
                let default = if self.defaultness.has_value() {
                    Some(inline::print_inlined_const(cx, self.def_id))
                } else {
                    None
                };
                AssociatedConstItem(ty.clean(cx), default)
2288
            }
2289
            ty::AssociatedKind::Method => {
2290
                let generics = (cx.tcx.generics_of(self.def_id),
2291
                                &cx.tcx.explicit_predicates_of(self.def_id)).clean(cx);
2292
                let sig = cx.tcx.fn_sig(self.def_id);
2293
                let mut decl = (self.def_id, sig).clean(cx);
2294 2295 2296 2297

                if self.method_has_self_argument {
                    let self_ty = match self.container {
                        ty::ImplContainer(def_id) => {
2298
                            cx.tcx.type_of(def_id)
2299
                        }
2300
                        ty::TraitContainer(_) => cx.tcx.mk_self_type()
2301
                    };
2302
                    let self_arg_ty = *sig.input(0).skip_binder();
2303
                    if self_arg_ty == self_ty {
2304
                        decl.inputs.values[0].type_ = Generic(String::from("Self"));
V
varkor 已提交
2305
                    } else if let ty::Ref(_, ty, _) = self_arg_ty.sty {
2306
                        if ty == self_ty {
2307
                            match decl.inputs.values[0].type_ {
2308 2309 2310
                                BorrowedRef{ref mut type_, ..} => {
                                    **type_ = Generic(String::from("Self"))
                                }
2311 2312 2313 2314 2315
                                _ => unreachable!(),
                            }
                        }
                    }
                }
2316

2317
                let provided = match self.container {
2318
                    ty::ImplContainer(_) => true,
2319
                    ty::TraitContainer(_) => self.defaultness.has_value()
2320
                };
2321
                let (all_types, ret_types) = get_all_types(&generics, &decl, cx);
2322
                if provided {
2323
                    let constness = if cx.tcx.is_min_const_fn(self.def_id) {
2324 2325 2326 2327
                        hir::Constness::Const
                    } else {
                        hir::Constness::NotConst
                    };
2328
                    MethodItem(Method {
2329 2330
                        generics,
                        decl,
W
Without Boats 已提交
2331 2332 2333 2334
                        header: hir::FnHeader {
                            unsafety: sig.unsafety(),
                            abi: sig.abi(),
                            constness,
2335
                            asyncness: hir::IsAsync::NotAsync,
2336 2337
                        },
                        defaultness: Some(self.defaultness),
2338
                        all_types,
2339
                        ret_types,
2340 2341 2342
                    })
                } else {
                    TyMethodItem(TyMethod {
2343 2344
                        generics,
                        decl,
W
Without Boats 已提交
2345 2346 2347
                        header: hir::FnHeader {
                            unsafety: sig.unsafety(),
                            abi: sig.abi(),
2348 2349
                            constness: hir::Constness::NotConst,
                            asyncness: hir::IsAsync::NotAsync,
2350 2351
                        },
                        all_types,
2352
                        ret_types,
2353
                    })
2354 2355
                }
            }
2356
            ty::AssociatedKind::Type => {
2357
                let my_name = self.ident.name.clean(cx);
2358

2359
                if let ty::TraitContainer(did) = self.container {
2360 2361 2362 2363
                    // 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.
2364
                    let predicates = cx.tcx.explicit_predicates_of(did);
2365
                    let generics = (cx.tcx.generics_of(did), &predicates).clean(cx);
2366
                    let mut bounds = generics.where_predicates.iter().filter_map(|pred| {
2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383
                        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)
2384 2385 2386 2387 2388 2389 2390 2391
                    }).flat_map(|i| i.iter().cloned()).collect::<Vec<_>>();
                    // Our Sized/?Sized bound didn't get handled when creating the generics
                    // because we didn't actually get our whole set of bounds until just now
                    // (some of them may have come from the trait). If we do have a sized
                    // bound, we remove it, and if we don't then we add the `?Sized` bound
                    // at the end.
                    match bounds.iter().position(|b| b.is_sized_bound(cx)) {
                        Some(i) => { bounds.remove(i); }
V
varkor 已提交
2392
                        None => bounds.push(GenericBound::maybe_sized(cx)),
2393
                    }
2394

2395 2396 2397 2398 2399
                    let ty = if self.defaultness.has_value() {
                        Some(cx.tcx.type_of(self.def_id))
                    } else {
                        None
                    };
2400

2401
                    AssociatedTypeItem(bounds, ty.clean(cx))
2402
                } else {
2403 2404 2405
                    TypedefItem(Typedef {
                        type_: cx.tcx.type_of(self.def_id).clean(cx),
                        generics: Generics {
2406
                            params: Vec::new(),
2407 2408 2409 2410
                            where_predicates: Vec::new(),
                        },
                    }, true)
                }
2411
            }
O
Oliver Schneider 已提交
2412
            ty::AssociatedKind::Existential => unimplemented!(),
2413 2414
        };

2415 2416 2417 2418 2419
        let visibility = match self.container {
            ty::ImplContainer(_) => self.vis.clean(cx),
            ty::TraitContainer(_) => None,
        };

2420
        Item {
2421
            name: Some(self.ident.name.clean(cx)),
2422
            visibility,
2423
            stability: get_stability(cx, self.def_id),
2424
            deprecation: get_deprecation(cx, self.def_id),
2425
            def_id: self.def_id,
2426
            attrs: inline::load_attrs(cx, self.def_id),
2427
            source: cx.tcx.def_span(self.def_id).clean(cx),
2428
            inner,
2429
        }
2430 2431 2432
    }
}

2433
/// A trait reference, which may have higher ranked lifetimes.
2434
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)]
2435 2436
pub struct PolyTrait {
    pub trait_: Type,
V
varkor 已提交
2437
    pub generic_params: Vec<GenericParamDef>,
2438 2439
}

C
Corey Richardson 已提交
2440
/// A representation of a Type suitable for hyperlinking purposes. Ideally one can get the original
2441
/// type out of the AST/TyCtxt given one of these, if more information is needed. Most importantly
C
Corey Richardson 已提交
2442
/// it does not preserve mutability or boxes.
2443
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)]
C
Corey Richardson 已提交
2444
pub enum Type {
A
Alexander Regueiro 已提交
2445
    /// Structs/enums/traits (most that'd be an `hir::TyKind::Path`).
2446
    ResolvedPath {
S
Steven Fackler 已提交
2447
        path: Path,
V
varkor 已提交
2448
        param_names: Option<Vec<GenericBound>>,
N
Niko Matsakis 已提交
2449
        did: DefId,
A
Alexander Regueiro 已提交
2450
        /// `true` if is a `T::Name` path for associated types.
2451
        is_generic: bool,
2452
    },
2453 2454 2455
    /// For parameterized types, so the consumer of the JSON don't go
    /// looking for types which don't exist anywhere.
    Generic(String),
2456
    /// Primitives are the fixed-size numeric types (plus int/usize/float), char,
2457
    /// arrays, slices, and tuples.
2458
    Primitive(PrimitiveType),
C
Corey Richardson 已提交
2459
    /// extern "ABI" fn
2460
    BareFunction(Box<BareFunctionDecl>),
2461
    Tuple(Vec<Type>),
2462
    Slice(Box<Type>),
2463
    Array(Box<Type>, String),
A
Andrew Cann 已提交
2464
    Never,
2465
    CVarArgs,
2466 2467
    Unique(Box<Type>),
    RawPointer(Mutability, Box<Type>),
2468
    BorrowedRef {
S
Steven Fackler 已提交
2469 2470 2471
        lifetime: Option<Lifetime>,
        mutability: Mutability,
        type_: Box<Type>,
2472
    },
2473 2474

    // <Type as Trait>::Name
T
Tom Jakubowski 已提交
2475 2476 2477 2478 2479
    QPath {
        name: String,
        self_type: Box<Type>,
        trait_: Box<Type>
    },
2480 2481 2482 2483

    // _
    Infer,

2484
    // impl TraitA+TraitB
V
varkor 已提交
2485
    ImplTrait(Vec<GenericBound>),
C
Corey Richardson 已提交
2486 2487
}

J
Jorge Aparicio 已提交
2488
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Copy, Debug)]
2489
pub enum PrimitiveType {
2490 2491
    Isize, I8, I16, I32, I64, I128,
    Usize, U8, U16, U32, U64, U128,
2492
    F32, F64,
2493 2494 2495 2496
    Char,
    Bool,
    Str,
    Slice,
2497
    Array,
2498
    Tuple,
2499
    Unit,
2500
    RawPointer,
2501
    Reference,
2502
    Fn,
A
Andrew Cann 已提交
2503
    Never,
2504
    CVarArgs,
2505 2506
}

J
Jorge Aparicio 已提交
2507
#[derive(Clone, RustcEncodable, RustcDecodable, Copy, Debug)]
2508
pub enum TypeKind {
2509 2510 2511 2512 2513 2514 2515 2516 2517 2518
    Enum,
    Function,
    Module,
    Const,
    Static,
    Struct,
    Union,
    Trait,
    Variant,
    Typedef,
P
Paul Lietar 已提交
2519
    Foreign,
M
Manish Goregaokar 已提交
2520
    Macro,
2521 2522
    Attr,
    Derive,
2523
    TraitAlias,
2524 2525
}

2526 2527 2528 2529 2530 2531 2532 2533 2534 2535
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())
    }
}

2536 2537 2538 2539
impl Type {
    pub fn primitive_type(&self) -> Option<PrimitiveType> {
        match *self {
            Primitive(p) | BorrowedRef { type_: box Primitive(p), ..} => Some(p),
2540 2541
            Slice(..) | BorrowedRef { type_: box Slice(..), .. } => Some(PrimitiveType::Slice),
            Array(..) | BorrowedRef { type_: box Array(..), .. } => Some(PrimitiveType::Array),
2542 2543 2544 2545 2546
            Tuple(ref tys) => if tys.is_empty() {
                Some(PrimitiveType::Unit)
            } else {
                Some(PrimitiveType::Tuple)
            },
2547
            RawPointer(..) => Some(PrimitiveType::RawPointer),
2548
            BorrowedRef { type_: box Generic(..), .. } => Some(PrimitiveType::Reference),
2549
            BareFunction(..) => Some(PrimitiveType::Fn),
A
Andrew Cann 已提交
2550
            Never => Some(PrimitiveType::Never),
2551 2552 2553
            _ => None,
        }
    }
2554

2555 2556 2557 2558 2559 2560
    pub fn is_generic(&self) -> bool {
        match *self {
            ResolvedPath { is_generic, .. } => is_generic,
            _ => false,
        }
    }
2561 2562 2563 2564 2565 2566 2567

    pub fn is_self_type(&self) -> bool {
        match *self {
            Generic(ref name) => name == "Self",
            _ => false
        }
    }
2568

2569
    pub fn generics(&self) -> Option<Vec<Type>> {
2570 2571 2572
        match *self {
            ResolvedPath { ref path, .. } => {
                path.segments.last().and_then(|seg| {
2573 2574 2575 2576 2577
                    if let GenericArgs::AngleBracketed { ref args, .. } = seg.args {
                        Some(args.iter().filter_map(|arg| match arg {
                            GenericArg::Type(ty) => Some(ty.clone()),
                            _ => None,
                        }).collect())
2578 2579 2580 2581 2582 2583 2584 2585
                    } else {
                        None
                    }
                })
            }
            _ => None,
        }
    }
2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600

    pub fn bindings(&self) -> Option<&[TypeBinding]> {
        match *self {
            ResolvedPath { ref path, .. } => {
                path.segments.last().and_then(|seg| {
                    if let GenericArgs::AngleBracketed { ref bindings, .. } = seg.args {
                        Some(&**bindings)
                    } else {
                        None
                    }
                })
            }
            _ => None
        }
    }
2601 2602 2603 2604 2605 2606 2607

    pub fn is_full_generic(&self) -> bool {
        match *self {
            Type::Generic(_) => true,
            _ => false,
        }
    }
2608
}
2609

2610
impl GetDefId for Type {
2611 2612 2613
    fn def_id(&self) -> Option<DefId> {
        match *self {
            ResolvedPath { did, .. } => Some(did),
2614
            Primitive(p) => crate::html::render::cache().primitive_locations.get(&p).cloned(),
2615 2616 2617
            BorrowedRef { type_: box Generic(..), .. } =>
                Primitive(PrimitiveType::Reference).def_id(),
            BorrowedRef { ref type_, .. } => type_.def_id(),
2618 2619 2620 2621 2622
            Tuple(ref tys) => if tys.is_empty() {
                Primitive(PrimitiveType::Unit).def_id()
            } else {
                Primitive(PrimitiveType::Tuple).def_id()
            },
2623
            BareFunction(..) => Primitive(PrimitiveType::Fn).def_id(),
A
Andrew Cann 已提交
2624
            Never => Primitive(PrimitiveType::Never).def_id(),
2625 2626 2627 2628
            Slice(..) => Primitive(PrimitiveType::Slice).def_id(),
            Array(..) => Primitive(PrimitiveType::Array).def_id(),
            RawPointer(..) => Primitive(PrimitiveType::RawPointer).def_id(),
            QPath { ref self_type, .. } => self_type.def_id(),
2629 2630 2631
            _ => None,
        }
    }
2632 2633
}

2634 2635
impl PrimitiveType {
    fn from_str(s: &str) -> Option<PrimitiveType> {
2636
        match s {
2637 2638 2639 2640 2641
            "isize" => Some(PrimitiveType::Isize),
            "i8" => Some(PrimitiveType::I8),
            "i16" => Some(PrimitiveType::I16),
            "i32" => Some(PrimitiveType::I32),
            "i64" => Some(PrimitiveType::I64),
2642
            "i128" => Some(PrimitiveType::I128),
2643 2644 2645 2646 2647
            "usize" => Some(PrimitiveType::Usize),
            "u8" => Some(PrimitiveType::U8),
            "u16" => Some(PrimitiveType::U16),
            "u32" => Some(PrimitiveType::U32),
            "u64" => Some(PrimitiveType::U64),
2648
            "u128" => Some(PrimitiveType::U128),
2649 2650 2651 2652 2653 2654 2655
            "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),
2656
            "tuple" => Some(PrimitiveType::Tuple),
2657
            "unit" => Some(PrimitiveType::Unit),
2658
            "pointer" => Some(PrimitiveType::RawPointer),
2659
            "reference" => Some(PrimitiveType::Reference),
2660
            "fn" => Some(PrimitiveType::Fn),
A
Andrew Cann 已提交
2661
            "never" => Some(PrimitiveType::Never),
2662 2663 2664 2665
            _ => None,
        }
    }

2666
    pub fn as_str(&self) -> &'static str {
E
est31 已提交
2667
        use self::PrimitiveType::*;
2668
        match *self {
2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688
            Isize => "isize",
            I8 => "i8",
            I16 => "i16",
            I32 => "i32",
            I64 => "i64",
            I128 => "i128",
            Usize => "usize",
            U8 => "u8",
            U16 => "u16",
            U32 => "u32",
            U64 => "u64",
            U128 => "u128",
            F32 => "f32",
            F64 => "f64",
            Str => "str",
            Bool => "bool",
            Char => "char",
            Array => "array",
            Slice => "slice",
            Tuple => "tuple",
2689
            Unit => "unit",
2690
            RawPointer => "pointer",
2691
            Reference => "reference",
2692
            Fn => "fn",
A
Andrew Cann 已提交
2693
            Never => "never",
2694
            CVarArgs => "...",
2695 2696 2697 2698
        }
    }

    pub fn to_url_str(&self) -> &'static str {
2699
        self.as_str()
2700 2701 2702
    }
}

2703 2704 2705
impl From<ast::IntTy> for PrimitiveType {
    fn from(int_ty: ast::IntTy) -> PrimitiveType {
        match int_ty {
2706
            ast::IntTy::Isize => PrimitiveType::Isize,
2707 2708 2709 2710
            ast::IntTy::I8 => PrimitiveType::I8,
            ast::IntTy::I16 => PrimitiveType::I16,
            ast::IntTy::I32 => PrimitiveType::I32,
            ast::IntTy::I64 => PrimitiveType::I64,
2711
            ast::IntTy::I128 => PrimitiveType::I128,
2712 2713 2714
        }
    }
}
2715

2716 2717 2718
impl From<ast::UintTy> for PrimitiveType {
    fn from(uint_ty: ast::UintTy) -> PrimitiveType {
        match uint_ty {
2719
            ast::UintTy::Usize => PrimitiveType::Usize,
2720 2721 2722 2723
            ast::UintTy::U8 => PrimitiveType::U8,
            ast::UintTy::U16 => PrimitiveType::U16,
            ast::UintTy::U32 => PrimitiveType::U32,
            ast::UintTy::U64 => PrimitiveType::U64,
2724
            ast::UintTy::U128 => PrimitiveType::U128,
2725 2726 2727 2728
        }
    }
}

2729 2730 2731 2732 2733 2734 2735 2736 2737
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,
        }
    }
}

2738
impl Clean<Type> for hir::Ty {
2739
    fn clean(&self, cx: &DocContext<'_>) -> Type {
2740
        use rustc::hir::*;
2741

2742
        match self.node {
C
csmoe 已提交
2743
            TyKind::Never => Never,
2744
            TyKind::CVarArgs(_) => CVarArgs,
C
csmoe 已提交
2745 2746
            TyKind::Ptr(ref m) => RawPointer(m.mutbl.clean(cx), box m.ty.clean(cx)),
            TyKind::Rptr(ref l, ref m) => {
2747 2748 2749 2750 2751 2752 2753 2754
                let lifetime = if l.is_elided() {
                    None
                } else {
                    Some(l.clean(cx))
                };
                BorrowedRef {lifetime: lifetime, mutability: m.mutbl.clean(cx),
                             type_: box m.ty.clean(cx)}
            }
C
csmoe 已提交
2755 2756
            TyKind::Slice(ref ty) => Slice(box ty.clean(cx)),
            TyKind::Array(ref ty, ref length) => {
L
ljedrz 已提交
2757
                let def_id = cx.tcx.hir().local_def_id_from_hir_id(length.hir_id);
2758
                let param_env = cx.tcx.param_env(def_id);
C
csmoe 已提交
2759
                let substs = InternalSubsts::identity_for_item(cx.tcx, def_id);
O
Oliver Schneider 已提交
2760 2761 2762 2763
                let cid = GlobalId {
                    instance: ty::Instance::new(def_id, substs),
                    promoted: None
                };
2764
                let length = match cx.tcx.const_eval(param_env.and(cid)) {
O
Oliver Scherer 已提交
2765
                    Ok(length) => print_const(cx, length),
2766 2767
                    Err(_) => "_".to_string(),
                };
2768
                Array(box ty.clean(cx), length)
2769
            },
C
csmoe 已提交
2770
            TyKind::Tup(ref tys) => Tuple(tys.clean(cx)),
O
Oliver Schneider 已提交
2771
            TyKind::Def(item_id, _) => {
2772
                let item = cx.tcx.hir().expect_item_by_hir_id(item_id.id);
O
Oliver Schneider 已提交
2773 2774 2775 2776 2777 2778
                if let hir::ItemKind::Existential(ref ty) = item.node {
                    ImplTrait(ty.bounds.clean(cx))
                } else {
                    unreachable!()
                }
            }
C
csmoe 已提交
2779
            TyKind::Path(hir::QPath::Resolved(None, ref path)) => {
2780
                if let Some(new_ty) = cx.ty_substs.borrow().get(&path.def).cloned() {
2781
                    return new_ty;
E
Eduard Burtescu 已提交
2782 2783
                }

2784
                if let Def::TyParam(did) = path.def {
2785 2786 2787 2788 2789
                    if let Some(bounds) = cx.impl_trait_bounds.borrow_mut().remove(&did) {
                        return ImplTrait(bounds);
                    }
                }

2790
                let mut alias = None;
2791
                if let Def::TyAlias(def_id) = path.def {
2792
                    // Substitute private type aliases
2793
                    if let Some(hir_id) = cx.tcx.hir().as_local_hir_id(def_id) {
2794
                        if !cx.renderinfo.borrow().access_levels.is_exported(def_id) {
2795
                            alias = Some(&cx.tcx.hir().expect_item_by_hir_id(hir_id).node);
2796
                        }
E
Eduard Burtescu 已提交
2797
                    }
2798 2799
                };

C
csmoe 已提交
2800
                if let Some(&hir::ItemKind::Ty(ref ty, ref generics)) = alias {
G
Guillaume Gomez 已提交
2801
                    let provided_params = &path.segments.last().expect("segments were empty");
2802 2803
                    let mut ty_substs = FxHashMap::default();
                    let mut lt_substs = FxHashMap::default();
V
varkor 已提交
2804
                    let mut const_substs = FxHashMap::default();
2805
                    provided_params.with_generic_args(|generic_args| {
V
varkor 已提交
2806
                        let mut indices: GenericParamCount = Default::default();
2807
                        for param in generics.params.iter() {
V
varkor 已提交
2808 2809
                            match param.kind {
                                hir::GenericParamKind::Lifetime { .. } => {
2810 2811 2812
                                    let mut j = 0;
                                    let lifetime = generic_args.args.iter().find_map(|arg| {
                                        match arg {
V
varkor 已提交
2813
                                            hir::GenericArg::Lifetime(lt) => {
2814 2815 2816 2817 2818 2819 2820 2821 2822 2823
                                                if indices.lifetimes == j {
                                                    return Some(lt);
                                                }
                                                j += 1;
                                                None
                                            }
                                            _ => None,
                                        }
                                    });
                                    if let Some(lt) = lifetime.cloned() {
2824 2825
                                        if !lt.is_elided() {
                                            let lt_def_id =
L
ljedrz 已提交
2826
                                                cx.tcx.hir().local_def_id_from_hir_id(param.hir_id);
2827 2828 2829 2830 2831
                                            lt_substs.insert(lt_def_id, lt.clean(cx));
                                        }
                                    }
                                    indices.lifetimes += 1;
                                }
V
varkor 已提交
2832
                                hir::GenericParamKind::Type { ref default, .. } => {
2833
                                    let ty_param_def =
L
ljedrz 已提交
2834 2835
                                        Def::TyParam(
                                            cx.tcx.hir().local_def_id_from_hir_id(param.hir_id));
2836 2837 2838
                                    let mut j = 0;
                                    let type_ = generic_args.args.iter().find_map(|arg| {
                                        match arg {
V
varkor 已提交
2839
                                            hir::GenericArg::Type(ty) => {
2840 2841 2842 2843 2844 2845 2846 2847 2848 2849
                                                if indices.types == j {
                                                    return Some(ty);
                                                }
                                                j += 1;
                                                None
                                            }
                                            _ => None,
                                        }
                                    });
                                    if let Some(ty) = type_.cloned() {
O
Oliver Schneider 已提交
2850
                                        ty_substs.insert(ty_param_def, ty.clean(cx));
V
varkor 已提交
2851
                                    } else if let Some(default) = default.clone() {
2852 2853 2854
                                        ty_substs.insert(ty_param_def,
                                                         default.into_inner().clean(cx));
                                    }
2855
                                    indices.types += 1;
2856
                                }
V
varkor 已提交
2857 2858
                                hir::GenericParamKind::Const { .. } => {
                                    let const_param_def =
L
ljedrz 已提交
2859 2860
                                        Def::ConstParam(
                                            cx.tcx.hir().local_def_id_from_hir_id(param.hir_id));
V
varkor 已提交
2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879
                                    let mut j = 0;
                                    let const_ = generic_args.args.iter().find_map(|arg| {
                                        match arg {
                                            hir::GenericArg::Const(ct) => {
                                                if indices.consts == j {
                                                    return Some(ct);
                                                }
                                                j += 1;
                                                None
                                            }
                                            _ => None,
                                        }
                                    });
                                    if let Some(ct) = const_.cloned() {
                                        const_substs.insert(const_param_def, ct.clean(cx));
                                    }
                                    // FIXME(const_generics:defaults)
                                    indices.consts += 1;
                                }
2880
                            }
2881
                        }
2882
                    });
V
varkor 已提交
2883
                    return cx.enter_alias(ty_substs, lt_substs, const_substs, || ty.clean(cx));
2884
                }
L
ljedrz 已提交
2885
                resolve_type(cx, path.clean(cx), self.hir_id)
N
Niko Matsakis 已提交
2886
            }
C
csmoe 已提交
2887
            TyKind::Path(hir::QPath::Resolved(Some(ref qself), ref p)) => {
2888 2889 2890 2891
                let mut segments: Vec<_> = p.segments.clone().into();
                segments.pop();
                let trait_path = hir::Path {
                    span: p.span,
2892
                    def: Def::Trait(cx.tcx.associated_item(p.def.def_id()).container.id()),
2893 2894
                    segments: segments.into(),
                };
2895
                Type::QPath {
G
Guillaume Gomez 已提交
2896
                    name: p.segments.last().expect("segments were empty").ident.name.clean(cx),
2897
                    self_type: box qself.clean(cx),
L
ljedrz 已提交
2898
                    trait_: box resolve_type(cx, trait_path.clean(cx), self.hir_id)
2899 2900
                }
            }
C
csmoe 已提交
2901
            TyKind::Path(hir::QPath::TypeRelative(ref qself, ref segment)) => {
2902
                let mut def = Def::Err;
2903
                let ty = hir_ty_to_ty(cx.tcx, self);
V
varkor 已提交
2904
                if let ty::Projection(proj) = ty.sty {
2905
                    def = Def::Trait(proj.trait_ref(cx.tcx).def_id);
2906
                }
2907 2908
                let trait_path = hir::Path {
                    span: self.span,
2909
                    def,
2910 2911 2912
                    segments: vec![].into(),
                };
                Type::QPath {
2913
                    name: segment.ident.name.clean(cx),
2914
                    self_type: box qself.clean(cx),
L
ljedrz 已提交
2915
                    trait_: box resolve_type(cx, trait_path.clean(cx), self.hir_id)
2916 2917
                }
            }
C
csmoe 已提交
2918
            TyKind::TraitObject(ref bounds, ref lifetime) => {
2919
                match bounds[0].clean(cx).trait_ {
V
varkor 已提交
2920
                    ResolvedPath { path, param_names: None, did, is_generic } => {
V
varkor 已提交
2921
                        let mut bounds: Vec<self::GenericBound> = bounds[1..].iter().map(|bound| {
V
varkor 已提交
2922 2923
                            self::GenericBound::TraitBound(bound.clean(cx),
                                                           hir::TraitBoundModifier::None)
2924 2925
                        }).collect();
                        if !lifetime.is_elided() {
V
varkor 已提交
2926
                            bounds.push(self::GenericBound::Outlives(lifetime.clean(cx)));
2927
                        }
V
varkor 已提交
2928
                        ResolvedPath { path, param_names: Some(bounds), did, is_generic, }
N
Niko Matsakis 已提交
2929
                    }
2930
                    _ => Infer // shouldn't happen
N
Niko Matsakis 已提交
2931
                }
2932
            }
C
csmoe 已提交
2933 2934 2935
            TyKind::BareFn(ref barefn) => BareFunction(box barefn.clean(cx)),
            TyKind::Infer | TyKind::Err => Infer,
            TyKind::Typeof(..) => panic!("Unimplemented type {:?}", self.node),
2936
        }
C
Corey Richardson 已提交
2937 2938 2939
    }
}

D
Douglas Campos 已提交
2940
impl<'tcx> Clean<Type> for Ty<'tcx> {
2941
    fn clean(&self, cx: &DocContext<'_>) -> Type {
2942
        match self.sty {
V
varkor 已提交
2943
            ty::Never => Never,
2944 2945 2946 2947 2948 2949
            ty::Bool => Primitive(PrimitiveType::Bool),
            ty::Char => Primitive(PrimitiveType::Char),
            ty::Int(int_ty) => Primitive(int_ty.into()),
            ty::Uint(uint_ty) => Primitive(uint_ty.into()),
            ty::Float(float_ty) => Primitive(float_ty.into()),
            ty::Str => Primitive(PrimitiveType::Str),
V
varkor 已提交
2950 2951
            ty::Slice(ty) => Slice(box ty.clean(cx)),
            ty::Array(ty, n) => {
2952
                let mut n = *cx.tcx.lift(&n).expect("array lift failed");
O
Oliver Scherer 已提交
2953
                if let ConstValue::Unevaluated(def_id, substs) = n.val {
2954
                    let param_env = cx.tcx.param_env(def_id);
O
Oliver Schneider 已提交
2955 2956 2957 2958 2959
                    let cid = GlobalId {
                        instance: ty::Instance::new(def_id, substs),
                        promoted: None
                    };
                    if let Ok(new_n) = cx.tcx.const_eval(param_env.and(cid)) {
O
Oliver Scherer 已提交
2960
                        n = new_n;
2961
                    }
2962
                };
O
Oliver Schneider 已提交
2963
                let n = print_const(cx, n);
2964 2965
                Array(box ty.clean(cx), n)
            }
V
varkor 已提交
2966 2967
            ty::RawPtr(mt) => RawPointer(mt.mutbl.clean(cx), box mt.ty.clean(cx)),
            ty::Ref(r, ty, mutbl) => BorrowedRef {
2968
                lifetime: r.clean(cx),
2969 2970
                mutability: mutbl.clean(cx),
                type_: box ty.clean(cx),
2971
            },
V
varkor 已提交
2972 2973 2974
            ty::FnDef(..) |
            ty::FnPtr(_) => {
                let ty = cx.tcx.lift(self).expect("FnPtr lift failed");
2975 2976 2977
                let sig = ty.fn_sig(cx.tcx);
                BareFunction(box BareFunctionDecl {
                    unsafety: sig.unsafety(),
2978
                    generic_params: Vec::new(),
2979
                    decl: (cx.tcx.hir().local_def_id(ast::CRATE_NODE_ID), sig).clean(cx),
2980 2981 2982
                    abi: sig.abi(),
                })
            }
V
varkor 已提交
2983
            ty::Adt(def, substs) => {
2984
                let did = def.did;
2985
                let kind = match def.adt_kind() {
2986 2987 2988
                    AdtKind::Struct => TypeKind::Struct,
                    AdtKind::Union => TypeKind::Union,
                    AdtKind::Enum => TypeKind::Enum,
2989
                };
M
mitaa 已提交
2990
                inline::record_extern_fqn(cx, did, kind);
2991
                let path = external_path(cx, &cx.tcx.item_name(did).as_str(),
2992
                                         None, false, vec![], substs);
2993
                ResolvedPath {
2994
                    path,
V
varkor 已提交
2995
                    param_names: None,
2996
                    did,
2997
                    is_generic: false,
2998 2999
                }
            }
V
varkor 已提交
3000
            ty::Foreign(did) => {
P
Paul Lietar 已提交
3001
                inline::record_extern_fqn(cx, did, TypeKind::Foreign);
3002
                let path = external_path(cx, &cx.tcx.item_name(did).as_str(),
C
csmoe 已提交
3003
                                         None, false, vec![], InternalSubsts::empty());
P
Paul Lietar 已提交
3004 3005
                ResolvedPath {
                    path: path,
V
varkor 已提交
3006
                    param_names: None,
P
Paul Lietar 已提交
3007 3008 3009 3010
                    did: did,
                    is_generic: false,
                }
            }
V
varkor 已提交
3011
            ty::Dynamic(ref obj, ref reg) => {
A
Ariel Ben-Yehuda 已提交
3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024
                // HACK: pick the first `did` as the `did` of the trait object. Someone
                // might want to implement "native" support for marker-trait-only
                // trait objects.
                let mut dids = obj.principal_def_id().into_iter().chain(obj.auto_traits());
                let did = dids.next().unwrap_or_else(|| {
                    panic!("found trait object `{:?}` with no traits?", self)
                });
                let substs = match obj.principal() {
                    Some(principal) => principal.skip_binder().substs,
                    // marker traits have no substs.
                    _ => cx.tcx.intern_substs(&[])
                };

3025 3026
                inline::record_extern_fqn(cx, did, TypeKind::Trait);

V
varkor 已提交
3027 3028
                let mut param_names = vec![];
                reg.clean(cx).map(|b| param_names.push(GenericBound::Outlives(b)));
A
Ariel Ben-Yehuda 已提交
3029
                for did in dids {
3030 3031 3032
                    let empty = cx.tcx.intern_substs(&[]);
                    let path = external_path(cx, &cx.tcx.item_name(did).as_str(),
                        Some(did), false, vec![], empty);
3033
                    inline::record_extern_fqn(cx, did, TypeKind::Trait);
3034 3035 3036
                    let bound = GenericBound::TraitBound(PolyTrait {
                        trait_: ResolvedPath {
                            path,
V
varkor 已提交
3037
                            param_names: None,
3038 3039 3040 3041 3042
                            did,
                            is_generic: false,
                        },
                        generic_params: Vec::new(),
                    }, hir::TraitBoundModifier::None);
V
varkor 已提交
3043
                    param_names.push(bound);
3044
                }
3045

3046 3047 3048 3049 3050 3051 3052
                let mut bindings = vec![];
                for pb in obj.projection_bounds() {
                    bindings.push(TypeBinding {
                        name: cx.tcx.associated_item(pb.item_def_id()).ident.name.clean(cx),
                        ty: pb.skip_binder().ty.clean(cx)
                    });
                }
3053

3054
                let path = external_path(cx, &cx.tcx.item_name(did).as_str(), Some(did),
A
Ariel Ben-Yehuda 已提交
3055
                    false, bindings, substs);
3056 3057
                ResolvedPath {
                    path,
V
varkor 已提交
3058
                    param_names: Some(param_names),
3059 3060
                    did,
                    is_generic: false,
3061 3062
                }
            }
V
varkor 已提交
3063
            ty::Tuple(ref t) => Tuple(t.clean(cx)),
3064

V
varkor 已提交
3065
            ty::Projection(ref data) => data.clean(cx),
3066

V
varkor 已提交
3067
            ty::Param(ref p) => Generic(p.name.to_string()),
3068

3069
            ty::Opaque(def_id, substs) => {
3070 3071
                // Grab the "TraitA + TraitB" from `impl TraitA + TraitB`,
                // by looking up the projections associated with the def_id.
3072
                let predicates_of = cx.tcx.explicit_predicates_of(def_id);
3073
                let substs = cx.tcx.lift(&substs).expect("Opaque lift failed");
3074
                let bounds = predicates_of.instantiate(cx.tcx, substs);
3075 3076 3077
                let mut regions = vec![];
                let mut has_sized = false;
                let mut bounds = bounds.predicates.iter().filter_map(|predicate| {
3078 3079
                    let trait_ref = if let Some(tr) = predicate.to_opt_poly_trait_ref() {
                        tr
3080 3081
                    } else if let ty::Predicate::TypeOutlives(pred) = *predicate {
                        // these should turn up at the end
3082
                        pred.skip_binder().1.clean(cx).map(|r| {
V
varkor 已提交
3083
                            regions.push(GenericBound::Outlives(r))
3084
                        });
3085
                        return None;
3086 3087 3088 3089
                    } else {
                        return None;
                    };

3090 3091
                    if let Some(sized) = cx.tcx.lang_items().sized_trait() {
                        if trait_ref.def_id() == sized {
3092
                            has_sized = true;
3093 3094 3095 3096
                            return None;
                        }
                    }

3097 3098 3099 3100 3101 3102
                    let bounds = bounds.predicates.iter().filter_map(|pred|
                        if let ty::Predicate::Projection(proj) = *pred {
                            let proj = proj.skip_binder();
                            if proj.projection_ty.trait_ref(cx.tcx) == *trait_ref.skip_binder() {
                                Some(TypeBinding {
                                    name: cx.tcx.associated_item(proj.projection_ty.item_def_id)
3103
                                                .ident.name.clean(cx),
3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114
                                    ty: proj.ty.clean(cx),
                                })
                            } else {
                                None
                            }
                        } else {
                            None
                        }
                    ).collect();

                    Some((trait_ref.skip_binder(), bounds).clean(cx))
3115 3116 3117
                }).collect::<Vec<_>>();
                bounds.extend(regions);
                if !has_sized && !bounds.is_empty() {
V
varkor 已提交
3118
                    bounds.insert(0, GenericBound::maybe_sized(cx));
3119 3120
                }
                ImplTrait(bounds)
3121 3122
            }

V
varkor 已提交
3123
            ty::Closure(..) | ty::Generator(..) => Tuple(vec![]), // FIXME(pcwalton)
3124

S
scalexm 已提交
3125
            ty::Bound(..) => panic!("Bound"),
S
scalexm 已提交
3126
            ty::Placeholder(..) => panic!("Placeholder"),
3127
            ty::UnnormalizedProjection(..) => panic!("UnnormalizedProjection"),
V
varkor 已提交
3128 3129 3130
            ty::GeneratorWitness(..) => panic!("GeneratorWitness"),
            ty::Infer(..) => panic!("Infer"),
            ty::Error => panic!("Error"),
3131 3132 3133 3134
        }
    }
}

V
varkor 已提交
3135 3136 3137 3138 3139 3140 3141 3142 3143
impl<'tcx> Clean<Constant> for ty::Const<'tcx> {
    fn clean(&self, cx: &DocContext<'_>) -> Constant {
        Constant {
            type_: self.ty.clean(cx),
            expr: format!("{:?}", self.val), // FIXME(const_generics)
        }
    }
}

3144
impl Clean<Item> for hir::StructField {
3145
    fn clean(&self, cx: &DocContext<'_>) -> Item {
L
ljedrz 已提交
3146 3147
        let local_did = cx.tcx.hir().local_def_id_from_hir_id(self.hir_id);

C
Corey Richardson 已提交
3148
        Item {
3149
            name: Some(self.ident.name).clean(cx),
3150
            attrs: self.attrs.clean(cx),
3151
            source: self.span.clean(cx),
3152
            visibility: self.vis.clean(cx),
L
ljedrz 已提交
3153 3154 3155
            stability: get_stability(cx, local_did),
            deprecation: get_deprecation(cx, local_did),
            def_id: local_did,
3156
            inner: StructFieldItem(self.ty.clean(cx)),
C
Corey Richardson 已提交
3157 3158 3159 3160
        }
    }
}

3161
impl<'tcx> Clean<Item> for ty::FieldDef {
3162
    fn clean(&self, cx: &DocContext<'_>) -> Item {
3163
        Item {
3164
            name: Some(self.ident.name).clean(cx),
3165
            attrs: cx.tcx.get_attrs(self.did).clean(cx),
3166
            source: cx.tcx.def_span(self.did).clean(cx),
3167
            visibility: self.vis.clean(cx),
3168
            stability: get_stability(cx, self.did),
3169
            deprecation: get_deprecation(cx, self.did),
3170
            def_id: self.did,
3171
            inner: StructFieldItem(cx.tcx.type_of(self.did).clean(cx)),
3172 3173 3174 3175
        }
    }
}

J
Jeffrey Seyfried 已提交
3176 3177 3178 3179
#[derive(Clone, PartialEq, Eq, RustcDecodable, RustcEncodable, Debug)]
pub enum Visibility {
    Public,
    Inherited,
3180 3181
    Crate,
    Restricted(DefId, Path),
J
Jeffrey Seyfried 已提交
3182
}
C
Corey Richardson 已提交
3183

3184
impl Clean<Option<Visibility>> for hir::Visibility {
3185
    fn clean(&self, cx: &DocContext<'_>) -> Option<Visibility> {
3186
        Some(match self.node {
3187 3188 3189 3190
            hir::VisibilityKind::Public => Visibility::Public,
            hir::VisibilityKind::Inherited => Visibility::Inherited,
            hir::VisibilityKind::Crate(_) => Visibility::Crate,
            hir::VisibilityKind::Restricted { ref path, .. } => {
3191 3192 3193 3194 3195
                let path = path.clean(cx);
                let did = register_def(cx, path.def);
                Visibility::Restricted(did, path)
            }
        })
3196 3197 3198 3199
    }
}

impl Clean<Option<Visibility>> for ty::Visibility {
3200
    fn clean(&self, _: &DocContext<'_>) -> Option<Visibility> {
J
Jeffrey Seyfried 已提交
3201
        Some(if *self == ty::Visibility::Public { Public } else { Inherited })
C
Corey Richardson 已提交
3202 3203 3204
    }
}

J
Jorge Aparicio 已提交
3205
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
3206
pub struct Struct {
3207 3208 3209 3210
    pub struct_type: doctree::StructType,
    pub generics: Generics,
    pub fields: Vec<Item>,
    pub fields_stripped: bool,
C
Corey Richardson 已提交
3211 3212
}

V
Vadim Petrochenkov 已提交
3213 3214 3215 3216 3217 3218 3219 3220
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
pub struct Union {
    pub struct_type: doctree::StructType,
    pub generics: Generics,
    pub fields: Vec<Item>,
    pub fields_stripped: bool,
}

3221
impl Clean<Item> for doctree::Struct {
3222
    fn clean(&self, cx: &DocContext<'_>) -> Item {
3223 3224
        Item {
            name: Some(self.name.clean(cx)),
3225 3226
            attrs: self.attrs.clean(cx),
            source: self.whence.clean(cx),
L
ljedrz 已提交
3227
            def_id: cx.tcx.hir().local_def_id_from_hir_id(self.id),
3228 3229
            visibility: self.vis.clean(cx),
            stability: self.stab.clean(cx),
3230
            deprecation: self.depr.clean(cx),
C
Corey Richardson 已提交
3231 3232
            inner: StructItem(Struct {
                struct_type: self.struct_type,
3233 3234
                generics: self.generics.clean(cx),
                fields: self.fields.clean(cx),
S
Steven Fackler 已提交
3235
                fields_stripped: false,
C
Corey Richardson 已提交
3236
            }),
3237
        }
C
Corey Richardson 已提交
3238 3239 3240
    }
}

3241
impl Clean<Item> for doctree::Union {
3242
    fn clean(&self, cx: &DocContext<'_>) -> Item {
3243 3244
        Item {
            name: Some(self.name.clean(cx)),
V
Vadim Petrochenkov 已提交
3245 3246
            attrs: self.attrs.clean(cx),
            source: self.whence.clean(cx),
L
ljedrz 已提交
3247
            def_id: cx.tcx.hir().local_def_id_from_hir_id(self.id),
V
Vadim Petrochenkov 已提交
3248 3249 3250 3251 3252 3253 3254 3255 3256
            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,
            }),
3257
        }
V
Vadim Petrochenkov 已提交
3258 3259 3260
    }
}

3261
/// This is a more limited form of the standard Struct, different in that
C
Corey Richardson 已提交
3262 3263
/// it lacks the things most items have (name, id, parameterization). Found
/// only as a variant in an enum.
J
Jorge Aparicio 已提交
3264
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
3265
pub struct VariantStruct {
3266 3267 3268
    pub struct_type: doctree::StructType,
    pub fields: Vec<Item>,
    pub fields_stripped: bool,
C
Corey Richardson 已提交
3269 3270
}

3271
impl Clean<VariantStruct> for ::rustc::hir::VariantData {
3272
    fn clean(&self, cx: &DocContext<'_>) -> VariantStruct {
C
Corey Richardson 已提交
3273 3274
        VariantStruct {
            struct_type: doctree::struct_type_from_def(self),
3275
            fields: self.fields().iter().map(|x| x.clean(cx)).collect(),
S
Steven Fackler 已提交
3276
            fields_stripped: false,
C
Corey Richardson 已提交
3277 3278 3279 3280
        }
    }
}

J
Jorge Aparicio 已提交
3281
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
3282
pub struct Enum {
3283
    pub variants: IndexVec<VariantIdx, Item>,
3284 3285
    pub generics: Generics,
    pub variants_stripped: bool,
C
Corey Richardson 已提交
3286 3287
}

3288
impl Clean<Item> for doctree::Enum {
3289
    fn clean(&self, cx: &DocContext<'_>) -> Item {
3290 3291
        Item {
            name: Some(self.name.clean(cx)),
3292 3293
            attrs: self.attrs.clean(cx),
            source: self.whence.clean(cx),
L
ljedrz 已提交
3294
            def_id: cx.tcx.hir().local_def_id_from_hir_id(self.id),
3295 3296
            visibility: self.vis.clean(cx),
            stability: self.stab.clean(cx),
3297
            deprecation: self.depr.clean(cx),
C
Corey Richardson 已提交
3298
            inner: EnumItem(Enum {
3299
                variants: self.variants.iter().map(|v| v.clean(cx)).collect(),
3300
                generics: self.generics.clean(cx),
S
Steven Fackler 已提交
3301
                variants_stripped: false,
C
Corey Richardson 已提交
3302
            }),
3303
        }
C
Corey Richardson 已提交
3304 3305 3306
    }
}

J
Jorge Aparicio 已提交
3307
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
3308
pub struct Variant {
3309
    pub kind: VariantKind,
C
Corey Richardson 已提交
3310 3311 3312
}

impl Clean<Item> for doctree::Variant {
3313
    fn clean(&self, cx: &DocContext<'_>) -> Item {
C
Corey Richardson 已提交
3314
        Item {
3315 3316 3317
            name: Some(self.name.clean(cx)),
            attrs: self.attrs.clean(cx),
            source: self.whence.clean(cx),
3318
            visibility: None,
3319
            stability: self.stab.clean(cx),
3320
            deprecation: self.depr.clean(cx),
3321
            def_id: cx.tcx.hir().local_def_id_from_hir_id(self.id),
C
Corey Richardson 已提交
3322
            inner: VariantItem(Variant {
3323
                kind: self.def.clean(cx),
C
Corey Richardson 已提交
3324 3325 3326 3327 3328
            }),
        }
    }
}

3329
impl<'tcx> Clean<Item> for ty::VariantDef {
3330
    fn clean(&self, cx: &DocContext<'_>) -> Item {
3331 3332 3333
        let kind = match self.ctor_kind {
            CtorKind::Const => VariantKind::CLike,
            CtorKind::Fn => {
3334
                VariantKind::Tuple(
3335
                    self.fields.iter().map(|f| cx.tcx.type_of(f.did).clean(cx)).collect()
3336
                )
3337
            }
3338
            CtorKind::Fictive => {
3339
                VariantKind::Struct(VariantStruct {
3340 3341
                    struct_type: doctree::Plain,
                    fields_stripped: false,
3342
                    fields: self.fields.iter().map(|field| {
3343
                        Item {
3344
                            source: cx.tcx.def_span(field.did).clean(cx),
3345
                            name: Some(field.ident.name.clean(cx)),
3346
                            attrs: cx.tcx.get_attrs(field.did).clean(cx),
3347
                            visibility: field.vis.clean(cx),
3348 3349 3350
                            def_id: field.did,
                            stability: get_stability(cx, field.did),
                            deprecation: get_deprecation(cx, field.did),
3351
                            inner: StructFieldItem(cx.tcx.type_of(field.did).clean(cx))
3352 3353 3354 3355 3356 3357
                        }
                    }).collect()
                })
            }
        };
        Item {
3358
            name: Some(self.ident.clean(cx)),
3359 3360
            attrs: inline::load_attrs(cx, self.def_id),
            source: cx.tcx.def_span(self.def_id).clean(cx),
J
Jeffrey Seyfried 已提交
3361
            visibility: Some(Inherited),
3362
            def_id: self.def_id,
T
teresy 已提交
3363
            inner: VariantItem(Variant { kind }),
3364 3365
            stability: get_stability(cx, self.def_id),
            deprecation: get_deprecation(cx, self.def_id),
3366 3367 3368 3369
        }
    }
}

J
Jorge Aparicio 已提交
3370
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
3371
pub enum VariantKind {
3372 3373 3374
    CLike,
    Tuple(Vec<Type>),
    Struct(VariantStruct),
C
Corey Richardson 已提交
3375 3376
}

3377
impl Clean<VariantKind> for hir::VariantData {
3378
    fn clean(&self, cx: &DocContext<'_>) -> VariantKind {
3379 3380 3381 3382 3383
        match self {
            hir::VariantData::Struct(..) => VariantKind::Struct(self.clean(cx)),
            hir::VariantData::Tuple(..) =>
                VariantKind::Tuple(self.fields().iter().map(|x| x.ty.clean(cx)).collect()),
            hir::VariantData::Unit(..) => VariantKind::CLike,
3384
        }
3385 3386 3387
    }
}

J
Jorge Aparicio 已提交
3388
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
3389
pub struct Span {
3390
    pub filename: FileName,
3391 3392 3393 3394
    pub loline: usize,
    pub locol: usize,
    pub hiline: usize,
    pub hicol: usize,
3395 3396
}

3397
impl Span {
3398
    pub fn empty() -> Span {
3399
        Span {
3400
            filename: FileName::Anon(0),
3401 3402 3403 3404 3405 3406
            loline: 0, locol: 0,
            hiline: 0, hicol: 0,
        }
    }
}

3407
impl Clean<Span> for syntax_pos::Span {
3408
    fn clean(&self, cx: &DocContext<'_>) -> Span {
V
Vadim Petrochenkov 已提交
3409
        if self.is_dummy() {
3410 3411 3412
            return Span::empty();
        }

D
Donato Sciarra 已提交
3413
        let cm = cx.sess().source_map();
3414
        let filename = cm.span_to_filename(*self);
3415 3416
        let lo = cm.lookup_char_pos(self.lo());
        let hi = cm.lookup_char_pos(self.hi());
3417
        Span {
3418
            filename,
3419
            loline: lo.line,
3420
            locol: lo.col.to_usize(),
3421
            hiline: hi.line,
3422
            hicol: hi.col.to_usize(),
3423
        }
C
Corey Richardson 已提交
3424 3425 3426
    }
}

3427
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)]
C
Corey Richardson 已提交
3428
pub struct Path {
3429
    pub global: bool,
3430
    pub def: Def,
3431
    pub segments: Vec<PathSegment>,
C
Corey Richardson 已提交
3432 3433
}

3434
impl Path {
B
bluss 已提交
3435
    pub fn last_name(&self) -> &str {
G
Guillaume Gomez 已提交
3436
        self.segments.last().expect("segments were empty").name.as_str()
3437
    }
3438 3439
}

3440
impl Clean<Path> for hir::Path {
3441
    fn clean(&self, cx: &DocContext<'_>) -> Path {
C
Corey Richardson 已提交
3442
        Path {
3443
            global: self.is_global(),
3444
            def: self.def,
3445
            segments: if self.is_global() { &self.segments[1..] } else { &self.segments }.clean(cx),
3446 3447 3448 3449
        }
    }
}

V
varkor 已提交
3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)]
pub enum GenericArg {
    Lifetime(Lifetime),
    Type(Type),
    Const(Constant),
}

impl fmt::Display for GenericArg {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            GenericArg::Lifetime(lt) => lt.fmt(f),
            GenericArg::Type(ty) => ty.fmt(f),
            GenericArg::Const(ct) => ct.fmt(f),
        }
    }
}

V
varkor 已提交
3467
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)]
3468
pub enum GenericArgs {
3469
    AngleBracketed {
3470
        args: Vec<GenericArg>,
3471
        bindings: Vec<TypeBinding>,
3472 3473 3474
    },
    Parenthesized {
        inputs: Vec<Type>,
3475
        output: Option<Type>,
3476
    }
3477 3478
}

3479
impl Clean<GenericArgs> for hir::GenericArgs {
3480
    fn clean(&self, cx: &DocContext<'_>) -> GenericArgs {
3481 3482
        if self.parenthesized {
            let output = self.bindings[0].ty.clean(cx);
3483
            GenericArgs::Parenthesized {
3484 3485
                inputs: self.inputs().clean(cx),
                output: if output != Type::Tuple(Vec::new()) { Some(output) } else { None }
3486
            }
3487
        } else {
3488 3489 3490 3491
            let elide_lifetimes = self.args.iter().all(|arg| match arg {
                hir::GenericArg::Lifetime(lt) => lt.is_elided(),
                _ => true,
            });
3492
            GenericArgs::AngleBracketed {
3493 3494 3495 3496 3497 3498 3499 3500
                args: self.args.iter().filter_map(|arg| match arg {
                    hir::GenericArg::Lifetime(lt) if !elide_lifetimes => {
                        Some(GenericArg::Lifetime(lt.clean(cx)))
                    }
                    hir::GenericArg::Lifetime(_) => None,
                    hir::GenericArg::Type(ty) => Some(GenericArg::Type(ty.clean(cx))),
                    hir::GenericArg::Const(ct) => Some(GenericArg::Const(ct.clean(cx))),
                }).collect(),
3501
                bindings: self.bindings.clean(cx),
3502
            }
3503 3504 3505
        }
    }
}
3506

3507
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)]
3508 3509
pub struct PathSegment {
    pub name: String,
V
varkor 已提交
3510
    pub args: GenericArgs,
3511 3512
}

3513
impl Clean<PathSegment> for hir::PathSegment {
3514
    fn clean(&self, cx: &DocContext<'_>) -> PathSegment {
3515
        PathSegment {
3516
            name: self.ident.name.clean(cx),
3517
            args: self.with_generic_args(|generic_args| generic_args.clean(cx))
C
Corey Richardson 已提交
3518 3519 3520 3521
        }
    }
}

3522 3523
fn strip_type(ty: Type) -> Type {
    match ty {
V
varkor 已提交
3524 3525
        Type::ResolvedPath { path, param_names, did, is_generic } => {
            Type::ResolvedPath { path: strip_path(&path), param_names, did, is_generic }
A
Aaron Hill 已提交
3526
        }
3527 3528
        Type::Tuple(inner_tys) => {
            Type::Tuple(inner_tys.iter().map(|t| strip_type(t.clone())).collect())
A
Aaron Hill 已提交
3529
        }
3530 3531 3532 3533 3534 3535
        Type::Slice(inner_ty) => Type::Slice(Box::new(strip_type(*inner_ty))),
        Type::Array(inner_ty, s) => Type::Array(Box::new(strip_type(*inner_ty)), s),
        Type::Unique(inner_ty) => Type::Unique(Box::new(strip_type(*inner_ty))),
        Type::RawPointer(m, inner_ty) => Type::RawPointer(m, Box::new(strip_type(*inner_ty))),
        Type::BorrowedRef { lifetime, mutability, type_ } => {
            Type::BorrowedRef { lifetime, mutability, type_: Box::new(strip_type(*type_)) }
A
Aaron Hill 已提交
3536
        }
3537 3538 3539 3540 3541
        Type::QPath { name, self_type, trait_ } => {
            Type::QPath {
                name,
                self_type: Box::new(strip_type(*self_type)), trait_: Box::new(strip_type(*trait_))
            }
A
Aaron Hill 已提交
3542
        }
3543 3544 3545 3546 3547 3548 3549 3550
        _ => ty
    }
}

fn strip_path(path: &Path) -> Path {
    let segments = path.segments.iter().map(|s| {
        PathSegment {
            name: s.name.clone(),
V
varkor 已提交
3551
            args: GenericArgs::AngleBracketed {
3552 3553
                args: vec![],
                bindings: vec![],
3554 3555 3556 3557 3558 3559 3560
            }
        }
    }).collect();

    Path {
        global: path.global,
        def: path.def.clone(),
A
Aaron Hill 已提交
3561
        segments,
3562 3563 3564
    }
}

3565
fn qpath_to_string(p: &hir::QPath) -> String {
3566 3567
    let segments = match *p {
        hir::QPath::Resolved(_, ref path) => &path.segments,
3568
        hir::QPath::TypeRelative(_, ref segment) => return segment.ident.to_string(),
3569 3570
    };

3571
    let mut s = String::new();
3572 3573
    for (i, seg) in segments.iter().enumerate() {
        if i > 0 {
C
Corey Richardson 已提交
3574 3575
            s.push_str("::");
        }
V
Vadim Petrochenkov 已提交
3576
        if seg.ident.name != keywords::PathRoot.name() {
3577
            s.push_str(&*seg.ident.as_str());
3578
        }
C
Corey Richardson 已提交
3579
    }
3580
    s
C
Corey Richardson 已提交
3581 3582
}

3583 3584
impl Clean<String> for Ident {
    #[inline]
3585
    fn clean(&self, cx: &DocContext<'_>) -> String {
3586 3587 3588 3589
        self.name.clean(cx)
    }
}

3590
impl Clean<String> for ast::Name {
3591
    #[inline]
3592
    fn clean(&self, _: &DocContext<'_>) -> String {
3593
        self.to_string()
3594 3595 3596
    }
}

3597
impl Clean<String> for InternedString {
3598
    #[inline]
3599
    fn clean(&self, _: &DocContext<'_>) -> String {
3600 3601 3602 3603
        self.to_string()
    }
}

J
Jorge Aparicio 已提交
3604
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
3605
pub struct Typedef {
3606 3607
    pub type_: Type,
    pub generics: Generics,
C
Corey Richardson 已提交
3608 3609 3610
}

impl Clean<Item> for doctree::Typedef {
3611
    fn clean(&self, cx: &DocContext<'_>) -> Item {
C
Corey Richardson 已提交
3612
        Item {
3613 3614 3615
            name: Some(self.name.clean(cx)),
            attrs: self.attrs.clean(cx),
            source: self.whence.clean(cx),
L
ljedrz 已提交
3616
            def_id: cx.tcx.hir().local_def_id_from_hir_id(self.id),
3617 3618
            visibility: self.vis.clean(cx),
            stability: self.stab.clean(cx),
3619
            deprecation: self.depr.clean(cx),
C
Corey Richardson 已提交
3620
            inner: TypedefItem(Typedef {
3621 3622
                type_: self.ty.clean(cx),
                generics: self.gen.clean(cx),
3623
            }, false),
C
Corey Richardson 已提交
3624 3625 3626 3627
        }
    }
}

O
Oliver Schneider 已提交
3628 3629 3630 3631 3632 3633 3634
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
pub struct Existential {
    pub bounds: Vec<GenericBound>,
    pub generics: Generics,
}

impl Clean<Item> for doctree::Existential {
3635
    fn clean(&self, cx: &DocContext<'_>) -> Item {
O
Oliver Schneider 已提交
3636 3637 3638 3639
        Item {
            name: Some(self.name.clean(cx)),
            attrs: self.attrs.clean(cx),
            source: self.whence.clean(cx),
L
ljedrz 已提交
3640
            def_id: cx.tcx.hir().local_def_id_from_hir_id(self.id),
O
Oliver Schneider 已提交
3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651
            visibility: self.vis.clean(cx),
            stability: self.stab.clean(cx),
            deprecation: self.depr.clean(cx),
            inner: ExistentialItem(Existential {
                bounds: self.exist_ty.bounds.clean(cx),
                generics: self.exist_ty.generics.clean(cx),
            }, false),
        }
    }
}

3652
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)]
C
Corey Richardson 已提交
3653
pub struct BareFunctionDecl {
3654
    pub unsafety: hir::Unsafety,
V
varkor 已提交
3655
    pub generic_params: Vec<GenericParamDef>,
3656
    pub decl: FnDecl,
3657
    pub abi: Abi,
C
Corey Richardson 已提交
3658 3659
}

3660
impl Clean<BareFunctionDecl> for hir::BareFnTy {
3661
    fn clean(&self, cx: &DocContext<'_>) -> BareFunctionDecl {
3662 3663 3664
        let (generic_params, decl) = enter_impl_trait(cx, || {
            (self.generic_params.clean(cx), (&*self.decl, &self.arg_names[..]).clean(cx))
        });
C
Corey Richardson 已提交
3665
        BareFunctionDecl {
N
Niko Matsakis 已提交
3666
            unsafety: self.unsafety,
W
Without Boats 已提交
3667
            abi: self.abi,
3668
            decl,
3669
            generic_params,
C
Corey Richardson 已提交
3670 3671 3672 3673
        }
    }
}

J
Jorge Aparicio 已提交
3674
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
3675
pub struct Static {
3676 3677
    pub type_: Type,
    pub mutability: Mutability,
C
Corey Richardson 已提交
3678 3679 3680
    /// 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.
3681
    pub expr: String,
C
Corey Richardson 已提交
3682 3683 3684
}

impl Clean<Item> for doctree::Static {
3685
    fn clean(&self, cx: &DocContext<'_>) -> Item {
3686
        debug!("cleaning static {}: {:?}", self.name.clean(cx), self);
C
Corey Richardson 已提交
3687
        Item {
3688 3689 3690
            name: Some(self.name.clean(cx)),
            attrs: self.attrs.clean(cx),
            source: self.whence.clean(cx),
L
ljedrz 已提交
3691
            def_id: cx.tcx.hir().local_def_id_from_hir_id(self.id),
3692 3693
            visibility: self.vis.clean(cx),
            stability: self.stab.clean(cx),
3694
            deprecation: self.depr.clean(cx),
C
Corey Richardson 已提交
3695
            inner: StaticItem(Static {
3696 3697
                type_: self.type_.clean(cx),
                mutability: self.mutability.clean(cx),
3698
                expr: print_const_expr(cx, self.expr),
C
Corey Richardson 已提交
3699 3700 3701 3702 3703
            }),
        }
    }
}

3704
#[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug)]
3705 3706 3707 3708 3709 3710
pub struct Constant {
    pub type_: Type,
    pub expr: String,
}

impl Clean<Item> for doctree::Constant {
3711
    fn clean(&self, cx: &DocContext<'_>) -> Item {
3712 3713 3714 3715
        Item {
            name: Some(self.name.clean(cx)),
            attrs: self.attrs.clean(cx),
            source: self.whence.clean(cx),
L
ljedrz 已提交
3716
            def_id: cx.tcx.hir().local_def_id_from_hir_id(self.id),
3717 3718
            visibility: self.vis.clean(cx),
            stability: self.stab.clean(cx),
3719
            deprecation: self.depr.clean(cx),
3720 3721
            inner: ConstantItem(Constant {
                type_: self.type_.clean(cx),
3722
                expr: print_const_expr(cx, self.expr),
3723 3724 3725 3726 3727
            }),
        }
    }
}

3728
#[derive(Debug, Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Copy, Hash)]
C
Corey Richardson 已提交
3729 3730 3731 3732 3733
pub enum Mutability {
    Mutable,
    Immutable,
}

3734
impl Clean<Mutability> for hir::Mutability {
3735
    fn clean(&self, _: &DocContext<'_>) -> Mutability {
C
Corey Richardson 已提交
3736
        match self {
3737 3738
            &hir::MutMutable => Mutable,
            &hir::MutImmutable => Immutable,
C
Corey Richardson 已提交
3739 3740 3741 3742
        }
    }
}

3743
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Copy, Debug, Hash)]
3744 3745 3746 3747 3748
pub enum ImplPolarity {
    Positive,
    Negative,
}

3749
impl Clean<ImplPolarity> for hir::ImplPolarity {
3750
    fn clean(&self, _: &DocContext<'_>) -> ImplPolarity {
3751
        match self {
3752 3753
            &hir::ImplPolarity::Positive => ImplPolarity::Positive,
            &hir::ImplPolarity::Negative => ImplPolarity::Negative,
3754 3755 3756 3757
        }
    }
}

J
Jorge Aparicio 已提交
3758
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
3759
pub struct Impl {
3760
    pub unsafety: hir::Unsafety,
3761
    pub generics: Generics,
3762
    pub provided_trait_methods: FxHashSet<String>,
3763 3764
    pub trait_: Option<Type>,
    pub for_: Type,
3765
    pub items: Vec<Item>,
3766
    pub polarity: Option<ImplPolarity>,
3767
    pub synthetic: bool,
3768
    pub blanket_impl: Option<Type>,
3769 3770
}

3771
pub fn get_auto_traits_with_hir_id(
3772
    cx: &DocContext<'_>,
3773
    id: hir::HirId,
H
Hirokazu Hata 已提交
3774 3775
    name: String
) -> Vec<Item> {
3776
    let finder = AutoTraitFinder::new(cx);
3777
    finder.get_with_hir_id(id, name)
3778 3779
}

H
Hirokazu Hata 已提交
3780
pub fn get_auto_traits_with_def_id(
3781
    cx: &DocContext<'_>,
H
Hirokazu Hata 已提交
3782 3783
    id: DefId
) -> Vec<Item> {
3784
    let finder = AutoTraitFinder::new(cx);
3785 3786

    finder.get_with_def_id(id)
C
Corey Richardson 已提交
3787 3788
}

3789
pub fn get_blanket_impls_with_hir_id(
3790
    cx: &DocContext<'_>,
3791
    id: hir::HirId,
H
Hirokazu Hata 已提交
3792 3793
    name: String
) -> Vec<Item> {
G
Guillaume Gomez 已提交
3794
    let finder = BlanketImplFinder::new(cx);
3795
    finder.get_with_hir_id(id, name)
G
Guillaume Gomez 已提交
3796 3797
}

H
Hirokazu Hata 已提交
3798
pub fn get_blanket_impls_with_def_id(
3799
    cx: &DocContext<'_>,
H
Hirokazu Hata 已提交
3800 3801
    id: DefId
) -> Vec<Item> {
G
Guillaume Gomez 已提交
3802 3803 3804 3805 3806
    let finder = BlanketImplFinder::new(cx);

    finder.get_with_def_id(id)
}

3807
impl Clean<Vec<Item>> for doctree::Impl {
3808
    fn clean(&self, cx: &DocContext<'_>) -> Vec<Item> {
3809 3810 3811 3812 3813 3814
        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.
3815
        if trait_.def_id() == cx.tcx.lang_items().deref_trait() {
3816
            build_deref_target_impls(cx, &items, &mut ret);
3817 3818
        }

3819 3820 3821
        let provided = trait_.def_id().map(|did| {
            cx.tcx.provided_trait_methods(did)
                  .into_iter()
3822
                  .map(|meth| meth.ident.to_string())
3823
                  .collect()
3824
        }).unwrap_or_default();
3825

3826
        ret.push(Item {
C
Corey Richardson 已提交
3827
            name: None,
3828 3829
            attrs: self.attrs.clean(cx),
            source: self.whence.clean(cx),
L
ljedrz 已提交
3830
            def_id: cx.tcx.hir().local_def_id_from_hir_id(self.id),
3831 3832
            visibility: self.vis.clean(cx),
            stability: self.stab.clean(cx),
3833
            deprecation: self.depr.clean(cx),
C
Corey Richardson 已提交
3834
            inner: ImplItem(Impl {
3835
                unsafety: self.unsafety,
3836
                generics: self.generics.clean(cx),
3837
                provided_trait_methods: provided,
3838
                trait_,
3839
                for_: self.for_.clean(cx),
3840
                items,
3841
                polarity: Some(self.polarity.clean(cx)),
A
Aaron Hill 已提交
3842
                synthetic: false,
3843
                blanket_impl: None,
3844
            })
3845
        });
M
mitaa 已提交
3846
        ret
3847 3848 3849
    }
}

3850
fn build_deref_target_impls(cx: &DocContext<'_>,
3851 3852
                            items: &[Item],
                            ret: &mut Vec<Item>) {
3853
    use self::PrimitiveType::*;
3854
    let tcx = cx.tcx;
3855 3856 3857

    for item in items {
        let target = match item.inner {
3858
            TypedefItem(ref t, true) => &t.type_,
3859 3860 3861
            _ => continue,
        };
        let primitive = match *target {
N
Niko Matsakis 已提交
3862
            ResolvedPath { did, .. } if did.is_local() => continue,
3863
            ResolvedPath { did, .. } => {
3864
                ret.extend(inline::build_impls(cx, did));
3865 3866 3867 3868 3869 3870 3871 3872
                continue
            }
            _ => match target.primitive_type() {
                Some(prim) => prim,
                None => continue,
            }
        };
        let did = match primitive {
3873 3874 3875 3876 3877 3878 3879 3880 3881 3882 3883 3884 3885 3886 3887
            Isize => tcx.lang_items().isize_impl(),
            I8 => tcx.lang_items().i8_impl(),
            I16 => tcx.lang_items().i16_impl(),
            I32 => tcx.lang_items().i32_impl(),
            I64 => tcx.lang_items().i64_impl(),
            I128 => tcx.lang_items().i128_impl(),
            Usize => tcx.lang_items().usize_impl(),
            U8 => tcx.lang_items().u8_impl(),
            U16 => tcx.lang_items().u16_impl(),
            U32 => tcx.lang_items().u32_impl(),
            U64 => tcx.lang_items().u64_impl(),
            U128 => tcx.lang_items().u128_impl(),
            F32 => tcx.lang_items().f32_impl(),
            F64 => tcx.lang_items().f64_impl(),
            Char => tcx.lang_items().char_impl(),
3888
            Bool => None,
3889 3890 3891
            Str => tcx.lang_items().str_impl(),
            Slice => tcx.lang_items().slice_impl(),
            Array => tcx.lang_items().slice_impl(),
3892
            Tuple => None,
3893
            Unit => None,
3894
            RawPointer => tcx.lang_items().const_ptr_impl(),
3895
            Reference => None,
3896
            Fn => None,
A
Andrew Cann 已提交
3897
            Never => None,
3898
            CVarArgs => tcx.lang_items().va_list(),
3899 3900
        };
        if let Some(did) = did {
N
Niko Matsakis 已提交
3901
            if !did.is_local() {
3902
                inline::build_impl(cx, did, ret);
3903
            }
C
Corey Richardson 已提交
3904 3905 3906 3907
        }
    }
}

D
DebugSteven 已提交
3908
impl Clean<Vec<Item>> for doctree::ExternCrate {
3909
    fn clean(&self, cx: &DocContext<'_>) -> Vec<Item> {
D
DebugSteven 已提交
3910 3911

        let please_inline = self.vis.node.is_pub() && self.attrs.iter().any(|a| {
3912
            a.check_name("doc") && match a.meta_item_list() {
D
DebugSteven 已提交
3913 3914 3915 3916 3917 3918 3919 3920 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930 3931
                Some(l) => attr::list_contains_name(&l, "inline"),
                None => false,
            }
        });

        if please_inline {
            let mut visited = FxHashSet::default();

            let def = Def::Mod(DefId {
                krate: self.cnum,
                index: CRATE_DEF_INDEX,
            });

            if let Some(items) = inline::try_inline(cx, def, self.name, &mut visited) {
                return items;
            }
        }

        vec![Item {
3932 3933 3934
            name: None,
            attrs: self.attrs.clean(cx),
            source: self.whence.clean(cx),
M
mitaa 已提交
3935
            def_id: DefId { krate: self.cnum, index: CRATE_DEF_INDEX },
3936 3937
            visibility: self.vis.clean(cx),
            stability: None,
3938
            deprecation: None,
3939
            inner: ExternCrateItem(self.name.clean(cx), self.path.clone())
D
DebugSteven 已提交
3940
        }]
3941
    }
C
Corey Richardson 已提交
3942 3943
}

3944
impl Clean<Vec<Item>> for doctree::Import {
3945
    fn clean(&self, cx: &DocContext<'_>) -> Vec<Item> {
J
Joseph Crail 已提交
3946
        // We consider inlining the documentation of `pub use` statements, but we
3947 3948
        // forcefully don't inline if this is not public or if the
        // #[doc(no_inline)] attribute is present.
3949
        // Don't inline doc(hidden) imports so they can be stripped at a later stage.
3950
        let mut denied = !self.vis.node.is_pub() || self.attrs.iter().any(|a| {
3951
            a.check_name("doc") && match a.meta_item_list() {
3952 3953
                Some(l) => attr::list_contains_name(&l, "no_inline") ||
                           attr::list_contains_name(&l, "hidden"),
3954 3955 3956
                None => false,
            }
        });
3957 3958 3959
        // Also check whether imports were asked to be inlined, in case we're trying to re-export a
        // crate in Rust 2018+
        let please_inline = self.attrs.lists("doc").has_word("inline");
3960 3961
        let path = self.path.clean(cx);
        let inner = if self.glob {
3962
            if !denied {
3963
                let mut visited = FxHashSet::default();
3964 3965 3966 3967 3968
                if let Some(items) = inline::try_inline_glob(cx, path.def, &mut visited) {
                    return items;
                }
            }

3969
            Import::Glob(resolve_use_source(cx, path))
3970 3971
        } else {
            let name = self.name;
3972 3973 3974 3975 3976 3977 3978 3979 3980 3981
            if !please_inline {
                match path.def {
                    Def::Mod(did) => if !did.is_local() && did.index == CRATE_DEF_INDEX {
                        // if we're `pub use`ing an extern crate root, don't inline it unless we
                        // were specifically asked for it
                        denied = true;
                    }
                    _ => {}
                }
            }
3982
            if !denied {
3983
                let mut visited = FxHashSet::default();
3984
                if let Some(items) = inline::try_inline(cx, path.def, name, &mut visited) {
3985
                    return items;
3986
                }
3987
            }
3988
            Import::Simple(name.clean(cx), resolve_use_source(cx, path))
3989
        };
G
Guillaume Gomez 已提交
3990

3991
        vec![Item {
3992 3993 3994
            name: None,
            attrs: self.attrs.clean(cx),
            source: self.whence.clean(cx),
3995
            def_id: cx.tcx.hir().local_def_id(ast::CRATE_NODE_ID),
3996 3997
            visibility: self.vis.clean(cx),
            stability: None,
3998
            deprecation: None,
3999
            inner: ImportItem(inner)
4000
        }]
C
Corey Richardson 已提交
4001 4002 4003
    }
}

J
Jorge Aparicio 已提交
4004
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
4005
pub enum Import {
4006
    // use source as str;
4007
    Simple(String, ImportSource),
A
Alex Crichton 已提交
4008
    // use source::*;
4009
    Glob(ImportSource)
A
Alex Crichton 已提交
4010 4011
}

J
Jorge Aparicio 已提交
4012
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
A
Alex Crichton 已提交
4013
pub struct ImportSource {
4014
    pub path: Path,
N
Niko Matsakis 已提交
4015
    pub did: Option<DefId>,
C
Corey Richardson 已提交
4016 4017
}

4018
impl Clean<Vec<Item>> for hir::ForeignMod {
4019
    fn clean(&self, cx: &DocContext<'_>) -> Vec<Item> {
4020 4021
        let mut items = self.items.clean(cx);
        for item in &mut items {
M
mitaa 已提交
4022
            if let ForeignFunctionItem(ref mut f) = item.inner {
W
Without Boats 已提交
4023
                f.header.abi = self.abi;
4024 4025 4026
            }
        }
        items
4027 4028 4029
    }
}

4030
impl Clean<Item> for hir::ForeignItem {
4031
    fn clean(&self, cx: &DocContext<'_>) -> Item {
4032
        let inner = match self.node {
C
csmoe 已提交
4033
            hir::ForeignItemKind::Fn(ref decl, ref names, ref generics) => {
4034 4035 4036
                let (generics, decl) = enter_impl_trait(cx, || {
                    (generics.clean(cx), (&**decl, &names[..]).clean(cx))
                });
4037
                let (all_types, ret_types) = get_all_types(&generics, &decl, cx);
4038
                ForeignFunctionItem(Function {
4039
                    decl,
4040
                    generics,
4041 4042 4043 4044 4045 4046
                    header: hir::FnHeader {
                        unsafety: hir::Unsafety::Unsafe,
                        abi: Abi::Rust,
                        constness: hir::Constness::NotConst,
                        asyncness: hir::IsAsync::NotAsync,
                    },
4047
                    all_types,
4048
                    ret_types,
4049 4050
                })
            }
C
csmoe 已提交
4051
            hir::ForeignItemKind::Static(ref ty, mutbl) => {
4052
                ForeignStaticItem(Static {
4053
                    type_: ty.clean(cx),
4054
                    mutability: if mutbl {Mutable} else {Immutable},
4055
                    expr: String::new(),
4056 4057
                })
            }
C
csmoe 已提交
4058
            hir::ForeignItemKind::Type => {
P
Paul Lietar 已提交
4059 4060
                ForeignTypeItem
            }
4061
        };
G
Guillaume Gomez 已提交
4062

L
ljedrz 已提交
4063 4064
        let local_did = cx.tcx.hir().local_def_id_from_hir_id(self.hir_id);

4065
        Item {
4066
            name: Some(self.ident.clean(cx)),
4067 4068
            attrs: self.attrs.clean(cx),
            source: self.span.clean(cx),
L
ljedrz 已提交
4069
            def_id: local_did,
4070
            visibility: self.vis.clean(cx),
L
ljedrz 已提交
4071 4072
            stability: get_stability(cx, local_did),
            deprecation: get_deprecation(cx, local_did),
4073
            inner,
4074 4075 4076 4077
        }
    }
}

C
Corey Richardson 已提交
4078 4079
// Utilities

4080
pub trait ToSource {
4081
    fn to_src(&self, cx: &DocContext<'_>) -> String;
C
Corey Richardson 已提交
4082 4083
}

4084
impl ToSource for syntax_pos::Span {
4085
    fn to_src(&self, cx: &DocContext<'_>) -> String {
4086
        debug!("converting span {:?} to snippet", self.clean(cx));
D
Donato Sciarra 已提交
4087
        let sn = match cx.sess().source_map().span_to_snippet(*self) {
S
Shotaro Yamada 已提交
4088
            Ok(x) => x,
4089
            Err(_) => String::new()
C
Corey Richardson 已提交
4090
        };
4091
        debug!("got snippet {}", sn);
C
Corey Richardson 已提交
4092 4093 4094 4095
        sn
    }
}

4096
fn name_from_pat(p: &hir::Pat) -> String {
4097
    use rustc::hir::*;
4098
    debug!("Trying to get a name from pattern: {:?}", p);
4099

C
Corey Richardson 已提交
4100
    match p.node {
4101
        PatKind::Wild => "_".to_string(),
L
ljedrz 已提交
4102
        PatKind::Binding(_, _, ident, _) => ident.to_string(),
4103
        PatKind::TupleStruct(ref p, ..) | PatKind::Path(ref p) => qpath_to_string(p),
4104
        PatKind::Struct(ref name, ref fields, etc) => {
4105
            format!("{} {{ {}{} }}", qpath_to_string(name),
4106
                fields.iter().map(|&Spanned { node: ref fp, .. }|
4107
                                  format!("{}: {}", fp.ident, name_from_pat(&*fp.pat)))
4108
                             .collect::<Vec<String>>().join(", "),
4109
                if etc { ", .." } else { "" }
4110
            )
4111
        }
4112
        PatKind::Tuple(ref elts, _) => format!("({})", elts.iter().map(|p| name_from_pat(&**p))
4113
                                            .collect::<Vec<String>>().join(", ")),
4114 4115 4116 4117
        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, \
4118
                  which is silly in function arguments");
4119
            "()".to_string()
4120
        },
4121
        PatKind::Range(..) => panic!("tried to get argument name from PatKind::Range, \
4122
                              which is not allowed in function arguments"),
4123
        PatKind::Slice(ref begin, ref mid, ref end) => {
4124 4125 4126
            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));
4127
            format!("[{}]", begin.chain(mid).chain(end).collect::<Vec<_>>().join(", "))
4128
        },
C
Corey Richardson 已提交
4129 4130 4131
    }
}

O
Oliver Scherer 已提交
4132 4133 4134
fn print_const(cx: &DocContext<'_>, n: ty::Const<'_>) -> String {
    match n.val {
        ConstValue::Unevaluated(def_id, _) => {
4135 4136
            if let Some(hir_id) = cx.tcx.hir().as_local_hir_id(def_id) {
                print_const_expr(cx, cx.tcx.hir().body_owned_by(hir_id))
O
Oliver Schneider 已提交
4137 4138 4139 4140
            } else {
                inline::print_inlined_const(cx, def_id)
            }
        },
O
Oliver Scherer 已提交
4141
        _ => {
O
Oliver Schneider 已提交
4142
            let mut s = String::new();
G
Guillaume Gomez 已提交
4143
            ::rustc::mir::fmt_const_val(&mut s, n).expect("fmt_const_val failed");
O
Oliver Schneider 已提交
4144 4145 4146 4147 4148 4149 4150 4151 4152 4153
            // array lengths are obviously usize
            if s.ends_with("usize") {
                let n = s.len() - "usize".len();
                s.truncate(n);
            }
            s
        },
    }
}

4154
fn print_const_expr(cx: &DocContext<'_>, body: hir::BodyId) -> String {
L
ljedrz 已提交
4155
    cx.tcx.hir().hir_to_pretty_string(body.hir_id)
4156 4157
}

4158
/// Given a type Path, resolve it to a Type using the TyCtxt
4159
fn resolve_type(cx: &DocContext<'_>,
N
Niko Matsakis 已提交
4160
                path: Path,
L
ljedrz 已提交
4161 4162
                id: hir::HirId) -> Type {
    if id == hir::DUMMY_HIR_ID {
4163 4164 4165 4166
        debug!("resolve_type({:?})", path);
    } else {
        debug!("resolve_type({:?},{:?})", path, id);
    }
4167

4168
    let is_generic = match path.def {
4169
        Def::PrimTy(p) => match p {
4170 4171 4172 4173 4174 4175
            hir::Str => return Primitive(PrimitiveType::Str),
            hir::Bool => return Primitive(PrimitiveType::Bool),
            hir::Char => return Primitive(PrimitiveType::Char),
            hir::Int(int_ty) => return Primitive(int_ty.into()),
            hir::Uint(uint_ty) => return Primitive(uint_ty.into()),
            hir::Float(float_ty) => return Primitive(float_ty.into()),
C
Corey Richardson 已提交
4176
        },
4177
        Def::SelfTy(..) if path.segments.len() == 1 => {
V
Vadim Petrochenkov 已提交
4178
            return Generic(keywords::SelfUpper.name().to_string());
4179
        }
4180
        Def::TyParam(..) if path.segments.len() == 1 => {
4181 4182
            return Generic(format!("{:#}", path));
        }
4183
        Def::SelfTy(..) | Def::TyParam(..) | Def::AssociatedTy(..) => true,
4184
        _ => false,
4185
    };
4186
    let did = register_def(&*cx, path.def);
V
varkor 已提交
4187
    ResolvedPath { path: path, param_names: None, did: did, is_generic: is_generic }
4188 4189
}

4190
pub fn register_def(cx: &DocContext<'_>, def: Def) -> DefId {
4191 4192
    debug!("register_def({:?})", def);

4193
    let (did, kind) = match def {
4194 4195 4196 4197 4198 4199 4200
        Def::Fn(i) => (i, TypeKind::Function),
        Def::TyAlias(i) => (i, TypeKind::Typedef),
        Def::Enum(i) => (i, TypeKind::Enum),
        Def::Trait(i) => (i, TypeKind::Trait),
        Def::Struct(i) => (i, TypeKind::Struct),
        Def::Union(i) => (i, TypeKind::Union),
        Def::Mod(i) => (i, TypeKind::Module),
V
varkor 已提交
4201
        Def::ForeignTy(i) => (i, TypeKind::Foreign),
4202
        Def::Const(i) => (i, TypeKind::Const),
4203
        Def::Static(i, _) => (i, TypeKind::Static),
4204
        Def::Variant(i) => (cx.tcx.parent(i).expect("cannot get parent def id"),
G
Guillaume Gomez 已提交
4205
                            TypeKind::Enum),
4206 4207 4208 4209 4210 4211
        Def::Macro(i, mac_kind) => match mac_kind {
            MacroKind::Bang => (i, TypeKind::Macro),
            MacroKind::Attr => (i, TypeKind::Attr),
            MacroKind::Derive => (i, TypeKind::Derive),
            MacroKind::ProcMacroStub => unreachable!(),
        },
4212
        Def::TraitAlias(i) => (i, TypeKind::TraitAlias),
4213
        Def::SelfTy(Some(def_id), _) => (def_id, TypeKind::Trait),
4214
        Def::SelfTy(_, Some(impl_def_id)) => return impl_def_id,
4215
        _ => return def.def_id()
C
Corey Richardson 已提交
4216
    };
N
Niko Matsakis 已提交
4217
    if did.is_local() { return did }
4218
    inline::record_extern_fqn(cx, did, kind);
4219
    if let TypeKind::Trait = kind {
4220
        inline::record_extern_trait(cx, did);
4221
    }
M
mitaa 已提交
4222
    did
C
Corey Richardson 已提交
4223
}
A
Alex Crichton 已提交
4224

4225
fn resolve_use_source(cx: &DocContext<'_>, path: Path) -> ImportSource {
A
Alex Crichton 已提交
4226
    ImportSource {
4227
        did: if path.def.opt_def_id().is_none() {
4228 4229 4230 4231
            None
        } else {
            Some(register_def(cx, path.def))
        },
4232
        path,
A
Alex Crichton 已提交
4233 4234 4235
    }
}

J
Jorge Aparicio 已提交
4236
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
4237
pub struct Macro {
4238
    pub source: String,
4239
    pub imported_from: Option<String>,
4240 4241 4242
}

impl Clean<Item> for doctree::Macro {
4243
    fn clean(&self, cx: &DocContext<'_>) -> Item {
4244
        let name = self.name.clean(cx);
4245
        Item {
4246
            name: Some(name.clone()),
4247 4248
            attrs: self.attrs.clean(cx),
            source: self.whence.clean(cx),
J
Jeffrey Seyfried 已提交
4249
            visibility: Some(Public),
4250
            stability: self.stab.clean(cx),
4251
            deprecation: self.depr.clean(cx),
4252
            def_id: self.def_id,
4253
            inner: MacroItem(Macro {
4254
                source: format!("macro_rules! {} {{\n{}}}",
4255 4256 4257 4258
                                name,
                                self.matchers.iter().map(|span| {
                                    format!("    {} => {{ ... }};\n", span.to_src(cx))
                                }).collect::<String>()),
4259
                imported_from: self.imported_from.clean(cx),
4260 4261 4262 4263
            }),
        }
    }
}
4264

4265 4266 4267
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
pub struct ProcMacro {
    pub kind: MacroKind,
4268
    pub helpers: Vec<String>,
4269 4270 4271
}

impl Clean<Item> for doctree::ProcMacro {
4272
    fn clean(&self, cx: &DocContext<'_>) -> Item {
4273 4274 4275 4276 4277 4278 4279
        Item {
            name: Some(self.name.clean(cx)),
            attrs: self.attrs.clean(cx),
            source: self.whence.clean(cx),
            visibility: Some(Public),
            stability: self.stab.clean(cx),
            deprecation: self.depr.clean(cx),
L
ljedrz 已提交
4280
            def_id: cx.tcx.hir().local_def_id_from_hir_id(self.id),
4281 4282
            inner: ProcMacroItem(ProcMacro {
                kind: self.kind,
4283
                helpers: self.helpers.clean(cx),
4284 4285 4286 4287 4288
            }),
        }
    }
}

J
Jorge Aparicio 已提交
4289
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
4290
pub struct Stability {
V
Vadim Petrochenkov 已提交
4291
    pub level: stability::StabilityLevel,
4292
    pub feature: Option<String>,
4293
    pub since: String,
4294 4295 4296
    pub deprecation: Option<Deprecation>,
    pub unstable_reason: Option<String>,
    pub issue: Option<u32>,
4297 4298
}

4299 4300
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
pub struct Deprecation {
4301 4302
    pub since: Option<String>,
    pub note: Option<String>,
4303 4304
}

4305
impl Clean<Stability> for attr::Stability {
4306
    fn clean(&self, _: &DocContext<'_>) -> Stability {
4307
        Stability {
V
Vadim Petrochenkov 已提交
4308
            level: stability::StabilityLevel::from_attr_level(&self.level),
4309
            feature: Some(self.feature.to_string()).filter(|f| !f.is_empty()),
V
Vadim Petrochenkov 已提交
4310 4311
            since: match self.level {
                attr::Stable {ref since} => since.to_string(),
4312
                _ => String::new(),
V
Vadim Petrochenkov 已提交
4313
            },
4314 4315 4316 4317 4318 4319
            deprecation: self.rustc_depr.as_ref().map(|d| {
                Deprecation {
                    note: Some(d.reason.to_string()).filter(|r| !r.is_empty()),
                    since: Some(d.since.to_string()).filter(|d| !d.is_empty()),
                }
            }),
4320
            unstable_reason: match self.level {
4321 4322
                attr::Unstable { reason: Some(ref reason), .. } => Some(reason.to_string()),
                _ => None,
V
Vadim Petrochenkov 已提交
4323 4324 4325 4326 4327
            },
            issue: match self.level {
                attr::Unstable {issue, ..} => Some(issue),
                _ => None,
            }
4328 4329 4330 4331 4332
        }
    }
}

impl<'a> Clean<Stability> for &'a attr::Stability {
4333
    fn clean(&self, dc: &DocContext<'_>) -> Stability {
V
Vadim Petrochenkov 已提交
4334
        (**self).clean(dc)
4335 4336
    }
}
A
Alex Crichton 已提交
4337

4338
impl Clean<Deprecation> for attr::Deprecation {
4339
    fn clean(&self, _: &DocContext<'_>) -> Deprecation {
4340
        Deprecation {
4341 4342
            since: self.since.map(|s| s.to_string()).filter(|s| !s.is_empty()),
            note: self.note.map(|n| n.to_string()).filter(|n| !n.is_empty()),
4343 4344 4345 4346
        }
    }
}

A
Alexander Regueiro 已提交
4347
/// An equality constraint on an associated type, e.g., `A = Bar` in `Foo<A = Bar>`
4348
#[derive(Clone, PartialEq, Eq, RustcDecodable, RustcEncodable, Debug, Hash)]
4349 4350 4351 4352 4353
pub struct TypeBinding {
    pub name: String,
    pub ty: Type
}

4354
impl Clean<TypeBinding> for hir::TypeBinding {
4355
    fn clean(&self, cx: &DocContext<'_>) -> TypeBinding {
4356
        TypeBinding {
4357
            name: self.ident.name.clean(cx),
4358 4359 4360 4361
            ty: self.ty.clean(cx)
        }
    }
}
4362

H
Hirokazu Hata 已提交
4363
pub fn def_id_to_path(
4364
    cx: &DocContext<'_>,
H
Hirokazu Hata 已提交
4365 4366 4367
    did: DefId,
    name: Option<String>
) -> Vec<String> {
4368 4369 4370 4371 4372 4373 4374 4375 4376 4377 4378 4379 4380
    let crate_name = name.unwrap_or_else(|| cx.tcx.crate_name(did.krate).to_string());
    let relative = cx.tcx.def_path(did).data.into_iter().filter_map(|elem| {
        // extern blocks have an empty name
        let s = elem.data.to_string();
        if !s.is_empty() {
            Some(s)
        } else {
            None
        }
    });
    once(crate_name).chain(relative).collect()
}

4381
pub fn enter_impl_trait<F, R>(cx: &DocContext<'_>, f: F) -> R
4382 4383 4384
where
    F: FnOnce() -> R,
{
4385
    let old_bounds = mem::replace(&mut *cx.impl_trait_bounds.borrow_mut(), Default::default());
4386 4387 4388 4389 4390 4391
    let r = f();
    assert!(cx.impl_trait_bounds.borrow().is_empty());
    *cx.impl_trait_bounds.borrow_mut() = old_bounds;
    r
}

4392 4393
// Start of code copied from rust-clippy

4394
pub fn path_to_def_local(tcx: &TyCtxt<'_, '_, '_>, path: &[&str]) -> Option<DefId> {
4395
    let krate = tcx.hir().krate();
4396 4397 4398 4399
    let mut items = krate.module.item_ids.clone();
    let mut path_it = path.iter().peekable();

    loop {
4400
        let segment = path_it.next()?;
4401 4402

        for item_id in mem::replace(&mut items, HirVec::new()).iter() {
4403
            let item = tcx.hir().expect_item_by_hir_id(item_id.id);
4404
            if item.ident.name == *segment {
4405
                if path_it.peek().is_none() {
4406
                    return Some(tcx.hir().local_def_id_from_hir_id(item_id.id))
4407 4408 4409
                }

                items = match &item.node {
C
csmoe 已提交
4410
                    &hir::ItemKind::Mod(ref m) => m.item_ids.clone(),
4411 4412 4413 4414 4415 4416 4417 4418
                    _ => panic!("Unexpected item {:?} in path {:?} path")
                };
                break;
            }
        }
    }
}

4419
pub fn path_to_def(tcx: &TyCtxt<'_, '_, '_>, path: &[&str]) -> Option<DefId> {
4420 4421 4422 4423 4424 4425 4426 4427 4428 4429 4430 4431 4432 4433 4434
    let crates = tcx.crates();

    let krate = crates
        .iter()
        .find(|&&krate| tcx.crate_name(krate) == path[0]);

    if let Some(krate) = krate {
        let krate = DefId {
            krate: *krate,
            index: CRATE_DEF_INDEX,
        };
        let mut items = tcx.item_children(krate);
        let mut path_it = path.iter().skip(1).peekable();

        loop {
4435
            let segment = path_it.next()?;
4436

4437
            for item in mem::replace(&mut items, Lrc::new(vec![])).iter() {
4438 4439 4440 4441
                if item.ident.name == *segment {
                    if path_it.peek().is_none() {
                        return match item.def {
                            def::Def::Trait(did) => Some(did),
A
Aaron Hill 已提交
4442
                            _ => None,
4443 4444 4445 4446 4447 4448 4449 4450 4451 4452 4453 4454 4455
                        }
                    }

                    items = tcx.item_children(item.def.def_id());
                    break;
                }
            }
        }
    } else {
        None
    }
}

4456 4457 4458 4459 4460 4461
pub fn get_path_for_type(
    tcx: TyCtxt<'_, '_, '_>,
    def_id: DefId,
    def_ctor: impl Fn(DefId) -> Def,
) -> hir::Path {
    use rustc::ty::print::Printer;
4462

4463 4464 4465
    struct AbsolutePathPrinter<'a, 'tcx> {
        tcx: TyCtxt<'a, 'tcx, 'tcx>,
    }
4466

4467
    impl Printer<'tcx, 'tcx> for AbsolutePathPrinter<'_, 'tcx> {
4468 4469
        type Error = !;

4470
        type Path = Vec<String>;
4471
        type Region = ();
4472
        type Type = ();
4473
        type DynExistential = ();
4474

4475 4476 4477 4478
        fn tcx(&'a self) -> TyCtxt<'a, 'tcx, 'tcx> {
            self.tcx
        }

4479
        fn print_region(
4480
            self,
4481 4482 4483 4484
            _region: ty::Region<'_>,
        ) -> Result<Self::Region, Self::Error> {
            Ok(())
        }
4485

4486
        fn print_type(
4487
            self,
4488 4489 4490 4491 4492
            _ty: Ty<'tcx>,
        ) -> Result<Self::Type, Self::Error> {
            Ok(())
        }

4493 4494
        fn print_dyn_existential(
            self,
4495 4496 4497 4498 4499
            _predicates: &'tcx ty::List<ty::ExistentialPredicate<'tcx>>,
        ) -> Result<Self::DynExistential, Self::Error> {
            Ok(())
        }

4500
        fn path_crate(
4501
            self,
4502 4503 4504
            cnum: CrateNum,
        ) -> Result<Self::Path, Self::Error> {
            Ok(vec![self.tcx.original_crate_name(cnum).to_string()])
4505
        }
4506
        fn path_qualified(
4507
            self,
4508 4509
            self_ty: Ty<'tcx>,
            trait_ref: Option<ty::TraitRef<'tcx>>,
4510
        ) -> Result<Self::Path, Self::Error> {
4511 4512 4513 4514 4515 4516 4517
            // This shouldn't ever be needed, but just in case:
            Ok(vec![match trait_ref {
                Some(trait_ref) => format!("{:?}", trait_ref),
                None => format!("<{}>", self_ty),
            }])
        }

4518 4519 4520
        fn path_append_impl(
            self,
            print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
4521
            _disambiguated_data: &DisambiguatedDefPathData,
4522 4523 4524 4525
            self_ty: Ty<'tcx>,
            trait_ref: Option<ty::TraitRef<'tcx>>,
        ) -> Result<Self::Path, Self::Error> {
            let mut path = print_prefix(self)?;
4526

4527
            // This shouldn't ever be needed, but just in case:
4528 4529 4530 4531 4532 4533
            path.push(match trait_ref {
                Some(trait_ref) => {
                    format!("<impl {} for {}>", trait_ref, self_ty)
                }
                None => format!("<impl {}>", self_ty),
            });
4534

4535
            Ok(path)
4536
        }
4537 4538 4539
        fn path_append(
            self,
            print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
4540
            disambiguated_data: &DisambiguatedDefPathData,
4541
        ) -> Result<Self::Path, Self::Error> {
4542
            let mut path = print_prefix(self)?;
4543
            path.push(disambiguated_data.data.as_interned_str().to_string());
4544
            Ok(path)
4545
        }
4546 4547 4548
        fn path_generic_args(
            self,
            print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
4549
            _args: &[Kind<'tcx>],
4550
        ) -> Result<Self::Path, Self::Error> {
4551
            print_prefix(self)
4552
        }
4553 4554
    }

4555
    let names = AbsolutePathPrinter { tcx: tcx.global_tcx() }
4556
        .print_def_path(def_id, &[])
4557
        .unwrap();
4558 4559 4560 4561

    hir::Path {
        span: DUMMY_SP,
        def: def_ctor(def_id),
4562
        segments: hir::HirVec::from_vec(names.iter().map(|s| hir::PathSegment {
4563
            ident: ast::Ident::from_str(&s),
L
ljedrz 已提交
4564
            hir_id: None,
N
Nick Cameron 已提交
4565
            def: None,
V
varkor 已提交
4566
            args: None,
A
Aaron Hill 已提交
4567
            infer_types: false,
4568 4569 4570 4571 4572 4573 4574 4575 4576 4577 4578 4579 4580 4581 4582 4583 4584 4585 4586 4587 4588
        }).collect())
    }
}

// End of code copied from rust-clippy


#[derive(Eq, PartialEq, Hash, Copy, Clone, Debug)]
enum RegionTarget<'tcx> {
    Region(Region<'tcx>),
    RegionVid(RegionVid)
}

#[derive(Default, Debug, Clone)]
struct RegionDeps<'tcx> {
    larger: FxHashSet<RegionTarget<'tcx>>,
    smaller: FxHashSet<RegionTarget<'tcx>>
}

#[derive(Eq, PartialEq, Hash, Debug)]
enum SimpleBound {
V
varkor 已提交
4589 4590
    TraitBound(Vec<PathSegment>, Vec<SimpleBound>, Vec<GenericParamDef>, hir::TraitBoundModifier),
    Outlives(Lifetime),
4591 4592 4593 4594 4595 4596 4597 4598 4599 4600 4601 4602
}

enum AutoTraitResult {
    ExplicitImpl,
    PositiveImpl(Generics),
    NegativeImpl,
}

impl AutoTraitResult {
    fn is_auto(&self) -> bool {
        match *self {
            AutoTraitResult::PositiveImpl(_) | AutoTraitResult::NegativeImpl => true,
A
Aaron Hill 已提交
4603
            _ => false,
4604 4605 4606 4607
        }
    }
}

V
varkor 已提交
4608 4609
impl From<GenericBound> for SimpleBound {
    fn from(bound: GenericBound) -> Self {
4610
        match bound.clone() {
V
varkor 已提交
4611 4612
            GenericBound::Outlives(l) => SimpleBound::Outlives(l),
            GenericBound::TraitBound(t, mod_) => match t.trait_ {
V
varkor 已提交
4613
                Type::ResolvedPath { path, param_names, .. } => {
4614
                    SimpleBound::TraitBound(path.segments,
V
varkor 已提交
4615
                                            param_names
4616 4617 4618 4619 4620
                                                .map_or_else(|| Vec::new(), |v| v.iter()
                                                        .map(|p| SimpleBound::from(p.clone()))
                                                        .collect()),
                                            t.generic_params,
                                            mod_)
A
Aaron Hill 已提交
4621
                }
A
Aaron Hill 已提交
4622
                _ => panic!("Unexpected bound {:?}", bound),
4623 4624 4625 4626
            }
        }
    }
}