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

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

S
Steven Fackler 已提交
14 15 16 17 18 19
pub use self::Type::*;
pub use self::Mutability::*;
pub use self::ItemEnum::*;
pub use self::TyParamBound::*;
pub use self::SelfTy::*;
pub use self::FunctionRetTy::*;
J
Jeffrey Seyfried 已提交
20
pub use self::Visibility::*;
S
Steven Fackler 已提交
21

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

33
use rustc::middle::const_val::ConstVal;
M
mitaa 已提交
34
use rustc::middle::privacy::AccessLevels;
35
use rustc::middle::resolve_lifetime as rl;
36
use rustc::ty::fold::TypeFolder;
37
use rustc::middle::lang_items;
38
use rustc::mir::interpret::GlobalId;
39 40 41 42
use rustc::hir::{self, HirVec};
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;
43
use rustc::ty::subst::Substs;
44
use rustc::ty::{self, TyCtxt, Region, RegionVid, Ty, AdtKind, Kind};
45
use rustc::middle::stability;
46
use rustc::util::nodemap::{FxHashMap, FxHashSet};
47
use rustc_typeck::hir_ty_to_ty;
48 49 50
use rustc::infer::region_constraints::{RegionConstraintData, Constraint};
use std::collections::hash_map::Entry;
use std::fmt;
51

52
use std::default::Default;
M
Manish Goregaokar 已提交
53
use std::{mem, slice, vec};
54
use std::iter::{FromIterator, once};
55
use rustc_data_structures::sync::Lrc;
56
use std::rc::Rc;
57
use std::cell::RefCell;
M
mitaa 已提交
58
use std::sync::Arc;
59
use std::u32;
60

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

68
pub mod inline;
K
kennytm 已提交
69
pub mod cfg;
70
mod simplify;
71
mod auto_trait;
72

K
kennytm 已提交
73
use self::cfg::Cfg;
74 75 76 77 78
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 已提交
79

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

85
fn get_deprecation(cx: &DocContext, def_id: DefId) -> Option<Deprecation> {
86
    cx.tcx.lookup_deprecation(def_id).clean(cx)
87 88
}

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

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

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

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

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

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

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

M
mitaa 已提交
129
#[derive(Clone, Debug)]
C
Corey Richardson 已提交
130
pub struct Crate {
131
    pub name: String,
132
    pub version: Option<String>,
133
    pub src: FileName,
134
    pub module: Option<Item>,
135 136
    pub externs: Vec<(CrateNum, ExternalCrate)>,
    pub primitives: Vec<(DefId, PrimitiveType, Attributes)>,
M
mitaa 已提交
137 138 139
    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.
140
    pub external_traits: FxHashMap<DefId, Trait>,
141
    pub masked_crates: FxHashSet<CrateNum>,
C
Corey Richardson 已提交
142 143
}

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

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

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

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

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

179
        let ExternalCrate { name, src, primitives, .. } = LOCAL_CRATE.clean(cx);
180 181 182 183 184
        {
            let m = match module.inner {
                ModuleItem(ref mut m) => m,
                _ => unreachable!(),
            };
185 186
            m.items.extend(primitives.iter().map(|&(def_id, prim, ref attrs)| {
                Item {
187 188
                    source: Span::empty(),
                    name: Some(prim.to_url_str().to_string()),
189
                    attrs: attrs.clone(),
J
Jeffrey Seyfried 已提交
190
                    visibility: Some(Public),
191 192
                    stability: get_stability(cx, def_id),
                    deprecation: get_deprecation(cx, def_id),
193
                    def_id,
194
                    inner: PrimitiveItem(prim),
195
                }
196 197
            }));
        }
198

M
mitaa 已提交
199 200 201
        let mut access_levels = cx.access_levels.borrow_mut();
        let mut external_traits = cx.external_traits.borrow_mut();

C
Corey Richardson 已提交
202
        Crate {
203
            name,
204
            version: None,
205
            src,
206
            module: Some(module),
207 208
            externs,
            primitives,
M
mitaa 已提交
209 210
            access_levels: Arc::new(mem::replace(&mut access_levels, Default::default())),
            external_traits: mem::replace(&mut external_traits, Default::default()),
211
            masked_crates,
212 213 214 215
        }
    }
}

J
Jorge Aparicio 已提交
216
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
217
pub struct ExternalCrate {
218
    pub name: String,
219
    pub src: FileName,
220
    pub attrs: Attributes,
221
    pub primitives: Vec<(DefId, PrimitiveType, Attributes)>,
222 223
}

A
Ariel Ben-Yehuda 已提交
224
impl Clean<ExternalCrate> for CrateNum {
225
    fn clean(&self, cx: &DocContext) -> ExternalCrate {
226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257
        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;
                            }
258
                            // FIXME: should warn on unknown primitives?
259 260 261 262 263 264 265 266
                        }
                    }
                }
                return prim.map(|p| (def_id, p, attrs));
            }
            None
        };
        let primitives = if root.is_local() {
267 268
            cx.tcx.hir.krate().module.item_ids.iter().filter_map(|&id| {
                let item = cx.tcx.hir.expect_item(id.id);
269 270
                match item.node {
                    hir::ItemMod(_) => {
271
                        as_primitive(Def::Mod(cx.tcx.hir.local_def_id(id.id)))
272 273 274 275 276
                    }
                    hir::ItemUse(ref path, hir::UseKind::Single)
                    if item.vis == hir::Visibility::Public => {
                        as_primitive(path.def).map(|(_, prim, attrs)| {
                            // Pretend the primitive is local.
277
                            (cx.tcx.hir.local_def_id(id.id), prim, attrs)
278 279 280 281 282 283
                        })
                    }
                    _ => None
                }
            }).collect()
        } else {
284
            cx.tcx.item_children(root).iter().map(|item| item.def)
285 286 287
              .filter_map(as_primitive).collect()
        };

288
        ExternalCrate {
289
            name: cx.tcx.crate_name(*self).to_string(),
290
            src: krate_src,
291
            attrs: cx.tcx.get_attrs(root).clean(cx),
292
            primitives,
C
Corey Richardson 已提交
293 294 295 296 297 298 299
        }
    }
}

/// 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.
300
#[derive(Clone, RustcEncodable, RustcDecodable)]
C
Corey Richardson 已提交
301 302
pub struct Item {
    /// Stringified span
303
    pub source: Span,
C
Corey Richardson 已提交
304
    /// Not everything has a name. E.g., impls
305
    pub name: Option<String>,
306
    pub attrs: Attributes,
307 308
    pub inner: ItemEnum,
    pub visibility: Option<Visibility>,
N
Niko Matsakis 已提交
309
    pub def_id: DefId,
310
    pub stability: Option<Stability>,
311
    pub deprecation: Option<Deprecation>,
C
Corey Richardson 已提交
312 313
}

314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333
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()
    }
}

334 335 336 337
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> {
338
        self.attrs.doc_value()
339
    }
340 341 342 343 344
    /// 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()
    }
345 346

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

M
mitaa 已提交
350 351
    pub fn is_crate(&self) -> bool {
        match self.inner {
352 353 354
            StrippedItem(box ModuleItem(Module { is_crate: true, ..})) |
            ModuleItem(Module { is_crate: true, ..}) => true,
            _ => false,
M
mitaa 已提交
355 356
        }
    }
357
    pub fn is_mod(&self) -> bool {
358
        self.type_() == ItemType::Module
359 360
    }
    pub fn is_trait(&self) -> bool {
361
        self.type_() == ItemType::Trait
362 363
    }
    pub fn is_struct(&self) -> bool {
364
        self.type_() == ItemType::Struct
365 366
    }
    pub fn is_enum(&self) -> bool {
367
        self.type_() == ItemType::Enum
368 369
    }
    pub fn is_fn(&self) -> bool {
370
        self.type_() == ItemType::Function
371
    }
M
mitaa 已提交
372
    pub fn is_associated_type(&self) -> bool {
373
        self.type_() == ItemType::AssociatedType
M
mitaa 已提交
374 375
    }
    pub fn is_associated_const(&self) -> bool {
376
        self.type_() == ItemType::AssociatedConst
M
mitaa 已提交
377 378
    }
    pub fn is_method(&self) -> bool {
379
        self.type_() == ItemType::Method
M
mitaa 已提交
380 381
    }
    pub fn is_ty_method(&self) -> bool {
382
        self.type_() == ItemType::TyMethod
383
    }
384 385 386
    pub fn is_typedef(&self) -> bool {
        self.type_() == ItemType::Typedef
    }
387
    pub fn is_primitive(&self) -> bool {
388
        self.type_() == ItemType::Primitive
389
    }
390 391 392
    pub fn is_union(&self) -> bool {
        self.type_() == ItemType::Union
    }
G
Guillaume Gomez 已提交
393 394 395
    pub fn is_import(&self) -> bool {
        self.type_() == ItemType::Import
    }
396 397 398
    pub fn is_extern_crate(&self) -> bool {
        self.type_() == ItemType::ExternCrate
    }
G
Guillaume Gomez 已提交
399

400 401
    pub fn is_stripped(&self) -> bool {
        match self.inner { StrippedItem(..) => true, _ => false }
M
mitaa 已提交
402
    }
403 404 405
    pub fn has_stripped_fields(&self) -> Option<bool> {
        match self.inner {
            StructItem(ref _struct) => Some(_struct.fields_stripped),
V
Vadim Petrochenkov 已提交
406
            UnionItem(ref union) => Some(union.fields_stripped),
407
            VariantItem(Variant { kind: VariantKind::Struct(ref vstruct)} ) => {
408 409 410 411 412
                Some(vstruct.fields_stripped)
            },
            _ => None,
        }
    }
413

414
    pub fn stability_class(&self) -> Option<String> {
415 416
        self.stability.as_ref().and_then(|ref s| {
            let mut classes = Vec::with_capacity(2);
417

418 419 420
            if s.level == stability::Unstable {
                classes.push("unstable");
            }
421

422 423 424
            if !s.deprecated_since.is_empty() {
                classes.push("deprecated");
            }
425

426 427 428 429
            if classes.len() != 0 {
                Some(classes.join(" "))
            } else {
                None
430
            }
431
        })
432
    }
433 434

    pub fn stable_since(&self) -> Option<&str> {
M
mitaa 已提交
435
        self.stability.as_ref().map(|s| &s.since[..])
436
    }
437 438 439 440 441

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

J
Jorge Aparicio 已提交
444
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
445
pub enum ItemEnum {
446 447
    ExternCrateItem(String, Option<String>),
    ImportItem(Import),
C
Corey Richardson 已提交
448
    StructItem(Struct),
V
Vadim Petrochenkov 已提交
449
    UnionItem(Union),
C
Corey Richardson 已提交
450 451 452
    EnumItem(Enum),
    FunctionItem(Function),
    ModuleItem(Module),
453
    TypedefItem(Typedef, bool /* is associated type */),
C
Corey Richardson 已提交
454
    StaticItem(Static),
455
    ConstantItem(Constant),
C
Corey Richardson 已提交
456 457
    TraitItem(Trait),
    ImplItem(Impl),
458 459
    /// A method signature only. Used for required methods in traits (ie,
    /// non-default-methods).
C
Corey Richardson 已提交
460
    TyMethodItem(TyMethod),
461
    /// A method with a body.
C
Corey Richardson 已提交
462
    MethodItem(Method),
463
    StructFieldItem(Type),
C
Corey Richardson 已提交
464
    VariantItem(Variant),
465
    /// `fn`s from an extern block
466
    ForeignFunctionItem(Function),
467
    /// `static`s from an extern block
468
    ForeignStaticItem(Static),
P
Paul Lietar 已提交
469 470
    /// `type`s from an extern block
    ForeignTypeItem,
471
    MacroItem(Macro),
472
    PrimitiveItem(PrimitiveType),
473
    AssociatedConstItem(Type, Option<String>),
474
    AssociatedTypeItem(Vec<TyParamBound>, Option<Type>),
475 476
    /// An item that has been stripped by a rustdoc pass
    StrippedItem(Box<ItemEnum>),
C
Corey Richardson 已提交
477 478
}

479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495
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 已提交
496
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
497
pub struct Module {
498 499
    pub items: Vec<Item>,
    pub is_crate: bool,
C
Corey Richardson 已提交
500 501 502
}

impl Clean<Item> for doctree::Module {
503
    fn clean(&self, cx: &DocContext) -> Item {
C
Corey Richardson 已提交
504
        let name = if self.name.is_some() {
505
            self.name.unwrap().clean(cx)
C
Corey Richardson 已提交
506
        } else {
507
            "".to_string()
C
Corey Richardson 已提交
508
        };
509

510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525
        // 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 已提交
526

527 528
        let mut items: Vec<Item> = vec![];
        items.extend(self.extern_crates.iter().map(|x| x.clean(cx)));
529
        items.extend(self.imports.iter().flat_map(|x| x.clean(cx)));
530 531 532
        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)));
533
        items.extend(self.fns.iter().map(|x| x.clean(cx)));
534
        items.extend(self.foreigns.iter().flat_map(|x| x.clean(cx)));
535 536 537 538 539
        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)));
540
        items.extend(self.impls.iter().flat_map(|x| x.clean(cx)));
541
        items.extend(self.macros.iter().map(|x| x.clean(cx)));
542

M
Manish Goregaokar 已提交
543 544
        cx.mod_ids.borrow_mut().pop();

545 546
        // determine if we should display the inner contents or
        // the outer `mod` item for the source code.
547
        let whence = {
548
            let cm = cx.sess().codemap();
549 550
            let outer = cm.lookup_char_pos(self.where_outer.lo());
            let inner = cm.lookup_char_pos(self.where_inner.lo());
551 552 553 554 555 556 557 558 559
            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 已提交
560 561
        Item {
            name: Some(name),
562
            attrs,
563 564 565
            source: whence.clean(cx),
            visibility: self.vis.clean(cx),
            stability: self.stab.clean(cx),
566
            deprecation: self.depr.clean(cx),
567
            def_id: cx.tcx.hir.local_def_id(self.id),
C
Corey Richardson 已提交
568
            inner: ModuleItem(Module {
569
               is_crate: self.is_crate,
570
               items,
C
Corey Richardson 已提交
571 572 573 574 575
            })
        }
    }
}

576 577
pub struct ListAttributesIter<'a> {
    attrs: slice::Iter<'a, ast::Attribute>,
578
    current_list: vec::IntoIter<ast::NestedMetaItem>,
579
    name: &'a str
M
mitaa 已提交
580 581
}

582
impl<'a> Iterator for ListAttributesIter<'a> {
583
    type Item = ast::NestedMetaItem;
584 585 586 587

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

590
        for attr in &mut self.attrs {
591
            if let Some(list) = attr.meta_item_list() {
592
                if attr.check_name(self.name) {
593
                    self.current_list = list.into_iter();
594 595 596
                    if let Some(nested) = self.current_list.next() {
                        return Some(nested);
                    }
M
mitaa 已提交
597 598 599
                }
            }
        }
600

M
mitaa 已提交
601 602
        None
    }
603 604 605 606 607

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

610
pub trait AttributesExt {
M
mitaa 已提交
611
    /// Finds an attribute as List and returns the list of attributes nested inside.
E
est31 已提交
612
    fn lists<'a>(&'a self, name: &'a str) -> ListAttributesIter<'a>;
613 614 615 616 617 618
}

impl AttributesExt for [ast::Attribute] {
    fn lists<'a>(&'a self, name: &'a str) -> ListAttributesIter<'a> {
        ListAttributesIter {
            attrs: self.iter(),
619
            current_list: Vec::new().into_iter(),
620
            name,
M
mitaa 已提交
621 622 623 624
        }
    }
}

625 626
pub trait NestedAttributesExt {
    /// Returns whether the attribute list contains a specific `Word`
E
est31 已提交
627
    fn has_word(self, word: &str) -> bool;
628 629
}

630
impl<I: IntoIterator<Item=ast::NestedMetaItem>> NestedAttributesExt for I {
631 632 633 634 635
    fn has_word(self, word: &str) -> bool {
        self.into_iter().any(|attr| attr.is_word() && attr.check_name(word))
    }
}

636 637 638 639 640 641 642 643
/// 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.
644
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)]
645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695
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
        })
    }
}

696
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Default, Hash)]
697
pub struct Attributes {
698
    pub doc_strings: Vec<DocFragment>,
699
    pub other_attrs: Vec<ast::Attribute>,
J
John Kåre Alsaker 已提交
700
    pub cfg: Option<Arc<Cfg>>,
701
    pub span: Option<syntax_pos::Span>,
M
Manish Goregaokar 已提交
702
    /// map from Rust paths to resolved defs and potential URL fragments
G
Guillaume Gomez 已提交
703
    pub links: Vec<(String, Option<DefId>, Option<String>)>,
704 705 706
}

impl Attributes {
K
kennytm 已提交
707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729
    /// 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
    }

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 758 759 760 761 762 763 764 765 766 767 768 769 770
    /// 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
        })
    }

771
    pub fn has_doc_flag(&self, flag: &str) -> bool {
772 773 774 775
        for attr in &self.other_attrs {
            if !attr.check_name("doc") { continue; }

            if let Some(items) = attr.meta_item_list() {
776
                if items.iter().filter_map(|i| i.meta_item()).any(|it| it.check_name(flag)) {
777 778 779 780 781 782 783 784
                    return true;
                }
            }
        }

        false
    }

785 786
    pub fn from_ast(diagnostic: &::errors::Handler,
                    attrs: &[ast::Attribute]) -> Attributes {
787
        let mut doc_strings = vec![];
788
        let mut sp = None;
K
kennytm 已提交
789
        let mut cfg = Cfg::True;
790
        let mut doc_line = 0;
K
kennytm 已提交
791

792 793
        let other_attrs = attrs.iter().filter_map(|attr| {
            attr.with_desugared_doc(|attr| {
K
kennytm 已提交
794 795 796 797
                if attr.check_name("doc") {
                    if let Some(mi) = attr.meta() {
                        if let Some(value) = mi.value_str() {
                            // Extracted #[doc = "..."]
798 799 800 801 802 803 804 805 806 807
                            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 已提交
808 809 810 811 812 813 814 815 816 817 818
                            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;
819 820 821 822 823 824 825 826
                        } 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));
827
                        }
828 829 830 831 832
                    }
                }
                Some(attr.clone())
            })
        }).collect();
833

834 835 836 837 838
        // 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() {
839 840
                    let meta = attr::mk_name_value_item_str(Ident::from_str("target_feature"),
                                                            dummy_spanned(feat));
841 842 843 844 845 846 847
                    if let Ok(feat_cfg) = Cfg::parse(&meta) {
                        cfg &= feat_cfg;
                    }
                }
            }
        }

848
        Attributes {
K
kennytm 已提交
849 850
            doc_strings,
            other_attrs,
J
John Kåre Alsaker 已提交
851
            cfg: if cfg == Cfg::True { None } else { Some(Arc::new(cfg)) },
852
            span: sp,
853
            links: vec![],
854 855
        }
    }
856 857 858 859

    /// Finds the `doc` attribute as a NameValue and returns the corresponding
    /// value found.
    pub fn doc_value<'a>(&'a self) -> Option<&'a str> {
860 861 862 863 864 865 866 867 868 869 870
        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
        }
871
    }
872 873 874 875

    /// Get links as a vector
    ///
    /// Cache must be populated before call
G
Guillaume Gomez 已提交
876
    pub fn links(&self, krate: &CrateNum) -> Vec<(String, String)> {
877
        use html::format::href;
M
Manish Goregaokar 已提交
878
        self.links.iter().filter_map(|&(ref s, did, ref fragment)| {
G
Guillaume Gomez 已提交
879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909
            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 已提交
910
                }
911 912 913
            }
        }).collect()
    }
C
Corey Richardson 已提交
914 915
}

916 917 918
impl AttributesExt for Attributes {
    fn lists<'a>(&'a self, name: &'a str) -> ListAttributesIter<'a> {
        self.other_attrs.lists(name)
C
Corey Richardson 已提交
919 920 921
    }
}

922 923 924 925 926 927 928
/// 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 已提交
929 930
        // structs, variants, and mods exist in both namespaces. skip them
        Def::StructCtor(..) | Def::Mod(..) | Def::Variant(..) | Def::VariantCtor(..) => None,
931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963
        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))
}

fn ambiguity_error(cx: &DocContext, attrs: &Attributes,
                   path_str: &str,
                   article1: &str, kind1: &str, disambig1: &str,
                   article2: &str, kind2: &str, disambig2: &str) {
    let sp = attrs.doc_strings.first()
                  .map_or(DUMMY_SP, |a| a.span());
    cx.sess()
M
Manish Goregaokar 已提交
964 965 966 967
      .struct_span_warn(sp,
                        &format!("`{}` is both {} {} and {} {}",
                                 path_str, article1, kind1,
                                 article2, kind2))
968 969 970
      .help(&format!("try `{}` if you want to select the {}, \
                      or `{}` if you want to \
                      select the {}",
971 972
                      disambig1, kind1, disambig2,
                      kind2))
973
      .emit();
974 975
}

M
Manish Goregaokar 已提交
976 977 978 979 980 981 982 983 984 985 986 987 988 989
/// 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 已提交
990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017
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)
    }
}

1018
/// Resolve a given string as a path, along with whether or not it is
M
Manish Goregaokar 已提交
1019 1020 1021
/// 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>), ()> {
1022 1023 1024
    // 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 已提交
1025 1026 1027 1028 1029 1030 1031
        let result = cx.resolver.borrow_mut()
                                .with_scope(*id,
            |resolver| {
                resolver.resolve_str_path_error(DUMMY_SP,
                                                &path_str, is_val)
        });

M
Manish Goregaokar 已提交
1032 1033 1034 1035 1036 1037
        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,
                Def::AssociatedTy(_)  => false,
M
Manish Goregaokar 已提交
1038
                Def::Variant(_) => return handle_variant(cx, result.def),
M
Manish Goregaokar 已提交
1039 1040 1041 1042 1043 1044 1045
                // not a trait item, just return what we found
                _ => return Ok((result.def, None))
            };

            if value != is_val {
                return Err(())
            }
G
Guillaume Gomez 已提交
1046 1047
        } else if let Some(prim) = is_primitive(path_str, is_val) {
            return Ok((prim, Some(path_str.to_owned())))
M
Manish Goregaokar 已提交
1048 1049 1050 1051 1052 1053 1054
        } 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 已提交
1055 1056
        }

M
Manish Goregaokar 已提交
1057
        // Try looking for methods and associated items
M
Manish Goregaokar 已提交
1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073
        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| {
1074
                resolver.resolve_str_path_error(DUMMY_SP, &path, false)
M
Manish Goregaokar 已提交
1075 1076 1077 1078 1079 1080 1081
        })?;
        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))
                                 .find(|item| item.name == item_name);
                if let Some(item) = item {
1082 1083 1084 1085 1086 1087
                    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 已提交
1088
                } else {
1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109
                    let is_enum = match ty.def {
                        Def::Enum(_) => true,
                        _ => false,
                    };
                    let elem = if is_enum {
                        cx.tcx.adt_def(did).all_fields().find(|item| item.name == item_name)
                    } else {
                        cx.tcx.adt_def(did)
                              .non_enum_variant()
                              .fields
                              .iter()
                              .find(|item| item.name == item_name)
                    };
                    if let Some(item) = elem {
                        Ok((ty.def,
                            Some(format!("{}.{}",
                                         if is_enum { "variant" } else { "structfield" },
                                         item.name))))
                    } else {
                        Err(())
                    }
M
Manish Goregaokar 已提交
1110 1111
                }
            }
M
Manish Goregaokar 已提交
1112 1113 1114 1115 1116 1117 1118 1119
            Def::Trait(did) => {
                let item = cx.tcx.associated_item_def_ids(did).iter()
                             .map(|item| cx.tcx.associated_item(*item))
                             .find(|item| item.name == item_name);
                if let Some(item) = item {
                    let kind = match item.kind {
                        ty::AssociatedKind::Const if is_val => "associatedconstant",
                        ty::AssociatedKind::Type if !is_val => "associatedtype",
1120 1121 1122 1123 1124 1125 1126
                        ty::AssociatedKind::Method if is_val => {
                            if item.defaultness.has_value() {
                                "method"
                            } else {
                                "tymethod"
                            }
                        }
M
Manish Goregaokar 已提交
1127 1128 1129 1130 1131 1132 1133
                        _ => return Err(())
                    };

                    Ok((ty.def, Some(format!("{}.{}", kind, item_name))))
                } else {
                    Err(())
                }
M
Manish Goregaokar 已提交
1134 1135 1136
            }
            _ => Err(())
        }
1137
    } else {
1138
        Err(())
1139 1140 1141
    }
}

1142 1143
/// Resolve a string as a macro
fn macro_resolve(cx: &DocContext, path_str: &str) -> Option<Def> {
1144
    use syntax::ext::base::{MacroKind, SyntaxExtension};
1145
    use syntax::ext::hygiene::Mark;
1146
    let segment = ast::PathSegment::from_ident(Ident::from_str(path_str));
1147
    let path = ast::Path { segments: vec![segment], span: DUMMY_SP };
1148 1149 1150 1151 1152
    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 {
1153 1154 1155 1156 1157
        if let SyntaxExtension::DeclMacro(..) = *resolver.get_macro(def) {
            Some(def)
        } else {
            None
        }
1158
    } else if let Some(def) = resolver.all_macros.get(&Symbol::intern(path_str)) {
1159 1160 1161 1162 1163 1164
        Some(*def)
    } else {
        None
    }
}

1165
#[derive(Debug)]
M
Manish Goregaokar 已提交
1166 1167 1168 1169 1170 1171 1172 1173
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
1174
    Type,
M
Manish Goregaokar 已提交
1175
}
1176

1177 1178 1179 1180
fn resolution_failure(cx: &DocContext, path_str: &str) {
    cx.sess().warn(&format!("[{}] cannot be resolved, ignoring it...", path_str));
}

1181
impl Clean<Attributes> for [ast::Attribute] {
K
kennytm 已提交
1182
    fn clean(&self, cx: &DocContext) -> Attributes {
1183 1184 1185 1186
        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);
1187
            for ori_link in markdown_links(&dox) {
1188
                // bail early for real links
1189
                if ori_link.contains('/') {
1190 1191
                    continue;
                }
1192 1193
                let link = ori_link.replace("`", "");
                let (def, fragment) = {
M
Manish Goregaokar 已提交
1194
                    let mut kind = PathKind::Unknown;
Q
QuietMisdreavus 已提交
1195
                    let path_str = if let Some(prefix) =
1196 1197
                        ["struct@", "enum@", "type@",
                         "trait@", "union@"].iter()
M
Manish Goregaokar 已提交
1198
                                          .find(|p| link.starts_with(**p)) {
M
Manish Goregaokar 已提交
1199
                        kind = PathKind::Type;
1200
                        link.trim_left_matches(prefix)
Q
QuietMisdreavus 已提交
1201
                    } else if let Some(prefix) =
1202
                        ["const@", "static@",
M
Manish Goregaokar 已提交
1203 1204
                         "value@", "function@", "mod@",
                         "fn@", "module@", "method@"]
1205
                            .iter().find(|p| link.starts_with(**p)) {
M
Manish Goregaokar 已提交
1206
                        kind = PathKind::Value;
1207
                        link.trim_left_matches(prefix)
Q
QuietMisdreavus 已提交
1208
                    } else if link.ends_with("()") {
M
Manish Goregaokar 已提交
1209
                        kind = PathKind::Value;
1210
                        link.trim_right_matches("()")
1211 1212 1213
                    } else if link.starts_with("macro@") {
                        kind = PathKind::Macro;
                        link.trim_left_matches("macro@")
M
Manish Goregaokar 已提交
1214 1215
                    } else if link.ends_with('!') {
                        kind = PathKind::Macro;
1216
                        link.trim_right_matches('!')
Q
QuietMisdreavus 已提交
1217
                    } else {
1218 1219
                        &link[..]
                    }.trim();
Q
QuietMisdreavus 已提交
1220

M
Manish Goregaokar 已提交
1221 1222
                    if path_str.contains(|ch: char| !(ch.is_alphanumeric() ||
                                                      ch == ':' || ch == '_')) {
1223 1224 1225
                        continue;
                    }

M
Manish Goregaokar 已提交
1226 1227
                    match kind {
                        PathKind::Value => {
M
Manish Goregaokar 已提交
1228 1229
                            if let Ok(def) = resolve(cx, path_str, true) {
                                def
M
Manish Goregaokar 已提交
1230
                            } else {
1231
                                resolution_failure(cx, path_str);
M
Manish Goregaokar 已提交
1232 1233 1234 1235 1236
                                // 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;
                            }
1237
                        }
M
Manish Goregaokar 已提交
1238
                        PathKind::Type => {
M
Manish Goregaokar 已提交
1239 1240
                            if let Ok(def) = resolve(cx, path_str, false) {
                                def
M
Manish Goregaokar 已提交
1241
                            } else {
1242
                                resolution_failure(cx, path_str);
M
Manish Goregaokar 已提交
1243 1244 1245 1246 1247
                                // this could just be a normal link
                                continue;
                            }
                        }
                        PathKind::Unknown => {
1248
                            // try everything!
1249
                            if let Some(macro_def) = macro_resolve(cx, path_str) {
M
Manish Goregaokar 已提交
1250
                                if let Ok(type_def) = resolve(cx, path_str, false) {
1251
                                    let (type_kind, article, type_disambig)
M
Manish Goregaokar 已提交
1252
                                        = type_ns_kind(type_def.0, path_str);
1253 1254 1255 1256
                                    ambiguity_error(cx, &attrs, path_str,
                                                    article, type_kind, &type_disambig,
                                                    "a", "macro", &format!("macro@{}", path_str));
                                    continue;
M
Manish Goregaokar 已提交
1257
                                } else if let Ok(value_def) = resolve(cx, path_str, true) {
1258
                                    let (value_kind, value_disambig)
M
Manish Goregaokar 已提交
1259
                                        = value_ns_kind(value_def.0, path_str)
1260 1261 1262 1263 1264 1265
                                            .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 已提交
1266
                                (macro_def, None)
M
Manish Goregaokar 已提交
1267
                            } else if let Ok(type_def) = resolve(cx, path_str, false) {
1268 1269 1270
                                // 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.
1271
                                // if there is something in both namespaces
M
Manish Goregaokar 已提交
1272
                                if let Ok(value_def) = resolve(cx, path_str, true) {
M
Manish Goregaokar 已提交
1273
                                    let kind = value_ns_kind(value_def.0, path_str);
1274 1275
                                    if let Some((value_kind, value_disambig)) = kind {
                                        let (type_kind, article, type_disambig)
M
Manish Goregaokar 已提交
1276
                                            = type_ns_kind(type_def.0, path_str);
1277 1278 1279
                                        ambiguity_error(cx, &attrs, path_str,
                                                        article, type_kind, &type_disambig,
                                                        "a", value_kind, &value_disambig);
1280 1281 1282
                                        continue;
                                    }
                                }
M
Manish Goregaokar 已提交
1283 1284 1285
                                type_def
                            } else if let Ok(value_def) = resolve(cx, path_str, true) {
                                value_def
M
Manish Goregaokar 已提交
1286
                            } else {
1287
                                resolution_failure(cx, path_str);
M
Manish Goregaokar 已提交
1288 1289 1290 1291 1292
                                // this could just be a normal link
                                continue;
                            }
                        }
                        PathKind::Macro => {
1293
                            if let Some(def) = macro_resolve(cx, path_str) {
M
Manish Goregaokar 已提交
1294
                                (def, None)
M
Manish Goregaokar 已提交
1295
                            } else {
1296
                                resolution_failure(cx, path_str);
1297
                                continue
M
Manish Goregaokar 已提交
1298
                            }
1299 1300
                        }
                    }
1301 1302
                };

G
Guillaume Gomez 已提交
1303 1304 1305 1306 1307 1308
                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));
                }
1309
            }
1310 1311

            cx.sess().abort_if_errors();
1312 1313 1314
        }

        attrs
C
Corey Richardson 已提交
1315 1316 1317
    }
}

1318
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)]
C
Corey Richardson 已提交
1319
pub struct TyParam {
1320
    pub name: String,
N
Niko Matsakis 已提交
1321
    pub did: DefId,
1322
    pub bounds: Vec<TyParamBound>,
1323
    pub default: Option<Type>,
1324
    pub synthetic: Option<hir::SyntheticTyParamKind>,
1325
}
C
Corey Richardson 已提交
1326

1327
impl Clean<TyParam> for hir::TyParam {
1328
    fn clean(&self, cx: &DocContext) -> TyParam {
C
Corey Richardson 已提交
1329
        TyParam {
1330
            name: self.name.clean(cx),
1331
            did: cx.tcx.hir.local_def_id(self.id),
1332
            bounds: self.bounds.clean(cx),
1333
            default: self.default.clean(cx),
1334
            synthetic: self.synthetic,
C
Corey Richardson 已提交
1335 1336 1337 1338
        }
    }
}

1339
impl<'tcx> Clean<TyParam> for ty::TypeParamDef {
1340
    fn clean(&self, cx: &DocContext) -> TyParam {
M
mitaa 已提交
1341
        cx.renderinfo.borrow_mut().external_typarams.insert(self.def_id, self.name.clean(cx));
1342
        TyParam {
1343
            name: self.name.clean(cx),
1344
            did: self.def_id,
1345
            bounds: vec![], // these are filled in from the where-clauses
1346
            default: if self.has_default {
1347
                Some(cx.tcx.type_of(self.def_id).clean(cx))
1348 1349
            } else {
                None
1350 1351
            },
            synthetic: None,
1352 1353 1354 1355
        }
    }
}

1356
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)]
C
Corey Richardson 已提交
1357
pub enum TyParamBound {
1358
    RegionBound(Lifetime),
1359
    TraitBound(PolyTrait, hir::TraitBoundModifier)
C
Corey Richardson 已提交
1360 1361
}

1362 1363
impl TyParamBound {
    fn maybe_sized(cx: &DocContext) -> TyParamBound {
1364
        let did = cx.tcx.require_lang_item(lang_items::SizedTraitLangItem);
1365
        let empty = cx.tcx.intern_substs(&[]);
1366
        let path = external_path(cx, &cx.tcx.item_name(did).as_str(),
1367 1368 1369 1370
            Some(did), false, vec![], empty);
        inline::record_extern_fqn(cx, did, TypeKind::Trait);
        TraitBound(PolyTrait {
            trait_: ResolvedPath {
1371
                path,
1372
                typarams: None,
1373
                did,
1374 1375
                is_generic: false,
            },
1376
            generic_params: Vec::new(),
1377
        }, hir::TraitBoundModifier::Maybe)
1378 1379 1380
    }

    fn is_sized_bound(&self, cx: &DocContext) -> bool {
1381
        use rustc::hir::TraitBoundModifier as TBM;
1382
        if let TyParamBound::TraitBound(PolyTrait { ref trait_, .. }, TBM::None) = *self {
1383
            if trait_.def_id() == cx.tcx.lang_items().sized_trait() {
1384
                return true;
1385 1386 1387 1388
            }
        }
        false
    }
1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403

    fn get_poly_trait(&self) -> Option<PolyTrait> {
        if let TyParamBound::TraitBound(ref p, _) = *self {
            return Some(p.clone())
        }
        None
    }

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

        if let TyParamBound::TraitBound(PolyTrait { ref trait_, .. }, _) = *self {
            return Some(trait_.clone());
        }
        None
    }
1404 1405
}

1406
impl Clean<TyParamBound> for hir::TyParamBound {
1407
    fn clean(&self, cx: &DocContext) -> TyParamBound {
C
Corey Richardson 已提交
1408
        match *self {
1409 1410
            hir::RegionTyParamBound(lt) => RegionBound(lt.clean(cx)),
            hir::TraitTyParamBound(ref t, modifier) => TraitBound(t.clean(cx), modifier),
C
Corey Richardson 已提交
1411 1412 1413 1414
        }
    }
}

1415
fn external_path_params(cx: &DocContext, trait_did: Option<DefId>, has_self: bool,
1416
                        bindings: Vec<TypeBinding>, substs: &Substs) -> PathParameters {
1417
    let lifetimes = substs.regions().filter_map(|v| v.clean(cx)).collect();
1418
    let types = substs.types().skip(has_self as usize).collect::<Vec<_>>();
1419

1420
    match trait_did {
1421
        // Attempt to sugar an external path like Fn<(A, B,), C> to Fn(A, B) -> C
1422
        Some(did) if cx.tcx.lang_items().fn_trait_kind(did).is_some() => {
1423
            assert_eq!(types.len(), 1);
1424
            let inputs = match types[0].sty {
A
Andrew Cann 已提交
1425
                ty::TyTuple(ref tys) => tys.iter().map(|t| t.clean(cx)).collect(),
1426 1427
                _ => {
                    return PathParameters::AngleBracketed {
1428
                        lifetimes,
1429
                        types: types.clean(cx),
1430
                        bindings,
1431 1432 1433
                    }
                }
            };
1434 1435 1436
            let output = None;
            // FIXME(#20299) return type comes from a projection now
            // match types[1].sty {
A
Andrew Cann 已提交
1437
            //     ty::TyTuple(ref v) if v.is_empty() => None, // -> ()
1438 1439
            //     _ => Some(types[1].clean(cx))
            // };
1440
            PathParameters::Parenthesized {
1441 1442
                inputs,
                output,
1443 1444
            }
        },
1445
        _ => {
1446
            PathParameters::AngleBracketed {
1447
                lifetimes,
1448
                types: types.clean(cx),
1449
                bindings,
1450 1451 1452 1453 1454 1455 1456
            }
        }
    }
}

// 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
1457
fn external_path(cx: &DocContext, name: &str, trait_did: Option<DefId>, has_self: bool,
1458
                 bindings: Vec<TypeBinding>, substs: &Substs) -> Path {
1459 1460
    Path {
        global: false,
1461
        def: Def::Err,
1462
        segments: vec![PathSegment {
1463
            name: name.to_string(),
1464
            params: external_path_params(cx, trait_did, has_self, bindings, substs)
1465
        }],
1466 1467 1468
    }
}

1469
impl<'a, 'tcx> Clean<TyParamBound> for (&'a ty::TraitRef<'tcx>, Vec<TypeBinding>) {
1470
    fn clean(&self, cx: &DocContext) -> TyParamBound {
1471 1472
        let (trait_ref, ref bounds) = *self;
        inline::record_extern_fqn(cx, trait_ref.def_id, TypeKind::Trait);
1473
        let path = external_path(cx, &cx.tcx.item_name(trait_ref.def_id).as_str(),
1474
                                 Some(trait_ref.def_id), true, bounds.clone(), trait_ref.substs);
1475

1476
        debug!("ty::TraitRef\n  subst: {:?}\n", trait_ref.substs);
1477 1478 1479

        // collect any late bound regions
        let mut late_bounds = vec![];
1480
        for ty_s in trait_ref.input_types().skip(1) {
A
Andrew Cann 已提交
1481
            if let ty::TyTuple(ts) = ty_s.sty {
1482
                for &ty_s in ts {
1483
                    if let ty::TyRef(ref reg, _, _) = ty_s.sty {
N
Niko Matsakis 已提交
1484
                        if let &ty::RegionKind::ReLateBound(..) = *reg {
1485
                            debug!("  hit an ReLateBound {:?}", reg);
1486
                            if let Some(lt) = reg.clean(cx) {
V
varkor 已提交
1487
                                late_bounds.push(GenericParamDef::Lifetime(lt));
1488 1489 1490 1491 1492 1493 1494
                            }
                        }
                    }
                }
            }
        }

1495 1496 1497
        TraitBound(
            PolyTrait {
                trait_: ResolvedPath {
1498
                    path,
1499
                    typarams: None,
1500
                    did: trait_ref.def_id,
1501 1502
                    is_generic: false,
                },
1503
                generic_params: late_bounds,
1504
            },
1505 1506
            hir::TraitBoundModifier::None
        )
1507 1508 1509
    }
}

1510 1511 1512 1513 1514 1515
impl<'tcx> Clean<TyParamBound> for ty::TraitRef<'tcx> {
    fn clean(&self, cx: &DocContext) -> TyParamBound {
        (self, vec![]).clean(cx)
    }
}

1516
impl<'tcx> Clean<Option<Vec<TyParamBound>>> for Substs<'tcx> {
1517
    fn clean(&self, cx: &DocContext) -> Option<Vec<TyParamBound>> {
1518
        let mut v = Vec::new();
1519
        v.extend(self.regions().filter_map(|r| r.clean(cx))
1520
                     .map(RegionBound));
1521
        v.extend(self.types().map(|t| TraitBound(PolyTrait {
1522
            trait_: t.clean(cx),
1523
            generic_params: Vec::new(),
1524
        }, hir::TraitBoundModifier::None)));
1525
        if !v.is_empty() {Some(v)} else {None}
1526 1527 1528
    }
}

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

1532 1533 1534
impl Lifetime {
    pub fn get_ref<'a>(&'a self) -> &'a str {
        let Lifetime(ref s) = *self;
1535
        let s: &'a str = s;
C
Corey Farwell 已提交
1536
        s
1537
    }
1538 1539 1540 1541

    pub fn statik() -> Lifetime {
        Lifetime("'static".to_string())
    }
1542 1543
}

1544
impl Clean<Lifetime> for hir::Lifetime {
E
Eduard Burtescu 已提交
1545
    fn clean(&self, cx: &DocContext) -> Lifetime {
1546 1547 1548 1549 1550 1551 1552 1553 1554 1555
        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 已提交
1556
                }
1557
                _ => {}
E
Eduard Burtescu 已提交
1558 1559
            }
        }
1560
        Lifetime(self.name.name().to_string())
C
Corey Richardson 已提交
1561 1562 1563
    }
}

1564
impl Clean<Lifetime> for hir::LifetimeDef {
1565
    fn clean(&self, _: &DocContext) -> Lifetime {
1566 1567
        if self.bounds.len() > 0 {
            let mut s = format!("{}: {}",
1568 1569
                                self.lifetime.name.name(),
                                self.bounds[0].name.name());
1570
            for bound in self.bounds.iter().skip(1) {
1571
                s.push_str(&format!(" + {}", bound.name.name()));
1572 1573 1574
            }
            Lifetime(s)
        } else {
1575
            Lifetime(self.lifetime.name.name().to_string())
1576
        }
1577 1578 1579
    }
}

1580
impl Clean<Lifetime> for ty::RegionParamDef {
1581
    fn clean(&self, _: &DocContext) -> Lifetime {
1582
        Lifetime(self.name.to_string())
1583 1584 1585
    }
}

1586
impl Clean<Option<Lifetime>> for ty::RegionKind {
1587
    fn clean(&self, cx: &DocContext) -> Option<Lifetime> {
1588
        match *self {
1589
            ty::ReStatic => Some(Lifetime::statik()),
1590
            ty::ReLateBound(_, ty::BrNamed(_, name)) => Some(Lifetime(name.to_string())),
N
Niko Matsakis 已提交
1591
            ty::ReEarlyBound(ref data) => Some(Lifetime(data.name.clean(cx))),
1592 1593 1594 1595

            ty::ReLateBound(..) |
            ty::ReFree(..) |
            ty::ReScope(..) |
1596 1597
            ty::ReVar(..) |
            ty::ReSkolemized(..) |
1598
            ty::ReEmpty |
1599
            ty::ReClosureBound(_) |
1600
            ty::ReCanonical(_) |
1601
            ty::ReErased => None
1602 1603 1604 1605
        }
    }
}

1606
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)]
1607 1608 1609
pub enum WherePredicate {
    BoundPredicate { ty: Type, bounds: Vec<TyParamBound> },
    RegionPredicate { lifetime: Lifetime, bounds: Vec<Lifetime>},
1610
    EqPredicate { lhs: Type, rhs: Type },
1611 1612
}

1613
impl Clean<WherePredicate> for hir::WherePredicate {
1614
    fn clean(&self, cx: &DocContext) -> WherePredicate {
N
Nick Cameron 已提交
1615
        match *self {
1616
            hir::WherePredicate::BoundPredicate(ref wbp) => {
1617
                WherePredicate::BoundPredicate {
1618
                    ty: wbp.bounded_ty.clean(cx),
N
Nick Cameron 已提交
1619 1620 1621
                    bounds: wbp.bounds.clean(cx)
                }
            }
1622

1623
            hir::WherePredicate::RegionPredicate(ref wrp) => {
1624 1625 1626 1627 1628 1629
                WherePredicate::RegionPredicate {
                    lifetime: wrp.lifetime.clean(cx),
                    bounds: wrp.bounds.clean(cx)
                }
            }

1630 1631 1632 1633 1634
            hir::WherePredicate::EqPredicate(ref wrp) => {
                WherePredicate::EqPredicate {
                    lhs: wrp.lhs_ty.clean(cx),
                    rhs: wrp.rhs_ty.clean(cx)
                }
N
Nick Cameron 已提交
1635
            }
1636 1637 1638 1639
        }
    }
}

1640 1641
impl<'a> Clean<WherePredicate> for ty::Predicate<'a> {
    fn clean(&self, cx: &DocContext) -> WherePredicate {
1642
        use rustc::ty::Predicate;
1643 1644 1645

        match *self {
            Predicate::Trait(ref pred) => pred.clean(cx),
N
Niko Matsakis 已提交
1646
            Predicate::Subtype(ref pred) => pred.clean(cx),
1647 1648
            Predicate::RegionOutlives(ref pred) => pred.clean(cx),
            Predicate::TypeOutlives(ref pred) => pred.clean(cx),
1649 1650 1651
            Predicate::Projection(ref pred) => pred.clean(cx),
            Predicate::WellFormed(_) => panic!("not user writable"),
            Predicate::ObjectSafe(_) => panic!("not user writable"),
1652
            Predicate::ClosureKind(..) => panic!("not user writable"),
1653
            Predicate::ConstEvaluatable(..) => panic!("not user writable"),
1654 1655 1656 1657 1658 1659 1660
        }
    }
}

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

N
Niko Matsakis 已提交
1667
impl<'tcx> Clean<WherePredicate> for ty::SubtypePredicate<'tcx> {
1668 1669 1670
    fn clean(&self, _cx: &DocContext) -> WherePredicate {
        panic!("subtype predicates are an internal rustc artifact \
                and should not be seen by rustdoc")
N
Niko Matsakis 已提交
1671 1672 1673
    }
}

N
Niko Matsakis 已提交
1674
impl<'tcx> Clean<WherePredicate> for ty::OutlivesPredicate<ty::Region<'tcx>, ty::Region<'tcx>> {
1675 1676 1677 1678 1679 1680 1681 1682 1683
    fn clean(&self, cx: &DocContext) -> WherePredicate {
        let ty::OutlivesPredicate(ref a, ref b) = *self;
        WherePredicate::RegionPredicate {
            lifetime: a.clean(cx).unwrap(),
            bounds: vec![b.clean(cx).unwrap()]
        }
    }
}

D
Douglas Campos 已提交
1684
impl<'tcx> Clean<WherePredicate> for ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>> {
1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705
    fn clean(&self, cx: &DocContext) -> WherePredicate {
        let ty::OutlivesPredicate(ref ty, ref lt) = *self;

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

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

impl<'tcx> Clean<Type> for ty::ProjectionTy<'tcx> {
    fn clean(&self, cx: &DocContext) -> Type {
1706
        let trait_ = match self.trait_ref(cx.tcx).clean(cx) {
1707
            TyParamBound::TraitBound(t, _) => t.trait_,
1708 1709 1710
            TyParamBound::RegionBound(_) => {
                panic!("cleaning a trait got a region")
            }
1711 1712
        };
        Type::QPath {
1713 1714
            name: cx.tcx.associated_item(self.item_def_id).name.clean(cx),
            self_type: box self.self_ty().clean(cx),
1715 1716 1717 1718 1719
            trait_: box trait_
        }
    }
}

1720
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)]
V
varkor 已提交
1721
pub enum GenericParamDef {
1722 1723 1724 1725
    Lifetime(Lifetime),
    Type(TyParam),
}

V
varkor 已提交
1726
impl GenericParamDef {
1727
    pub fn is_synthetic_type_param(&self) -> bool {
V
varkor 已提交
1728
        if let GenericParamDef::Type(ref t) = *self {
1729 1730 1731 1732 1733 1734 1735
            t.synthetic.is_some()
        } else {
            false
        }
    }
}

V
varkor 已提交
1736 1737
impl Clean<GenericParamDef> for hir::GenericParam {
    fn clean(&self, cx: &DocContext) -> GenericParamDef {
1738
        match *self {
V
varkor 已提交
1739 1740
            hir::GenericParam::Lifetime(ref l) => GenericParamDef::Lifetime(l.clean(cx)),
            hir::GenericParam::Type(ref t) => GenericParamDef::Type(t.clean(cx)),
1741 1742 1743 1744
        }
    }
}

1745 1746
// maybe use a Generic enum and use Vec<Generic>?
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Default, Hash)]
C
Corey Richardson 已提交
1747
pub struct Generics {
V
varkor 已提交
1748
    pub params: Vec<GenericParamDef>,
1749
    pub where_predicates: Vec<WherePredicate>,
1750
}
C
Corey Richardson 已提交
1751

1752
impl Clean<Generics> for hir::Generics {
1753
    fn clean(&self, cx: &DocContext) -> Generics {
1754 1755 1756 1757 1758 1759 1760 1761 1762 1763
        let mut params = Vec::with_capacity(self.params.len());
        for p in &self.params {
            let p = p.clean(cx);
            if let GenericParam::Type(ref tp) = p {
                if tp.synthetic == Some(hir::SyntheticTyParamKind::ImplTrait) {
                    cx.impl_trait_bounds.borrow_mut().insert(tp.did, tp.bounds.clone());
                }
            }
            params.push(p);
        }
1764
        let mut g = Generics {
1765
            params,
1766
            where_predicates: self.where_clause.predicates.clean(cx)
1767 1768 1769 1770 1771 1772 1773 1774 1775
        };

        // 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.
        for where_pred in &mut g.where_predicates {
            match *where_pred {
                WherePredicate::BoundPredicate { ty: Generic(ref name), ref mut bounds } => {
                    if bounds.is_empty() {
1776
                        for param in &mut g.params {
V
varkor 已提交
1777
                            if let GenericParamDef::Type(ref mut type_param) = *param {
1778 1779 1780 1781
                                if &type_param.name == name {
                                    mem::swap(bounds, &mut type_param.bounds);
                                    break
                                }
1782 1783 1784 1785 1786 1787
                            }
                        }
                    }
                }
                _ => continue,
            }
C
Corey Richardson 已提交
1788
        }
1789
        g
C
Corey Richardson 已提交
1790 1791 1792
    }
}

1793
impl<'a, 'tcx> Clean<Generics> for (&'a ty::Generics,
1794
                                    &'a ty::GenericPredicates<'tcx>) {
1795
    fn clean(&self, cx: &DocContext) -> Generics {
1796 1797
        use self::WherePredicate as WP;

1798
        let (gens, preds) = *self;
1799

1800 1801 1802
        // Bounds in the type_params and lifetimes fields are repeated in the
        // predicates field (see rustc_typeck::collect::ty_generics), so remove
        // them.
V
varkor 已提交
1803 1804 1805 1806 1807 1808 1809 1810
        let stripped_typarams = gens.params.iter().filter_map(|param| {
            if let ty::GenericParamDef::Type(ty) = param {
                if ty.name == keywords::SelfType.name().as_str() {
                    assert_eq!(ty.index, 0);
                    None
                } else {
                    Some(ty.clean(cx))
                }
1811
            } else {
V
varkor 已提交
1812
                None
1813
            }
1814 1815
        }).collect::<Vec<_>>();

1816
        let mut where_predicates = preds.predicates.to_vec().clean(cx);
1817

1818
        // Type parameters and have a Sized bound by default unless removed with
1819
        // ?Sized. Scan through the predicates and mark any type parameter with
1820
        // a Sized bound, removing the bounds as we find them.
1821 1822
        //
        // Note that associated types also have a sized bound by default, but we
1823
        // don't actually know the set of associated types right here so that's
1824
        // handled in cleaning associated types
1825
        let mut sized_params = FxHashSet();
1826 1827 1828 1829 1830 1831 1832 1833 1834
        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
                    }
1835
                }
1836
                _ => true,
1837
            }
1838
        });
1839

1840
        // Run through the type parameters again and insert a ?Sized
1841
        // unbound for any we didn't find to be Sized.
1842
        for tp in &stripped_typarams {
1843 1844 1845
            if !sized_params.contains(&tp.name) {
                where_predicates.push(WP::BoundPredicate {
                    ty: Type::Generic(tp.name.clone()),
1846
                    bounds: vec![TyParamBound::maybe_sized(cx)],
1847 1848 1849 1850 1851 1852 1853 1854
                })
            }
        }

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

1855
        Generics {
V
varkor 已提交
1856 1857 1858 1859 1860 1861 1862 1863 1864
            params: gens.params
                        .iter()
                        .flat_map(|param| {
                            if let ty::GenericParamDef::Lifetime(lt) = param {
                                Some(GenericParamDef::Lifetime(lt.clean(cx)))
                            } else {
                                None
                            }
                        }).chain(
V
varkor 已提交
1865 1866
                            simplify::ty_params(stripped_typarams)
                                .into_iter()
V
varkor 已提交
1867
                                .map(|tp| GenericParamDef::Type(tp))
V
varkor 已提交
1868 1869
                        )
                        .collect(),
1870
            where_predicates: simplify::where_clauses(cx, where_predicates),
1871 1872 1873 1874
        }
    }
}

J
Jorge Aparicio 已提交
1875
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
1876
pub struct Method {
1877
    pub generics: Generics,
1878 1879
    pub unsafety: hir::Unsafety,
    pub constness: hir::Constness,
1880
    pub decl: FnDecl,
1881
    pub abi: Abi,
C
Corey Richardson 已提交
1882 1883
}

S
Sunjay Varma 已提交
1884
impl<'a> Clean<Method> for (&'a hir::MethodSig, &'a hir::Generics, hir::BodyId) {
1885
    fn clean(&self, cx: &DocContext) -> Method {
1886 1887 1888
        let (generics, decl) = enter_impl_trait(cx, || {
            (self.1.clean(cx), (&*self.0.decl, self.2).clean(cx))
        });
1889
        Method {
1890
            decl,
1891
            generics,
1892 1893 1894
            unsafety: self.0.unsafety,
            constness: self.0.constness,
            abi: self.0.abi
C
Corey Richardson 已提交
1895 1896 1897 1898
        }
    }
}

J
Jorge Aparicio 已提交
1899
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
1900
pub struct TyMethod {
1901
    pub unsafety: hir::Unsafety,
1902 1903
    pub decl: FnDecl,
    pub generics: Generics,
1904
    pub abi: Abi,
C
Corey Richardson 已提交
1905 1906
}

J
Jorge Aparicio 已提交
1907
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
1908
pub struct Function {
1909 1910
    pub decl: FnDecl,
    pub generics: Generics,
1911 1912
    pub unsafety: hir::Unsafety,
    pub constness: hir::Constness,
1913
    pub abi: Abi,
C
Corey Richardson 已提交
1914 1915 1916
}

impl Clean<Item> for doctree::Function {
1917
    fn clean(&self, cx: &DocContext) -> Item {
1918 1919 1920
        let (generics, decl) = enter_impl_trait(cx, || {
            (self.generics.clean(cx), (&self.decl, self.body).clean(cx))
        });
C
Corey Richardson 已提交
1921
        Item {
1922 1923 1924 1925 1926
            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),
1927
            deprecation: self.depr.clean(cx),
1928
            def_id: cx.tcx.hir.local_def_id(self.id),
C
Corey Richardson 已提交
1929
            inner: FunctionItem(Function {
1930 1931
                decl,
                generics,
N
Niko Matsakis 已提交
1932
                unsafety: self.unsafety,
1933
                constness: self.constness,
1934
                abi: self.abi,
C
Corey Richardson 已提交
1935 1936 1937 1938 1939
            }),
        }
    }
}

1940
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)]
C
Corey Richardson 已提交
1941
pub struct FnDecl {
1942
    pub inputs: Arguments,
1943
    pub output: FunctionRetTy,
1944
    pub variadic: bool,
1945
    pub attrs: Attributes,
1946
}
C
Corey Richardson 已提交
1947

1948 1949
impl FnDecl {
    pub fn has_self(&self) -> bool {
C
Corey Farwell 已提交
1950
        self.inputs.values.len() > 0 && self.inputs.values[0].name == "self"
1951
    }
1952 1953 1954 1955

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

1958
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)]
1959
pub struct Arguments {
1960
    pub values: Vec<Argument>,
1961 1962
}

1963 1964 1965 1966 1967 1968 1969 1970 1971 1972
impl<'a> Clean<Arguments> for (&'a [P<hir::Ty>], &'a [Spanned<ast::Name>]) {
    fn clean(&self, cx: &DocContext) -> Arguments {
        Arguments {
            values: self.0.iter().enumerate().map(|(i, ty)| {
                let mut name = self.1.get(i).map(|n| n.node.to_string())
                                            .unwrap_or(String::new());
                if name.is_empty() {
                    name = "_".to_string();
                }
                Argument {
1973
                    name,
1974 1975 1976 1977 1978 1979 1980 1981 1982
                    type_: ty.clean(cx),
                }
            }).collect()
        }
    }
}

impl<'a> Clean<Arguments> for (&'a [P<hir::Ty>], hir::BodyId) {
    fn clean(&self, cx: &DocContext) -> Arguments {
1983
        let body = cx.tcx.hir.body(self.1);
1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998

        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)
    where (&'a [P<hir::Ty>], A): Clean<Arguments>
{
1999
    fn clean(&self, cx: &DocContext) -> FnDecl {
C
Corey Richardson 已提交
2000
        FnDecl {
2001 2002 2003
            inputs: (&self.0.inputs[..], self.1).clean(cx),
            output: self.0.output.clean(cx),
            variadic: self.0.variadic,
2004
            attrs: Attributes::default()
C
Corey Richardson 已提交
2005 2006 2007 2008
        }
    }
}

2009
impl<'a, 'tcx> Clean<FnDecl> for (DefId, ty::PolyFnSig<'tcx>) {
2010
    fn clean(&self, cx: &DocContext) -> FnDecl {
2011
        let (did, sig) = *self;
2012
        let mut names = if cx.tcx.hir.as_local_node_id(did).is_some() {
2013
            vec![].into_iter()
2014
        } else {
A
achernyak 已提交
2015
            cx.tcx.fn_arg_names(did).into_iter()
S
Cleanup  
Shotaro Yamada 已提交
2016 2017
        };

2018
        FnDecl {
2019
            output: Return(sig.skip_binder().output().clean(cx)),
2020
            attrs: Attributes::default(),
2021
            variadic: sig.skip_binder().variadic,
2022
            inputs: Arguments {
2023
                values: sig.skip_binder().inputs().iter().map(|t| {
2024
                    Argument {
2025
                        type_: t.clean(cx),
2026
                        name: names.next().map_or("".to_string(), |name| name.to_string()),
2027 2028 2029 2030 2031 2032 2033
                    }
                }).collect(),
            },
        }
    }
}

2034
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)]
C
Corey Richardson 已提交
2035
pub struct Argument {
2036
    pub type_: Type,
2037
    pub name: String,
C
Corey Richardson 已提交
2038 2039
}

2040 2041 2042 2043 2044 2045 2046 2047 2048
#[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> {
2049 2050 2051 2052 2053 2054 2055 2056 2057
        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))
2058
            }
2059
            _ => Some(SelfExplicit(self.type_.clone()))
2060 2061 2062 2063
        }
    }
}

2064
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)]
2065 2066
pub enum FunctionRetTy {
    Return(Type),
2067
    DefaultReturn,
C
Corey Richardson 已提交
2068 2069
}

2070
impl Clean<FunctionRetTy> for hir::FunctionRetTy {
2071
    fn clean(&self, cx: &DocContext) -> FunctionRetTy {
C
Corey Richardson 已提交
2072
        match *self {
2073 2074
            hir::Return(ref typ) => Return(typ.clean(cx)),
            hir::DefaultReturn(..) => DefaultReturn,
C
Corey Richardson 已提交
2075 2076 2077 2078
        }
    }
}

2079 2080 2081 2082 2083 2084 2085 2086 2087
impl GetDefId for FunctionRetTy {
    fn def_id(&self) -> Option<DefId> {
        match *self {
            Return(ref ty) => ty.def_id(),
            DefaultReturn => None,
        }
    }
}

J
Jorge Aparicio 已提交
2088
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
2089
pub struct Trait {
2090
    pub auto: bool,
2091
    pub unsafety: hir::Unsafety,
2092
    pub items: Vec<Item>,
2093
    pub generics: Generics,
2094
    pub bounds: Vec<TyParamBound>,
2095
    pub is_spotlight: bool,
2096
    pub is_auto: bool,
C
Corey Richardson 已提交
2097 2098 2099
}

impl Clean<Item> for doctree::Trait {
2100
    fn clean(&self, cx: &DocContext) -> Item {
2101 2102
        let attrs = self.attrs.clean(cx);
        let is_spotlight = attrs.has_doc_flag("spotlight");
C
Corey Richardson 已提交
2103
        Item {
2104
            name: Some(self.name.clean(cx)),
2105
            attrs: attrs,
2106
            source: self.whence.clean(cx),
2107
            def_id: cx.tcx.hir.local_def_id(self.id),
2108 2109
            visibility: self.vis.clean(cx),
            stability: self.stab.clean(cx),
2110
            deprecation: self.depr.clean(cx),
C
Corey Richardson 已提交
2111
            inner: TraitItem(Trait {
2112
                auto: self.is_auto.clean(cx),
2113
                unsafety: self.unsafety,
2114 2115 2116
                items: self.items.clean(cx),
                generics: self.generics.clean(cx),
                bounds: self.bounds.clean(cx),
2117
                is_spotlight: is_spotlight,
2118
                is_auto: self.is_auto.clean(cx),
C
Corey Richardson 已提交
2119 2120 2121 2122 2123
            }),
        }
    }
}

2124 2125 2126 2127 2128 2129 2130 2131 2132
impl Clean<bool> for hir::IsAuto {
    fn clean(&self, _: &DocContext) -> bool {
        match *self {
            hir::IsAuto::Yes => true,
            hir::IsAuto::No => false,
        }
    }
}

2133
impl Clean<Type> for hir::TraitRef {
2134
    fn clean(&self, cx: &DocContext) -> Type {
N
Niko Matsakis 已提交
2135
        resolve_type(cx, self.path.clean(cx), self.ref_id)
C
Corey Richardson 已提交
2136 2137 2138
    }
}

2139
impl Clean<PolyTrait> for hir::PolyTraitRef {
2140 2141 2142
    fn clean(&self, cx: &DocContext) -> PolyTrait {
        PolyTrait {
            trait_: self.trait_ref.clean(cx),
2143
            generic_params: self.bound_generic_params.clean(cx)
2144
        }
N
Niko Matsakis 已提交
2145 2146 2147
    }
}

2148
impl Clean<Item> for hir::TraitItem {
2149 2150
    fn clean(&self, cx: &DocContext) -> Item {
        let inner = match self.node {
2151
            hir::TraitItemKind::Const(ref ty, default) => {
2152
                AssociatedConstItem(ty.clean(cx),
2153
                                    default.map(|e| print_const_expr(cx, e)))
2154
            }
2155
            hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Provided(body)) => {
S
Sunjay Varma 已提交
2156
                MethodItem((sig, &self.generics, body).clean(cx))
2157
            }
2158
            hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Required(ref names)) => {
2159 2160 2161
                let (generics, decl) = enter_impl_trait(cx, || {
                    (self.generics.clean(cx), (&*sig.decl, &names[..]).clean(cx))
                });
2162 2163
                TyMethodItem(TyMethod {
                    unsafety: sig.unsafety.clone(),
2164
                    decl,
2165
                    generics,
2166 2167
                    abi: sig.abi
                })
2168
            }
2169
            hir::TraitItemKind::Type(ref bounds, ref default) => {
2170 2171 2172 2173
                AssociatedTypeItem(bounds.clean(cx), default.clean(cx))
            }
        };
        Item {
V
Vadim Petrochenkov 已提交
2174
            name: Some(self.name.clean(cx)),
2175 2176
            attrs: self.attrs.clean(cx),
            source: self.span.clean(cx),
2177
            def_id: cx.tcx.hir.local_def_id(self.id),
2178
            visibility: None,
2179 2180
            stability: get_stability(cx, cx.tcx.hir.local_def_id(self.id)),
            deprecation: get_deprecation(cx, cx.tcx.hir.local_def_id(self.id)),
2181
            inner,
2182 2183 2184 2185
        }
    }
}

2186
impl Clean<Item> for hir::ImplItem {
2187 2188
    fn clean(&self, cx: &DocContext) -> Item {
        let inner = match self.node {
2189
            hir::ImplItemKind::Const(ref ty, expr) => {
2190
                AssociatedConstItem(ty.clean(cx),
2191
                                    Some(print_const_expr(cx, expr)))
2192
            }
2193
            hir::ImplItemKind::Method(ref sig, body) => {
S
Sunjay Varma 已提交
2194
                MethodItem((sig, &self.generics, body).clean(cx))
2195
            }
2196
            hir::ImplItemKind::Type(ref ty) => TypedefItem(Typedef {
2197
                type_: ty.clean(cx),
2198
                generics: Generics::default(),
2199
            }, true),
2200 2201
        };
        Item {
V
Vadim Petrochenkov 已提交
2202
            name: Some(self.name.clean(cx)),
2203 2204
            source: self.span.clean(cx),
            attrs: self.attrs.clean(cx),
2205
            def_id: cx.tcx.hir.local_def_id(self.id),
2206
            visibility: self.vis.clean(cx),
2207 2208
            stability: get_stability(cx, cx.tcx.hir.local_def_id(self.id)),
            deprecation: get_deprecation(cx, cx.tcx.hir.local_def_id(self.id)),
2209
            inner,
C
Corey Richardson 已提交
2210 2211 2212 2213
        }
    }
}

2214
impl<'tcx> Clean<Item> for ty::AssociatedItem {
2215
    fn clean(&self, cx: &DocContext) -> Item {
2216 2217
        let inner = match self.kind {
            ty::AssociatedKind::Const => {
2218
                let ty = cx.tcx.type_of(self.def_id);
2219 2220 2221 2222 2223 2224
                let default = if self.defaultness.has_value() {
                    Some(inline::print_inlined_const(cx, self.def_id))
                } else {
                    None
                };
                AssociatedConstItem(ty.clean(cx), default)
2225
            }
2226
            ty::AssociatedKind::Method => {
2227 2228
                let generics = (cx.tcx.generics_of(self.def_id),
                                &cx.tcx.predicates_of(self.def_id)).clean(cx);
2229
                let sig = cx.tcx.fn_sig(self.def_id);
2230
                let mut decl = (self.def_id, sig).clean(cx);
2231 2232 2233 2234

                if self.method_has_self_argument {
                    let self_ty = match self.container {
                        ty::ImplContainer(def_id) => {
2235
                            cx.tcx.type_of(def_id)
2236
                        }
2237
                        ty::TraitContainer(_) => cx.tcx.mk_self_type()
2238
                    };
2239
                    let self_arg_ty = *sig.input(0).skip_binder();
2240
                    if self_arg_ty == self_ty {
2241
                        decl.inputs.values[0].type_ = Generic(String::from("Self"));
2242 2243
                    } else if let ty::TyRef(_, ty, _) = self_arg_ty.sty {
                        if ty == self_ty {
2244
                            match decl.inputs.values[0].type_ {
2245 2246 2247
                                BorrowedRef{ref mut type_, ..} => {
                                    **type_ = Generic(String::from("Self"))
                                }
2248 2249 2250 2251 2252
                                _ => unreachable!(),
                            }
                        }
                    }
                }
2253

2254
                let provided = match self.container {
2255
                    ty::ImplContainer(_) => true,
2256
                    ty::TraitContainer(_) => self.defaultness.has_value()
2257 2258
                };
                if provided {
2259 2260 2261 2262 2263
                    let constness = if cx.tcx.is_const_fn(self.def_id) {
                        hir::Constness::Const
                    } else {
                        hir::Constness::NotConst
                    };
2264
                    MethodItem(Method {
2265
                        unsafety: sig.unsafety(),
2266 2267
                        generics,
                        decl,
2268
                        abi: sig.abi(),
2269
                        constness,
2270 2271 2272
                    })
                } else {
                    TyMethodItem(TyMethod {
2273
                        unsafety: sig.unsafety(),
2274 2275
                        generics,
                        decl,
2276
                        abi: sig.abi(),
2277
                    })
2278 2279
                }
            }
2280 2281 2282
            ty::AssociatedKind::Type => {
                let my_name = self.name.clean(cx);

2283
                if let ty::TraitContainer(did) = self.container {
2284 2285 2286 2287
                    // 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.
2288 2289
                    let predicates = cx.tcx.predicates_of(did);
                    let generics = (cx.tcx.generics_of(did), &predicates).clean(cx);
2290
                    let mut bounds = generics.where_predicates.iter().filter_map(|pred| {
2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307
                        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)
2308 2309 2310 2311 2312 2313 2314 2315 2316 2317
                    }).flat_map(|i| i.iter().cloned()).collect::<Vec<_>>();
                    // Our Sized/?Sized bound didn't get handled when creating the generics
                    // because we didn't actually get our whole set of bounds until just now
                    // (some of them may have come from the trait). If we do have a sized
                    // bound, we remove it, and if we don't then we add the `?Sized` bound
                    // at the end.
                    match bounds.iter().position(|b| b.is_sized_bound(cx)) {
                        Some(i) => { bounds.remove(i); }
                        None => bounds.push(TyParamBound::maybe_sized(cx)),
                    }
2318

2319 2320 2321 2322 2323
                    let ty = if self.defaultness.has_value() {
                        Some(cx.tcx.type_of(self.def_id))
                    } else {
                        None
                    };
2324

2325
                    AssociatedTypeItem(bounds, ty.clean(cx))
2326
                } else {
2327 2328 2329
                    TypedefItem(Typedef {
                        type_: cx.tcx.type_of(self.def_id).clean(cx),
                        generics: Generics {
2330
                            params: Vec::new(),
2331 2332 2333 2334
                            where_predicates: Vec::new(),
                        },
                    }, true)
                }
2335 2336 2337
            }
        };

2338 2339 2340 2341 2342
        let visibility = match self.container {
            ty::ImplContainer(_) => self.vis.clean(cx),
            ty::TraitContainer(_) => None,
        };

2343
        Item {
2344
            name: Some(self.name.clean(cx)),
2345
            visibility,
2346
            stability: get_stability(cx, self.def_id),
2347
            deprecation: get_deprecation(cx, self.def_id),
2348
            def_id: self.def_id,
2349
            attrs: inline::load_attrs(cx, self.def_id),
2350
            source: cx.tcx.def_span(self.def_id).clean(cx),
2351
            inner,
2352
        }
2353 2354 2355
    }
}

2356
/// A trait reference, which may have higher ranked lifetimes.
2357
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)]
2358 2359
pub struct PolyTrait {
    pub trait_: Type,
V
varkor 已提交
2360
    pub generic_params: Vec<GenericParamDef>,
2361 2362
}

C
Corey Richardson 已提交
2363
/// A representation of a Type suitable for hyperlinking purposes. Ideally one can get the original
2364
/// type out of the AST/TyCtxt given one of these, if more information is needed. Most importantly
C
Corey Richardson 已提交
2365
/// it does not preserve mutability or boxes.
2366
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)]
C
Corey Richardson 已提交
2367
pub enum Type {
2368
    /// structs/enums/traits (most that'd be an hir::TyPath)
2369
    ResolvedPath {
S
Steven Fackler 已提交
2370 2371
        path: Path,
        typarams: Option<Vec<TyParamBound>>,
N
Niko Matsakis 已提交
2372
        did: DefId,
2373 2374
        /// true if is a `T::Name` path for associated types
        is_generic: bool,
2375
    },
2376 2377 2378
    /// For parameterized types, so the consumer of the JSON don't go
    /// looking for types which don't exist anywhere.
    Generic(String),
2379
    /// Primitives are the fixed-size numeric types (plus int/usize/float), char,
2380
    /// arrays, slices, and tuples.
2381
    Primitive(PrimitiveType),
C
Corey Richardson 已提交
2382
    /// extern "ABI" fn
2383
    BareFunction(Box<BareFunctionDecl>),
2384
    Tuple(Vec<Type>),
2385
    Slice(Box<Type>),
2386
    Array(Box<Type>, String),
A
Andrew Cann 已提交
2387
    Never,
2388 2389
    Unique(Box<Type>),
    RawPointer(Mutability, Box<Type>),
2390
    BorrowedRef {
S
Steven Fackler 已提交
2391 2392 2393
        lifetime: Option<Lifetime>,
        mutability: Mutability,
        type_: Box<Type>,
2394
    },
2395 2396

    // <Type as Trait>::Name
T
Tom Jakubowski 已提交
2397 2398 2399 2400 2401
    QPath {
        name: String,
        self_type: Box<Type>,
        trait_: Box<Type>
    },
2402 2403 2404 2405

    // _
    Infer,

2406 2407
    // impl TraitA+TraitB
    ImplTrait(Vec<TyParamBound>),
C
Corey Richardson 已提交
2408 2409
}

J
Jorge Aparicio 已提交
2410
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Copy, Debug)]
2411
pub enum PrimitiveType {
2412 2413
    Isize, I8, I16, I32, I64, I128,
    Usize, U8, U16, U32, U64, U128,
2414
    F32, F64,
2415 2416 2417 2418
    Char,
    Bool,
    Str,
    Slice,
2419
    Array,
2420
    Tuple,
2421
    Unit,
2422
    RawPointer,
2423
    Reference,
2424
    Fn,
A
Andrew Cann 已提交
2425
    Never,
2426 2427
}

J
Jorge Aparicio 已提交
2428
#[derive(Clone, RustcEncodable, RustcDecodable, Copy, Debug)]
2429
pub enum TypeKind {
2430 2431 2432 2433 2434 2435 2436 2437 2438 2439
    Enum,
    Function,
    Module,
    Const,
    Static,
    Struct,
    Union,
    Trait,
    Variant,
    Typedef,
P
Paul Lietar 已提交
2440
    Foreign,
M
Manish Goregaokar 已提交
2441
    Macro,
2442 2443
}

2444 2445 2446 2447 2448 2449 2450 2451 2452 2453
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())
    }
}

2454 2455 2456 2457
impl Type {
    pub fn primitive_type(&self) -> Option<PrimitiveType> {
        match *self {
            Primitive(p) | BorrowedRef { type_: box Primitive(p), ..} => Some(p),
2458 2459
            Slice(..) | BorrowedRef { type_: box Slice(..), .. } => Some(PrimitiveType::Slice),
            Array(..) | BorrowedRef { type_: box Array(..), .. } => Some(PrimitiveType::Array),
2460 2461 2462 2463 2464
            Tuple(ref tys) => if tys.is_empty() {
                Some(PrimitiveType::Unit)
            } else {
                Some(PrimitiveType::Tuple)
            },
2465
            RawPointer(..) => Some(PrimitiveType::RawPointer),
2466
            BorrowedRef { type_: box Generic(..), .. } => Some(PrimitiveType::Reference),
2467
            BareFunction(..) => Some(PrimitiveType::Fn),
A
Andrew Cann 已提交
2468
            Never => Some(PrimitiveType::Never),
2469 2470 2471
            _ => None,
        }
    }
2472

2473 2474 2475 2476 2477 2478
    pub fn is_generic(&self) -> bool {
        match *self {
            ResolvedPath { is_generic, .. } => is_generic,
            _ => false,
        }
    }
2479 2480 2481 2482 2483 2484 2485

    pub fn is_self_type(&self) -> bool {
        match *self {
            Generic(ref name) => name == "Self",
            _ => false
        }
    }
2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500

    pub fn generics(&self) -> Option<&[Type]> {
        match *self {
            ResolvedPath { ref path, .. } => {
                path.segments.last().and_then(|seg| {
                    if let PathParameters::AngleBracketed { ref types, .. } = seg.params {
                        Some(&**types)
                    } else {
                        None
                    }
                })
            }
            _ => None,
        }
    }
2501
}
2502

2503
impl GetDefId for Type {
2504 2505 2506
    fn def_id(&self) -> Option<DefId> {
        match *self {
            ResolvedPath { did, .. } => Some(did),
2507 2508 2509 2510
            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(),
2511 2512 2513 2514 2515
            Tuple(ref tys) => if tys.is_empty() {
                Primitive(PrimitiveType::Unit).def_id()
            } else {
                Primitive(PrimitiveType::Tuple).def_id()
            },
2516
            BareFunction(..) => Primitive(PrimitiveType::Fn).def_id(),
A
Andrew Cann 已提交
2517
            Never => Primitive(PrimitiveType::Never).def_id(),
2518 2519 2520 2521
            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(),
2522 2523 2524
            _ => None,
        }
    }
2525 2526
}

2527 2528
impl PrimitiveType {
    fn from_str(s: &str) -> Option<PrimitiveType> {
2529
        match s {
2530 2531 2532 2533 2534
            "isize" => Some(PrimitiveType::Isize),
            "i8" => Some(PrimitiveType::I8),
            "i16" => Some(PrimitiveType::I16),
            "i32" => Some(PrimitiveType::I32),
            "i64" => Some(PrimitiveType::I64),
2535
            "i128" => Some(PrimitiveType::I128),
2536 2537 2538 2539 2540
            "usize" => Some(PrimitiveType::Usize),
            "u8" => Some(PrimitiveType::U8),
            "u16" => Some(PrimitiveType::U16),
            "u32" => Some(PrimitiveType::U32),
            "u64" => Some(PrimitiveType::U64),
2541
            "u128" => Some(PrimitiveType::U128),
2542 2543 2544 2545 2546 2547 2548
            "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),
2549
            "tuple" => Some(PrimitiveType::Tuple),
2550
            "unit" => Some(PrimitiveType::Unit),
2551
            "pointer" => Some(PrimitiveType::RawPointer),
2552
            "reference" => Some(PrimitiveType::Reference),
2553
            "fn" => Some(PrimitiveType::Fn),
A
Andrew Cann 已提交
2554
            "never" => Some(PrimitiveType::Never),
2555 2556 2557 2558
            _ => None,
        }
    }

2559
    pub fn as_str(&self) -> &'static str {
E
est31 已提交
2560
        use self::PrimitiveType::*;
2561
        match *self {
2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581
            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",
2582
            Unit => "unit",
2583
            RawPointer => "pointer",
2584
            Reference => "reference",
2585
            Fn => "fn",
A
Andrew Cann 已提交
2586
            Never => "never",
2587 2588 2589 2590
        }
    }

    pub fn to_url_str(&self) -> &'static str {
2591
        self.as_str()
2592 2593 2594
    }
}

2595 2596 2597
impl From<ast::IntTy> for PrimitiveType {
    fn from(int_ty: ast::IntTy) -> PrimitiveType {
        match int_ty {
2598
            ast::IntTy::Isize => PrimitiveType::Isize,
2599 2600 2601 2602
            ast::IntTy::I8 => PrimitiveType::I8,
            ast::IntTy::I16 => PrimitiveType::I16,
            ast::IntTy::I32 => PrimitiveType::I32,
            ast::IntTy::I64 => PrimitiveType::I64,
2603
            ast::IntTy::I128 => PrimitiveType::I128,
2604 2605 2606
        }
    }
}
2607

2608 2609 2610
impl From<ast::UintTy> for PrimitiveType {
    fn from(uint_ty: ast::UintTy) -> PrimitiveType {
        match uint_ty {
2611
            ast::UintTy::Usize => PrimitiveType::Usize,
2612 2613 2614 2615
            ast::UintTy::U8 => PrimitiveType::U8,
            ast::UintTy::U16 => PrimitiveType::U16,
            ast::UintTy::U32 => PrimitiveType::U32,
            ast::UintTy::U64 => PrimitiveType::U64,
2616
            ast::UintTy::U128 => PrimitiveType::U128,
2617 2618 2619 2620
        }
    }
}

2621 2622 2623 2624 2625 2626 2627 2628 2629
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,
        }
    }
}

2630
impl Clean<Type> for hir::Ty {
2631
    fn clean(&self, cx: &DocContext) -> Type {
2632
        use rustc::hir::*;
2633
        match self.node {
A
Andrew Cann 已提交
2634
            TyNever => Never,
2635
            TyPtr(ref m) => RawPointer(m.mutbl.clean(cx), box m.ty.clean(cx)),
2636 2637 2638 2639 2640 2641 2642 2643 2644
            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)}
            }
2645
            TySlice(ref ty) => Slice(box ty.clean(cx)),
2646 2647
            TyArray(ref ty, n) => {
                let def_id = cx.tcx.hir.body_owner_def_id(n);
2648
                let param_env = cx.tcx.param_env(def_id);
2649
                let substs = Substs::identity_for_item(cx.tcx, def_id);
O
Oliver Schneider 已提交
2650 2651 2652 2653 2654
                let cid = GlobalId {
                    instance: ty::Instance::new(def_id, substs),
                    promoted: None
                };
                let n = cx.tcx.const_eval(param_env.and(cid)).unwrap_or_else(|_| {
2655
                    ty::Const::unevaluated(cx.tcx, def_id, substs, cx.tcx.types.usize)
2656
                });
O
Oliver Schneider 已提交
2657
                let n = print_const(cx, n);
2658
                Array(box ty.clean(cx), n)
2659
            },
2660
            TyTup(ref tys) => Tuple(tys.clean(cx)),
2661
            TyPath(hir::QPath::Resolved(None, ref path)) => {
2662
                if let Some(new_ty) = cx.ty_substs.borrow().get(&path.def).cloned() {
2663
                    return new_ty;
E
Eduard Burtescu 已提交
2664 2665
                }

2666 2667 2668 2669 2670 2671
                if let Def::TyParam(did) = path.def {
                    if let Some(bounds) = cx.impl_trait_bounds.borrow_mut().remove(&did) {
                        return ImplTrait(bounds);
                    }
                }

2672
                let mut alias = None;
2673
                if let Def::TyAlias(def_id) = path.def {
2674
                    // Substitute private type aliases
2675
                    if let Some(node_id) = cx.tcx.hir.as_local_node_id(def_id) {
2676
                        if !cx.access_levels.borrow().is_exported(def_id) {
2677
                            alias = Some(&cx.tcx.hir.expect_item(node_id).node);
2678
                        }
E
Eduard Burtescu 已提交
2679
                    }
2680 2681 2682
                };

                if let Some(&hir::ItemTy(ref ty, ref generics)) = alias {
2683
                    let provided_params = &path.segments.last().unwrap();
2684 2685
                    let mut ty_substs = FxHashMap();
                    let mut lt_substs = FxHashMap();
2686
                    provided_params.with_parameters(|provided_params| {
2687 2688 2689
                        let mut indices = FxHashMap();
                        for param in generics.params.iter() {
                            match param {
V
varkor 已提交
2690
                                hir::GenericParam::Type(ty_param) => {
2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701
                                    let i = indices.entry(Kind::Type).or_insert(0);
                                    let ty_param_def =
                                        Def::TyParam(cx.tcx.hir.local_def_id(ty_param.id));
                                    if let Some(ty) = provided_params.types.get(*i).cloned() {
                                        ty_substs.insert(ty_param_def, ty.into_inner().clean(cx));
                                    } else if let Some(default) = ty_param.default.clone() {
                                        ty_substs.insert(ty_param_def,
                                                         default.into_inner().clean(cx));
                                    }
                                    *i += 1;
                                }
V
varkor 已提交
2702
                                hir::GenericParam::Lifetime(lt_param) => {
2703 2704 2705 2706 2707 2708 2709 2710 2711
                                    let i = indices.entry(Kind::Type).or_insert(0);
                                    if let Some(lt) = provided_params.lifetimes.get(*i).cloned() {
                                        if !lt.is_elided() {
                                            let lt_def_id =
                                                cx.tcx.hir.local_def_id(lt_param.lifetime.id);
                                            lt_substs.insert(lt_def_id, lt.clean(cx));
                                        }
                                    }
                                    *i += 1;
2712
                                }
2713
                            }
2714
                        }
2715
                    });
E
Eduard Burtescu 已提交
2716
                    return cx.enter_alias(ty_substs, lt_substs, || ty.clean(cx));
2717 2718
                }
                resolve_type(cx, path.clean(cx), self.id)
N
Niko Matsakis 已提交
2719
            }
2720
            TyPath(hir::QPath::Resolved(Some(ref qself), ref p)) => {
2721 2722 2723 2724
                let mut segments: Vec<_> = p.segments.clone().into();
                segments.pop();
                let trait_path = hir::Path {
                    span: p.span,
2725
                    def: Def::Trait(cx.tcx.associated_item(p.def.def_id()).container.id()),
2726 2727
                    segments: segments.into(),
                };
2728
                Type::QPath {
V
Vadim Petrochenkov 已提交
2729
                    name: p.segments.last().unwrap().name.clean(cx),
2730 2731 2732 2733 2734
                    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)) => {
2735
                let mut def = Def::Err;
2736 2737
                let ty = hir_ty_to_ty(cx.tcx, self);
                if let ty::TyProjection(proj) = ty.sty {
2738
                    def = Def::Trait(proj.trait_ref(cx.tcx).def_id);
2739
                }
2740 2741
                let trait_path = hir::Path {
                    span: self.span,
2742
                    def,
2743 2744 2745 2746 2747
                    segments: vec![].into(),
                };
                Type::QPath {
                    name: segment.name.clean(cx),
                    self_type: box qself.clean(cx),
2748
                    trait_: box resolve_type(cx, trait_path.clean(cx), self.id)
2749 2750
                }
            }
2751 2752 2753 2754 2755 2756 2757 2758 2759 2760
            TyTraitObject(ref bounds, ref lifetime) => {
                match bounds[0].clean(cx).trait_ {
                    ResolvedPath { path, typarams: None, did, is_generic } => {
                        let mut bounds: Vec<_> = bounds[1..].iter().map(|bound| {
                            TraitBound(bound.clean(cx), hir::TraitBoundModifier::None)
                        }).collect();
                        if !lifetime.is_elided() {
                            bounds.push(RegionBound(lifetime.clean(cx)));
                        }
                        ResolvedPath {
2761
                            path,
2762
                            typarams: Some(bounds),
2763 2764
                            did,
                            is_generic,
2765
                        }
N
Niko Matsakis 已提交
2766
                    }
2767
                    _ => Infer // shouldn't happen
N
Niko Matsakis 已提交
2768
                }
2769
            }
2770
            TyBareFn(ref barefn) => BareFunction(box barefn.clean(cx)),
T
Taylor Cramer 已提交
2771
            TyImplTraitExistential(ref exist_ty, ref _lts) => ImplTrait(exist_ty.bounds.clean(cx)),
2772
            TyInfer | TyErr => Infer,
M
mitaa 已提交
2773
            TyTypeof(..) => panic!("Unimplemented type {:?}", self.node),
2774
        }
C
Corey Richardson 已提交
2775 2776 2777
    }
}

D
Douglas Campos 已提交
2778
impl<'tcx> Clean<Type> for Ty<'tcx> {
2779
    fn clean(&self, cx: &DocContext) -> Type {
2780
        match self.sty {
A
Andrew Cann 已提交
2781
            ty::TyNever => Never,
2782 2783
            ty::TyBool => Primitive(PrimitiveType::Bool),
            ty::TyChar => Primitive(PrimitiveType::Char),
2784
            ty::TyInt(int_ty) => Primitive(int_ty.into()),
2785
            ty::TyUint(uint_ty) => Primitive(uint_ty.into()),
2786
            ty::TyFloat(float_ty) => Primitive(float_ty.into()),
2787
            ty::TyStr => Primitive(PrimitiveType::Str),
2788
            ty::TySlice(ty) => Slice(box ty.clean(cx)),
2789
            ty::TyArray(ty, n) => {
2790 2791 2792
                let mut n = cx.tcx.lift(&n).unwrap();
                if let ConstVal::Unevaluated(def_id, substs) = n.val {
                    let param_env = cx.tcx.param_env(def_id);
O
Oliver Schneider 已提交
2793 2794 2795 2796 2797
                    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)) {
2798 2799
                        n = new_n;
                    }
2800
                };
O
Oliver Schneider 已提交
2801
                let n = print_const(cx, n);
2802 2803
                Array(box ty.clean(cx), n)
            }
2804
            ty::TyRawPtr(mt) => RawPointer(mt.mutbl.clean(cx), box mt.ty.clean(cx)),
2805
            ty::TyRef(r, ty, mutbl) => BorrowedRef {
2806
                lifetime: r.clean(cx),
2807 2808
                mutability: mutbl.clean(cx),
                type_: box ty.clean(cx),
2809
            },
2810 2811 2812 2813 2814 2815
            ty::TyFnDef(..) |
            ty::TyFnPtr(_) => {
                let ty = cx.tcx.lift(self).unwrap();
                let sig = ty.fn_sig(cx.tcx);
                BareFunction(box BareFunctionDecl {
                    unsafety: sig.unsafety(),
2816
                    generic_params: Vec::new(),
2817 2818 2819 2820
                    decl: (cx.tcx.hir.local_def_id(ast::CRATE_NODE_ID), sig).clean(cx),
                    abi: sig.abi(),
                })
            }
2821
            ty::TyAdt(def, substs) => {
2822
                let did = def.did;
2823
                let kind = match def.adt_kind() {
2824 2825 2826
                    AdtKind::Struct => TypeKind::Struct,
                    AdtKind::Union => TypeKind::Union,
                    AdtKind::Enum => TypeKind::Enum,
2827
                };
M
mitaa 已提交
2828
                inline::record_extern_fqn(cx, did, kind);
2829
                let path = external_path(cx, &cx.tcx.item_name(did).as_str(),
2830
                                         None, false, vec![], substs);
2831
                ResolvedPath {
2832
                    path,
2833
                    typarams: None,
2834
                    did,
2835
                    is_generic: false,
2836 2837
                }
            }
P
Paul Lietar 已提交
2838 2839
            ty::TyForeign(did) => {
                inline::record_extern_fqn(cx, did, TypeKind::Foreign);
2840
                let path = external_path(cx, &cx.tcx.item_name(did).as_str(),
P
Paul Lietar 已提交
2841 2842 2843 2844 2845 2846 2847 2848
                                         None, false, vec![], Substs::empty());
                ResolvedPath {
                    path: path,
                    typarams: None,
                    did: did,
                    is_generic: false,
                }
            }
2849
            ty::TyDynamic(ref obj, ref reg) => {
2850 2851 2852 2853 2854
                if let Some(principal) = obj.principal() {
                    let did = principal.def_id();
                    inline::record_extern_fqn(cx, did, TypeKind::Trait);

                    let mut typarams = vec![];
2855
                    reg.clean(cx).map(|b| typarams.push(RegionBound(b)));
2856
                    for did in obj.auto_traits() {
2857
                        let empty = cx.tcx.intern_substs(&[]);
2858
                        let path = external_path(cx, &cx.tcx.item_name(did).as_str(),
2859 2860 2861 2862
                            Some(did), false, vec![], empty);
                        inline::record_extern_fqn(cx, did, TypeKind::Trait);
                        let bound = TraitBound(PolyTrait {
                            trait_: ResolvedPath {
2863
                                path,
2864
                                typarams: None,
2865
                                did,
2866 2867
                                is_generic: false,
                            },
2868
                            generic_params: Vec::new(),
2869 2870
                        }, hir::TraitBoundModifier::None);
                        typarams.push(bound);
2871
                    }
2872

2873
                    let mut bindings = vec![];
2874
                    for pb in obj.projection_bounds() {
2875
                        bindings.push(TypeBinding {
2876 2877
                            name: cx.tcx.associated_item(pb.item_def_id()).name.clean(cx),
                            ty: pb.skip_binder().ty.clean(cx)
2878 2879
                        });
                    }
2880

2881
                    let path = external_path(cx, &cx.tcx.item_name(did).as_str(), Some(did),
2882
                        false, bindings, principal.skip_binder().substs);
2883
                    ResolvedPath {
2884
                        path,
2885
                        typarams: Some(typarams),
2886
                        did,
2887 2888 2889 2890
                        is_generic: false,
                    }
                } else {
                    Never
2891 2892
                }
            }
A
Andrew Cann 已提交
2893
            ty::TyTuple(ref t) => Tuple(t.clean(cx)),
2894

2895
            ty::TyProjection(ref data) => data.clean(cx),
2896

2897
            ty::TyParam(ref p) => Generic(p.name.to_string()),
2898

2899 2900 2901
            ty::TyAnon(def_id, substs) => {
                // Grab the "TraitA + TraitB" from `impl TraitA + TraitB`,
                // by looking up the projections associated with the def_id.
2902
                let predicates_of = cx.tcx.predicates_of(def_id);
2903
                let substs = cx.tcx.lift(&substs).unwrap();
2904
                let bounds = predicates_of.instantiate(cx.tcx, substs);
2905 2906 2907
                let mut regions = vec![];
                let mut has_sized = false;
                let mut bounds = bounds.predicates.iter().filter_map(|predicate| {
2908 2909
                    let trait_ref = if let Some(tr) = predicate.to_opt_poly_trait_ref() {
                        tr
2910 2911 2912 2913
                    } else if let ty::Predicate::TypeOutlives(pred) = *predicate {
                        // these should turn up at the end
                        pred.skip_binder().1.clean(cx).map(|r| regions.push(RegionBound(r)));
                        return None;
2914 2915 2916 2917
                    } else {
                        return None;
                    };

2918 2919
                    if let Some(sized) = cx.tcx.lang_items().sized_trait() {
                        if trait_ref.def_id() == sized {
2920
                            has_sized = true;
2921 2922 2923 2924 2925
                            return None;
                        }
                    }


2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943
                    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)
                                                .name.clean(cx),
                                    ty: proj.ty.clean(cx),
                                })
                            } else {
                                None
                            }
                        } else {
                            None
                        }
                    ).collect();

                    Some((trait_ref.skip_binder(), bounds).clean(cx))
2944 2945 2946 2947 2948 2949
                }).collect::<Vec<_>>();
                bounds.extend(regions);
                if !has_sized && !bounds.is_empty() {
                    bounds.insert(0, TyParamBound::maybe_sized(cx));
                }
                ImplTrait(bounds)
2950 2951
            }

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

2954
            ty::TyGeneratorWitness(..) => panic!("TyGeneratorWitness"),
2955 2956
            ty::TyInfer(..) => panic!("TyInfer"),
            ty::TyError => panic!("TyError"),
2957 2958 2959 2960
        }
    }
}

2961
impl Clean<Item> for hir::StructField {
2962
    fn clean(&self, cx: &DocContext) -> Item {
C
Corey Richardson 已提交
2963
        Item {
2964 2965
            name: Some(self.name).clean(cx),
            attrs: self.attrs.clean(cx),
2966
            source: self.span.clean(cx),
2967
            visibility: self.vis.clean(cx),
2968 2969 2970
            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),
2971
            inner: StructFieldItem(self.ty.clean(cx)),
C
Corey Richardson 已提交
2972 2973 2974 2975
        }
    }
}

2976
impl<'tcx> Clean<Item> for ty::FieldDef {
2977
    fn clean(&self, cx: &DocContext) -> Item {
2978
        Item {
2979
            name: Some(self.name).clean(cx),
2980
            attrs: cx.tcx.get_attrs(self.did).clean(cx),
2981
            source: cx.tcx.def_span(self.did).clean(cx),
2982
            visibility: self.vis.clean(cx),
2983
            stability: get_stability(cx, self.did),
2984
            deprecation: get_deprecation(cx, self.did),
2985
            def_id: self.did,
2986
            inner: StructFieldItem(cx.tcx.type_of(self.did).clean(cx)),
2987 2988 2989 2990
        }
    }
}

J
Jeffrey Seyfried 已提交
2991 2992 2993 2994 2995
#[derive(Clone, PartialEq, Eq, RustcDecodable, RustcEncodable, Debug)]
pub enum Visibility {
    Public,
    Inherited,
}
C
Corey Richardson 已提交
2996

2997
impl Clean<Option<Visibility>> for hir::Visibility {
2998
    fn clean(&self, _: &DocContext) -> Option<Visibility> {
J
Jeffrey Seyfried 已提交
2999
        Some(if *self == hir::Visibility::Public { Public } else { Inherited })
3000 3001 3002 3003 3004
    }
}

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

J
Jorge Aparicio 已提交
3009
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
3010
pub struct Struct {
3011 3012 3013 3014
    pub struct_type: doctree::StructType,
    pub generics: Generics,
    pub fields: Vec<Item>,
    pub fields_stripped: bool,
C
Corey Richardson 已提交
3015 3016
}

V
Vadim Petrochenkov 已提交
3017 3018 3019 3020 3021 3022 3023 3024
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
pub struct Union {
    pub struct_type: doctree::StructType,
    pub generics: Generics,
    pub fields: Vec<Item>,
    pub fields_stripped: bool,
}

3025 3026 3027 3028 3029 3030 3031
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),
3032 3033
            attrs: self.attrs.clean(cx),
            source: self.whence.clean(cx),
3034
            def_id: cx.tcx.hir.local_def_id(self.id),
3035 3036
            visibility: self.vis.clean(cx),
            stability: self.stab.clean(cx),
3037
            deprecation: self.depr.clean(cx),
C
Corey Richardson 已提交
3038 3039
            inner: StructItem(Struct {
                struct_type: self.struct_type,
3040 3041
                generics: self.generics.clean(cx),
                fields: self.fields.clean(cx),
S
Steven Fackler 已提交
3042
                fields_stripped: false,
C
Corey Richardson 已提交
3043
            }),
3044 3045 3046
        });

        ret
C
Corey Richardson 已提交
3047 3048 3049
    }
}

3050 3051 3052 3053 3054 3055 3056
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 已提交
3057 3058
            attrs: self.attrs.clean(cx),
            source: self.whence.clean(cx),
3059
            def_id: cx.tcx.hir.local_def_id(self.id),
V
Vadim Petrochenkov 已提交
3060 3061 3062 3063 3064 3065 3066 3067 3068
            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,
            }),
3069 3070 3071
        });

        ret
V
Vadim Petrochenkov 已提交
3072 3073 3074
    }
}

3075
/// This is a more limited form of the standard Struct, different in that
C
Corey Richardson 已提交
3076 3077
/// it lacks the things most items have (name, id, parameterization). Found
/// only as a variant in an enum.
J
Jorge Aparicio 已提交
3078
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
3079
pub struct VariantStruct {
3080 3081 3082
    pub struct_type: doctree::StructType,
    pub fields: Vec<Item>,
    pub fields_stripped: bool,
C
Corey Richardson 已提交
3083 3084
}

3085
impl Clean<VariantStruct> for ::rustc::hir::VariantData {
3086
    fn clean(&self, cx: &DocContext) -> VariantStruct {
C
Corey Richardson 已提交
3087 3088
        VariantStruct {
            struct_type: doctree::struct_type_from_def(self),
3089
            fields: self.fields().iter().map(|x| x.clean(cx)).collect(),
S
Steven Fackler 已提交
3090
            fields_stripped: false,
C
Corey Richardson 已提交
3091 3092 3093 3094
        }
    }
}

J
Jorge Aparicio 已提交
3095
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
3096
pub struct Enum {
3097 3098 3099
    pub variants: Vec<Item>,
    pub generics: Generics,
    pub variants_stripped: bool,
C
Corey Richardson 已提交
3100 3101
}

3102 3103 3104 3105 3106 3107 3108
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),
3109 3110
            attrs: self.attrs.clean(cx),
            source: self.whence.clean(cx),
3111
            def_id: cx.tcx.hir.local_def_id(self.id),
3112 3113
            visibility: self.vis.clean(cx),
            stability: self.stab.clean(cx),
3114
            deprecation: self.depr.clean(cx),
C
Corey Richardson 已提交
3115
            inner: EnumItem(Enum {
3116 3117
                variants: self.variants.clean(cx),
                generics: self.generics.clean(cx),
S
Steven Fackler 已提交
3118
                variants_stripped: false,
C
Corey Richardson 已提交
3119
            }),
3120 3121 3122
        });

        ret
C
Corey Richardson 已提交
3123 3124 3125
    }
}

J
Jorge Aparicio 已提交
3126
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
3127
pub struct Variant {
3128
    pub kind: VariantKind,
C
Corey Richardson 已提交
3129 3130 3131
}

impl Clean<Item> for doctree::Variant {
3132
    fn clean(&self, cx: &DocContext) -> Item {
C
Corey Richardson 已提交
3133
        Item {
3134 3135 3136
            name: Some(self.name.clean(cx)),
            attrs: self.attrs.clean(cx),
            source: self.whence.clean(cx),
3137
            visibility: None,
3138
            stability: self.stab.clean(cx),
3139
            deprecation: self.depr.clean(cx),
3140
            def_id: cx.tcx.hir.local_def_id(self.def.id()),
C
Corey Richardson 已提交
3141
            inner: VariantItem(Variant {
3142
                kind: self.def.clean(cx),
C
Corey Richardson 已提交
3143 3144 3145 3146 3147
            }),
        }
    }
}

3148
impl<'tcx> Clean<Item> for ty::VariantDef {
3149
    fn clean(&self, cx: &DocContext) -> Item {
3150 3151 3152
        let kind = match self.ctor_kind {
            CtorKind::Const => VariantKind::CLike,
            CtorKind::Fn => {
3153
                VariantKind::Tuple(
3154
                    self.fields.iter().map(|f| cx.tcx.type_of(f.did).clean(cx)).collect()
3155
                )
3156
            }
3157
            CtorKind::Fictive => {
3158
                VariantKind::Struct(VariantStruct {
3159 3160
                    struct_type: doctree::Plain,
                    fields_stripped: false,
3161
                    fields: self.fields.iter().map(|field| {
3162
                        Item {
3163
                            source: cx.tcx.def_span(field.did).clean(cx),
3164
                            name: Some(field.name.clean(cx)),
3165
                            attrs: cx.tcx.get_attrs(field.did).clean(cx),
3166
                            visibility: field.vis.clean(cx),
3167 3168 3169
                            def_id: field.did,
                            stability: get_stability(cx, field.did),
                            deprecation: get_deprecation(cx, field.did),
3170
                            inner: StructFieldItem(cx.tcx.type_of(field.did).clean(cx))
3171 3172 3173 3174 3175 3176
                        }
                    }).collect()
                })
            }
        };
        Item {
3177
            name: Some(self.name.clean(cx)),
3178
            attrs: inline::load_attrs(cx, self.did),
3179
            source: cx.tcx.def_span(self.did).clean(cx),
J
Jeffrey Seyfried 已提交
3180
            visibility: Some(Inherited),
3181
            def_id: self.did,
3182
            inner: VariantItem(Variant { kind: kind }),
3183
            stability: get_stability(cx, self.did),
3184
            deprecation: get_deprecation(cx, self.did),
3185 3186 3187 3188
        }
    }
}

J
Jorge Aparicio 已提交
3189
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
3190
pub enum VariantKind {
3191 3192 3193
    CLike,
    Tuple(Vec<Type>),
    Struct(VariantStruct),
C
Corey Richardson 已提交
3194 3195
}

3196 3197 3198
impl Clean<VariantKind> for hir::VariantData {
    fn clean(&self, cx: &DocContext) -> VariantKind {
        if self.is_struct() {
3199
            VariantKind::Struct(self.clean(cx))
3200
        } else if self.is_unit() {
3201
            VariantKind::CLike
3202
        } else {
3203
            VariantKind::Tuple(self.fields().iter().map(|x| x.ty.clean(cx)).collect())
3204
        }
3205 3206 3207
    }
}

J
Jorge Aparicio 已提交
3208
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
3209
pub struct Span {
3210
    pub filename: FileName,
3211 3212 3213 3214
    pub loline: usize,
    pub locol: usize,
    pub hiline: usize,
    pub hicol: usize,
3215 3216
}

3217
impl Span {
3218
    pub fn empty() -> Span {
3219
        Span {
3220
            filename: FileName::Anon,
3221 3222 3223 3224 3225 3226
            loline: 0, locol: 0,
            hiline: 0, hicol: 0,
        }
    }
}

3227
impl Clean<Span> for syntax_pos::Span {
3228
    fn clean(&self, cx: &DocContext) -> Span {
3229 3230 3231 3232
        if *self == DUMMY_SP {
            return Span::empty();
        }

3233
        let cm = cx.sess().codemap();
3234
        let filename = cm.span_to_filename(*self);
3235 3236
        let lo = cm.lookup_char_pos(self.lo());
        let hi = cm.lookup_char_pos(self.hi());
3237
        Span {
3238
            filename,
3239
            loline: lo.line,
3240
            locol: lo.col.to_usize(),
3241
            hiline: hi.line,
3242
            hicol: hi.col.to_usize(),
3243
        }
C
Corey Richardson 已提交
3244 3245 3246
    }
}

3247
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)]
C
Corey Richardson 已提交
3248
pub struct Path {
3249
    pub global: bool,
3250
    pub def: Def,
3251
    pub segments: Vec<PathSegment>,
C
Corey Richardson 已提交
3252 3253
}

3254 3255 3256 3257
impl Path {
    pub fn singleton(name: String) -> Path {
        Path {
            global: false,
3258
            def: Def::Err,
3259
            segments: vec![PathSegment {
3260
                name,
3261 3262 3263
                params: PathParameters::AngleBracketed {
                    lifetimes: Vec::new(),
                    types: Vec::new(),
A
Aaron Hill 已提交
3264
                    bindings: Vec::new(),
3265 3266 3267 3268
                }
            }]
        }
    }
3269

B
bluss 已提交
3270
    pub fn last_name(&self) -> &str {
E
Esteban Küber 已提交
3271
        self.segments.last().unwrap().name.as_str()
3272
    }
3273 3274
}

3275
impl Clean<Path> for hir::Path {
3276
    fn clean(&self, cx: &DocContext) -> Path {
C
Corey Richardson 已提交
3277
        Path {
3278
            global: self.is_global(),
3279
            def: self.def,
3280
            segments: if self.is_global() { &self.segments[1..] } else { &self.segments }.clean(cx),
3281 3282 3283 3284
        }
    }
}

3285
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)]
3286 3287 3288 3289
pub enum PathParameters {
    AngleBracketed {
        lifetimes: Vec<Lifetime>,
        types: Vec<Type>,
3290
        bindings: Vec<TypeBinding>,
3291 3292 3293
    },
    Parenthesized {
        inputs: Vec<Type>,
3294
        output: Option<Type>,
3295
    }
3296 3297
}

3298
impl Clean<PathParameters> for hir::PathParameters {
3299
    fn clean(&self, cx: &DocContext) -> PathParameters {
3300 3301 3302 3303 3304
        if self.parenthesized {
            let output = self.bindings[0].ty.clean(cx);
            PathParameters::Parenthesized {
                inputs: self.inputs().clean(cx),
                output: if output != Type::Tuple(Vec::new()) { Some(output) } else { None }
3305
            }
3306 3307 3308 3309 3310 3311 3312 3313 3314
        } else {
            PathParameters::AngleBracketed {
                lifetimes: if self.lifetimes.iter().all(|lt| lt.is_elided()) {
                    vec![]
                } else {
                    self.lifetimes.clean(cx)
                },
                types: self.types.clean(cx),
                bindings: self.bindings.clean(cx),
3315
            }
3316 3317 3318
        }
    }
}
3319

3320
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)]
3321 3322
pub struct PathSegment {
    pub name: String,
3323
    pub params: PathParameters,
3324 3325
}

3326
impl Clean<PathSegment> for hir::PathSegment {
3327
    fn clean(&self, cx: &DocContext) -> PathSegment {
3328
        PathSegment {
V
Vadim Petrochenkov 已提交
3329
            name: self.name.clean(cx),
3330
            params: self.with_parameters(|parameters| parameters.clean(cx))
C
Corey Richardson 已提交
3331 3332 3333 3334
        }
    }
}

3335 3336 3337 3338
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 已提交
3339
        }
3340 3341
        Type::Tuple(inner_tys) => {
            Type::Tuple(inner_tys.iter().map(|t| strip_type(t.clone())).collect())
A
Aaron Hill 已提交
3342
        }
3343 3344 3345 3346 3347 3348
        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 已提交
3349
        }
3350 3351 3352 3353 3354
        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 已提交
3355
        }
3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366
        _ => ty
    }
}

fn strip_path(path: &Path) -> Path {
    let segments = path.segments.iter().map(|s| {
        PathSegment {
            name: s.name.clone(),
            params: PathParameters::AngleBracketed {
                lifetimes: Vec::new(),
                types: Vec::new(),
A
Aaron Hill 已提交
3367
                bindings: Vec::new(),
3368 3369 3370 3371 3372 3373 3374
            }
        }
    }).collect();

    Path {
        global: path.global,
        def: path.def.clone(),
A
Aaron Hill 已提交
3375
        segments,
3376 3377 3378
    }
}

3379
fn qpath_to_string(p: &hir::QPath) -> String {
3380 3381 3382
    let segments = match *p {
        hir::QPath::Resolved(_, ref path) => &path.segments,
        hir::QPath::TypeRelative(_, ref segment) => return segment.name.to_string(),
3383 3384
    };

3385
    let mut s = String::new();
3386 3387
    for (i, seg) in segments.iter().enumerate() {
        if i > 0 {
C
Corey Richardson 已提交
3388 3389
            s.push_str("::");
        }
3390 3391 3392
        if seg.name != keywords::CrateRoot.name() {
            s.push_str(&*seg.name.as_str());
        }
C
Corey Richardson 已提交
3393
    }
3394
    s
C
Corey Richardson 已提交
3395 3396
}

3397
impl Clean<String> for ast::Name {
3398
    fn clean(&self, _: &DocContext) -> String {
3399
        self.to_string()
3400 3401 3402
    }
}

3403 3404 3405 3406 3407 3408
impl Clean<String> for InternedString {
    fn clean(&self, _: &DocContext) -> String {
        self.to_string()
    }
}

J
Jorge Aparicio 已提交
3409
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
3410
pub struct Typedef {
3411 3412
    pub type_: Type,
    pub generics: Generics,
C
Corey Richardson 已提交
3413 3414 3415
}

impl Clean<Item> for doctree::Typedef {
3416
    fn clean(&self, cx: &DocContext) -> Item {
C
Corey Richardson 已提交
3417
        Item {
3418 3419 3420
            name: Some(self.name.clean(cx)),
            attrs: self.attrs.clean(cx),
            source: self.whence.clean(cx),
3421
            def_id: cx.tcx.hir.local_def_id(self.id.clone()),
3422 3423
            visibility: self.vis.clean(cx),
            stability: self.stab.clean(cx),
3424
            deprecation: self.depr.clean(cx),
C
Corey Richardson 已提交
3425
            inner: TypedefItem(Typedef {
3426 3427
                type_: self.ty.clean(cx),
                generics: self.gen.clean(cx),
3428
            }, false),
C
Corey Richardson 已提交
3429 3430 3431 3432
        }
    }
}

3433
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)]
C
Corey Richardson 已提交
3434
pub struct BareFunctionDecl {
3435
    pub unsafety: hir::Unsafety,
V
varkor 已提交
3436
    pub generic_params: Vec<GenericParamDef>,
3437
    pub decl: FnDecl,
3438
    pub abi: Abi,
C
Corey Richardson 已提交
3439 3440
}

3441
impl Clean<BareFunctionDecl> for hir::BareFnTy {
3442
    fn clean(&self, cx: &DocContext) -> BareFunctionDecl {
3443 3444 3445
        let (generic_params, decl) = enter_impl_trait(cx, || {
            (self.generic_params.clean(cx), (&*self.decl, &self.arg_names[..]).clean(cx))
        });
C
Corey Richardson 已提交
3446
        BareFunctionDecl {
N
Niko Matsakis 已提交
3447
            unsafety: self.unsafety,
3448
            decl,
3449
            generic_params,
3450
            abi: self.abi,
C
Corey Richardson 已提交
3451 3452 3453 3454
        }
    }
}

J
Jorge Aparicio 已提交
3455
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
3456
pub struct Static {
3457 3458
    pub type_: Type,
    pub mutability: Mutability,
C
Corey Richardson 已提交
3459 3460 3461
    /// 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.
3462
    pub expr: String,
C
Corey Richardson 已提交
3463 3464 3465
}

impl Clean<Item> for doctree::Static {
3466
    fn clean(&self, cx: &DocContext) -> Item {
3467
        debug!("cleaning static {}: {:?}", self.name.clean(cx), self);
C
Corey Richardson 已提交
3468
        Item {
3469 3470 3471
            name: Some(self.name.clean(cx)),
            attrs: self.attrs.clean(cx),
            source: self.whence.clean(cx),
3472
            def_id: cx.tcx.hir.local_def_id(self.id),
3473 3474
            visibility: self.vis.clean(cx),
            stability: self.stab.clean(cx),
3475
            deprecation: self.depr.clean(cx),
C
Corey Richardson 已提交
3476
            inner: StaticItem(Static {
3477 3478
                type_: self.type_.clean(cx),
                mutability: self.mutability.clean(cx),
3479
                expr: print_const_expr(cx, self.expr),
C
Corey Richardson 已提交
3480 3481 3482 3483 3484
            }),
        }
    }
}

J
Jorge Aparicio 已提交
3485
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496
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),
3497
            def_id: cx.tcx.hir.local_def_id(self.id),
3498 3499
            visibility: self.vis.clean(cx),
            stability: self.stab.clean(cx),
3500
            deprecation: self.depr.clean(cx),
3501 3502
            inner: ConstantItem(Constant {
                type_: self.type_.clean(cx),
3503
                expr: print_const_expr(cx, self.expr),
3504 3505 3506 3507 3508
            }),
        }
    }
}

3509
#[derive(Debug, Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Copy, Hash)]
C
Corey Richardson 已提交
3510 3511 3512 3513 3514
pub enum Mutability {
    Mutable,
    Immutable,
}

3515
impl Clean<Mutability> for hir::Mutability {
3516
    fn clean(&self, _: &DocContext) -> Mutability {
C
Corey Richardson 已提交
3517
        match self {
3518 3519
            &hir::MutMutable => Mutable,
            &hir::MutImmutable => Immutable,
C
Corey Richardson 已提交
3520 3521 3522 3523
        }
    }
}

3524
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Copy, Debug, Hash)]
3525 3526 3527 3528 3529
pub enum ImplPolarity {
    Positive,
    Negative,
}

3530
impl Clean<ImplPolarity> for hir::ImplPolarity {
3531 3532
    fn clean(&self, _: &DocContext) -> ImplPolarity {
        match self {
3533 3534
            &hir::ImplPolarity::Positive => ImplPolarity::Positive,
            &hir::ImplPolarity::Negative => ImplPolarity::Negative,
3535 3536 3537 3538
        }
    }
}

J
Jorge Aparicio 已提交
3539
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
C
Corey Richardson 已提交
3540
pub struct Impl {
3541
    pub unsafety: hir::Unsafety,
3542
    pub generics: Generics,
3543
    pub provided_trait_methods: FxHashSet<String>,
3544 3545
    pub trait_: Option<Type>,
    pub for_: Type,
3546
    pub items: Vec<Item>,
3547
    pub polarity: Option<ImplPolarity>,
3548 3549 3550 3551
    pub synthetic: bool,
}

pub fn get_auto_traits_with_node_id(cx: &DocContext, id: ast::NodeId, name: String) -> Vec<Item> {
3552
    let finder = AutoTraitFinder::new(cx);
3553 3554 3555 3556
    finder.get_with_node_id(id, name)
}

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

    finder.get_with_def_id(id)
C
Corey Richardson 已提交
3560 3561
}

3562 3563 3564 3565 3566 3567 3568 3569
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.
3570
        if trait_.def_id() == cx.tcx.lang_items().deref_trait() {
3571
            build_deref_target_impls(cx, &items, &mut ret);
3572 3573
        }

3574 3575 3576 3577 3578
        let provided = trait_.def_id().map(|did| {
            cx.tcx.provided_trait_methods(did)
                  .into_iter()
                  .map(|meth| meth.name.to_string())
                  .collect()
3579
        }).unwrap_or(FxHashSet());
3580

3581
        ret.push(Item {
C
Corey Richardson 已提交
3582
            name: None,
3583 3584
            attrs: self.attrs.clean(cx),
            source: self.whence.clean(cx),
3585
            def_id: cx.tcx.hir.local_def_id(self.id),
3586 3587
            visibility: self.vis.clean(cx),
            stability: self.stab.clean(cx),
3588
            deprecation: self.depr.clean(cx),
C
Corey Richardson 已提交
3589
            inner: ImplItem(Impl {
3590
                unsafety: self.unsafety,
3591
                generics: self.generics.clean(cx),
3592
                provided_trait_methods: provided,
3593
                trait_,
3594
                for_: self.for_.clean(cx),
3595
                items,
3596
                polarity: Some(self.polarity.clean(cx)),
A
Aaron Hill 已提交
3597
                synthetic: false,
3598
            })
3599
        });
M
mitaa 已提交
3600
        ret
3601 3602 3603 3604 3605 3606
    }
}

fn build_deref_target_impls(cx: &DocContext,
                            items: &[Item],
                            ret: &mut Vec<Item>) {
3607
    use self::PrimitiveType::*;
3608
    let tcx = cx.tcx;
3609 3610 3611

    for item in items {
        let target = match item.inner {
3612
            TypedefItem(ref t, true) => &t.type_,
3613 3614 3615
            _ => continue,
        };
        let primitive = match *target {
N
Niko Matsakis 已提交
3616
            ResolvedPath { did, .. } if did.is_local() => continue,
3617
            ResolvedPath { did, .. } => {
3618 3619 3620 3621 3622
                // 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));
3623 3624 3625 3626 3627 3628 3629 3630
                continue
            }
            _ => match target.primitive_type() {
                Some(prim) => prim,
                None => continue,
            }
        };
        let did = match primitive {
3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645
            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(),
3646
            Bool => None,
3647 3648 3649
            Str => tcx.lang_items().str_impl(),
            Slice => tcx.lang_items().slice_impl(),
            Array => tcx.lang_items().slice_impl(),
3650
            Tuple => None,
3651
            Unit => None,
3652
            RawPointer => tcx.lang_items().const_ptr_impl(),
3653
            Reference => None,
3654
            Fn => None,
A
Andrew Cann 已提交
3655
            Never => None,
3656 3657
        };
        if let Some(did) = did {
N
Niko Matsakis 已提交
3658
            if !did.is_local() {
3659
                inline::build_impl(cx, did, ret);
3660
            }
C
Corey Richardson 已提交
3661 3662 3663 3664
        }
    }
}

3665 3666 3667 3668 3669 3670
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 已提交
3671
            def_id: DefId { krate: self.cnum, index: CRATE_DEF_INDEX },
3672 3673
            visibility: self.vis.clean(cx),
            stability: None,
3674
            deprecation: None,
3675 3676 3677
            inner: ExternCrateItem(self.name.clean(cx), self.path.clone())
        }
    }
C
Corey Richardson 已提交
3678 3679
}

3680
impl Clean<Vec<Item>> for doctree::Import {
3681
    fn clean(&self, cx: &DocContext) -> Vec<Item> {
J
Joseph Crail 已提交
3682
        // We consider inlining the documentation of `pub use` statements, but we
3683 3684
        // forcefully don't inline if this is not public or if the
        // #[doc(no_inline)] attribute is present.
3685
        // Don't inline doc(hidden) imports so they can be stripped at a later stage.
3686
        let denied = self.vis != hir::Public || self.attrs.iter().any(|a| {
3687
            a.name() == "doc" && match a.meta_item_list() {
3688 3689
                Some(l) => attr::list_contains_name(&l, "no_inline") ||
                           attr::list_contains_name(&l, "hidden"),
3690 3691 3692
                None => false,
            }
        });
3693 3694
        let path = self.path.clean(cx);
        let inner = if self.glob {
3695
            Import::Glob(resolve_use_source(cx, path))
3696 3697 3698
        } else {
            let name = self.name;
            if !denied {
3699 3700
                let mut visited = FxHashSet();
                if let Some(items) = inline::try_inline(cx, path.def, name, &mut visited) {
3701
                    return items;
3702
                }
3703
            }
3704
            Import::Simple(name.clean(cx), resolve_use_source(cx, path))
3705
        };
3706
        vec![Item {
3707 3708 3709
            name: None,
            attrs: self.attrs.clean(cx),
            source: self.whence.clean(cx),
3710
            def_id: cx.tcx.hir.local_def_id(ast::CRATE_NODE_ID),
3711 3712
            visibility: self.vis.clean(cx),
            stability: None,
3713
            deprecation: None,
3714
            inner: ImportItem(inner)
3715
        }]
C
Corey Richardson 已提交
3716 3717 3718
    }
}

J
Jorge Aparicio 已提交
3719
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
3720
pub enum Import {
3721
    // use source as str;
3722
    Simple(String, ImportSource),
A
Alex Crichton 已提交
3723
    // use source::*;
3724
    Glob(ImportSource)
A
Alex Crichton 已提交
3725 3726
}

J
Jorge Aparicio 已提交
3727
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
A
Alex Crichton 已提交
3728
pub struct ImportSource {
3729
    pub path: Path,
N
Niko Matsakis 已提交
3730
    pub did: Option<DefId>,
C
Corey Richardson 已提交
3731 3732
}

3733
impl Clean<Vec<Item>> for hir::ForeignMod {
3734
    fn clean(&self, cx: &DocContext) -> Vec<Item> {
3735 3736
        let mut items = self.items.clean(cx);
        for item in &mut items {
M
mitaa 已提交
3737 3738
            if let ForeignFunctionItem(ref mut f) = item.inner {
                f.abi = self.abi;
3739 3740 3741
            }
        }
        items
3742 3743 3744
    }
}

3745
impl Clean<Item> for hir::ForeignItem {
3746
    fn clean(&self, cx: &DocContext) -> Item {
3747
        let inner = match self.node {
3748
            hir::ForeignItemFn(ref decl, ref names, ref generics) => {
3749 3750 3751
                let (generics, decl) = enter_impl_trait(cx, || {
                    (generics.clean(cx), (&**decl, &names[..]).clean(cx))
                });
3752
                ForeignFunctionItem(Function {
3753
                    decl,
3754
                    generics,
3755
                    unsafety: hir::Unsafety::Unsafe,
3756
                    abi: Abi::Rust,
3757
                    constness: hir::Constness::NotConst,
3758 3759
                })
            }
3760
            hir::ForeignItemStatic(ref ty, mutbl) => {
3761
                ForeignStaticItem(Static {
3762
                    type_: ty.clean(cx),
3763
                    mutability: if mutbl {Mutable} else {Immutable},
3764
                    expr: "".to_string(),
3765 3766
                })
            }
P
Paul Lietar 已提交
3767 3768 3769
            hir::ForeignItemType => {
                ForeignTypeItem
            }
3770 3771
        };
        Item {
V
Vadim Petrochenkov 已提交
3772
            name: Some(self.name.clean(cx)),
3773 3774
            attrs: self.attrs.clean(cx),
            source: self.span.clean(cx),
3775
            def_id: cx.tcx.hir.local_def_id(self.id),
3776
            visibility: self.vis.clean(cx),
3777 3778
            stability: get_stability(cx, cx.tcx.hir.local_def_id(self.id)),
            deprecation: get_deprecation(cx, cx.tcx.hir.local_def_id(self.id)),
3779
            inner,
3780 3781 3782 3783
        }
    }
}

C
Corey Richardson 已提交
3784 3785 3786
// Utilities

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

3790
impl ToSource for syntax_pos::Span {
3791
    fn to_src(&self, cx: &DocContext) -> String {
3792
        debug!("converting span {:?} to snippet", self.clean(cx));
3793
        let sn = match cx.sess().codemap().span_to_snippet(*self) {
3794 3795
            Ok(x) => x.to_string(),
            Err(_) => "".to_string()
C
Corey Richardson 已提交
3796
        };
3797
        debug!("got snippet {}", sn);
C
Corey Richardson 已提交
3798 3799 3800 3801
        sn
    }
}

3802
fn name_from_pat(p: &hir::Pat) -> String {
3803
    use rustc::hir::*;
3804
    debug!("Trying to get a name from pattern: {:?}", p);
3805

C
Corey Richardson 已提交
3806
    match p.node {
3807
        PatKind::Wild => "_".to_string(),
3808
        PatKind::Binding(_, _, ref p, _) => p.node.to_string(),
3809
        PatKind::TupleStruct(ref p, ..) | PatKind::Path(ref p) => qpath_to_string(p),
3810
        PatKind::Struct(ref name, ref fields, etc) => {
3811
            format!("{} {{ {}{} }}", qpath_to_string(name),
3812
                fields.iter().map(|&Spanned { node: ref fp, .. }|
3813
                                  format!("{}: {}", fp.name, name_from_pat(&*fp.pat)))
3814
                             .collect::<Vec<String>>().join(", "),
3815 3816
                if etc { ", ..." } else { "" }
            )
3817
        }
3818
        PatKind::Tuple(ref elts, _) => format!("({})", elts.iter().map(|p| name_from_pat(&**p))
3819
                                            .collect::<Vec<String>>().join(", ")),
3820 3821 3822 3823
        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, \
3824
                  which is silly in function arguments");
3825
            "()".to_string()
3826
        },
3827
        PatKind::Range(..) => panic!("tried to get argument name from PatKind::Range, \
3828
                              which is not allowed in function arguments"),
3829
        PatKind::Slice(ref begin, ref mid, ref end) => {
3830 3831 3832
            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));
3833
            format!("[{}]", begin.chain(mid).chain(end).collect::<Vec<_>>().join(", "))
3834
        },
C
Corey Richardson 已提交
3835 3836 3837
    }
}

O
Oliver Schneider 已提交
3838 3839 3840 3841 3842 3843 3844 3845 3846
fn print_const(cx: &DocContext, n: &ty::Const) -> String {
    match n.val {
        ConstVal::Unevaluated(def_id, _) => {
            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)
            }
        },
3847
        ConstVal::Value(..) => {
O
Oliver Schneider 已提交
3848
            let mut s = String::new();
3849
            ::rustc::mir::fmt_const_val(&mut s, n).unwrap();
O
Oliver Schneider 已提交
3850 3851 3852 3853 3854 3855 3856 3857 3858 3859
            // array lengths are obviously usize
            if s.ends_with("usize") {
                let n = s.len() - "usize".len();
                s.truncate(n);
            }
            s
        },
    }
}

3860
fn print_const_expr(cx: &DocContext, body: hir::BodyId) -> String {
3861
    cx.tcx.hir.node_to_pretty_string(body.node_id)
3862 3863
}

3864
/// Given a type Path, resolve it to a Type using the TyCtxt
N
Niko Matsakis 已提交
3865 3866
fn resolve_type(cx: &DocContext,
                path: Path,
3867
                id: ast::NodeId) -> Type {
3868 3869 3870 3871 3872
    if id == ast::DUMMY_NODE_ID {
        debug!("resolve_type({:?})", path);
    } else {
        debug!("resolve_type({:?},{:?})", path, id);
    }
3873

3874
    let is_generic = match path.def {
3875
        Def::PrimTy(p) => match p {
3876 3877 3878
            hir::TyStr => return Primitive(PrimitiveType::Str),
            hir::TyBool => return Primitive(PrimitiveType::Bool),
            hir::TyChar => return Primitive(PrimitiveType::Char),
3879
            hir::TyInt(int_ty) => return Primitive(int_ty.into()),
3880
            hir::TyUint(uint_ty) => return Primitive(uint_ty.into()),
3881
            hir::TyFloat(float_ty) => return Primitive(float_ty.into()),
C
Corey Richardson 已提交
3882
        },
3883
        Def::SelfTy(..) if path.segments.len() == 1 => {
3884
            return Generic(keywords::SelfType.name().to_string());
3885
        }
3886 3887 3888
        Def::TyParam(..) if path.segments.len() == 1 => {
            return Generic(format!("{:#}", path));
        }
3889
        Def::SelfTy(..) | Def::TyParam(..) | Def::AssociatedTy(..) => true,
3890
        _ => false,
3891
    };
3892
    let did = register_def(&*cx, path.def);
3893
    ResolvedPath { path: path, typarams: None, did: did, is_generic: is_generic }
3894 3895
}

3896
fn register_def(cx: &DocContext, def: Def) -> DefId {
3897 3898
    debug!("register_def({:?})", def);

3899
    let (did, kind) = match def {
3900 3901 3902 3903 3904 3905 3906
        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),
3907
        Def::TyForeign(i) => (i, TypeKind::Foreign),
3908
        Def::Const(i) => (i, TypeKind::Const),
3909
        Def::Static(i, _) => (i, TypeKind::Static),
3910
        Def::Variant(i) => (cx.tcx.parent_def_id(i).unwrap(), TypeKind::Enum),
M
Manish Goregaokar 已提交
3911
        Def::Macro(i, _) => (i, TypeKind::Macro),
3912
        Def::SelfTy(Some(def_id), _) => (def_id, TypeKind::Trait),
3913 3914
        Def::SelfTy(_, Some(impl_def_id)) => {
            return impl_def_id
3915
        }
3916
        _ => return def.def_id()
C
Corey Richardson 已提交
3917
    };
N
Niko Matsakis 已提交
3918
    if did.is_local() { return did }
3919
    inline::record_extern_fqn(cx, did, kind);
3920
    if let TypeKind::Trait = kind {
3921
        inline::record_extern_trait(cx, did);
3922
    }
M
mitaa 已提交
3923
    did
C
Corey Richardson 已提交
3924
}
A
Alex Crichton 已提交
3925

3926
fn resolve_use_source(cx: &DocContext, path: Path) -> ImportSource {
A
Alex Crichton 已提交
3927
    ImportSource {
3928 3929 3930 3931 3932
        did: if path.def == Def::Err {
            None
        } else {
            Some(register_def(cx, path.def))
        },
3933
        path,
A
Alex Crichton 已提交
3934 3935 3936
    }
}

J
Jorge Aparicio 已提交
3937
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
3938
pub struct Macro {
3939
    pub source: String,
3940
    pub imported_from: Option<String>,
3941 3942 3943
}

impl Clean<Item> for doctree::Macro {
3944
    fn clean(&self, cx: &DocContext) -> Item {
3945
        let name = self.name.clean(cx);
3946
        Item {
3947
            name: Some(name.clone()),
3948 3949
            attrs: self.attrs.clean(cx),
            source: self.whence.clean(cx),
J
Jeffrey Seyfried 已提交
3950
            visibility: Some(Public),
3951
            stability: self.stab.clean(cx),
3952
            deprecation: self.depr.clean(cx),
3953
            def_id: self.def_id,
3954
            inner: MacroItem(Macro {
3955
                source: format!("macro_rules! {} {{\n{}}}",
3956 3957 3958 3959
                                name,
                                self.matchers.iter().map(|span| {
                                    format!("    {} => {{ ... }};\n", span.to_src(cx))
                                }).collect::<String>()),
3960
                imported_from: self.imported_from.clean(cx),
3961 3962 3963 3964
            }),
        }
    }
}
3965

J
Jorge Aparicio 已提交
3966
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
3967
pub struct Stability {
V
Vadim Petrochenkov 已提交
3968
    pub level: stability::StabilityLevel,
3969 3970
    pub feature: String,
    pub since: String,
3971
    pub deprecated_since: String,
3972 3973
    pub deprecated_reason: String,
    pub unstable_reason: String,
3974
    pub issue: Option<u32>
3975 3976
}

3977 3978 3979 3980 3981 3982
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
pub struct Deprecation {
    pub since: String,
    pub note: String,
}

3983
impl Clean<Stability> for attr::Stability {
3984 3985
    fn clean(&self, _: &DocContext) -> Stability {
        Stability {
V
Vadim Petrochenkov 已提交
3986
            level: stability::StabilityLevel::from_attr_level(&self.level),
3987
            feature: self.feature.to_string(),
V
Vadim Petrochenkov 已提交
3988 3989 3990 3991
            since: match self.level {
                attr::Stable {ref since} => since.to_string(),
                _ => "".to_string(),
            },
3992 3993
            deprecated_since: match self.rustc_depr {
                Some(attr::RustcDeprecation {ref since, ..}) => since.to_string(),
V
Vadim Petrochenkov 已提交
3994 3995
                _=> "".to_string(),
            },
3996 3997 3998 3999 4000 4001 4002
            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 已提交
4003 4004 4005 4006 4007
            },
            issue: match self.level {
                attr::Unstable {issue, ..} => Some(issue),
                _ => None,
            }
4008 4009 4010 4011 4012
        }
    }
}

impl<'a> Clean<Stability> for &'a attr::Stability {
V
Vadim Petrochenkov 已提交
4013 4014
    fn clean(&self, dc: &DocContext) -> Stability {
        (**self).clean(dc)
4015 4016
    }
}
A
Alex Crichton 已提交
4017

4018 4019 4020 4021 4022 4023 4024 4025 4026
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()),
        }
    }
}

4027
/// An equality constraint on an associated type, e.g. `A=Bar` in `Foo<A=Bar>`
4028
#[derive(Clone, PartialEq, Eq, RustcDecodable, RustcEncodable, Debug, Hash)]
4029 4030 4031 4032 4033
pub struct TypeBinding {
    pub name: String,
    pub ty: Type
}

4034
impl Clean<TypeBinding> for hir::TypeBinding {
4035 4036
    fn clean(&self, cx: &DocContext) -> TypeBinding {
        TypeBinding {
4037
            name: self.name.clean(cx),
4038 4039 4040 4041
            ty: self.ty.clean(cx)
        }
    }
}
4042 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056

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

4057
pub fn enter_impl_trait<F, R>(cx: &DocContext, f: F) -> R
4058 4059 4060
where
    F: FnOnce() -> R,
{
4061
    let old_bounds = mem::replace(&mut *cx.impl_trait_bounds.borrow_mut(), Default::default());
4062 4063 4064 4065 4066 4067
    let r = f();
    assert!(cx.impl_trait_bounds.borrow().is_empty());
    *cx.impl_trait_bounds.borrow_mut() = old_bounds;
    r
}

4068 4069 4070
// 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 已提交
4071
    if use_local {
4072 4073 4074
        path_to_def_local(tcx, path)
    } else {
        path_to_def(tcx, path)
A
Aaron Hill 已提交
4075
    }
4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126
}

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,
            };

4127
            for item in mem::replace(&mut items, Lrc::new(vec![])).iter() {
4128 4129 4130 4131
                if item.ident.name == *segment {
                    if path_it.peek().is_none() {
                        return match item.def {
                            def::Def::Trait(did) => Some(did),
A
Aaron Hill 已提交
4132
                            _ => None,
4133 4134 4135 4136 4137 4138 4139 4140 4141 4142 4143 4144 4145 4146 4147 4148 4149 4150 4151 4152 4153 4154 4155 4156 4157 4158 4159 4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171
                        }
                    }

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

fn get_path_for_type(tcx: TyCtxt, def_id: DefId, def_ctor: fn(DefId) -> Def) -> hir::Path {
    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 {
            name: ast::Name::intern(&s),
            parameters: None,
A
Aaron Hill 已提交
4172
            infer_types: false,
4173 4174 4175 4176 4177 4178 4179 4180 4181 4182 4183 4184 4185 4186 4187 4188 4189 4190 4191 4192 4193 4194
        }).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 {
    RegionBound(Lifetime),
V
varkor 已提交
4195
    TraitBound(Vec<PathSegment>, Vec<SimpleBound>, Vec<GenericParamDef>, hir::TraitBoundModifier)
4196 4197 4198 4199 4200 4201 4202 4203 4204 4205 4206 4207
}

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

impl AutoTraitResult {
    fn is_auto(&self) -> bool {
        match *self {
            AutoTraitResult::PositiveImpl(_) | AutoTraitResult::NegativeImpl => true,
A
Aaron Hill 已提交
4208
            _ => false,
4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225
        }
    }
}

impl From<TyParamBound> for SimpleBound {
    fn from(bound: TyParamBound) -> Self {
        match bound.clone() {
            TyParamBound::RegionBound(l) => SimpleBound::RegionBound(l),
            TyParamBound::TraitBound(t, mod_) => match t.trait_ {
                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 已提交
4226
                }
A
Aaron Hill 已提交
4227
                _ => panic!("Unexpected bound {:?}", bound),
4228 4229 4230 4231
            }
        }
    }
}