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

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

S
Steven Fackler 已提交
14 15 16 17 18
pub use self::Type::*;
pub use self::Mutability::*;
pub use self::ItemEnum::*;
pub use self::SelfTy::*;
pub use self::FunctionRetTy::*;
19
pub use self::Visibility::{Public, Inherited};
S
Steven Fackler 已提交
20

21
use rustc_target::spec::abi::Abi;
W
Without Boats 已提交
22
use syntax;
23
use syntax::ast::{self, AttrStyle, NodeId, Ident};
24
use syntax::attr;
25
use syntax::codemap::{dummy_spanned, Spanned};
26
use syntax::feature_gate::UnstableFeatures;
27
use syntax::ptr::P;
G
Guillaume Gomez 已提交
28
use syntax::symbol::keywords::{self, Keyword};
29
use syntax::symbol::{Symbol, InternedString};
30
use syntax_pos::{self, DUMMY_SP, Pos, FileName};
C
Corey Richardson 已提交
31

32
use rustc::mir::interpret::ConstValue;
M
mitaa 已提交
33
use rustc::middle::privacy::AccessLevels;
34
use rustc::middle::resolve_lifetime as rl;
35
use rustc::ty::fold::TypeFolder;
36
use rustc::middle::lang_items;
37
use rustc::mir::interpret::GlobalId;
38
use rustc::hir::{self, GenericArg, HirVec};
39 40 41
use rustc::hir::def::{self, Def, CtorKind};
use rustc::hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE};
use rustc::hir::def_id::DefIndexAddressSpace;
42
use rustc::ty::subst::Substs;
43
use rustc::ty::{self, TyCtxt, Region, RegionVid, Ty, AdtKind};
44
use rustc::middle::stability;
45
use rustc::util::nodemap::{FxHashMap, FxHashSet};
46
use rustc_typeck::hir_ty_to_ty;
47
use rustc::infer::region_constraints::{RegionConstraintData, Constraint};
48 49
use rustc::lint as lint;

50 51
use std::collections::hash_map::Entry;
use std::fmt;
52
use std::hash::{Hash, Hasher};
53
use std::default::Default;
M
Manish Goregaokar 已提交
54
use std::{mem, slice, vec};
55
use std::iter::{FromIterator, once};
56
use rustc_data_structures::sync::Lrc;
57
use std::rc::Rc;
G
Guillaume Gomez 已提交
58
use std::str::FromStr;
59
use std::cell::RefCell;
M
mitaa 已提交
60
use std::sync::Arc;
61
use std::u32;
62
use std::ops::Range;
63

64
use core::{self, DocContext};
C
Corey Richardson 已提交
65 66
use doctree;
use visit_ast;
G
Guillaume Gomez 已提交
67
use html::render::{cache, ExternalLocation};
68
use html::item_type::ItemType;
69
use html::markdown::markdown_links;
C
Corey Richardson 已提交
70

71
pub mod inline;
K
kennytm 已提交
72
pub mod cfg;
73
mod simplify;
74
mod auto_trait;
75

K
kennytm 已提交
76
use self::cfg::Cfg;
77 78 79 80 81
use self::auto_trait::AutoTraitFinder;

thread_local!(static MAX_DEF_ID: RefCell<FxHashMap<CrateNum, DefId>> = RefCell::new(FxHashMap()));

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

83
// extract the stability index for a node from tcx, if possible
N
Niko Matsakis 已提交
84
fn get_stability(cx: &DocContext, def_id: DefId) -> Option<Stability> {
85
    cx.tcx.lookup_stability(def_id).clean(cx)
86 87
}

88
fn get_deprecation(cx: &DocContext, def_id: DefId) -> Option<Deprecation> {
89
    cx.tcx.lookup_deprecation(def_id).clean(cx)
90 91
}

C
Corey Richardson 已提交
92
pub trait Clean<T> {
93
    fn clean(&self, cx: &DocContext) -> T;
C
Corey Richardson 已提交
94 95
}

96
impl<T: Clean<U>, U> Clean<Vec<U>> for [T] {
97 98
    fn clean(&self, cx: &DocContext) -> Vec<U> {
        self.iter().map(|x| x.clean(cx)).collect()
99 100 101
    }
}

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

108
impl<T: Clean<U>, U> Clean<U> for Rc<T> {
109 110
    fn clean(&self, cx: &DocContext) -> U {
        (**self).clean(cx)
111 112 113
    }
}

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

120 121
impl<T, U> Clean<U> for ty::Binder<T> where T: Clean<U> {
    fn clean(&self, cx: &DocContext) -> U {
122
        self.skip_binder().clean(cx)
123 124 125
    }
}

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

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

Q
cleanup  
QuietMisdreavus 已提交
147
impl<'a, 'tcx, 'rcx> Clean<Crate> for visit_ast::RustdocVisitor<'a, 'tcx, 'rcx> {
148
    fn clean(&self, cx: &DocContext) -> Crate {
M
mitaa 已提交
149
        use ::visit_lib::LibEmbargoVisitor;
150

151 152
        {
            let mut r = cx.renderinfo.borrow_mut();
153 154 155
            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();
156 157
        }

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

166
        // Clean the crate, translating the entire libsyntax AST to one that is
167
        // understood by rustdoc.
168
        let mut module = self.module.clean(cx);
169 170 171 172 173
        let mut masked_crates = FxHashSet();

        match module.inner {
            ModuleItem(ref module) => {
                for it in &module.items {
174
                    if it.is_extern_crate() && it.attrs.has_doc_flag("masked") {
175 176 177 178 179 180
                        masked_crates.insert(it.def_id.krate);
                    }
                }
            }
            _ => unreachable!(),
        }
181

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

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

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

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

A
Ariel Ben-Yehuda 已提交
240
impl Clean<ExternalCrate> for CrateNum {
241
    fn clean(&self, cx: &DocContext) -> ExternalCrate {
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 271 272 273
        let root = DefId { krate: *self, index: CRATE_DEF_INDEX };
        let krate_span = cx.tcx.def_span(root);
        let krate_src = cx.sess().codemap().span_to_filename(krate_span);

        // 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;
                            }
274
                            // FIXME: should warn on unknown primitives?
275 276 277 278 279 280 281 282
                        }
                    }
                }
                return prim.map(|p| (def_id, p, attrs));
            }
            None
        };
        let primitives = if root.is_local() {
283 284
            cx.tcx.hir.krate().module.item_ids.iter().filter_map(|&id| {
                let item = cx.tcx.hir.expect_item(id.id);
285 286
                match item.node {
                    hir::ItemMod(_) => {
287
                        as_primitive(Def::Mod(cx.tcx.hir.local_def_id(id.id)))
288 289
                    }
                    hir::ItemUse(ref path, hir::UseKind::Single)
290
                    if item.vis.node.is_pub() => {
291 292
                        as_primitive(path.def).map(|(_, prim, attrs)| {
                            // Pretend the primitive is local.
293
                            (cx.tcx.hir.local_def_id(id.id), prim, attrs)
294 295 296 297 298 299
                        })
                    }
                    _ => None
                }
            }).collect()
        } else {
300
            cx.tcx.item_children(root).iter().map(|item| item.def)
301 302 303
              .filter_map(as_primitive).collect()
        };

G
Guillaume Gomez 已提交
304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331
        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() {
            cx.tcx.hir.krate().module.item_ids.iter().filter_map(|&id| {
                let item = cx.tcx.hir.expect_item(id.id);
                match item.node {
                    hir::ItemMod(_) => {
                        as_keyword(Def::Mod(cx.tcx.hir.local_def_id(id.id)))
                    }
                    hir::ItemUse(ref path, hir::UseKind::Single)
332
                    if item.vis.node.is_pub() => {
G
Guillaume Gomez 已提交
333 334 335 336 337 338 339 340 341 342 343 344
                        as_keyword(path.def).map(|(_, prim, attrs)| {
                            (cx.tcx.hir.local_def_id(id.id), prim, attrs)
                        })
                    }
                    _ => None
                }
            }).collect()
        } else {
            cx.tcx.item_children(root).iter().map(|item| item.def)
              .filter_map(as_keyword).collect()
        };

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

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

372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391
impl fmt::Debug for Item {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {

        let fake = MAX_DEF_ID.with(|m| m.borrow().get(&self.def_id.krate)
                                   .map(|id| self.def_id >= *id).unwrap_or(false));
        let def_id: &fmt::Debug = if fake { &"**FAKE**" } else { &self.def_id };

        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()
    }
}

392 393 394 395
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> {
396
        self.attrs.doc_value()
397
    }
398 399 400 401 402
    /// 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()
    }
403 404

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

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

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

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

479 480 481
            if s.level == stability::Unstable {
                classes.push("unstable");
            }
482

483 484 485
            if !s.deprecated_since.is_empty() {
                classes.push("deprecated");
            }
486

487 488 489 490
            if classes.len() != 0 {
                Some(classes.join(" "))
            } else {
                None
491
            }
492
        })
493
    }
494 495

    pub fn stable_since(&self) -> Option<&str> {
M
mitaa 已提交
496
        self.stability.as_ref().map(|s| &s.since[..])
497
    }
498 499 500 501 502

    /// Returns a documentation-level item type from the item.
    pub fn type_(&self) -> ItemType {
        ItemType::from(self)
    }
503 504
}

J
Jorge Aparicio 已提交
505
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
506
pub enum ItemEnum {
507 508
    ExternCrateItem(String, Option<String>),
    ImportItem(Import),
C
Corey Richardson 已提交
509
    StructItem(Struct),
V
Vadim Petrochenkov 已提交
510
    UnionItem(Union),
C
Corey Richardson 已提交
511 512 513
    EnumItem(Enum),
    FunctionItem(Function),
    ModuleItem(Module),
514
    TypedefItem(Typedef, bool /* is associated type */),
C
Corey Richardson 已提交
515
    StaticItem(Static),
516
    ConstantItem(Constant),
C
Corey Richardson 已提交
517 518
    TraitItem(Trait),
    ImplItem(Impl),
519 520
    /// A method signature only. Used for required methods in traits (ie,
    /// non-default-methods).
C
Corey Richardson 已提交
521
    TyMethodItem(TyMethod),
522
    /// A method with a body.
C
Corey Richardson 已提交
523
    MethodItem(Method),
524
    StructFieldItem(Type),
C
Corey Richardson 已提交
525
    VariantItem(Variant),
526
    /// `fn`s from an extern block
527
    ForeignFunctionItem(Function),
528
    /// `static`s from an extern block
529
    ForeignStaticItem(Static),
P
Paul Lietar 已提交
530 531
    /// `type`s from an extern block
    ForeignTypeItem,
532
    MacroItem(Macro),
533
    PrimitiveItem(PrimitiveType),
534
    AssociatedConstItem(Type, Option<String>),
V
varkor 已提交
535
    AssociatedTypeItem(Vec<GenericBound>, Option<Type>),
536 537
    /// An item that has been stripped by a rustdoc pass
    StrippedItem(Box<ItemEnum>),
G
Guillaume Gomez 已提交
538
    KeywordItem(String),
C
Corey Richardson 已提交
539 540
}

541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557
impl ItemEnum {
    pub fn generics(&self) -> Option<&Generics> {
        Some(match *self {
            ItemEnum::StructItem(ref s) => &s.generics,
            ItemEnum::EnumItem(ref e) => &e.generics,
            ItemEnum::FunctionItem(ref f) => &f.generics,
            ItemEnum::TypedefItem(ref t, _) => &t.generics,
            ItemEnum::TraitItem(ref t) => &t.generics,
            ItemEnum::ImplItem(ref i) => &i.generics,
            ItemEnum::TyMethodItem(ref i) => &i.generics,
            ItemEnum::MethodItem(ref i) => &i.generics,
            ItemEnum::ForeignFunctionItem(ref f) => &f.generics,
            _ => return None,
        })
    }
}

J
Jorge Aparicio 已提交
558
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
559
pub struct Module {
560 561
    pub items: Vec<Item>,
    pub is_crate: bool,
C
Corey Richardson 已提交
562 563 564
}

impl Clean<Item> for doctree::Module {
565
    fn clean(&self, cx: &DocContext) -> Item {
C
Corey Richardson 已提交
566
        let name = if self.name.is_some() {
567
            self.name.unwrap().clean(cx)
C
Corey Richardson 已提交
568
        } else {
569
            "".to_string()
C
Corey Richardson 已提交
570
        };
571

572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587
        // 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
        let attrs = if self.attrs.iter()
                                 .filter(|a| a.check_name("doc"))
                                 .next()
                                 .map_or(true, |a| a.style == AttrStyle::Inner) {
            // inner doc comment, use the module's own scope for resolution
            cx.mod_ids.borrow_mut().push(self.id);
            self.attrs.clean(cx)
        } else {
            // outer doc comment, use its parent's scope
            let attrs = self.attrs.clean(cx);
            cx.mod_ids.borrow_mut().push(self.id);
            attrs
        };
M
Manish Goregaokar 已提交
588

589 590
        let mut items: Vec<Item> = vec![];
        items.extend(self.extern_crates.iter().map(|x| x.clean(cx)));
591
        items.extend(self.imports.iter().flat_map(|x| x.clean(cx)));
592 593 594
        items.extend(self.structs.iter().flat_map(|x| x.clean(cx)));
        items.extend(self.unions.iter().flat_map(|x| x.clean(cx)));
        items.extend(self.enums.iter().flat_map(|x| x.clean(cx)));
595
        items.extend(self.fns.iter().map(|x| x.clean(cx)));
596
        items.extend(self.foreigns.iter().flat_map(|x| x.clean(cx)));
597 598 599 600 601
        items.extend(self.mods.iter().map(|x| x.clean(cx)));
        items.extend(self.typedefs.iter().map(|x| x.clean(cx)));
        items.extend(self.statics.iter().map(|x| x.clean(cx)));
        items.extend(self.constants.iter().map(|x| x.clean(cx)));
        items.extend(self.traits.iter().map(|x| x.clean(cx)));
602
        items.extend(self.impls.iter().flat_map(|x| x.clean(cx)));
603
        items.extend(self.macros.iter().map(|x| x.clean(cx)));
604

M
Manish Goregaokar 已提交
605 606
        cx.mod_ids.borrow_mut().pop();

607 608
        // determine if we should display the inner contents or
        // the outer `mod` item for the source code.
609
        let whence = {
610
            let cm = cx.sess().codemap();
611 612
            let outer = cm.lookup_char_pos(self.where_outer.lo());
            let inner = cm.lookup_char_pos(self.where_inner.lo());
613 614 615 616 617 618 619 620 621
            if outer.file.start_pos == inner.file.start_pos {
                // mod foo { ... }
                self.where_outer
            } else {
                // mod foo; (and a separate FileMap for the contents)
                self.where_inner
            }
        };

C
Corey Richardson 已提交
622 623
        Item {
            name: Some(name),
624
            attrs,
625 626 627
            source: whence.clean(cx),
            visibility: self.vis.clean(cx),
            stability: self.stab.clean(cx),
628
            deprecation: self.depr.clean(cx),
629
            def_id: cx.tcx.hir.local_def_id(self.id),
C
Corey Richardson 已提交
630
            inner: ModuleItem(Module {
631
               is_crate: self.is_crate,
632
               items,
C
Corey Richardson 已提交
633 634 635 636 637
            })
        }
    }
}

638 639
pub struct ListAttributesIter<'a> {
    attrs: slice::Iter<'a, ast::Attribute>,
640
    current_list: vec::IntoIter<ast::NestedMetaItem>,
641
    name: &'a str
M
mitaa 已提交
642 643
}

644
impl<'a> Iterator for ListAttributesIter<'a> {
645
    type Item = ast::NestedMetaItem;
646 647 648 649

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

652
        for attr in &mut self.attrs {
653
            if let Some(list) = attr.meta_item_list() {
654
                if attr.check_name(self.name) {
655
                    self.current_list = list.into_iter();
656 657 658
                    if let Some(nested) = self.current_list.next() {
                        return Some(nested);
                    }
M
mitaa 已提交
659 660 661
                }
            }
        }
662

M
mitaa 已提交
663 664
        None
    }
665 666 667 668 669

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

672
pub trait AttributesExt {
M
mitaa 已提交
673
    /// Finds an attribute as List and returns the list of attributes nested inside.
E
est31 已提交
674
    fn lists<'a>(&'a self, name: &'a str) -> ListAttributesIter<'a>;
675 676 677 678 679 680
}

impl AttributesExt for [ast::Attribute] {
    fn lists<'a>(&'a self, name: &'a str) -> ListAttributesIter<'a> {
        ListAttributesIter {
            attrs: self.iter(),
681
            current_list: Vec::new().into_iter(),
682
            name,
M
mitaa 已提交
683 684 685 686
        }
    }
}

687 688
pub trait NestedAttributesExt {
    /// Returns whether the attribute list contains a specific `Word`
E
est31 已提交
689
    fn has_word(self, word: &str) -> bool;
690 691
}

692
impl<I: IntoIterator<Item=ast::NestedMetaItem>> NestedAttributesExt for I {
693 694 695 696 697
    fn has_word(self, word: &str) -> bool {
        self.into_iter().any(|attr| attr.is_word() && attr.check_name(word))
    }
}

698 699 700 701 702 703 704 705
/// 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.
706
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)]
707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 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
pub enum DocFragment {
    // FIXME #44229 (misdreavus): sugared and raw doc comments can be brought back together once
    // hoedown is completely removed from rustdoc.
    /// 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
        })
    }
}

758
#[derive(Clone, RustcEncodable, RustcDecodable, Debug, Default)]
759
pub struct Attributes {
760
    pub doc_strings: Vec<DocFragment>,
761
    pub other_attrs: Vec<ast::Attribute>,
J
John Kåre Alsaker 已提交
762
    pub cfg: Option<Arc<Cfg>>,
763
    pub span: Option<syntax_pos::Span>,
M
Manish Goregaokar 已提交
764
    /// map from Rust paths to resolved defs and potential URL fragments
G
Guillaume Gomez 已提交
765
    pub links: Vec<(String, Option<DefId>, Option<String>)>,
766 767 768
}

impl Attributes {
K
kennytm 已提交
769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791
    /// Extracts the content from an attribute `#[doc(cfg(content))]`.
    fn extract_cfg(mi: &ast::MetaItem) -> Option<&ast::MetaItem> {
        use syntax::ast::NestedMetaItemKind::MetaItem;

        if let ast::MetaItemKind::List(ref nmis) = mi.node {
            if nmis.len() == 1 {
                if let MetaItem(ref cfg_mi) = nmis[0].node {
                    if cfg_mi.check_name("cfg") {
                        if let ast::MetaItemKind::List(ref cfg_nmis) = cfg_mi.node {
                            if cfg_nmis.len() == 1 {
                                if let MetaItem(ref content_mi) = cfg_nmis[0].node {
                                    return Some(content_mi);
                                }
                            }
                        }
                    }
                }
            }
        }

        None
    }

792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832
    /// 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
        })
    }

833
    pub fn has_doc_flag(&self, flag: &str) -> bool {
834 835 836 837
        for attr in &self.other_attrs {
            if !attr.check_name("doc") { continue; }

            if let Some(items) = attr.meta_item_list() {
838
                if items.iter().filter_map(|i| i.meta_item()).any(|it| it.check_name(flag)) {
839 840 841 842 843 844 845 846
                    return true;
                }
            }
        }

        false
    }

847 848
    pub fn from_ast(diagnostic: &::errors::Handler,
                    attrs: &[ast::Attribute]) -> Attributes {
849
        let mut doc_strings = vec![];
850
        let mut sp = None;
K
kennytm 已提交
851
        let mut cfg = Cfg::True;
852
        let mut doc_line = 0;
K
kennytm 已提交
853

854 855
        let other_attrs = attrs.iter().filter_map(|attr| {
            attr.with_desugared_doc(|attr| {
K
kennytm 已提交
856 857 858 859
                if attr.check_name("doc") {
                    if let Some(mi) = attr.meta() {
                        if let Some(value) = mi.value_str() {
                            // Extracted #[doc = "..."]
860 861 862 863 864 865 866 867 868 869
                            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 已提交
870 871 872 873 874 875 876 877 878 879 880
                            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;
881 882 883 884 885 886 887 888
                        } 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));
889
                        }
890 891 892 893 894
                    }
                }
                Some(attr.clone())
            })
        }).collect();
895

896 897 898 899 900
        // 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() {
901 902
                    let meta = attr::mk_name_value_item_str(Ident::from_str("target_feature"),
                                                            dummy_spanned(feat));
903 904 905 906 907 908 909
                    if let Ok(feat_cfg) = Cfg::parse(&meta) {
                        cfg &= feat_cfg;
                    }
                }
            }
        }

910
        Attributes {
K
kennytm 已提交
911 912
            doc_strings,
            other_attrs,
J
John Kåre Alsaker 已提交
913
            cfg: if cfg == Cfg::True { None } else { Some(Arc::new(cfg)) },
914
            span: sp,
915
            links: vec![],
916 917
        }
    }
918 919 920 921

    /// Finds the `doc` attribute as a NameValue and returns the corresponding
    /// value found.
    pub fn doc_value<'a>(&'a self) -> Option<&'a str> {
922 923 924 925 926 927 928 929 930 931 932
        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
        }
933
    }
934 935 936 937

    /// Get links as a vector
    ///
    /// Cache must be populated before call
G
Guillaume Gomez 已提交
938
    pub fn links(&self, krate: &CrateNum) -> Vec<(String, String)> {
939
        use html::format::href;
M
Manish Goregaokar 已提交
940
        self.links.iter().filter_map(|&(ref s, did, ref fragment)| {
G
Guillaume Gomez 已提交
941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971
            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".
                        Some((s.clone(),
                              format!("{}{}std/primitive.{}.html",
                                      url,
                                      if !url.ends_with('/') { "/" } else { "" },
                                      fragment)))
                    } else {
                        panic!("This isn't a primitive?!");
                    }
M
Manish Goregaokar 已提交
972
                }
973 974 975
            }
        }).collect()
    }
C
Corey Richardson 已提交
976 977
}

978 979 980 981 982 983
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 &&
984
        self.other_attrs.iter().map(|attr| attr.id).eq(rhs.other_attrs.iter().map(|attr| attr.id))
985 986 987 988 989
    }
}

impl Eq for Attributes {}

990 991 992 993 994 995 996 997 998 999 1000 1001
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);
        }
    }
}

1002 1003 1004
impl AttributesExt for Attributes {
    fn lists<'a>(&'a self, name: &'a str) -> ListAttributesIter<'a> {
        self.other_attrs.lists(name)
C
Corey Richardson 已提交
1005 1006 1007
    }
}

1008 1009 1010 1011 1012 1013 1014
/// Given a def, returns its name and disambiguator
/// for a value namespace
///
/// Returns None for things which cannot be ambiguous since
/// they exist in both namespaces (structs and modules)
fn value_ns_kind(def: Def, path_str: &str) -> Option<(&'static str, String)> {
    match def {
M
Manish Goregaokar 已提交
1015 1016
        // structs, variants, and mods exist in both namespaces. skip them
        Def::StructCtor(..) | Def::Mod(..) | Def::Variant(..) | Def::VariantCtor(..) => None,
1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042
        Def::Fn(..)
            => Some(("function", format!("{}()", path_str))),
        Def::Method(..)
            => Some(("method", format!("{}()", path_str))),
        Def::Const(..)
            => Some(("const", format!("const@{}", path_str))),
        Def::Static(..)
            => Some(("static", format!("static@{}", path_str))),
        _ => Some(("value", format!("value@{}", path_str))),
    }
}

/// Given a def, returns its name, the article to be used, and a disambiguator
/// for the type namespace
fn type_ns_kind(def: Def, path_str: &str) -> (&'static str, &'static str, String) {
    let (kind, article) = match def {
        // we can still have non-tuple structs
        Def::Struct(..) => ("struct", "a"),
        Def::Enum(..) => ("enum", "an"),
        Def::Trait(..) => ("trait", "a"),
        Def::Union(..) => ("union", "a"),
        _ => ("type", "a"),
    };
    (kind, article, format!("{}@{}", kind, path_str))
}

1043 1044 1045 1046 1047 1048 1049 1050 1051
fn span_of_attrs(attrs: &Attributes) -> syntax_pos::Span {
    if attrs.doc_strings.is_empty() {
        return DUMMY_SP;
    }
    let start = attrs.doc_strings[0].span();
    let end = attrs.doc_strings.last().unwrap().span();
    start.to(end)
}

1052 1053 1054 1055
fn ambiguity_error(cx: &DocContext, attrs: &Attributes,
                   path_str: &str,
                   article1: &str, kind1: &str, disambig1: &str,
                   article2: &str, kind2: &str, disambig2: &str) {
1056
    let sp = span_of_attrs(attrs);
1057
    cx.sess()
M
Manish Goregaokar 已提交
1058 1059 1060 1061
      .struct_span_warn(sp,
                        &format!("`{}` is both {} {} and {} {}",
                                 path_str, article1, kind1,
                                 article2, kind2))
1062 1063 1064
      .help(&format!("try `{}` if you want to select the {}, \
                      or `{}` if you want to \
                      select the {}",
1065 1066
                      disambig1, kind1, disambig2,
                      kind2))
1067
      .emit();
1068 1069
}

M
Manish Goregaokar 已提交
1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083
/// Given an enum variant's def, return the def of its enum and the associated fragment
fn handle_variant(cx: &DocContext, def: Def) -> Result<(Def, Option<String>), ()> {
    use rustc::ty::DefIdTree;

    let parent = if let Some(parent) = cx.tcx.parent(def.def_id()) {
        parent
    } else {
        return Err(())
    };
    let parent_def = Def::Enum(parent);
    let variant = cx.tcx.expect_variant_def(def);
    Ok((parent_def, Some(format!("{}.v", variant.name))))
}

G
Guillaume Gomez 已提交
1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111
const PRIMITIVES: &[(&str, Def)] = &[
    ("u8",    Def::PrimTy(hir::PrimTy::TyUint(syntax::ast::UintTy::U8))),
    ("u16",   Def::PrimTy(hir::PrimTy::TyUint(syntax::ast::UintTy::U16))),
    ("u32",   Def::PrimTy(hir::PrimTy::TyUint(syntax::ast::UintTy::U32))),
    ("u64",   Def::PrimTy(hir::PrimTy::TyUint(syntax::ast::UintTy::U64))),
    ("u128",  Def::PrimTy(hir::PrimTy::TyUint(syntax::ast::UintTy::U128))),
    ("usize", Def::PrimTy(hir::PrimTy::TyUint(syntax::ast::UintTy::Usize))),
    ("i8",    Def::PrimTy(hir::PrimTy::TyInt(syntax::ast::IntTy::I8))),
    ("i16",   Def::PrimTy(hir::PrimTy::TyInt(syntax::ast::IntTy::I16))),
    ("i32",   Def::PrimTy(hir::PrimTy::TyInt(syntax::ast::IntTy::I32))),
    ("i64",   Def::PrimTy(hir::PrimTy::TyInt(syntax::ast::IntTy::I64))),
    ("i128",  Def::PrimTy(hir::PrimTy::TyInt(syntax::ast::IntTy::I128))),
    ("isize", Def::PrimTy(hir::PrimTy::TyInt(syntax::ast::IntTy::Isize))),
    ("f32",   Def::PrimTy(hir::PrimTy::TyFloat(syntax::ast::FloatTy::F32))),
    ("f64",   Def::PrimTy(hir::PrimTy::TyFloat(syntax::ast::FloatTy::F64))),
    ("str",   Def::PrimTy(hir::PrimTy::TyStr)),
    ("bool",  Def::PrimTy(hir::PrimTy::TyBool)),
    ("char",  Def::PrimTy(hir::PrimTy::TyChar)),
];

fn is_primitive(path_str: &str, is_val: bool) -> Option<Def> {
    if is_val {
        None
    } else {
        PRIMITIVES.iter().find(|x| x.0 == path_str).map(|x| x.1)
    }
}

1112
/// Resolve a given string as a path, along with whether or not it is
M
Manish Goregaokar 已提交
1113 1114 1115
/// in the value namespace. Also returns an optional URL fragment in the case
/// of variants and methods
fn resolve(cx: &DocContext, path_str: &str, is_val: bool) -> Result<(Def, Option<String>), ()> {
1116 1117 1118
    // In case we're in a module, try to resolve the relative
    // path
    if let Some(id) = cx.mod_ids.borrow().last() {
M
Manish Goregaokar 已提交
1119 1120 1121 1122 1123 1124 1125
        let result = cx.resolver.borrow_mut()
                                .with_scope(*id,
            |resolver| {
                resolver.resolve_str_path_error(DUMMY_SP,
                                                &path_str, is_val)
        });

M
Manish Goregaokar 已提交
1126 1127 1128 1129 1130
        if let Ok(result) = result {
            // In case this is a trait item, skip the
            // early return and try looking for the trait
            let value = match result.def {
                Def::Method(_) | Def::AssociatedConst(_) => true,
1131
                Def::AssociatedTy(_) => false,
M
Manish Goregaokar 已提交
1132
                Def::Variant(_) => return handle_variant(cx, result.def),
M
Manish Goregaokar 已提交
1133 1134 1135 1136 1137 1138 1139
                // not a trait item, just return what we found
                _ => return Ok((result.def, None))
            };

            if value != is_val {
                return Err(())
            }
G
Guillaume Gomez 已提交
1140 1141
        } else if let Some(prim) = is_primitive(path_str, is_val) {
            return Ok((prim, Some(path_str.to_owned())))
M
Manish Goregaokar 已提交
1142 1143 1144 1145 1146 1147 1148
        } else {
            // If resolution failed, it may still be a method
            // because methods are not handled by the resolver
            // If so, bail when we're not looking for a value
            if !is_val {
                return Err(())
            }
M
Manish Goregaokar 已提交
1149 1150
        }

M
Manish Goregaokar 已提交
1151
        // Try looking for methods and associated items
M
Manish Goregaokar 已提交
1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167
        let mut split = path_str.rsplitn(2, "::");
        let mut item_name = if let Some(first) = split.next() {
            first
        } else {
            return Err(())
        };

        let mut path = if let Some(second) = split.next() {
            second
        } else {
            return Err(())
        };

        let ty = cx.resolver.borrow_mut()
                            .with_scope(*id,
            |resolver| {
1168
                resolver.resolve_str_path_error(DUMMY_SP, &path, false)
M
Manish Goregaokar 已提交
1169 1170 1171 1172 1173
        })?;
        match ty.def {
            Def::Struct(did) | Def::Union(did) | Def::Enum(did) | Def::TyAlias(did) => {
                let item = cx.tcx.inherent_impls(did).iter()
                                 .flat_map(|imp| cx.tcx.associated_items(*imp))
1174
                                 .find(|item| item.ident.name == item_name);
M
Manish Goregaokar 已提交
1175
                if let Some(item) = item {
1176 1177 1178 1179 1180 1181
                    let out = match item.kind {
                        ty::AssociatedKind::Method if is_val => "method",
                        ty::AssociatedKind::Const if is_val => "associatedconstant",
                        _ => return Err(())
                    };
                    Ok((ty.def, Some(format!("{}.{}", out, item_name))))
M
Manish Goregaokar 已提交
1182
                } else {
1183 1184 1185 1186 1187
                    let is_enum = match ty.def {
                        Def::Enum(_) => true,
                        _ => false,
                    };
                    let elem = if is_enum {
1188
                        cx.tcx.adt_def(did).all_fields().find(|item| item.ident.name == item_name)
1189 1190 1191 1192 1193
                    } else {
                        cx.tcx.adt_def(did)
                              .non_enum_variant()
                              .fields
                              .iter()
1194
                              .find(|item| item.ident.name == item_name)
1195 1196 1197 1198 1199
                    };
                    if let Some(item) = elem {
                        Ok((ty.def,
                            Some(format!("{}.{}",
                                         if is_enum { "variant" } else { "structfield" },
1200
                                         item.ident))))
1201 1202 1203
                    } else {
                        Err(())
                    }
M
Manish Goregaokar 已提交
1204 1205
                }
            }
M
Manish Goregaokar 已提交
1206 1207 1208
            Def::Trait(did) => {
                let item = cx.tcx.associated_item_def_ids(did).iter()
                             .map(|item| cx.tcx.associated_item(*item))
1209
                             .find(|item| item.ident.name == item_name);
M
Manish Goregaokar 已提交
1210 1211 1212 1213
                if let Some(item) = item {
                    let kind = match item.kind {
                        ty::AssociatedKind::Const if is_val => "associatedconstant",
                        ty::AssociatedKind::Type if !is_val => "associatedtype",
1214 1215 1216 1217 1218 1219 1220
                        ty::AssociatedKind::Method if is_val => {
                            if item.defaultness.has_value() {
                                "method"
                            } else {
                                "tymethod"
                            }
                        }
M
Manish Goregaokar 已提交
1221 1222 1223 1224 1225 1226 1227
                        _ => return Err(())
                    };

                    Ok((ty.def, Some(format!("{}.{}", kind, item_name))))
                } else {
                    Err(())
                }
M
Manish Goregaokar 已提交
1228 1229 1230
            }
            _ => Err(())
        }
1231
    } else {
1232
        Err(())
1233 1234 1235
    }
}

1236 1237
/// Resolve a string as a macro
fn macro_resolve(cx: &DocContext, path_str: &str) -> Option<Def> {
1238
    use syntax::ext::base::{MacroKind, SyntaxExtension};
1239
    use syntax::ext::hygiene::Mark;
1240
    let segment = ast::PathSegment::from_ident(Ident::from_str(path_str));
1241
    let path = ast::Path { segments: vec![segment], span: DUMMY_SP };
1242 1243 1244 1245 1246
    let mut resolver = cx.resolver.borrow_mut();
    let mark = Mark::root();
    let res = resolver
        .resolve_macro_to_def_inner(mark, &path, MacroKind::Bang, false);
    if let Ok(def) = res {
1247
        if let SyntaxExtension::DeclMacro { .. } = *resolver.get_macro(def) {
1248 1249 1250 1251
            Some(def)
        } else {
            None
        }
1252
    } else if let Some(def) = resolver.all_macros.get(&Symbol::intern(path_str)) {
1253 1254 1255 1256 1257 1258
        Some(*def)
    } else {
        None
    }
}

1259
#[derive(Debug)]
M
Manish Goregaokar 已提交
1260 1261 1262 1263 1264 1265 1266 1267
enum PathKind {
    /// can be either value or type, not a macro
    Unknown,
    /// macro
    Macro,
    /// values, functions, consts, statics, everything in the value namespace
    Value,
    /// types, traits, everything in the type namespace
1268
    Type,
M
Manish Goregaokar 已提交
1269
}
1270

1271 1272 1273 1274 1275 1276 1277
fn resolution_failure(
    cx: &DocContext,
    attrs: &Attributes,
    path_str: &str,
    dox: &str,
    link_range: Option<Range<usize>>,
) {
1278
    let sp = span_of_attrs(attrs);
1279
    let msg = format!("`[{}]` cannot be resolved, ignoring it...", path_str);
1280

1281 1282 1283 1284
    let code_dox = sp.to_src(cx);

    let doc_comment_padding = 3;
    let mut diag = if let Some(link_range) = link_range {
1285 1286 1287 1288 1289
        // blah blah blah\nblah\nblah [blah] blah blah\nblah blah
        //                       ^    ~~~~~~
        //                       |    link_range
        //                       last_new_line_offset

1290 1291 1292
        let mut diag;
        if dox.lines().count() == code_dox.lines().count() {
            let line_offset = dox[..link_range.start].lines().count();
1293
            // The span starts in the `///`, so we don't have to account for the leading whitespace
1294 1295 1296 1297 1298 1299 1300 1301 1302 1303
            let code_dox_len = if line_offset <= 1 {
                doc_comment_padding
            } else {
                // The first `///`
                doc_comment_padding +
                    // Each subsequent leading whitespace and `///`
                    code_dox.lines().skip(1).take(line_offset - 1).fold(0, |sum, line| {
                        sum + doc_comment_padding + line.len() - line.trim().len()
                    })
            };
1304

1305
            // Extract the specific span
1306 1307 1308 1309
            let sp = sp.from_inner_byte_pos(
                link_range.start + code_dox_len,
                link_range.end + code_dox_len,
            );
1310

G
Guillaume Gomez 已提交
1311
            diag = cx.tcx.struct_span_lint_node(lint::builtin::INTRA_DOC_LINK_RESOLUTION_FAILURE,
1312 1313 1314
                                                NodeId::new(0),
                                                sp,
                                                &msg);
1315 1316
            diag.span_label(sp, "cannot be resolved, ignoring");
        } else {
G
Guillaume Gomez 已提交
1317
            diag = cx.tcx.struct_span_lint_node(lint::builtin::INTRA_DOC_LINK_RESOLUTION_FAILURE,
1318 1319 1320
                                                NodeId::new(0),
                                                sp,
                                                &msg);
1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334

            let last_new_line_offset = dox[..link_range.start].rfind('\n').map_or(0, |n| n + 1);
            let line = dox[last_new_line_offset..].lines().next().unwrap_or("");

            // Print the line containing the `link_range` and manually mark it with '^'s
            diag.note(&format!(
                "the link appears in this line:\n\n{line}\n\
                 {indicator: <before$}{indicator:^<found$}",
                line=line,
                indicator="",
                before=link_range.start - last_new_line_offset,
                found=link_range.len(),
            ));
        }
1335 1336
        diag
    } else {
G
Guillaume Gomez 已提交
1337
        cx.tcx.struct_span_lint_node(lint::builtin::INTRA_DOC_LINK_RESOLUTION_FAILURE,
G
Guillaume Gomez 已提交
1338 1339 1340
                                     NodeId::new(0),
                                     sp,
                                     &msg)
1341
    };
1342 1343
    diag.help("to escape `[` and `]` characters, just add '\\' before them like \
               `\\[` or `\\]`");
1344
    diag.emit();
1345 1346
}

1347
impl Clean<Attributes> for [ast::Attribute] {
K
kennytm 已提交
1348
    fn clean(&self, cx: &DocContext) -> Attributes {
1349 1350 1351 1352
        let mut attrs = Attributes::from_ast(cx.sess().diagnostic(), self);

        if UnstableFeatures::from_environment().is_nightly_build() {
            let dox = attrs.collapsed_doc_value().unwrap_or_else(String::new);
1353
            for (ori_link, link_range) in markdown_links(&dox) {
1354
                // bail early for real links
1355
                if ori_link.contains('/') {
1356 1357
                    continue;
                }
1358 1359
                let link = ori_link.replace("`", "");
                let (def, fragment) = {
M
Manish Goregaokar 已提交
1360
                    let mut kind = PathKind::Unknown;
Q
QuietMisdreavus 已提交
1361
                    let path_str = if let Some(prefix) =
1362 1363
                        ["struct@", "enum@", "type@",
                         "trait@", "union@"].iter()
M
Manish Goregaokar 已提交
1364
                                          .find(|p| link.starts_with(**p)) {
M
Manish Goregaokar 已提交
1365
                        kind = PathKind::Type;
1366
                        link.trim_left_matches(prefix)
Q
QuietMisdreavus 已提交
1367
                    } else if let Some(prefix) =
1368
                        ["const@", "static@",
M
Manish Goregaokar 已提交
1369 1370
                         "value@", "function@", "mod@",
                         "fn@", "module@", "method@"]
1371
                            .iter().find(|p| link.starts_with(**p)) {
M
Manish Goregaokar 已提交
1372
                        kind = PathKind::Value;
1373
                        link.trim_left_matches(prefix)
Q
QuietMisdreavus 已提交
1374
                    } else if link.ends_with("()") {
M
Manish Goregaokar 已提交
1375
                        kind = PathKind::Value;
1376
                        link.trim_right_matches("()")
1377 1378 1379
                    } else if link.starts_with("macro@") {
                        kind = PathKind::Macro;
                        link.trim_left_matches("macro@")
M
Manish Goregaokar 已提交
1380 1381
                    } else if link.ends_with('!') {
                        kind = PathKind::Macro;
1382
                        link.trim_right_matches('!')
Q
QuietMisdreavus 已提交
1383
                    } else {
1384 1385
                        &link[..]
                    }.trim();
Q
QuietMisdreavus 已提交
1386

M
Manish Goregaokar 已提交
1387 1388
                    if path_str.contains(|ch: char| !(ch.is_alphanumeric() ||
                                                      ch == ':' || ch == '_')) {
1389 1390 1391
                        continue;
                    }

M
Manish Goregaokar 已提交
1392 1393
                    match kind {
                        PathKind::Value => {
M
Manish Goregaokar 已提交
1394 1395
                            if let Ok(def) = resolve(cx, path_str, true) {
                                def
M
Manish Goregaokar 已提交
1396
                            } else {
1397
                                resolution_failure(cx, &attrs, path_str, &dox, link_range);
M
Manish Goregaokar 已提交
1398 1399 1400 1401 1402
                                // this could just be a normal link or a broken link
                                // we could potentially check if something is
                                // "intra-doc-link-like" and warn in that case
                                continue;
                            }
1403
                        }
M
Manish Goregaokar 已提交
1404
                        PathKind::Type => {
M
Manish Goregaokar 已提交
1405 1406
                            if let Ok(def) = resolve(cx, path_str, false) {
                                def
M
Manish Goregaokar 已提交
1407
                            } else {
1408
                                resolution_failure(cx, &attrs, path_str, &dox, link_range);
M
Manish Goregaokar 已提交
1409 1410 1411 1412 1413
                                // this could just be a normal link
                                continue;
                            }
                        }
                        PathKind::Unknown => {
1414
                            // try everything!
1415
                            if let Some(macro_def) = macro_resolve(cx, path_str) {
M
Manish Goregaokar 已提交
1416
                                if let Ok(type_def) = resolve(cx, path_str, false) {
1417
                                    let (type_kind, article, type_disambig)
M
Manish Goregaokar 已提交
1418
                                        = type_ns_kind(type_def.0, path_str);
1419 1420 1421 1422
                                    ambiguity_error(cx, &attrs, path_str,
                                                    article, type_kind, &type_disambig,
                                                    "a", "macro", &format!("macro@{}", path_str));
                                    continue;
M
Manish Goregaokar 已提交
1423
                                } else if let Ok(value_def) = resolve(cx, path_str, true) {
1424
                                    let (value_kind, value_disambig)
M
Manish Goregaokar 已提交
1425
                                        = value_ns_kind(value_def.0, path_str)
1426 1427 1428 1429 1430 1431
                                            .expect("struct and mod cases should have been \
                                                     caught in previous branch");
                                    ambiguity_error(cx, &attrs, path_str,
                                                    "a", value_kind, &value_disambig,
                                                    "a", "macro", &format!("macro@{}", path_str));
                                }
M
Manish Goregaokar 已提交
1432
                                (macro_def, None)
M
Manish Goregaokar 已提交
1433
                            } else if let Ok(type_def) = resolve(cx, path_str, false) {
1434 1435 1436
                                // It is imperative we search for not-a-value first
                                // Otherwise we will find struct ctors for when we are looking
                                // for structs, and the link won't work.
1437
                                // if there is something in both namespaces
M
Manish Goregaokar 已提交
1438
                                if let Ok(value_def) = resolve(cx, path_str, true) {
M
Manish Goregaokar 已提交
1439
                                    let kind = value_ns_kind(value_def.0, path_str);
1440 1441
                                    if let Some((value_kind, value_disambig)) = kind {
                                        let (type_kind, article, type_disambig)
M
Manish Goregaokar 已提交
1442
                                            = type_ns_kind(type_def.0, path_str);
1443 1444 1445
                                        ambiguity_error(cx, &attrs, path_str,
                                                        article, type_kind, &type_disambig,
                                                        "a", value_kind, &value_disambig);
1446 1447 1448
                                        continue;
                                    }
                                }
M
Manish Goregaokar 已提交
1449 1450 1451
                                type_def
                            } else if let Ok(value_def) = resolve(cx, path_str, true) {
                                value_def
M
Manish Goregaokar 已提交
1452
                            } else {
1453
                                resolution_failure(cx, &attrs, path_str, &dox, link_range);
M
Manish Goregaokar 已提交
1454 1455 1456 1457 1458
                                // this could just be a normal link
                                continue;
                            }
                        }
                        PathKind::Macro => {
1459
                            if let Some(def) = macro_resolve(cx, path_str) {
M
Manish Goregaokar 已提交
1460
                                (def, None)
M
Manish Goregaokar 已提交
1461
                            } else {
1462
                                resolution_failure(cx, &attrs, path_str, &dox, link_range);
1463
                                continue
M
Manish Goregaokar 已提交
1464
                            }
1465 1466
                        }
                    }
1467 1468
                };

G
Guillaume Gomez 已提交
1469 1470 1471 1472 1473 1474
                if let Def::PrimTy(_) = def {
                    attrs.links.push((ori_link, None, fragment));
                } else {
                    let id = register_def(cx, def);
                    attrs.links.push((ori_link, Some(id), fragment));
                }
1475
            }
1476 1477

            cx.sess().abort_if_errors();
1478 1479 1480
        }

        attrs
C
Corey Richardson 已提交
1481 1482 1483
    }
}

1484
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)]
V
varkor 已提交
1485
pub enum GenericBound {
V
varkor 已提交
1486 1487
    TraitBound(PolyTrait, hir::TraitBoundModifier),
    Outlives(Lifetime),
C
Corey Richardson 已提交
1488 1489
}

V
varkor 已提交
1490 1491
impl GenericBound {
    fn maybe_sized(cx: &DocContext) -> GenericBound {
1492
        let did = cx.tcx.require_lang_item(lang_items::SizedTraitLangItem);
1493
        let empty = cx.tcx.intern_substs(&[]);
1494
        let path = external_path(cx, &cx.tcx.item_name(did).as_str(),
1495 1496
            Some(did), false, vec![], empty);
        inline::record_extern_fqn(cx, did, TypeKind::Trait);
V
varkor 已提交
1497
        GenericBound::TraitBound(PolyTrait {
1498
            trait_: ResolvedPath {
1499
                path,
1500
                typarams: None,
1501
                did,
1502 1503
                is_generic: false,
            },
1504
            generic_params: Vec::new(),
1505
        }, hir::TraitBoundModifier::Maybe)
1506 1507 1508
    }

    fn is_sized_bound(&self, cx: &DocContext) -> bool {
1509
        use rustc::hir::TraitBoundModifier as TBM;
V
varkor 已提交
1510
        if let GenericBound::TraitBound(PolyTrait { ref trait_, .. }, TBM::None) = *self {
1511
            if trait_.def_id() == cx.tcx.lang_items().sized_trait() {
1512
                return true;
1513 1514 1515 1516
            }
        }
        false
    }
1517 1518

    fn get_poly_trait(&self) -> Option<PolyTrait> {
V
varkor 已提交
1519
        if let GenericBound::TraitBound(ref p, _) = *self {
1520 1521 1522 1523 1524 1525 1526
            return Some(p.clone())
        }
        None
    }

    fn get_trait_type(&self) -> Option<Type> {

V
varkor 已提交
1527
        if let GenericBound::TraitBound(PolyTrait { ref trait_, .. }, _) = *self {
1528 1529 1530 1531
            return Some(trait_.clone());
        }
        None
    }
1532 1533
}

V
varkor 已提交
1534 1535
impl Clean<GenericBound> for hir::GenericBound {
    fn clean(&self, cx: &DocContext) -> GenericBound {
C
Corey Richardson 已提交
1536
        match *self {
V
varkor 已提交
1537 1538 1539 1540
            hir::GenericBound::Outlives(lt) => GenericBound::Outlives(lt.clean(cx)),
            hir::GenericBound::Trait(ref t, modifier) => {
                GenericBound::TraitBound(t.clean(cx), modifier)
            }
C
Corey Richardson 已提交
1541 1542 1543 1544
        }
    }
}

1545 1546
fn external_generic_args(cx: &DocContext, trait_did: Option<DefId>, has_self: bool,
                        bindings: Vec<TypeBinding>, substs: &Substs) -> GenericArgs {
1547
    let lifetimes = substs.regions().filter_map(|v| v.clean(cx)).collect();
1548
    let types = substs.types().skip(has_self as usize).collect::<Vec<_>>();
1549

1550
    match trait_did {
1551
        // Attempt to sugar an external path like Fn<(A, B,), C> to Fn(A, B) -> C
1552
        Some(did) if cx.tcx.lang_items().fn_trait_kind(did).is_some() => {
1553
            assert_eq!(types.len(), 1);
1554
            let inputs = match types[0].sty {
A
Andrew Cann 已提交
1555
                ty::TyTuple(ref tys) => tys.iter().map(|t| t.clean(cx)).collect(),
1556
                _ => {
1557
                    return GenericArgs::AngleBracketed {
1558
                        lifetimes,
1559
                        types: types.clean(cx),
1560
                        bindings,
1561 1562 1563
                    }
                }
            };
1564 1565 1566
            let output = None;
            // FIXME(#20299) return type comes from a projection now
            // match types[1].sty {
A
Andrew Cann 已提交
1567
            //     ty::TyTuple(ref v) if v.is_empty() => None, // -> ()
1568 1569
            //     _ => Some(types[1].clean(cx))
            // };
1570
            GenericArgs::Parenthesized {
1571 1572
                inputs,
                output,
1573 1574
            }
        },
1575
        _ => {
1576
            GenericArgs::AngleBracketed {
1577
                lifetimes,
1578
                types: types.clean(cx),
1579
                bindings,
1580 1581 1582 1583 1584 1585 1586
            }
        }
    }
}

// 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
1587
fn external_path(cx: &DocContext, name: &str, trait_did: Option<DefId>, has_self: bool,
1588
                 bindings: Vec<TypeBinding>, substs: &Substs) -> Path {
1589 1590
    Path {
        global: false,
1591
        def: Def::Err,
1592
        segments: vec![PathSegment {
1593
            name: name.to_string(),
V
varkor 已提交
1594
            args: external_generic_args(cx, trait_did, has_self, bindings, substs)
1595
        }],
1596 1597 1598
    }
}

V
varkor 已提交
1599 1600
impl<'a, 'tcx> Clean<GenericBound> for (&'a ty::TraitRef<'tcx>, Vec<TypeBinding>) {
    fn clean(&self, cx: &DocContext) -> GenericBound {
1601 1602
        let (trait_ref, ref bounds) = *self;
        inline::record_extern_fqn(cx, trait_ref.def_id, TypeKind::Trait);
1603
        let path = external_path(cx, &cx.tcx.item_name(trait_ref.def_id).as_str(),
1604
                                 Some(trait_ref.def_id), true, bounds.clone(), trait_ref.substs);
1605

1606
        debug!("ty::TraitRef\n  subst: {:?}\n", trait_ref.substs);
1607 1608 1609

        // collect any late bound regions
        let mut late_bounds = vec![];
1610
        for ty_s in trait_ref.input_types().skip(1) {
A
Andrew Cann 已提交
1611
            if let ty::TyTuple(ts) = ty_s.sty {
1612
                for &ty_s in ts {
1613
                    if let ty::TyRef(ref reg, _, _) = ty_s.sty {
N
Niko Matsakis 已提交
1614
                        if let &ty::RegionKind::ReLateBound(..) = *reg {
1615
                            debug!("  hit an ReLateBound {:?}", reg);
1616 1617 1618 1619 1620
                            if let Some(Lifetime(name)) = reg.clean(cx) {
                                late_bounds.push(GenericParamDef {
                                    name,
                                    kind: GenericParamDefKind::Lifetime,
                                });
1621 1622 1623 1624 1625 1626 1627
                            }
                        }
                    }
                }
            }
        }

V
varkor 已提交
1628
        GenericBound::TraitBound(
1629 1630
            PolyTrait {
                trait_: ResolvedPath {
1631
                    path,
1632
                    typarams: None,
1633
                    did: trait_ref.def_id,
1634 1635
                    is_generic: false,
                },
1636
                generic_params: late_bounds,
1637
            },
1638 1639
            hir::TraitBoundModifier::None
        )
1640 1641 1642
    }
}

V
varkor 已提交
1643 1644
impl<'tcx> Clean<GenericBound> for ty::TraitRef<'tcx> {
    fn clean(&self, cx: &DocContext) -> GenericBound {
1645 1646 1647 1648
        (self, vec![]).clean(cx)
    }
}

V
varkor 已提交
1649 1650
impl<'tcx> Clean<Option<Vec<GenericBound>>> for Substs<'tcx> {
    fn clean(&self, cx: &DocContext) -> Option<Vec<GenericBound>> {
1651
        let mut v = Vec::new();
V
varkor 已提交
1652 1653
        v.extend(self.regions().filter_map(|r| r.clean(cx)).map(GenericBound::Outlives));
        v.extend(self.types().map(|t| GenericBound::TraitBound(PolyTrait {
1654
            trait_: t.clean(cx),
1655
            generic_params: Vec::new(),
1656
        }, hir::TraitBoundModifier::None)));
1657
        if !v.is_empty() {Some(v)} else {None}
1658 1659 1660
    }
}

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

1664 1665 1666
impl Lifetime {
    pub fn get_ref<'a>(&'a self) -> &'a str {
        let Lifetime(ref s) = *self;
1667
        let s: &'a str = s;
C
Corey Farwell 已提交
1668
        s
1669
    }
1670 1671 1672 1673

    pub fn statik() -> Lifetime {
        Lifetime("'static".to_string())
    }
1674 1675
}

1676
impl Clean<Lifetime> for hir::Lifetime {
E
Eduard Burtescu 已提交
1677
    fn clean(&self, cx: &DocContext) -> Lifetime {
1678 1679 1680 1681 1682 1683 1684 1685 1686 1687
        if self.id != ast::DUMMY_NODE_ID {
            let hir_id = cx.tcx.hir.node_to_hir_id(self.id);
            let def = cx.tcx.named_region(hir_id);
            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 已提交
1688
                }
1689
                _ => {}
E
Eduard Burtescu 已提交
1690 1691
            }
        }
1692
        Lifetime(self.name.ident().to_string())
C
Corey Richardson 已提交
1693 1694 1695
    }
}

V
varkor 已提交
1696
impl Clean<Lifetime> for hir::GenericParam {
1697
    fn clean(&self, _: &DocContext) -> Lifetime {
V
varkor 已提交
1698
        match self.kind {
V
varkor 已提交
1699 1700 1701
            hir::GenericParamKind::Lifetime { .. } => {
                if self.bounds.len() > 0 {
                    let mut bounds = self.bounds.iter().map(|bound| match bound {
V
varkor 已提交
1702
                        hir::GenericBound::Outlives(lt) => lt,
V
varkor 已提交
1703 1704
                        _ => panic!(),
                    });
1705 1706
                    let name = bounds.next().unwrap().name.ident();
                    let mut s = format!("{}: {}", self.name.ident(), name);
V
varkor 已提交
1707
                    for bound in bounds {
1708
                        s.push_str(&format!(" + {}", bound.name.ident()));
V
varkor 已提交
1709 1710 1711
                    }
                    Lifetime(s)
                } else {
1712
                    Lifetime(self.name.ident().to_string())
V
varkor 已提交
1713
                }
1714
            }
V
varkor 已提交
1715
            _ => panic!(),
1716
        }
1717 1718 1719
    }
}

1720 1721
impl<'tcx> Clean<Lifetime> for ty::GenericParamDef {
    fn clean(&self, _cx: &DocContext) -> Lifetime {
1722
        Lifetime(self.name.to_string())
1723 1724 1725
    }
}

1726
impl Clean<Option<Lifetime>> for ty::RegionKind {
1727
    fn clean(&self, cx: &DocContext) -> Option<Lifetime> {
1728
        match *self {
1729
            ty::ReStatic => Some(Lifetime::statik()),
1730
            ty::ReLateBound(_, ty::BrNamed(_, name)) => Some(Lifetime(name.to_string())),
N
Niko Matsakis 已提交
1731
            ty::ReEarlyBound(ref data) => Some(Lifetime(data.name.clean(cx))),
1732 1733 1734 1735

            ty::ReLateBound(..) |
            ty::ReFree(..) |
            ty::ReScope(..) |
1736 1737
            ty::ReVar(..) |
            ty::ReSkolemized(..) |
1738
            ty::ReEmpty |
1739
            ty::ReClosureBound(_) |
1740
            ty::ReCanonical(_) |
1741
            ty::ReErased => None
1742 1743 1744 1745
        }
    }
}

1746
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)]
1747
pub enum WherePredicate {
V
varkor 已提交
1748 1749
    BoundPredicate { ty: Type, bounds: Vec<GenericBound> },
    RegionPredicate { lifetime: Lifetime, bounds: Vec<GenericBound> },
1750
    EqPredicate { lhs: Type, rhs: Type },
1751 1752
}

1753
impl Clean<WherePredicate> for hir::WherePredicate {
1754
    fn clean(&self, cx: &DocContext) -> WherePredicate {
N
Nick Cameron 已提交
1755
        match *self {
1756
            hir::WherePredicate::BoundPredicate(ref wbp) => {
1757
                WherePredicate::BoundPredicate {
1758
                    ty: wbp.bounded_ty.clean(cx),
N
Nick Cameron 已提交
1759 1760 1761
                    bounds: wbp.bounds.clean(cx)
                }
            }
1762

1763
            hir::WherePredicate::RegionPredicate(ref wrp) => {
1764 1765 1766 1767 1768 1769
                WherePredicate::RegionPredicate {
                    lifetime: wrp.lifetime.clean(cx),
                    bounds: wrp.bounds.clean(cx)
                }
            }

1770 1771 1772 1773 1774
            hir::WherePredicate::EqPredicate(ref wrp) => {
                WherePredicate::EqPredicate {
                    lhs: wrp.lhs_ty.clean(cx),
                    rhs: wrp.rhs_ty.clean(cx)
                }
N
Nick Cameron 已提交
1775
            }
1776 1777 1778 1779
        }
    }
}

1780 1781
impl<'a> Clean<WherePredicate> for ty::Predicate<'a> {
    fn clean(&self, cx: &DocContext) -> WherePredicate {
1782
        use rustc::ty::Predicate;
1783 1784 1785

        match *self {
            Predicate::Trait(ref pred) => pred.clean(cx),
N
Niko Matsakis 已提交
1786
            Predicate::Subtype(ref pred) => pred.clean(cx),
1787 1788
            Predicate::RegionOutlives(ref pred) => pred.clean(cx),
            Predicate::TypeOutlives(ref pred) => pred.clean(cx),
1789 1790 1791
            Predicate::Projection(ref pred) => pred.clean(cx),
            Predicate::WellFormed(_) => panic!("not user writable"),
            Predicate::ObjectSafe(_) => panic!("not user writable"),
1792
            Predicate::ClosureKind(..) => panic!("not user writable"),
1793
            Predicate::ConstEvaluatable(..) => panic!("not user writable"),
1794 1795 1796 1797 1798 1799 1800
        }
    }
}

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

N
Niko Matsakis 已提交
1807
impl<'tcx> Clean<WherePredicate> for ty::SubtypePredicate<'tcx> {
1808 1809 1810
    fn clean(&self, _cx: &DocContext) -> WherePredicate {
        panic!("subtype predicates are an internal rustc artifact \
                and should not be seen by rustdoc")
N
Niko Matsakis 已提交
1811 1812 1813
    }
}

N
Niko Matsakis 已提交
1814
impl<'tcx> Clean<WherePredicate> for ty::OutlivesPredicate<ty::Region<'tcx>, ty::Region<'tcx>> {
1815 1816 1817 1818
    fn clean(&self, cx: &DocContext) -> WherePredicate {
        let ty::OutlivesPredicate(ref a, ref b) = *self;
        WherePredicate::RegionPredicate {
            lifetime: a.clean(cx).unwrap(),
V
varkor 已提交
1819
            bounds: vec![GenericBound::Outlives(b.clean(cx).unwrap())]
1820 1821 1822 1823
        }
    }
}

D
Douglas Campos 已提交
1824
impl<'tcx> Clean<WherePredicate> for ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>> {
1825 1826 1827 1828 1829
    fn clean(&self, cx: &DocContext) -> WherePredicate {
        let ty::OutlivesPredicate(ref ty, ref lt) = *self;

        WherePredicate::BoundPredicate {
            ty: ty.clean(cx),
V
varkor 已提交
1830
            bounds: vec![GenericBound::Outlives(lt.clean(cx).unwrap())]
1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845
        }
    }
}

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

impl<'tcx> Clean<Type> for ty::ProjectionTy<'tcx> {
    fn clean(&self, cx: &DocContext) -> Type {
1846
        let trait_ = match self.trait_ref(cx.tcx).clean(cx) {
V
varkor 已提交
1847 1848
            GenericBound::TraitBound(t, _) => t.trait_,
            GenericBound::Outlives(_) => panic!("cleaning a trait got a lifetime"),
1849 1850
        };
        Type::QPath {
1851
            name: cx.tcx.associated_item(self.item_def_id).ident.name.clean(cx),
1852
            self_type: box self.self_ty().clean(cx),
1853 1854 1855 1856 1857
            trait_: box trait_
        }
    }
}

V
Vadim Petrochenkov 已提交
1858
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)]
1859 1860 1861 1862
pub enum GenericParamDefKind {
    Lifetime,
    Type {
        did: DefId,
V
varkor 已提交
1863
        bounds: Vec<GenericBound>,
1864 1865 1866 1867 1868 1869 1870 1871 1872 1873
        default: Option<Type>,
        synthetic: Option<hir::SyntheticTyParamKind>,
    },
}

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

    pub kind: GenericParamDefKind,
1874 1875
}

V
varkor 已提交
1876
impl GenericParamDef {
1877
    pub fn is_synthetic_type_param(&self) -> bool {
1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910
        match self.kind {
            GenericParamDefKind::Lifetime => false,
            GenericParamDefKind::Type { ref synthetic, .. } => synthetic.is_some(),
        }
    }
}

impl<'tcx> Clean<GenericParamDef> for ty::GenericParamDef {
    fn clean(&self, cx: &DocContext) -> GenericParamDef {
        let (name, kind) = match self.kind {
            ty::GenericParamDefKind::Lifetime => {
                (self.name.to_string(), GenericParamDefKind::Lifetime)
            }
            ty::GenericParamDefKind::Type { has_default, .. } => {
                cx.renderinfo.borrow_mut().external_typarams
                             .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,
                })
            }
        };

        GenericParamDef {
            name,
            kind,
1911 1912 1913 1914
        }
    }
}

V
varkor 已提交
1915 1916
impl Clean<GenericParamDef> for hir::GenericParam {
    fn clean(&self, cx: &DocContext) -> GenericParamDef {
1917
        let (name, kind) = match self.kind {
V
varkor 已提交
1918 1919 1920
            hir::GenericParamKind::Lifetime { .. } => {
                let name = if self.bounds.len() > 0 {
                    let mut bounds = self.bounds.iter().map(|bound| match bound {
V
varkor 已提交
1921
                        hir::GenericBound::Outlives(lt) => lt,
V
varkor 已提交
1922 1923
                        _ => panic!(),
                    });
V
Vadim Petrochenkov 已提交
1924 1925
                    let name = bounds.next().unwrap().name.ident();
                    let mut s = format!("{}: {}", self.name.ident(), name);
V
varkor 已提交
1926
                    for bound in bounds {
V
Vadim Petrochenkov 已提交
1927
                        s.push_str(&format!(" + {}", bound.name.ident()));
1928 1929 1930
                    }
                    s
                } else {
V
Vadim Petrochenkov 已提交
1931
                    self.name.ident().to_string()
1932 1933 1934
                };
                (name, GenericParamDefKind::Lifetime)
            }
V
varkor 已提交
1935
            hir::GenericParamKind::Type { ref default, synthetic, .. } => {
V
Vadim Petrochenkov 已提交
1936
                (self.name.ident().name.clean(cx), GenericParamDefKind::Type {
1937
                    did: cx.tcx.hir.local_def_id(self.id),
V
varkor 已提交
1938
                    bounds: self.bounds.clean(cx),
1939 1940 1941
                    default: default.clean(cx),
                    synthetic: synthetic,
                })
V
varkor 已提交
1942
            }
1943 1944 1945 1946 1947
        };

        GenericParamDef {
            name,
            kind,
1948 1949 1950 1951
        }
    }
}

1952 1953
// maybe use a Generic enum and use Vec<Generic>?
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Default, Hash)]
C
Corey Richardson 已提交
1954
pub struct Generics {
V
varkor 已提交
1955
    pub params: Vec<GenericParamDef>,
1956
    pub where_predicates: Vec<WherePredicate>,
1957
}
C
Corey Richardson 已提交
1958

1959
impl Clean<Generics> for hir::Generics {
1960
    fn clean(&self, cx: &DocContext) -> Generics {
1961 1962 1963 1964
        // 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 已提交
1965 1966 1967 1968 1969
            match param.kind {
                hir::GenericParamKind::Type { synthetic, .. } => {
                    synthetic == Some(hir::SyntheticTyParamKind::ImplTrait)
                }
                _ => false,
1970 1971 1972 1973
            }
        }
        let impl_trait_params = self.params
            .iter()
1974 1975 1976 1977 1978 1979 1980 1981
            .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());
                    }
1982
                }
1983
                param
1984 1985 1986
            })
            .collect::<Vec<_>>();

1987
        let mut params = Vec::with_capacity(self.params.len());
1988
        for p in self.params.iter().filter(|p| !is_impl_trait(p)) {
1989 1990 1991
            let p = p.clean(cx);
            params.push(p);
        }
1992 1993
        params.extend(impl_trait_params);

1994
        let mut generics = Generics {
1995
            params,
1996
            where_predicates: self.where_clause.predicates.clean(cx),
1997 1998 1999 2000 2001
        };

        // 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.
2002
        for where_pred in &mut generics.where_predicates {
2003 2004 2005
            match *where_pred {
                WherePredicate::BoundPredicate { ty: Generic(ref name), ref mut bounds } => {
                    if bounds.is_empty() {
2006 2007 2008 2009 2010 2011 2012 2013
                        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
                                    }
2014
                                }
2015 2016 2017 2018 2019 2020
                            }
                        }
                    }
                }
                _ => continue,
            }
C
Corey Richardson 已提交
2021
        }
2022
        generics
C
Corey Richardson 已提交
2023 2024 2025
    }
}

2026
impl<'a, 'tcx> Clean<Generics> for (&'a ty::Generics,
2027
                                    &'a ty::GenericPredicates<'tcx>) {
2028
    fn clean(&self, cx: &DocContext) -> Generics {
2029 2030
        use self::WherePredicate as WP;

2031
        let (gens, preds) = *self;
2032

2033 2034 2035
        // Bounds in the type_params and lifetimes fields are repeated in the
        // predicates field (see rustc_typeck::collect::ty_generics), so remove
        // them.
2036 2037 2038
        let stripped_typarams = gens.params.iter().filter_map(|param| match param.kind {
            ty::GenericParamDefKind::Lifetime => None,
            ty::GenericParamDefKind::Type { .. } => {
2039 2040
                if param.name == keywords::SelfType.name().as_str() {
                    assert_eq!(param.index, 0);
2041
                    return None;
V
varkor 已提交
2042
                }
2043
                Some(param.clean(cx))
2044
            }
2045
        }).collect::<Vec<GenericParamDef>>();
2046

2047
        let mut where_predicates = preds.predicates.to_vec().clean(cx);
2048

2049
        // Type parameters and have a Sized bound by default unless removed with
2050
        // ?Sized. Scan through the predicates and mark any type parameter with
2051
        // a Sized bound, removing the bounds as we find them.
2052 2053
        //
        // Note that associated types also have a sized bound by default, but we
2054
        // don't actually know the set of associated types right here so that's
2055
        // handled in cleaning associated types
2056
        let mut sized_params = FxHashSet();
2057 2058 2059 2060 2061 2062 2063 2064 2065
        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
                    }
2066
                }
2067
                _ => true,
2068
            }
2069
        });
2070

2071
        // Run through the type parameters again and insert a ?Sized
2072
        // unbound for any we didn't find to be Sized.
2073
        for tp in &stripped_typarams {
2074 2075 2076
            if !sized_params.contains(&tp.name) {
                where_predicates.push(WP::BoundPredicate {
                    ty: Type::Generic(tp.name.clone()),
V
varkor 已提交
2077
                    bounds: vec![GenericBound::maybe_sized(cx)],
2078 2079 2080 2081 2082 2083 2084 2085
                })
            }
        }

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

2086
        Generics {
V
varkor 已提交
2087 2088
            params: gens.params
                        .iter()
2089
                        .flat_map(|param| match param.kind {
2090
                            ty::GenericParamDefKind::Lifetime => Some(param.clean(cx)),
2091
                            ty::GenericParamDefKind::Type { .. } => None,
2092
                        }).chain(simplify::ty_params(stripped_typarams).into_iter())
V
varkor 已提交
2093
                        .collect(),
2094
            where_predicates: simplify::where_clauses(cx, where_predicates),
2095 2096 2097 2098
        }
    }
}

J
Jorge Aparicio 已提交
2099
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
2100
pub struct Method {
2101 2102
    pub generics: Generics,
    pub decl: FnDecl,
W
Without Boats 已提交
2103
    pub header: hir::FnHeader,
C
Corey Richardson 已提交
2104 2105
}

S
Sunjay Varma 已提交
2106
impl<'a> Clean<Method> for (&'a hir::MethodSig, &'a hir::Generics, hir::BodyId) {
2107
    fn clean(&self, cx: &DocContext) -> Method {
2108 2109 2110
        let (generics, decl) = enter_impl_trait(cx, || {
            (self.1.clean(cx), (&*self.0.decl, self.2).clean(cx))
        });
2111
        Method {
2112
            decl,
2113
            generics,
W
Without Boats 已提交
2114
            header: self.0.header,
C
Corey Richardson 已提交
2115 2116 2117 2118
        }
    }
}

J
Jorge Aparicio 已提交
2119
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
2120
pub struct TyMethod {
W
Without Boats 已提交
2121
    pub header: hir::FnHeader,
2122 2123
    pub decl: FnDecl,
    pub generics: Generics,
C
Corey Richardson 已提交
2124 2125
}

J
Jorge Aparicio 已提交
2126
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
2127
pub struct Function {
2128 2129
    pub decl: FnDecl,
    pub generics: Generics,
W
Without Boats 已提交
2130
    pub header: hir::FnHeader,
C
Corey Richardson 已提交
2131 2132 2133
}

impl Clean<Item> for doctree::Function {
2134
    fn clean(&self, cx: &DocContext) -> Item {
2135 2136 2137
        let (generics, decl) = enter_impl_trait(cx, || {
            (self.generics.clean(cx), (&self.decl, self.body).clean(cx))
        });
C
Corey Richardson 已提交
2138
        Item {
2139 2140 2141 2142 2143
            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),
2144
            deprecation: self.depr.clean(cx),
2145
            def_id: cx.tcx.hir.local_def_id(self.id),
C
Corey Richardson 已提交
2146
            inner: FunctionItem(Function {
2147 2148
                decl,
                generics,
W
Without Boats 已提交
2149
                header: self.header,
C
Corey Richardson 已提交
2150 2151 2152 2153 2154
            }),
        }
    }
}

2155
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)]
C
Corey Richardson 已提交
2156
pub struct FnDecl {
2157
    pub inputs: Arguments,
2158
    pub output: FunctionRetTy,
2159
    pub variadic: bool,
2160
    pub attrs: Attributes,
2161
}
C
Corey Richardson 已提交
2162

2163 2164
impl FnDecl {
    pub fn has_self(&self) -> bool {
C
Corey Farwell 已提交
2165
        self.inputs.values.len() > 0 && self.inputs.values[0].name == "self"
2166
    }
2167 2168 2169 2170

    pub fn self_type(&self) -> Option<SelfTy> {
        self.inputs.values.get(0).and_then(|v| v.to_self())
    }
2171 2172
}

2173
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)]
2174
pub struct Arguments {
2175
    pub values: Vec<Argument>,
2176 2177
}

2178
impl<'a> Clean<Arguments> for (&'a [hir::Ty], &'a [ast::Ident]) {
2179 2180 2181
    fn clean(&self, cx: &DocContext) -> Arguments {
        Arguments {
            values: self.0.iter().enumerate().map(|(i, ty)| {
2182
                let mut name = self.1.get(i).map(|ident| ident.to_string())
2183 2184 2185 2186 2187
                                            .unwrap_or(String::new());
                if name.is_empty() {
                    name = "_".to_string();
                }
                Argument {
2188
                    name,
2189 2190 2191 2192 2193 2194 2195
                    type_: ty.clean(cx),
                }
            }).collect()
        }
    }
}

O
Oliver Schneider 已提交
2196
impl<'a> Clean<Arguments> for (&'a [hir::Ty], hir::BodyId) {
2197
    fn clean(&self, cx: &DocContext) -> Arguments {
2198
        let body = cx.tcx.hir.body(self.1);
2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211

        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 已提交
2212
    where (&'a [hir::Ty], A): Clean<Arguments>
2213
{
2214
    fn clean(&self, cx: &DocContext) -> FnDecl {
C
Corey Richardson 已提交
2215
        FnDecl {
2216 2217 2218
            inputs: (&self.0.inputs[..], self.1).clean(cx),
            output: self.0.output.clean(cx),
            variadic: self.0.variadic,
2219
            attrs: Attributes::default()
C
Corey Richardson 已提交
2220 2221 2222 2223
        }
    }
}

2224
impl<'a, 'tcx> Clean<FnDecl> for (DefId, ty::PolyFnSig<'tcx>) {
2225
    fn clean(&self, cx: &DocContext) -> FnDecl {
2226
        let (did, sig) = *self;
2227
        let mut names = if cx.tcx.hir.as_local_node_id(did).is_some() {
2228
            vec![].into_iter()
2229
        } else {
A
achernyak 已提交
2230
            cx.tcx.fn_arg_names(did).into_iter()
S
Cleanup  
Shotaro Yamada 已提交
2231 2232
        };

2233
        FnDecl {
2234
            output: Return(sig.skip_binder().output().clean(cx)),
2235
            attrs: Attributes::default(),
2236
            variadic: sig.skip_binder().variadic,
2237
            inputs: Arguments {
2238
                values: sig.skip_binder().inputs().iter().map(|t| {
2239
                    Argument {
2240
                        type_: t.clean(cx),
2241
                        name: names.next().map_or("".to_string(), |name| name.to_string()),
2242 2243 2244 2245 2246 2247 2248
                    }
                }).collect(),
            },
        }
    }
}

2249
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)]
C
Corey Richardson 已提交
2250
pub struct Argument {
2251
    pub type_: Type,
2252
    pub name: String,
C
Corey Richardson 已提交
2253 2254
}

2255 2256 2257 2258 2259 2260 2261 2262 2263
#[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> {
2264 2265 2266 2267 2268 2269 2270 2271 2272
        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))
2273
            }
2274
            _ => Some(SelfExplicit(self.type_.clone()))
2275 2276 2277 2278
        }
    }
}

2279
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)]
2280 2281
pub enum FunctionRetTy {
    Return(Type),
2282
    DefaultReturn,
C
Corey Richardson 已提交
2283 2284
}

2285
impl Clean<FunctionRetTy> for hir::FunctionRetTy {
2286
    fn clean(&self, cx: &DocContext) -> FunctionRetTy {
C
Corey Richardson 已提交
2287
        match *self {
2288 2289
            hir::Return(ref typ) => Return(typ.clean(cx)),
            hir::DefaultReturn(..) => DefaultReturn,
C
Corey Richardson 已提交
2290 2291 2292 2293
        }
    }
}

2294 2295 2296 2297 2298 2299 2300 2301 2302
impl GetDefId for FunctionRetTy {
    fn def_id(&self) -> Option<DefId> {
        match *self {
            Return(ref ty) => ty.def_id(),
            DefaultReturn => None,
        }
    }
}

J
Jorge Aparicio 已提交
2303
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
2304
pub struct Trait {
2305
    pub auto: bool,
2306
    pub unsafety: hir::Unsafety,
2307
    pub items: Vec<Item>,
2308
    pub generics: Generics,
V
varkor 已提交
2309
    pub bounds: Vec<GenericBound>,
2310
    pub is_spotlight: bool,
2311
    pub is_auto: bool,
C
Corey Richardson 已提交
2312 2313 2314
}

impl Clean<Item> for doctree::Trait {
2315
    fn clean(&self, cx: &DocContext) -> Item {
2316 2317
        let attrs = self.attrs.clean(cx);
        let is_spotlight = attrs.has_doc_flag("spotlight");
C
Corey Richardson 已提交
2318
        Item {
2319
            name: Some(self.name.clean(cx)),
2320
            attrs: attrs,
2321
            source: self.whence.clean(cx),
2322
            def_id: cx.tcx.hir.local_def_id(self.id),
2323 2324
            visibility: self.vis.clean(cx),
            stability: self.stab.clean(cx),
2325
            deprecation: self.depr.clean(cx),
C
Corey Richardson 已提交
2326
            inner: TraitItem(Trait {
2327
                auto: self.is_auto.clean(cx),
2328
                unsafety: self.unsafety,
2329 2330 2331
                items: self.items.clean(cx),
                generics: self.generics.clean(cx),
                bounds: self.bounds.clean(cx),
2332
                is_spotlight: is_spotlight,
2333
                is_auto: self.is_auto.clean(cx),
C
Corey Richardson 已提交
2334 2335 2336 2337 2338
            }),
        }
    }
}

2339 2340 2341 2342 2343 2344 2345 2346 2347
impl Clean<bool> for hir::IsAuto {
    fn clean(&self, _: &DocContext) -> bool {
        match *self {
            hir::IsAuto::Yes => true,
            hir::IsAuto::No => false,
        }
    }
}

2348
impl Clean<Type> for hir::TraitRef {
2349
    fn clean(&self, cx: &DocContext) -> Type {
N
Niko Matsakis 已提交
2350
        resolve_type(cx, self.path.clean(cx), self.ref_id)
C
Corey Richardson 已提交
2351 2352 2353
    }
}

2354
impl Clean<PolyTrait> for hir::PolyTraitRef {
2355 2356 2357
    fn clean(&self, cx: &DocContext) -> PolyTrait {
        PolyTrait {
            trait_: self.trait_ref.clean(cx),
2358
            generic_params: self.bound_generic_params.clean(cx)
2359
        }
N
Niko Matsakis 已提交
2360 2361 2362
    }
}

2363
impl Clean<Item> for hir::TraitItem {
2364 2365
    fn clean(&self, cx: &DocContext) -> Item {
        let inner = match self.node {
2366
            hir::TraitItemKind::Const(ref ty, default) => {
2367
                AssociatedConstItem(ty.clean(cx),
2368
                                    default.map(|e| print_const_expr(cx, e)))
2369
            }
2370
            hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Provided(body)) => {
S
Sunjay Varma 已提交
2371
                MethodItem((sig, &self.generics, body).clean(cx))
2372
            }
2373
            hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Required(ref names)) => {
2374 2375 2376
                let (generics, decl) = enter_impl_trait(cx, || {
                    (self.generics.clean(cx), (&*sig.decl, &names[..]).clean(cx))
                });
2377
                TyMethodItem(TyMethod {
W
Without Boats 已提交
2378
                    header: sig.header,
2379
                    decl,
2380
                    generics,
2381
                })
2382
            }
2383
            hir::TraitItemKind::Type(ref bounds, ref default) => {
2384 2385 2386 2387
                AssociatedTypeItem(bounds.clean(cx), default.clean(cx))
            }
        };
        Item {
2388
            name: Some(self.ident.name.clean(cx)),
2389 2390
            attrs: self.attrs.clean(cx),
            source: self.span.clean(cx),
2391
            def_id: cx.tcx.hir.local_def_id(self.id),
2392
            visibility: None,
2393 2394
            stability: get_stability(cx, cx.tcx.hir.local_def_id(self.id)),
            deprecation: get_deprecation(cx, cx.tcx.hir.local_def_id(self.id)),
2395
            inner,
2396 2397 2398 2399
        }
    }
}

2400
impl Clean<Item> for hir::ImplItem {
2401 2402
    fn clean(&self, cx: &DocContext) -> Item {
        let inner = match self.node {
2403
            hir::ImplItemKind::Const(ref ty, expr) => {
2404
                AssociatedConstItem(ty.clean(cx),
2405
                                    Some(print_const_expr(cx, expr)))
2406
            }
2407
            hir::ImplItemKind::Method(ref sig, body) => {
S
Sunjay Varma 已提交
2408
                MethodItem((sig, &self.generics, body).clean(cx))
2409
            }
2410
            hir::ImplItemKind::Type(ref ty) => TypedefItem(Typedef {
2411
                type_: ty.clean(cx),
2412
                generics: Generics::default(),
2413
            }, true),
2414 2415
        };
        Item {
2416
            name: Some(self.ident.name.clean(cx)),
2417 2418
            source: self.span.clean(cx),
            attrs: self.attrs.clean(cx),
2419
            def_id: cx.tcx.hir.local_def_id(self.id),
2420
            visibility: self.vis.clean(cx),
2421 2422
            stability: get_stability(cx, cx.tcx.hir.local_def_id(self.id)),
            deprecation: get_deprecation(cx, cx.tcx.hir.local_def_id(self.id)),
2423
            inner,
C
Corey Richardson 已提交
2424 2425 2426 2427
        }
    }
}

2428
impl<'tcx> Clean<Item> for ty::AssociatedItem {
2429
    fn clean(&self, cx: &DocContext) -> Item {
2430 2431
        let inner = match self.kind {
            ty::AssociatedKind::Const => {
2432
                let ty = cx.tcx.type_of(self.def_id);
2433 2434 2435 2436 2437 2438
                let default = if self.defaultness.has_value() {
                    Some(inline::print_inlined_const(cx, self.def_id))
                } else {
                    None
                };
                AssociatedConstItem(ty.clean(cx), default)
2439
            }
2440
            ty::AssociatedKind::Method => {
2441 2442
                let generics = (cx.tcx.generics_of(self.def_id),
                                &cx.tcx.predicates_of(self.def_id)).clean(cx);
2443
                let sig = cx.tcx.fn_sig(self.def_id);
2444
                let mut decl = (self.def_id, sig).clean(cx);
2445 2446 2447 2448

                if self.method_has_self_argument {
                    let self_ty = match self.container {
                        ty::ImplContainer(def_id) => {
2449
                            cx.tcx.type_of(def_id)
2450
                        }
2451
                        ty::TraitContainer(_) => cx.tcx.mk_self_type()
2452
                    };
2453
                    let self_arg_ty = *sig.input(0).skip_binder();
2454
                    if self_arg_ty == self_ty {
2455
                        decl.inputs.values[0].type_ = Generic(String::from("Self"));
2456 2457
                    } else if let ty::TyRef(_, ty, _) = self_arg_ty.sty {
                        if ty == self_ty {
2458
                            match decl.inputs.values[0].type_ {
2459 2460 2461
                                BorrowedRef{ref mut type_, ..} => {
                                    **type_ = Generic(String::from("Self"))
                                }
2462 2463 2464 2465 2466
                                _ => unreachable!(),
                            }
                        }
                    }
                }
2467

2468
                let provided = match self.container {
2469
                    ty::ImplContainer(_) => true,
2470
                    ty::TraitContainer(_) => self.defaultness.has_value()
2471 2472
                };
                if provided {
2473 2474 2475 2476 2477
                    let constness = if cx.tcx.is_const_fn(self.def_id) {
                        hir::Constness::Const
                    } else {
                        hir::Constness::NotConst
                    };
2478
                    MethodItem(Method {
2479 2480
                        generics,
                        decl,
W
Without Boats 已提交
2481 2482 2483 2484
                        header: hir::FnHeader {
                            unsafety: sig.unsafety(),
                            abi: sig.abi(),
                            constness,
2485
                            asyncness: hir::IsAsync::NotAsync,
W
Without Boats 已提交
2486
                        }
2487 2488 2489
                    })
                } else {
                    TyMethodItem(TyMethod {
2490 2491
                        generics,
                        decl,
W
Without Boats 已提交
2492 2493 2494
                        header: hir::FnHeader {
                            unsafety: sig.unsafety(),
                            abi: sig.abi(),
2495 2496
                            constness: hir::Constness::NotConst,
                            asyncness: hir::IsAsync::NotAsync,
W
Without Boats 已提交
2497
                        }
2498
                    })
2499 2500
                }
            }
2501
            ty::AssociatedKind::Type => {
2502
                let my_name = self.ident.name.clean(cx);
2503

2504
                if let ty::TraitContainer(did) = self.container {
2505 2506 2507 2508
                    // 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.
2509 2510
                    let predicates = cx.tcx.predicates_of(did);
                    let generics = (cx.tcx.generics_of(did), &predicates).clean(cx);
2511
                    let mut bounds = generics.where_predicates.iter().filter_map(|pred| {
2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528
                        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)
2529 2530 2531 2532 2533 2534 2535 2536
                    }).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 已提交
2537
                        None => bounds.push(GenericBound::maybe_sized(cx)),
2538
                    }
2539

2540 2541 2542 2543 2544
                    let ty = if self.defaultness.has_value() {
                        Some(cx.tcx.type_of(self.def_id))
                    } else {
                        None
                    };
2545

2546
                    AssociatedTypeItem(bounds, ty.clean(cx))
2547
                } else {
2548 2549 2550
                    TypedefItem(Typedef {
                        type_: cx.tcx.type_of(self.def_id).clean(cx),
                        generics: Generics {
2551
                            params: Vec::new(),
2552 2553 2554 2555
                            where_predicates: Vec::new(),
                        },
                    }, true)
                }
2556 2557 2558
            }
        };

2559 2560 2561 2562 2563
        let visibility = match self.container {
            ty::ImplContainer(_) => self.vis.clean(cx),
            ty::TraitContainer(_) => None,
        };

2564
        Item {
2565
            name: Some(self.ident.name.clean(cx)),
2566
            visibility,
2567
            stability: get_stability(cx, self.def_id),
2568
            deprecation: get_deprecation(cx, self.def_id),
2569
            def_id: self.def_id,
2570
            attrs: inline::load_attrs(cx, self.def_id),
2571
            source: cx.tcx.def_span(self.def_id).clean(cx),
2572
            inner,
2573
        }
2574 2575 2576
    }
}

2577
/// A trait reference, which may have higher ranked lifetimes.
2578
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)]
2579 2580
pub struct PolyTrait {
    pub trait_: Type,
V
varkor 已提交
2581
    pub generic_params: Vec<GenericParamDef>,
2582 2583
}

C
Corey Richardson 已提交
2584
/// A representation of a Type suitable for hyperlinking purposes. Ideally one can get the original
2585
/// type out of the AST/TyCtxt given one of these, if more information is needed. Most importantly
C
Corey Richardson 已提交
2586
/// it does not preserve mutability or boxes.
2587
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)]
C
Corey Richardson 已提交
2588
pub enum Type {
C
TyKind  
csmoe 已提交
2589
    /// structs/enums/traits (most that'd be an hir::TyKind::Path)
2590
    ResolvedPath {
S
Steven Fackler 已提交
2591
        path: Path,
V
varkor 已提交
2592
        typarams: Option<Vec<GenericBound>>,
N
Niko Matsakis 已提交
2593
        did: DefId,
2594 2595
        /// true if is a `T::Name` path for associated types
        is_generic: bool,
2596
    },
2597 2598 2599
    /// For parameterized types, so the consumer of the JSON don't go
    /// looking for types which don't exist anywhere.
    Generic(String),
2600
    /// Primitives are the fixed-size numeric types (plus int/usize/float), char,
2601
    /// arrays, slices, and tuples.
2602
    Primitive(PrimitiveType),
C
Corey Richardson 已提交
2603
    /// extern "ABI" fn
2604
    BareFunction(Box<BareFunctionDecl>),
2605
    Tuple(Vec<Type>),
2606
    Slice(Box<Type>),
2607
    Array(Box<Type>, String),
A
Andrew Cann 已提交
2608
    Never,
2609 2610
    Unique(Box<Type>),
    RawPointer(Mutability, Box<Type>),
2611
    BorrowedRef {
S
Steven Fackler 已提交
2612 2613 2614
        lifetime: Option<Lifetime>,
        mutability: Mutability,
        type_: Box<Type>,
2615
    },
2616 2617

    // <Type as Trait>::Name
T
Tom Jakubowski 已提交
2618 2619 2620 2621 2622
    QPath {
        name: String,
        self_type: Box<Type>,
        trait_: Box<Type>
    },
2623 2624 2625 2626

    // _
    Infer,

2627
    // impl TraitA+TraitB
V
varkor 已提交
2628
    ImplTrait(Vec<GenericBound>),
C
Corey Richardson 已提交
2629 2630
}

J
Jorge Aparicio 已提交
2631
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Copy, Debug)]
2632
pub enum PrimitiveType {
2633 2634
    Isize, I8, I16, I32, I64, I128,
    Usize, U8, U16, U32, U64, U128,
2635
    F32, F64,
2636 2637 2638 2639
    Char,
    Bool,
    Str,
    Slice,
2640
    Array,
2641
    Tuple,
2642
    Unit,
2643
    RawPointer,
2644
    Reference,
2645
    Fn,
A
Andrew Cann 已提交
2646
    Never,
2647 2648
}

J
Jorge Aparicio 已提交
2649
#[derive(Clone, RustcEncodable, RustcDecodable, Copy, Debug)]
2650
pub enum TypeKind {
2651 2652 2653 2654 2655 2656 2657 2658 2659 2660
    Enum,
    Function,
    Module,
    Const,
    Static,
    Struct,
    Union,
    Trait,
    Variant,
    Typedef,
P
Paul Lietar 已提交
2661
    Foreign,
M
Manish Goregaokar 已提交
2662
    Macro,
2663 2664
}

2665 2666 2667 2668 2669 2670 2671 2672 2673 2674
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())
    }
}

2675 2676 2677 2678
impl Type {
    pub fn primitive_type(&self) -> Option<PrimitiveType> {
        match *self {
            Primitive(p) | BorrowedRef { type_: box Primitive(p), ..} => Some(p),
2679 2680
            Slice(..) | BorrowedRef { type_: box Slice(..), .. } => Some(PrimitiveType::Slice),
            Array(..) | BorrowedRef { type_: box Array(..), .. } => Some(PrimitiveType::Array),
2681 2682 2683 2684 2685
            Tuple(ref tys) => if tys.is_empty() {
                Some(PrimitiveType::Unit)
            } else {
                Some(PrimitiveType::Tuple)
            },
2686
            RawPointer(..) => Some(PrimitiveType::RawPointer),
2687
            BorrowedRef { type_: box Generic(..), .. } => Some(PrimitiveType::Reference),
2688
            BareFunction(..) => Some(PrimitiveType::Fn),
A
Andrew Cann 已提交
2689
            Never => Some(PrimitiveType::Never),
2690 2691 2692
            _ => None,
        }
    }
2693

2694 2695 2696 2697 2698 2699
    pub fn is_generic(&self) -> bool {
        match *self {
            ResolvedPath { is_generic, .. } => is_generic,
            _ => false,
        }
    }
2700 2701 2702 2703 2704 2705 2706

    pub fn is_self_type(&self) -> bool {
        match *self {
            Generic(ref name) => name == "Self",
            _ => false
        }
    }
2707 2708 2709 2710 2711

    pub fn generics(&self) -> Option<&[Type]> {
        match *self {
            ResolvedPath { ref path, .. } => {
                path.segments.last().and_then(|seg| {
V
varkor 已提交
2712
                    if let GenericArgs::AngleBracketed { ref types, .. } = seg.args {
2713 2714 2715 2716 2717 2718 2719 2720 2721
                        Some(&**types)
                    } else {
                        None
                    }
                })
            }
            _ => None,
        }
    }
2722
}
2723

2724
impl GetDefId for Type {
2725 2726 2727
    fn def_id(&self) -> Option<DefId> {
        match *self {
            ResolvedPath { did, .. } => Some(did),
2728 2729 2730 2731
            Primitive(p) => ::html::render::cache().primitive_locations.get(&p).cloned(),
            BorrowedRef { type_: box Generic(..), .. } =>
                Primitive(PrimitiveType::Reference).def_id(),
            BorrowedRef { ref type_, .. } => type_.def_id(),
2732 2733 2734 2735 2736
            Tuple(ref tys) => if tys.is_empty() {
                Primitive(PrimitiveType::Unit).def_id()
            } else {
                Primitive(PrimitiveType::Tuple).def_id()
            },
2737
            BareFunction(..) => Primitive(PrimitiveType::Fn).def_id(),
A
Andrew Cann 已提交
2738
            Never => Primitive(PrimitiveType::Never).def_id(),
2739 2740 2741 2742
            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(),
2743 2744 2745
            _ => None,
        }
    }
2746 2747
}

2748 2749
impl PrimitiveType {
    fn from_str(s: &str) -> Option<PrimitiveType> {
2750
        match s {
2751 2752 2753 2754 2755
            "isize" => Some(PrimitiveType::Isize),
            "i8" => Some(PrimitiveType::I8),
            "i16" => Some(PrimitiveType::I16),
            "i32" => Some(PrimitiveType::I32),
            "i64" => Some(PrimitiveType::I64),
2756
            "i128" => Some(PrimitiveType::I128),
2757 2758 2759 2760 2761
            "usize" => Some(PrimitiveType::Usize),
            "u8" => Some(PrimitiveType::U8),
            "u16" => Some(PrimitiveType::U16),
            "u32" => Some(PrimitiveType::U32),
            "u64" => Some(PrimitiveType::U64),
2762
            "u128" => Some(PrimitiveType::U128),
2763 2764 2765 2766 2767 2768 2769
            "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),
2770
            "tuple" => Some(PrimitiveType::Tuple),
2771
            "unit" => Some(PrimitiveType::Unit),
2772
            "pointer" => Some(PrimitiveType::RawPointer),
2773
            "reference" => Some(PrimitiveType::Reference),
2774
            "fn" => Some(PrimitiveType::Fn),
A
Andrew Cann 已提交
2775
            "never" => Some(PrimitiveType::Never),
2776 2777 2778 2779
            _ => None,
        }
    }

2780
    pub fn as_str(&self) -> &'static str {
E
est31 已提交
2781
        use self::PrimitiveType::*;
2782
        match *self {
2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802
            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",
2803
            Unit => "unit",
2804
            RawPointer => "pointer",
2805
            Reference => "reference",
2806
            Fn => "fn",
A
Andrew Cann 已提交
2807
            Never => "never",
2808 2809 2810 2811
        }
    }

    pub fn to_url_str(&self) -> &'static str {
2812
        self.as_str()
2813 2814 2815
    }
}

2816 2817 2818
impl From<ast::IntTy> for PrimitiveType {
    fn from(int_ty: ast::IntTy) -> PrimitiveType {
        match int_ty {
2819
            ast::IntTy::Isize => PrimitiveType::Isize,
2820 2821 2822 2823
            ast::IntTy::I8 => PrimitiveType::I8,
            ast::IntTy::I16 => PrimitiveType::I16,
            ast::IntTy::I32 => PrimitiveType::I32,
            ast::IntTy::I64 => PrimitiveType::I64,
2824
            ast::IntTy::I128 => PrimitiveType::I128,
2825 2826 2827
        }
    }
}
2828

2829 2830 2831
impl From<ast::UintTy> for PrimitiveType {
    fn from(uint_ty: ast::UintTy) -> PrimitiveType {
        match uint_ty {
2832
            ast::UintTy::Usize => PrimitiveType::Usize,
2833 2834 2835 2836
            ast::UintTy::U8 => PrimitiveType::U8,
            ast::UintTy::U16 => PrimitiveType::U16,
            ast::UintTy::U32 => PrimitiveType::U32,
            ast::UintTy::U64 => PrimitiveType::U64,
2837
            ast::UintTy::U128 => PrimitiveType::U128,
2838 2839 2840 2841
        }
    }
}

2842 2843 2844 2845 2846 2847 2848 2849 2850
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,
        }
    }
}

2851
impl Clean<Type> for hir::Ty {
2852
    fn clean(&self, cx: &DocContext) -> Type {
2853
        use rustc::hir::*;
2854
        match self.node {
A
Andrew Cann 已提交
2855
            TyNever => Never,
2856
            TyPtr(ref m) => RawPointer(m.mutbl.clean(cx), box m.ty.clean(cx)),
2857 2858 2859 2860 2861 2862 2863 2864 2865
            TyRptr(ref l, ref m) => {
                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)}
            }
2866
            TySlice(ref ty) => Slice(box ty.clean(cx)),
2867 2868
            TyArray(ref ty, ref length) => {
                let def_id = cx.tcx.hir.local_def_id(length.id);
2869
                let param_env = cx.tcx.param_env(def_id);
2870
                let substs = Substs::identity_for_item(cx.tcx, def_id);
O
Oliver Schneider 已提交
2871 2872 2873 2874
                let cid = GlobalId {
                    instance: ty::Instance::new(def_id, substs),
                    promoted: None
                };
2875
                let length = cx.tcx.const_eval(param_env.and(cid)).unwrap_or_else(|_| {
2876
                    ty::Const::unevaluated(cx.tcx, def_id, substs, cx.tcx.types.usize)
2877
                });
2878 2879
                let length = print_const(cx, length);
                Array(box ty.clean(cx), length)
2880
            },
2881
            TyTup(ref tys) => Tuple(tys.clean(cx)),
2882
            TyPath(hir::QPath::Resolved(None, ref path)) => {
2883
                if let Some(new_ty) = cx.ty_substs.borrow().get(&path.def).cloned() {
2884
                    return new_ty;
E
Eduard Burtescu 已提交
2885 2886
                }

2887 2888 2889 2890 2891 2892
                if let Def::TyParam(did) = path.def {
                    if let Some(bounds) = cx.impl_trait_bounds.borrow_mut().remove(&did) {
                        return ImplTrait(bounds);
                    }
                }

2893
                let mut alias = None;
2894
                if let Def::TyAlias(def_id) = path.def {
2895
                    // Substitute private type aliases
2896
                    if let Some(node_id) = cx.tcx.hir.as_local_node_id(def_id) {
2897
                        if !cx.access_levels.borrow().is_exported(def_id) {
2898
                            alias = Some(&cx.tcx.hir.expect_item(node_id).node);
2899
                        }
E
Eduard Burtescu 已提交
2900
                    }
2901 2902 2903
                };

                if let Some(&hir::ItemTy(ref ty, ref generics)) = alias {
2904
                    let provided_params = &path.segments.last().unwrap();
2905 2906
                    let mut ty_substs = FxHashMap();
                    let mut lt_substs = FxHashMap();
2907
                    provided_params.with_generic_args(|generic_args| {
2908
                        let mut indices = ty::GenericParamCount {
2909 2910 2911
                            lifetimes: 0,
                            types: 0
                        };
2912
                        for param in generics.params.iter() {
V
varkor 已提交
2913 2914
                            match param.kind {
                                hir::GenericParamKind::Lifetime { .. } => {
2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928
                                    let mut j = 0;
                                    let lifetime = generic_args.args.iter().find_map(|arg| {
                                        match arg {
                                            GenericArg::Lifetime(lt) => {
                                                if indices.lifetimes == j {
                                                    return Some(lt);
                                                }
                                                j += 1;
                                                None
                                            }
                                            _ => None,
                                        }
                                    });
                                    if let Some(lt) = lifetime.cloned() {
2929 2930
                                        if !lt.is_elided() {
                                            let lt_def_id =
V
varkor 已提交
2931
                                                cx.tcx.hir.local_def_id(param.id);
2932 2933 2934 2935 2936
                                            lt_substs.insert(lt_def_id, lt.clean(cx));
                                        }
                                    }
                                    indices.lifetimes += 1;
                                }
V
varkor 已提交
2937
                                hir::GenericParamKind::Type { ref default, .. } => {
2938
                                    let ty_param_def =
V
varkor 已提交
2939
                                        Def::TyParam(cx.tcx.hir.local_def_id(param.id));
2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953
                                    let mut j = 0;
                                    let type_ = generic_args.args.iter().find_map(|arg| {
                                        match arg {
                                            GenericArg::Type(ty) => {
                                                if indices.types == j {
                                                    return Some(ty);
                                                }
                                                j += 1;
                                                None
                                            }
                                            _ => None,
                                        }
                                    });
                                    if let Some(ty) = type_.cloned() {
O
Oliver Schneider 已提交
2954
                                        ty_substs.insert(ty_param_def, ty.clean(cx));
V
varkor 已提交
2955
                                    } else if let Some(default) = default.clone() {
2956 2957 2958
                                        ty_substs.insert(ty_param_def,
                                                         default.into_inner().clean(cx));
                                    }
2959
                                    indices.types += 1;
2960
                                }
2961
                            }
2962
                        }
2963
                    });
E
Eduard Burtescu 已提交
2964
                    return cx.enter_alias(ty_substs, lt_substs, || ty.clean(cx));
2965 2966
                }
                resolve_type(cx, path.clean(cx), self.id)
N
Niko Matsakis 已提交
2967
            }
2968
            TyPath(hir::QPath::Resolved(Some(ref qself), ref p)) => {
2969 2970 2971 2972
                let mut segments: Vec<_> = p.segments.clone().into();
                segments.pop();
                let trait_path = hir::Path {
                    span: p.span,
2973
                    def: Def::Trait(cx.tcx.associated_item(p.def.def_id()).container.id()),
2974 2975
                    segments: segments.into(),
                };
2976
                Type::QPath {
2977
                    name: p.segments.last().unwrap().ident.name.clean(cx),
2978 2979 2980 2981 2982
                    self_type: box qself.clean(cx),
                    trait_: box resolve_type(cx, trait_path.clean(cx), self.id)
                }
            }
            TyPath(hir::QPath::TypeRelative(ref qself, ref segment)) => {
2983
                let mut def = Def::Err;
2984 2985
                let ty = hir_ty_to_ty(cx.tcx, self);
                if let ty::TyProjection(proj) = ty.sty {
2986
                    def = Def::Trait(proj.trait_ref(cx.tcx).def_id);
2987
                }
2988 2989
                let trait_path = hir::Path {
                    span: self.span,
2990
                    def,
2991 2992 2993
                    segments: vec![].into(),
                };
                Type::QPath {
2994
                    name: segment.ident.name.clean(cx),
2995
                    self_type: box qself.clean(cx),
2996
                    trait_: box resolve_type(cx, trait_path.clean(cx), self.id)
2997 2998
                }
            }
2999 3000 3001
            TyTraitObject(ref bounds, ref lifetime) => {
                match bounds[0].clean(cx).trait_ {
                    ResolvedPath { path, typarams: None, did, is_generic } => {
V
varkor 已提交
3002
                        let mut bounds: Vec<self::GenericBound> = bounds[1..].iter().map(|bound| {
V
varkor 已提交
3003 3004
                            self::GenericBound::TraitBound(bound.clean(cx),
                                                           hir::TraitBoundModifier::None)
3005 3006
                        }).collect();
                        if !lifetime.is_elided() {
V
varkor 已提交
3007
                            bounds.push(self::GenericBound::Outlives(lifetime.clean(cx)));
3008
                        }
V
varkor 已提交
3009
                        ResolvedPath { path, typarams: Some(bounds), did, is_generic, }
N
Niko Matsakis 已提交
3010
                    }
3011
                    _ => Infer // shouldn't happen
N
Niko Matsakis 已提交
3012
                }
3013
            }
3014
            TyBareFn(ref barefn) => BareFunction(box barefn.clean(cx)),
3015
            TyInfer | TyErr => Infer,
M
mitaa 已提交
3016
            TyTypeof(..) => panic!("Unimplemented type {:?}", self.node),
3017
        }
C
Corey Richardson 已提交
3018 3019 3020
    }
}

D
Douglas Campos 已提交
3021
impl<'tcx> Clean<Type> for Ty<'tcx> {
3022
    fn clean(&self, cx: &DocContext) -> Type {
3023
        match self.sty {
A
Andrew Cann 已提交
3024
            ty::TyNever => Never,
3025 3026
            ty::TyBool => Primitive(PrimitiveType::Bool),
            ty::TyChar => Primitive(PrimitiveType::Char),
3027
            ty::TyInt(int_ty) => Primitive(int_ty.into()),
3028
            ty::TyUint(uint_ty) => Primitive(uint_ty.into()),
3029
            ty::TyFloat(float_ty) => Primitive(float_ty.into()),
3030
            ty::TyStr => Primitive(PrimitiveType::Str),
3031
            ty::TySlice(ty) => Slice(box ty.clean(cx)),
3032
            ty::TyArray(ty, n) => {
3033
                let mut n = cx.tcx.lift(&n).unwrap();
3034
                if let ConstValue::Unevaluated(def_id, substs) = n.val {
3035
                    let param_env = cx.tcx.param_env(def_id);
O
Oliver Schneider 已提交
3036 3037 3038 3039 3040
                    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)) {
3041 3042
                        n = new_n;
                    }
3043
                };
O
Oliver Schneider 已提交
3044
                let n = print_const(cx, n);
3045 3046
                Array(box ty.clean(cx), n)
            }
3047
            ty::TyRawPtr(mt) => RawPointer(mt.mutbl.clean(cx), box mt.ty.clean(cx)),
3048
            ty::TyRef(r, ty, mutbl) => BorrowedRef {
3049
                lifetime: r.clean(cx),
3050 3051
                mutability: mutbl.clean(cx),
                type_: box ty.clean(cx),
3052
            },
3053 3054 3055 3056 3057 3058
            ty::TyFnDef(..) |
            ty::TyFnPtr(_) => {
                let ty = cx.tcx.lift(self).unwrap();
                let sig = ty.fn_sig(cx.tcx);
                BareFunction(box BareFunctionDecl {
                    unsafety: sig.unsafety(),
3059
                    generic_params: Vec::new(),
3060 3061 3062 3063
                    decl: (cx.tcx.hir.local_def_id(ast::CRATE_NODE_ID), sig).clean(cx),
                    abi: sig.abi(),
                })
            }
3064
            ty::TyAdt(def, substs) => {
3065
                let did = def.did;
3066
                let kind = match def.adt_kind() {
3067 3068 3069
                    AdtKind::Struct => TypeKind::Struct,
                    AdtKind::Union => TypeKind::Union,
                    AdtKind::Enum => TypeKind::Enum,
3070
                };
M
mitaa 已提交
3071
                inline::record_extern_fqn(cx, did, kind);
3072
                let path = external_path(cx, &cx.tcx.item_name(did).as_str(),
3073
                                         None, false, vec![], substs);
3074
                ResolvedPath {
3075
                    path,
3076
                    typarams: None,
3077
                    did,
3078
                    is_generic: false,
3079 3080
                }
            }
P
Paul Lietar 已提交
3081 3082
            ty::TyForeign(did) => {
                inline::record_extern_fqn(cx, did, TypeKind::Foreign);
3083
                let path = external_path(cx, &cx.tcx.item_name(did).as_str(),
P
Paul Lietar 已提交
3084 3085 3086 3087 3088 3089 3090 3091
                                         None, false, vec![], Substs::empty());
                ResolvedPath {
                    path: path,
                    typarams: None,
                    did: did,
                    is_generic: false,
                }
            }
3092
            ty::TyDynamic(ref obj, ref reg) => {
3093 3094 3095 3096 3097
                if let Some(principal) = obj.principal() {
                    let did = principal.def_id();
                    inline::record_extern_fqn(cx, did, TypeKind::Trait);

                    let mut typarams = vec![];
V
varkor 已提交
3098
                    reg.clean(cx).map(|b| typarams.push(GenericBound::Outlives(b)));
3099
                    for did in obj.auto_traits() {
3100
                        let empty = cx.tcx.intern_substs(&[]);
3101
                        let path = external_path(cx, &cx.tcx.item_name(did).as_str(),
3102 3103
                            Some(did), false, vec![], empty);
                        inline::record_extern_fqn(cx, did, TypeKind::Trait);
V
varkor 已提交
3104
                        let bound = GenericBound::TraitBound(PolyTrait {
3105
                            trait_: ResolvedPath {
3106
                                path,
3107
                                typarams: None,
3108
                                did,
3109 3110
                                is_generic: false,
                            },
3111
                            generic_params: Vec::new(),
3112 3113
                        }, hir::TraitBoundModifier::None);
                        typarams.push(bound);
3114
                    }
3115

3116
                    let mut bindings = vec![];
3117
                    for pb in obj.projection_bounds() {
3118
                        bindings.push(TypeBinding {
3119
                            name: cx.tcx.associated_item(pb.item_def_id()).ident.name.clean(cx),
3120
                            ty: pb.skip_binder().ty.clean(cx)
3121 3122
                        });
                    }
3123

3124
                    let path = external_path(cx, &cx.tcx.item_name(did).as_str(), Some(did),
3125
                        false, bindings, principal.skip_binder().substs);
3126
                    ResolvedPath {
3127
                        path,
3128
                        typarams: Some(typarams),
3129
                        did,
3130 3131 3132 3133
                        is_generic: false,
                    }
                } else {
                    Never
3134 3135
                }
            }
A
Andrew Cann 已提交
3136
            ty::TyTuple(ref t) => Tuple(t.clean(cx)),
3137

3138
            ty::TyProjection(ref data) => data.clean(cx),
3139

3140
            ty::TyParam(ref p) => Generic(p.name.to_string()),
3141

3142 3143 3144
            ty::TyAnon(def_id, substs) => {
                // Grab the "TraitA + TraitB" from `impl TraitA + TraitB`,
                // by looking up the projections associated with the def_id.
3145
                let predicates_of = cx.tcx.predicates_of(def_id);
3146
                let substs = cx.tcx.lift(&substs).unwrap();
3147
                let bounds = predicates_of.instantiate(cx.tcx, substs);
3148 3149 3150
                let mut regions = vec![];
                let mut has_sized = false;
                let mut bounds = bounds.predicates.iter().filter_map(|predicate| {
3151 3152
                    let trait_ref = if let Some(tr) = predicate.to_opt_poly_trait_ref() {
                        tr
3153 3154
                    } else if let ty::Predicate::TypeOutlives(pred) = *predicate {
                        // these should turn up at the end
3155
                        pred.skip_binder().1.clean(cx).map(|r| {
V
varkor 已提交
3156
                            regions.push(GenericBound::Outlives(r))
3157
                        });
3158
                        return None;
3159 3160 3161 3162
                    } else {
                        return None;
                    };

3163 3164
                    if let Some(sized) = cx.tcx.lang_items().sized_trait() {
                        if trait_ref.def_id() == sized {
3165
                            has_sized = true;
3166 3167 3168 3169
                            return None;
                        }
                    }

3170 3171 3172 3173 3174 3175
                    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)
3176
                                                .ident.name.clean(cx),
3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187
                                    ty: proj.ty.clean(cx),
                                })
                            } else {
                                None
                            }
                        } else {
                            None
                        }
                    ).collect();

                    Some((trait_ref.skip_binder(), bounds).clean(cx))
3188 3189 3190
                }).collect::<Vec<_>>();
                bounds.extend(regions);
                if !has_sized && !bounds.is_empty() {
V
varkor 已提交
3191
                    bounds.insert(0, GenericBound::maybe_sized(cx));
3192 3193
                }
                ImplTrait(bounds)
3194 3195
            }

J
John Kåre Alsaker 已提交
3196
            ty::TyClosure(..) | ty::TyGenerator(..) => Tuple(vec![]), // FIXME(pcwalton)
3197

3198
            ty::TyGeneratorWitness(..) => panic!("TyGeneratorWitness"),
3199 3200
            ty::TyInfer(..) => panic!("TyInfer"),
            ty::TyError => panic!("TyError"),
3201 3202 3203 3204
        }
    }
}

3205
impl Clean<Item> for hir::StructField {
3206
    fn clean(&self, cx: &DocContext) -> Item {
C
Corey Richardson 已提交
3207
        Item {
3208
            name: Some(self.ident.name).clean(cx),
3209
            attrs: self.attrs.clean(cx),
3210
            source: self.span.clean(cx),
3211
            visibility: self.vis.clean(cx),
3212 3213 3214
            stability: get_stability(cx, cx.tcx.hir.local_def_id(self.id)),
            deprecation: get_deprecation(cx, cx.tcx.hir.local_def_id(self.id)),
            def_id: cx.tcx.hir.local_def_id(self.id),
3215
            inner: StructFieldItem(self.ty.clean(cx)),
C
Corey Richardson 已提交
3216 3217 3218 3219
        }
    }
}

3220
impl<'tcx> Clean<Item> for ty::FieldDef {
3221
    fn clean(&self, cx: &DocContext) -> Item {
3222
        Item {
3223
            name: Some(self.ident.name).clean(cx),
3224
            attrs: cx.tcx.get_attrs(self.did).clean(cx),
3225
            source: cx.tcx.def_span(self.did).clean(cx),
3226
            visibility: self.vis.clean(cx),
3227
            stability: get_stability(cx, self.did),
3228
            deprecation: get_deprecation(cx, self.did),
3229
            def_id: self.did,
3230
            inner: StructFieldItem(cx.tcx.type_of(self.did).clean(cx)),
3231 3232 3233 3234
        }
    }
}

J
Jeffrey Seyfried 已提交
3235 3236 3237 3238
#[derive(Clone, PartialEq, Eq, RustcDecodable, RustcEncodable, Debug)]
pub enum Visibility {
    Public,
    Inherited,
3239 3240
    Crate,
    Restricted(DefId, Path),
J
Jeffrey Seyfried 已提交
3241
}
C
Corey Richardson 已提交
3242

3243
impl Clean<Option<Visibility>> for hir::Visibility {
3244
    fn clean(&self, cx: &DocContext) -> Option<Visibility> {
3245
        Some(match self.node {
3246 3247 3248 3249
            hir::VisibilityKind::Public => Visibility::Public,
            hir::VisibilityKind::Inherited => Visibility::Inherited,
            hir::VisibilityKind::Crate(_) => Visibility::Crate,
            hir::VisibilityKind::Restricted { ref path, .. } => {
3250 3251 3252 3253 3254
                let path = path.clean(cx);
                let did = register_def(cx, path.def);
                Visibility::Restricted(did, path)
            }
        })
3255 3256 3257 3258 3259
    }
}

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

J
Jorge Aparicio 已提交
3264
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
3265
pub struct Struct {
3266 3267 3268 3269
    pub struct_type: doctree::StructType,
    pub generics: Generics,
    pub fields: Vec<Item>,
    pub fields_stripped: bool,
C
Corey Richardson 已提交
3270 3271
}

V
Vadim Petrochenkov 已提交
3272 3273 3274 3275 3276 3277 3278 3279
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
pub struct Union {
    pub struct_type: doctree::StructType,
    pub generics: Generics,
    pub fields: Vec<Item>,
    pub fields_stripped: bool,
}

3280 3281 3282 3283 3284 3285 3286
impl Clean<Vec<Item>> for doctree::Struct {
    fn clean(&self, cx: &DocContext) -> Vec<Item> {
        let name = self.name.clean(cx);
        let mut ret = get_auto_traits_with_node_id(cx, self.id, name.clone());

        ret.push(Item {
            name: Some(name),
3287 3288
            attrs: self.attrs.clean(cx),
            source: self.whence.clean(cx),
3289
            def_id: cx.tcx.hir.local_def_id(self.id),
3290 3291
            visibility: self.vis.clean(cx),
            stability: self.stab.clean(cx),
3292
            deprecation: self.depr.clean(cx),
C
Corey Richardson 已提交
3293 3294
            inner: StructItem(Struct {
                struct_type: self.struct_type,
3295 3296
                generics: self.generics.clean(cx),
                fields: self.fields.clean(cx),
S
Steven Fackler 已提交
3297
                fields_stripped: false,
C
Corey Richardson 已提交
3298
            }),
3299 3300 3301
        });

        ret
C
Corey Richardson 已提交
3302 3303 3304
    }
}

3305 3306 3307 3308 3309 3310 3311
impl Clean<Vec<Item>> for doctree::Union {
    fn clean(&self, cx: &DocContext) -> Vec<Item> {
        let name = self.name.clean(cx);
        let mut ret = get_auto_traits_with_node_id(cx, self.id, name.clone());

        ret.push(Item {
            name: Some(name),
V
Vadim Petrochenkov 已提交
3312 3313
            attrs: self.attrs.clean(cx),
            source: self.whence.clean(cx),
3314
            def_id: cx.tcx.hir.local_def_id(self.id),
V
Vadim Petrochenkov 已提交
3315 3316 3317 3318 3319 3320 3321 3322 3323
            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,
            }),
3324 3325 3326
        });

        ret
V
Vadim Petrochenkov 已提交
3327 3328 3329
    }
}

3330
/// This is a more limited form of the standard Struct, different in that
C
Corey Richardson 已提交
3331 3332
/// it lacks the things most items have (name, id, parameterization). Found
/// only as a variant in an enum.
J
Jorge Aparicio 已提交
3333
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
3334
pub struct VariantStruct {
3335 3336 3337
    pub struct_type: doctree::StructType,
    pub fields: Vec<Item>,
    pub fields_stripped: bool,
C
Corey Richardson 已提交
3338 3339
}

3340
impl Clean<VariantStruct> for ::rustc::hir::VariantData {
3341
    fn clean(&self, cx: &DocContext) -> VariantStruct {
C
Corey Richardson 已提交
3342 3343
        VariantStruct {
            struct_type: doctree::struct_type_from_def(self),
3344
            fields: self.fields().iter().map(|x| x.clean(cx)).collect(),
S
Steven Fackler 已提交
3345
            fields_stripped: false,
C
Corey Richardson 已提交
3346 3347 3348 3349
        }
    }
}

J
Jorge Aparicio 已提交
3350
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
3351
pub struct Enum {
3352 3353 3354
    pub variants: Vec<Item>,
    pub generics: Generics,
    pub variants_stripped: bool,
C
Corey Richardson 已提交
3355 3356
}

3357 3358 3359 3360 3361 3362 3363
impl Clean<Vec<Item>> for doctree::Enum {
    fn clean(&self, cx: &DocContext) -> Vec<Item> {
        let name = self.name.clean(cx);
        let mut ret = get_auto_traits_with_node_id(cx, self.id, name.clone());

        ret.push(Item {
            name: Some(name),
3364 3365
            attrs: self.attrs.clean(cx),
            source: self.whence.clean(cx),
3366
            def_id: cx.tcx.hir.local_def_id(self.id),
3367 3368
            visibility: self.vis.clean(cx),
            stability: self.stab.clean(cx),
3369
            deprecation: self.depr.clean(cx),
C
Corey Richardson 已提交
3370
            inner: EnumItem(Enum {
3371 3372
                variants: self.variants.clean(cx),
                generics: self.generics.clean(cx),
S
Steven Fackler 已提交
3373
                variants_stripped: false,
C
Corey Richardson 已提交
3374
            }),
3375 3376 3377
        });

        ret
C
Corey Richardson 已提交
3378 3379 3380
    }
}

J
Jorge Aparicio 已提交
3381
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
3382
pub struct Variant {
3383
    pub kind: VariantKind,
C
Corey Richardson 已提交
3384 3385 3386
}

impl Clean<Item> for doctree::Variant {
3387
    fn clean(&self, cx: &DocContext) -> Item {
C
Corey Richardson 已提交
3388
        Item {
3389 3390 3391
            name: Some(self.name.clean(cx)),
            attrs: self.attrs.clean(cx),
            source: self.whence.clean(cx),
3392
            visibility: None,
3393
            stability: self.stab.clean(cx),
3394
            deprecation: self.depr.clean(cx),
3395
            def_id: cx.tcx.hir.local_def_id(self.def.id()),
C
Corey Richardson 已提交
3396
            inner: VariantItem(Variant {
3397
                kind: self.def.clean(cx),
C
Corey Richardson 已提交
3398 3399 3400 3401 3402
            }),
        }
    }
}

3403
impl<'tcx> Clean<Item> for ty::VariantDef {
3404
    fn clean(&self, cx: &DocContext) -> Item {
3405 3406 3407
        let kind = match self.ctor_kind {
            CtorKind::Const => VariantKind::CLike,
            CtorKind::Fn => {
3408
                VariantKind::Tuple(
3409
                    self.fields.iter().map(|f| cx.tcx.type_of(f.did).clean(cx)).collect()
3410
                )
3411
            }
3412
            CtorKind::Fictive => {
3413
                VariantKind::Struct(VariantStruct {
3414 3415
                    struct_type: doctree::Plain,
                    fields_stripped: false,
3416
                    fields: self.fields.iter().map(|field| {
3417
                        Item {
3418
                            source: cx.tcx.def_span(field.did).clean(cx),
3419
                            name: Some(field.ident.name.clean(cx)),
3420
                            attrs: cx.tcx.get_attrs(field.did).clean(cx),
3421
                            visibility: field.vis.clean(cx),
3422 3423 3424
                            def_id: field.did,
                            stability: get_stability(cx, field.did),
                            deprecation: get_deprecation(cx, field.did),
3425
                            inner: StructFieldItem(cx.tcx.type_of(field.did).clean(cx))
3426 3427 3428 3429 3430 3431
                        }
                    }).collect()
                })
            }
        };
        Item {
3432
            name: Some(self.name.clean(cx)),
3433
            attrs: inline::load_attrs(cx, self.did),
3434
            source: cx.tcx.def_span(self.did).clean(cx),
J
Jeffrey Seyfried 已提交
3435
            visibility: Some(Inherited),
3436
            def_id: self.did,
3437
            inner: VariantItem(Variant { kind: kind }),
3438
            stability: get_stability(cx, self.did),
3439
            deprecation: get_deprecation(cx, self.did),
3440 3441 3442 3443
        }
    }
}

J
Jorge Aparicio 已提交
3444
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
3445
pub enum VariantKind {
3446 3447 3448
    CLike,
    Tuple(Vec<Type>),
    Struct(VariantStruct),
C
Corey Richardson 已提交
3449 3450
}

3451 3452 3453
impl Clean<VariantKind> for hir::VariantData {
    fn clean(&self, cx: &DocContext) -> VariantKind {
        if self.is_struct() {
3454
            VariantKind::Struct(self.clean(cx))
3455
        } else if self.is_unit() {
3456
            VariantKind::CLike
3457
        } else {
3458
            VariantKind::Tuple(self.fields().iter().map(|x| x.ty.clean(cx)).collect())
3459
        }
3460 3461 3462
    }
}

J
Jorge Aparicio 已提交
3463
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
3464
pub struct Span {
3465
    pub filename: FileName,
3466 3467 3468 3469
    pub loline: usize,
    pub locol: usize,
    pub hiline: usize,
    pub hicol: usize,
3470 3471
}

3472
impl Span {
3473
    pub fn empty() -> Span {
3474
        Span {
3475
            filename: FileName::Anon,
3476 3477 3478 3479 3480 3481
            loline: 0, locol: 0,
            hiline: 0, hicol: 0,
        }
    }
}

3482
impl Clean<Span> for syntax_pos::Span {
3483
    fn clean(&self, cx: &DocContext) -> Span {
V
Vadim Petrochenkov 已提交
3484
        if self.is_dummy() {
3485 3486 3487
            return Span::empty();
        }

3488
        let cm = cx.sess().codemap();
3489
        let filename = cm.span_to_filename(*self);
3490 3491
        let lo = cm.lookup_char_pos(self.lo());
        let hi = cm.lookup_char_pos(self.hi());
3492
        Span {
3493
            filename,
3494
            loline: lo.line,
3495
            locol: lo.col.to_usize(),
3496
            hiline: hi.line,
3497
            hicol: hi.col.to_usize(),
3498
        }
C
Corey Richardson 已提交
3499 3500 3501
    }
}

3502
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)]
C
Corey Richardson 已提交
3503
pub struct Path {
3504
    pub global: bool,
3505
    pub def: Def,
3506
    pub segments: Vec<PathSegment>,
C
Corey Richardson 已提交
3507 3508
}

3509 3510 3511 3512
impl Path {
    pub fn singleton(name: String) -> Path {
        Path {
            global: false,
3513
            def: Def::Err,
3514
            segments: vec![PathSegment {
3515
                name,
V
varkor 已提交
3516
                args: GenericArgs::AngleBracketed {
3517 3518
                    lifetimes: Vec::new(),
                    types: Vec::new(),
A
Aaron Hill 已提交
3519
                    bindings: Vec::new(),
3520 3521 3522 3523
                }
            }]
        }
    }
3524

B
bluss 已提交
3525
    pub fn last_name(&self) -> &str {
E
Esteban Küber 已提交
3526
        self.segments.last().unwrap().name.as_str()
3527
    }
3528 3529
}

3530
impl Clean<Path> for hir::Path {
3531
    fn clean(&self, cx: &DocContext) -> Path {
C
Corey Richardson 已提交
3532
        Path {
3533
            global: self.is_global(),
3534
            def: self.def,
3535
            segments: if self.is_global() { &self.segments[1..] } else { &self.segments }.clean(cx),
3536 3537 3538 3539
        }
    }
}

V
varkor 已提交
3540
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)]
3541
pub enum GenericArgs {
3542 3543 3544
    AngleBracketed {
        lifetimes: Vec<Lifetime>,
        types: Vec<Type>,
3545
        bindings: Vec<TypeBinding>,
3546 3547 3548
    },
    Parenthesized {
        inputs: Vec<Type>,
3549
        output: Option<Type>,
3550
    }
3551 3552
}

3553 3554
impl Clean<GenericArgs> for hir::GenericArgs {
    fn clean(&self, cx: &DocContext) -> GenericArgs {
3555 3556
        if self.parenthesized {
            let output = self.bindings[0].ty.clean(cx);
3557
            GenericArgs::Parenthesized {
3558 3559
                inputs: self.inputs().clean(cx),
                output: if output != Type::Tuple(Vec::new()) { Some(output) } else { None }
3560
            }
3561
        } else {
V
varkor 已提交
3562
            let (mut lifetimes, mut types) = (vec![], vec![]);
3563 3564 3565
            let mut elided_lifetimes = true;
            for arg in &self.args {
                match arg {
V
varkor 已提交
3566 3567
                    GenericArg::Lifetime(lt) => {
                        if !lt.is_elided() {
3568 3569 3570 3571 3572 3573 3574 3575 3576
                            elided_lifetimes = false;
                        }
                        lifetimes.push(lt.clean(cx));
                    }
                    GenericArg::Type(ty) => {
                        types.push(ty.clean(cx));
                    }
                }
            }
3577
            GenericArgs::AngleBracketed {
V
varkor 已提交
3578
                lifetimes: if elided_lifetimes { vec![] } else { lifetimes },
3579
                types,
3580
                bindings: self.bindings.clean(cx),
3581
            }
3582 3583 3584
        }
    }
}
3585

3586
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)]
3587 3588
pub struct PathSegment {
    pub name: String,
V
varkor 已提交
3589
    pub args: GenericArgs,
3590 3591
}

3592
impl Clean<PathSegment> for hir::PathSegment {
3593
    fn clean(&self, cx: &DocContext) -> PathSegment {
3594
        PathSegment {
3595
            name: self.ident.name.clean(cx),
3596
            args: self.with_generic_args(|generic_args| generic_args.clean(cx))
C
Corey Richardson 已提交
3597 3598 3599 3600
        }
    }
}

3601 3602 3603 3604
fn strip_type(ty: Type) -> Type {
    match ty {
        Type::ResolvedPath { path, typarams, did, is_generic } => {
            Type::ResolvedPath { path: strip_path(&path), typarams, did, is_generic }
A
Aaron Hill 已提交
3605
        }
3606 3607
        Type::Tuple(inner_tys) => {
            Type::Tuple(inner_tys.iter().map(|t| strip_type(t.clone())).collect())
A
Aaron Hill 已提交
3608
        }
3609 3610 3611 3612 3613 3614
        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 已提交
3615
        }
3616 3617 3618 3619 3620
        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 已提交
3621
        }
3622 3623 3624 3625 3626 3627 3628 3629
        _ => ty
    }
}

fn strip_path(path: &Path) -> Path {
    let segments = path.segments.iter().map(|s| {
        PathSegment {
            name: s.name.clone(),
V
varkor 已提交
3630
            args: GenericArgs::AngleBracketed {
3631 3632
                lifetimes: Vec::new(),
                types: Vec::new(),
A
Aaron Hill 已提交
3633
                bindings: Vec::new(),
3634 3635 3636 3637 3638 3639 3640
            }
        }
    }).collect();

    Path {
        global: path.global,
        def: path.def.clone(),
A
Aaron Hill 已提交
3641
        segments,
3642 3643 3644
    }
}

3645
fn qpath_to_string(p: &hir::QPath) -> String {
3646 3647
    let segments = match *p {
        hir::QPath::Resolved(_, ref path) => &path.segments,
3648
        hir::QPath::TypeRelative(_, ref segment) => return segment.ident.to_string(),
3649 3650
    };

3651
    let mut s = String::new();
3652 3653
    for (i, seg) in segments.iter().enumerate() {
        if i > 0 {
C
Corey Richardson 已提交
3654 3655
            s.push_str("::");
        }
3656 3657
        if seg.ident.name != keywords::CrateRoot.name() {
            s.push_str(&*seg.ident.as_str());
3658
        }
C
Corey Richardson 已提交
3659
    }
3660
    s
C
Corey Richardson 已提交
3661 3662
}

3663
impl Clean<String> for ast::Name {
3664
    fn clean(&self, _: &DocContext) -> String {
3665
        self.to_string()
3666 3667 3668
    }
}

3669 3670 3671 3672 3673 3674
impl Clean<String> for InternedString {
    fn clean(&self, _: &DocContext) -> String {
        self.to_string()
    }
}

J
Jorge Aparicio 已提交
3675
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
3676
pub struct Typedef {
3677 3678
    pub type_: Type,
    pub generics: Generics,
C
Corey Richardson 已提交
3679 3680 3681
}

impl Clean<Item> for doctree::Typedef {
3682
    fn clean(&self, cx: &DocContext) -> Item {
C
Corey Richardson 已提交
3683
        Item {
3684 3685 3686
            name: Some(self.name.clean(cx)),
            attrs: self.attrs.clean(cx),
            source: self.whence.clean(cx),
3687
            def_id: cx.tcx.hir.local_def_id(self.id.clone()),
3688 3689
            visibility: self.vis.clean(cx),
            stability: self.stab.clean(cx),
3690
            deprecation: self.depr.clean(cx),
C
Corey Richardson 已提交
3691
            inner: TypedefItem(Typedef {
3692 3693
                type_: self.ty.clean(cx),
                generics: self.gen.clean(cx),
3694
            }, false),
C
Corey Richardson 已提交
3695 3696 3697 3698
        }
    }
}

3699
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)]
C
Corey Richardson 已提交
3700
pub struct BareFunctionDecl {
3701
    pub unsafety: hir::Unsafety,
V
varkor 已提交
3702
    pub generic_params: Vec<GenericParamDef>,
3703
    pub decl: FnDecl,
3704
    pub abi: Abi,
C
Corey Richardson 已提交
3705 3706
}

3707
impl Clean<BareFunctionDecl> for hir::BareFnTy {
3708
    fn clean(&self, cx: &DocContext) -> BareFunctionDecl {
3709 3710 3711
        let (generic_params, decl) = enter_impl_trait(cx, || {
            (self.generic_params.clean(cx), (&*self.decl, &self.arg_names[..]).clean(cx))
        });
C
Corey Richardson 已提交
3712
        BareFunctionDecl {
N
Niko Matsakis 已提交
3713
            unsafety: self.unsafety,
W
Without Boats 已提交
3714
            abi: self.abi,
3715
            decl,
3716
            generic_params,
C
Corey Richardson 已提交
3717 3718 3719 3720
        }
    }
}

J
Jorge Aparicio 已提交
3721
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
3722
pub struct Static {
3723 3724
    pub type_: Type,
    pub mutability: Mutability,
C
Corey Richardson 已提交
3725 3726 3727
    /// 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.
3728
    pub expr: String,
C
Corey Richardson 已提交
3729 3730 3731
}

impl Clean<Item> for doctree::Static {
3732
    fn clean(&self, cx: &DocContext) -> Item {
3733
        debug!("cleaning static {}: {:?}", self.name.clean(cx), self);
C
Corey Richardson 已提交
3734
        Item {
3735 3736 3737
            name: Some(self.name.clean(cx)),
            attrs: self.attrs.clean(cx),
            source: self.whence.clean(cx),
3738
            def_id: cx.tcx.hir.local_def_id(self.id),
3739 3740
            visibility: self.vis.clean(cx),
            stability: self.stab.clean(cx),
3741
            deprecation: self.depr.clean(cx),
C
Corey Richardson 已提交
3742
            inner: StaticItem(Static {
3743 3744
                type_: self.type_.clean(cx),
                mutability: self.mutability.clean(cx),
3745
                expr: print_const_expr(cx, self.expr),
C
Corey Richardson 已提交
3746 3747 3748 3749 3750
            }),
        }
    }
}

J
Jorge Aparicio 已提交
3751
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
3752 3753 3754 3755 3756 3757 3758 3759 3760 3761 3762
pub struct Constant {
    pub type_: Type,
    pub expr: String,
}

impl Clean<Item> for doctree::Constant {
    fn clean(&self, cx: &DocContext) -> Item {
        Item {
            name: Some(self.name.clean(cx)),
            attrs: self.attrs.clean(cx),
            source: self.whence.clean(cx),
3763
            def_id: cx.tcx.hir.local_def_id(self.id),
3764 3765
            visibility: self.vis.clean(cx),
            stability: self.stab.clean(cx),
3766
            deprecation: self.depr.clean(cx),
3767 3768
            inner: ConstantItem(Constant {
                type_: self.type_.clean(cx),
3769
                expr: print_const_expr(cx, self.expr),
3770 3771 3772 3773 3774
            }),
        }
    }
}

3775
#[derive(Debug, Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Copy, Hash)]
C
Corey Richardson 已提交
3776 3777 3778 3779 3780
pub enum Mutability {
    Mutable,
    Immutable,
}

3781
impl Clean<Mutability> for hir::Mutability {
3782
    fn clean(&self, _: &DocContext) -> Mutability {
C
Corey Richardson 已提交
3783
        match self {
3784 3785
            &hir::MutMutable => Mutable,
            &hir::MutImmutable => Immutable,
C
Corey Richardson 已提交
3786 3787 3788 3789
        }
    }
}

3790
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Copy, Debug, Hash)]
3791 3792 3793 3794 3795
pub enum ImplPolarity {
    Positive,
    Negative,
}

3796
impl Clean<ImplPolarity> for hir::ImplPolarity {
3797 3798
    fn clean(&self, _: &DocContext) -> ImplPolarity {
        match self {
3799 3800
            &hir::ImplPolarity::Positive => ImplPolarity::Positive,
            &hir::ImplPolarity::Negative => ImplPolarity::Negative,
3801 3802 3803 3804
        }
    }
}

J
Jorge Aparicio 已提交
3805
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
3806
pub struct Impl {
3807
    pub unsafety: hir::Unsafety,
3808
    pub generics: Generics,
3809
    pub provided_trait_methods: FxHashSet<String>,
3810 3811
    pub trait_: Option<Type>,
    pub for_: Type,
3812
    pub items: Vec<Item>,
3813
    pub polarity: Option<ImplPolarity>,
3814 3815 3816 3817
    pub synthetic: bool,
}

pub fn get_auto_traits_with_node_id(cx: &DocContext, id: ast::NodeId, name: String) -> Vec<Item> {
3818
    let finder = AutoTraitFinder::new(cx);
3819 3820 3821 3822
    finder.get_with_node_id(id, name)
}

pub fn get_auto_traits_with_def_id(cx: &DocContext, id: DefId) -> Vec<Item> {
3823
    let finder = AutoTraitFinder::new(cx);
3824 3825

    finder.get_with_def_id(id)
C
Corey Richardson 已提交
3826 3827
}

3828 3829 3830 3831 3832 3833 3834 3835
impl Clean<Vec<Item>> for doctree::Impl {
    fn clean(&self, cx: &DocContext) -> Vec<Item> {
        let mut ret = Vec::new();
        let trait_ = self.trait_.clean(cx);
        let items = self.items.clean(cx);

        // If this impl block is an implementation of the Deref trait, then we
        // need to try inlining the target's inherent impl blocks as well.
3836
        if trait_.def_id() == cx.tcx.lang_items().deref_trait() {
3837
            build_deref_target_impls(cx, &items, &mut ret);
3838 3839
        }

3840 3841 3842
        let provided = trait_.def_id().map(|did| {
            cx.tcx.provided_trait_methods(did)
                  .into_iter()
3843
                  .map(|meth| meth.ident.to_string())
3844
                  .collect()
3845
        }).unwrap_or(FxHashSet());
3846

3847
        ret.push(Item {
C
Corey Richardson 已提交
3848
            name: None,
3849 3850
            attrs: self.attrs.clean(cx),
            source: self.whence.clean(cx),
3851
            def_id: cx.tcx.hir.local_def_id(self.id),
3852 3853
            visibility: self.vis.clean(cx),
            stability: self.stab.clean(cx),
3854
            deprecation: self.depr.clean(cx),
C
Corey Richardson 已提交
3855
            inner: ImplItem(Impl {
3856
                unsafety: self.unsafety,
3857
                generics: self.generics.clean(cx),
3858
                provided_trait_methods: provided,
3859
                trait_,
3860
                for_: self.for_.clean(cx),
3861
                items,
3862
                polarity: Some(self.polarity.clean(cx)),
A
Aaron Hill 已提交
3863
                synthetic: false,
3864
            })
3865
        });
M
mitaa 已提交
3866
        ret
3867 3868 3869 3870 3871 3872
    }
}

fn build_deref_target_impls(cx: &DocContext,
                            items: &[Item],
                            ret: &mut Vec<Item>) {
3873
    use self::PrimitiveType::*;
3874
    let tcx = cx.tcx;
3875 3876 3877

    for item in items {
        let target = match item.inner {
3878
            TypedefItem(ref t, true) => &t.type_,
3879 3880 3881
            _ => continue,
        };
        let primitive = match *target {
N
Niko Matsakis 已提交
3882
            ResolvedPath { did, .. } if did.is_local() => continue,
3883
            ResolvedPath { did, .. } => {
3884 3885 3886 3887 3888
                // We set the last parameter to false to avoid looking for auto-impls for traits
                // and therefore avoid an ICE.
                // The reason behind this is that auto-traits don't propagate through Deref so
                // we're not supposed to synthesise impls for them.
                ret.extend(inline::build_impls(cx, did, false));
3889 3890 3891 3892 3893 3894 3895 3896
                continue
            }
            _ => match target.primitive_type() {
                Some(prim) => prim,
                None => continue,
            }
        };
        let did = match primitive {
3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911
            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(),
3912
            Bool => None,
3913 3914 3915
            Str => tcx.lang_items().str_impl(),
            Slice => tcx.lang_items().slice_impl(),
            Array => tcx.lang_items().slice_impl(),
3916
            Tuple => None,
3917
            Unit => None,
3918
            RawPointer => tcx.lang_items().const_ptr_impl(),
3919
            Reference => None,
3920
            Fn => None,
A
Andrew Cann 已提交
3921
            Never => None,
3922 3923
        };
        if let Some(did) = did {
N
Niko Matsakis 已提交
3924
            if !did.is_local() {
3925
                inline::build_impl(cx, did, ret);
3926
            }
C
Corey Richardson 已提交
3927 3928 3929 3930
        }
    }
}

3931 3932 3933 3934 3935 3936
impl Clean<Item> for doctree::ExternCrate {
    fn clean(&self, cx: &DocContext) -> Item {
        Item {
            name: None,
            attrs: self.attrs.clean(cx),
            source: self.whence.clean(cx),
M
mitaa 已提交
3937
            def_id: DefId { krate: self.cnum, index: CRATE_DEF_INDEX },
3938 3939
            visibility: self.vis.clean(cx),
            stability: None,
3940
            deprecation: None,
3941 3942 3943
            inner: ExternCrateItem(self.name.clean(cx), self.path.clone())
        }
    }
C
Corey Richardson 已提交
3944 3945
}

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

3968
            Import::Glob(resolve_use_source(cx, path))
3969 3970 3971
        } else {
            let name = self.name;
            if !denied {
3972 3973
                let mut visited = FxHashSet();
                if let Some(items) = inline::try_inline(cx, path.def, name, &mut visited) {
3974
                    return items;
3975
                }
3976
            }
3977
            Import::Simple(name.clean(cx), resolve_use_source(cx, path))
3978
        };
3979
        vec![Item {
3980 3981 3982
            name: None,
            attrs: self.attrs.clean(cx),
            source: self.whence.clean(cx),
3983
            def_id: cx.tcx.hir.local_def_id(ast::CRATE_NODE_ID),
3984 3985
            visibility: self.vis.clean(cx),
            stability: None,
3986
            deprecation: None,
3987
            inner: ImportItem(inner)
3988
        }]
C
Corey Richardson 已提交
3989 3990 3991
    }
}

J
Jorge Aparicio 已提交
3992
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
3993
pub enum Import {
3994
    // use source as str;
3995
    Simple(String, ImportSource),
A
Alex Crichton 已提交
3996
    // use source::*;
3997
    Glob(ImportSource)
A
Alex Crichton 已提交
3998 3999
}

J
Jorge Aparicio 已提交
4000
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
A
Alex Crichton 已提交
4001
pub struct ImportSource {
4002
    pub path: Path,
N
Niko Matsakis 已提交
4003
    pub did: Option<DefId>,
C
Corey Richardson 已提交
4004 4005
}

4006
impl Clean<Vec<Item>> for hir::ForeignMod {
4007
    fn clean(&self, cx: &DocContext) -> Vec<Item> {
4008 4009
        let mut items = self.items.clean(cx);
        for item in &mut items {
M
mitaa 已提交
4010
            if let ForeignFunctionItem(ref mut f) = item.inner {
W
Without Boats 已提交
4011
                f.header.abi = self.abi;
4012 4013 4014
            }
        }
        items
4015 4016 4017
    }
}

4018
impl Clean<Item> for hir::ForeignItem {
4019
    fn clean(&self, cx: &DocContext) -> Item {
4020
        let inner = match self.node {
4021
            hir::ForeignItemFn(ref decl, ref names, ref generics) => {
4022 4023 4024
                let (generics, decl) = enter_impl_trait(cx, || {
                    (generics.clean(cx), (&**decl, &names[..]).clean(cx))
                });
4025
                ForeignFunctionItem(Function {
4026
                    decl,
4027
                    generics,
4028 4029 4030 4031 4032 4033
                    header: hir::FnHeader {
                        unsafety: hir::Unsafety::Unsafe,
                        abi: Abi::Rust,
                        constness: hir::Constness::NotConst,
                        asyncness: hir::IsAsync::NotAsync,
                    },
4034 4035
                })
            }
4036
            hir::ForeignItemStatic(ref ty, mutbl) => {
4037
                ForeignStaticItem(Static {
4038
                    type_: ty.clean(cx),
4039
                    mutability: if mutbl {Mutable} else {Immutable},
4040
                    expr: "".to_string(),
4041 4042
                })
            }
P
Paul Lietar 已提交
4043 4044 4045
            hir::ForeignItemType => {
                ForeignTypeItem
            }
4046 4047
        };
        Item {
V
Vadim Petrochenkov 已提交
4048
            name: Some(self.name.clean(cx)),
4049 4050
            attrs: self.attrs.clean(cx),
            source: self.span.clean(cx),
4051
            def_id: cx.tcx.hir.local_def_id(self.id),
4052
            visibility: self.vis.clean(cx),
4053 4054
            stability: get_stability(cx, cx.tcx.hir.local_def_id(self.id)),
            deprecation: get_deprecation(cx, cx.tcx.hir.local_def_id(self.id)),
4055
            inner,
4056 4057 4058 4059
        }
    }
}

C
Corey Richardson 已提交
4060 4061 4062
// Utilities

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

4066
impl ToSource for syntax_pos::Span {
4067
    fn to_src(&self, cx: &DocContext) -> String {
4068
        debug!("converting span {:?} to snippet", self.clean(cx));
4069
        let sn = match cx.sess().codemap().span_to_snippet(*self) {
4070 4071
            Ok(x) => x.to_string(),
            Err(_) => "".to_string()
C
Corey Richardson 已提交
4072
        };
4073
        debug!("got snippet {}", sn);
C
Corey Richardson 已提交
4074 4075 4076 4077
        sn
    }
}

4078
fn name_from_pat(p: &hir::Pat) -> String {
4079
    use rustc::hir::*;
4080
    debug!("Trying to get a name from pattern: {:?}", p);
4081

C
Corey Richardson 已提交
4082
    match p.node {
4083
        PatKind::Wild => "_".to_string(),
4084
        PatKind::Binding(_, _, ident, _) => ident.to_string(),
4085
        PatKind::TupleStruct(ref p, ..) | PatKind::Path(ref p) => qpath_to_string(p),
4086
        PatKind::Struct(ref name, ref fields, etc) => {
4087
            format!("{} {{ {}{} }}", qpath_to_string(name),
4088
                fields.iter().map(|&Spanned { node: ref fp, .. }|
4089
                                  format!("{}: {}", fp.ident, name_from_pat(&*fp.pat)))
4090
                             .collect::<Vec<String>>().join(", "),
4091 4092
                if etc { ", ..." } else { "" }
            )
4093
        }
4094
        PatKind::Tuple(ref elts, _) => format!("({})", elts.iter().map(|p| name_from_pat(&**p))
4095
                                            .collect::<Vec<String>>().join(", ")),
4096 4097 4098 4099
        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, \
4100
                  which is silly in function arguments");
4101
            "()".to_string()
4102
        },
4103
        PatKind::Range(..) => panic!("tried to get argument name from PatKind::Range, \
4104
                              which is not allowed in function arguments"),
4105
        PatKind::Slice(ref begin, ref mid, ref end) => {
4106 4107 4108
            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));
4109
            format!("[{}]", begin.chain(mid).chain(end).collect::<Vec<_>>().join(", "))
4110
        },
C
Corey Richardson 已提交
4111 4112 4113
    }
}

O
Oliver Schneider 已提交
4114 4115
fn print_const(cx: &DocContext, n: &ty::Const) -> String {
    match n.val {
4116
        ConstValue::Unevaluated(def_id, _) => {
O
Oliver Schneider 已提交
4117 4118 4119 4120 4121 4122
            if let Some(node_id) = cx.tcx.hir.as_local_node_id(def_id) {
                print_const_expr(cx, cx.tcx.hir.body_owned_by(node_id))
            } else {
                inline::print_inlined_const(cx, def_id)
            }
        },
4123
        _ => {
O
Oliver Schneider 已提交
4124
            let mut s = String::new();
4125
            ::rustc::mir::fmt_const_val(&mut s, n).unwrap();
O
Oliver Schneider 已提交
4126 4127 4128 4129 4130 4131 4132 4133 4134 4135
            // array lengths are obviously usize
            if s.ends_with("usize") {
                let n = s.len() - "usize".len();
                s.truncate(n);
            }
            s
        },
    }
}

4136
fn print_const_expr(cx: &DocContext, body: hir::BodyId) -> String {
4137
    cx.tcx.hir.node_to_pretty_string(body.node_id)
4138 4139
}

4140
/// Given a type Path, resolve it to a Type using the TyCtxt
N
Niko Matsakis 已提交
4141 4142
fn resolve_type(cx: &DocContext,
                path: Path,
4143
                id: ast::NodeId) -> Type {
4144 4145 4146 4147 4148
    if id == ast::DUMMY_NODE_ID {
        debug!("resolve_type({:?})", path);
    } else {
        debug!("resolve_type({:?},{:?})", path, id);
    }
4149

4150
    let is_generic = match path.def {
4151
        Def::PrimTy(p) => match p {
4152 4153 4154
            hir::TyStr => return Primitive(PrimitiveType::Str),
            hir::TyBool => return Primitive(PrimitiveType::Bool),
            hir::TyChar => return Primitive(PrimitiveType::Char),
4155
            hir::TyInt(int_ty) => return Primitive(int_ty.into()),
4156
            hir::TyUint(uint_ty) => return Primitive(uint_ty.into()),
4157
            hir::TyFloat(float_ty) => return Primitive(float_ty.into()),
C
Corey Richardson 已提交
4158
        },
4159
        Def::SelfTy(..) if path.segments.len() == 1 => {
4160
            return Generic(keywords::SelfType.name().to_string());
4161
        }
4162 4163 4164
        Def::TyParam(..) if path.segments.len() == 1 => {
            return Generic(format!("{:#}", path));
        }
4165
        Def::SelfTy(..) | Def::TyParam(..) | Def::AssociatedTy(..) => true,
4166
        _ => false,
4167
    };
4168
    let did = register_def(&*cx, path.def);
4169
    ResolvedPath { path: path, typarams: None, did: did, is_generic: is_generic }
4170 4171
}

4172
fn register_def(cx: &DocContext, def: Def) -> DefId {
4173 4174
    debug!("register_def({:?})", def);

4175
    let (did, kind) = match def {
4176 4177 4178 4179 4180 4181 4182
        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),
4183
        Def::TyForeign(i) => (i, TypeKind::Foreign),
4184
        Def::Const(i) => (i, TypeKind::Const),
4185
        Def::Static(i, _) => (i, TypeKind::Static),
4186
        Def::Variant(i) => (cx.tcx.parent_def_id(i).unwrap(), TypeKind::Enum),
M
Manish Goregaokar 已提交
4187
        Def::Macro(i, _) => (i, TypeKind::Macro),
4188
        Def::SelfTy(Some(def_id), _) => (def_id, TypeKind::Trait),
4189 4190
        Def::SelfTy(_, Some(impl_def_id)) => {
            return impl_def_id
4191
        }
4192
        _ => return def.def_id()
C
Corey Richardson 已提交
4193
    };
N
Niko Matsakis 已提交
4194
    if did.is_local() { return did }
4195
    inline::record_extern_fqn(cx, did, kind);
4196
    if let TypeKind::Trait = kind {
4197
        inline::record_extern_trait(cx, did);
4198
    }
M
mitaa 已提交
4199
    did
C
Corey Richardson 已提交
4200
}
A
Alex Crichton 已提交
4201

4202
fn resolve_use_source(cx: &DocContext, path: Path) -> ImportSource {
A
Alex Crichton 已提交
4203
    ImportSource {
4204 4205 4206 4207 4208
        did: if path.def == Def::Err {
            None
        } else {
            Some(register_def(cx, path.def))
        },
4209
        path,
A
Alex Crichton 已提交
4210 4211 4212
    }
}

J
Jorge Aparicio 已提交
4213
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
4214
pub struct Macro {
4215
    pub source: String,
4216
    pub imported_from: Option<String>,
4217 4218 4219
}

impl Clean<Item> for doctree::Macro {
4220
    fn clean(&self, cx: &DocContext) -> Item {
4221
        let name = self.name.clean(cx);
4222
        Item {
4223
            name: Some(name.clone()),
4224 4225
            attrs: self.attrs.clean(cx),
            source: self.whence.clean(cx),
J
Jeffrey Seyfried 已提交
4226
            visibility: Some(Public),
4227
            stability: self.stab.clean(cx),
4228
            deprecation: self.depr.clean(cx),
4229
            def_id: self.def_id,
4230
            inner: MacroItem(Macro {
4231
                source: format!("macro_rules! {} {{\n{}}}",
4232 4233 4234 4235
                                name,
                                self.matchers.iter().map(|span| {
                                    format!("    {} => {{ ... }};\n", span.to_src(cx))
                                }).collect::<String>()),
4236
                imported_from: self.imported_from.clean(cx),
4237 4238 4239 4240
            }),
        }
    }
}
4241

J
Jorge Aparicio 已提交
4242
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
4243
pub struct Stability {
V
Vadim Petrochenkov 已提交
4244
    pub level: stability::StabilityLevel,
4245 4246
    pub feature: String,
    pub since: String,
4247
    pub deprecated_since: String,
4248 4249
    pub deprecated_reason: String,
    pub unstable_reason: String,
4250
    pub issue: Option<u32>
4251 4252
}

4253 4254 4255 4256 4257 4258
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
pub struct Deprecation {
    pub since: String,
    pub note: String,
}

4259
impl Clean<Stability> for attr::Stability {
4260 4261
    fn clean(&self, _: &DocContext) -> Stability {
        Stability {
V
Vadim Petrochenkov 已提交
4262
            level: stability::StabilityLevel::from_attr_level(&self.level),
4263
            feature: self.feature.to_string(),
V
Vadim Petrochenkov 已提交
4264 4265 4266 4267
            since: match self.level {
                attr::Stable {ref since} => since.to_string(),
                _ => "".to_string(),
            },
4268 4269
            deprecated_since: match self.rustc_depr {
                Some(attr::RustcDeprecation {ref since, ..}) => since.to_string(),
V
Vadim Petrochenkov 已提交
4270 4271
                _=> "".to_string(),
            },
4272 4273 4274 4275 4276 4277 4278
            deprecated_reason: match self.rustc_depr {
                Some(ref depr) => depr.reason.to_string(),
                _ => "".to_string(),
            },
            unstable_reason: match self.level {
                attr::Unstable { reason: Some(ref reason), .. } => reason.to_string(),
                _ => "".to_string(),
V
Vadim Petrochenkov 已提交
4279 4280 4281 4282 4283
            },
            issue: match self.level {
                attr::Unstable {issue, ..} => Some(issue),
                _ => None,
            }
4284 4285 4286 4287 4288
        }
    }
}

impl<'a> Clean<Stability> for &'a attr::Stability {
V
Vadim Petrochenkov 已提交
4289 4290
    fn clean(&self, dc: &DocContext) -> Stability {
        (**self).clean(dc)
4291 4292
    }
}
A
Alex Crichton 已提交
4293

4294 4295 4296 4297 4298 4299 4300 4301 4302
impl Clean<Deprecation> for attr::Deprecation {
    fn clean(&self, _: &DocContext) -> Deprecation {
        Deprecation {
            since: self.since.as_ref().map_or("".to_string(), |s| s.to_string()),
            note: self.note.as_ref().map_or("".to_string(), |s| s.to_string()),
        }
    }
}

4303
/// An equality constraint on an associated type, e.g. `A=Bar` in `Foo<A=Bar>`
4304
#[derive(Clone, PartialEq, Eq, RustcDecodable, RustcEncodable, Debug, Hash)]
4305 4306 4307 4308 4309
pub struct TypeBinding {
    pub name: String,
    pub ty: Type
}

4310
impl Clean<TypeBinding> for hir::TypeBinding {
4311 4312
    fn clean(&self, cx: &DocContext) -> TypeBinding {
        TypeBinding {
4313
            name: self.ident.name.clean(cx),
4314 4315 4316 4317
            ty: self.ty.clean(cx)
        }
    }
}
4318 4319 4320 4321 4322 4323 4324 4325 4326 4327 4328 4329 4330 4331 4332

pub fn def_id_to_path(cx: &DocContext, did: DefId, name: Option<String>) -> Vec<String> {
    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()
}

4333
pub fn enter_impl_trait<F, R>(cx: &DocContext, f: F) -> R
4334 4335 4336
where
    F: FnOnce() -> R,
{
4337
    let old_bounds = mem::replace(&mut *cx.impl_trait_bounds.borrow_mut(), Default::default());
4338 4339 4340 4341 4342 4343
    let r = f();
    assert!(cx.impl_trait_bounds.borrow().is_empty());
    *cx.impl_trait_bounds.borrow_mut() = old_bounds;
    r
}

4344 4345 4346
// Start of code copied from rust-clippy

pub fn get_trait_def_id(tcx: &TyCtxt, path: &[&str], use_local: bool) -> Option<DefId> {
A
Aaron Hill 已提交
4347
    if use_local {
4348 4349 4350
        path_to_def_local(tcx, path)
    } else {
        path_to_def(tcx, path)
A
Aaron Hill 已提交
4351
    }
4352 4353 4354 4355 4356 4357 4358 4359 4360 4361 4362 4363 4364 4365 4366 4367 4368 4369 4370 4371 4372 4373 4374 4375 4376 4377 4378 4379 4380 4381 4382 4383 4384 4385 4386 4387 4388 4389 4390 4391 4392 4393 4394 4395 4396 4397 4398 4399 4400 4401 4402
}

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

    loop {
        let segment = match path_it.next() {
            Some(segment) => segment,
            None => return None,
        };

        for item_id in mem::replace(&mut items, HirVec::new()).iter() {
            let item = tcx.hir.expect_item(item_id.id);
            if item.name == *segment {
                if path_it.peek().is_none() {
                    return Some(tcx.hir.local_def_id(item_id.id))
                }

                items = match &item.node {
                    &hir::ItemMod(ref m) => m.item_ids.clone(),
                    _ => panic!("Unexpected item {:?} in path {:?} path")
                };
                break;
            }
        }
    }
}

pub fn path_to_def(tcx: &TyCtxt, path: &[&str]) -> Option<DefId> {
    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 {
            let segment = match path_it.next() {
                Some(segment) => segment,
                None => return None,
            };

4403
            for item in mem::replace(&mut items, Lrc::new(vec![])).iter() {
4404 4405 4406 4407
                if item.ident.name == *segment {
                    if path_it.peek().is_none() {
                        return match item.def {
                            def::Def::Trait(did) => Some(did),
A
Aaron Hill 已提交
4408
                            _ => None,
4409 4410 4411 4412 4413 4414 4415 4416 4417 4418 4419 4420 4421
                        }
                    }

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

4422 4423
fn get_path_for_type<F>(tcx: TyCtxt, def_id: DefId, def_ctor: F) -> hir::Path
where F: Fn(DefId) -> Def {
4424 4425 4426 4427 4428 4429 4430 4431 4432 4433 4434 4435 4436 4437 4438 4439 4440 4441 4442 4443 4444 4445 4446
    struct AbsolutePathBuffer {
        names: Vec<String>,
    }

    impl ty::item_path::ItemPathBuffer for AbsolutePathBuffer {
        fn root_mode(&self) -> &ty::item_path::RootMode {
            const ABSOLUTE: &'static ty::item_path::RootMode = &ty::item_path::RootMode::Absolute;
            ABSOLUTE
        }

        fn push(&mut self, text: &str) {
            self.names.push(text.to_owned());
        }
    }

    let mut apb = AbsolutePathBuffer { names: vec![] };

    tcx.push_item_path(&mut apb, def_id);

    hir::Path {
        span: DUMMY_SP,
        def: def_ctor(def_id),
        segments: hir::HirVec::from_vec(apb.names.iter().map(|s| hir::PathSegment {
4447
            ident: ast::Ident::from_str(&s),
V
varkor 已提交
4448
            args: None,
A
Aaron Hill 已提交
4449
            infer_types: false,
4450 4451 4452 4453 4454 4455 4456 4457 4458 4459 4460 4461 4462 4463 4464 4465 4466 4467 4468 4469 4470
        }).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 已提交
4471 4472
    TraitBound(Vec<PathSegment>, Vec<SimpleBound>, Vec<GenericParamDef>, hir::TraitBoundModifier),
    Outlives(Lifetime),
4473 4474 4475 4476 4477 4478 4479 4480 4481 4482 4483 4484
}

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

impl AutoTraitResult {
    fn is_auto(&self) -> bool {
        match *self {
            AutoTraitResult::PositiveImpl(_) | AutoTraitResult::NegativeImpl => true,
A
Aaron Hill 已提交
4485
            _ => false,
4486 4487 4488 4489
        }
    }
}

V
varkor 已提交
4490 4491
impl From<GenericBound> for SimpleBound {
    fn from(bound: GenericBound) -> Self {
4492
        match bound.clone() {
V
varkor 已提交
4493 4494
            GenericBound::Outlives(l) => SimpleBound::Outlives(l),
            GenericBound::TraitBound(t, mod_) => match t.trait_ {
4495 4496 4497 4498 4499 4500 4501 4502
                Type::ResolvedPath { path, typarams, .. } => {
                    SimpleBound::TraitBound(path.segments,
                                            typarams
                                                .map_or_else(|| Vec::new(), |v| v.iter()
                                                        .map(|p| SimpleBound::from(p.clone()))
                                                        .collect()),
                                            t.generic_params,
                                            mod_)
A
Aaron Hill 已提交
4503
                }
A
Aaron Hill 已提交
4504
                _ => panic!("Unexpected bound {:?}", bound),
4505 4506 4507 4508
            }
        }
    }
}