]> git.proxmox.com Git - rustc.git/blob - src/librustdoc/clean/mod.rs
New upstream version 1.25.0+dfsg1
[rustc.git] / src / librustdoc / clean / mod.rs
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
14 pub use self::Type::*;
15 pub use self::Mutability::*;
16 pub use self::ItemEnum::*;
17 pub use self::TyParamBound::*;
18 pub use self::SelfTy::*;
19 pub use self::FunctionRetTy::*;
20 pub use self::Visibility::*;
21
22 use syntax::abi::Abi;
23 use syntax::ast::{self, AttrStyle};
24 use syntax::attr;
25 use syntax::codemap::Spanned;
26 use syntax::feature_gate::UnstableFeatures;
27 use syntax::ptr::P;
28 use syntax::symbol::keywords;
29 use syntax_pos::{self, DUMMY_SP, Pos, FileName};
30
31 use rustc::middle::const_val::ConstVal;
32 use rustc::middle::privacy::AccessLevels;
33 use rustc::middle::resolve_lifetime as rl;
34 use rustc::middle::lang_items;
35 use rustc::hir::def::{Def, CtorKind};
36 use rustc::hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
37 use rustc::ty::subst::Substs;
38 use rustc::ty::{self, Ty, AdtKind};
39 use rustc::middle::stability;
40 use rustc::util::nodemap::{FxHashMap, FxHashSet};
41 use rustc_typeck::hir_ty_to_ty;
42
43 use rustc::hir;
44
45 use rustc_const_math::ConstInt;
46 use std::default::Default;
47 use std::{mem, slice, vec};
48 use std::iter::FromIterator;
49 use std::rc::Rc;
50 use std::sync::Arc;
51 use std::u32;
52
53 use core::DocContext;
54 use doctree;
55 use visit_ast;
56 use html::item_type::ItemType;
57 use html::markdown::markdown_links;
58
59 pub mod inline;
60 pub mod cfg;
61 mod simplify;
62
63 use self::cfg::Cfg;
64
65 // extract the stability index for a node from tcx, if possible
66 fn get_stability(cx: &DocContext, def_id: DefId) -> Option<Stability> {
67 cx.tcx.lookup_stability(def_id).clean(cx)
68 }
69
70 fn get_deprecation(cx: &DocContext, def_id: DefId) -> Option<Deprecation> {
71 cx.tcx.lookup_deprecation(def_id).clean(cx)
72 }
73
74 pub trait Clean<T> {
75 fn clean(&self, cx: &DocContext) -> T;
76 }
77
78 impl<T: Clean<U>, U> Clean<Vec<U>> for [T] {
79 fn clean(&self, cx: &DocContext) -> Vec<U> {
80 self.iter().map(|x| x.clean(cx)).collect()
81 }
82 }
83
84 impl<T: Clean<U>, U> Clean<U> for P<T> {
85 fn clean(&self, cx: &DocContext) -> U {
86 (**self).clean(cx)
87 }
88 }
89
90 impl<T: Clean<U>, U> Clean<U> for Rc<T> {
91 fn clean(&self, cx: &DocContext) -> U {
92 (**self).clean(cx)
93 }
94 }
95
96 impl<T: Clean<U>, U> Clean<Option<U>> for Option<T> {
97 fn clean(&self, cx: &DocContext) -> Option<U> {
98 self.as_ref().map(|v| v.clean(cx))
99 }
100 }
101
102 impl<T, U> Clean<U> for ty::Binder<T> where T: Clean<U> {
103 fn clean(&self, cx: &DocContext) -> U {
104 self.0.clean(cx)
105 }
106 }
107
108 impl<T: Clean<U>, U> Clean<Vec<U>> for P<[T]> {
109 fn clean(&self, cx: &DocContext) -> Vec<U> {
110 self.iter().map(|x| x.clean(cx)).collect()
111 }
112 }
113
114 #[derive(Clone, Debug)]
115 pub struct Crate {
116 pub name: String,
117 pub version: Option<String>,
118 pub src: FileName,
119 pub module: Option<Item>,
120 pub externs: Vec<(CrateNum, ExternalCrate)>,
121 pub primitives: Vec<(DefId, PrimitiveType, Attributes)>,
122 pub access_levels: Arc<AccessLevels<DefId>>,
123 // These are later on moved into `CACHEKEY`, leaving the map empty.
124 // Only here so that they can be filtered through the rustdoc passes.
125 pub external_traits: FxHashMap<DefId, Trait>,
126 pub masked_crates: FxHashSet<CrateNum>,
127 }
128
129 impl<'a, 'tcx, 'rcx> Clean<Crate> for visit_ast::RustdocVisitor<'a, 'tcx, 'rcx> {
130 fn clean(&self, cx: &DocContext) -> Crate {
131 use ::visit_lib::LibEmbargoVisitor;
132
133 {
134 let mut r = cx.renderinfo.borrow_mut();
135 r.deref_trait_did = cx.tcx.lang_items().deref_trait();
136 r.deref_mut_trait_did = cx.tcx.lang_items().deref_mut_trait();
137 r.owned_box_did = cx.tcx.lang_items().owned_box();
138 }
139
140 let mut externs = Vec::new();
141 for &cnum in cx.tcx.crates().iter() {
142 externs.push((cnum, cnum.clean(cx)));
143 // Analyze doc-reachability for extern items
144 LibEmbargoVisitor::new(cx).visit_lib(cnum);
145 }
146 externs.sort_by(|&(a, _), &(b, _)| a.cmp(&b));
147
148 // Clean the crate, translating the entire libsyntax AST to one that is
149 // understood by rustdoc.
150 let mut module = self.module.clean(cx);
151 let mut masked_crates = FxHashSet();
152
153 match module.inner {
154 ModuleItem(ref module) => {
155 for it in &module.items {
156 if it.is_extern_crate() && it.attrs.has_doc_flag("masked") {
157 masked_crates.insert(it.def_id.krate);
158 }
159 }
160 }
161 _ => unreachable!(),
162 }
163
164 let ExternalCrate { name, src, primitives, .. } = LOCAL_CRATE.clean(cx);
165 {
166 let m = match module.inner {
167 ModuleItem(ref mut m) => m,
168 _ => unreachable!(),
169 };
170 m.items.extend(primitives.iter().map(|&(def_id, prim, ref attrs)| {
171 Item {
172 source: Span::empty(),
173 name: Some(prim.to_url_str().to_string()),
174 attrs: attrs.clone(),
175 visibility: Some(Public),
176 stability: get_stability(cx, def_id),
177 deprecation: get_deprecation(cx, def_id),
178 def_id,
179 inner: PrimitiveItem(prim),
180 }
181 }));
182 }
183
184 let mut access_levels = cx.access_levels.borrow_mut();
185 let mut external_traits = cx.external_traits.borrow_mut();
186
187 Crate {
188 name,
189 version: None,
190 src,
191 module: Some(module),
192 externs,
193 primitives,
194 access_levels: Arc::new(mem::replace(&mut access_levels, Default::default())),
195 external_traits: mem::replace(&mut external_traits, Default::default()),
196 masked_crates,
197 }
198 }
199 }
200
201 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
202 pub struct ExternalCrate {
203 pub name: String,
204 pub src: FileName,
205 pub attrs: Attributes,
206 pub primitives: Vec<(DefId, PrimitiveType, Attributes)>,
207 }
208
209 impl Clean<ExternalCrate> for CrateNum {
210 fn clean(&self, cx: &DocContext) -> ExternalCrate {
211 let root = DefId { krate: *self, index: CRATE_DEF_INDEX };
212 let krate_span = cx.tcx.def_span(root);
213 let krate_src = cx.sess().codemap().span_to_filename(krate_span);
214
215 // Collect all inner modules which are tagged as implementations of
216 // primitives.
217 //
218 // Note that this loop only searches the top-level items of the crate,
219 // and this is intentional. If we were to search the entire crate for an
220 // item tagged with `#[doc(primitive)]` then we would also have to
221 // search the entirety of external modules for items tagged
222 // `#[doc(primitive)]`, which is a pretty inefficient process (decoding
223 // all that metadata unconditionally).
224 //
225 // In order to keep the metadata load under control, the
226 // `#[doc(primitive)]` feature is explicitly designed to only allow the
227 // primitive tags to show up as the top level items in a crate.
228 //
229 // Also note that this does not attempt to deal with modules tagged
230 // duplicately for the same primitive. This is handled later on when
231 // rendering by delegating everything to a hash map.
232 let as_primitive = |def: Def| {
233 if let Def::Mod(def_id) = def {
234 let attrs = cx.tcx.get_attrs(def_id).clean(cx);
235 let mut prim = None;
236 for attr in attrs.lists("doc") {
237 if let Some(v) = attr.value_str() {
238 if attr.check_name("primitive") {
239 prim = PrimitiveType::from_str(&v.as_str());
240 if prim.is_some() {
241 break;
242 }
243 // FIXME: should warn on unknown primitives?
244 }
245 }
246 }
247 return prim.map(|p| (def_id, p, attrs));
248 }
249 None
250 };
251 let primitives = if root.is_local() {
252 cx.tcx.hir.krate().module.item_ids.iter().filter_map(|&id| {
253 let item = cx.tcx.hir.expect_item(id.id);
254 match item.node {
255 hir::ItemMod(_) => {
256 as_primitive(Def::Mod(cx.tcx.hir.local_def_id(id.id)))
257 }
258 hir::ItemUse(ref path, hir::UseKind::Single)
259 if item.vis == hir::Visibility::Public => {
260 as_primitive(path.def).map(|(_, prim, attrs)| {
261 // Pretend the primitive is local.
262 (cx.tcx.hir.local_def_id(id.id), prim, attrs)
263 })
264 }
265 _ => None
266 }
267 }).collect()
268 } else {
269 cx.tcx.item_children(root).iter().map(|item| item.def)
270 .filter_map(as_primitive).collect()
271 };
272
273 ExternalCrate {
274 name: cx.tcx.crate_name(*self).to_string(),
275 src: krate_src,
276 attrs: cx.tcx.get_attrs(root).clean(cx),
277 primitives,
278 }
279 }
280 }
281
282 /// Anything with a source location and set of attributes and, optionally, a
283 /// name. That is, anything that can be documented. This doesn't correspond
284 /// directly to the AST's concept of an item; it's a strict superset.
285 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
286 pub struct Item {
287 /// Stringified span
288 pub source: Span,
289 /// Not everything has a name. E.g., impls
290 pub name: Option<String>,
291 pub attrs: Attributes,
292 pub inner: ItemEnum,
293 pub visibility: Option<Visibility>,
294 pub def_id: DefId,
295 pub stability: Option<Stability>,
296 pub deprecation: Option<Deprecation>,
297 }
298
299 impl Item {
300 /// Finds the `doc` attribute as a NameValue and returns the corresponding
301 /// value found.
302 pub fn doc_value<'a>(&'a self) -> Option<&'a str> {
303 self.attrs.doc_value()
304 }
305 /// Finds all `doc` attributes as NameValues and returns their corresponding values, joined
306 /// with newlines.
307 pub fn collapsed_doc_value(&self) -> Option<String> {
308 self.attrs.collapsed_doc_value()
309 }
310
311 pub fn links(&self) -> Vec<(String, String)> {
312 self.attrs.links()
313 }
314
315 pub fn is_crate(&self) -> bool {
316 match self.inner {
317 StrippedItem(box ModuleItem(Module { is_crate: true, ..})) |
318 ModuleItem(Module { is_crate: true, ..}) => true,
319 _ => false,
320 }
321 }
322 pub fn is_mod(&self) -> bool {
323 self.type_() == ItemType::Module
324 }
325 pub fn is_trait(&self) -> bool {
326 self.type_() == ItemType::Trait
327 }
328 pub fn is_struct(&self) -> bool {
329 self.type_() == ItemType::Struct
330 }
331 pub fn is_enum(&self) -> bool {
332 self.type_() == ItemType::Enum
333 }
334 pub fn is_fn(&self) -> bool {
335 self.type_() == ItemType::Function
336 }
337 pub fn is_associated_type(&self) -> bool {
338 self.type_() == ItemType::AssociatedType
339 }
340 pub fn is_associated_const(&self) -> bool {
341 self.type_() == ItemType::AssociatedConst
342 }
343 pub fn is_method(&self) -> bool {
344 self.type_() == ItemType::Method
345 }
346 pub fn is_ty_method(&self) -> bool {
347 self.type_() == ItemType::TyMethod
348 }
349 pub fn is_typedef(&self) -> bool {
350 self.type_() == ItemType::Typedef
351 }
352 pub fn is_primitive(&self) -> bool {
353 self.type_() == ItemType::Primitive
354 }
355 pub fn is_union(&self) -> bool {
356 self.type_() == ItemType::Union
357 }
358 pub fn is_import(&self) -> bool {
359 self.type_() == ItemType::Import
360 }
361 pub fn is_extern_crate(&self) -> bool {
362 self.type_() == ItemType::ExternCrate
363 }
364
365 pub fn is_stripped(&self) -> bool {
366 match self.inner { StrippedItem(..) => true, _ => false }
367 }
368 pub fn has_stripped_fields(&self) -> Option<bool> {
369 match self.inner {
370 StructItem(ref _struct) => Some(_struct.fields_stripped),
371 UnionItem(ref union) => Some(union.fields_stripped),
372 VariantItem(Variant { kind: VariantKind::Struct(ref vstruct)} ) => {
373 Some(vstruct.fields_stripped)
374 },
375 _ => None,
376 }
377 }
378
379 pub fn stability_class(&self) -> Option<String> {
380 self.stability.as_ref().and_then(|ref s| {
381 let mut classes = Vec::with_capacity(2);
382
383 if s.level == stability::Unstable {
384 classes.push("unstable");
385 }
386
387 if !s.deprecated_since.is_empty() {
388 classes.push("deprecated");
389 }
390
391 if classes.len() != 0 {
392 Some(classes.join(" "))
393 } else {
394 None
395 }
396 })
397 }
398
399 pub fn stable_since(&self) -> Option<&str> {
400 self.stability.as_ref().map(|s| &s.since[..])
401 }
402
403 /// Returns a documentation-level item type from the item.
404 pub fn type_(&self) -> ItemType {
405 ItemType::from(self)
406 }
407 }
408
409 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
410 pub enum ItemEnum {
411 ExternCrateItem(String, Option<String>),
412 ImportItem(Import),
413 StructItem(Struct),
414 UnionItem(Union),
415 EnumItem(Enum),
416 FunctionItem(Function),
417 ModuleItem(Module),
418 TypedefItem(Typedef, bool /* is associated type */),
419 StaticItem(Static),
420 ConstantItem(Constant),
421 TraitItem(Trait),
422 ImplItem(Impl),
423 /// A method signature only. Used for required methods in traits (ie,
424 /// non-default-methods).
425 TyMethodItem(TyMethod),
426 /// A method with a body.
427 MethodItem(Method),
428 StructFieldItem(Type),
429 VariantItem(Variant),
430 /// `fn`s from an extern block
431 ForeignFunctionItem(Function),
432 /// `static`s from an extern block
433 ForeignStaticItem(Static),
434 /// `type`s from an extern block
435 ForeignTypeItem,
436 MacroItem(Macro),
437 PrimitiveItem(PrimitiveType),
438 AssociatedConstItem(Type, Option<String>),
439 AssociatedTypeItem(Vec<TyParamBound>, Option<Type>),
440 /// An item that has been stripped by a rustdoc pass
441 StrippedItem(Box<ItemEnum>),
442 }
443
444 impl ItemEnum {
445 pub fn generics(&self) -> Option<&Generics> {
446 Some(match *self {
447 ItemEnum::StructItem(ref s) => &s.generics,
448 ItemEnum::EnumItem(ref e) => &e.generics,
449 ItemEnum::FunctionItem(ref f) => &f.generics,
450 ItemEnum::TypedefItem(ref t, _) => &t.generics,
451 ItemEnum::TraitItem(ref t) => &t.generics,
452 ItemEnum::ImplItem(ref i) => &i.generics,
453 ItemEnum::TyMethodItem(ref i) => &i.generics,
454 ItemEnum::MethodItem(ref i) => &i.generics,
455 ItemEnum::ForeignFunctionItem(ref f) => &f.generics,
456 _ => return None,
457 })
458 }
459 }
460
461 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
462 pub struct Module {
463 pub items: Vec<Item>,
464 pub is_crate: bool,
465 }
466
467 impl Clean<Item> for doctree::Module {
468 fn clean(&self, cx: &DocContext) -> Item {
469 let name = if self.name.is_some() {
470 self.name.unwrap().clean(cx)
471 } else {
472 "".to_string()
473 };
474
475 // maintain a stack of mod ids, for doc comment path resolution
476 // but we also need to resolve the module's own docs based on whether its docs were written
477 // inside or outside the module, so check for that
478 let attrs = if self.attrs.iter()
479 .filter(|a| a.check_name("doc"))
480 .next()
481 .map_or(true, |a| a.style == AttrStyle::Inner) {
482 // inner doc comment, use the module's own scope for resolution
483 cx.mod_ids.borrow_mut().push(self.id);
484 self.attrs.clean(cx)
485 } else {
486 // outer doc comment, use its parent's scope
487 let attrs = self.attrs.clean(cx);
488 cx.mod_ids.borrow_mut().push(self.id);
489 attrs
490 };
491
492 let mut items: Vec<Item> = vec![];
493 items.extend(self.extern_crates.iter().map(|x| x.clean(cx)));
494 items.extend(self.imports.iter().flat_map(|x| x.clean(cx)));
495 items.extend(self.structs.iter().map(|x| x.clean(cx)));
496 items.extend(self.unions.iter().map(|x| x.clean(cx)));
497 items.extend(self.enums.iter().map(|x| x.clean(cx)));
498 items.extend(self.fns.iter().map(|x| x.clean(cx)));
499 items.extend(self.foreigns.iter().flat_map(|x| x.clean(cx)));
500 items.extend(self.mods.iter().map(|x| x.clean(cx)));
501 items.extend(self.typedefs.iter().map(|x| x.clean(cx)));
502 items.extend(self.statics.iter().map(|x| x.clean(cx)));
503 items.extend(self.constants.iter().map(|x| x.clean(cx)));
504 items.extend(self.traits.iter().map(|x| x.clean(cx)));
505 items.extend(self.impls.iter().flat_map(|x| x.clean(cx)));
506 items.extend(self.macros.iter().map(|x| x.clean(cx)));
507
508 cx.mod_ids.borrow_mut().pop();
509
510 // determine if we should display the inner contents or
511 // the outer `mod` item for the source code.
512 let whence = {
513 let cm = cx.sess().codemap();
514 let outer = cm.lookup_char_pos(self.where_outer.lo());
515 let inner = cm.lookup_char_pos(self.where_inner.lo());
516 if outer.file.start_pos == inner.file.start_pos {
517 // mod foo { ... }
518 self.where_outer
519 } else {
520 // mod foo; (and a separate FileMap for the contents)
521 self.where_inner
522 }
523 };
524
525 Item {
526 name: Some(name),
527 attrs,
528 source: whence.clean(cx),
529 visibility: self.vis.clean(cx),
530 stability: self.stab.clean(cx),
531 deprecation: self.depr.clean(cx),
532 def_id: cx.tcx.hir.local_def_id(self.id),
533 inner: ModuleItem(Module {
534 is_crate: self.is_crate,
535 items,
536 })
537 }
538 }
539 }
540
541 pub struct ListAttributesIter<'a> {
542 attrs: slice::Iter<'a, ast::Attribute>,
543 current_list: vec::IntoIter<ast::NestedMetaItem>,
544 name: &'a str
545 }
546
547 impl<'a> Iterator for ListAttributesIter<'a> {
548 type Item = ast::NestedMetaItem;
549
550 fn next(&mut self) -> Option<Self::Item> {
551 if let Some(nested) = self.current_list.next() {
552 return Some(nested);
553 }
554
555 for attr in &mut self.attrs {
556 if let Some(list) = attr.meta_item_list() {
557 if attr.check_name(self.name) {
558 self.current_list = list.into_iter();
559 if let Some(nested) = self.current_list.next() {
560 return Some(nested);
561 }
562 }
563 }
564 }
565
566 None
567 }
568 }
569
570 pub trait AttributesExt {
571 /// Finds an attribute as List and returns the list of attributes nested inside.
572 fn lists<'a>(&'a self, name: &'a str) -> ListAttributesIter<'a>;
573 }
574
575 impl AttributesExt for [ast::Attribute] {
576 fn lists<'a>(&'a self, name: &'a str) -> ListAttributesIter<'a> {
577 ListAttributesIter {
578 attrs: self.iter(),
579 current_list: Vec::new().into_iter(),
580 name,
581 }
582 }
583 }
584
585 pub trait NestedAttributesExt {
586 /// Returns whether the attribute list contains a specific `Word`
587 fn has_word(self, word: &str) -> bool;
588 }
589
590 impl<I: IntoIterator<Item=ast::NestedMetaItem>> NestedAttributesExt for I {
591 fn has_word(self, word: &str) -> bool {
592 self.into_iter().any(|attr| attr.is_word() && attr.check_name(word))
593 }
594 }
595
596 /// A portion of documentation, extracted from a `#[doc]` attribute.
597 ///
598 /// Each variant contains the line number within the complete doc-comment where the fragment
599 /// starts, as well as the Span where the corresponding doc comment or attribute is located.
600 ///
601 /// Included files are kept separate from inline doc comments so that proper line-number
602 /// information can be given when a doctest fails. Sugared doc comments and "raw" doc comments are
603 /// kept separate because of issue #42760.
604 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
605 pub enum DocFragment {
606 // FIXME #44229 (misdreavus): sugared and raw doc comments can be brought back together once
607 // hoedown is completely removed from rustdoc.
608 /// A doc fragment created from a `///` or `//!` doc comment.
609 SugaredDoc(usize, syntax_pos::Span, String),
610 /// A doc fragment created from a "raw" `#[doc=""]` attribute.
611 RawDoc(usize, syntax_pos::Span, String),
612 /// A doc fragment created from a `#[doc(include="filename")]` attribute. Contains both the
613 /// given filename and the file contents.
614 Include(usize, syntax_pos::Span, String, String),
615 }
616
617 impl DocFragment {
618 pub fn as_str(&self) -> &str {
619 match *self {
620 DocFragment::SugaredDoc(_, _, ref s) => &s[..],
621 DocFragment::RawDoc(_, _, ref s) => &s[..],
622 DocFragment::Include(_, _, _, ref s) => &s[..],
623 }
624 }
625
626 pub fn span(&self) -> syntax_pos::Span {
627 match *self {
628 DocFragment::SugaredDoc(_, span, _) |
629 DocFragment::RawDoc(_, span, _) |
630 DocFragment::Include(_, span, _, _) => span,
631 }
632 }
633 }
634
635 impl<'a> FromIterator<&'a DocFragment> for String {
636 fn from_iter<T>(iter: T) -> Self
637 where
638 T: IntoIterator<Item = &'a DocFragment>
639 {
640 iter.into_iter().fold(String::new(), |mut acc, frag| {
641 if !acc.is_empty() {
642 acc.push('\n');
643 }
644 match *frag {
645 DocFragment::SugaredDoc(_, _, ref docs)
646 | DocFragment::RawDoc(_, _, ref docs)
647 | DocFragment::Include(_, _, _, ref docs) =>
648 acc.push_str(docs),
649 }
650
651 acc
652 })
653 }
654 }
655
656 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug, Default)]
657 pub struct Attributes {
658 pub doc_strings: Vec<DocFragment>,
659 pub other_attrs: Vec<ast::Attribute>,
660 pub cfg: Option<Rc<Cfg>>,
661 pub span: Option<syntax_pos::Span>,
662 /// map from Rust paths to resolved defs and potential URL fragments
663 pub links: Vec<(String, DefId, Option<String>)>,
664 }
665
666 impl Attributes {
667 /// Extracts the content from an attribute `#[doc(cfg(content))]`.
668 fn extract_cfg(mi: &ast::MetaItem) -> Option<&ast::MetaItem> {
669 use syntax::ast::NestedMetaItemKind::MetaItem;
670
671 if let ast::MetaItemKind::List(ref nmis) = mi.node {
672 if nmis.len() == 1 {
673 if let MetaItem(ref cfg_mi) = nmis[0].node {
674 if cfg_mi.check_name("cfg") {
675 if let ast::MetaItemKind::List(ref cfg_nmis) = cfg_mi.node {
676 if cfg_nmis.len() == 1 {
677 if let MetaItem(ref content_mi) = cfg_nmis[0].node {
678 return Some(content_mi);
679 }
680 }
681 }
682 }
683 }
684 }
685 }
686
687 None
688 }
689
690 /// Reads a `MetaItem` from within an attribute, looks for whether it is a
691 /// `#[doc(include="file")]`, and returns the filename and contents of the file as loaded from
692 /// its expansion.
693 fn extract_include(mi: &ast::MetaItem)
694 -> Option<(String, String)>
695 {
696 mi.meta_item_list().and_then(|list| {
697 for meta in list {
698 if meta.check_name("include") {
699 // the actual compiled `#[doc(include="filename")]` gets expanded to
700 // `#[doc(include(file="filename", contents="file contents")]` so we need to
701 // look for that instead
702 return meta.meta_item_list().and_then(|list| {
703 let mut filename: Option<String> = None;
704 let mut contents: Option<String> = None;
705
706 for it in list {
707 if it.check_name("file") {
708 if let Some(name) = it.value_str() {
709 filename = Some(name.to_string());
710 }
711 } else if it.check_name("contents") {
712 if let Some(docs) = it.value_str() {
713 contents = Some(docs.to_string());
714 }
715 }
716 }
717
718 if let (Some(filename), Some(contents)) = (filename, contents) {
719 Some((filename, contents))
720 } else {
721 None
722 }
723 });
724 }
725 }
726
727 None
728 })
729 }
730
731 pub fn has_doc_flag(&self, flag: &str) -> bool {
732 for attr in &self.other_attrs {
733 if !attr.check_name("doc") { continue; }
734
735 if let Some(items) = attr.meta_item_list() {
736 if items.iter().filter_map(|i| i.meta_item()).any(|it| it.check_name(flag)) {
737 return true;
738 }
739 }
740 }
741
742 false
743 }
744
745 pub fn from_ast(diagnostic: &::errors::Handler,
746 attrs: &[ast::Attribute]) -> Attributes {
747 let mut doc_strings = vec![];
748 let mut sp = None;
749 let mut cfg = Cfg::True;
750 let mut doc_line = 0;
751
752 let other_attrs = attrs.iter().filter_map(|attr| {
753 attr.with_desugared_doc(|attr| {
754 if attr.check_name("doc") {
755 if let Some(mi) = attr.meta() {
756 if let Some(value) = mi.value_str() {
757 // Extracted #[doc = "..."]
758 let value = value.to_string();
759 let line = doc_line;
760 doc_line += value.lines().count();
761
762 if attr.is_sugared_doc {
763 doc_strings.push(DocFragment::SugaredDoc(line, attr.span, value));
764 } else {
765 doc_strings.push(DocFragment::RawDoc(line, attr.span, value));
766 }
767
768 if sp.is_none() {
769 sp = Some(attr.span);
770 }
771 return None;
772 } else if let Some(cfg_mi) = Attributes::extract_cfg(&mi) {
773 // Extracted #[doc(cfg(...))]
774 match Cfg::parse(cfg_mi) {
775 Ok(new_cfg) => cfg &= new_cfg,
776 Err(e) => diagnostic.span_err(e.span, e.msg),
777 }
778 return None;
779 } else if let Some((filename, contents)) = Attributes::extract_include(&mi)
780 {
781 let line = doc_line;
782 doc_line += contents.lines().count();
783 doc_strings.push(DocFragment::Include(line,
784 attr.span,
785 filename,
786 contents));
787 }
788 }
789 }
790 Some(attr.clone())
791 })
792 }).collect();
793
794 Attributes {
795 doc_strings,
796 other_attrs,
797 cfg: if cfg == Cfg::True { None } else { Some(Rc::new(cfg)) },
798 span: sp,
799 links: vec![],
800 }
801 }
802
803 /// Finds the `doc` attribute as a NameValue and returns the corresponding
804 /// value found.
805 pub fn doc_value<'a>(&'a self) -> Option<&'a str> {
806 self.doc_strings.first().map(|s| s.as_str())
807 }
808
809 /// Finds all `doc` attributes as NameValues and returns their corresponding values, joined
810 /// with newlines.
811 pub fn collapsed_doc_value(&self) -> Option<String> {
812 if !self.doc_strings.is_empty() {
813 Some(self.doc_strings.iter().collect())
814 } else {
815 None
816 }
817 }
818
819 /// Get links as a vector
820 ///
821 /// Cache must be populated before call
822 pub fn links(&self) -> Vec<(String, String)> {
823 use html::format::href;
824 self.links.iter().filter_map(|&(ref s, did, ref fragment)| {
825 if let Some((mut href, ..)) = href(did) {
826 if let Some(ref fragment) = *fragment {
827 href.push_str("#");
828 href.push_str(fragment);
829 }
830 Some((s.clone(), href))
831 } else {
832 None
833 }
834 }).collect()
835 }
836 }
837
838 impl AttributesExt for Attributes {
839 fn lists<'a>(&'a self, name: &'a str) -> ListAttributesIter<'a> {
840 self.other_attrs.lists(name)
841 }
842 }
843
844 /// Given a def, returns its name and disambiguator
845 /// for a value namespace
846 ///
847 /// Returns None for things which cannot be ambiguous since
848 /// they exist in both namespaces (structs and modules)
849 fn value_ns_kind(def: Def, path_str: &str) -> Option<(&'static str, String)> {
850 match def {
851 // structs, variants, and mods exist in both namespaces. skip them
852 Def::StructCtor(..) | Def::Mod(..) | Def::Variant(..) | Def::VariantCtor(..) => None,
853 Def::Fn(..)
854 => Some(("function", format!("{}()", path_str))),
855 Def::Method(..)
856 => Some(("method", format!("{}()", path_str))),
857 Def::Const(..)
858 => Some(("const", format!("const@{}", path_str))),
859 Def::Static(..)
860 => Some(("static", format!("static@{}", path_str))),
861 _ => Some(("value", format!("value@{}", path_str))),
862 }
863 }
864
865 /// Given a def, returns its name, the article to be used, and a disambiguator
866 /// for the type namespace
867 fn type_ns_kind(def: Def, path_str: &str) -> (&'static str, &'static str, String) {
868 let (kind, article) = match def {
869 // we can still have non-tuple structs
870 Def::Struct(..) => ("struct", "a"),
871 Def::Enum(..) => ("enum", "an"),
872 Def::Trait(..) => ("trait", "a"),
873 Def::Union(..) => ("union", "a"),
874 _ => ("type", "a"),
875 };
876 (kind, article, format!("{}@{}", kind, path_str))
877 }
878
879 fn ambiguity_error(cx: &DocContext, attrs: &Attributes,
880 path_str: &str,
881 article1: &str, kind1: &str, disambig1: &str,
882 article2: &str, kind2: &str, disambig2: &str) {
883 let sp = attrs.doc_strings.first()
884 .map_or(DUMMY_SP, |a| a.span());
885 cx.sess()
886 .struct_span_warn(sp,
887 &format!("`{}` is both {} {} and {} {}",
888 path_str, article1, kind1,
889 article2, kind2))
890 .help(&format!("try `{}` if you want to select the {}, \
891 or `{}` if you want to \
892 select the {}",
893 disambig1, kind1, disambig2,
894 kind2))
895 .emit();
896 }
897
898 /// Given an enum variant's def, return the def of its enum and the associated fragment
899 fn handle_variant(cx: &DocContext, def: Def) -> Result<(Def, Option<String>), ()> {
900 use rustc::ty::DefIdTree;
901
902 let parent = if let Some(parent) = cx.tcx.parent(def.def_id()) {
903 parent
904 } else {
905 return Err(())
906 };
907 let parent_def = Def::Enum(parent);
908 let variant = cx.tcx.expect_variant_def(def);
909 Ok((parent_def, Some(format!("{}.v", variant.name))))
910 }
911
912 /// Resolve a given string as a path, along with whether or not it is
913 /// in the value namespace. Also returns an optional URL fragment in the case
914 /// of variants and methods
915 fn resolve(cx: &DocContext, path_str: &str, is_val: bool) -> Result<(Def, Option<String>), ()> {
916 // In case we're in a module, try to resolve the relative
917 // path
918 if let Some(id) = cx.mod_ids.borrow().last() {
919 let result = cx.resolver.borrow_mut()
920 .with_scope(*id,
921 |resolver| {
922 resolver.resolve_str_path_error(DUMMY_SP,
923 &path_str, is_val)
924 });
925
926 if let Ok(result) = result {
927 // In case this is a trait item, skip the
928 // early return and try looking for the trait
929 let value = match result.def {
930 Def::Method(_) | Def::AssociatedConst(_) => true,
931 Def::AssociatedTy(_) => false,
932 Def::Variant(_) => return handle_variant(cx, result.def),
933 // not a trait item, just return what we found
934 _ => return Ok((result.def, None))
935 };
936
937 if value != is_val {
938 return Err(())
939 }
940 } else {
941 // If resolution failed, it may still be a method
942 // because methods are not handled by the resolver
943 // If so, bail when we're not looking for a value
944 if !is_val {
945 return Err(())
946 }
947 }
948
949 // Try looking for methods and associated items
950 let mut split = path_str.rsplitn(2, "::");
951 let mut item_name = if let Some(first) = split.next() {
952 first
953 } else {
954 return Err(())
955 };
956
957 let mut path = if let Some(second) = split.next() {
958 second
959 } else {
960 return Err(())
961 };
962
963 let ty = cx.resolver.borrow_mut()
964 .with_scope(*id,
965 |resolver| {
966 resolver.resolve_str_path_error(DUMMY_SP,
967 &path, false)
968 })?;
969 match ty.def {
970 Def::Struct(did) | Def::Union(did) | Def::Enum(did) | Def::TyAlias(did) => {
971 let item = cx.tcx.inherent_impls(did).iter()
972 .flat_map(|imp| cx.tcx.associated_items(*imp))
973 .find(|item| item.name == item_name);
974 if let Some(item) = item {
975 if item.kind == ty::AssociatedKind::Method && is_val {
976 Ok((ty.def, Some(format!("method.{}", item_name))))
977 } else {
978 Err(())
979 }
980 } else {
981 Err(())
982 }
983 }
984 Def::Trait(did) => {
985 let item = cx.tcx.associated_item_def_ids(did).iter()
986 .map(|item| cx.tcx.associated_item(*item))
987 .find(|item| item.name == item_name);
988 if let Some(item) = item {
989 let kind = match item.kind {
990 ty::AssociatedKind::Const if is_val => "associatedconstant",
991 ty::AssociatedKind::Type if !is_val => "associatedtype",
992 ty::AssociatedKind::Method if is_val => "tymethod",
993 _ => return Err(())
994 };
995
996 Ok((ty.def, Some(format!("{}.{}", kind, item_name))))
997 } else {
998 Err(())
999 }
1000 }
1001 _ => Err(())
1002 }
1003
1004 } else {
1005 Err(())
1006 }
1007 }
1008
1009 /// Resolve a string as a macro
1010 fn macro_resolve(cx: &DocContext, path_str: &str) -> Option<Def> {
1011 use syntax::ext::base::MacroKind;
1012 use syntax::ext::hygiene::Mark;
1013 let segment = ast::PathSegment {
1014 identifier: ast::Ident::from_str(path_str),
1015 span: DUMMY_SP,
1016 parameters: None,
1017 };
1018 let path = ast::Path {
1019 span: DUMMY_SP,
1020 segments: vec![segment],
1021 };
1022
1023 let mut resolver = cx.resolver.borrow_mut();
1024 let mark = Mark::root();
1025 let res = resolver
1026 .resolve_macro_to_def_inner(mark, &path, MacroKind::Bang, false);
1027 if let Ok(def) = res {
1028 Some(def)
1029 } else if let Some(def) = resolver.all_macros.get(&path_str.into()) {
1030 Some(*def)
1031 } else {
1032 None
1033 }
1034 }
1035
1036 enum PathKind {
1037 /// can be either value or type, not a macro
1038 Unknown,
1039 /// macro
1040 Macro,
1041 /// values, functions, consts, statics, everything in the value namespace
1042 Value,
1043 /// types, traits, everything in the type namespace
1044 Type
1045 }
1046
1047 impl Clean<Attributes> for [ast::Attribute] {
1048 fn clean(&self, cx: &DocContext) -> Attributes {
1049 let mut attrs = Attributes::from_ast(cx.sess().diagnostic(), self);
1050
1051 if UnstableFeatures::from_environment().is_nightly_build() {
1052 let dox = attrs.collapsed_doc_value().unwrap_or_else(String::new);
1053 for link in markdown_links(&dox, cx.render_type) {
1054 // bail early for real links
1055 if link.contains('/') {
1056 continue;
1057 }
1058 let (def, fragment) = {
1059 let mut kind = PathKind::Unknown;
1060 let path_str = if let Some(prefix) =
1061 ["struct@", "enum@", "type@",
1062 "trait@", "union@"].iter()
1063 .find(|p| link.starts_with(**p)) {
1064 kind = PathKind::Type;
1065 link.trim_left_matches(prefix)
1066 } else if let Some(prefix) =
1067 ["const@", "static@",
1068 "value@", "function@", "mod@",
1069 "fn@", "module@", "method@"]
1070 .iter().find(|p| link.starts_with(**p)) {
1071 kind = PathKind::Value;
1072 link.trim_left_matches(prefix)
1073 } else if link.ends_with("()") {
1074 kind = PathKind::Value;
1075 link.trim_right_matches("()")
1076 } else if link.starts_with("macro@") {
1077 kind = PathKind::Macro;
1078 link.trim_left_matches("macro@")
1079 } else if link.ends_with('!') {
1080 kind = PathKind::Macro;
1081 link.trim_right_matches('!')
1082 } else {
1083 &link[..]
1084 }.trim();
1085
1086 // avoid resolving things (i.e. regular links) which aren't like paths
1087 // FIXME(Manishearth) given that most links have slashes in them might be worth
1088 // doing a check for slashes first
1089 if path_str.contains(|ch: char| !(ch.is_alphanumeric() ||
1090 ch == ':' || ch == '_')) {
1091 continue;
1092 }
1093
1094
1095 match kind {
1096 PathKind::Value => {
1097 if let Ok(def) = resolve(cx, path_str, true) {
1098 def
1099 } else {
1100 // this could just be a normal link or a broken link
1101 // we could potentially check if something is
1102 // "intra-doc-link-like" and warn in that case
1103 continue;
1104 }
1105 }
1106 PathKind::Type => {
1107 if let Ok(def) = resolve(cx, path_str, false) {
1108 def
1109 } else {
1110 // this could just be a normal link
1111 continue;
1112 }
1113 }
1114 PathKind::Unknown => {
1115 // try everything!
1116 if let Some(macro_def) = macro_resolve(cx, path_str) {
1117 if let Ok(type_def) = resolve(cx, path_str, false) {
1118 let (type_kind, article, type_disambig)
1119 = type_ns_kind(type_def.0, path_str);
1120 ambiguity_error(cx, &attrs, path_str,
1121 article, type_kind, &type_disambig,
1122 "a", "macro", &format!("macro@{}", path_str));
1123 continue;
1124 } else if let Ok(value_def) = resolve(cx, path_str, true) {
1125 let (value_kind, value_disambig)
1126 = value_ns_kind(value_def.0, path_str)
1127 .expect("struct and mod cases should have been \
1128 caught in previous branch");
1129 ambiguity_error(cx, &attrs, path_str,
1130 "a", value_kind, &value_disambig,
1131 "a", "macro", &format!("macro@{}", path_str));
1132 }
1133 (macro_def, None)
1134 } else if let Ok(type_def) = resolve(cx, path_str, false) {
1135 // It is imperative we search for not-a-value first
1136 // Otherwise we will find struct ctors for when we are looking
1137 // for structs, and the link won't work.
1138 // if there is something in both namespaces
1139 if let Ok(value_def) = resolve(cx, path_str, true) {
1140 let kind = value_ns_kind(value_def.0, path_str);
1141 if let Some((value_kind, value_disambig)) = kind {
1142 let (type_kind, article, type_disambig)
1143 = type_ns_kind(type_def.0, path_str);
1144 ambiguity_error(cx, &attrs, path_str,
1145 article, type_kind, &type_disambig,
1146 "a", value_kind, &value_disambig);
1147 continue;
1148 }
1149 }
1150 type_def
1151 } else if let Ok(value_def) = resolve(cx, path_str, true) {
1152 value_def
1153 } else {
1154 // this could just be a normal link
1155 continue;
1156 }
1157 }
1158 PathKind::Macro => {
1159 if let Some(def) = macro_resolve(cx, path_str) {
1160 (def, None)
1161 } else {
1162 continue
1163 }
1164 }
1165 }
1166 };
1167
1168
1169 let id = register_def(cx, def);
1170 attrs.links.push((link, id, fragment));
1171 }
1172
1173 cx.sess().abort_if_errors();
1174 }
1175
1176 attrs
1177 }
1178 }
1179
1180 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
1181 pub struct TyParam {
1182 pub name: String,
1183 pub did: DefId,
1184 pub bounds: Vec<TyParamBound>,
1185 pub default: Option<Type>,
1186 }
1187
1188 impl Clean<TyParam> for hir::TyParam {
1189 fn clean(&self, cx: &DocContext) -> TyParam {
1190 TyParam {
1191 name: self.name.clean(cx),
1192 did: cx.tcx.hir.local_def_id(self.id),
1193 bounds: self.bounds.clean(cx),
1194 default: self.default.clean(cx),
1195 }
1196 }
1197 }
1198
1199 impl<'tcx> Clean<TyParam> for ty::TypeParameterDef {
1200 fn clean(&self, cx: &DocContext) -> TyParam {
1201 cx.renderinfo.borrow_mut().external_typarams.insert(self.def_id, self.name.clean(cx));
1202 TyParam {
1203 name: self.name.clean(cx),
1204 did: self.def_id,
1205 bounds: vec![], // these are filled in from the where-clauses
1206 default: if self.has_default {
1207 Some(cx.tcx.type_of(self.def_id).clean(cx))
1208 } else {
1209 None
1210 }
1211 }
1212 }
1213 }
1214
1215 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
1216 pub enum TyParamBound {
1217 RegionBound(Lifetime),
1218 TraitBound(PolyTrait, hir::TraitBoundModifier)
1219 }
1220
1221 impl TyParamBound {
1222 fn maybe_sized(cx: &DocContext) -> TyParamBound {
1223 let did = cx.tcx.require_lang_item(lang_items::SizedTraitLangItem);
1224 let empty = cx.tcx.intern_substs(&[]);
1225 let path = external_path(cx, &cx.tcx.item_name(did),
1226 Some(did), false, vec![], empty);
1227 inline::record_extern_fqn(cx, did, TypeKind::Trait);
1228 TraitBound(PolyTrait {
1229 trait_: ResolvedPath {
1230 path,
1231 typarams: None,
1232 did,
1233 is_generic: false,
1234 },
1235 generic_params: Vec::new(),
1236 }, hir::TraitBoundModifier::Maybe)
1237 }
1238
1239 fn is_sized_bound(&self, cx: &DocContext) -> bool {
1240 use rustc::hir::TraitBoundModifier as TBM;
1241 if let TyParamBound::TraitBound(PolyTrait { ref trait_, .. }, TBM::None) = *self {
1242 if trait_.def_id() == cx.tcx.lang_items().sized_trait() {
1243 return true;
1244 }
1245 }
1246 false
1247 }
1248 }
1249
1250 impl Clean<TyParamBound> for hir::TyParamBound {
1251 fn clean(&self, cx: &DocContext) -> TyParamBound {
1252 match *self {
1253 hir::RegionTyParamBound(lt) => RegionBound(lt.clean(cx)),
1254 hir::TraitTyParamBound(ref t, modifier) => TraitBound(t.clean(cx), modifier),
1255 }
1256 }
1257 }
1258
1259 fn external_path_params(cx: &DocContext, trait_did: Option<DefId>, has_self: bool,
1260 bindings: Vec<TypeBinding>, substs: &Substs) -> PathParameters {
1261 let lifetimes = substs.regions().filter_map(|v| v.clean(cx)).collect();
1262 let types = substs.types().skip(has_self as usize).collect::<Vec<_>>();
1263
1264 match trait_did {
1265 // Attempt to sugar an external path like Fn<(A, B,), C> to Fn(A, B) -> C
1266 Some(did) if cx.tcx.lang_items().fn_trait_kind(did).is_some() => {
1267 assert_eq!(types.len(), 1);
1268 let inputs = match types[0].sty {
1269 ty::TyTuple(ref tys, _) => tys.iter().map(|t| t.clean(cx)).collect(),
1270 _ => {
1271 return PathParameters::AngleBracketed {
1272 lifetimes,
1273 types: types.clean(cx),
1274 bindings,
1275 }
1276 }
1277 };
1278 let output = None;
1279 // FIXME(#20299) return type comes from a projection now
1280 // match types[1].sty {
1281 // ty::TyTuple(ref v, _) if v.is_empty() => None, // -> ()
1282 // _ => Some(types[1].clean(cx))
1283 // };
1284 PathParameters::Parenthesized {
1285 inputs,
1286 output,
1287 }
1288 },
1289 _ => {
1290 PathParameters::AngleBracketed {
1291 lifetimes,
1292 types: types.clean(cx),
1293 bindings,
1294 }
1295 }
1296 }
1297 }
1298
1299 // trait_did should be set to a trait's DefId if called on a TraitRef, in order to sugar
1300 // from Fn<(A, B,), C> to Fn(A, B) -> C
1301 fn external_path(cx: &DocContext, name: &str, trait_did: Option<DefId>, has_self: bool,
1302 bindings: Vec<TypeBinding>, substs: &Substs) -> Path {
1303 Path {
1304 global: false,
1305 def: Def::Err,
1306 segments: vec![PathSegment {
1307 name: name.to_string(),
1308 params: external_path_params(cx, trait_did, has_self, bindings, substs)
1309 }],
1310 }
1311 }
1312
1313 impl<'tcx> Clean<TyParamBound> for ty::TraitRef<'tcx> {
1314 fn clean(&self, cx: &DocContext) -> TyParamBound {
1315 inline::record_extern_fqn(cx, self.def_id, TypeKind::Trait);
1316 let path = external_path(cx, &cx.tcx.item_name(self.def_id),
1317 Some(self.def_id), true, vec![], self.substs);
1318
1319 debug!("ty::TraitRef\n subst: {:?}\n", self.substs);
1320
1321 // collect any late bound regions
1322 let mut late_bounds = vec![];
1323 for ty_s in self.input_types().skip(1) {
1324 if let ty::TyTuple(ts, _) = ty_s.sty {
1325 for &ty_s in ts {
1326 if let ty::TyRef(ref reg, _) = ty_s.sty {
1327 if let &ty::RegionKind::ReLateBound(..) = *reg {
1328 debug!(" hit an ReLateBound {:?}", reg);
1329 if let Some(lt) = reg.clean(cx) {
1330 late_bounds.push(GenericParam::Lifetime(lt));
1331 }
1332 }
1333 }
1334 }
1335 }
1336 }
1337
1338 TraitBound(
1339 PolyTrait {
1340 trait_: ResolvedPath {
1341 path,
1342 typarams: None,
1343 did: self.def_id,
1344 is_generic: false,
1345 },
1346 generic_params: late_bounds,
1347 },
1348 hir::TraitBoundModifier::None
1349 )
1350 }
1351 }
1352
1353 impl<'tcx> Clean<Option<Vec<TyParamBound>>> for Substs<'tcx> {
1354 fn clean(&self, cx: &DocContext) -> Option<Vec<TyParamBound>> {
1355 let mut v = Vec::new();
1356 v.extend(self.regions().filter_map(|r| r.clean(cx))
1357 .map(RegionBound));
1358 v.extend(self.types().map(|t| TraitBound(PolyTrait {
1359 trait_: t.clean(cx),
1360 generic_params: Vec::new(),
1361 }, hir::TraitBoundModifier::None)));
1362 if !v.is_empty() {Some(v)} else {None}
1363 }
1364 }
1365
1366 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
1367 pub struct Lifetime(String);
1368
1369 impl Lifetime {
1370 pub fn get_ref<'a>(&'a self) -> &'a str {
1371 let Lifetime(ref s) = *self;
1372 let s: &'a str = s;
1373 s
1374 }
1375
1376 pub fn statik() -> Lifetime {
1377 Lifetime("'static".to_string())
1378 }
1379 }
1380
1381 impl Clean<Lifetime> for hir::Lifetime {
1382 fn clean(&self, cx: &DocContext) -> Lifetime {
1383 let hir_id = cx.tcx.hir.node_to_hir_id(self.id);
1384 let def = cx.tcx.named_region(hir_id);
1385 match def {
1386 Some(rl::Region::EarlyBound(_, node_id, _)) |
1387 Some(rl::Region::LateBound(_, node_id, _)) |
1388 Some(rl::Region::Free(_, node_id)) => {
1389 if let Some(lt) = cx.lt_substs.borrow().get(&node_id).cloned() {
1390 return lt;
1391 }
1392 }
1393 _ => {}
1394 }
1395 Lifetime(self.name.name().to_string())
1396 }
1397 }
1398
1399 impl Clean<Lifetime> for hir::LifetimeDef {
1400 fn clean(&self, _: &DocContext) -> Lifetime {
1401 if self.bounds.len() > 0 {
1402 let mut s = format!("{}: {}",
1403 self.lifetime.name.name(),
1404 self.bounds[0].name.name());
1405 for bound in self.bounds.iter().skip(1) {
1406 s.push_str(&format!(" + {}", bound.name.name()));
1407 }
1408 Lifetime(s)
1409 } else {
1410 Lifetime(self.lifetime.name.name().to_string())
1411 }
1412 }
1413 }
1414
1415 impl Clean<Lifetime> for ty::RegionParameterDef {
1416 fn clean(&self, _: &DocContext) -> Lifetime {
1417 Lifetime(self.name.to_string())
1418 }
1419 }
1420
1421 impl Clean<Option<Lifetime>> for ty::RegionKind {
1422 fn clean(&self, cx: &DocContext) -> Option<Lifetime> {
1423 match *self {
1424 ty::ReStatic => Some(Lifetime::statik()),
1425 ty::ReLateBound(_, ty::BrNamed(_, name)) => Some(Lifetime(name.to_string())),
1426 ty::ReEarlyBound(ref data) => Some(Lifetime(data.name.clean(cx))),
1427
1428 ty::ReLateBound(..) |
1429 ty::ReFree(..) |
1430 ty::ReScope(..) |
1431 ty::ReVar(..) |
1432 ty::ReSkolemized(..) |
1433 ty::ReEmpty |
1434 ty::ReClosureBound(_) |
1435 ty::ReErased => None
1436 }
1437 }
1438 }
1439
1440 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
1441 pub enum WherePredicate {
1442 BoundPredicate { ty: Type, bounds: Vec<TyParamBound> },
1443 RegionPredicate { lifetime: Lifetime, bounds: Vec<Lifetime>},
1444 EqPredicate { lhs: Type, rhs: Type },
1445 }
1446
1447 impl Clean<WherePredicate> for hir::WherePredicate {
1448 fn clean(&self, cx: &DocContext) -> WherePredicate {
1449 match *self {
1450 hir::WherePredicate::BoundPredicate(ref wbp) => {
1451 WherePredicate::BoundPredicate {
1452 ty: wbp.bounded_ty.clean(cx),
1453 bounds: wbp.bounds.clean(cx)
1454 }
1455 }
1456
1457 hir::WherePredicate::RegionPredicate(ref wrp) => {
1458 WherePredicate::RegionPredicate {
1459 lifetime: wrp.lifetime.clean(cx),
1460 bounds: wrp.bounds.clean(cx)
1461 }
1462 }
1463
1464 hir::WherePredicate::EqPredicate(ref wrp) => {
1465 WherePredicate::EqPredicate {
1466 lhs: wrp.lhs_ty.clean(cx),
1467 rhs: wrp.rhs_ty.clean(cx)
1468 }
1469 }
1470 }
1471 }
1472 }
1473
1474 impl<'a> Clean<WherePredicate> for ty::Predicate<'a> {
1475 fn clean(&self, cx: &DocContext) -> WherePredicate {
1476 use rustc::ty::Predicate;
1477
1478 match *self {
1479 Predicate::Trait(ref pred) => pred.clean(cx),
1480 Predicate::Equate(ref pred) => pred.clean(cx),
1481 Predicate::Subtype(ref pred) => pred.clean(cx),
1482 Predicate::RegionOutlives(ref pred) => pred.clean(cx),
1483 Predicate::TypeOutlives(ref pred) => pred.clean(cx),
1484 Predicate::Projection(ref pred) => pred.clean(cx),
1485 Predicate::WellFormed(_) => panic!("not user writable"),
1486 Predicate::ObjectSafe(_) => panic!("not user writable"),
1487 Predicate::ClosureKind(..) => panic!("not user writable"),
1488 Predicate::ConstEvaluatable(..) => panic!("not user writable"),
1489 }
1490 }
1491 }
1492
1493 impl<'a> Clean<WherePredicate> for ty::TraitPredicate<'a> {
1494 fn clean(&self, cx: &DocContext) -> WherePredicate {
1495 WherePredicate::BoundPredicate {
1496 ty: self.trait_ref.self_ty().clean(cx),
1497 bounds: vec![self.trait_ref.clean(cx)]
1498 }
1499 }
1500 }
1501
1502 impl<'tcx> Clean<WherePredicate> for ty::EquatePredicate<'tcx> {
1503 fn clean(&self, cx: &DocContext) -> WherePredicate {
1504 let ty::EquatePredicate(ref lhs, ref rhs) = *self;
1505 WherePredicate::EqPredicate {
1506 lhs: lhs.clean(cx),
1507 rhs: rhs.clean(cx)
1508 }
1509 }
1510 }
1511
1512 impl<'tcx> Clean<WherePredicate> for ty::SubtypePredicate<'tcx> {
1513 fn clean(&self, _cx: &DocContext) -> WherePredicate {
1514 panic!("subtype predicates are an internal rustc artifact \
1515 and should not be seen by rustdoc")
1516 }
1517 }
1518
1519 impl<'tcx> Clean<WherePredicate> for ty::OutlivesPredicate<ty::Region<'tcx>, ty::Region<'tcx>> {
1520 fn clean(&self, cx: &DocContext) -> WherePredicate {
1521 let ty::OutlivesPredicate(ref a, ref b) = *self;
1522 WherePredicate::RegionPredicate {
1523 lifetime: a.clean(cx).unwrap(),
1524 bounds: vec![b.clean(cx).unwrap()]
1525 }
1526 }
1527 }
1528
1529 impl<'tcx> Clean<WherePredicate> for ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>> {
1530 fn clean(&self, cx: &DocContext) -> WherePredicate {
1531 let ty::OutlivesPredicate(ref ty, ref lt) = *self;
1532
1533 WherePredicate::BoundPredicate {
1534 ty: ty.clean(cx),
1535 bounds: vec![TyParamBound::RegionBound(lt.clean(cx).unwrap())]
1536 }
1537 }
1538 }
1539
1540 impl<'tcx> Clean<WherePredicate> for ty::ProjectionPredicate<'tcx> {
1541 fn clean(&self, cx: &DocContext) -> WherePredicate {
1542 WherePredicate::EqPredicate {
1543 lhs: self.projection_ty.clean(cx),
1544 rhs: self.ty.clean(cx)
1545 }
1546 }
1547 }
1548
1549 impl<'tcx> Clean<Type> for ty::ProjectionTy<'tcx> {
1550 fn clean(&self, cx: &DocContext) -> Type {
1551 let trait_ = match self.trait_ref(cx.tcx).clean(cx) {
1552 TyParamBound::TraitBound(t, _) => t.trait_,
1553 TyParamBound::RegionBound(_) => {
1554 panic!("cleaning a trait got a region")
1555 }
1556 };
1557 Type::QPath {
1558 name: cx.tcx.associated_item(self.item_def_id).name.clean(cx),
1559 self_type: box self.self_ty().clean(cx),
1560 trait_: box trait_
1561 }
1562 }
1563 }
1564
1565 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
1566 pub enum GenericParam {
1567 Lifetime(Lifetime),
1568 Type(TyParam),
1569 }
1570
1571 impl Clean<GenericParam> for hir::GenericParam {
1572 fn clean(&self, cx: &DocContext) -> GenericParam {
1573 match *self {
1574 hir::GenericParam::Lifetime(ref l) => GenericParam::Lifetime(l.clean(cx)),
1575 hir::GenericParam::Type(ref t) => GenericParam::Type(t.clean(cx)),
1576 }
1577 }
1578 }
1579
1580 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug, Default)]
1581 pub struct Generics {
1582 pub params: Vec<GenericParam>,
1583 pub where_predicates: Vec<WherePredicate>,
1584 }
1585
1586 impl Clean<Generics> for hir::Generics {
1587 fn clean(&self, cx: &DocContext) -> Generics {
1588 let mut g = Generics {
1589 params: self.params.clean(cx),
1590 where_predicates: self.where_clause.predicates.clean(cx)
1591 };
1592
1593 // Some duplicates are generated for ?Sized bounds between type params and where
1594 // predicates. The point in here is to move the bounds definitions from type params
1595 // to where predicates when such cases occur.
1596 for where_pred in &mut g.where_predicates {
1597 match *where_pred {
1598 WherePredicate::BoundPredicate { ty: Generic(ref name), ref mut bounds } => {
1599 if bounds.is_empty() {
1600 for param in &mut g.params {
1601 if let GenericParam::Type(ref mut type_param) = *param {
1602 if &type_param.name == name {
1603 mem::swap(bounds, &mut type_param.bounds);
1604 break
1605 }
1606 }
1607 }
1608 }
1609 }
1610 _ => continue,
1611 }
1612 }
1613 g
1614 }
1615 }
1616
1617 impl<'a, 'tcx> Clean<Generics> for (&'a ty::Generics,
1618 &'a ty::GenericPredicates<'tcx>) {
1619 fn clean(&self, cx: &DocContext) -> Generics {
1620 use self::WherePredicate as WP;
1621
1622 let (gens, preds) = *self;
1623
1624 // Bounds in the type_params and lifetimes fields are repeated in the
1625 // predicates field (see rustc_typeck::collect::ty_generics), so remove
1626 // them.
1627 let stripped_typarams = gens.types.iter().filter_map(|tp| {
1628 if tp.name == keywords::SelfType.name() {
1629 assert_eq!(tp.index, 0);
1630 None
1631 } else {
1632 Some(tp.clean(cx))
1633 }
1634 }).collect::<Vec<_>>();
1635
1636 let mut where_predicates = preds.predicates.to_vec().clean(cx);
1637
1638 // Type parameters and have a Sized bound by default unless removed with
1639 // ?Sized. Scan through the predicates and mark any type parameter with
1640 // a Sized bound, removing the bounds as we find them.
1641 //
1642 // Note that associated types also have a sized bound by default, but we
1643 // don't actually know the set of associated types right here so that's
1644 // handled in cleaning associated types
1645 let mut sized_params = FxHashSet();
1646 where_predicates.retain(|pred| {
1647 match *pred {
1648 WP::BoundPredicate { ty: Generic(ref g), ref bounds } => {
1649 if bounds.iter().any(|b| b.is_sized_bound(cx)) {
1650 sized_params.insert(g.clone());
1651 false
1652 } else {
1653 true
1654 }
1655 }
1656 _ => true,
1657 }
1658 });
1659
1660 // Run through the type parameters again and insert a ?Sized
1661 // unbound for any we didn't find to be Sized.
1662 for tp in &stripped_typarams {
1663 if !sized_params.contains(&tp.name) {
1664 where_predicates.push(WP::BoundPredicate {
1665 ty: Type::Generic(tp.name.clone()),
1666 bounds: vec![TyParamBound::maybe_sized(cx)],
1667 })
1668 }
1669 }
1670
1671 // It would be nice to collect all of the bounds on a type and recombine
1672 // them if possible, to avoid e.g. `where T: Foo, T: Bar, T: Sized, T: 'a`
1673 // and instead see `where T: Foo + Bar + Sized + 'a`
1674
1675 Generics {
1676 params: gens.regions
1677 .clean(cx)
1678 .into_iter()
1679 .map(|lp| GenericParam::Lifetime(lp))
1680 .chain(
1681 simplify::ty_params(stripped_typarams)
1682 .into_iter()
1683 .map(|tp| GenericParam::Type(tp))
1684 )
1685 .collect(),
1686 where_predicates: simplify::where_clauses(cx, where_predicates),
1687 }
1688 }
1689 }
1690
1691 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
1692 pub struct Method {
1693 pub generics: Generics,
1694 pub unsafety: hir::Unsafety,
1695 pub constness: hir::Constness,
1696 pub decl: FnDecl,
1697 pub abi: Abi,
1698 }
1699
1700 impl<'a> Clean<Method> for (&'a hir::MethodSig, &'a hir::Generics, hir::BodyId) {
1701 fn clean(&self, cx: &DocContext) -> Method {
1702 Method {
1703 generics: self.1.clean(cx),
1704 unsafety: self.0.unsafety,
1705 constness: self.0.constness,
1706 decl: (&*self.0.decl, self.2).clean(cx),
1707 abi: self.0.abi
1708 }
1709 }
1710 }
1711
1712 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
1713 pub struct TyMethod {
1714 pub unsafety: hir::Unsafety,
1715 pub decl: FnDecl,
1716 pub generics: Generics,
1717 pub abi: Abi,
1718 }
1719
1720 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
1721 pub struct Function {
1722 pub decl: FnDecl,
1723 pub generics: Generics,
1724 pub unsafety: hir::Unsafety,
1725 pub constness: hir::Constness,
1726 pub abi: Abi,
1727 }
1728
1729 impl Clean<Item> for doctree::Function {
1730 fn clean(&self, cx: &DocContext) -> Item {
1731 Item {
1732 name: Some(self.name.clean(cx)),
1733 attrs: self.attrs.clean(cx),
1734 source: self.whence.clean(cx),
1735 visibility: self.vis.clean(cx),
1736 stability: self.stab.clean(cx),
1737 deprecation: self.depr.clean(cx),
1738 def_id: cx.tcx.hir.local_def_id(self.id),
1739 inner: FunctionItem(Function {
1740 decl: (&self.decl, self.body).clean(cx),
1741 generics: self.generics.clean(cx),
1742 unsafety: self.unsafety,
1743 constness: self.constness,
1744 abi: self.abi,
1745 }),
1746 }
1747 }
1748 }
1749
1750 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
1751 pub struct FnDecl {
1752 pub inputs: Arguments,
1753 pub output: FunctionRetTy,
1754 pub variadic: bool,
1755 pub attrs: Attributes,
1756 }
1757
1758 impl FnDecl {
1759 pub fn has_self(&self) -> bool {
1760 self.inputs.values.len() > 0 && self.inputs.values[0].name == "self"
1761 }
1762
1763 pub fn self_type(&self) -> Option<SelfTy> {
1764 self.inputs.values.get(0).and_then(|v| v.to_self())
1765 }
1766 }
1767
1768 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
1769 pub struct Arguments {
1770 pub values: Vec<Argument>,
1771 }
1772
1773 impl<'a> Clean<Arguments> for (&'a [P<hir::Ty>], &'a [Spanned<ast::Name>]) {
1774 fn clean(&self, cx: &DocContext) -> Arguments {
1775 Arguments {
1776 values: self.0.iter().enumerate().map(|(i, ty)| {
1777 let mut name = self.1.get(i).map(|n| n.node.to_string())
1778 .unwrap_or(String::new());
1779 if name.is_empty() {
1780 name = "_".to_string();
1781 }
1782 Argument {
1783 name,
1784 type_: ty.clean(cx),
1785 }
1786 }).collect()
1787 }
1788 }
1789 }
1790
1791 impl<'a> Clean<Arguments> for (&'a [P<hir::Ty>], hir::BodyId) {
1792 fn clean(&self, cx: &DocContext) -> Arguments {
1793 let body = cx.tcx.hir.body(self.1);
1794
1795 Arguments {
1796 values: self.0.iter().enumerate().map(|(i, ty)| {
1797 Argument {
1798 name: name_from_pat(&body.arguments[i].pat),
1799 type_: ty.clean(cx),
1800 }
1801 }).collect()
1802 }
1803 }
1804 }
1805
1806 impl<'a, A: Copy> Clean<FnDecl> for (&'a hir::FnDecl, A)
1807 where (&'a [P<hir::Ty>], A): Clean<Arguments>
1808 {
1809 fn clean(&self, cx: &DocContext) -> FnDecl {
1810 FnDecl {
1811 inputs: (&self.0.inputs[..], self.1).clean(cx),
1812 output: self.0.output.clean(cx),
1813 variadic: self.0.variadic,
1814 attrs: Attributes::default()
1815 }
1816 }
1817 }
1818
1819 impl<'a, 'tcx> Clean<FnDecl> for (DefId, ty::PolyFnSig<'tcx>) {
1820 fn clean(&self, cx: &DocContext) -> FnDecl {
1821 let (did, sig) = *self;
1822 let mut names = if cx.tcx.hir.as_local_node_id(did).is_some() {
1823 vec![].into_iter()
1824 } else {
1825 cx.tcx.fn_arg_names(did).into_iter()
1826 }.peekable();
1827 FnDecl {
1828 output: Return(sig.skip_binder().output().clean(cx)),
1829 attrs: Attributes::default(),
1830 variadic: sig.skip_binder().variadic,
1831 inputs: Arguments {
1832 values: sig.skip_binder().inputs().iter().map(|t| {
1833 Argument {
1834 type_: t.clean(cx),
1835 name: names.next().map_or("".to_string(), |name| name.to_string()),
1836 }
1837 }).collect(),
1838 },
1839 }
1840 }
1841 }
1842
1843 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
1844 pub struct Argument {
1845 pub type_: Type,
1846 pub name: String,
1847 }
1848
1849 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
1850 pub enum SelfTy {
1851 SelfValue,
1852 SelfBorrowed(Option<Lifetime>, Mutability),
1853 SelfExplicit(Type),
1854 }
1855
1856 impl Argument {
1857 pub fn to_self(&self) -> Option<SelfTy> {
1858 if self.name != "self" {
1859 return None;
1860 }
1861 if self.type_.is_self_type() {
1862 return Some(SelfValue);
1863 }
1864 match self.type_ {
1865 BorrowedRef{ref lifetime, mutability, ref type_} if type_.is_self_type() => {
1866 Some(SelfBorrowed(lifetime.clone(), mutability))
1867 }
1868 _ => Some(SelfExplicit(self.type_.clone()))
1869 }
1870 }
1871 }
1872
1873 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
1874 pub enum FunctionRetTy {
1875 Return(Type),
1876 DefaultReturn,
1877 }
1878
1879 impl Clean<FunctionRetTy> for hir::FunctionRetTy {
1880 fn clean(&self, cx: &DocContext) -> FunctionRetTy {
1881 match *self {
1882 hir::Return(ref typ) => Return(typ.clean(cx)),
1883 hir::DefaultReturn(..) => DefaultReturn,
1884 }
1885 }
1886 }
1887
1888 impl GetDefId for FunctionRetTy {
1889 fn def_id(&self) -> Option<DefId> {
1890 match *self {
1891 Return(ref ty) => ty.def_id(),
1892 DefaultReturn => None,
1893 }
1894 }
1895 }
1896
1897 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
1898 pub struct Trait {
1899 pub unsafety: hir::Unsafety,
1900 pub items: Vec<Item>,
1901 pub generics: Generics,
1902 pub bounds: Vec<TyParamBound>,
1903 pub is_spotlight: bool,
1904 pub is_auto: bool,
1905 }
1906
1907 impl Clean<Item> for doctree::Trait {
1908 fn clean(&self, cx: &DocContext) -> Item {
1909 let attrs = self.attrs.clean(cx);
1910 let is_spotlight = attrs.has_doc_flag("spotlight");
1911 Item {
1912 name: Some(self.name.clean(cx)),
1913 attrs: attrs,
1914 source: self.whence.clean(cx),
1915 def_id: cx.tcx.hir.local_def_id(self.id),
1916 visibility: self.vis.clean(cx),
1917 stability: self.stab.clean(cx),
1918 deprecation: self.depr.clean(cx),
1919 inner: TraitItem(Trait {
1920 unsafety: self.unsafety,
1921 items: self.items.clean(cx),
1922 generics: self.generics.clean(cx),
1923 bounds: self.bounds.clean(cx),
1924 is_spotlight: is_spotlight,
1925 is_auto: self.is_auto.clean(cx),
1926 }),
1927 }
1928 }
1929 }
1930
1931 impl Clean<bool> for hir::IsAuto {
1932 fn clean(&self, _: &DocContext) -> bool {
1933 match *self {
1934 hir::IsAuto::Yes => true,
1935 hir::IsAuto::No => false,
1936 }
1937 }
1938 }
1939
1940 impl Clean<Type> for hir::TraitRef {
1941 fn clean(&self, cx: &DocContext) -> Type {
1942 resolve_type(cx, self.path.clean(cx), self.ref_id)
1943 }
1944 }
1945
1946 impl Clean<PolyTrait> for hir::PolyTraitRef {
1947 fn clean(&self, cx: &DocContext) -> PolyTrait {
1948 PolyTrait {
1949 trait_: self.trait_ref.clean(cx),
1950 generic_params: self.bound_generic_params.clean(cx)
1951 }
1952 }
1953 }
1954
1955 impl Clean<Item> for hir::TraitItem {
1956 fn clean(&self, cx: &DocContext) -> Item {
1957 let inner = match self.node {
1958 hir::TraitItemKind::Const(ref ty, default) => {
1959 AssociatedConstItem(ty.clean(cx),
1960 default.map(|e| print_const_expr(cx, e)))
1961 }
1962 hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Provided(body)) => {
1963 MethodItem((sig, &self.generics, body).clean(cx))
1964 }
1965 hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Required(ref names)) => {
1966 TyMethodItem(TyMethod {
1967 unsafety: sig.unsafety.clone(),
1968 decl: (&*sig.decl, &names[..]).clean(cx),
1969 generics: self.generics.clean(cx),
1970 abi: sig.abi
1971 })
1972 }
1973 hir::TraitItemKind::Type(ref bounds, ref default) => {
1974 AssociatedTypeItem(bounds.clean(cx), default.clean(cx))
1975 }
1976 };
1977 Item {
1978 name: Some(self.name.clean(cx)),
1979 attrs: self.attrs.clean(cx),
1980 source: self.span.clean(cx),
1981 def_id: cx.tcx.hir.local_def_id(self.id),
1982 visibility: None,
1983 stability: get_stability(cx, cx.tcx.hir.local_def_id(self.id)),
1984 deprecation: get_deprecation(cx, cx.tcx.hir.local_def_id(self.id)),
1985 inner,
1986 }
1987 }
1988 }
1989
1990 impl Clean<Item> for hir::ImplItem {
1991 fn clean(&self, cx: &DocContext) -> Item {
1992 let inner = match self.node {
1993 hir::ImplItemKind::Const(ref ty, expr) => {
1994 AssociatedConstItem(ty.clean(cx),
1995 Some(print_const_expr(cx, expr)))
1996 }
1997 hir::ImplItemKind::Method(ref sig, body) => {
1998 MethodItem((sig, &self.generics, body).clean(cx))
1999 }
2000 hir::ImplItemKind::Type(ref ty) => TypedefItem(Typedef {
2001 type_: ty.clean(cx),
2002 generics: Generics::default(),
2003 }, true),
2004 };
2005 Item {
2006 name: Some(self.name.clean(cx)),
2007 source: self.span.clean(cx),
2008 attrs: self.attrs.clean(cx),
2009 def_id: cx.tcx.hir.local_def_id(self.id),
2010 visibility: self.vis.clean(cx),
2011 stability: get_stability(cx, cx.tcx.hir.local_def_id(self.id)),
2012 deprecation: get_deprecation(cx, cx.tcx.hir.local_def_id(self.id)),
2013 inner,
2014 }
2015 }
2016 }
2017
2018 impl<'tcx> Clean<Item> for ty::AssociatedItem {
2019 fn clean(&self, cx: &DocContext) -> Item {
2020 let inner = match self.kind {
2021 ty::AssociatedKind::Const => {
2022 let ty = cx.tcx.type_of(self.def_id);
2023 let default = if self.defaultness.has_value() {
2024 Some(inline::print_inlined_const(cx, self.def_id))
2025 } else {
2026 None
2027 };
2028 AssociatedConstItem(ty.clean(cx), default)
2029 }
2030 ty::AssociatedKind::Method => {
2031 let generics = (cx.tcx.generics_of(self.def_id),
2032 &cx.tcx.predicates_of(self.def_id)).clean(cx);
2033 let sig = cx.tcx.fn_sig(self.def_id);
2034 let mut decl = (self.def_id, sig).clean(cx);
2035
2036 if self.method_has_self_argument {
2037 let self_ty = match self.container {
2038 ty::ImplContainer(def_id) => {
2039 cx.tcx.type_of(def_id)
2040 }
2041 ty::TraitContainer(_) => cx.tcx.mk_self_type()
2042 };
2043 let self_arg_ty = *sig.input(0).skip_binder();
2044 if self_arg_ty == self_ty {
2045 decl.inputs.values[0].type_ = Generic(String::from("Self"));
2046 } else if let ty::TyRef(_, mt) = self_arg_ty.sty {
2047 if mt.ty == self_ty {
2048 match decl.inputs.values[0].type_ {
2049 BorrowedRef{ref mut type_, ..} => {
2050 **type_ = Generic(String::from("Self"))
2051 }
2052 _ => unreachable!(),
2053 }
2054 }
2055 }
2056 }
2057
2058 let provided = match self.container {
2059 ty::ImplContainer(_) => true,
2060 ty::TraitContainer(_) => self.defaultness.has_value()
2061 };
2062 if provided {
2063 let constness = if cx.tcx.is_const_fn(self.def_id) {
2064 hir::Constness::Const
2065 } else {
2066 hir::Constness::NotConst
2067 };
2068 MethodItem(Method {
2069 unsafety: sig.unsafety(),
2070 generics,
2071 decl,
2072 abi: sig.abi(),
2073 constness,
2074 })
2075 } else {
2076 TyMethodItem(TyMethod {
2077 unsafety: sig.unsafety(),
2078 generics,
2079 decl,
2080 abi: sig.abi(),
2081 })
2082 }
2083 }
2084 ty::AssociatedKind::Type => {
2085 let my_name = self.name.clean(cx);
2086
2087 if let ty::TraitContainer(did) = self.container {
2088 // When loading a cross-crate associated type, the bounds for this type
2089 // are actually located on the trait/impl itself, so we need to load
2090 // all of the generics from there and then look for bounds that are
2091 // applied to this associated type in question.
2092 let predicates = cx.tcx.predicates_of(did);
2093 let generics = (cx.tcx.generics_of(did), &predicates).clean(cx);
2094 let mut bounds = generics.where_predicates.iter().filter_map(|pred| {
2095 let (name, self_type, trait_, bounds) = match *pred {
2096 WherePredicate::BoundPredicate {
2097 ty: QPath { ref name, ref self_type, ref trait_ },
2098 ref bounds
2099 } => (name, self_type, trait_, bounds),
2100 _ => return None,
2101 };
2102 if *name != my_name { return None }
2103 match **trait_ {
2104 ResolvedPath { did, .. } if did == self.container.id() => {}
2105 _ => return None,
2106 }
2107 match **self_type {
2108 Generic(ref s) if *s == "Self" => {}
2109 _ => return None,
2110 }
2111 Some(bounds)
2112 }).flat_map(|i| i.iter().cloned()).collect::<Vec<_>>();
2113 // Our Sized/?Sized bound didn't get handled when creating the generics
2114 // because we didn't actually get our whole set of bounds until just now
2115 // (some of them may have come from the trait). If we do have a sized
2116 // bound, we remove it, and if we don't then we add the `?Sized` bound
2117 // at the end.
2118 match bounds.iter().position(|b| b.is_sized_bound(cx)) {
2119 Some(i) => { bounds.remove(i); }
2120 None => bounds.push(TyParamBound::maybe_sized(cx)),
2121 }
2122
2123 let ty = if self.defaultness.has_value() {
2124 Some(cx.tcx.type_of(self.def_id))
2125 } else {
2126 None
2127 };
2128
2129 AssociatedTypeItem(bounds, ty.clean(cx))
2130 } else {
2131 TypedefItem(Typedef {
2132 type_: cx.tcx.type_of(self.def_id).clean(cx),
2133 generics: Generics {
2134 params: Vec::new(),
2135 where_predicates: Vec::new(),
2136 },
2137 }, true)
2138 }
2139 }
2140 };
2141
2142 let visibility = match self.container {
2143 ty::ImplContainer(_) => self.vis.clean(cx),
2144 ty::TraitContainer(_) => None,
2145 };
2146
2147 Item {
2148 name: Some(self.name.clean(cx)),
2149 visibility,
2150 stability: get_stability(cx, self.def_id),
2151 deprecation: get_deprecation(cx, self.def_id),
2152 def_id: self.def_id,
2153 attrs: inline::load_attrs(cx, self.def_id),
2154 source: cx.tcx.def_span(self.def_id).clean(cx),
2155 inner,
2156 }
2157 }
2158 }
2159
2160 /// A trait reference, which may have higher ranked lifetimes.
2161 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
2162 pub struct PolyTrait {
2163 pub trait_: Type,
2164 pub generic_params: Vec<GenericParam>,
2165 }
2166
2167 /// A representation of a Type suitable for hyperlinking purposes. Ideally one can get the original
2168 /// type out of the AST/TyCtxt given one of these, if more information is needed. Most importantly
2169 /// it does not preserve mutability or boxes.
2170 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
2171 pub enum Type {
2172 /// structs/enums/traits (most that'd be an hir::TyPath)
2173 ResolvedPath {
2174 path: Path,
2175 typarams: Option<Vec<TyParamBound>>,
2176 did: DefId,
2177 /// true if is a `T::Name` path for associated types
2178 is_generic: bool,
2179 },
2180 /// For parameterized types, so the consumer of the JSON don't go
2181 /// looking for types which don't exist anywhere.
2182 Generic(String),
2183 /// Primitives are the fixed-size numeric types (plus int/usize/float), char,
2184 /// arrays, slices, and tuples.
2185 Primitive(PrimitiveType),
2186 /// extern "ABI" fn
2187 BareFunction(Box<BareFunctionDecl>),
2188 Tuple(Vec<Type>),
2189 Slice(Box<Type>),
2190 Array(Box<Type>, String),
2191 Never,
2192 Unique(Box<Type>),
2193 RawPointer(Mutability, Box<Type>),
2194 BorrowedRef {
2195 lifetime: Option<Lifetime>,
2196 mutability: Mutability,
2197 type_: Box<Type>,
2198 },
2199
2200 // <Type as Trait>::Name
2201 QPath {
2202 name: String,
2203 self_type: Box<Type>,
2204 trait_: Box<Type>
2205 },
2206
2207 // _
2208 Infer,
2209
2210 // impl TraitA+TraitB
2211 ImplTrait(Vec<TyParamBound>),
2212 }
2213
2214 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Copy, Debug)]
2215 pub enum PrimitiveType {
2216 Isize, I8, I16, I32, I64, I128,
2217 Usize, U8, U16, U32, U64, U128,
2218 F32, F64,
2219 Char,
2220 Bool,
2221 Str,
2222 Slice,
2223 Array,
2224 Tuple,
2225 Unit,
2226 RawPointer,
2227 Reference,
2228 Fn,
2229 Never,
2230 }
2231
2232 #[derive(Clone, RustcEncodable, RustcDecodable, Copy, Debug)]
2233 pub enum TypeKind {
2234 Enum,
2235 Function,
2236 Module,
2237 Const,
2238 Static,
2239 Struct,
2240 Union,
2241 Trait,
2242 Variant,
2243 Typedef,
2244 Foreign,
2245 Macro,
2246 }
2247
2248 pub trait GetDefId {
2249 fn def_id(&self) -> Option<DefId>;
2250 }
2251
2252 impl<T: GetDefId> GetDefId for Option<T> {
2253 fn def_id(&self) -> Option<DefId> {
2254 self.as_ref().and_then(|d| d.def_id())
2255 }
2256 }
2257
2258 impl Type {
2259 pub fn primitive_type(&self) -> Option<PrimitiveType> {
2260 match *self {
2261 Primitive(p) | BorrowedRef { type_: box Primitive(p), ..} => Some(p),
2262 Slice(..) | BorrowedRef { type_: box Slice(..), .. } => Some(PrimitiveType::Slice),
2263 Array(..) | BorrowedRef { type_: box Array(..), .. } => Some(PrimitiveType::Array),
2264 Tuple(ref tys) => if tys.is_empty() {
2265 Some(PrimitiveType::Unit)
2266 } else {
2267 Some(PrimitiveType::Tuple)
2268 },
2269 RawPointer(..) => Some(PrimitiveType::RawPointer),
2270 BorrowedRef { type_: box Generic(..), .. } => Some(PrimitiveType::Reference),
2271 BareFunction(..) => Some(PrimitiveType::Fn),
2272 Never => Some(PrimitiveType::Never),
2273 _ => None,
2274 }
2275 }
2276
2277 pub fn is_generic(&self) -> bool {
2278 match *self {
2279 ResolvedPath { is_generic, .. } => is_generic,
2280 _ => false,
2281 }
2282 }
2283
2284 pub fn is_self_type(&self) -> bool {
2285 match *self {
2286 Generic(ref name) => name == "Self",
2287 _ => false
2288 }
2289 }
2290
2291 pub fn generics(&self) -> Option<&[Type]> {
2292 match *self {
2293 ResolvedPath { ref path, .. } => {
2294 path.segments.last().and_then(|seg| {
2295 if let PathParameters::AngleBracketed { ref types, .. } = seg.params {
2296 Some(&**types)
2297 } else {
2298 None
2299 }
2300 })
2301 }
2302 _ => None,
2303 }
2304 }
2305 }
2306
2307 impl GetDefId for Type {
2308 fn def_id(&self) -> Option<DefId> {
2309 match *self {
2310 ResolvedPath { did, .. } => Some(did),
2311 Primitive(p) => ::html::render::cache().primitive_locations.get(&p).cloned(),
2312 BorrowedRef { type_: box Generic(..), .. } =>
2313 Primitive(PrimitiveType::Reference).def_id(),
2314 BorrowedRef { ref type_, .. } => type_.def_id(),
2315 Tuple(ref tys) => if tys.is_empty() {
2316 Primitive(PrimitiveType::Unit).def_id()
2317 } else {
2318 Primitive(PrimitiveType::Tuple).def_id()
2319 },
2320 BareFunction(..) => Primitive(PrimitiveType::Fn).def_id(),
2321 Never => Primitive(PrimitiveType::Never).def_id(),
2322 Slice(..) => Primitive(PrimitiveType::Slice).def_id(),
2323 Array(..) => Primitive(PrimitiveType::Array).def_id(),
2324 RawPointer(..) => Primitive(PrimitiveType::RawPointer).def_id(),
2325 QPath { ref self_type, .. } => self_type.def_id(),
2326 _ => None,
2327 }
2328 }
2329 }
2330
2331 impl PrimitiveType {
2332 fn from_str(s: &str) -> Option<PrimitiveType> {
2333 match s {
2334 "isize" => Some(PrimitiveType::Isize),
2335 "i8" => Some(PrimitiveType::I8),
2336 "i16" => Some(PrimitiveType::I16),
2337 "i32" => Some(PrimitiveType::I32),
2338 "i64" => Some(PrimitiveType::I64),
2339 "i128" => Some(PrimitiveType::I128),
2340 "usize" => Some(PrimitiveType::Usize),
2341 "u8" => Some(PrimitiveType::U8),
2342 "u16" => Some(PrimitiveType::U16),
2343 "u32" => Some(PrimitiveType::U32),
2344 "u64" => Some(PrimitiveType::U64),
2345 "u128" => Some(PrimitiveType::U128),
2346 "bool" => Some(PrimitiveType::Bool),
2347 "char" => Some(PrimitiveType::Char),
2348 "str" => Some(PrimitiveType::Str),
2349 "f32" => Some(PrimitiveType::F32),
2350 "f64" => Some(PrimitiveType::F64),
2351 "array" => Some(PrimitiveType::Array),
2352 "slice" => Some(PrimitiveType::Slice),
2353 "tuple" => Some(PrimitiveType::Tuple),
2354 "unit" => Some(PrimitiveType::Unit),
2355 "pointer" => Some(PrimitiveType::RawPointer),
2356 "reference" => Some(PrimitiveType::Reference),
2357 "fn" => Some(PrimitiveType::Fn),
2358 "never" => Some(PrimitiveType::Never),
2359 _ => None,
2360 }
2361 }
2362
2363 pub fn as_str(&self) -> &'static str {
2364 use self::PrimitiveType::*;
2365 match *self {
2366 Isize => "isize",
2367 I8 => "i8",
2368 I16 => "i16",
2369 I32 => "i32",
2370 I64 => "i64",
2371 I128 => "i128",
2372 Usize => "usize",
2373 U8 => "u8",
2374 U16 => "u16",
2375 U32 => "u32",
2376 U64 => "u64",
2377 U128 => "u128",
2378 F32 => "f32",
2379 F64 => "f64",
2380 Str => "str",
2381 Bool => "bool",
2382 Char => "char",
2383 Array => "array",
2384 Slice => "slice",
2385 Tuple => "tuple",
2386 Unit => "unit",
2387 RawPointer => "pointer",
2388 Reference => "reference",
2389 Fn => "fn",
2390 Never => "never",
2391 }
2392 }
2393
2394 pub fn to_url_str(&self) -> &'static str {
2395 self.as_str()
2396 }
2397 }
2398
2399 impl From<ast::IntTy> for PrimitiveType {
2400 fn from(int_ty: ast::IntTy) -> PrimitiveType {
2401 match int_ty {
2402 ast::IntTy::Isize => PrimitiveType::Isize,
2403 ast::IntTy::I8 => PrimitiveType::I8,
2404 ast::IntTy::I16 => PrimitiveType::I16,
2405 ast::IntTy::I32 => PrimitiveType::I32,
2406 ast::IntTy::I64 => PrimitiveType::I64,
2407 ast::IntTy::I128 => PrimitiveType::I128,
2408 }
2409 }
2410 }
2411
2412 impl From<ast::UintTy> for PrimitiveType {
2413 fn from(uint_ty: ast::UintTy) -> PrimitiveType {
2414 match uint_ty {
2415 ast::UintTy::Usize => PrimitiveType::Usize,
2416 ast::UintTy::U8 => PrimitiveType::U8,
2417 ast::UintTy::U16 => PrimitiveType::U16,
2418 ast::UintTy::U32 => PrimitiveType::U32,
2419 ast::UintTy::U64 => PrimitiveType::U64,
2420 ast::UintTy::U128 => PrimitiveType::U128,
2421 }
2422 }
2423 }
2424
2425 impl From<ast::FloatTy> for PrimitiveType {
2426 fn from(float_ty: ast::FloatTy) -> PrimitiveType {
2427 match float_ty {
2428 ast::FloatTy::F32 => PrimitiveType::F32,
2429 ast::FloatTy::F64 => PrimitiveType::F64,
2430 }
2431 }
2432 }
2433
2434 impl Clean<Type> for hir::Ty {
2435 fn clean(&self, cx: &DocContext) -> Type {
2436 use rustc::hir::*;
2437 match self.node {
2438 TyNever => Never,
2439 TyPtr(ref m) => RawPointer(m.mutbl.clean(cx), box m.ty.clean(cx)),
2440 TyRptr(ref l, ref m) => {
2441 let lifetime = if l.is_elided() {
2442 None
2443 } else {
2444 Some(l.clean(cx))
2445 };
2446 BorrowedRef {lifetime: lifetime, mutability: m.mutbl.clean(cx),
2447 type_: box m.ty.clean(cx)}
2448 }
2449 TySlice(ref ty) => Slice(box ty.clean(cx)),
2450 TyArray(ref ty, n) => {
2451 let def_id = cx.tcx.hir.body_owner_def_id(n);
2452 let param_env = cx.tcx.param_env(def_id);
2453 let substs = Substs::identity_for_item(cx.tcx, def_id);
2454 let n = cx.tcx.const_eval(param_env.and((def_id, substs))).unwrap_or_else(|_| {
2455 cx.tcx.mk_const(ty::Const {
2456 val: ConstVal::Unevaluated(def_id, substs),
2457 ty: cx.tcx.types.usize
2458 })
2459 });
2460 let n = if let ConstVal::Integral(ConstInt::Usize(n)) = n.val {
2461 n.to_string()
2462 } else if let ConstVal::Unevaluated(def_id, _) = n.val {
2463 if let Some(node_id) = cx.tcx.hir.as_local_node_id(def_id) {
2464 print_const_expr(cx, cx.tcx.hir.body_owned_by(node_id))
2465 } else {
2466 inline::print_inlined_const(cx, def_id)
2467 }
2468 } else {
2469 format!("{:?}", n)
2470 };
2471 Array(box ty.clean(cx), n)
2472 },
2473 TyTup(ref tys) => Tuple(tys.clean(cx)),
2474 TyPath(hir::QPath::Resolved(None, ref path)) => {
2475 if let Some(new_ty) = cx.ty_substs.borrow().get(&path.def).cloned() {
2476 return new_ty;
2477 }
2478
2479 let mut alias = None;
2480 if let Def::TyAlias(def_id) = path.def {
2481 // Substitute private type aliases
2482 if let Some(node_id) = cx.tcx.hir.as_local_node_id(def_id) {
2483 if !cx.access_levels.borrow().is_exported(def_id) {
2484 alias = Some(&cx.tcx.hir.expect_item(node_id).node);
2485 }
2486 }
2487 };
2488
2489 if let Some(&hir::ItemTy(ref ty, ref generics)) = alias {
2490 let provided_params = &path.segments.last().unwrap();
2491 let mut ty_substs = FxHashMap();
2492 let mut lt_substs = FxHashMap();
2493 provided_params.with_parameters(|provided_params| {
2494 for (i, ty_param) in generics.ty_params().enumerate() {
2495 let ty_param_def = Def::TyParam(cx.tcx.hir.local_def_id(ty_param.id));
2496 if let Some(ty) = provided_params.types.get(i).cloned() {
2497 ty_substs.insert(ty_param_def, ty.into_inner().clean(cx));
2498 } else if let Some(default) = ty_param.default.clone() {
2499 ty_substs.insert(ty_param_def, default.into_inner().clean(cx));
2500 }
2501 }
2502
2503 for (i, lt_param) in generics.lifetimes().enumerate() {
2504 if let Some(lt) = provided_params.lifetimes.get(i).cloned() {
2505 if !lt.is_elided() {
2506 let lt_def_id = cx.tcx.hir.local_def_id(lt_param.lifetime.id);
2507 lt_substs.insert(lt_def_id, lt.clean(cx));
2508 }
2509 }
2510 }
2511 });
2512 return cx.enter_alias(ty_substs, lt_substs, || ty.clean(cx));
2513 }
2514 resolve_type(cx, path.clean(cx), self.id)
2515 }
2516 TyPath(hir::QPath::Resolved(Some(ref qself), ref p)) => {
2517 let mut segments: Vec<_> = p.segments.clone().into();
2518 segments.pop();
2519 let trait_path = hir::Path {
2520 span: p.span,
2521 def: Def::Trait(cx.tcx.associated_item(p.def.def_id()).container.id()),
2522 segments: segments.into(),
2523 };
2524 Type::QPath {
2525 name: p.segments.last().unwrap().name.clean(cx),
2526 self_type: box qself.clean(cx),
2527 trait_: box resolve_type(cx, trait_path.clean(cx), self.id)
2528 }
2529 }
2530 TyPath(hir::QPath::TypeRelative(ref qself, ref segment)) => {
2531 let mut def = Def::Err;
2532 let ty = hir_ty_to_ty(cx.tcx, self);
2533 if let ty::TyProjection(proj) = ty.sty {
2534 def = Def::Trait(proj.trait_ref(cx.tcx).def_id);
2535 }
2536 let trait_path = hir::Path {
2537 span: self.span,
2538 def,
2539 segments: vec![].into(),
2540 };
2541 Type::QPath {
2542 name: segment.name.clean(cx),
2543 self_type: box qself.clean(cx),
2544 trait_: box resolve_type(cx, trait_path.clean(cx), self.id)
2545 }
2546 }
2547 TyTraitObject(ref bounds, ref lifetime) => {
2548 match bounds[0].clean(cx).trait_ {
2549 ResolvedPath { path, typarams: None, did, is_generic } => {
2550 let mut bounds: Vec<_> = bounds[1..].iter().map(|bound| {
2551 TraitBound(bound.clean(cx), hir::TraitBoundModifier::None)
2552 }).collect();
2553 if !lifetime.is_elided() {
2554 bounds.push(RegionBound(lifetime.clean(cx)));
2555 }
2556 ResolvedPath {
2557 path,
2558 typarams: Some(bounds),
2559 did,
2560 is_generic,
2561 }
2562 }
2563 _ => Infer // shouldn't happen
2564 }
2565 }
2566 TyBareFn(ref barefn) => BareFunction(box barefn.clean(cx)),
2567 TyImplTraitExistential(ref exist_ty, ref _lts) => ImplTrait(exist_ty.bounds.clean(cx)),
2568 TyInfer | TyErr => Infer,
2569 TyTypeof(..) => panic!("Unimplemented type {:?}", self.node),
2570 }
2571 }
2572 }
2573
2574 impl<'tcx> Clean<Type> for Ty<'tcx> {
2575 fn clean(&self, cx: &DocContext) -> Type {
2576 match self.sty {
2577 ty::TyNever => Never,
2578 ty::TyBool => Primitive(PrimitiveType::Bool),
2579 ty::TyChar => Primitive(PrimitiveType::Char),
2580 ty::TyInt(int_ty) => Primitive(int_ty.into()),
2581 ty::TyUint(uint_ty) => Primitive(uint_ty.into()),
2582 ty::TyFloat(float_ty) => Primitive(float_ty.into()),
2583 ty::TyStr => Primitive(PrimitiveType::Str),
2584 ty::TySlice(ty) => Slice(box ty.clean(cx)),
2585 ty::TyArray(ty, n) => {
2586 let mut n = cx.tcx.lift(&n).unwrap();
2587 if let ConstVal::Unevaluated(def_id, substs) = n.val {
2588 let param_env = cx.tcx.param_env(def_id);
2589 if let Ok(new_n) = cx.tcx.const_eval(param_env.and((def_id, substs))) {
2590 n = new_n;
2591 }
2592 };
2593 let n = if let ConstVal::Integral(ConstInt::Usize(n)) = n.val {
2594 n.to_string()
2595 } else if let ConstVal::Unevaluated(def_id, _) = n.val {
2596 if let Some(node_id) = cx.tcx.hir.as_local_node_id(def_id) {
2597 print_const_expr(cx, cx.tcx.hir.body_owned_by(node_id))
2598 } else {
2599 inline::print_inlined_const(cx, def_id)
2600 }
2601 } else {
2602 format!("{:?}", n)
2603 };
2604 Array(box ty.clean(cx), n)
2605 }
2606 ty::TyRawPtr(mt) => RawPointer(mt.mutbl.clean(cx), box mt.ty.clean(cx)),
2607 ty::TyRef(r, mt) => BorrowedRef {
2608 lifetime: r.clean(cx),
2609 mutability: mt.mutbl.clean(cx),
2610 type_: box mt.ty.clean(cx),
2611 },
2612 ty::TyFnDef(..) |
2613 ty::TyFnPtr(_) => {
2614 let ty = cx.tcx.lift(self).unwrap();
2615 let sig = ty.fn_sig(cx.tcx);
2616 BareFunction(box BareFunctionDecl {
2617 unsafety: sig.unsafety(),
2618 generic_params: Vec::new(),
2619 decl: (cx.tcx.hir.local_def_id(ast::CRATE_NODE_ID), sig).clean(cx),
2620 abi: sig.abi(),
2621 })
2622 }
2623 ty::TyAdt(def, substs) => {
2624 let did = def.did;
2625 let kind = match def.adt_kind() {
2626 AdtKind::Struct => TypeKind::Struct,
2627 AdtKind::Union => TypeKind::Union,
2628 AdtKind::Enum => TypeKind::Enum,
2629 };
2630 inline::record_extern_fqn(cx, did, kind);
2631 let path = external_path(cx, &cx.tcx.item_name(did),
2632 None, false, vec![], substs);
2633 ResolvedPath {
2634 path,
2635 typarams: None,
2636 did,
2637 is_generic: false,
2638 }
2639 }
2640 ty::TyForeign(did) => {
2641 inline::record_extern_fqn(cx, did, TypeKind::Foreign);
2642 let path = external_path(cx, &cx.tcx.item_name(did),
2643 None, false, vec![], Substs::empty());
2644 ResolvedPath {
2645 path: path,
2646 typarams: None,
2647 did: did,
2648 is_generic: false,
2649 }
2650 }
2651 ty::TyDynamic(ref obj, ref reg) => {
2652 if let Some(principal) = obj.principal() {
2653 let did = principal.def_id();
2654 inline::record_extern_fqn(cx, did, TypeKind::Trait);
2655
2656 let mut typarams = vec![];
2657 reg.clean(cx).map(|b| typarams.push(RegionBound(b)));
2658 for did in obj.auto_traits() {
2659 let empty = cx.tcx.intern_substs(&[]);
2660 let path = external_path(cx, &cx.tcx.item_name(did),
2661 Some(did), false, vec![], empty);
2662 inline::record_extern_fqn(cx, did, TypeKind::Trait);
2663 let bound = TraitBound(PolyTrait {
2664 trait_: ResolvedPath {
2665 path,
2666 typarams: None,
2667 did,
2668 is_generic: false,
2669 },
2670 generic_params: Vec::new(),
2671 }, hir::TraitBoundModifier::None);
2672 typarams.push(bound);
2673 }
2674
2675 let mut bindings = vec![];
2676 for ty::Binder(ref pb) in obj.projection_bounds() {
2677 bindings.push(TypeBinding {
2678 name: cx.tcx.associated_item(pb.item_def_id).name.clean(cx),
2679 ty: pb.ty.clean(cx)
2680 });
2681 }
2682
2683 let path = external_path(cx, &cx.tcx.item_name(did), Some(did),
2684 false, bindings, principal.0.substs);
2685 ResolvedPath {
2686 path,
2687 typarams: Some(typarams),
2688 did,
2689 is_generic: false,
2690 }
2691 } else {
2692 Never
2693 }
2694 }
2695 ty::TyTuple(ref t, _) => Tuple(t.clean(cx)),
2696
2697 ty::TyProjection(ref data) => data.clean(cx),
2698
2699 ty::TyParam(ref p) => Generic(p.name.to_string()),
2700
2701 ty::TyAnon(def_id, substs) => {
2702 // Grab the "TraitA + TraitB" from `impl TraitA + TraitB`,
2703 // by looking up the projections associated with the def_id.
2704 let predicates_of = cx.tcx.predicates_of(def_id);
2705 let substs = cx.tcx.lift(&substs).unwrap();
2706 let bounds = predicates_of.instantiate(cx.tcx, substs);
2707 ImplTrait(bounds.predicates.into_iter().filter_map(|predicate| {
2708 predicate.to_opt_poly_trait_ref().clean(cx)
2709 }).collect())
2710 }
2711
2712 ty::TyClosure(..) | ty::TyGenerator(..) => Tuple(vec![]), // FIXME(pcwalton)
2713
2714 ty::TyGeneratorWitness(..) => panic!("TyGeneratorWitness"),
2715 ty::TyInfer(..) => panic!("TyInfer"),
2716 ty::TyError => panic!("TyError"),
2717 }
2718 }
2719 }
2720
2721 impl Clean<Item> for hir::StructField {
2722 fn clean(&self, cx: &DocContext) -> Item {
2723 Item {
2724 name: Some(self.name).clean(cx),
2725 attrs: self.attrs.clean(cx),
2726 source: self.span.clean(cx),
2727 visibility: self.vis.clean(cx),
2728 stability: get_stability(cx, cx.tcx.hir.local_def_id(self.id)),
2729 deprecation: get_deprecation(cx, cx.tcx.hir.local_def_id(self.id)),
2730 def_id: cx.tcx.hir.local_def_id(self.id),
2731 inner: StructFieldItem(self.ty.clean(cx)),
2732 }
2733 }
2734 }
2735
2736 impl<'tcx> Clean<Item> for ty::FieldDef {
2737 fn clean(&self, cx: &DocContext) -> Item {
2738 Item {
2739 name: Some(self.name).clean(cx),
2740 attrs: cx.tcx.get_attrs(self.did).clean(cx),
2741 source: cx.tcx.def_span(self.did).clean(cx),
2742 visibility: self.vis.clean(cx),
2743 stability: get_stability(cx, self.did),
2744 deprecation: get_deprecation(cx, self.did),
2745 def_id: self.did,
2746 inner: StructFieldItem(cx.tcx.type_of(self.did).clean(cx)),
2747 }
2748 }
2749 }
2750
2751 #[derive(Clone, PartialEq, Eq, RustcDecodable, RustcEncodable, Debug)]
2752 pub enum Visibility {
2753 Public,
2754 Inherited,
2755 }
2756
2757 impl Clean<Option<Visibility>> for hir::Visibility {
2758 fn clean(&self, _: &DocContext) -> Option<Visibility> {
2759 Some(if *self == hir::Visibility::Public { Public } else { Inherited })
2760 }
2761 }
2762
2763 impl Clean<Option<Visibility>> for ty::Visibility {
2764 fn clean(&self, _: &DocContext) -> Option<Visibility> {
2765 Some(if *self == ty::Visibility::Public { Public } else { Inherited })
2766 }
2767 }
2768
2769 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
2770 pub struct Struct {
2771 pub struct_type: doctree::StructType,
2772 pub generics: Generics,
2773 pub fields: Vec<Item>,
2774 pub fields_stripped: bool,
2775 }
2776
2777 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
2778 pub struct Union {
2779 pub struct_type: doctree::StructType,
2780 pub generics: Generics,
2781 pub fields: Vec<Item>,
2782 pub fields_stripped: bool,
2783 }
2784
2785 impl Clean<Item> for doctree::Struct {
2786 fn clean(&self, cx: &DocContext) -> Item {
2787 Item {
2788 name: Some(self.name.clean(cx)),
2789 attrs: self.attrs.clean(cx),
2790 source: self.whence.clean(cx),
2791 def_id: cx.tcx.hir.local_def_id(self.id),
2792 visibility: self.vis.clean(cx),
2793 stability: self.stab.clean(cx),
2794 deprecation: self.depr.clean(cx),
2795 inner: StructItem(Struct {
2796 struct_type: self.struct_type,
2797 generics: self.generics.clean(cx),
2798 fields: self.fields.clean(cx),
2799 fields_stripped: false,
2800 }),
2801 }
2802 }
2803 }
2804
2805 impl Clean<Item> for doctree::Union {
2806 fn clean(&self, cx: &DocContext) -> Item {
2807 Item {
2808 name: Some(self.name.clean(cx)),
2809 attrs: self.attrs.clean(cx),
2810 source: self.whence.clean(cx),
2811 def_id: cx.tcx.hir.local_def_id(self.id),
2812 visibility: self.vis.clean(cx),
2813 stability: self.stab.clean(cx),
2814 deprecation: self.depr.clean(cx),
2815 inner: UnionItem(Union {
2816 struct_type: self.struct_type,
2817 generics: self.generics.clean(cx),
2818 fields: self.fields.clean(cx),
2819 fields_stripped: false,
2820 }),
2821 }
2822 }
2823 }
2824
2825 /// This is a more limited form of the standard Struct, different in that
2826 /// it lacks the things most items have (name, id, parameterization). Found
2827 /// only as a variant in an enum.
2828 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
2829 pub struct VariantStruct {
2830 pub struct_type: doctree::StructType,
2831 pub fields: Vec<Item>,
2832 pub fields_stripped: bool,
2833 }
2834
2835 impl Clean<VariantStruct> for ::rustc::hir::VariantData {
2836 fn clean(&self, cx: &DocContext) -> VariantStruct {
2837 VariantStruct {
2838 struct_type: doctree::struct_type_from_def(self),
2839 fields: self.fields().iter().map(|x| x.clean(cx)).collect(),
2840 fields_stripped: false,
2841 }
2842 }
2843 }
2844
2845 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
2846 pub struct Enum {
2847 pub variants: Vec<Item>,
2848 pub generics: Generics,
2849 pub variants_stripped: bool,
2850 }
2851
2852 impl Clean<Item> for doctree::Enum {
2853 fn clean(&self, cx: &DocContext) -> Item {
2854 Item {
2855 name: Some(self.name.clean(cx)),
2856 attrs: self.attrs.clean(cx),
2857 source: self.whence.clean(cx),
2858 def_id: cx.tcx.hir.local_def_id(self.id),
2859 visibility: self.vis.clean(cx),
2860 stability: self.stab.clean(cx),
2861 deprecation: self.depr.clean(cx),
2862 inner: EnumItem(Enum {
2863 variants: self.variants.clean(cx),
2864 generics: self.generics.clean(cx),
2865 variants_stripped: false,
2866 }),
2867 }
2868 }
2869 }
2870
2871 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
2872 pub struct Variant {
2873 pub kind: VariantKind,
2874 }
2875
2876 impl Clean<Item> for doctree::Variant {
2877 fn clean(&self, cx: &DocContext) -> Item {
2878 Item {
2879 name: Some(self.name.clean(cx)),
2880 attrs: self.attrs.clean(cx),
2881 source: self.whence.clean(cx),
2882 visibility: None,
2883 stability: self.stab.clean(cx),
2884 deprecation: self.depr.clean(cx),
2885 def_id: cx.tcx.hir.local_def_id(self.def.id()),
2886 inner: VariantItem(Variant {
2887 kind: self.def.clean(cx),
2888 }),
2889 }
2890 }
2891 }
2892
2893 impl<'tcx> Clean<Item> for ty::VariantDef {
2894 fn clean(&self, cx: &DocContext) -> Item {
2895 let kind = match self.ctor_kind {
2896 CtorKind::Const => VariantKind::CLike,
2897 CtorKind::Fn => {
2898 VariantKind::Tuple(
2899 self.fields.iter().map(|f| cx.tcx.type_of(f.did).clean(cx)).collect()
2900 )
2901 }
2902 CtorKind::Fictive => {
2903 VariantKind::Struct(VariantStruct {
2904 struct_type: doctree::Plain,
2905 fields_stripped: false,
2906 fields: self.fields.iter().map(|field| {
2907 Item {
2908 source: cx.tcx.def_span(field.did).clean(cx),
2909 name: Some(field.name.clean(cx)),
2910 attrs: cx.tcx.get_attrs(field.did).clean(cx),
2911 visibility: field.vis.clean(cx),
2912 def_id: field.did,
2913 stability: get_stability(cx, field.did),
2914 deprecation: get_deprecation(cx, field.did),
2915 inner: StructFieldItem(cx.tcx.type_of(field.did).clean(cx))
2916 }
2917 }).collect()
2918 })
2919 }
2920 };
2921 Item {
2922 name: Some(self.name.clean(cx)),
2923 attrs: inline::load_attrs(cx, self.did),
2924 source: cx.tcx.def_span(self.did).clean(cx),
2925 visibility: Some(Inherited),
2926 def_id: self.did,
2927 inner: VariantItem(Variant { kind: kind }),
2928 stability: get_stability(cx, self.did),
2929 deprecation: get_deprecation(cx, self.did),
2930 }
2931 }
2932 }
2933
2934 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
2935 pub enum VariantKind {
2936 CLike,
2937 Tuple(Vec<Type>),
2938 Struct(VariantStruct),
2939 }
2940
2941 impl Clean<VariantKind> for hir::VariantData {
2942 fn clean(&self, cx: &DocContext) -> VariantKind {
2943 if self.is_struct() {
2944 VariantKind::Struct(self.clean(cx))
2945 } else if self.is_unit() {
2946 VariantKind::CLike
2947 } else {
2948 VariantKind::Tuple(self.fields().iter().map(|x| x.ty.clean(cx)).collect())
2949 }
2950 }
2951 }
2952
2953 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
2954 pub struct Span {
2955 pub filename: FileName,
2956 pub loline: usize,
2957 pub locol: usize,
2958 pub hiline: usize,
2959 pub hicol: usize,
2960 }
2961
2962 impl Span {
2963 pub fn empty() -> Span {
2964 Span {
2965 filename: FileName::Anon,
2966 loline: 0, locol: 0,
2967 hiline: 0, hicol: 0,
2968 }
2969 }
2970 }
2971
2972 impl Clean<Span> for syntax_pos::Span {
2973 fn clean(&self, cx: &DocContext) -> Span {
2974 if *self == DUMMY_SP {
2975 return Span::empty();
2976 }
2977
2978 let cm = cx.sess().codemap();
2979 let filename = cm.span_to_filename(*self);
2980 let lo = cm.lookup_char_pos(self.lo());
2981 let hi = cm.lookup_char_pos(self.hi());
2982 Span {
2983 filename,
2984 loline: lo.line,
2985 locol: lo.col.to_usize(),
2986 hiline: hi.line,
2987 hicol: hi.col.to_usize(),
2988 }
2989 }
2990 }
2991
2992 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
2993 pub struct Path {
2994 pub global: bool,
2995 pub def: Def,
2996 pub segments: Vec<PathSegment>,
2997 }
2998
2999 impl Path {
3000 pub fn singleton(name: String) -> Path {
3001 Path {
3002 global: false,
3003 def: Def::Err,
3004 segments: vec![PathSegment {
3005 name,
3006 params: PathParameters::AngleBracketed {
3007 lifetimes: Vec::new(),
3008 types: Vec::new(),
3009 bindings: Vec::new()
3010 }
3011 }]
3012 }
3013 }
3014
3015 pub fn last_name(&self) -> &str {
3016 self.segments.last().unwrap().name.as_str()
3017 }
3018 }
3019
3020 impl Clean<Path> for hir::Path {
3021 fn clean(&self, cx: &DocContext) -> Path {
3022 Path {
3023 global: self.is_global(),
3024 def: self.def,
3025 segments: if self.is_global() { &self.segments[1..] } else { &self.segments }.clean(cx),
3026 }
3027 }
3028 }
3029
3030 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
3031 pub enum PathParameters {
3032 AngleBracketed {
3033 lifetimes: Vec<Lifetime>,
3034 types: Vec<Type>,
3035 bindings: Vec<TypeBinding>,
3036 },
3037 Parenthesized {
3038 inputs: Vec<Type>,
3039 output: Option<Type>,
3040 }
3041 }
3042
3043 impl Clean<PathParameters> for hir::PathParameters {
3044 fn clean(&self, cx: &DocContext) -> PathParameters {
3045 if self.parenthesized {
3046 let output = self.bindings[0].ty.clean(cx);
3047 PathParameters::Parenthesized {
3048 inputs: self.inputs().clean(cx),
3049 output: if output != Type::Tuple(Vec::new()) { Some(output) } else { None }
3050 }
3051 } else {
3052 PathParameters::AngleBracketed {
3053 lifetimes: if self.lifetimes.iter().all(|lt| lt.is_elided()) {
3054 vec![]
3055 } else {
3056 self.lifetimes.clean(cx)
3057 },
3058 types: self.types.clean(cx),
3059 bindings: self.bindings.clean(cx),
3060 }
3061 }
3062 }
3063 }
3064
3065 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
3066 pub struct PathSegment {
3067 pub name: String,
3068 pub params: PathParameters,
3069 }
3070
3071 impl Clean<PathSegment> for hir::PathSegment {
3072 fn clean(&self, cx: &DocContext) -> PathSegment {
3073 PathSegment {
3074 name: self.name.clean(cx),
3075 params: self.with_parameters(|parameters| parameters.clean(cx))
3076 }
3077 }
3078 }
3079
3080 fn qpath_to_string(p: &hir::QPath) -> String {
3081 let segments = match *p {
3082 hir::QPath::Resolved(_, ref path) => &path.segments,
3083 hir::QPath::TypeRelative(_, ref segment) => return segment.name.to_string(),
3084 };
3085
3086 let mut s = String::new();
3087 for (i, seg) in segments.iter().enumerate() {
3088 if i > 0 {
3089 s.push_str("::");
3090 }
3091 if seg.name != keywords::CrateRoot.name() {
3092 s.push_str(&*seg.name.as_str());
3093 }
3094 }
3095 s
3096 }
3097
3098 impl Clean<String> for ast::Name {
3099 fn clean(&self, _: &DocContext) -> String {
3100 self.to_string()
3101 }
3102 }
3103
3104 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
3105 pub struct Typedef {
3106 pub type_: Type,
3107 pub generics: Generics,
3108 }
3109
3110 impl Clean<Item> for doctree::Typedef {
3111 fn clean(&self, cx: &DocContext) -> Item {
3112 Item {
3113 name: Some(self.name.clean(cx)),
3114 attrs: self.attrs.clean(cx),
3115 source: self.whence.clean(cx),
3116 def_id: cx.tcx.hir.local_def_id(self.id.clone()),
3117 visibility: self.vis.clean(cx),
3118 stability: self.stab.clean(cx),
3119 deprecation: self.depr.clean(cx),
3120 inner: TypedefItem(Typedef {
3121 type_: self.ty.clean(cx),
3122 generics: self.gen.clean(cx),
3123 }, false),
3124 }
3125 }
3126 }
3127
3128 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
3129 pub struct BareFunctionDecl {
3130 pub unsafety: hir::Unsafety,
3131 pub generic_params: Vec<GenericParam>,
3132 pub decl: FnDecl,
3133 pub abi: Abi,
3134 }
3135
3136 impl Clean<BareFunctionDecl> for hir::BareFnTy {
3137 fn clean(&self, cx: &DocContext) -> BareFunctionDecl {
3138 BareFunctionDecl {
3139 unsafety: self.unsafety,
3140 generic_params: self.generic_params.clean(cx),
3141 decl: (&*self.decl, &self.arg_names[..]).clean(cx),
3142 abi: self.abi,
3143 }
3144 }
3145 }
3146
3147 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
3148 pub struct Static {
3149 pub type_: Type,
3150 pub mutability: Mutability,
3151 /// It's useful to have the value of a static documented, but I have no
3152 /// desire to represent expressions (that'd basically be all of the AST,
3153 /// which is huge!). So, have a string.
3154 pub expr: String,
3155 }
3156
3157 impl Clean<Item> for doctree::Static {
3158 fn clean(&self, cx: &DocContext) -> Item {
3159 debug!("cleaning static {}: {:?}", self.name.clean(cx), self);
3160 Item {
3161 name: Some(self.name.clean(cx)),
3162 attrs: self.attrs.clean(cx),
3163 source: self.whence.clean(cx),
3164 def_id: cx.tcx.hir.local_def_id(self.id),
3165 visibility: self.vis.clean(cx),
3166 stability: self.stab.clean(cx),
3167 deprecation: self.depr.clean(cx),
3168 inner: StaticItem(Static {
3169 type_: self.type_.clean(cx),
3170 mutability: self.mutability.clean(cx),
3171 expr: print_const_expr(cx, self.expr),
3172 }),
3173 }
3174 }
3175 }
3176
3177 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
3178 pub struct Constant {
3179 pub type_: Type,
3180 pub expr: String,
3181 }
3182
3183 impl Clean<Item> for doctree::Constant {
3184 fn clean(&self, cx: &DocContext) -> Item {
3185 Item {
3186 name: Some(self.name.clean(cx)),
3187 attrs: self.attrs.clean(cx),
3188 source: self.whence.clean(cx),
3189 def_id: cx.tcx.hir.local_def_id(self.id),
3190 visibility: self.vis.clean(cx),
3191 stability: self.stab.clean(cx),
3192 deprecation: self.depr.clean(cx),
3193 inner: ConstantItem(Constant {
3194 type_: self.type_.clean(cx),
3195 expr: print_const_expr(cx, self.expr),
3196 }),
3197 }
3198 }
3199 }
3200
3201 #[derive(Debug, Clone, RustcEncodable, RustcDecodable, PartialEq, Copy)]
3202 pub enum Mutability {
3203 Mutable,
3204 Immutable,
3205 }
3206
3207 impl Clean<Mutability> for hir::Mutability {
3208 fn clean(&self, _: &DocContext) -> Mutability {
3209 match self {
3210 &hir::MutMutable => Mutable,
3211 &hir::MutImmutable => Immutable,
3212 }
3213 }
3214 }
3215
3216 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Copy, Debug)]
3217 pub enum ImplPolarity {
3218 Positive,
3219 Negative,
3220 }
3221
3222 impl Clean<ImplPolarity> for hir::ImplPolarity {
3223 fn clean(&self, _: &DocContext) -> ImplPolarity {
3224 match self {
3225 &hir::ImplPolarity::Positive => ImplPolarity::Positive,
3226 &hir::ImplPolarity::Negative => ImplPolarity::Negative,
3227 }
3228 }
3229 }
3230
3231 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
3232 pub struct Impl {
3233 pub unsafety: hir::Unsafety,
3234 pub generics: Generics,
3235 pub provided_trait_methods: FxHashSet<String>,
3236 pub trait_: Option<Type>,
3237 pub for_: Type,
3238 pub items: Vec<Item>,
3239 pub polarity: Option<ImplPolarity>,
3240 }
3241
3242 impl Clean<Vec<Item>> for doctree::Impl {
3243 fn clean(&self, cx: &DocContext) -> Vec<Item> {
3244 let mut ret = Vec::new();
3245 let trait_ = self.trait_.clean(cx);
3246 let items = self.items.clean(cx);
3247
3248 // If this impl block is an implementation of the Deref trait, then we
3249 // need to try inlining the target's inherent impl blocks as well.
3250 if trait_.def_id() == cx.tcx.lang_items().deref_trait() {
3251 build_deref_target_impls(cx, &items, &mut ret);
3252 }
3253
3254 let provided = trait_.def_id().map(|did| {
3255 cx.tcx.provided_trait_methods(did)
3256 .into_iter()
3257 .map(|meth| meth.name.to_string())
3258 .collect()
3259 }).unwrap_or(FxHashSet());
3260
3261 ret.push(Item {
3262 name: None,
3263 attrs: self.attrs.clean(cx),
3264 source: self.whence.clean(cx),
3265 def_id: cx.tcx.hir.local_def_id(self.id),
3266 visibility: self.vis.clean(cx),
3267 stability: self.stab.clean(cx),
3268 deprecation: self.depr.clean(cx),
3269 inner: ImplItem(Impl {
3270 unsafety: self.unsafety,
3271 generics: self.generics.clean(cx),
3272 provided_trait_methods: provided,
3273 trait_,
3274 for_: self.for_.clean(cx),
3275 items,
3276 polarity: Some(self.polarity.clean(cx)),
3277 }),
3278 });
3279 ret
3280 }
3281 }
3282
3283 fn build_deref_target_impls(cx: &DocContext,
3284 items: &[Item],
3285 ret: &mut Vec<Item>) {
3286 use self::PrimitiveType::*;
3287 let tcx = cx.tcx;
3288
3289 for item in items {
3290 let target = match item.inner {
3291 TypedefItem(ref t, true) => &t.type_,
3292 _ => continue,
3293 };
3294 let primitive = match *target {
3295 ResolvedPath { did, .. } if did.is_local() => continue,
3296 ResolvedPath { did, .. } => {
3297 ret.extend(inline::build_impls(cx, did));
3298 continue
3299 }
3300 _ => match target.primitive_type() {
3301 Some(prim) => prim,
3302 None => continue,
3303 }
3304 };
3305 let did = match primitive {
3306 Isize => tcx.lang_items().isize_impl(),
3307 I8 => tcx.lang_items().i8_impl(),
3308 I16 => tcx.lang_items().i16_impl(),
3309 I32 => tcx.lang_items().i32_impl(),
3310 I64 => tcx.lang_items().i64_impl(),
3311 I128 => tcx.lang_items().i128_impl(),
3312 Usize => tcx.lang_items().usize_impl(),
3313 U8 => tcx.lang_items().u8_impl(),
3314 U16 => tcx.lang_items().u16_impl(),
3315 U32 => tcx.lang_items().u32_impl(),
3316 U64 => tcx.lang_items().u64_impl(),
3317 U128 => tcx.lang_items().u128_impl(),
3318 F32 => tcx.lang_items().f32_impl(),
3319 F64 => tcx.lang_items().f64_impl(),
3320 Char => tcx.lang_items().char_impl(),
3321 Bool => None,
3322 Str => tcx.lang_items().str_impl(),
3323 Slice => tcx.lang_items().slice_impl(),
3324 Array => tcx.lang_items().slice_impl(),
3325 Tuple => None,
3326 Unit => None,
3327 RawPointer => tcx.lang_items().const_ptr_impl(),
3328 Reference => None,
3329 Fn => None,
3330 Never => None,
3331 };
3332 if let Some(did) = did {
3333 if !did.is_local() {
3334 inline::build_impl(cx, did, ret);
3335 }
3336 }
3337 }
3338 }
3339
3340 impl Clean<Item> for doctree::ExternCrate {
3341 fn clean(&self, cx: &DocContext) -> Item {
3342 Item {
3343 name: None,
3344 attrs: self.attrs.clean(cx),
3345 source: self.whence.clean(cx),
3346 def_id: DefId { krate: self.cnum, index: CRATE_DEF_INDEX },
3347 visibility: self.vis.clean(cx),
3348 stability: None,
3349 deprecation: None,
3350 inner: ExternCrateItem(self.name.clean(cx), self.path.clone())
3351 }
3352 }
3353 }
3354
3355 impl Clean<Vec<Item>> for doctree::Import {
3356 fn clean(&self, cx: &DocContext) -> Vec<Item> {
3357 // We consider inlining the documentation of `pub use` statements, but we
3358 // forcefully don't inline if this is not public or if the
3359 // #[doc(no_inline)] attribute is present.
3360 // Don't inline doc(hidden) imports so they can be stripped at a later stage.
3361 let denied = self.vis != hir::Public || self.attrs.iter().any(|a| {
3362 a.name().unwrap() == "doc" && match a.meta_item_list() {
3363 Some(l) => attr::list_contains_name(&l, "no_inline") ||
3364 attr::list_contains_name(&l, "hidden"),
3365 None => false,
3366 }
3367 });
3368 let path = self.path.clean(cx);
3369 let inner = if self.glob {
3370 Import::Glob(resolve_use_source(cx, path))
3371 } else {
3372 let name = self.name;
3373 if !denied {
3374 if let Some(items) = inline::try_inline(cx, path.def, name) {
3375 return items;
3376 }
3377 }
3378 Import::Simple(name.clean(cx), resolve_use_source(cx, path))
3379 };
3380 vec![Item {
3381 name: None,
3382 attrs: self.attrs.clean(cx),
3383 source: self.whence.clean(cx),
3384 def_id: cx.tcx.hir.local_def_id(ast::CRATE_NODE_ID),
3385 visibility: self.vis.clean(cx),
3386 stability: None,
3387 deprecation: None,
3388 inner: ImportItem(inner)
3389 }]
3390 }
3391 }
3392
3393 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
3394 pub enum Import {
3395 // use source as str;
3396 Simple(String, ImportSource),
3397 // use source::*;
3398 Glob(ImportSource)
3399 }
3400
3401 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
3402 pub struct ImportSource {
3403 pub path: Path,
3404 pub did: Option<DefId>,
3405 }
3406
3407 impl Clean<Vec<Item>> for hir::ForeignMod {
3408 fn clean(&self, cx: &DocContext) -> Vec<Item> {
3409 let mut items = self.items.clean(cx);
3410 for item in &mut items {
3411 if let ForeignFunctionItem(ref mut f) = item.inner {
3412 f.abi = self.abi;
3413 }
3414 }
3415 items
3416 }
3417 }
3418
3419 impl Clean<Item> for hir::ForeignItem {
3420 fn clean(&self, cx: &DocContext) -> Item {
3421 let inner = match self.node {
3422 hir::ForeignItemFn(ref decl, ref names, ref generics) => {
3423 ForeignFunctionItem(Function {
3424 decl: (&**decl, &names[..]).clean(cx),
3425 generics: generics.clean(cx),
3426 unsafety: hir::Unsafety::Unsafe,
3427 abi: Abi::Rust,
3428 constness: hir::Constness::NotConst,
3429 })
3430 }
3431 hir::ForeignItemStatic(ref ty, mutbl) => {
3432 ForeignStaticItem(Static {
3433 type_: ty.clean(cx),
3434 mutability: if mutbl {Mutable} else {Immutable},
3435 expr: "".to_string(),
3436 })
3437 }
3438 hir::ForeignItemType => {
3439 ForeignTypeItem
3440 }
3441 };
3442 Item {
3443 name: Some(self.name.clean(cx)),
3444 attrs: self.attrs.clean(cx),
3445 source: self.span.clean(cx),
3446 def_id: cx.tcx.hir.local_def_id(self.id),
3447 visibility: self.vis.clean(cx),
3448 stability: get_stability(cx, cx.tcx.hir.local_def_id(self.id)),
3449 deprecation: get_deprecation(cx, cx.tcx.hir.local_def_id(self.id)),
3450 inner,
3451 }
3452 }
3453 }
3454
3455 // Utilities
3456
3457 trait ToSource {
3458 fn to_src(&self, cx: &DocContext) -> String;
3459 }
3460
3461 impl ToSource for syntax_pos::Span {
3462 fn to_src(&self, cx: &DocContext) -> String {
3463 debug!("converting span {:?} to snippet", self.clean(cx));
3464 let sn = match cx.sess().codemap().span_to_snippet(*self) {
3465 Ok(x) => x.to_string(),
3466 Err(_) => "".to_string()
3467 };
3468 debug!("got snippet {}", sn);
3469 sn
3470 }
3471 }
3472
3473 fn name_from_pat(p: &hir::Pat) -> String {
3474 use rustc::hir::*;
3475 debug!("Trying to get a name from pattern: {:?}", p);
3476
3477 match p.node {
3478 PatKind::Wild => "_".to_string(),
3479 PatKind::Binding(_, _, ref p, _) => p.node.to_string(),
3480 PatKind::TupleStruct(ref p, ..) | PatKind::Path(ref p) => qpath_to_string(p),
3481 PatKind::Struct(ref name, ref fields, etc) => {
3482 format!("{} {{ {}{} }}", qpath_to_string(name),
3483 fields.iter().map(|&Spanned { node: ref fp, .. }|
3484 format!("{}: {}", fp.name, name_from_pat(&*fp.pat)))
3485 .collect::<Vec<String>>().join(", "),
3486 if etc { ", ..." } else { "" }
3487 )
3488 }
3489 PatKind::Tuple(ref elts, _) => format!("({})", elts.iter().map(|p| name_from_pat(&**p))
3490 .collect::<Vec<String>>().join(", ")),
3491 PatKind::Box(ref p) => name_from_pat(&**p),
3492 PatKind::Ref(ref p, _) => name_from_pat(&**p),
3493 PatKind::Lit(..) => {
3494 warn!("tried to get argument name from PatKind::Lit, \
3495 which is silly in function arguments");
3496 "()".to_string()
3497 },
3498 PatKind::Range(..) => panic!("tried to get argument name from PatKind::Range, \
3499 which is not allowed in function arguments"),
3500 PatKind::Slice(ref begin, ref mid, ref end) => {
3501 let begin = begin.iter().map(|p| name_from_pat(&**p));
3502 let mid = mid.as_ref().map(|p| format!("..{}", name_from_pat(&**p))).into_iter();
3503 let end = end.iter().map(|p| name_from_pat(&**p));
3504 format!("[{}]", begin.chain(mid).chain(end).collect::<Vec<_>>().join(", "))
3505 },
3506 }
3507 }
3508
3509 fn print_const_expr(cx: &DocContext, body: hir::BodyId) -> String {
3510 cx.tcx.hir.node_to_pretty_string(body.node_id)
3511 }
3512
3513 /// Given a type Path, resolve it to a Type using the TyCtxt
3514 fn resolve_type(cx: &DocContext,
3515 path: Path,
3516 id: ast::NodeId) -> Type {
3517 debug!("resolve_type({:?},{:?})", path, id);
3518
3519 let is_generic = match path.def {
3520 Def::PrimTy(p) => match p {
3521 hir::TyStr => return Primitive(PrimitiveType::Str),
3522 hir::TyBool => return Primitive(PrimitiveType::Bool),
3523 hir::TyChar => return Primitive(PrimitiveType::Char),
3524 hir::TyInt(int_ty) => return Primitive(int_ty.into()),
3525 hir::TyUint(uint_ty) => return Primitive(uint_ty.into()),
3526 hir::TyFloat(float_ty) => return Primitive(float_ty.into()),
3527 },
3528 Def::SelfTy(..) if path.segments.len() == 1 => {
3529 return Generic(keywords::SelfType.name().to_string());
3530 }
3531 Def::TyParam(..) if path.segments.len() == 1 => {
3532 return Generic(format!("{:#}", path));
3533 }
3534 Def::SelfTy(..) | Def::TyParam(..) | Def::AssociatedTy(..) => true,
3535 _ => false,
3536 };
3537 let did = register_def(&*cx, path.def);
3538 ResolvedPath { path: path, typarams: None, did: did, is_generic: is_generic }
3539 }
3540
3541 fn register_def(cx: &DocContext, def: Def) -> DefId {
3542 debug!("register_def({:?})", def);
3543
3544 let (did, kind) = match def {
3545 Def::Fn(i) => (i, TypeKind::Function),
3546 Def::TyAlias(i) => (i, TypeKind::Typedef),
3547 Def::Enum(i) => (i, TypeKind::Enum),
3548 Def::Trait(i) => (i, TypeKind::Trait),
3549 Def::Struct(i) => (i, TypeKind::Struct),
3550 Def::Union(i) => (i, TypeKind::Union),
3551 Def::Mod(i) => (i, TypeKind::Module),
3552 Def::TyForeign(i) => (i, TypeKind::Foreign),
3553 Def::Static(i, _) => (i, TypeKind::Static),
3554 Def::Variant(i) => (cx.tcx.parent_def_id(i).unwrap(), TypeKind::Enum),
3555 Def::Macro(i, _) => (i, TypeKind::Macro),
3556 Def::SelfTy(Some(def_id), _) => (def_id, TypeKind::Trait),
3557 Def::SelfTy(_, Some(impl_def_id)) => {
3558 return impl_def_id
3559 }
3560 _ => return def.def_id()
3561 };
3562 if did.is_local() { return did }
3563 inline::record_extern_fqn(cx, did, kind);
3564 if let TypeKind::Trait = kind {
3565 inline::record_extern_trait(cx, did);
3566 }
3567 did
3568 }
3569
3570 fn resolve_use_source(cx: &DocContext, path: Path) -> ImportSource {
3571 ImportSource {
3572 did: if path.def == Def::Err {
3573 None
3574 } else {
3575 Some(register_def(cx, path.def))
3576 },
3577 path,
3578 }
3579 }
3580
3581 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
3582 pub struct Macro {
3583 pub source: String,
3584 pub imported_from: Option<String>,
3585 }
3586
3587 impl Clean<Item> for doctree::Macro {
3588 fn clean(&self, cx: &DocContext) -> Item {
3589 let name = self.name.clean(cx);
3590 Item {
3591 name: Some(name.clone()),
3592 attrs: self.attrs.clean(cx),
3593 source: self.whence.clean(cx),
3594 visibility: Some(Public),
3595 stability: self.stab.clean(cx),
3596 deprecation: self.depr.clean(cx),
3597 def_id: self.def_id,
3598 inner: MacroItem(Macro {
3599 source: format!("macro_rules! {} {{\n{}}}",
3600 name,
3601 self.matchers.iter().map(|span| {
3602 format!(" {} => {{ ... }};\n", span.to_src(cx))
3603 }).collect::<String>()),
3604 imported_from: self.imported_from.clean(cx),
3605 }),
3606 }
3607 }
3608 }
3609
3610 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
3611 pub struct Stability {
3612 pub level: stability::StabilityLevel,
3613 pub feature: String,
3614 pub since: String,
3615 pub deprecated_since: String,
3616 pub deprecated_reason: String,
3617 pub unstable_reason: String,
3618 pub issue: Option<u32>
3619 }
3620
3621 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
3622 pub struct Deprecation {
3623 pub since: String,
3624 pub note: String,
3625 }
3626
3627 impl Clean<Stability> for attr::Stability {
3628 fn clean(&self, _: &DocContext) -> Stability {
3629 Stability {
3630 level: stability::StabilityLevel::from_attr_level(&self.level),
3631 feature: self.feature.to_string(),
3632 since: match self.level {
3633 attr::Stable {ref since} => since.to_string(),
3634 _ => "".to_string(),
3635 },
3636 deprecated_since: match self.rustc_depr {
3637 Some(attr::RustcDeprecation {ref since, ..}) => since.to_string(),
3638 _=> "".to_string(),
3639 },
3640 deprecated_reason: match self.rustc_depr {
3641 Some(ref depr) => depr.reason.to_string(),
3642 _ => "".to_string(),
3643 },
3644 unstable_reason: match self.level {
3645 attr::Unstable { reason: Some(ref reason), .. } => reason.to_string(),
3646 _ => "".to_string(),
3647 },
3648 issue: match self.level {
3649 attr::Unstable {issue, ..} => Some(issue),
3650 _ => None,
3651 }
3652 }
3653 }
3654 }
3655
3656 impl<'a> Clean<Stability> for &'a attr::Stability {
3657 fn clean(&self, dc: &DocContext) -> Stability {
3658 (**self).clean(dc)
3659 }
3660 }
3661
3662 impl Clean<Deprecation> for attr::Deprecation {
3663 fn clean(&self, _: &DocContext) -> Deprecation {
3664 Deprecation {
3665 since: self.since.as_ref().map_or("".to_string(), |s| s.to_string()),
3666 note: self.note.as_ref().map_or("".to_string(), |s| s.to_string()),
3667 }
3668 }
3669 }
3670
3671 /// An equality constraint on an associated type, e.g. `A=Bar` in `Foo<A=Bar>`
3672 #[derive(Clone, PartialEq, RustcDecodable, RustcEncodable, Debug)]
3673 pub struct TypeBinding {
3674 pub name: String,
3675 pub ty: Type
3676 }
3677
3678 impl Clean<TypeBinding> for hir::TypeBinding {
3679 fn clean(&self, cx: &DocContext) -> TypeBinding {
3680 TypeBinding {
3681 name: self.name.clean(cx),
3682 ty: self.ty.clean(cx)
3683 }
3684 }
3685 }