]> git.proxmox.com Git - rustc.git/blame - src/librustdoc/clean/mod.rs
New upstream version 1.20.0+dfsg1
[rustc.git] / src / librustdoc / clean / mod.rs
CommitLineData
1a4d82fc
JJ
1// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
2// file at the top-level directory of this distribution and at
3// http://rust-lang.org/COPYRIGHT.
4//
5// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8// option. This file may not be copied, modified, or distributed
9// except according to those terms.
10
11//! This module contains the "cleaned" pieces of the AST, and the functions
12//! that clean them.
13
1a4d82fc 14pub use self::Type::*;
1a4d82fc 15pub use self::Mutability::*;
1a4d82fc 16pub use self::ItemEnum::*;
1a4d82fc
JJ
17pub use self::TyParamBound::*;
18pub use self::SelfTy::*;
19pub use self::FunctionRetTy::*;
a7813a04 20pub use self::Visibility::*;
1a4d82fc 21
7453a54e 22use syntax::abi::Abi;
1a4d82fc 23use syntax::ast;
b039eaaf 24use syntax::attr;
3157f602 25use syntax::codemap::Spanned;
1a4d82fc 26use syntax::ptr::P;
476ff2be 27use syntax::symbol::keywords;
3157f602 28use syntax_pos::{self, DUMMY_SP, Pos};
1a4d82fc 29
a7813a04 30use rustc::middle::privacy::AccessLevels;
32a655c1 31use rustc::middle::resolve_lifetime as rl;
476ff2be 32use rustc::middle::lang_items;
c30ab7b3 33use rustc::hir::def::{Def, CtorKind};
476ff2be 34use rustc::hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
9e0c209e
SL
35use rustc::ty::subst::Substs;
36use rustc::ty::{self, AdtKind};
1a4d82fc 37use rustc::middle::stability;
476ff2be 38use rustc::util::nodemap::{FxHashMap, FxHashSet};
7cac9316 39use rustc_typeck::hir_ty_to_ty;
1a4d82fc 40
54a0048b 41use rustc::hir;
e9174d1e 42
cc61c64b 43use std::{mem, slice, vec};
9346a6ac 44use std::path::PathBuf;
1a4d82fc 45use std::rc::Rc;
a7813a04 46use std::sync::Arc;
1a4d82fc 47use std::u32;
1a4d82fc
JJ
48
49use core::DocContext;
50use doctree;
51use visit_ast;
54a0048b 52use html::item_type::ItemType;
1a4d82fc 53
a7813a04 54pub mod inline;
9346a6ac 55mod simplify;
1a4d82fc
JJ
56
57// extract the stability index for a node from tcx, if possible
e9174d1e 58fn get_stability(cx: &DocContext, def_id: DefId) -> Option<Stability> {
476ff2be 59 cx.tcx.lookup_stability(def_id).clean(cx)
9cc50fc6
SL
60}
61
62fn get_deprecation(cx: &DocContext, def_id: DefId) -> Option<Deprecation> {
476ff2be 63 cx.tcx.lookup_deprecation(def_id).clean(cx)
1a4d82fc
JJ
64}
65
66pub trait Clean<T> {
67 fn clean(&self, cx: &DocContext) -> T;
68}
69
c34b1796 70impl<T: Clean<U>, U> Clean<Vec<U>> for [T] {
1a4d82fc
JJ
71 fn clean(&self, cx: &DocContext) -> Vec<U> {
72 self.iter().map(|x| x.clean(cx)).collect()
73 }
74}
75
1a4d82fc
JJ
76impl<T: Clean<U>, U> Clean<U> for P<T> {
77 fn clean(&self, cx: &DocContext) -> U {
78 (**self).clean(cx)
79 }
80}
81
82impl<T: Clean<U>, U> Clean<U> for Rc<T> {
83 fn clean(&self, cx: &DocContext) -> U {
84 (**self).clean(cx)
85 }
86}
87
88impl<T: Clean<U>, U> Clean<Option<U>> for Option<T> {
89 fn clean(&self, cx: &DocContext) -> Option<U> {
54a0048b 90 self.as_ref().map(|v| v.clean(cx))
1a4d82fc
JJ
91 }
92}
93
85aaf69f
SL
94impl<T, U> Clean<U> for ty::Binder<T> where T: Clean<U> {
95 fn clean(&self, cx: &DocContext) -> U {
96 self.0.clean(cx)
97 }
98}
99
9cc50fc6 100impl<T: Clean<U>, U> Clean<Vec<U>> for P<[T]> {
1a4d82fc
JJ
101 fn clean(&self, cx: &DocContext) -> Vec<U> {
102 self.iter().map(|x| x.clean(cx)).collect()
103 }
104}
105
a7813a04 106#[derive(Clone, Debug)]
1a4d82fc
JJ
107pub struct Crate {
108 pub name: String,
c34b1796 109 pub src: PathBuf,
1a4d82fc 110 pub module: Option<Item>,
476ff2be
SL
111 pub externs: Vec<(CrateNum, ExternalCrate)>,
112 pub primitives: Vec<(DefId, PrimitiveType, Attributes)>,
a7813a04
XL
113 pub access_levels: Arc<AccessLevels<DefId>>,
114 // These are later on moved into `CACHEKEY`, leaving the map empty.
115 // Only here so that they can be filtered through the rustdoc passes.
476ff2be 116 pub external_traits: FxHashMap<DefId, Trait>,
1a4d82fc
JJ
117}
118
119impl<'a, 'tcx> Clean<Crate> for visit_ast::RustdocVisitor<'a, 'tcx> {
120 fn clean(&self, cx: &DocContext) -> Crate {
a7813a04 121 use ::visit_lib::LibEmbargoVisitor;
85aaf69f 122
476ff2be
SL
123 {
124 let mut r = cx.renderinfo.borrow_mut();
125 r.deref_trait_did = cx.tcx.lang_items.deref_trait();
126 r.deref_mut_trait_did = cx.tcx.lang_items.deref_mut_trait();
041b39d2 127 r.owned_box_did = cx.tcx.lang_items.owned_box();
d9579d0f
AL
128 }
129
1a4d82fc 130 let mut externs = Vec::new();
92a42be0 131 for cnum in cx.sess().cstore.crates() {
476ff2be
SL
132 externs.push((cnum, cnum.clean(cx)));
133 // Analyze doc-reachability for extern items
134 LibEmbargoVisitor::new(cx).visit_lib(cnum);
92a42be0 135 }
1a4d82fc
JJ
136 externs.sort_by(|&(a, _), &(b, _)| a.cmp(&b));
137
1a4d82fc
JJ
138 // Clean the crate, translating the entire libsyntax AST to one that is
139 // understood by rustdoc.
140 let mut module = self.module.clean(cx);
141
476ff2be 142 let ExternalCrate { name, src, primitives, .. } = LOCAL_CRATE.clean(cx);
1a4d82fc
JJ
143 {
144 let m = match module.inner {
145 ModuleItem(ref mut m) => m,
146 _ => unreachable!(),
147 };
476ff2be
SL
148 m.items.extend(primitives.iter().map(|&(def_id, prim, ref attrs)| {
149 Item {
1a4d82fc
JJ
150 source: Span::empty(),
151 name: Some(prim.to_url_str().to_string()),
476ff2be 152 attrs: attrs.clone(),
a7813a04 153 visibility: Some(Public),
32a655c1
SL
154 stability: get_stability(cx, def_id),
155 deprecation: get_deprecation(cx, def_id),
476ff2be 156 def_id: def_id,
1a4d82fc 157 inner: PrimitiveItem(prim),
7453a54e 158 }
476ff2be
SL
159 }));
160 }
85aaf69f 161
a7813a04
XL
162 let mut access_levels = cx.access_levels.borrow_mut();
163 let mut external_traits = cx.external_traits.borrow_mut();
164
1a4d82fc 165 Crate {
476ff2be 166 name: name,
85aaf69f 167 src: src,
1a4d82fc
JJ
168 module: Some(module),
169 externs: externs,
170 primitives: primitives,
a7813a04
XL
171 access_levels: Arc::new(mem::replace(&mut access_levels, Default::default())),
172 external_traits: mem::replace(&mut external_traits, Default::default()),
1a4d82fc
JJ
173 }
174 }
175}
176
85aaf69f 177#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
1a4d82fc
JJ
178pub struct ExternalCrate {
179 pub name: String,
476ff2be
SL
180 pub src: PathBuf,
181 pub attrs: Attributes,
182 pub primitives: Vec<(DefId, PrimitiveType, Attributes)>,
1a4d82fc
JJ
183}
184
92a42be0 185impl Clean<ExternalCrate> for CrateNum {
1a4d82fc 186 fn clean(&self, cx: &DocContext) -> ExternalCrate {
476ff2be
SL
187 let root = DefId { krate: *self, index: CRATE_DEF_INDEX };
188 let krate_span = cx.tcx.def_span(root);
189 let krate_src = cx.sess().codemap().span_to_filename(krate_span);
190
191 // Collect all inner modules which are tagged as implementations of
192 // primitives.
193 //
194 // Note that this loop only searches the top-level items of the crate,
195 // and this is intentional. If we were to search the entire crate for an
196 // item tagged with `#[doc(primitive)]` then we would also have to
197 // search the entirety of external modules for items tagged
198 // `#[doc(primitive)]`, which is a pretty inefficient process (decoding
199 // all that metadata unconditionally).
200 //
201 // In order to keep the metadata load under control, the
202 // `#[doc(primitive)]` feature is explicitly designed to only allow the
203 // primitive tags to show up as the top level items in a crate.
204 //
205 // Also note that this does not attempt to deal with modules tagged
206 // duplicately for the same primitive. This is handled later on when
207 // rendering by delegating everything to a hash map.
208 let as_primitive = |def: Def| {
209 if let Def::Mod(def_id) = def {
210 let attrs = cx.tcx.get_attrs(def_id).clean(cx);
211 let mut prim = None;
212 for attr in attrs.lists("doc") {
213 if let Some(v) = attr.value_str() {
214 if attr.check_name("primitive") {
215 prim = PrimitiveType::from_str(&v.as_str());
216 if prim.is_some() {
217 break;
218 }
219 }
220 }
221 }
222 return prim.map(|p| (def_id, p, attrs));
92a42be0 223 }
476ff2be
SL
224 None
225 };
226 let primitives = if root.is_local() {
32a655c1
SL
227 cx.tcx.hir.krate().module.item_ids.iter().filter_map(|&id| {
228 let item = cx.tcx.hir.expect_item(id.id);
476ff2be
SL
229 match item.node {
230 hir::ItemMod(_) => {
32a655c1 231 as_primitive(Def::Mod(cx.tcx.hir.local_def_id(id.id)))
476ff2be
SL
232 }
233 hir::ItemUse(ref path, hir::UseKind::Single)
234 if item.vis == hir::Visibility::Public => {
235 as_primitive(path.def).map(|(_, prim, attrs)| {
236 // Pretend the primitive is local.
32a655c1 237 (cx.tcx.hir.local_def_id(id.id), prim, attrs)
476ff2be
SL
238 })
239 }
240 _ => None
241 }
242 }).collect()
243 } else {
041b39d2 244 cx.tcx.sess.cstore.item_children(root, cx.tcx.sess).iter().map(|item| item.def)
476ff2be
SL
245 .filter_map(as_primitive).collect()
246 };
247
1a4d82fc 248 ExternalCrate {
476ff2be
SL
249 name: cx.tcx.crate_name(*self).to_string(),
250 src: PathBuf::from(krate_src),
251 attrs: cx.tcx.get_attrs(root).clean(cx),
1a4d82fc
JJ
252 primitives: primitives,
253 }
254 }
255}
256
257/// Anything with a source location and set of attributes and, optionally, a
258/// name. That is, anything that can be documented. This doesn't correspond
259/// directly to the AST's concept of an item; it's a strict superset.
85aaf69f 260#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
1a4d82fc
JJ
261pub struct Item {
262 /// Stringified span
263 pub source: Span,
264 /// Not everything has a name. E.g., impls
265 pub name: Option<String>,
476ff2be 266 pub attrs: Attributes,
1a4d82fc
JJ
267 pub inner: ItemEnum,
268 pub visibility: Option<Visibility>,
e9174d1e 269 pub def_id: DefId,
1a4d82fc 270 pub stability: Option<Stability>,
9cc50fc6 271 pub deprecation: Option<Deprecation>,
1a4d82fc
JJ
272}
273
274impl Item {
1a4d82fc
JJ
275 /// Finds the `doc` attribute as a NameValue and returns the corresponding
276 /// value found.
277 pub fn doc_value<'a>(&'a self) -> Option<&'a str> {
476ff2be 278 self.attrs.doc_value()
1a4d82fc 279 }
54a0048b
SL
280 pub fn is_crate(&self) -> bool {
281 match self.inner {
282 StrippedItem(box ModuleItem(Module { is_crate: true, ..})) |
283 ModuleItem(Module { is_crate: true, ..}) => true,
284 _ => false,
1a4d82fc 285 }
1a4d82fc 286 }
1a4d82fc 287 pub fn is_mod(&self) -> bool {
c30ab7b3 288 self.type_() == ItemType::Module
1a4d82fc
JJ
289 }
290 pub fn is_trait(&self) -> bool {
c30ab7b3 291 self.type_() == ItemType::Trait
1a4d82fc
JJ
292 }
293 pub fn is_struct(&self) -> bool {
c30ab7b3 294 self.type_() == ItemType::Struct
1a4d82fc
JJ
295 }
296 pub fn is_enum(&self) -> bool {
cc61c64b 297 self.type_() == ItemType::Enum
1a4d82fc
JJ
298 }
299 pub fn is_fn(&self) -> bool {
c30ab7b3 300 self.type_() == ItemType::Function
54a0048b
SL
301 }
302 pub fn is_associated_type(&self) -> bool {
c30ab7b3 303 self.type_() == ItemType::AssociatedType
54a0048b
SL
304 }
305 pub fn is_associated_const(&self) -> bool {
c30ab7b3 306 self.type_() == ItemType::AssociatedConst
54a0048b
SL
307 }
308 pub fn is_method(&self) -> bool {
c30ab7b3 309 self.type_() == ItemType::Method
54a0048b
SL
310 }
311 pub fn is_ty_method(&self) -> bool {
c30ab7b3 312 self.type_() == ItemType::TyMethod
54a0048b 313 }
041b39d2
XL
314 pub fn is_typedef(&self) -> bool {
315 self.type_() == ItemType::Typedef
316 }
5bcae85e 317 pub fn is_primitive(&self) -> bool {
c30ab7b3 318 self.type_() == ItemType::Primitive
5bcae85e 319 }
cc61c64b
XL
320 pub fn is_union(&self) -> bool {
321 self.type_() == ItemType::Union
322 }
54a0048b
SL
323 pub fn is_stripped(&self) -> bool {
324 match self.inner { StrippedItem(..) => true, _ => false }
325 }
326 pub fn has_stripped_fields(&self) -> Option<bool> {
327 match self.inner {
328 StructItem(ref _struct) => Some(_struct.fields_stripped),
9e0c209e 329 UnionItem(ref union) => Some(union.fields_stripped),
c30ab7b3 330 VariantItem(Variant { kind: VariantKind::Struct(ref vstruct)} ) => {
54a0048b
SL
331 Some(vstruct.fields_stripped)
332 },
333 _ => None,
334 }
1a4d82fc 335 }
d9579d0f 336
8bb4bdeb
XL
337 pub fn stability_class(&self) -> Option<String> {
338 self.stability.as_ref().and_then(|ref s| {
339 let mut classes = Vec::with_capacity(2);
340
341 if s.level == stability::Unstable {
342 classes.push("unstable");
343 }
344
54a0048b 345 if !s.deprecated_since.is_empty() {
8bb4bdeb
XL
346 classes.push("deprecated");
347 }
348
349 if classes.len() != 0 {
350 Some(classes.join(" "))
351 } else {
352 None
d9579d0f 353 }
8bb4bdeb 354 })
d9579d0f 355 }
7453a54e
SL
356
357 pub fn stable_since(&self) -> Option<&str> {
54a0048b 358 self.stability.as_ref().map(|s| &s.since[..])
7453a54e 359 }
c30ab7b3
SL
360
361 /// Returns a documentation-level item type from the item.
362 pub fn type_(&self) -> ItemType {
363 ItemType::from(self)
364 }
1a4d82fc
JJ
365}
366
85aaf69f 367#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
1a4d82fc 368pub enum ItemEnum {
85aaf69f
SL
369 ExternCrateItem(String, Option<String>),
370 ImportItem(Import),
1a4d82fc 371 StructItem(Struct),
9e0c209e 372 UnionItem(Union),
1a4d82fc
JJ
373 EnumItem(Enum),
374 FunctionItem(Function),
375 ModuleItem(Module),
62682a34 376 TypedefItem(Typedef, bool /* is associated type */),
1a4d82fc
JJ
377 StaticItem(Static),
378 ConstantItem(Constant),
379 TraitItem(Trait),
380 ImplItem(Impl),
1a4d82fc
JJ
381 /// A method signature only. Used for required methods in traits (ie,
382 /// non-default-methods).
383 TyMethodItem(TyMethod),
384 /// A method with a body.
385 MethodItem(Method),
54a0048b 386 StructFieldItem(Type),
1a4d82fc
JJ
387 VariantItem(Variant),
388 /// `fn`s from an extern block
389 ForeignFunctionItem(Function),
390 /// `static`s from an extern block
391 ForeignStaticItem(Static),
392 MacroItem(Macro),
393 PrimitiveItem(PrimitiveType),
d9579d0f 394 AssociatedConstItem(Type, Option<String>),
c34b1796
AL
395 AssociatedTypeItem(Vec<TyParamBound>, Option<Type>),
396 DefaultImplItem(DefaultImpl),
54a0048b
SL
397 /// An item that has been stripped by a rustdoc pass
398 StrippedItem(Box<ItemEnum>),
1a4d82fc
JJ
399}
400
9e0c209e
SL
401impl ItemEnum {
402 pub fn generics(&self) -> Option<&Generics> {
403 Some(match *self {
404 ItemEnum::StructItem(ref s) => &s.generics,
405 ItemEnum::EnumItem(ref e) => &e.generics,
406 ItemEnum::FunctionItem(ref f) => &f.generics,
407 ItemEnum::TypedefItem(ref t, _) => &t.generics,
408 ItemEnum::TraitItem(ref t) => &t.generics,
409 ItemEnum::ImplItem(ref i) => &i.generics,
410 ItemEnum::TyMethodItem(ref i) => &i.generics,
411 ItemEnum::MethodItem(ref i) => &i.generics,
412 ItemEnum::ForeignFunctionItem(ref f) => &f.generics,
413 _ => return None,
414 })
415 }
416}
417
85aaf69f 418#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
1a4d82fc
JJ
419pub struct Module {
420 pub items: Vec<Item>,
421 pub is_crate: bool,
422}
423
424impl Clean<Item> for doctree::Module {
425 fn clean(&self, cx: &DocContext) -> Item {
426 let name = if self.name.is_some() {
427 self.name.unwrap().clean(cx)
428 } else {
429 "".to_string()
430 };
85aaf69f
SL
431
432 let mut items: Vec<Item> = vec![];
433 items.extend(self.extern_crates.iter().map(|x| x.clean(cx)));
62682a34 434 items.extend(self.imports.iter().flat_map(|x| x.clean(cx)));
85aaf69f 435 items.extend(self.structs.iter().map(|x| x.clean(cx)));
9e0c209e 436 items.extend(self.unions.iter().map(|x| x.clean(cx)));
85aaf69f
SL
437 items.extend(self.enums.iter().map(|x| x.clean(cx)));
438 items.extend(self.fns.iter().map(|x| x.clean(cx)));
62682a34 439 items.extend(self.foreigns.iter().flat_map(|x| x.clean(cx)));
85aaf69f
SL
440 items.extend(self.mods.iter().map(|x| x.clean(cx)));
441 items.extend(self.typedefs.iter().map(|x| x.clean(cx)));
442 items.extend(self.statics.iter().map(|x| x.clean(cx)));
443 items.extend(self.constants.iter().map(|x| x.clean(cx)));
444 items.extend(self.traits.iter().map(|x| x.clean(cx)));
62682a34 445 items.extend(self.impls.iter().flat_map(|x| x.clean(cx)));
85aaf69f 446 items.extend(self.macros.iter().map(|x| x.clean(cx)));
c34b1796 447 items.extend(self.def_traits.iter().map(|x| x.clean(cx)));
1a4d82fc
JJ
448
449 // determine if we should display the inner contents or
450 // the outer `mod` item for the source code.
451 let whence = {
452 let cm = cx.sess().codemap();
453 let outer = cm.lookup_char_pos(self.where_outer.lo);
454 let inner = cm.lookup_char_pos(self.where_inner.lo);
455 if outer.file.start_pos == inner.file.start_pos {
456 // mod foo { ... }
457 self.where_outer
458 } else {
459 // mod foo; (and a separate FileMap for the contents)
460 self.where_inner
461 }
462 };
463
464 Item {
465 name: Some(name),
466 attrs: self.attrs.clean(cx),
467 source: whence.clean(cx),
468 visibility: self.vis.clean(cx),
469 stability: self.stab.clean(cx),
9cc50fc6 470 deprecation: self.depr.clean(cx),
32a655c1 471 def_id: cx.tcx.hir.local_def_id(self.id),
1a4d82fc
JJ
472 inner: ModuleItem(Module {
473 is_crate: self.is_crate,
85aaf69f 474 items: items
1a4d82fc
JJ
475 })
476 }
477 }
478}
479
476ff2be
SL
480pub struct ListAttributesIter<'a> {
481 attrs: slice::Iter<'a, ast::Attribute>,
cc61c64b 482 current_list: vec::IntoIter<ast::NestedMetaItem>,
476ff2be 483 name: &'a str
54a0048b
SL
484}
485
476ff2be 486impl<'a> Iterator for ListAttributesIter<'a> {
cc61c64b 487 type Item = ast::NestedMetaItem;
476ff2be
SL
488
489 fn next(&mut self) -> Option<Self::Item> {
490 if let Some(nested) = self.current_list.next() {
491 return Some(nested);
54a0048b 492 }
54a0048b 493
476ff2be 494 for attr in &mut self.attrs {
cc61c64b 495 if let Some(list) = attr.meta_item_list() {
476ff2be 496 if attr.check_name(self.name) {
cc61c64b 497 self.current_list = list.into_iter();
476ff2be
SL
498 if let Some(nested) = self.current_list.next() {
499 return Some(nested);
500 }
54a0048b
SL
501 }
502 }
503 }
476ff2be 504
54a0048b
SL
505 None
506 }
476ff2be 507}
54a0048b 508
476ff2be 509pub trait AttributesExt {
54a0048b 510 /// Finds an attribute as List and returns the list of attributes nested inside.
7cac9316 511 fn lists<'a>(&'a self, name: &'a str) -> ListAttributesIter<'a>;
476ff2be
SL
512}
513
514impl AttributesExt for [ast::Attribute] {
515 fn lists<'a>(&'a self, name: &'a str) -> ListAttributesIter<'a> {
516 ListAttributesIter {
517 attrs: self.iter(),
cc61c64b 518 current_list: Vec::new().into_iter(),
476ff2be 519 name: name
54a0048b 520 }
54a0048b
SL
521 }
522}
523
476ff2be
SL
524pub trait NestedAttributesExt {
525 /// Returns whether the attribute list contains a specific `Word`
7cac9316 526 fn has_word(self, word: &str) -> bool;
476ff2be
SL
527}
528
cc61c64b 529impl<I: IntoIterator<Item=ast::NestedMetaItem>> NestedAttributesExt for I {
476ff2be
SL
530 fn has_word(self, word: &str) -> bool {
531 self.into_iter().any(|attr| attr.is_word() && attr.check_name(word))
532 }
533}
534
535#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug, Default)]
536pub struct Attributes {
537 pub doc_strings: Vec<String>,
8bb4bdeb
XL
538 pub other_attrs: Vec<ast::Attribute>,
539 pub span: Option<syntax_pos::Span>,
9e0c209e
SL
540}
541
476ff2be
SL
542impl Attributes {
543 pub fn from_ast(attrs: &[ast::Attribute]) -> Attributes {
544 let mut doc_strings = vec![];
8bb4bdeb 545 let mut sp = None;
476ff2be
SL
546 let other_attrs = attrs.iter().filter_map(|attr| {
547 attr.with_desugared_doc(|attr| {
548 if let Some(value) = attr.value_str() {
549 if attr.check_name("doc") {
550 doc_strings.push(value.to_string());
8bb4bdeb
XL
551 if sp.is_none() {
552 sp = Some(attr.span);
553 }
476ff2be
SL
554 return None;
555 }
556 }
557
558 Some(attr.clone())
559 })
560 }).collect();
561 Attributes {
562 doc_strings: doc_strings,
8bb4bdeb
XL
563 other_attrs: other_attrs,
564 span: sp,
9e0c209e
SL
565 }
566 }
476ff2be
SL
567
568 /// Finds the `doc` attribute as a NameValue and returns the corresponding
569 /// value found.
570 pub fn doc_value<'a>(&'a self) -> Option<&'a str> {
571 self.doc_strings.first().map(|s| &s[..])
572 }
1a4d82fc
JJ
573}
574
476ff2be
SL
575impl AttributesExt for Attributes {
576 fn lists<'a>(&'a self, name: &'a str) -> ListAttributesIter<'a> {
577 self.other_attrs.lists(name)
1a4d82fc
JJ
578 }
579}
580
476ff2be
SL
581impl Clean<Attributes> for [ast::Attribute] {
582 fn clean(&self, _cx: &DocContext) -> Attributes {
583 Attributes::from_ast(self)
1a4d82fc
JJ
584 }
585}
586
85aaf69f 587#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
1a4d82fc
JJ
588pub struct TyParam {
589 pub name: String,
e9174d1e 590 pub did: DefId,
1a4d82fc
JJ
591 pub bounds: Vec<TyParamBound>,
592 pub default: Option<Type>,
593}
594
e9174d1e 595impl Clean<TyParam> for hir::TyParam {
1a4d82fc
JJ
596 fn clean(&self, cx: &DocContext) -> TyParam {
597 TyParam {
b039eaaf 598 name: self.name.clean(cx),
32a655c1 599 did: cx.tcx.hir.local_def_id(self.id),
1a4d82fc
JJ
600 bounds: self.bounds.clean(cx),
601 default: self.default.clean(cx),
602 }
603 }
604}
605
8bb4bdeb 606impl<'tcx> Clean<TyParam> for ty::TypeParameterDef {
1a4d82fc 607 fn clean(&self, cx: &DocContext) -> TyParam {
a7813a04 608 cx.renderinfo.borrow_mut().external_typarams.insert(self.def_id, self.name.clean(cx));
1a4d82fc
JJ
609 TyParam {
610 name: self.name.clean(cx),
611 did: self.def_id,
c34b1796 612 bounds: vec![], // these are filled in from the where-clauses
8bb4bdeb 613 default: if self.has_default {
7cac9316 614 Some(cx.tcx.type_of(self.def_id).clean(cx))
8bb4bdeb
XL
615 } else {
616 None
617 }
1a4d82fc
JJ
618 }
619 }
620}
621
85aaf69f 622#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
1a4d82fc
JJ
623pub enum TyParamBound {
624 RegionBound(Lifetime),
e9174d1e 625 TraitBound(PolyTrait, hir::TraitBoundModifier)
1a4d82fc
JJ
626}
627
9346a6ac
AL
628impl TyParamBound {
629 fn maybe_sized(cx: &DocContext) -> TyParamBound {
476ff2be
SL
630 let did = cx.tcx.require_lang_item(lang_items::SizedTraitLangItem);
631 let empty = cx.tcx.intern_substs(&[]);
632 let path = external_path(cx, &cx.tcx.item_name(did).as_str(),
633 Some(did), false, vec![], empty);
634 inline::record_extern_fqn(cx, did, TypeKind::Trait);
635 TraitBound(PolyTrait {
636 trait_: ResolvedPath {
637 path: path,
638 typarams: None,
639 did: did,
640 is_generic: false,
641 },
642 lifetimes: vec![]
643 }, hir::TraitBoundModifier::Maybe)
9346a6ac
AL
644 }
645
646 fn is_sized_bound(&self, cx: &DocContext) -> bool {
54a0048b 647 use rustc::hir::TraitBoundModifier as TBM;
476ff2be
SL
648 if let TyParamBound::TraitBound(PolyTrait { ref trait_, .. }, TBM::None) = *self {
649 if trait_.def_id() == cx.tcx.lang_items.sized_trait() {
650 return true;
9346a6ac
AL
651 }
652 }
653 false
654 }
655}
656
e9174d1e 657impl Clean<TyParamBound> for hir::TyParamBound {
1a4d82fc
JJ
658 fn clean(&self, cx: &DocContext) -> TyParamBound {
659 match *self {
e9174d1e
SL
660 hir::RegionTyParamBound(lt) => RegionBound(lt.clean(cx)),
661 hir::TraitTyParamBound(ref t, modifier) => TraitBound(t.clean(cx), modifier),
1a4d82fc
JJ
662 }
663 }
664}
665
9e0c209e
SL
666fn external_path_params(cx: &DocContext, trait_did: Option<DefId>, has_self: bool,
667 bindings: Vec<TypeBinding>, substs: &Substs) -> PathParameters {
668 let lifetimes = substs.regions().filter_map(|v| v.clean(cx)).collect();
669 let types = substs.types().skip(has_self as usize).collect::<Vec<_>>();
1a4d82fc 670
476ff2be 671 match trait_did {
1a4d82fc 672 // Attempt to sugar an external path like Fn<(A, B,), C> to Fn(A, B) -> C
476ff2be 673 Some(did) if cx.tcx.lang_items.fn_trait_kind(did).is_some() => {
85aaf69f 674 assert_eq!(types.len(), 1);
1a4d82fc 675 let inputs = match types[0].sty {
8bb4bdeb 676 ty::TyTuple(ref tys, _) => tys.iter().map(|t| t.clean(cx)).collect(),
1a4d82fc
JJ
677 _ => {
678 return PathParameters::AngleBracketed {
679 lifetimes: lifetimes,
680 types: types.clean(cx),
85aaf69f 681 bindings: bindings
1a4d82fc
JJ
682 }
683 }
684 };
85aaf69f
SL
685 let output = None;
686 // FIXME(#20299) return type comes from a projection now
687 // match types[1].sty {
8bb4bdeb 688 // ty::TyTuple(ref v, _) if v.is_empty() => None, // -> ()
85aaf69f
SL
689 // _ => Some(types[1].clean(cx))
690 // };
1a4d82fc
JJ
691 PathParameters::Parenthesized {
692 inputs: inputs,
693 output: output
694 }
695 },
476ff2be 696 _ => {
1a4d82fc
JJ
697 PathParameters::AngleBracketed {
698 lifetimes: lifetimes,
699 types: types.clean(cx),
85aaf69f 700 bindings: bindings
1a4d82fc
JJ
701 }
702 }
703 }
704}
705
706// trait_did should be set to a trait's DefId if called on a TraitRef, in order to sugar
707// from Fn<(A, B,), C> to Fn(A, B) -> C
9e0c209e
SL
708fn external_path(cx: &DocContext, name: &str, trait_did: Option<DefId>, has_self: bool,
709 bindings: Vec<TypeBinding>, substs: &Substs) -> Path {
1a4d82fc
JJ
710 Path {
711 global: false,
476ff2be 712 def: Def::Err,
1a4d82fc
JJ
713 segments: vec![PathSegment {
714 name: name.to_string(),
9e0c209e 715 params: external_path_params(cx, trait_did, has_self, bindings, substs)
1a4d82fc
JJ
716 }],
717 }
718}
719
1a4d82fc
JJ
720impl<'tcx> Clean<TyParamBound> for ty::TraitRef<'tcx> {
721 fn clean(&self, cx: &DocContext) -> TyParamBound {
c30ab7b3 722 inline::record_extern_fqn(cx, self.def_id, TypeKind::Trait);
476ff2be 723 let path = external_path(cx, &cx.tcx.item_name(self.def_id).as_str(),
9e0c209e 724 Some(self.def_id), true, vec![], self.substs);
1a4d82fc 725
9e0c209e 726 debug!("ty::TraitRef\n subst: {:?}\n", self.substs);
1a4d82fc
JJ
727
728 // collect any late bound regions
729 let mut late_bounds = vec![];
9e0c209e 730 for ty_s in self.input_types().skip(1) {
8bb4bdeb 731 if let ty::TyTuple(ts, _) = ty_s.sty {
85aaf69f 732 for &ty_s in ts {
62682a34 733 if let ty::TyRef(ref reg, _) = ty_s.sty {
7cac9316 734 if let &ty::RegionKind::ReLateBound(..) = *reg {
1a4d82fc
JJ
735 debug!(" hit an ReLateBound {:?}", reg);
736 if let Some(lt) = reg.clean(cx) {
54a0048b 737 late_bounds.push(lt);
1a4d82fc
JJ
738 }
739 }
740 }
741 }
742 }
743 }
744
54a0048b
SL
745 TraitBound(
746 PolyTrait {
747 trait_: ResolvedPath {
748 path: path,
749 typarams: None,
750 did: self.def_id,
751 is_generic: false,
752 },
753 lifetimes: late_bounds,
62682a34 754 },
54a0048b
SL
755 hir::TraitBoundModifier::None
756 )
1a4d82fc
JJ
757 }
758}
759
9e0c209e 760impl<'tcx> Clean<Option<Vec<TyParamBound>>> for Substs<'tcx> {
1a4d82fc
JJ
761 fn clean(&self, cx: &DocContext) -> Option<Vec<TyParamBound>> {
762 let mut v = Vec::new();
9e0c209e
SL
763 v.extend(self.regions().filter_map(|r| r.clean(cx))
764 .map(RegionBound));
765 v.extend(self.types().map(|t| TraitBound(PolyTrait {
1a4d82fc
JJ
766 trait_: t.clean(cx),
767 lifetimes: vec![]
e9174d1e 768 }, hir::TraitBoundModifier::None)));
9346a6ac 769 if !v.is_empty() {Some(v)} else {None}
1a4d82fc
JJ
770 }
771}
772
85aaf69f 773#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
1a4d82fc
JJ
774pub struct Lifetime(String);
775
776impl Lifetime {
777 pub fn get_ref<'a>(&'a self) -> &'a str {
778 let Lifetime(ref s) = *self;
85aaf69f 779 let s: &'a str = s;
c30ab7b3 780 s
1a4d82fc
JJ
781 }
782
783 pub fn statik() -> Lifetime {
784 Lifetime("'static".to_string())
785 }
786}
787
e9174d1e 788impl Clean<Lifetime> for hir::Lifetime {
9e0c209e 789 fn clean(&self, cx: &DocContext) -> Lifetime {
476ff2be
SL
790 let def = cx.tcx.named_region_map.defs.get(&self.id).cloned();
791 match def {
32a655c1
SL
792 Some(rl::Region::EarlyBound(_, node_id)) |
793 Some(rl::Region::LateBound(_, node_id)) |
794 Some(rl::Region::Free(_, node_id)) => {
476ff2be
SL
795 if let Some(lt) = cx.lt_substs.borrow().get(&node_id).cloned() {
796 return lt;
9e0c209e 797 }
9e0c209e 798 }
476ff2be 799 _ => {}
9e0c209e 800 }
c1a9b12d 801 Lifetime(self.name.to_string())
1a4d82fc
JJ
802 }
803}
804
e9174d1e 805impl Clean<Lifetime> for hir::LifetimeDef {
1a4d82fc 806 fn clean(&self, _: &DocContext) -> Lifetime {
a7813a04
XL
807 if self.bounds.len() > 0 {
808 let mut s = format!("{}: {}",
809 self.lifetime.name.to_string(),
810 self.bounds[0].name.to_string());
811 for bound in self.bounds.iter().skip(1) {
812 s.push_str(&format!(" + {}", bound.name.to_string()));
813 }
814 Lifetime(s)
815 } else {
816 Lifetime(self.lifetime.name.to_string())
817 }
1a4d82fc
JJ
818 }
819}
820
32a655c1 821impl Clean<Lifetime> for ty::RegionParameterDef {
1a4d82fc 822 fn clean(&self, _: &DocContext) -> Lifetime {
c1a9b12d 823 Lifetime(self.name.to_string())
1a4d82fc
JJ
824 }
825}
826
7cac9316 827impl Clean<Option<Lifetime>> for ty::RegionKind {
1a4d82fc
JJ
828 fn clean(&self, cx: &DocContext) -> Option<Lifetime> {
829 match *self {
830 ty::ReStatic => Some(Lifetime::statik()),
8bb4bdeb 831 ty::ReLateBound(_, ty::BrNamed(_, name)) => Some(Lifetime(name.to_string())),
9346a6ac 832 ty::ReEarlyBound(ref data) => Some(Lifetime(data.name.clean(cx))),
1a4d82fc
JJ
833
834 ty::ReLateBound(..) |
835 ty::ReFree(..) |
836 ty::ReScope(..) |
e9174d1e
SL
837 ty::ReVar(..) |
838 ty::ReSkolemized(..) |
3157f602
XL
839 ty::ReEmpty |
840 ty::ReErased => None
1a4d82fc
JJ
841 }
842 }
843}
844
85aaf69f 845#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
1a4d82fc
JJ
846pub enum WherePredicate {
847 BoundPredicate { ty: Type, bounds: Vec<TyParamBound> },
848 RegionPredicate { lifetime: Lifetime, bounds: Vec<Lifetime>},
cc61c64b 849 EqPredicate { lhs: Type, rhs: Type },
1a4d82fc
JJ
850}
851
e9174d1e 852impl Clean<WherePredicate> for hir::WherePredicate {
1a4d82fc
JJ
853 fn clean(&self, cx: &DocContext) -> WherePredicate {
854 match *self {
e9174d1e 855 hir::WherePredicate::BoundPredicate(ref wbp) => {
1a4d82fc
JJ
856 WherePredicate::BoundPredicate {
857 ty: wbp.bounded_ty.clean(cx),
858 bounds: wbp.bounds.clean(cx)
859 }
860 }
861
e9174d1e 862 hir::WherePredicate::RegionPredicate(ref wrp) => {
1a4d82fc
JJ
863 WherePredicate::RegionPredicate {
864 lifetime: wrp.lifetime.clean(cx),
865 bounds: wrp.bounds.clean(cx)
866 }
867 }
868
32a655c1
SL
869 hir::WherePredicate::EqPredicate(ref wrp) => {
870 WherePredicate::EqPredicate {
871 lhs: wrp.lhs_ty.clean(cx),
872 rhs: wrp.rhs_ty.clean(cx)
873 }
1a4d82fc
JJ
874 }
875 }
876 }
877}
878
85aaf69f
SL
879impl<'a> Clean<WherePredicate> for ty::Predicate<'a> {
880 fn clean(&self, cx: &DocContext) -> WherePredicate {
54a0048b 881 use rustc::ty::Predicate;
85aaf69f
SL
882
883 match *self {
884 Predicate::Trait(ref pred) => pred.clean(cx),
885 Predicate::Equate(ref pred) => pred.clean(cx),
cc61c64b 886 Predicate::Subtype(ref pred) => pred.clean(cx),
85aaf69f
SL
887 Predicate::RegionOutlives(ref pred) => pred.clean(cx),
888 Predicate::TypeOutlives(ref pred) => pred.clean(cx),
e9174d1e
SL
889 Predicate::Projection(ref pred) => pred.clean(cx),
890 Predicate::WellFormed(_) => panic!("not user writable"),
891 Predicate::ObjectSafe(_) => panic!("not user writable"),
a7813a04 892 Predicate::ClosureKind(..) => panic!("not user writable"),
85aaf69f
SL
893 }
894 }
895}
896
897impl<'a> Clean<WherePredicate> for ty::TraitPredicate<'a> {
898 fn clean(&self, cx: &DocContext) -> WherePredicate {
899 WherePredicate::BoundPredicate {
9e0c209e 900 ty: self.trait_ref.self_ty().clean(cx),
85aaf69f
SL
901 bounds: vec![self.trait_ref.clean(cx)]
902 }
903 }
904}
905
906impl<'tcx> Clean<WherePredicate> for ty::EquatePredicate<'tcx> {
907 fn clean(&self, cx: &DocContext) -> WherePredicate {
908 let ty::EquatePredicate(ref lhs, ref rhs) = *self;
909 WherePredicate::EqPredicate {
910 lhs: lhs.clean(cx),
911 rhs: rhs.clean(cx)
912 }
913 }
914}
915
cc61c64b
XL
916impl<'tcx> Clean<WherePredicate> for ty::SubtypePredicate<'tcx> {
917 fn clean(&self, _cx: &DocContext) -> WherePredicate {
918 panic!("subtype predicates are an internal rustc artifact \
919 and should not be seen by rustdoc")
920 }
921}
922
7cac9316 923impl<'tcx> Clean<WherePredicate> for ty::OutlivesPredicate<ty::Region<'tcx>, ty::Region<'tcx>> {
85aaf69f
SL
924 fn clean(&self, cx: &DocContext) -> WherePredicate {
925 let ty::OutlivesPredicate(ref a, ref b) = *self;
926 WherePredicate::RegionPredicate {
927 lifetime: a.clean(cx).unwrap(),
928 bounds: vec![b.clean(cx).unwrap()]
929 }
930 }
931}
932
7cac9316 933impl<'tcx> Clean<WherePredicate> for ty::OutlivesPredicate<ty::Ty<'tcx>, ty::Region<'tcx>> {
85aaf69f
SL
934 fn clean(&self, cx: &DocContext) -> WherePredicate {
935 let ty::OutlivesPredicate(ref ty, ref lt) = *self;
936
937 WherePredicate::BoundPredicate {
938 ty: ty.clean(cx),
939 bounds: vec![TyParamBound::RegionBound(lt.clean(cx).unwrap())]
940 }
941 }
942}
943
944impl<'tcx> Clean<WherePredicate> for ty::ProjectionPredicate<'tcx> {
945 fn clean(&self, cx: &DocContext) -> WherePredicate {
946 WherePredicate::EqPredicate {
947 lhs: self.projection_ty.clean(cx),
948 rhs: self.ty.clean(cx)
949 }
950 }
951}
952
953impl<'tcx> Clean<Type> for ty::ProjectionTy<'tcx> {
954 fn clean(&self, cx: &DocContext) -> Type {
041b39d2 955 let trait_ = match self.trait_ref(cx.tcx).clean(cx) {
85aaf69f 956 TyParamBound::TraitBound(t, _) => t.trait_,
9346a6ac
AL
957 TyParamBound::RegionBound(_) => {
958 panic!("cleaning a trait got a region")
959 }
85aaf69f
SL
960 };
961 Type::QPath {
041b39d2
XL
962 name: cx.tcx.associated_item(self.item_def_id).name.clean(cx),
963 self_type: box self.self_ty().clean(cx),
85aaf69f
SL
964 trait_: box trait_
965 }
966 }
967}
968
d9579d0f 969// maybe use a Generic enum and use Vec<Generic>?
85aaf69f 970#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
1a4d82fc
JJ
971pub struct Generics {
972 pub lifetimes: Vec<Lifetime>,
973 pub type_params: Vec<TyParam>,
974 pub where_predicates: Vec<WherePredicate>
975}
976
e9174d1e 977impl Clean<Generics> for hir::Generics {
1a4d82fc
JJ
978 fn clean(&self, cx: &DocContext) -> Generics {
979 Generics {
980 lifetimes: self.lifetimes.clean(cx),
981 type_params: self.ty_params.clean(cx),
982 where_predicates: self.where_clause.predicates.clean(cx)
983 }
984 }
985}
986
8bb4bdeb 987impl<'a, 'tcx> Clean<Generics> for (&'a ty::Generics,
9e0c209e 988 &'a ty::GenericPredicates<'tcx>) {
1a4d82fc 989 fn clean(&self, cx: &DocContext) -> Generics {
85aaf69f
SL
990 use self::WherePredicate as WP;
991
9e0c209e 992 let (gens, preds) = *self;
85aaf69f 993
9346a6ac
AL
994 // Bounds in the type_params and lifetimes fields are repeated in the
995 // predicates field (see rustc_typeck::collect::ty_generics), so remove
996 // them.
9e0c209e
SL
997 let stripped_typarams = gens.types.iter().filter_map(|tp| {
998 if tp.name == keywords::SelfType.name() {
999 assert_eq!(tp.index, 0);
1000 None
1001 } else {
1002 Some(tp.clean(cx))
1003 }
85aaf69f 1004 }).collect::<Vec<_>>();
85aaf69f 1005
9e0c209e 1006 let mut where_predicates = preds.predicates.to_vec().clean(cx);
85aaf69f 1007
9346a6ac
AL
1008 // Type parameters and have a Sized bound by default unless removed with
1009 // ?Sized. Scan through the predicates and mark any type parameter with
1010 // a Sized bound, removing the bounds as we find them.
1011 //
1012 // Note that associated types also have a sized bound by default, but we
d9579d0f 1013 // don't actually know the set of associated types right here so that's
9346a6ac 1014 // handled in cleaning associated types
476ff2be 1015 let mut sized_params = FxHashSet();
9346a6ac
AL
1016 where_predicates.retain(|pred| {
1017 match *pred {
1018 WP::BoundPredicate { ty: Generic(ref g), ref bounds } => {
1019 if bounds.iter().any(|b| b.is_sized_bound(cx)) {
1020 sized_params.insert(g.clone());
1021 false
1022 } else {
1023 true
1024 }
85aaf69f 1025 }
9346a6ac 1026 _ => true,
85aaf69f 1027 }
9346a6ac 1028 });
85aaf69f 1029
9346a6ac
AL
1030 // Run through the type parameters again and insert a ?Sized
1031 // unbound for any we didn't find to be Sized.
85aaf69f
SL
1032 for tp in &stripped_typarams {
1033 if !sized_params.contains(&tp.name) {
85aaf69f
SL
1034 where_predicates.push(WP::BoundPredicate {
1035 ty: Type::Generic(tp.name.clone()),
9346a6ac 1036 bounds: vec![TyParamBound::maybe_sized(cx)],
85aaf69f
SL
1037 })
1038 }
1039 }
1040
1041 // It would be nice to collect all of the bounds on a type and recombine
1042 // them if possible, to avoid e.g. `where T: Foo, T: Bar, T: Sized, T: 'a`
1043 // and instead see `where T: Foo + Bar + Sized + 'a`
1044
1a4d82fc 1045 Generics {
9346a6ac 1046 type_params: simplify::ty_params(stripped_typarams),
32a655c1 1047 lifetimes: gens.regions.clean(cx),
9346a6ac 1048 where_predicates: simplify::where_clauses(cx, where_predicates),
1a4d82fc
JJ
1049 }
1050 }
1051}
1052
85aaf69f 1053#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
1a4d82fc
JJ
1054pub struct Method {
1055 pub generics: Generics,
e9174d1e
SL
1056 pub unsafety: hir::Unsafety,
1057 pub constness: hir::Constness,
1a4d82fc 1058 pub decl: FnDecl,
7453a54e 1059 pub abi: Abi,
1a4d82fc
JJ
1060}
1061
32a655c1 1062impl<'a> Clean<Method> for (&'a hir::MethodSig, hir::BodyId) {
c34b1796 1063 fn clean(&self, cx: &DocContext) -> Method {
c34b1796 1064 Method {
32a655c1
SL
1065 generics: self.0.generics.clean(cx),
1066 unsafety: self.0.unsafety,
1067 constness: self.0.constness,
1068 decl: (&*self.0.decl, self.1).clean(cx),
1069 abi: self.0.abi
1a4d82fc
JJ
1070 }
1071 }
1072}
1073
85aaf69f 1074#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
1a4d82fc 1075pub struct TyMethod {
e9174d1e 1076 pub unsafety: hir::Unsafety,
1a4d82fc
JJ
1077 pub decl: FnDecl,
1078 pub generics: Generics,
7453a54e 1079 pub abi: Abi,
1a4d82fc
JJ
1080}
1081
85aaf69f 1082#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
1a4d82fc
JJ
1083pub struct Function {
1084 pub decl: FnDecl,
1085 pub generics: Generics,
e9174d1e
SL
1086 pub unsafety: hir::Unsafety,
1087 pub constness: hir::Constness,
7453a54e 1088 pub abi: Abi,
1a4d82fc
JJ
1089}
1090
1091impl Clean<Item> for doctree::Function {
1092 fn clean(&self, cx: &DocContext) -> Item {
1093 Item {
1094 name: Some(self.name.clean(cx)),
1095 attrs: self.attrs.clean(cx),
1096 source: self.whence.clean(cx),
1097 visibility: self.vis.clean(cx),
1098 stability: self.stab.clean(cx),
9cc50fc6 1099 deprecation: self.depr.clean(cx),
32a655c1 1100 def_id: cx.tcx.hir.local_def_id(self.id),
1a4d82fc 1101 inner: FunctionItem(Function {
32a655c1 1102 decl: (&self.decl, self.body).clean(cx),
1a4d82fc
JJ
1103 generics: self.generics.clean(cx),
1104 unsafety: self.unsafety,
62682a34 1105 constness: self.constness,
9346a6ac 1106 abi: self.abi,
1a4d82fc
JJ
1107 }),
1108 }
1109 }
1110}
1111
85aaf69f 1112#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
1a4d82fc
JJ
1113pub struct FnDecl {
1114 pub inputs: Arguments,
1115 pub output: FunctionRetTy,
e9174d1e 1116 pub variadic: bool,
476ff2be 1117 pub attrs: Attributes,
1a4d82fc
JJ
1118}
1119
a7813a04
XL
1120impl FnDecl {
1121 pub fn has_self(&self) -> bool {
c30ab7b3 1122 self.inputs.values.len() > 0 && self.inputs.values[0].name == "self"
a7813a04 1123 }
9e0c209e
SL
1124
1125 pub fn self_type(&self) -> Option<SelfTy> {
1126 self.inputs.values.get(0).and_then(|v| v.to_self())
1127 }
a7813a04
XL
1128}
1129
85aaf69f 1130#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
1a4d82fc
JJ
1131pub struct Arguments {
1132 pub values: Vec<Argument>,
1133}
1134
32a655c1
SL
1135impl<'a> Clean<Arguments> for (&'a [P<hir::Ty>], &'a [Spanned<ast::Name>]) {
1136 fn clean(&self, cx: &DocContext) -> Arguments {
1137 Arguments {
1138 values: self.0.iter().enumerate().map(|(i, ty)| {
1139 let mut name = self.1.get(i).map(|n| n.node.to_string())
1140 .unwrap_or(String::new());
1141 if name.is_empty() {
1142 name = "_".to_string();
1143 }
1144 Argument {
1145 name: name,
1146 type_: ty.clean(cx),
1147 }
1148 }).collect()
1149 }
1150 }
1151}
1152
1153impl<'a> Clean<Arguments> for (&'a [P<hir::Ty>], hir::BodyId) {
1154 fn clean(&self, cx: &DocContext) -> Arguments {
1155 let body = cx.tcx.hir.body(self.1);
1156
1157 Arguments {
1158 values: self.0.iter().enumerate().map(|(i, ty)| {
1159 Argument {
1160 name: name_from_pat(&body.arguments[i].pat),
1161 type_: ty.clean(cx),
1162 }
1163 }).collect()
1164 }
1165 }
1166}
1167
1168impl<'a, A: Copy> Clean<FnDecl> for (&'a hir::FnDecl, A)
1169 where (&'a [P<hir::Ty>], A): Clean<Arguments>
1170{
1a4d82fc
JJ
1171 fn clean(&self, cx: &DocContext) -> FnDecl {
1172 FnDecl {
32a655c1
SL
1173 inputs: (&self.0.inputs[..], self.1).clean(cx),
1174 output: self.0.output.clean(cx),
1175 variadic: self.0.variadic,
476ff2be 1176 attrs: Attributes::default()
1a4d82fc
JJ
1177 }
1178 }
1179}
1180
8bb4bdeb 1181impl<'a, 'tcx> Clean<FnDecl> for (DefId, ty::PolyFnSig<'tcx>) {
1a4d82fc
JJ
1182 fn clean(&self, cx: &DocContext) -> FnDecl {
1183 let (did, sig) = *self;
32a655c1 1184 let mut names = if cx.tcx.hir.as_local_node_id(did).is_some() {
b039eaaf 1185 vec![].into_iter()
1a4d82fc 1186 } else {
7cac9316 1187 cx.tcx.fn_arg_names(did).into_iter()
1a4d82fc 1188 }.peekable();
1a4d82fc 1189 FnDecl {
476ff2be
SL
1190 output: Return(sig.skip_binder().output().clean(cx)),
1191 attrs: Attributes::default(),
1192 variadic: sig.skip_binder().variadic,
1a4d82fc 1193 inputs: Arguments {
476ff2be 1194 values: sig.skip_binder().inputs().iter().map(|t| {
1a4d82fc
JJ
1195 Argument {
1196 type_: t.clean(cx),
9e0c209e 1197 name: names.next().map_or("".to_string(), |name| name.to_string()),
1a4d82fc
JJ
1198 }
1199 }).collect(),
1200 },
1201 }
1202 }
1203}
1204
85aaf69f 1205#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
1a4d82fc
JJ
1206pub struct Argument {
1207 pub type_: Type,
1208 pub name: String,
1a4d82fc
JJ
1209}
1210
a7813a04
XL
1211#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
1212pub enum SelfTy {
1213 SelfValue,
1214 SelfBorrowed(Option<Lifetime>, Mutability),
1215 SelfExplicit(Type),
1216}
1217
1218impl Argument {
1219 pub fn to_self(&self) -> Option<SelfTy> {
32a655c1
SL
1220 if self.name != "self" {
1221 return None;
a7813a04 1222 }
32a655c1
SL
1223 if self.type_.is_self_type() {
1224 return Some(SelfValue);
1225 }
1226 match self.type_ {
1227 BorrowedRef{ref lifetime, mutability, ref type_} if type_.is_self_type() => {
1228 Some(SelfBorrowed(lifetime.clone(), mutability))
1229 }
1230 _ => Some(SelfExplicit(self.type_.clone()))
1a4d82fc
JJ
1231 }
1232 }
1233}
1234
85aaf69f 1235#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
1a4d82fc
JJ
1236pub enum FunctionRetTy {
1237 Return(Type),
85aaf69f 1238 DefaultReturn,
1a4d82fc
JJ
1239}
1240
e9174d1e 1241impl Clean<FunctionRetTy> for hir::FunctionRetTy {
1a4d82fc
JJ
1242 fn clean(&self, cx: &DocContext) -> FunctionRetTy {
1243 match *self {
e9174d1e
SL
1244 hir::Return(ref typ) => Return(typ.clean(cx)),
1245 hir::DefaultReturn(..) => DefaultReturn,
1a4d82fc
JJ
1246 }
1247 }
1248}
1249
85aaf69f 1250#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
1a4d82fc 1251pub struct Trait {
e9174d1e 1252 pub unsafety: hir::Unsafety,
c34b1796 1253 pub items: Vec<Item>,
1a4d82fc
JJ
1254 pub generics: Generics,
1255 pub bounds: Vec<TyParamBound>,
1256}
1257
1258impl Clean<Item> for doctree::Trait {
1259 fn clean(&self, cx: &DocContext) -> Item {
1260 Item {
1261 name: Some(self.name.clean(cx)),
1262 attrs: self.attrs.clean(cx),
1263 source: self.whence.clean(cx),
32a655c1 1264 def_id: cx.tcx.hir.local_def_id(self.id),
1a4d82fc
JJ
1265 visibility: self.vis.clean(cx),
1266 stability: self.stab.clean(cx),
9cc50fc6 1267 deprecation: self.depr.clean(cx),
1a4d82fc
JJ
1268 inner: TraitItem(Trait {
1269 unsafety: self.unsafety,
1270 items: self.items.clean(cx),
1271 generics: self.generics.clean(cx),
1272 bounds: self.bounds.clean(cx),
1273 }),
1274 }
1275 }
1276}
1277
e9174d1e 1278impl Clean<Type> for hir::TraitRef {
1a4d82fc
JJ
1279 fn clean(&self, cx: &DocContext) -> Type {
1280 resolve_type(cx, self.path.clean(cx), self.ref_id)
1281 }
1282}
1283
e9174d1e 1284impl Clean<PolyTrait> for hir::PolyTraitRef {
1a4d82fc
JJ
1285 fn clean(&self, cx: &DocContext) -> PolyTrait {
1286 PolyTrait {
1287 trait_: self.trait_ref.clean(cx),
1288 lifetimes: self.bound_lifetimes.clean(cx)
1289 }
1290 }
1291}
1292
e9174d1e 1293impl Clean<Item> for hir::TraitItem {
c34b1796
AL
1294 fn clean(&self, cx: &DocContext) -> Item {
1295 let inner = match self.node {
32a655c1 1296 hir::TraitItemKind::Const(ref ty, default) => {
d9579d0f 1297 AssociatedConstItem(ty.clean(cx),
32a655c1 1298 default.map(|e| print_const_expr(cx, e)))
d9579d0f 1299 }
32a655c1
SL
1300 hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Provided(body)) => {
1301 MethodItem((sig, body).clean(cx))
c34b1796 1302 }
32a655c1
SL
1303 hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Required(ref names)) => {
1304 TyMethodItem(TyMethod {
1305 unsafety: sig.unsafety.clone(),
1306 decl: (&*sig.decl, &names[..]).clean(cx),
1307 generics: sig.generics.clean(cx),
1308 abi: sig.abi
1309 })
c34b1796 1310 }
32a655c1 1311 hir::TraitItemKind::Type(ref bounds, ref default) => {
c34b1796
AL
1312 AssociatedTypeItem(bounds.clean(cx), default.clean(cx))
1313 }
1314 };
1315 Item {
b039eaaf 1316 name: Some(self.name.clean(cx)),
c34b1796
AL
1317 attrs: self.attrs.clean(cx),
1318 source: self.span.clean(cx),
32a655c1 1319 def_id: cx.tcx.hir.local_def_id(self.id),
c34b1796 1320 visibility: None,
32a655c1
SL
1321 stability: get_stability(cx, cx.tcx.hir.local_def_id(self.id)),
1322 deprecation: get_deprecation(cx, cx.tcx.hir.local_def_id(self.id)),
c34b1796 1323 inner: inner
1a4d82fc
JJ
1324 }
1325 }
1326}
1327
e9174d1e 1328impl Clean<Item> for hir::ImplItem {
c34b1796
AL
1329 fn clean(&self, cx: &DocContext) -> Item {
1330 let inner = match self.node {
32a655c1 1331 hir::ImplItemKind::Const(ref ty, expr) => {
7453a54e 1332 AssociatedConstItem(ty.clean(cx),
32a655c1 1333 Some(print_const_expr(cx, expr)))
d9579d0f 1334 }
32a655c1
SL
1335 hir::ImplItemKind::Method(ref sig, body) => {
1336 MethodItem((sig, body).clean(cx))
c34b1796 1337 }
92a42be0 1338 hir::ImplItemKind::Type(ref ty) => TypedefItem(Typedef {
c34b1796
AL
1339 type_: ty.clean(cx),
1340 generics: Generics {
1341 lifetimes: Vec::new(),
1342 type_params: Vec::new(),
1343 where_predicates: Vec::new()
1344 },
62682a34 1345 }, true),
c34b1796
AL
1346 };
1347 Item {
b039eaaf 1348 name: Some(self.name.clean(cx)),
c34b1796
AL
1349 source: self.span.clean(cx),
1350 attrs: self.attrs.clean(cx),
32a655c1 1351 def_id: cx.tcx.hir.local_def_id(self.id),
c34b1796 1352 visibility: self.vis.clean(cx),
32a655c1
SL
1353 stability: get_stability(cx, cx.tcx.hir.local_def_id(self.id)),
1354 deprecation: get_deprecation(cx, cx.tcx.hir.local_def_id(self.id)),
c34b1796 1355 inner: inner
1a4d82fc
JJ
1356 }
1357 }
1358}
1359
476ff2be 1360impl<'tcx> Clean<Item> for ty::AssociatedItem {
1a4d82fc 1361 fn clean(&self, cx: &DocContext) -> Item {
476ff2be
SL
1362 let inner = match self.kind {
1363 ty::AssociatedKind::Const => {
7cac9316 1364 let ty = cx.tcx.type_of(self.def_id);
476ff2be 1365 AssociatedConstItem(ty.clean(cx), None)
a7813a04 1366 }
476ff2be 1367 ty::AssociatedKind::Method => {
7cac9316
XL
1368 let generics = (cx.tcx.generics_of(self.def_id),
1369 &cx.tcx.predicates_of(self.def_id)).clean(cx);
041b39d2 1370 let sig = cx.tcx.fn_sig(self.def_id);
8bb4bdeb 1371 let mut decl = (self.def_id, sig).clean(cx);
476ff2be
SL
1372
1373 if self.method_has_self_argument {
1374 let self_ty = match self.container {
1375 ty::ImplContainer(def_id) => {
7cac9316 1376 cx.tcx.type_of(def_id)
476ff2be
SL
1377 }
1378 ty::TraitContainer(_) => cx.tcx.mk_self_type()
1379 };
8bb4bdeb 1380 let self_arg_ty = *sig.input(0).skip_binder();
476ff2be 1381 if self_arg_ty == self_ty {
32a655c1 1382 decl.inputs.values[0].type_ = Generic(String::from("Self"));
476ff2be
SL
1383 } else if let ty::TyRef(_, mt) = self_arg_ty.sty {
1384 if mt.ty == self_ty {
1385 match decl.inputs.values[0].type_ {
32a655c1
SL
1386 BorrowedRef{ref mut type_, ..} => {
1387 **type_ = Generic(String::from("Self"))
1388 }
476ff2be
SL
1389 _ => unreachable!(),
1390 }
1391 }
1392 }
1393 }
1394
1395 let provided = match self.container {
1396 ty::ImplContainer(_) => false,
1397 ty::TraitContainer(_) => self.defaultness.has_value()
1398 };
1399 if provided {
1400 MethodItem(Method {
8bb4bdeb 1401 unsafety: sig.unsafety(),
476ff2be
SL
1402 generics: generics,
1403 decl: decl,
8bb4bdeb 1404 abi: sig.abi(),
476ff2be 1405
cc61c64b 1406 // trait methods cannot (currently, at least) be const
476ff2be
SL
1407 constness: hir::Constness::NotConst,
1408 })
1409 } else {
1410 TyMethodItem(TyMethod {
8bb4bdeb 1411 unsafety: sig.unsafety(),
476ff2be
SL
1412 generics: generics,
1413 decl: decl,
8bb4bdeb 1414 abi: sig.abi(),
476ff2be 1415 })
a7813a04
XL
1416 }
1417 }
476ff2be
SL
1418 ty::AssociatedKind::Type => {
1419 let my_name = self.name.clean(cx);
1420
1421 let mut bounds = if let ty::TraitContainer(did) = self.container {
1422 // When loading a cross-crate associated type, the bounds for this type
1423 // are actually located on the trait/impl itself, so we need to load
1424 // all of the generics from there and then look for bounds that are
1425 // applied to this associated type in question.
7cac9316
XL
1426 let predicates = cx.tcx.predicates_of(did);
1427 let generics = (cx.tcx.generics_of(did), &predicates).clean(cx);
476ff2be
SL
1428 generics.where_predicates.iter().filter_map(|pred| {
1429 let (name, self_type, trait_, bounds) = match *pred {
1430 WherePredicate::BoundPredicate {
1431 ty: QPath { ref name, ref self_type, ref trait_ },
1432 ref bounds
1433 } => (name, self_type, trait_, bounds),
1434 _ => return None,
1435 };
1436 if *name != my_name { return None }
1437 match **trait_ {
1438 ResolvedPath { did, .. } if did == self.container.id() => {}
1439 _ => return None,
1440 }
1441 match **self_type {
1442 Generic(ref s) if *s == "Self" => {}
1443 _ => return None,
1444 }
1445 Some(bounds)
1446 }).flat_map(|i| i.iter().cloned()).collect::<Vec<_>>()
1447 } else {
1448 vec![]
1449 };
1450
1451 // Our Sized/?Sized bound didn't get handled when creating the generics
1452 // because we didn't actually get our whole set of bounds until just now
1453 // (some of them may have come from the trait). If we do have a sized
1454 // bound, we remove it, and if we don't then we add the `?Sized` bound
1455 // at the end.
1456 match bounds.iter().position(|b| b.is_sized_bound(cx)) {
1457 Some(i) => { bounds.remove(i); }
1458 None => bounds.push(TyParamBound::maybe_sized(cx)),
1459 }
1460
1461 let ty = if self.defaultness.has_value() {
7cac9316 1462 Some(cx.tcx.type_of(self.def_id))
476ff2be
SL
1463 } else {
1464 None
1465 };
1466
1467 AssociatedTypeItem(bounds, ty.clean(cx))
9346a6ac
AL
1468 }
1469 };
9346a6ac 1470
1a4d82fc
JJ
1471 Item {
1472 name: Some(self.name.clean(cx)),
a7813a04 1473 visibility: Some(Inherited),
1a4d82fc 1474 stability: get_stability(cx, self.def_id),
9cc50fc6 1475 deprecation: get_deprecation(cx, self.def_id),
1a4d82fc 1476 def_id: self.def_id,
476ff2be
SL
1477 attrs: inline::load_attrs(cx, self.def_id),
1478 source: cx.tcx.def_span(self.def_id).clean(cx),
9346a6ac 1479 inner: inner,
1a4d82fc
JJ
1480 }
1481 }
1482}
1483
1a4d82fc 1484/// A trait reference, which may have higher ranked lifetimes.
85aaf69f 1485#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
1a4d82fc
JJ
1486pub struct PolyTrait {
1487 pub trait_: Type,
1488 pub lifetimes: Vec<Lifetime>
1489}
1490
1491/// A representation of a Type suitable for hyperlinking purposes. Ideally one can get the original
54a0048b 1492/// type out of the AST/TyCtxt given one of these, if more information is needed. Most importantly
1a4d82fc 1493/// it does not preserve mutability or boxes.
7cac9316 1494#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
1a4d82fc 1495pub enum Type {
e9174d1e 1496 /// structs/enums/traits (most that'd be an hir::TyPath)
1a4d82fc
JJ
1497 ResolvedPath {
1498 path: Path,
1499 typarams: Option<Vec<TyParamBound>>,
e9174d1e 1500 did: DefId,
62682a34
SL
1501 /// true if is a `T::Name` path for associated types
1502 is_generic: bool,
1a4d82fc 1503 },
1a4d82fc
JJ
1504 /// For parameterized types, so the consumer of the JSON don't go
1505 /// looking for types which don't exist anywhere.
1506 Generic(String),
c34b1796
AL
1507 /// Primitives are the fixed-size numeric types (plus int/usize/float), char,
1508 /// arrays, slices, and tuples.
1a4d82fc 1509 Primitive(PrimitiveType),
1a4d82fc
JJ
1510 /// extern "ABI" fn
1511 BareFunction(Box<BareFunctionDecl>),
1512 Tuple(Vec<Type>),
7cac9316
XL
1513 Slice(Box<Type>),
1514 Array(Box<Type>, usize),
5bcae85e 1515 Never,
1a4d82fc
JJ
1516 Unique(Box<Type>),
1517 RawPointer(Mutability, Box<Type>),
1518 BorrowedRef {
1519 lifetime: Option<Lifetime>,
1520 mutability: Mutability,
1521 type_: Box<Type>,
1522 },
1523
1524 // <Type as Trait>::Name
1525 QPath {
1526 name: String,
1527 self_type: Box<Type>,
1528 trait_: Box<Type>
1529 },
1530
1531 // _
1532 Infer,
1533
5bcae85e
SL
1534 // impl TraitA+TraitB
1535 ImplTrait(Vec<TyParamBound>),
1a4d82fc
JJ
1536}
1537
85aaf69f 1538#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Copy, Debug)]
1a4d82fc 1539pub enum PrimitiveType {
32a655c1
SL
1540 Isize, I8, I16, I32, I64, I128,
1541 Usize, U8, U16, U32, U64, U128,
1a4d82fc
JJ
1542 F32, F64,
1543 Char,
1544 Bool,
1545 Str,
1546 Slice,
c34b1796 1547 Array,
9e0c209e
SL
1548 Tuple,
1549 RawPointer,
1a4d82fc
JJ
1550}
1551
85aaf69f 1552#[derive(Clone, RustcEncodable, RustcDecodable, Copy, Debug)]
1a4d82fc 1553pub enum TypeKind {
c30ab7b3
SL
1554 Enum,
1555 Function,
1556 Module,
1557 Const,
1558 Static,
1559 Struct,
1560 Union,
1561 Trait,
1562 Variant,
1563 Typedef,
1a4d82fc
JJ
1564}
1565
54a0048b
SL
1566pub trait GetDefId {
1567 fn def_id(&self) -> Option<DefId>;
1568}
1569
1570impl<T: GetDefId> GetDefId for Option<T> {
1571 fn def_id(&self) -> Option<DefId> {
1572 self.as_ref().and_then(|d| d.def_id())
1573 }
1574}
1575
9346a6ac
AL
1576impl Type {
1577 pub fn primitive_type(&self) -> Option<PrimitiveType> {
1578 match *self {
1579 Primitive(p) | BorrowedRef { type_: box Primitive(p), ..} => Some(p),
7cac9316
XL
1580 Slice(..) | BorrowedRef { type_: box Slice(..), .. } => Some(PrimitiveType::Slice),
1581 Array(..) | BorrowedRef { type_: box Array(..), .. } => Some(PrimitiveType::Array),
9e0c209e
SL
1582 Tuple(..) => Some(PrimitiveType::Tuple),
1583 RawPointer(..) => Some(PrimitiveType::RawPointer),
9346a6ac
AL
1584 _ => None,
1585 }
1586 }
a7813a04
XL
1587
1588 pub fn is_generic(&self) -> bool {
1589 match *self {
1590 ResolvedPath { is_generic, .. } => is_generic,
1591 _ => false,
1592 }
1593 }
32a655c1
SL
1594
1595 pub fn is_self_type(&self) -> bool {
1596 match *self {
1597 Generic(ref name) => name == "Self",
1598 _ => false
1599 }
1600 }
9346a6ac
AL
1601}
1602
54a0048b
SL
1603impl GetDefId for Type {
1604 fn def_id(&self) -> Option<DefId> {
1605 match *self {
1606 ResolvedPath { did, .. } => Some(did),
1607 _ => None,
1608 }
1609 }
1610}
1611
1a4d82fc
JJ
1612impl PrimitiveType {
1613 fn from_str(s: &str) -> Option<PrimitiveType> {
85aaf69f 1614 match s {
9e0c209e
SL
1615 "isize" => Some(PrimitiveType::Isize),
1616 "i8" => Some(PrimitiveType::I8),
1617 "i16" => Some(PrimitiveType::I16),
1618 "i32" => Some(PrimitiveType::I32),
1619 "i64" => Some(PrimitiveType::I64),
32a655c1 1620 "i128" => Some(PrimitiveType::I128),
9e0c209e
SL
1621 "usize" => Some(PrimitiveType::Usize),
1622 "u8" => Some(PrimitiveType::U8),
1623 "u16" => Some(PrimitiveType::U16),
1624 "u32" => Some(PrimitiveType::U32),
1625 "u64" => Some(PrimitiveType::U64),
32a655c1 1626 "u128" => Some(PrimitiveType::U128),
9e0c209e
SL
1627 "bool" => Some(PrimitiveType::Bool),
1628 "char" => Some(PrimitiveType::Char),
1629 "str" => Some(PrimitiveType::Str),
1630 "f32" => Some(PrimitiveType::F32),
1631 "f64" => Some(PrimitiveType::F64),
1632 "array" => Some(PrimitiveType::Array),
1633 "slice" => Some(PrimitiveType::Slice),
1634 "tuple" => Some(PrimitiveType::Tuple),
1635 "pointer" => Some(PrimitiveType::RawPointer),
1a4d82fc
JJ
1636 _ => None,
1637 }
1638 }
1639
c30ab7b3 1640 pub fn as_str(&self) -> &'static str {
32a655c1 1641 use self::PrimitiveType::*;
1a4d82fc 1642 match *self {
32a655c1
SL
1643 Isize => "isize",
1644 I8 => "i8",
1645 I16 => "i16",
1646 I32 => "i32",
1647 I64 => "i64",
1648 I128 => "i128",
1649 Usize => "usize",
1650 U8 => "u8",
1651 U16 => "u16",
1652 U32 => "u32",
1653 U64 => "u64",
1654 U128 => "u128",
1655 F32 => "f32",
1656 F64 => "f64",
1657 Str => "str",
1658 Bool => "bool",
1659 Char => "char",
1660 Array => "array",
1661 Slice => "slice",
1662 Tuple => "tuple",
1663 RawPointer => "pointer",
1a4d82fc
JJ
1664 }
1665 }
1666
1667 pub fn to_url_str(&self) -> &'static str {
c30ab7b3 1668 self.as_str()
1a4d82fc 1669 }
1a4d82fc
JJ
1670}
1671
9e0c209e
SL
1672impl From<ast::IntTy> for PrimitiveType {
1673 fn from(int_ty: ast::IntTy) -> PrimitiveType {
1674 match int_ty {
1675 ast::IntTy::Is => PrimitiveType::Isize,
1676 ast::IntTy::I8 => PrimitiveType::I8,
1677 ast::IntTy::I16 => PrimitiveType::I16,
1678 ast::IntTy::I32 => PrimitiveType::I32,
1679 ast::IntTy::I64 => PrimitiveType::I64,
32a655c1 1680 ast::IntTy::I128 => PrimitiveType::I128,
9e0c209e
SL
1681 }
1682 }
5bcae85e
SL
1683}
1684
9e0c209e
SL
1685impl From<ast::UintTy> for PrimitiveType {
1686 fn from(uint_ty: ast::UintTy) -> PrimitiveType {
1687 match uint_ty {
1688 ast::UintTy::Us => PrimitiveType::Usize,
1689 ast::UintTy::U8 => PrimitiveType::U8,
1690 ast::UintTy::U16 => PrimitiveType::U16,
1691 ast::UintTy::U32 => PrimitiveType::U32,
1692 ast::UintTy::U64 => PrimitiveType::U64,
32a655c1 1693 ast::UintTy::U128 => PrimitiveType::U128,
5bcae85e 1694 }
5bcae85e 1695 }
9e0c209e
SL
1696}
1697
1698impl From<ast::FloatTy> for PrimitiveType {
1699 fn from(float_ty: ast::FloatTy) -> PrimitiveType {
1700 match float_ty {
1701 ast::FloatTy::F32 => PrimitiveType::F32,
1702 ast::FloatTy::F64 => PrimitiveType::F64,
5bcae85e 1703 }
5bcae85e
SL
1704 }
1705}
1706
e9174d1e 1707impl Clean<Type> for hir::Ty {
1a4d82fc 1708 fn clean(&self, cx: &DocContext) -> Type {
54a0048b 1709 use rustc::hir::*;
1a4d82fc 1710 match self.node {
5bcae85e 1711 TyNever => Never,
1a4d82fc 1712 TyPtr(ref m) => RawPointer(m.mutbl.clean(cx), box m.ty.clean(cx)),
32a655c1
SL
1713 TyRptr(ref l, ref m) => {
1714 let lifetime = if l.is_elided() {
1715 None
1716 } else {
1717 Some(l.clean(cx))
5bcae85e 1718 };
32a655c1
SL
1719 BorrowedRef {lifetime: lifetime, mutability: m.mutbl.clean(cx),
1720 type_: box m.ty.clean(cx)}
1721 }
7cac9316 1722 TySlice(ref ty) => Slice(box ty.clean(cx)),
32a655c1 1723 TyArray(ref ty, length) => {
cc61c64b 1724 use rustc::middle::const_val::eval_length;
32a655c1 1725 let n = eval_length(cx.tcx, length, "array length").unwrap();
7cac9316 1726 Array(box ty.clean(cx), n)
5bcae85e 1727 },
1a4d82fc 1728 TyTup(ref tys) => Tuple(tys.clean(cx)),
476ff2be
SL
1729 TyPath(hir::QPath::Resolved(None, ref path)) => {
1730 if let Some(new_ty) = cx.ty_substs.borrow().get(&path.def).cloned() {
1731 return new_ty;
9e0c209e
SL
1732 }
1733
476ff2be
SL
1734 let mut alias = None;
1735 if let Def::TyAlias(def_id) = path.def {
1736 // Substitute private type aliases
32a655c1 1737 if let Some(node_id) = cx.tcx.hir.as_local_node_id(def_id) {
476ff2be 1738 if !cx.access_levels.borrow().is_exported(def_id) {
32a655c1 1739 alias = Some(&cx.tcx.hir.expect_item(node_id).node);
476ff2be 1740 }
9e0c209e 1741 }
476ff2be
SL
1742 };
1743
1744 if let Some(&hir::ItemTy(ref ty, ref generics)) = alias {
9e0c209e 1745 let provided_params = &path.segments.last().unwrap().parameters;
476ff2be
SL
1746 let mut ty_substs = FxHashMap();
1747 let mut lt_substs = FxHashMap();
9e0c209e 1748 for (i, ty_param) in generics.ty_params.iter().enumerate() {
32a655c1 1749 let ty_param_def = Def::TyParam(cx.tcx.hir.local_def_id(ty_param.id));
9e0c209e
SL
1750 if let Some(ty) = provided_params.types().get(i).cloned()
1751 .cloned() {
1752 ty_substs.insert(ty_param_def, ty.unwrap().clean(cx));
1753 } else if let Some(default) = ty_param.default.clone() {
1754 ty_substs.insert(ty_param_def, default.unwrap().clean(cx));
5bcae85e
SL
1755 }
1756 }
9e0c209e
SL
1757 for (i, lt_param) in generics.lifetimes.iter().enumerate() {
1758 if let Some(lt) = provided_params.lifetimes().get(i).cloned()
1759 .cloned() {
32a655c1
SL
1760 if !lt.is_elided() {
1761 lt_substs.insert(lt_param.lifetime.id, lt.clean(cx));
1762 }
9e0c209e
SL
1763 }
1764 }
1765 return cx.enter_alias(ty_substs, lt_substs, || ty.clean(cx));
5bcae85e
SL
1766 }
1767 resolve_type(cx, path.clean(cx), self.id)
c34b1796 1768 }
476ff2be 1769 TyPath(hir::QPath::Resolved(Some(ref qself), ref p)) => {
9cc50fc6
SL
1770 let mut segments: Vec<_> = p.segments.clone().into();
1771 segments.pop();
1772 let trait_path = hir::Path {
1773 span: p.span,
476ff2be 1774 def: Def::Trait(cx.tcx.associated_item(p.def.def_id()).container.id()),
9cc50fc6
SL
1775 segments: segments.into(),
1776 };
c34b1796 1777 Type::QPath {
a7813a04 1778 name: p.segments.last().unwrap().name.clean(cx),
476ff2be
SL
1779 self_type: box qself.clean(cx),
1780 trait_: box resolve_type(cx, trait_path.clean(cx), self.id)
1781 }
1782 }
1783 TyPath(hir::QPath::TypeRelative(ref qself, ref segment)) => {
1784 let mut def = Def::Err;
7cac9316
XL
1785 let ty = hir_ty_to_ty(cx.tcx, self);
1786 if let ty::TyProjection(proj) = ty.sty {
041b39d2 1787 def = Def::Trait(proj.trait_ref(cx.tcx).def_id);
476ff2be
SL
1788 }
1789 let trait_path = hir::Path {
1790 span: self.span,
476ff2be
SL
1791 def: def,
1792 segments: vec![].into(),
1793 };
1794 Type::QPath {
1795 name: segment.name.clean(cx),
1796 self_type: box qself.clean(cx),
c34b1796
AL
1797 trait_: box resolve_type(cx, trait_path.clean(cx), self.id)
1798 }
1a4d82fc 1799 }
32a655c1
SL
1800 TyTraitObject(ref bounds, ref lifetime) => {
1801 match bounds[0].clean(cx).trait_ {
62682a34 1802 ResolvedPath { path, typarams: None, did, is_generic } => {
32a655c1
SL
1803 let mut bounds: Vec<_> = bounds[1..].iter().map(|bound| {
1804 TraitBound(bound.clean(cx), hir::TraitBoundModifier::None)
1805 }).collect();
1806 if !lifetime.is_elided() {
1807 bounds.push(RegionBound(lifetime.clean(cx)));
1808 }
62682a34
SL
1809 ResolvedPath {
1810 path: path,
32a655c1 1811 typarams: Some(bounds),
62682a34
SL
1812 did: did,
1813 is_generic: is_generic,
1814 }
1a4d82fc 1815 }
32a655c1 1816 _ => Infer // shouldn't happen
1a4d82fc
JJ
1817 }
1818 }
1819 TyBareFn(ref barefn) => BareFunction(box barefn.clean(cx)),
5bcae85e 1820 TyImplTrait(ref bounds) => ImplTrait(bounds.clean(cx)),
cc61c64b 1821 TyInfer | TyErr => Infer,
54a0048b 1822 TyTypeof(..) => panic!("Unimplemented type {:?}", self.node),
1a4d82fc
JJ
1823 }
1824 }
1825}
1826
1827impl<'tcx> Clean<Type> for ty::Ty<'tcx> {
1828 fn clean(&self, cx: &DocContext) -> Type {
1829 match self.sty {
5bcae85e 1830 ty::TyNever => Never,
9e0c209e
SL
1831 ty::TyBool => Primitive(PrimitiveType::Bool),
1832 ty::TyChar => Primitive(PrimitiveType::Char),
1833 ty::TyInt(int_ty) => Primitive(int_ty.into()),
1834 ty::TyUint(uint_ty) => Primitive(uint_ty.into()),
1835 ty::TyFloat(float_ty) => Primitive(float_ty.into()),
1836 ty::TyStr => Primitive(PrimitiveType::Str),
7cac9316
XL
1837 ty::TySlice(ty) => Slice(box ty.clean(cx)),
1838 ty::TyArray(ty, n) => Array(box ty.clean(cx), n),
62682a34
SL
1839 ty::TyRawPtr(mt) => RawPointer(mt.mutbl.clean(cx), box mt.ty.clean(cx)),
1840 ty::TyRef(r, mt) => BorrowedRef {
1a4d82fc
JJ
1841 lifetime: r.clean(cx),
1842 mutability: mt.mutbl.clean(cx),
1843 type_: box mt.ty.clean(cx),
1844 },
041b39d2
XL
1845 ty::TyFnDef(..) |
1846 ty::TyFnPtr(_) => {
1847 let ty = cx.tcx.lift(self).unwrap();
1848 let sig = ty.fn_sig(cx.tcx);
1849 BareFunction(box BareFunctionDecl {
1850 unsafety: sig.unsafety(),
1851 generics: Generics {
1852 lifetimes: Vec::new(),
1853 type_params: Vec::new(),
1854 where_predicates: Vec::new()
1855 },
1856 decl: (cx.tcx.hir.local_def_id(ast::CRATE_NODE_ID), sig).clean(cx),
1857 abi: sig.abi(),
1858 })
1859 }
9e0c209e 1860 ty::TyAdt(def, substs) => {
e9174d1e 1861 let did = def.did;
9e0c209e 1862 let kind = match def.adt_kind() {
c30ab7b3
SL
1863 AdtKind::Struct => TypeKind::Struct,
1864 AdtKind::Union => TypeKind::Union,
1865 AdtKind::Enum => TypeKind::Enum,
1a4d82fc 1866 };
92a42be0 1867 inline::record_extern_fqn(cx, did, kind);
476ff2be 1868 let path = external_path(cx, &cx.tcx.item_name(did).as_str(),
9e0c209e 1869 None, false, vec![], substs);
1a4d82fc
JJ
1870 ResolvedPath {
1871 path: path,
1872 typarams: None,
1873 did: did,
62682a34 1874 is_generic: false,
1a4d82fc
JJ
1875 }
1876 }
476ff2be
SL
1877 ty::TyDynamic(ref obj, ref reg) => {
1878 if let Some(principal) = obj.principal() {
1879 let did = principal.def_id();
1880 inline::record_extern_fqn(cx, did, TypeKind::Trait);
1881
1882 let mut typarams = vec![];
1883 reg.clean(cx).map(|b| typarams.push(RegionBound(b)));
1884 for did in obj.auto_traits() {
1885 let empty = cx.tcx.intern_substs(&[]);
1886 let path = external_path(cx, &cx.tcx.item_name(did).as_str(),
1887 Some(did), false, vec![], empty);
1888 inline::record_extern_fqn(cx, did, TypeKind::Trait);
1889 let bound = TraitBound(PolyTrait {
1890 trait_: ResolvedPath {
1891 path: path,
1892 typarams: None,
1893 did: did,
1894 is_generic: false,
1895 },
1896 lifetimes: vec![]
1897 }, hir::TraitBoundModifier::None);
1898 typarams.push(bound);
1899 }
9e0c209e 1900
476ff2be
SL
1901 let mut bindings = vec![];
1902 for ty::Binder(ref pb) in obj.projection_bounds() {
1903 bindings.push(TypeBinding {
041b39d2 1904 name: cx.tcx.associated_item(pb.item_def_id).name.clean(cx),
476ff2be
SL
1905 ty: pb.ty.clean(cx)
1906 });
1907 }
9e0c209e 1908
476ff2be
SL
1909 let path = external_path(cx, &cx.tcx.item_name(did).as_str(), Some(did),
1910 false, bindings, principal.0.substs);
1911 ResolvedPath {
1912 path: path,
1913 typarams: Some(typarams),
1914 did: did,
1915 is_generic: false,
1916 }
1917 } else {
1918 Never
1a4d82fc
JJ
1919 }
1920 }
8bb4bdeb 1921 ty::TyTuple(ref t, _) => Tuple(t.clean(cx)),
1a4d82fc 1922
62682a34 1923 ty::TyProjection(ref data) => data.clean(cx),
1a4d82fc 1924
c1a9b12d 1925 ty::TyParam(ref p) => Generic(p.name.to_string()),
1a4d82fc 1926
5bcae85e
SL
1927 ty::TyAnon(def_id, substs) => {
1928 // Grab the "TraitA + TraitB" from `impl TraitA + TraitB`,
1929 // by looking up the projections associated with the def_id.
7cac9316 1930 let predicates_of = cx.tcx.predicates_of(def_id);
476ff2be 1931 let substs = cx.tcx.lift(&substs).unwrap();
7cac9316 1932 let bounds = predicates_of.instantiate(cx.tcx, substs);
9e0c209e 1933 ImplTrait(bounds.predicates.into_iter().filter_map(|predicate| {
5bcae85e
SL
1934 predicate.to_opt_poly_trait_ref().clean(cx)
1935 }).collect())
1936 }
1937
62682a34 1938 ty::TyClosure(..) => Tuple(vec![]), // FIXME(pcwalton)
1a4d82fc 1939
62682a34
SL
1940 ty::TyInfer(..) => panic!("TyInfer"),
1941 ty::TyError => panic!("TyError"),
1a4d82fc
JJ
1942 }
1943 }
1944}
1945
e9174d1e 1946impl Clean<Item> for hir::StructField {
1a4d82fc 1947 fn clean(&self, cx: &DocContext) -> Item {
1a4d82fc 1948 Item {
54a0048b
SL
1949 name: Some(self.name).clean(cx),
1950 attrs: self.attrs.clean(cx),
1a4d82fc 1951 source: self.span.clean(cx),
54a0048b 1952 visibility: self.vis.clean(cx),
32a655c1
SL
1953 stability: get_stability(cx, cx.tcx.hir.local_def_id(self.id)),
1954 deprecation: get_deprecation(cx, cx.tcx.hir.local_def_id(self.id)),
1955 def_id: cx.tcx.hir.local_def_id(self.id),
54a0048b 1956 inner: StructFieldItem(self.ty.clean(cx)),
1a4d82fc
JJ
1957 }
1958 }
1959}
1960
476ff2be 1961impl<'tcx> Clean<Item> for ty::FieldDef {
1a4d82fc 1962 fn clean(&self, cx: &DocContext) -> Item {
1a4d82fc 1963 Item {
54a0048b 1964 name: Some(self.name).clean(cx),
476ff2be
SL
1965 attrs: cx.tcx.get_attrs(self.did).clean(cx),
1966 source: cx.tcx.def_span(self.did).clean(cx),
54a0048b 1967 visibility: self.vis.clean(cx),
e9174d1e 1968 stability: get_stability(cx, self.did),
9cc50fc6 1969 deprecation: get_deprecation(cx, self.did),
e9174d1e 1970 def_id: self.did,
7cac9316 1971 inner: StructFieldItem(cx.tcx.type_of(self.did).clean(cx)),
1a4d82fc
JJ
1972 }
1973 }
1974}
1975
a7813a04
XL
1976#[derive(Clone, PartialEq, Eq, RustcDecodable, RustcEncodable, Debug)]
1977pub enum Visibility {
1978 Public,
1979 Inherited,
1980}
1a4d82fc 1981
e9174d1e 1982impl Clean<Option<Visibility>> for hir::Visibility {
1a4d82fc 1983 fn clean(&self, _: &DocContext) -> Option<Visibility> {
a7813a04 1984 Some(if *self == hir::Visibility::Public { Public } else { Inherited })
54a0048b
SL
1985 }
1986}
1987
1988impl Clean<Option<Visibility>> for ty::Visibility {
1989 fn clean(&self, _: &DocContext) -> Option<Visibility> {
a7813a04 1990 Some(if *self == ty::Visibility::Public { Public } else { Inherited })
1a4d82fc
JJ
1991 }
1992}
1993
85aaf69f 1994#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
1a4d82fc
JJ
1995pub struct Struct {
1996 pub struct_type: doctree::StructType,
1997 pub generics: Generics,
1998 pub fields: Vec<Item>,
1999 pub fields_stripped: bool,
2000}
2001
9e0c209e
SL
2002#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
2003pub struct Union {
2004 pub struct_type: doctree::StructType,
2005 pub generics: Generics,
2006 pub fields: Vec<Item>,
2007 pub fields_stripped: bool,
2008}
2009
1a4d82fc
JJ
2010impl Clean<Item> for doctree::Struct {
2011 fn clean(&self, cx: &DocContext) -> Item {
2012 Item {
2013 name: Some(self.name.clean(cx)),
2014 attrs: self.attrs.clean(cx),
2015 source: self.whence.clean(cx),
32a655c1 2016 def_id: cx.tcx.hir.local_def_id(self.id),
1a4d82fc
JJ
2017 visibility: self.vis.clean(cx),
2018 stability: self.stab.clean(cx),
9cc50fc6 2019 deprecation: self.depr.clean(cx),
1a4d82fc
JJ
2020 inner: StructItem(Struct {
2021 struct_type: self.struct_type,
2022 generics: self.generics.clean(cx),
2023 fields: self.fields.clean(cx),
2024 fields_stripped: false,
2025 }),
2026 }
2027 }
2028}
2029
9e0c209e
SL
2030impl Clean<Item> for doctree::Union {
2031 fn clean(&self, cx: &DocContext) -> Item {
2032 Item {
2033 name: Some(self.name.clean(cx)),
2034 attrs: self.attrs.clean(cx),
2035 source: self.whence.clean(cx),
32a655c1 2036 def_id: cx.tcx.hir.local_def_id(self.id),
9e0c209e
SL
2037 visibility: self.vis.clean(cx),
2038 stability: self.stab.clean(cx),
2039 deprecation: self.depr.clean(cx),
2040 inner: UnionItem(Union {
2041 struct_type: self.struct_type,
2042 generics: self.generics.clean(cx),
2043 fields: self.fields.clean(cx),
2044 fields_stripped: false,
2045 }),
2046 }
2047 }
2048}
2049
1a4d82fc
JJ
2050/// This is a more limited form of the standard Struct, different in that
2051/// it lacks the things most items have (name, id, parameterization). Found
2052/// only as a variant in an enum.
85aaf69f 2053#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
1a4d82fc
JJ
2054pub struct VariantStruct {
2055 pub struct_type: doctree::StructType,
2056 pub fields: Vec<Item>,
2057 pub fields_stripped: bool,
2058}
2059
54a0048b 2060impl Clean<VariantStruct> for ::rustc::hir::VariantData {
1a4d82fc
JJ
2061 fn clean(&self, cx: &DocContext) -> VariantStruct {
2062 VariantStruct {
2063 struct_type: doctree::struct_type_from_def(self),
b039eaaf 2064 fields: self.fields().iter().map(|x| x.clean(cx)).collect(),
1a4d82fc
JJ
2065 fields_stripped: false,
2066 }
2067 }
2068}
2069
85aaf69f 2070#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
1a4d82fc
JJ
2071pub struct Enum {
2072 pub variants: Vec<Item>,
2073 pub generics: Generics,
2074 pub variants_stripped: bool,
2075}
2076
2077impl Clean<Item> for doctree::Enum {
2078 fn clean(&self, cx: &DocContext) -> Item {
2079 Item {
2080 name: Some(self.name.clean(cx)),
2081 attrs: self.attrs.clean(cx),
2082 source: self.whence.clean(cx),
32a655c1 2083 def_id: cx.tcx.hir.local_def_id(self.id),
1a4d82fc
JJ
2084 visibility: self.vis.clean(cx),
2085 stability: self.stab.clean(cx),
9cc50fc6 2086 deprecation: self.depr.clean(cx),
1a4d82fc
JJ
2087 inner: EnumItem(Enum {
2088 variants: self.variants.clean(cx),
2089 generics: self.generics.clean(cx),
2090 variants_stripped: false,
2091 }),
2092 }
2093 }
2094}
2095
85aaf69f 2096#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
1a4d82fc
JJ
2097pub struct Variant {
2098 pub kind: VariantKind,
2099}
2100
2101impl Clean<Item> for doctree::Variant {
2102 fn clean(&self, cx: &DocContext) -> Item {
2103 Item {
2104 name: Some(self.name.clean(cx)),
2105 attrs: self.attrs.clean(cx),
2106 source: self.whence.clean(cx),
b039eaaf 2107 visibility: None,
1a4d82fc 2108 stability: self.stab.clean(cx),
9cc50fc6 2109 deprecation: self.depr.clean(cx),
32a655c1 2110 def_id: cx.tcx.hir.local_def_id(self.def.id()),
1a4d82fc 2111 inner: VariantItem(Variant {
c30ab7b3 2112 kind: self.def.clean(cx),
1a4d82fc
JJ
2113 }),
2114 }
2115 }
2116}
2117
476ff2be 2118impl<'tcx> Clean<Item> for ty::VariantDef {
1a4d82fc 2119 fn clean(&self, cx: &DocContext) -> Item {
c30ab7b3
SL
2120 let kind = match self.ctor_kind {
2121 CtorKind::Const => VariantKind::CLike,
2122 CtorKind::Fn => {
2123 VariantKind::Tuple(
7cac9316 2124 self.fields.iter().map(|f| cx.tcx.type_of(f.did).clean(cx)).collect()
e9174d1e 2125 )
1a4d82fc 2126 }
c30ab7b3
SL
2127 CtorKind::Fictive => {
2128 VariantKind::Struct(VariantStruct {
1a4d82fc
JJ
2129 struct_type: doctree::Plain,
2130 fields_stripped: false,
e9174d1e 2131 fields: self.fields.iter().map(|field| {
1a4d82fc 2132 Item {
476ff2be 2133 source: cx.tcx.def_span(field.did).clean(cx),
e9174d1e 2134 name: Some(field.name.clean(cx)),
476ff2be 2135 attrs: cx.tcx.get_attrs(field.did).clean(cx),
54a0048b
SL
2136 visibility: field.vis.clean(cx),
2137 def_id: field.did,
2138 stability: get_stability(cx, field.did),
2139 deprecation: get_deprecation(cx, field.did),
7cac9316 2140 inner: StructFieldItem(cx.tcx.type_of(field.did).clean(cx))
1a4d82fc
JJ
2141 }
2142 }).collect()
2143 })
2144 }
2145 };
2146 Item {
2147 name: Some(self.name.clean(cx)),
476ff2be
SL
2148 attrs: inline::load_attrs(cx, self.did),
2149 source: cx.tcx.def_span(self.did).clean(cx),
a7813a04 2150 visibility: Some(Inherited),
e9174d1e 2151 def_id: self.did,
1a4d82fc 2152 inner: VariantItem(Variant { kind: kind }),
e9174d1e 2153 stability: get_stability(cx, self.did),
9cc50fc6 2154 deprecation: get_deprecation(cx, self.did),
1a4d82fc
JJ
2155 }
2156 }
2157}
2158
85aaf69f 2159#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
1a4d82fc 2160pub enum VariantKind {
c30ab7b3
SL
2161 CLike,
2162 Tuple(Vec<Type>),
2163 Struct(VariantStruct),
1a4d82fc
JJ
2164}
2165
c30ab7b3
SL
2166impl Clean<VariantKind> for hir::VariantData {
2167 fn clean(&self, cx: &DocContext) -> VariantKind {
2168 if self.is_struct() {
2169 VariantKind::Struct(self.clean(cx))
2170 } else if self.is_unit() {
2171 VariantKind::CLike
2172 } else {
2173 VariantKind::Tuple(self.fields().iter().map(|x| x.ty.clean(cx)).collect())
2174 }
1a4d82fc
JJ
2175 }
2176}
2177
85aaf69f 2178#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
1a4d82fc
JJ
2179pub struct Span {
2180 pub filename: String,
c34b1796
AL
2181 pub loline: usize,
2182 pub locol: usize,
2183 pub hiline: usize,
2184 pub hicol: usize,
1a4d82fc
JJ
2185}
2186
2187impl Span {
2188 fn empty() -> Span {
2189 Span {
2190 filename: "".to_string(),
2191 loline: 0, locol: 0,
2192 hiline: 0, hicol: 0,
2193 }
2194 }
2195}
2196
3157f602 2197impl Clean<Span> for syntax_pos::Span {
1a4d82fc 2198 fn clean(&self, cx: &DocContext) -> Span {
c1a9b12d
SL
2199 if *self == DUMMY_SP {
2200 return Span::empty();
2201 }
2202
1a4d82fc
JJ
2203 let cm = cx.sess().codemap();
2204 let filename = cm.span_to_filename(*self);
2205 let lo = cm.lookup_char_pos(self.lo);
2206 let hi = cm.lookup_char_pos(self.hi);
2207 Span {
2208 filename: filename.to_string(),
2209 loline: lo.line,
85aaf69f 2210 locol: lo.col.to_usize(),
1a4d82fc 2211 hiline: hi.line,
85aaf69f 2212 hicol: hi.col.to_usize(),
1a4d82fc
JJ
2213 }
2214 }
2215}
2216
85aaf69f 2217#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
1a4d82fc
JJ
2218pub struct Path {
2219 pub global: bool,
476ff2be 2220 pub def: Def,
1a4d82fc
JJ
2221 pub segments: Vec<PathSegment>,
2222}
2223
9346a6ac
AL
2224impl Path {
2225 pub fn singleton(name: String) -> Path {
2226 Path {
2227 global: false,
476ff2be 2228 def: Def::Err,
9346a6ac
AL
2229 segments: vec![PathSegment {
2230 name: name,
2231 params: PathParameters::AngleBracketed {
2232 lifetimes: Vec::new(),
2233 types: Vec::new(),
2234 bindings: Vec::new()
2235 }
2236 }]
2237 }
2238 }
a7813a04 2239
32a655c1
SL
2240 pub fn last_name(&self) -> &str {
2241 self.segments.last().unwrap().name.as_str()
a7813a04 2242 }
9346a6ac
AL
2243}
2244
e9174d1e 2245impl Clean<Path> for hir::Path {
1a4d82fc
JJ
2246 fn clean(&self, cx: &DocContext) -> Path {
2247 Path {
32a655c1 2248 global: self.is_global(),
476ff2be 2249 def: self.def,
32a655c1 2250 segments: if self.is_global() { &self.segments[1..] } else { &self.segments }.clean(cx),
1a4d82fc
JJ
2251 }
2252 }
2253}
2254
85aaf69f 2255#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
1a4d82fc
JJ
2256pub enum PathParameters {
2257 AngleBracketed {
2258 lifetimes: Vec<Lifetime>,
2259 types: Vec<Type>,
cc61c64b 2260 bindings: Vec<TypeBinding>,
1a4d82fc
JJ
2261 },
2262 Parenthesized {
2263 inputs: Vec<Type>,
cc61c64b 2264 output: Option<Type>,
1a4d82fc
JJ
2265 }
2266}
2267
e9174d1e 2268impl Clean<PathParameters> for hir::PathParameters {
1a4d82fc
JJ
2269 fn clean(&self, cx: &DocContext) -> PathParameters {
2270 match *self {
e9174d1e 2271 hir::AngleBracketedParameters(ref data) => {
1a4d82fc 2272 PathParameters::AngleBracketed {
32a655c1
SL
2273 lifetimes: if data.lifetimes.iter().all(|lt| lt.is_elided()) {
2274 vec![]
2275 } else {
2276 data.lifetimes.clean(cx)
2277 },
1a4d82fc 2278 types: data.types.clean(cx),
cc61c64b 2279 bindings: data.bindings.clean(cx),
1a4d82fc
JJ
2280 }
2281 }
2282
e9174d1e 2283 hir::ParenthesizedParameters(ref data) => {
1a4d82fc
JJ
2284 PathParameters::Parenthesized {
2285 inputs: data.inputs.clean(cx),
cc61c64b 2286 output: data.output.clean(cx),
1a4d82fc
JJ
2287 }
2288 }
2289 }
2290 }
2291}
2292
85aaf69f 2293#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
1a4d82fc
JJ
2294pub struct PathSegment {
2295 pub name: String,
cc61c64b 2296 pub params: PathParameters,
1a4d82fc
JJ
2297}
2298
e9174d1e 2299impl Clean<PathSegment> for hir::PathSegment {
1a4d82fc
JJ
2300 fn clean(&self, cx: &DocContext) -> PathSegment {
2301 PathSegment {
a7813a04 2302 name: self.name.clean(cx),
1a4d82fc
JJ
2303 params: self.parameters.clean(cx)
2304 }
2305 }
2306}
2307
476ff2be 2308fn qpath_to_string(p: &hir::QPath) -> String {
32a655c1
SL
2309 let segments = match *p {
2310 hir::QPath::Resolved(_, ref path) => &path.segments,
2311 hir::QPath::TypeRelative(_, ref segment) => return segment.name.to_string(),
476ff2be
SL
2312 };
2313
1a4d82fc 2314 let mut s = String::new();
32a655c1
SL
2315 for (i, seg) in segments.iter().enumerate() {
2316 if i > 0 {
1a4d82fc 2317 s.push_str("::");
1a4d82fc 2318 }
32a655c1
SL
2319 if seg.name != keywords::CrateRoot.name() {
2320 s.push_str(&*seg.name.as_str());
2321 }
1a4d82fc
JJ
2322 }
2323 s
2324}
2325
1a4d82fc
JJ
2326impl Clean<String> for ast::Name {
2327 fn clean(&self, _: &DocContext) -> String {
c1a9b12d 2328 self.to_string()
1a4d82fc
JJ
2329 }
2330}
2331
85aaf69f 2332#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
1a4d82fc
JJ
2333pub struct Typedef {
2334 pub type_: Type,
2335 pub generics: Generics,
2336}
2337
2338impl Clean<Item> for doctree::Typedef {
2339 fn clean(&self, cx: &DocContext) -> Item {
2340 Item {
2341 name: Some(self.name.clean(cx)),
2342 attrs: self.attrs.clean(cx),
2343 source: self.whence.clean(cx),
32a655c1 2344 def_id: cx.tcx.hir.local_def_id(self.id.clone()),
1a4d82fc
JJ
2345 visibility: self.vis.clean(cx),
2346 stability: self.stab.clean(cx),
9cc50fc6 2347 deprecation: self.depr.clean(cx),
1a4d82fc
JJ
2348 inner: TypedefItem(Typedef {
2349 type_: self.ty.clean(cx),
2350 generics: self.gen.clean(cx),
62682a34 2351 }, false),
1a4d82fc
JJ
2352 }
2353 }
2354}
2355
85aaf69f 2356#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
1a4d82fc 2357pub struct BareFunctionDecl {
e9174d1e 2358 pub unsafety: hir::Unsafety,
1a4d82fc
JJ
2359 pub generics: Generics,
2360 pub decl: FnDecl,
a7813a04 2361 pub abi: Abi,
1a4d82fc
JJ
2362}
2363
e9174d1e 2364impl Clean<BareFunctionDecl> for hir::BareFnTy {
1a4d82fc
JJ
2365 fn clean(&self, cx: &DocContext) -> BareFunctionDecl {
2366 BareFunctionDecl {
2367 unsafety: self.unsafety,
2368 generics: Generics {
2369 lifetimes: self.lifetimes.clean(cx),
2370 type_params: Vec::new(),
2371 where_predicates: Vec::new()
2372 },
32a655c1 2373 decl: (&*self.decl, &[][..]).clean(cx),
a7813a04 2374 abi: self.abi,
1a4d82fc
JJ
2375 }
2376 }
2377}
2378
85aaf69f 2379#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
1a4d82fc
JJ
2380pub struct Static {
2381 pub type_: Type,
2382 pub mutability: Mutability,
2383 /// It's useful to have the value of a static documented, but I have no
2384 /// desire to represent expressions (that'd basically be all of the AST,
2385 /// which is huge!). So, have a string.
2386 pub expr: String,
2387}
2388
2389impl Clean<Item> for doctree::Static {
2390 fn clean(&self, cx: &DocContext) -> Item {
2391 debug!("cleaning static {}: {:?}", self.name.clean(cx), self);
2392 Item {
2393 name: Some(self.name.clean(cx)),
2394 attrs: self.attrs.clean(cx),
2395 source: self.whence.clean(cx),
32a655c1 2396 def_id: cx.tcx.hir.local_def_id(self.id),
1a4d82fc
JJ
2397 visibility: self.vis.clean(cx),
2398 stability: self.stab.clean(cx),
9cc50fc6 2399 deprecation: self.depr.clean(cx),
1a4d82fc
JJ
2400 inner: StaticItem(Static {
2401 type_: self.type_.clean(cx),
2402 mutability: self.mutability.clean(cx),
32a655c1 2403 expr: print_const_expr(cx, self.expr),
1a4d82fc
JJ
2404 }),
2405 }
2406 }
2407}
2408
85aaf69f 2409#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
1a4d82fc
JJ
2410pub struct Constant {
2411 pub type_: Type,
2412 pub expr: String,
2413}
2414
2415impl Clean<Item> for doctree::Constant {
2416 fn clean(&self, cx: &DocContext) -> Item {
2417 Item {
2418 name: Some(self.name.clean(cx)),
2419 attrs: self.attrs.clean(cx),
2420 source: self.whence.clean(cx),
32a655c1 2421 def_id: cx.tcx.hir.local_def_id(self.id),
1a4d82fc
JJ
2422 visibility: self.vis.clean(cx),
2423 stability: self.stab.clean(cx),
9cc50fc6 2424 deprecation: self.depr.clean(cx),
1a4d82fc
JJ
2425 inner: ConstantItem(Constant {
2426 type_: self.type_.clean(cx),
32a655c1 2427 expr: print_const_expr(cx, self.expr),
1a4d82fc
JJ
2428 }),
2429 }
2430 }
2431}
2432
85aaf69f 2433#[derive(Debug, Clone, RustcEncodable, RustcDecodable, PartialEq, Copy)]
1a4d82fc
JJ
2434pub enum Mutability {
2435 Mutable,
2436 Immutable,
2437}
2438
e9174d1e 2439impl Clean<Mutability> for hir::Mutability {
1a4d82fc
JJ
2440 fn clean(&self, _: &DocContext) -> Mutability {
2441 match self {
e9174d1e
SL
2442 &hir::MutMutable => Mutable,
2443 &hir::MutImmutable => Immutable,
1a4d82fc
JJ
2444 }
2445 }
2446}
2447
85aaf69f
SL
2448#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Copy, Debug)]
2449pub enum ImplPolarity {
2450 Positive,
2451 Negative,
2452}
2453
e9174d1e 2454impl Clean<ImplPolarity> for hir::ImplPolarity {
85aaf69f
SL
2455 fn clean(&self, _: &DocContext) -> ImplPolarity {
2456 match self {
e9174d1e
SL
2457 &hir::ImplPolarity::Positive => ImplPolarity::Positive,
2458 &hir::ImplPolarity::Negative => ImplPolarity::Negative,
85aaf69f
SL
2459 }
2460 }
2461}
2462
2463#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
1a4d82fc 2464pub struct Impl {
e9174d1e 2465 pub unsafety: hir::Unsafety,
1a4d82fc 2466 pub generics: Generics,
476ff2be 2467 pub provided_trait_methods: FxHashSet<String>,
1a4d82fc
JJ
2468 pub trait_: Option<Type>,
2469 pub for_: Type,
2470 pub items: Vec<Item>,
85aaf69f 2471 pub polarity: Option<ImplPolarity>,
1a4d82fc
JJ
2472}
2473
d9579d0f
AL
2474impl Clean<Vec<Item>> for doctree::Impl {
2475 fn clean(&self, cx: &DocContext) -> Vec<Item> {
2476 let mut ret = Vec::new();
2477 let trait_ = self.trait_.clean(cx);
2478 let items = self.items.clean(cx);
2479
2480 // If this impl block is an implementation of the Deref trait, then we
2481 // need to try inlining the target's inherent impl blocks as well.
476ff2be 2482 if trait_.def_id() == cx.tcx.lang_items.deref_trait() {
54a0048b 2483 build_deref_target_impls(cx, &items, &mut ret);
d9579d0f
AL
2484 }
2485
476ff2be
SL
2486 let provided = trait_.def_id().map(|did| {
2487 cx.tcx.provided_trait_methods(did)
2488 .into_iter()
2489 .map(|meth| meth.name.to_string())
2490 .collect()
2491 }).unwrap_or(FxHashSet());
54a0048b 2492
d9579d0f 2493 ret.push(Item {
1a4d82fc
JJ
2494 name: None,
2495 attrs: self.attrs.clean(cx),
2496 source: self.whence.clean(cx),
32a655c1 2497 def_id: cx.tcx.hir.local_def_id(self.id),
1a4d82fc
JJ
2498 visibility: self.vis.clean(cx),
2499 stability: self.stab.clean(cx),
9cc50fc6 2500 deprecation: self.depr.clean(cx),
1a4d82fc 2501 inner: ImplItem(Impl {
c34b1796 2502 unsafety: self.unsafety,
1a4d82fc 2503 generics: self.generics.clean(cx),
54a0048b 2504 provided_trait_methods: provided,
d9579d0f 2505 trait_: trait_,
1a4d82fc 2506 for_: self.for_.clean(cx),
d9579d0f 2507 items: items,
85aaf69f 2508 polarity: Some(self.polarity.clean(cx)),
1a4d82fc 2509 }),
d9579d0f 2510 });
54a0048b 2511 ret
d9579d0f
AL
2512 }
2513}
2514
2515fn build_deref_target_impls(cx: &DocContext,
2516 items: &[Item],
2517 ret: &mut Vec<Item>) {
32a655c1 2518 use self::PrimitiveType::*;
476ff2be 2519 let tcx = cx.tcx;
d9579d0f
AL
2520
2521 for item in items {
2522 let target = match item.inner {
62682a34 2523 TypedefItem(ref t, true) => &t.type_,
d9579d0f
AL
2524 _ => continue,
2525 };
2526 let primitive = match *target {
e9174d1e 2527 ResolvedPath { did, .. } if did.is_local() => continue,
d9579d0f 2528 ResolvedPath { did, .. } => {
476ff2be 2529 ret.extend(inline::build_impls(cx, did));
d9579d0f
AL
2530 continue
2531 }
2532 _ => match target.primitive_type() {
2533 Some(prim) => prim,
2534 None => continue,
2535 }
2536 };
2537 let did = match primitive {
32a655c1
SL
2538 Isize => tcx.lang_items.isize_impl(),
2539 I8 => tcx.lang_items.i8_impl(),
2540 I16 => tcx.lang_items.i16_impl(),
2541 I32 => tcx.lang_items.i32_impl(),
2542 I64 => tcx.lang_items.i64_impl(),
2543 I128 => tcx.lang_items.i128_impl(),
2544 Usize => tcx.lang_items.usize_impl(),
2545 U8 => tcx.lang_items.u8_impl(),
2546 U16 => tcx.lang_items.u16_impl(),
2547 U32 => tcx.lang_items.u32_impl(),
2548 U64 => tcx.lang_items.u64_impl(),
2549 U128 => tcx.lang_items.u128_impl(),
2550 F32 => tcx.lang_items.f32_impl(),
2551 F64 => tcx.lang_items.f64_impl(),
2552 Char => tcx.lang_items.char_impl(),
2553 Bool => None,
2554 Str => tcx.lang_items.str_impl(),
2555 Slice => tcx.lang_items.slice_impl(),
2556 Array => tcx.lang_items.slice_impl(),
2557 Tuple => None,
2558 RawPointer => tcx.lang_items.const_ptr_impl(),
d9579d0f
AL
2559 };
2560 if let Some(did) = did {
e9174d1e 2561 if !did.is_local() {
476ff2be 2562 inline::build_impl(cx, did, ret);
d9579d0f 2563 }
1a4d82fc
JJ
2564 }
2565 }
2566}
2567
c34b1796
AL
2568#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
2569pub struct DefaultImpl {
e9174d1e 2570 pub unsafety: hir::Unsafety,
c34b1796
AL
2571 pub trait_: Type,
2572}
2573
2574impl Clean<Item> for doctree::DefaultImpl {
2575 fn clean(&self, cx: &DocContext) -> Item {
2576 Item {
2577 name: None,
2578 attrs: self.attrs.clean(cx),
2579 source: self.whence.clean(cx),
32a655c1 2580 def_id: cx.tcx.hir.local_def_id(self.id),
a7813a04 2581 visibility: Some(Public),
c34b1796 2582 stability: None,
9cc50fc6 2583 deprecation: None,
c34b1796
AL
2584 inner: DefaultImplItem(DefaultImpl {
2585 unsafety: self.unsafety,
2586 trait_: self.trait_.clean(cx),
2587 }),
2588 }
2589 }
2590}
2591
85aaf69f
SL
2592impl Clean<Item> for doctree::ExternCrate {
2593 fn clean(&self, cx: &DocContext) -> Item {
2594 Item {
2595 name: None,
2596 attrs: self.attrs.clean(cx),
2597 source: self.whence.clean(cx),
a7813a04 2598 def_id: DefId { krate: self.cnum, index: CRATE_DEF_INDEX },
85aaf69f
SL
2599 visibility: self.vis.clean(cx),
2600 stability: None,
9cc50fc6 2601 deprecation: None,
85aaf69f
SL
2602 inner: ExternCrateItem(self.name.clean(cx), self.path.clone())
2603 }
2604 }
1a4d82fc
JJ
2605}
2606
85aaf69f 2607impl Clean<Vec<Item>> for doctree::Import {
1a4d82fc
JJ
2608 fn clean(&self, cx: &DocContext) -> Vec<Item> {
2609 // We consider inlining the documentation of `pub use` statements, but we
2610 // forcefully don't inline if this is not public or if the
2611 // #[doc(no_inline)] attribute is present.
3157f602 2612 // Don't inline doc(hidden) imports so they can be stripped at a later stage.
e9174d1e 2613 let denied = self.vis != hir::Public || self.attrs.iter().any(|a| {
cc61c64b
XL
2614 a.name().unwrap() == "doc" && match a.meta_item_list() {
2615 Some(l) => attr::list_contains_name(&l, "no_inline") ||
2616 attr::list_contains_name(&l, "hidden"),
1a4d82fc
JJ
2617 None => false,
2618 }
2619 });
476ff2be
SL
2620 let path = self.path.clean(cx);
2621 let inner = if self.glob {
2622 Import::Glob(resolve_use_source(cx, path))
2623 } else {
2624 let name = self.name;
2625 if !denied {
7cac9316 2626 if let Some(items) = inline::try_inline(cx, path.def, name) {
476ff2be 2627 return items;
85aaf69f 2628 }
1a4d82fc 2629 }
476ff2be 2630 Import::Simple(name.clean(cx), resolve_use_source(cx, path))
85aaf69f 2631 };
476ff2be 2632 vec![Item {
85aaf69f
SL
2633 name: None,
2634 attrs: self.attrs.clean(cx),
2635 source: self.whence.clean(cx),
32a655c1 2636 def_id: cx.tcx.hir.local_def_id(ast::CRATE_NODE_ID),
85aaf69f
SL
2637 visibility: self.vis.clean(cx),
2638 stability: None,
9cc50fc6 2639 deprecation: None,
85aaf69f 2640 inner: ImportItem(inner)
476ff2be 2641 }]
1a4d82fc
JJ
2642 }
2643}
2644
85aaf69f
SL
2645#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
2646pub enum Import {
1a4d82fc 2647 // use source as str;
c30ab7b3 2648 Simple(String, ImportSource),
1a4d82fc 2649 // use source::*;
476ff2be 2650 Glob(ImportSource)
1a4d82fc
JJ
2651}
2652
85aaf69f 2653#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
1a4d82fc
JJ
2654pub struct ImportSource {
2655 pub path: Path,
e9174d1e 2656 pub did: Option<DefId>,
1a4d82fc
JJ
2657}
2658
e9174d1e 2659impl Clean<Vec<Item>> for hir::ForeignMod {
1a4d82fc 2660 fn clean(&self, cx: &DocContext) -> Vec<Item> {
9346a6ac
AL
2661 let mut items = self.items.clean(cx);
2662 for item in &mut items {
54a0048b
SL
2663 if let ForeignFunctionItem(ref mut f) = item.inner {
2664 f.abi = self.abi;
9346a6ac
AL
2665 }
2666 }
2667 items
1a4d82fc
JJ
2668 }
2669}
2670
e9174d1e 2671impl Clean<Item> for hir::ForeignItem {
1a4d82fc
JJ
2672 fn clean(&self, cx: &DocContext) -> Item {
2673 let inner = match self.node {
32a655c1 2674 hir::ForeignItemFn(ref decl, ref names, ref generics) => {
1a4d82fc 2675 ForeignFunctionItem(Function {
32a655c1 2676 decl: (&**decl, &names[..]).clean(cx),
1a4d82fc 2677 generics: generics.clean(cx),
e9174d1e 2678 unsafety: hir::Unsafety::Unsafe,
7453a54e 2679 abi: Abi::Rust,
e9174d1e 2680 constness: hir::Constness::NotConst,
1a4d82fc
JJ
2681 })
2682 }
e9174d1e 2683 hir::ForeignItemStatic(ref ty, mutbl) => {
1a4d82fc
JJ
2684 ForeignStaticItem(Static {
2685 type_: ty.clean(cx),
2686 mutability: if mutbl {Mutable} else {Immutable},
2687 expr: "".to_string(),
2688 })
2689 }
2690 };
2691 Item {
b039eaaf 2692 name: Some(self.name.clean(cx)),
1a4d82fc
JJ
2693 attrs: self.attrs.clean(cx),
2694 source: self.span.clean(cx),
32a655c1 2695 def_id: cx.tcx.hir.local_def_id(self.id),
1a4d82fc 2696 visibility: self.vis.clean(cx),
32a655c1
SL
2697 stability: get_stability(cx, cx.tcx.hir.local_def_id(self.id)),
2698 deprecation: get_deprecation(cx, cx.tcx.hir.local_def_id(self.id)),
1a4d82fc
JJ
2699 inner: inner,
2700 }
2701 }
2702}
2703
2704// Utilities
2705
2706trait ToSource {
2707 fn to_src(&self, cx: &DocContext) -> String;
2708}
2709
3157f602 2710impl ToSource for syntax_pos::Span {
1a4d82fc
JJ
2711 fn to_src(&self, cx: &DocContext) -> String {
2712 debug!("converting span {:?} to snippet", self.clean(cx));
2713 let sn = match cx.sess().codemap().span_to_snippet(*self) {
85aaf69f
SL
2714 Ok(x) => x.to_string(),
2715 Err(_) => "".to_string()
1a4d82fc
JJ
2716 };
2717 debug!("got snippet {}", sn);
2718 sn
2719 }
2720}
2721
e9174d1e 2722fn name_from_pat(p: &hir::Pat) -> String {
54a0048b 2723 use rustc::hir::*;
1a4d82fc
JJ
2724 debug!("Trying to get a name from pattern: {:?}", p);
2725
2726 match p.node {
7453a54e 2727 PatKind::Wild => "_".to_string(),
476ff2be
SL
2728 PatKind::Binding(_, _, ref p, _) => p.node.to_string(),
2729 PatKind::TupleStruct(ref p, ..) | PatKind::Path(ref p) => qpath_to_string(p),
7453a54e 2730 PatKind::Struct(ref name, ref fields, etc) => {
476ff2be 2731 format!("{} {{ {}{} }}", qpath_to_string(name),
1a4d82fc 2732 fields.iter().map(|&Spanned { node: ref fp, .. }|
b039eaaf 2733 format!("{}: {}", fp.name, name_from_pat(&*fp.pat)))
c1a9b12d 2734 .collect::<Vec<String>>().join(", "),
1a4d82fc
JJ
2735 if etc { ", ..." } else { "" }
2736 )
476ff2be 2737 }
3157f602 2738 PatKind::Tuple(ref elts, _) => format!("({})", elts.iter().map(|p| name_from_pat(&**p))
c1a9b12d 2739 .collect::<Vec<String>>().join(", ")),
7453a54e
SL
2740 PatKind::Box(ref p) => name_from_pat(&**p),
2741 PatKind::Ref(ref p, _) => name_from_pat(&**p),
2742 PatKind::Lit(..) => {
2743 warn!("tried to get argument name from PatKind::Lit, \
1a4d82fc
JJ
2744 which is silly in function arguments");
2745 "()".to_string()
2746 },
7453a54e 2747 PatKind::Range(..) => panic!("tried to get argument name from PatKind::Range, \
1a4d82fc 2748 which is not allowed in function arguments"),
c30ab7b3 2749 PatKind::Slice(ref begin, ref mid, ref end) => {
1a4d82fc
JJ
2750 let begin = begin.iter().map(|p| name_from_pat(&**p));
2751 let mid = mid.as_ref().map(|p| format!("..{}", name_from_pat(&**p))).into_iter();
2752 let end = end.iter().map(|p| name_from_pat(&**p));
c1a9b12d 2753 format!("[{}]", begin.chain(mid).chain(end).collect::<Vec<_>>().join(", "))
1a4d82fc 2754 },
1a4d82fc
JJ
2755 }
2756}
2757
32a655c1
SL
2758fn print_const_expr(cx: &DocContext, body: hir::BodyId) -> String {
2759 cx.tcx.hir.node_to_pretty_string(body.node_id)
2760}
2761
476ff2be 2762/// Given a type Path, resolve it to a Type using the TyCtxt
1a4d82fc
JJ
2763fn resolve_type(cx: &DocContext,
2764 path: Path,
2765 id: ast::NodeId) -> Type {
b039eaaf 2766 debug!("resolve_type({:?},{:?})", path, id);
b039eaaf 2767
476ff2be 2768 let is_generic = match path.def {
7453a54e 2769 Def::PrimTy(p) => match p {
9e0c209e
SL
2770 hir::TyStr => return Primitive(PrimitiveType::Str),
2771 hir::TyBool => return Primitive(PrimitiveType::Bool),
2772 hir::TyChar => return Primitive(PrimitiveType::Char),
2773 hir::TyInt(int_ty) => return Primitive(int_ty.into()),
2774 hir::TyUint(uint_ty) => return Primitive(uint_ty.into()),
2775 hir::TyFloat(float_ty) => return Primitive(float_ty.into()),
1a4d82fc 2776 },
7453a54e 2777 Def::SelfTy(..) if path.segments.len() == 1 => {
a7813a04 2778 return Generic(keywords::SelfType.name().to_string());
c34b1796 2779 }
5bcae85e 2780 Def::SelfTy(..) | Def::TyParam(..) | Def::AssociatedTy(..) => true,
62682a34 2781 _ => false,
1a4d82fc 2782 };
476ff2be 2783 let did = register_def(&*cx, path.def);
62682a34 2784 ResolvedPath { path: path, typarams: None, did: did, is_generic: is_generic }
1a4d82fc
JJ
2785}
2786
7453a54e 2787fn register_def(cx: &DocContext, def: Def) -> DefId {
b039eaaf
SL
2788 debug!("register_def({:?})", def);
2789
1a4d82fc 2790 let (did, kind) = match def {
c30ab7b3
SL
2791 Def::Fn(i) => (i, TypeKind::Function),
2792 Def::TyAlias(i) => (i, TypeKind::Typedef),
2793 Def::Enum(i) => (i, TypeKind::Enum),
2794 Def::Trait(i) => (i, TypeKind::Trait),
2795 Def::Struct(i) => (i, TypeKind::Struct),
2796 Def::Union(i) => (i, TypeKind::Union),
2797 Def::Mod(i) => (i, TypeKind::Module),
2798 Def::Static(i, _) => (i, TypeKind::Static),
476ff2be 2799 Def::Variant(i) => (cx.tcx.parent_def_id(i).unwrap(), TypeKind::Enum),
c30ab7b3 2800 Def::SelfTy(Some(def_id), _) => (def_id, TypeKind::Trait),
9e0c209e
SL
2801 Def::SelfTy(_, Some(impl_def_id)) => {
2802 return impl_def_id
5bcae85e 2803 }
1a4d82fc
JJ
2804 _ => return def.def_id()
2805 };
e9174d1e 2806 if did.is_local() { return did }
1a4d82fc 2807 inline::record_extern_fqn(cx, did, kind);
c30ab7b3 2808 if let TypeKind::Trait = kind {
476ff2be 2809 let t = inline::build_external_trait(cx, did);
a7813a04 2810 cx.external_traits.borrow_mut().insert(did, t);
1a4d82fc 2811 }
54a0048b 2812 did
1a4d82fc
JJ
2813}
2814
476ff2be 2815fn resolve_use_source(cx: &DocContext, path: Path) -> ImportSource {
1a4d82fc 2816 ImportSource {
476ff2be
SL
2817 did: if path.def == Def::Err {
2818 None
2819 } else {
2820 Some(register_def(cx, path.def))
2821 },
1a4d82fc 2822 path: path,
1a4d82fc
JJ
2823 }
2824}
2825
85aaf69f 2826#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
1a4d82fc
JJ
2827pub struct Macro {
2828 pub source: String,
d9579d0f 2829 pub imported_from: Option<String>,
1a4d82fc
JJ
2830}
2831
2832impl Clean<Item> for doctree::Macro {
2833 fn clean(&self, cx: &DocContext) -> Item {
9e0c209e 2834 let name = self.name.clean(cx);
1a4d82fc 2835 Item {
92a42be0 2836 name: Some(name.clone()),
1a4d82fc
JJ
2837 attrs: self.attrs.clean(cx),
2838 source: self.whence.clean(cx),
a7813a04 2839 visibility: Some(Public),
1a4d82fc 2840 stability: self.stab.clean(cx),
9cc50fc6 2841 deprecation: self.depr.clean(cx),
32a655c1 2842 def_id: self.def_id,
1a4d82fc 2843 inner: MacroItem(Macro {
92a42be0 2844 source: format!("macro_rules! {} {{\n{}}}",
9e0c209e
SL
2845 name,
2846 self.matchers.iter().map(|span| {
2847 format!(" {} => {{ ... }};\n", span.to_src(cx))
2848 }).collect::<String>()),
d9579d0f 2849 imported_from: self.imported_from.clean(cx),
1a4d82fc
JJ
2850 }),
2851 }
2852 }
2853}
2854
85aaf69f 2855#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
1a4d82fc 2856pub struct Stability {
b039eaaf 2857 pub level: stability::StabilityLevel,
85aaf69f
SL
2858 pub feature: String,
2859 pub since: String,
2860 pub deprecated_since: String,
476ff2be
SL
2861 pub deprecated_reason: String,
2862 pub unstable_reason: String,
e9174d1e 2863 pub issue: Option<u32>
1a4d82fc
JJ
2864}
2865
9cc50fc6
SL
2866#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
2867pub struct Deprecation {
2868 pub since: String,
2869 pub note: String,
2870}
2871
1a4d82fc
JJ
2872impl Clean<Stability> for attr::Stability {
2873 fn clean(&self, _: &DocContext) -> Stability {
2874 Stability {
b039eaaf 2875 level: stability::StabilityLevel::from_attr_level(&self.level),
85aaf69f 2876 feature: self.feature.to_string(),
b039eaaf
SL
2877 since: match self.level {
2878 attr::Stable {ref since} => since.to_string(),
2879 _ => "".to_string(),
2880 },
9cc50fc6
SL
2881 deprecated_since: match self.rustc_depr {
2882 Some(attr::RustcDeprecation {ref since, ..}) => since.to_string(),
b039eaaf
SL
2883 _=> "".to_string(),
2884 },
476ff2be
SL
2885 deprecated_reason: match self.rustc_depr {
2886 Some(ref depr) => depr.reason.to_string(),
2887 _ => "".to_string(),
2888 },
2889 unstable_reason: match self.level {
2890 attr::Unstable { reason: Some(ref reason), .. } => reason.to_string(),
2891 _ => "".to_string(),
b039eaaf
SL
2892 },
2893 issue: match self.level {
2894 attr::Unstable {issue, ..} => Some(issue),
2895 _ => None,
2896 }
1a4d82fc
JJ
2897 }
2898 }
2899}
2900
62682a34 2901impl<'a> Clean<Stability> for &'a attr::Stability {
b039eaaf
SL
2902 fn clean(&self, dc: &DocContext) -> Stability {
2903 (**self).clean(dc)
62682a34
SL
2904 }
2905}
2906
9cc50fc6
SL
2907impl Clean<Deprecation> for attr::Deprecation {
2908 fn clean(&self, _: &DocContext) -> Deprecation {
2909 Deprecation {
2910 since: self.since.as_ref().map_or("".to_string(), |s| s.to_string()),
2911 note: self.note.as_ref().map_or("".to_string(), |s| s.to_string()),
2912 }
2913 }
2914}
2915
1a4d82fc 2916/// An equality constraint on an associated type, e.g. `A=Bar` in `Foo<A=Bar>`
85aaf69f 2917#[derive(Clone, PartialEq, RustcDecodable, RustcEncodable, Debug)]
1a4d82fc
JJ
2918pub struct TypeBinding {
2919 pub name: String,
2920 pub ty: Type
2921}
2922
e9174d1e 2923impl Clean<TypeBinding> for hir::TypeBinding {
1a4d82fc
JJ
2924 fn clean(&self, cx: &DocContext) -> TypeBinding {
2925 TypeBinding {
b039eaaf 2926 name: self.name.clean(cx),
1a4d82fc
JJ
2927 ty: self.ty.clean(cx)
2928 }
2929 }
2930}