]> git.proxmox.com Git - rustc.git/blob - src/librustdoc/clean/mod.rs
New upstream version 1.40.0+dfsg1
[rustc.git] / src / librustdoc / clean / mod.rs
1 // ignore-tidy-filelength
2
3 //! This module contains the "cleaned" pieces of the AST, and the functions
4 //! that clean them.
5
6 pub mod inline;
7 pub mod cfg;
8 mod simplify;
9 mod auto_trait;
10 mod blanket_impl;
11
12 use rustc_index::vec::{IndexVec, Idx};
13 use rustc_target::spec::abi::Abi;
14 use rustc_typeck::hir_ty_to_ty;
15 use rustc::infer::region_constraints::{RegionConstraintData, Constraint};
16 use rustc::middle::resolve_lifetime as rl;
17 use rustc::middle::lang_items;
18 use rustc::middle::stability;
19 use rustc::mir::interpret::{GlobalId, ConstValue};
20 use rustc::hir;
21 use rustc::hir::def::{CtorKind, DefKind, Res};
22 use rustc::hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
23 use rustc::hir::ptr::P;
24 use rustc::ty::subst::{InternalSubsts, SubstsRef, GenericArgKind};
25 use rustc::ty::{self, DefIdTree, TyCtxt, Region, RegionVid, Ty, AdtKind};
26 use rustc::ty::fold::TypeFolder;
27 use rustc::ty::layout::VariantIdx;
28 use rustc::util::nodemap::{FxHashMap, FxHashSet};
29 use syntax::ast::{self, Attribute, AttrStyle, AttrItem, Ident};
30 use syntax::attr;
31 use syntax::parse::lexer::comments;
32 use syntax::source_map::DUMMY_SP;
33 use syntax_pos::symbol::{Symbol, kw, sym};
34 use syntax_pos::hygiene::MacroKind;
35 use syntax_pos::{self, Pos, FileName};
36
37 use std::collections::hash_map::Entry;
38 use std::fmt;
39 use std::hash::{Hash, Hasher};
40 use std::default::Default;
41 use std::{mem, slice, vec};
42 use std::iter::FromIterator;
43 use std::rc::Rc;
44 use std::cell::RefCell;
45 use std::sync::Arc;
46 use std::u32;
47
48 use crate::core::{self, DocContext, ImplTraitParam};
49 use crate::doctree;
50 use crate::html::render::{cache, ExternalLocation};
51 use crate::html::item_type::ItemType;
52
53
54 use self::cfg::Cfg;
55 use self::auto_trait::AutoTraitFinder;
56 use self::blanket_impl::BlanketImplFinder;
57
58 pub use self::Type::*;
59 pub use self::Mutability::*;
60 pub use self::ItemEnum::*;
61 pub use self::SelfTy::*;
62 pub use self::FunctionRetTy::*;
63 pub use self::Visibility::{Public, Inherited};
64
65 thread_local!(pub static MAX_DEF_ID: RefCell<FxHashMap<CrateNum, DefId>> = Default::default());
66
67 const FN_OUTPUT_NAME: &'static str = "Output";
68
69 // extract the stability index for a node from tcx, if possible
70 fn get_stability(cx: &DocContext<'_>, def_id: DefId) -> Option<Stability> {
71 cx.tcx.lookup_stability(def_id).clean(cx)
72 }
73
74 fn get_deprecation(cx: &DocContext<'_>, def_id: DefId) -> Option<Deprecation> {
75 cx.tcx.lookup_deprecation(def_id).clean(cx)
76 }
77
78 pub trait Clean<T> {
79 fn clean(&self, cx: &DocContext<'_>) -> T;
80 }
81
82 impl<T: Clean<U>, U> Clean<Vec<U>> for [T] {
83 fn clean(&self, cx: &DocContext<'_>) -> Vec<U> {
84 self.iter().map(|x| x.clean(cx)).collect()
85 }
86 }
87
88 impl<T: Clean<U>, U, V: Idx> Clean<IndexVec<V, U>> for IndexVec<V, T> {
89 fn clean(&self, cx: &DocContext<'_>) -> IndexVec<V, U> {
90 self.iter().map(|x| x.clean(cx)).collect()
91 }
92 }
93
94 impl<T: Clean<U>, U> Clean<U> for P<T> {
95 fn clean(&self, cx: &DocContext<'_>) -> U {
96 (**self).clean(cx)
97 }
98 }
99
100 impl<T: Clean<U>, U> Clean<U> for Rc<T> {
101 fn clean(&self, cx: &DocContext<'_>) -> U {
102 (**self).clean(cx)
103 }
104 }
105
106 impl<T: Clean<U>, U> Clean<Option<U>> for Option<T> {
107 fn clean(&self, cx: &DocContext<'_>) -> Option<U> {
108 self.as_ref().map(|v| v.clean(cx))
109 }
110 }
111
112 impl<T, U> Clean<U> for ty::Binder<T> where T: Clean<U> {
113 fn clean(&self, cx: &DocContext<'_>) -> U {
114 self.skip_binder().clean(cx)
115 }
116 }
117
118 impl<T: Clean<U>, U> Clean<Vec<U>> for P<[T]> {
119 fn clean(&self, cx: &DocContext<'_>) -> Vec<U> {
120 self.iter().map(|x| x.clean(cx)).collect()
121 }
122 }
123
124 #[derive(Clone, Debug)]
125 pub struct Crate {
126 pub name: String,
127 pub version: Option<String>,
128 pub src: FileName,
129 pub module: Option<Item>,
130 pub externs: Vec<(CrateNum, ExternalCrate)>,
131 pub primitives: Vec<(DefId, PrimitiveType, Attributes)>,
132 // These are later on moved into `CACHEKEY`, leaving the map empty.
133 // Only here so that they can be filtered through the rustdoc passes.
134 pub external_traits: Rc<RefCell<FxHashMap<DefId, Trait>>>,
135 pub masked_crates: FxHashSet<CrateNum>,
136 pub collapsed: bool,
137 }
138
139 pub fn krate(mut cx: &mut DocContext<'_>) -> Crate {
140 use crate::visit_lib::LibEmbargoVisitor;
141
142 let krate = cx.tcx.hir().krate();
143 let module = crate::visit_ast::RustdocVisitor::new(&mut cx).visit(krate);
144
145 let mut r = cx.renderinfo.get_mut();
146 r.deref_trait_did = cx.tcx.lang_items().deref_trait();
147 r.deref_mut_trait_did = cx.tcx.lang_items().deref_mut_trait();
148 r.owned_box_did = cx.tcx.lang_items().owned_box();
149
150 let mut externs = Vec::new();
151 for &cnum in cx.tcx.crates().iter() {
152 externs.push((cnum, cnum.clean(cx)));
153 // Analyze doc-reachability for extern items
154 LibEmbargoVisitor::new(&mut cx).visit_lib(cnum);
155 }
156 externs.sort_by(|&(a, _), &(b, _)| a.cmp(&b));
157
158 // Clean the crate, translating the entire libsyntax AST to one that is
159 // understood by rustdoc.
160 let mut module = module.clean(cx);
161 let mut masked_crates = FxHashSet::default();
162
163 match module.inner {
164 ModuleItem(ref module) => {
165 for it in &module.items {
166 // `compiler_builtins` should be masked too, but we can't apply
167 // `#[doc(masked)]` to the injected `extern crate` because it's unstable.
168 if it.is_extern_crate()
169 && (it.attrs.has_doc_flag(sym::masked)
170 || cx.tcx.is_compiler_builtins(it.def_id.krate))
171 {
172 masked_crates.insert(it.def_id.krate);
173 }
174 }
175 }
176 _ => unreachable!(),
177 }
178
179 let ExternalCrate { name, src, primitives, keywords, .. } = LOCAL_CRATE.clean(cx);
180 {
181 let m = match module.inner {
182 ModuleItem(ref mut m) => m,
183 _ => unreachable!(),
184 };
185 m.items.extend(primitives.iter().map(|&(def_id, prim, ref attrs)| {
186 Item {
187 source: Span::empty(),
188 name: Some(prim.to_url_str().to_string()),
189 attrs: attrs.clone(),
190 visibility: Public,
191 stability: get_stability(cx, def_id),
192 deprecation: get_deprecation(cx, def_id),
193 def_id,
194 inner: PrimitiveItem(prim),
195 }
196 }));
197 m.items.extend(keywords.into_iter().map(|(def_id, kw, attrs)| {
198 Item {
199 source: Span::empty(),
200 name: Some(kw.clone()),
201 attrs,
202 visibility: Public,
203 stability: get_stability(cx, def_id),
204 deprecation: get_deprecation(cx, def_id),
205 def_id,
206 inner: KeywordItem(kw),
207 }
208 }));
209 }
210
211 Crate {
212 name,
213 version: None,
214 src,
215 module: Some(module),
216 externs,
217 primitives,
218 external_traits: cx.external_traits.clone(),
219 masked_crates,
220 collapsed: false,
221 }
222 }
223
224 #[derive(Clone, Debug)]
225 pub struct ExternalCrate {
226 pub name: String,
227 pub src: FileName,
228 pub attrs: Attributes,
229 pub primitives: Vec<(DefId, PrimitiveType, Attributes)>,
230 pub keywords: Vec<(DefId, String, Attributes)>,
231 }
232
233 impl Clean<ExternalCrate> for CrateNum {
234 fn clean(&self, cx: &DocContext<'_>) -> ExternalCrate {
235 let root = DefId { krate: *self, index: CRATE_DEF_INDEX };
236 let krate_span = cx.tcx.def_span(root);
237 let krate_src = cx.sess().source_map().span_to_filename(krate_span);
238
239 // Collect all inner modules which are tagged as implementations of
240 // primitives.
241 //
242 // Note that this loop only searches the top-level items of the crate,
243 // and this is intentional. If we were to search the entire crate for an
244 // item tagged with `#[doc(primitive)]` then we would also have to
245 // search the entirety of external modules for items tagged
246 // `#[doc(primitive)]`, which is a pretty inefficient process (decoding
247 // all that metadata unconditionally).
248 //
249 // In order to keep the metadata load under control, the
250 // `#[doc(primitive)]` feature is explicitly designed to only allow the
251 // primitive tags to show up as the top level items in a crate.
252 //
253 // Also note that this does not attempt to deal with modules tagged
254 // duplicately for the same primitive. This is handled later on when
255 // rendering by delegating everything to a hash map.
256 let as_primitive = |res: Res| {
257 if let Res::Def(DefKind::Mod, def_id) = res {
258 let attrs = cx.tcx.get_attrs(def_id).clean(cx);
259 let mut prim = None;
260 for attr in attrs.lists(sym::doc) {
261 if let Some(v) = attr.value_str() {
262 if attr.check_name(sym::primitive) {
263 prim = PrimitiveType::from_str(&v.as_str());
264 if prim.is_some() {
265 break;
266 }
267 // FIXME: should warn on unknown primitives?
268 }
269 }
270 }
271 return prim.map(|p| (def_id, p, attrs));
272 }
273 None
274 };
275 let primitives = if root.is_local() {
276 cx.tcx.hir().krate().module.item_ids.iter().filter_map(|&id| {
277 let item = cx.tcx.hir().expect_item(id.id);
278 match item.kind {
279 hir::ItemKind::Mod(_) => {
280 as_primitive(Res::Def(
281 DefKind::Mod,
282 cx.tcx.hir().local_def_id(id.id),
283 ))
284 }
285 hir::ItemKind::Use(ref path, hir::UseKind::Single)
286 if item.vis.node.is_pub() => {
287 as_primitive(path.res).map(|(_, prim, attrs)| {
288 // Pretend the primitive is local.
289 (cx.tcx.hir().local_def_id(id.id), prim, attrs)
290 })
291 }
292 _ => None
293 }
294 }).collect()
295 } else {
296 cx.tcx.item_children(root).iter().map(|item| item.res)
297 .filter_map(as_primitive).collect()
298 };
299
300 let as_keyword = |res: Res| {
301 if let Res::Def(DefKind::Mod, def_id) = res {
302 let attrs = cx.tcx.get_attrs(def_id).clean(cx);
303 let mut keyword = None;
304 for attr in attrs.lists(sym::doc) {
305 if let Some(v) = attr.value_str() {
306 if attr.check_name(sym::keyword) {
307 if v.is_doc_keyword() {
308 keyword = Some(v.to_string());
309 break;
310 }
311 // FIXME: should warn on unknown keywords?
312 }
313 }
314 }
315 return keyword.map(|p| (def_id, p, attrs));
316 }
317 None
318 };
319 let keywords = if root.is_local() {
320 cx.tcx.hir().krate().module.item_ids.iter().filter_map(|&id| {
321 let item = cx.tcx.hir().expect_item(id.id);
322 match item.kind {
323 hir::ItemKind::Mod(_) => {
324 as_keyword(Res::Def(
325 DefKind::Mod,
326 cx.tcx.hir().local_def_id(id.id),
327 ))
328 }
329 hir::ItemKind::Use(ref path, hir::UseKind::Single)
330 if item.vis.node.is_pub() => {
331 as_keyword(path.res).map(|(_, prim, attrs)| {
332 (cx.tcx.hir().local_def_id(id.id), prim, attrs)
333 })
334 }
335 _ => None
336 }
337 }).collect()
338 } else {
339 cx.tcx.item_children(root).iter().map(|item| item.res)
340 .filter_map(as_keyword).collect()
341 };
342
343 ExternalCrate {
344 name: cx.tcx.crate_name(*self).to_string(),
345 src: krate_src,
346 attrs: cx.tcx.get_attrs(root).clean(cx),
347 primitives,
348 keywords,
349 }
350 }
351 }
352
353 /// Anything with a source location and set of attributes and, optionally, a
354 /// name. That is, anything that can be documented. This doesn't correspond
355 /// directly to the AST's concept of an item; it's a strict superset.
356 #[derive(Clone)]
357 pub struct Item {
358 /// Stringified span
359 pub source: Span,
360 /// Not everything has a name. E.g., impls
361 pub name: Option<String>,
362 pub attrs: Attributes,
363 pub inner: ItemEnum,
364 pub visibility: Visibility,
365 pub def_id: DefId,
366 pub stability: Option<Stability>,
367 pub deprecation: Option<Deprecation>,
368 }
369
370 impl fmt::Debug for Item {
371 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
372
373 let fake = MAX_DEF_ID.with(|m| m.borrow().get(&self.def_id.krate)
374 .map(|id| self.def_id >= *id).unwrap_or(false));
375 let def_id: &dyn fmt::Debug = if fake { &"**FAKE**" } else { &self.def_id };
376
377 fmt.debug_struct("Item")
378 .field("source", &self.source)
379 .field("name", &self.name)
380 .field("attrs", &self.attrs)
381 .field("inner", &self.inner)
382 .field("visibility", &self.visibility)
383 .field("def_id", def_id)
384 .field("stability", &self.stability)
385 .field("deprecation", &self.deprecation)
386 .finish()
387 }
388 }
389
390 impl Item {
391 /// Finds the `doc` attribute as a NameValue and returns the corresponding
392 /// value found.
393 pub fn doc_value(&self) -> Option<&str> {
394 self.attrs.doc_value()
395 }
396 /// Finds all `doc` attributes as NameValues and returns their corresponding values, joined
397 /// with newlines.
398 pub fn collapsed_doc_value(&self) -> Option<String> {
399 self.attrs.collapsed_doc_value()
400 }
401
402 pub fn links(&self) -> Vec<(String, String)> {
403 self.attrs.links(&self.def_id.krate)
404 }
405
406 pub fn is_crate(&self) -> bool {
407 match self.inner {
408 StrippedItem(box ModuleItem(Module { is_crate: true, ..})) |
409 ModuleItem(Module { is_crate: true, ..}) => true,
410 _ => false,
411 }
412 }
413 pub fn is_mod(&self) -> bool {
414 self.type_() == ItemType::Module
415 }
416 pub fn is_trait(&self) -> bool {
417 self.type_() == ItemType::Trait
418 }
419 pub fn is_struct(&self) -> bool {
420 self.type_() == ItemType::Struct
421 }
422 pub fn is_enum(&self) -> bool {
423 self.type_() == ItemType::Enum
424 }
425 pub fn is_variant(&self) -> bool {
426 self.type_() == ItemType::Variant
427 }
428 pub fn is_associated_type(&self) -> bool {
429 self.type_() == ItemType::AssocType
430 }
431 pub fn is_associated_const(&self) -> bool {
432 self.type_() == ItemType::AssocConst
433 }
434 pub fn is_method(&self) -> bool {
435 self.type_() == ItemType::Method
436 }
437 pub fn is_ty_method(&self) -> bool {
438 self.type_() == ItemType::TyMethod
439 }
440 pub fn is_typedef(&self) -> bool {
441 self.type_() == ItemType::Typedef
442 }
443 pub fn is_primitive(&self) -> bool {
444 self.type_() == ItemType::Primitive
445 }
446 pub fn is_union(&self) -> bool {
447 self.type_() == ItemType::Union
448 }
449 pub fn is_import(&self) -> bool {
450 self.type_() == ItemType::Import
451 }
452 pub fn is_extern_crate(&self) -> bool {
453 self.type_() == ItemType::ExternCrate
454 }
455 pub fn is_keyword(&self) -> bool {
456 self.type_() == ItemType::Keyword
457 }
458
459 pub fn is_stripped(&self) -> bool {
460 match self.inner { StrippedItem(..) => true, _ => false }
461 }
462 pub fn has_stripped_fields(&self) -> Option<bool> {
463 match self.inner {
464 StructItem(ref _struct) => Some(_struct.fields_stripped),
465 UnionItem(ref union) => Some(union.fields_stripped),
466 VariantItem(Variant { kind: VariantKind::Struct(ref vstruct)} ) => {
467 Some(vstruct.fields_stripped)
468 },
469 _ => None,
470 }
471 }
472
473 pub fn stability_class(&self) -> Option<String> {
474 self.stability.as_ref().and_then(|ref s| {
475 let mut classes = Vec::with_capacity(2);
476
477 if s.level == stability::Unstable {
478 classes.push("unstable");
479 }
480
481 if s.deprecation.is_some() {
482 classes.push("deprecated");
483 }
484
485 if classes.len() != 0 {
486 Some(classes.join(" "))
487 } else {
488 None
489 }
490 })
491 }
492
493 pub fn stable_since(&self) -> Option<&str> {
494 self.stability.as_ref().map(|s| &s.since[..])
495 }
496
497 pub fn is_non_exhaustive(&self) -> bool {
498 self.attrs.other_attrs.iter()
499 .any(|a| a.check_name(sym::non_exhaustive))
500 }
501
502 /// Returns a documentation-level item type from the item.
503 pub fn type_(&self) -> ItemType {
504 ItemType::from(self)
505 }
506
507 /// Returns the info in the item's `#[deprecated]` or `#[rustc_deprecated]` attributes.
508 ///
509 /// If the item is not deprecated, returns `None`.
510 pub fn deprecation(&self) -> Option<&Deprecation> {
511 self.deprecation
512 .as_ref()
513 .or_else(|| self.stability.as_ref().and_then(|s| s.deprecation.as_ref()))
514 }
515 pub fn is_default(&self) -> bool {
516 match self.inner {
517 ItemEnum::MethodItem(ref meth) => {
518 if let Some(defaultness) = meth.defaultness {
519 defaultness.has_value() && !defaultness.is_final()
520 } else {
521 false
522 }
523 }
524 _ => false,
525 }
526 }
527 }
528
529 #[derive(Clone, Debug)]
530 pub enum ItemEnum {
531 ExternCrateItem(String, Option<String>),
532 ImportItem(Import),
533 StructItem(Struct),
534 UnionItem(Union),
535 EnumItem(Enum),
536 FunctionItem(Function),
537 ModuleItem(Module),
538 TypedefItem(Typedef, bool /* is associated type */),
539 OpaqueTyItem(OpaqueTy, bool /* is associated type */),
540 StaticItem(Static),
541 ConstantItem(Constant),
542 TraitItem(Trait),
543 TraitAliasItem(TraitAlias),
544 ImplItem(Impl),
545 /// A method signature only. Used for required methods in traits (ie,
546 /// non-default-methods).
547 TyMethodItem(TyMethod),
548 /// A method with a body.
549 MethodItem(Method),
550 StructFieldItem(Type),
551 VariantItem(Variant),
552 /// `fn`s from an extern block
553 ForeignFunctionItem(Function),
554 /// `static`s from an extern block
555 ForeignStaticItem(Static),
556 /// `type`s from an extern block
557 ForeignTypeItem,
558 MacroItem(Macro),
559 ProcMacroItem(ProcMacro),
560 PrimitiveItem(PrimitiveType),
561 AssocConstItem(Type, Option<String>),
562 AssocTypeItem(Vec<GenericBound>, Option<Type>),
563 /// An item that has been stripped by a rustdoc pass
564 StrippedItem(Box<ItemEnum>),
565 KeywordItem(String),
566 }
567
568 impl ItemEnum {
569 pub fn is_associated(&self) -> bool {
570 match *self {
571 ItemEnum::TypedefItem(_, _) |
572 ItemEnum::AssocTypeItem(_, _) => true,
573 _ => false,
574 }
575 }
576 }
577
578 #[derive(Clone, Debug)]
579 pub struct Module {
580 pub items: Vec<Item>,
581 pub is_crate: bool,
582 }
583
584 impl Clean<Item> for doctree::Module<'_> {
585 fn clean(&self, cx: &DocContext<'_>) -> Item {
586 let name = if self.name.is_some() {
587 self.name.expect("No name provided").clean(cx)
588 } else {
589 String::new()
590 };
591
592 // maintain a stack of mod ids, for doc comment path resolution
593 // but we also need to resolve the module's own docs based on whether its docs were written
594 // inside or outside the module, so check for that
595 let attrs = self.attrs.clean(cx);
596
597 let mut items: Vec<Item> = vec![];
598 items.extend(self.extern_crates.iter().flat_map(|x| x.clean(cx)));
599 items.extend(self.imports.iter().flat_map(|x| x.clean(cx)));
600 items.extend(self.structs.iter().map(|x| x.clean(cx)));
601 items.extend(self.unions.iter().map(|x| x.clean(cx)));
602 items.extend(self.enums.iter().map(|x| x.clean(cx)));
603 items.extend(self.fns.iter().map(|x| x.clean(cx)));
604 items.extend(self.foreigns.iter().map(|x| x.clean(cx)));
605 items.extend(self.mods.iter().map(|x| x.clean(cx)));
606 items.extend(self.typedefs.iter().map(|x| x.clean(cx)));
607 items.extend(self.opaque_tys.iter().map(|x| x.clean(cx)));
608 items.extend(self.statics.iter().map(|x| x.clean(cx)));
609 items.extend(self.constants.iter().map(|x| x.clean(cx)));
610 items.extend(self.traits.iter().map(|x| x.clean(cx)));
611 items.extend(self.impls.iter().flat_map(|x| x.clean(cx)));
612 items.extend(self.macros.iter().map(|x| x.clean(cx)));
613 items.extend(self.proc_macros.iter().map(|x| x.clean(cx)));
614 items.extend(self.trait_aliases.iter().map(|x| x.clean(cx)));
615
616 // determine if we should display the inner contents or
617 // the outer `mod` item for the source code.
618 let whence = {
619 let cm = cx.sess().source_map();
620 let outer = cm.lookup_char_pos(self.where_outer.lo());
621 let inner = cm.lookup_char_pos(self.where_inner.lo());
622 if outer.file.start_pos == inner.file.start_pos {
623 // mod foo { ... }
624 self.where_outer
625 } else {
626 // mod foo; (and a separate SourceFile for the contents)
627 self.where_inner
628 }
629 };
630
631 Item {
632 name: Some(name),
633 attrs,
634 source: whence.clean(cx),
635 visibility: self.vis.clean(cx),
636 stability: cx.stability(self.id).clean(cx),
637 deprecation: cx.deprecation(self.id).clean(cx),
638 def_id: cx.tcx.hir().local_def_id(self.id),
639 inner: ModuleItem(Module {
640 is_crate: self.is_crate,
641 items,
642 })
643 }
644 }
645 }
646
647 pub struct ListAttributesIter<'a> {
648 attrs: slice::Iter<'a, ast::Attribute>,
649 current_list: vec::IntoIter<ast::NestedMetaItem>,
650 name: Symbol,
651 }
652
653 impl<'a> Iterator for ListAttributesIter<'a> {
654 type Item = ast::NestedMetaItem;
655
656 fn next(&mut self) -> Option<Self::Item> {
657 if let Some(nested) = self.current_list.next() {
658 return Some(nested);
659 }
660
661 for attr in &mut self.attrs {
662 if let Some(list) = attr.meta_item_list() {
663 if attr.check_name(self.name) {
664 self.current_list = list.into_iter();
665 if let Some(nested) = self.current_list.next() {
666 return Some(nested);
667 }
668 }
669 }
670 }
671
672 None
673 }
674
675 fn size_hint(&self) -> (usize, Option<usize>) {
676 let lower = self.current_list.len();
677 (lower, None)
678 }
679 }
680
681 pub trait AttributesExt {
682 /// Finds an attribute as List and returns the list of attributes nested inside.
683 fn lists(&self, name: Symbol) -> ListAttributesIter<'_>;
684 }
685
686 impl AttributesExt for [ast::Attribute] {
687 fn lists(&self, name: Symbol) -> ListAttributesIter<'_> {
688 ListAttributesIter {
689 attrs: self.iter(),
690 current_list: Vec::new().into_iter(),
691 name,
692 }
693 }
694 }
695
696 pub trait NestedAttributesExt {
697 /// Returns `true` if the attribute list contains a specific `Word`
698 fn has_word(self, word: Symbol) -> bool;
699 }
700
701 impl<I: IntoIterator<Item=ast::NestedMetaItem>> NestedAttributesExt for I {
702 fn has_word(self, word: Symbol) -> bool {
703 self.into_iter().any(|attr| attr.is_word() && attr.check_name(word))
704 }
705 }
706
707 /// A portion of documentation, extracted from a `#[doc]` attribute.
708 ///
709 /// Each variant contains the line number within the complete doc-comment where the fragment
710 /// starts, as well as the Span where the corresponding doc comment or attribute is located.
711 ///
712 /// Included files are kept separate from inline doc comments so that proper line-number
713 /// information can be given when a doctest fails. Sugared doc comments and "raw" doc comments are
714 /// kept separate because of issue #42760.
715 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
716 pub enum DocFragment {
717 /// A doc fragment created from a `///` or `//!` doc comment.
718 SugaredDoc(usize, syntax_pos::Span, String),
719 /// A doc fragment created from a "raw" `#[doc=""]` attribute.
720 RawDoc(usize, syntax_pos::Span, String),
721 /// A doc fragment created from a `#[doc(include="filename")]` attribute. Contains both the
722 /// given filename and the file contents.
723 Include(usize, syntax_pos::Span, String, String),
724 }
725
726 impl DocFragment {
727 pub fn as_str(&self) -> &str {
728 match *self {
729 DocFragment::SugaredDoc(_, _, ref s) => &s[..],
730 DocFragment::RawDoc(_, _, ref s) => &s[..],
731 DocFragment::Include(_, _, _, ref s) => &s[..],
732 }
733 }
734
735 pub fn span(&self) -> syntax_pos::Span {
736 match *self {
737 DocFragment::SugaredDoc(_, span, _) |
738 DocFragment::RawDoc(_, span, _) |
739 DocFragment::Include(_, span, _, _) => span,
740 }
741 }
742 }
743
744 impl<'a> FromIterator<&'a DocFragment> for String {
745 fn from_iter<T>(iter: T) -> Self
746 where
747 T: IntoIterator<Item = &'a DocFragment>
748 {
749 iter.into_iter().fold(String::new(), |mut acc, frag| {
750 if !acc.is_empty() {
751 acc.push('\n');
752 }
753 match *frag {
754 DocFragment::SugaredDoc(_, _, ref docs)
755 | DocFragment::RawDoc(_, _, ref docs)
756 | DocFragment::Include(_, _, _, ref docs) =>
757 acc.push_str(docs),
758 }
759
760 acc
761 })
762 }
763 }
764
765 #[derive(Clone, Debug, Default)]
766 pub struct Attributes {
767 pub doc_strings: Vec<DocFragment>,
768 pub other_attrs: Vec<ast::Attribute>,
769 pub cfg: Option<Arc<Cfg>>,
770 pub span: Option<syntax_pos::Span>,
771 /// map from Rust paths to resolved defs and potential URL fragments
772 pub links: Vec<(String, Option<DefId>, Option<String>)>,
773 pub inner_docs: bool,
774 }
775
776 impl Attributes {
777 /// Extracts the content from an attribute `#[doc(cfg(content))]`.
778 fn extract_cfg(mi: &ast::MetaItem) -> Option<&ast::MetaItem> {
779 use syntax::ast::NestedMetaItem::MetaItem;
780
781 if let ast::MetaItemKind::List(ref nmis) = mi.kind {
782 if nmis.len() == 1 {
783 if let MetaItem(ref cfg_mi) = nmis[0] {
784 if cfg_mi.check_name(sym::cfg) {
785 if let ast::MetaItemKind::List(ref cfg_nmis) = cfg_mi.kind {
786 if cfg_nmis.len() == 1 {
787 if let MetaItem(ref content_mi) = cfg_nmis[0] {
788 return Some(content_mi);
789 }
790 }
791 }
792 }
793 }
794 }
795 }
796
797 None
798 }
799
800 /// Reads a `MetaItem` from within an attribute, looks for whether it is a
801 /// `#[doc(include="file")]`, and returns the filename and contents of the file as loaded from
802 /// its expansion.
803 fn extract_include(mi: &ast::MetaItem)
804 -> Option<(String, String)>
805 {
806 mi.meta_item_list().and_then(|list| {
807 for meta in list {
808 if meta.check_name(sym::include) {
809 // the actual compiled `#[doc(include="filename")]` gets expanded to
810 // `#[doc(include(file="filename", contents="file contents")]` so we need to
811 // look for that instead
812 return meta.meta_item_list().and_then(|list| {
813 let mut filename: Option<String> = None;
814 let mut contents: Option<String> = None;
815
816 for it in list {
817 if it.check_name(sym::file) {
818 if let Some(name) = it.value_str() {
819 filename = Some(name.to_string());
820 }
821 } else if it.check_name(sym::contents) {
822 if let Some(docs) = it.value_str() {
823 contents = Some(docs.to_string());
824 }
825 }
826 }
827
828 if let (Some(filename), Some(contents)) = (filename, contents) {
829 Some((filename, contents))
830 } else {
831 None
832 }
833 });
834 }
835 }
836
837 None
838 })
839 }
840
841 pub fn has_doc_flag(&self, flag: Symbol) -> bool {
842 for attr in &self.other_attrs {
843 if !attr.check_name(sym::doc) { continue; }
844
845 if let Some(items) = attr.meta_item_list() {
846 if items.iter().filter_map(|i| i.meta_item()).any(|it| it.check_name(flag)) {
847 return true;
848 }
849 }
850 }
851
852 false
853 }
854
855 pub fn from_ast(diagnostic: &::errors::Handler,
856 attrs: &[ast::Attribute]) -> Attributes {
857 let mut doc_strings = vec![];
858 let mut sp = None;
859 let mut cfg = Cfg::True;
860 let mut doc_line = 0;
861
862 /// Converts `attr` to a normal `#[doc="foo"]` comment, if it is a
863 /// comment like `///` or `/** */`. (Returns `attr` unchanged for
864 /// non-sugared doc attributes.)
865 pub fn with_desugared_doc<T>(attr: &Attribute, f: impl FnOnce(&Attribute) -> T) -> T {
866 if attr.is_sugared_doc {
867 let comment = attr.value_str().unwrap();
868 let meta = attr::mk_name_value_item_str(
869 Ident::with_dummy_span(sym::doc),
870 Symbol::intern(&comments::strip_doc_comment_decoration(&comment.as_str())),
871 DUMMY_SP,
872 );
873 f(&Attribute {
874 item: AttrItem { path: meta.path, tokens: meta.kind.tokens(meta.span) },
875 id: attr.id,
876 style: attr.style,
877 is_sugared_doc: true,
878 span: attr.span,
879 })
880 } else {
881 f(attr)
882 }
883 }
884
885 let other_attrs = attrs.iter().filter_map(|attr| {
886 with_desugared_doc(attr, |attr| {
887 if attr.check_name(sym::doc) {
888 if let Some(mi) = attr.meta() {
889 if let Some(value) = mi.value_str() {
890 // Extracted #[doc = "..."]
891 let value = value.to_string();
892 let line = doc_line;
893 doc_line += value.lines().count();
894
895 if attr.is_sugared_doc {
896 doc_strings.push(DocFragment::SugaredDoc(line, attr.span, value));
897 } else {
898 doc_strings.push(DocFragment::RawDoc(line, attr.span, value));
899 }
900
901 if sp.is_none() {
902 sp = Some(attr.span);
903 }
904 return None;
905 } else if let Some(cfg_mi) = Attributes::extract_cfg(&mi) {
906 // Extracted #[doc(cfg(...))]
907 match Cfg::parse(cfg_mi) {
908 Ok(new_cfg) => cfg &= new_cfg,
909 Err(e) => diagnostic.span_err(e.span, e.msg),
910 }
911 return None;
912 } else if let Some((filename, contents)) = Attributes::extract_include(&mi)
913 {
914 let line = doc_line;
915 doc_line += contents.lines().count();
916 doc_strings.push(DocFragment::Include(line,
917 attr.span,
918 filename,
919 contents));
920 }
921 }
922 }
923 Some(attr.clone())
924 })
925 }).collect();
926
927 // treat #[target_feature(enable = "feat")] attributes as if they were
928 // #[doc(cfg(target_feature = "feat"))] attributes as well
929 for attr in attrs.lists(sym::target_feature) {
930 if attr.check_name(sym::enable) {
931 if let Some(feat) = attr.value_str() {
932 let meta = attr::mk_name_value_item_str(
933 Ident::with_dummy_span(sym::target_feature), feat, DUMMY_SP
934 );
935 if let Ok(feat_cfg) = Cfg::parse(&meta) {
936 cfg &= feat_cfg;
937 }
938 }
939 }
940 }
941
942 let inner_docs = attrs.iter()
943 .filter(|a| a.check_name(sym::doc))
944 .next()
945 .map_or(true, |a| a.style == AttrStyle::Inner);
946
947 Attributes {
948 doc_strings,
949 other_attrs,
950 cfg: if cfg == Cfg::True { None } else { Some(Arc::new(cfg)) },
951 span: sp,
952 links: vec![],
953 inner_docs,
954 }
955 }
956
957 /// Finds the `doc` attribute as a NameValue and returns the corresponding
958 /// value found.
959 pub fn doc_value(&self) -> Option<&str> {
960 self.doc_strings.first().map(|s| s.as_str())
961 }
962
963 /// Finds all `doc` attributes as NameValues and returns their corresponding values, joined
964 /// with newlines.
965 pub fn collapsed_doc_value(&self) -> Option<String> {
966 if !self.doc_strings.is_empty() {
967 Some(self.doc_strings.iter().collect())
968 } else {
969 None
970 }
971 }
972
973 /// Gets links as a vector
974 ///
975 /// Cache must be populated before call
976 pub fn links(&self, krate: &CrateNum) -> Vec<(String, String)> {
977 use crate::html::format::href;
978
979 self.links.iter().filter_map(|&(ref s, did, ref fragment)| {
980 match did {
981 Some(did) => {
982 if let Some((mut href, ..)) = href(did) {
983 if let Some(ref fragment) = *fragment {
984 href.push_str("#");
985 href.push_str(fragment);
986 }
987 Some((s.clone(), href))
988 } else {
989 None
990 }
991 }
992 None => {
993 if let Some(ref fragment) = *fragment {
994 let cache = cache();
995 let url = match cache.extern_locations.get(krate) {
996 Some(&(_, ref src, ExternalLocation::Local)) =>
997 src.to_str().expect("invalid file path"),
998 Some(&(_, _, ExternalLocation::Remote(ref s))) => s,
999 Some(&(_, _, ExternalLocation::Unknown)) | None =>
1000 "https://doc.rust-lang.org/nightly",
1001 };
1002 // This is a primitive so the url is done "by hand".
1003 let tail = fragment.find('#').unwrap_or_else(|| fragment.len());
1004 Some((s.clone(),
1005 format!("{}{}std/primitive.{}.html{}",
1006 url,
1007 if !url.ends_with('/') { "/" } else { "" },
1008 &fragment[..tail],
1009 &fragment[tail..])))
1010 } else {
1011 panic!("This isn't a primitive?!");
1012 }
1013 }
1014 }
1015 }).collect()
1016 }
1017 }
1018
1019 impl PartialEq for Attributes {
1020 fn eq(&self, rhs: &Self) -> bool {
1021 self.doc_strings == rhs.doc_strings &&
1022 self.cfg == rhs.cfg &&
1023 self.span == rhs.span &&
1024 self.links == rhs.links &&
1025 self.other_attrs.iter().map(|attr| attr.id).eq(rhs.other_attrs.iter().map(|attr| attr.id))
1026 }
1027 }
1028
1029 impl Eq for Attributes {}
1030
1031 impl Hash for Attributes {
1032 fn hash<H: Hasher>(&self, hasher: &mut H) {
1033 self.doc_strings.hash(hasher);
1034 self.cfg.hash(hasher);
1035 self.span.hash(hasher);
1036 self.links.hash(hasher);
1037 for attr in &self.other_attrs {
1038 attr.id.hash(hasher);
1039 }
1040 }
1041 }
1042
1043 impl AttributesExt for Attributes {
1044 fn lists(&self, name: Symbol) -> ListAttributesIter<'_> {
1045 self.other_attrs.lists(name)
1046 }
1047 }
1048
1049 impl Clean<Attributes> for [ast::Attribute] {
1050 fn clean(&self, cx: &DocContext<'_>) -> Attributes {
1051 Attributes::from_ast(cx.sess().diagnostic(), self)
1052 }
1053 }
1054
1055 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
1056 pub enum GenericBound {
1057 TraitBound(PolyTrait, hir::TraitBoundModifier),
1058 Outlives(Lifetime),
1059 }
1060
1061 impl GenericBound {
1062 fn maybe_sized(cx: &DocContext<'_>) -> GenericBound {
1063 let did = cx.tcx.require_lang_item(lang_items::SizedTraitLangItem, None);
1064 let empty = cx.tcx.intern_substs(&[]);
1065 let path = external_path(cx, cx.tcx.item_name(did),
1066 Some(did), false, vec![], empty);
1067 inline::record_extern_fqn(cx, did, TypeKind::Trait);
1068 GenericBound::TraitBound(PolyTrait {
1069 trait_: ResolvedPath {
1070 path,
1071 param_names: None,
1072 did,
1073 is_generic: false,
1074 },
1075 generic_params: Vec::new(),
1076 }, hir::TraitBoundModifier::Maybe)
1077 }
1078
1079 fn is_sized_bound(&self, cx: &DocContext<'_>) -> bool {
1080 use rustc::hir::TraitBoundModifier as TBM;
1081 if let GenericBound::TraitBound(PolyTrait { ref trait_, .. }, TBM::None) = *self {
1082 if trait_.def_id() == cx.tcx.lang_items().sized_trait() {
1083 return true;
1084 }
1085 }
1086 false
1087 }
1088
1089 fn get_poly_trait(&self) -> Option<PolyTrait> {
1090 if let GenericBound::TraitBound(ref p, _) = *self {
1091 return Some(p.clone())
1092 }
1093 None
1094 }
1095
1096 fn get_trait_type(&self) -> Option<Type> {
1097 if let GenericBound::TraitBound(PolyTrait { ref trait_, .. }, _) = *self {
1098 Some(trait_.clone())
1099 } else {
1100 None
1101 }
1102 }
1103 }
1104
1105 impl Clean<GenericBound> for hir::GenericBound {
1106 fn clean(&self, cx: &DocContext<'_>) -> GenericBound {
1107 match *self {
1108 hir::GenericBound::Outlives(lt) => GenericBound::Outlives(lt.clean(cx)),
1109 hir::GenericBound::Trait(ref t, modifier) => {
1110 GenericBound::TraitBound(t.clean(cx), modifier)
1111 }
1112 }
1113 }
1114 }
1115
1116 fn external_generic_args(
1117 cx: &DocContext<'_>,
1118 trait_did: Option<DefId>,
1119 has_self: bool,
1120 bindings: Vec<TypeBinding>,
1121 substs: SubstsRef<'_>,
1122 ) -> GenericArgs {
1123 let mut skip_self = has_self;
1124 let mut ty_kind = None;
1125 let args: Vec<_> = substs.iter().filter_map(|kind| match kind.unpack() {
1126 GenericArgKind::Lifetime(lt) => {
1127 lt.clean(cx).and_then(|lt| Some(GenericArg::Lifetime(lt)))
1128 }
1129 GenericArgKind::Type(_) if skip_self => {
1130 skip_self = false;
1131 None
1132 }
1133 GenericArgKind::Type(ty) => {
1134 ty_kind = Some(&ty.kind);
1135 Some(GenericArg::Type(ty.clean(cx)))
1136 }
1137 GenericArgKind::Const(ct) => Some(GenericArg::Const(ct.clean(cx))),
1138 }).collect();
1139
1140 match trait_did {
1141 // Attempt to sugar an external path like Fn<(A, B,), C> to Fn(A, B) -> C
1142 Some(did) if cx.tcx.lang_items().fn_trait_kind(did).is_some() => {
1143 assert!(ty_kind.is_some());
1144 let inputs = match ty_kind {
1145 Some(ty::Tuple(ref tys)) => tys.iter().map(|t| t.expect_ty().clean(cx)).collect(),
1146 _ => return GenericArgs::AngleBracketed { args, bindings },
1147 };
1148 let output = None;
1149 // FIXME(#20299) return type comes from a projection now
1150 // match types[1].kind {
1151 // ty::Tuple(ref v) if v.is_empty() => None, // -> ()
1152 // _ => Some(types[1].clean(cx))
1153 // };
1154 GenericArgs::Parenthesized { inputs, output }
1155 },
1156 _ => {
1157 GenericArgs::AngleBracketed { args, bindings }
1158 }
1159 }
1160 }
1161
1162 // trait_did should be set to a trait's DefId if called on a TraitRef, in order to sugar
1163 // from Fn<(A, B,), C> to Fn(A, B) -> C
1164 fn external_path(cx: &DocContext<'_>, name: Symbol, trait_did: Option<DefId>, has_self: bool,
1165 bindings: Vec<TypeBinding>, substs: SubstsRef<'_>) -> Path {
1166 Path {
1167 global: false,
1168 res: Res::Err,
1169 segments: vec![PathSegment {
1170 name: name.as_str().to_string(),
1171 args: external_generic_args(cx, trait_did, has_self, bindings, substs)
1172 }],
1173 }
1174 }
1175
1176 impl<'a, 'tcx> Clean<GenericBound> for (&'a ty::TraitRef<'tcx>, Vec<TypeBinding>) {
1177 fn clean(&self, cx: &DocContext<'_>) -> GenericBound {
1178 let (trait_ref, ref bounds) = *self;
1179 inline::record_extern_fqn(cx, trait_ref.def_id, TypeKind::Trait);
1180 let path = external_path(cx, cx.tcx.item_name(trait_ref.def_id),
1181 Some(trait_ref.def_id), true, bounds.clone(), trait_ref.substs);
1182
1183 debug!("ty::TraitRef\n subst: {:?}\n", trait_ref.substs);
1184
1185 // collect any late bound regions
1186 let mut late_bounds = vec![];
1187 for ty_s in trait_ref.input_types().skip(1) {
1188 if let ty::Tuple(ts) = ty_s.kind {
1189 for &ty_s in ts {
1190 if let ty::Ref(ref reg, _, _) = ty_s.expect_ty().kind {
1191 if let &ty::RegionKind::ReLateBound(..) = *reg {
1192 debug!(" hit an ReLateBound {:?}", reg);
1193 if let Some(Lifetime(name)) = reg.clean(cx) {
1194 late_bounds.push(GenericParamDef {
1195 name,
1196 kind: GenericParamDefKind::Lifetime,
1197 });
1198 }
1199 }
1200 }
1201 }
1202 }
1203 }
1204
1205 GenericBound::TraitBound(
1206 PolyTrait {
1207 trait_: ResolvedPath {
1208 path,
1209 param_names: None,
1210 did: trait_ref.def_id,
1211 is_generic: false,
1212 },
1213 generic_params: late_bounds,
1214 },
1215 hir::TraitBoundModifier::None
1216 )
1217 }
1218 }
1219
1220 impl<'tcx> Clean<GenericBound> for ty::TraitRef<'tcx> {
1221 fn clean(&self, cx: &DocContext<'_>) -> GenericBound {
1222 (self, vec![]).clean(cx)
1223 }
1224 }
1225
1226 impl<'tcx> Clean<Option<Vec<GenericBound>>> for InternalSubsts<'tcx> {
1227 fn clean(&self, cx: &DocContext<'_>) -> Option<Vec<GenericBound>> {
1228 let mut v = Vec::new();
1229 v.extend(self.regions().filter_map(|r| r.clean(cx)).map(GenericBound::Outlives));
1230 v.extend(self.types().map(|t| GenericBound::TraitBound(PolyTrait {
1231 trait_: t.clean(cx),
1232 generic_params: Vec::new(),
1233 }, hir::TraitBoundModifier::None)));
1234 if !v.is_empty() {Some(v)} else {None}
1235 }
1236 }
1237
1238 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
1239 pub struct Lifetime(String);
1240
1241 impl Lifetime {
1242 pub fn get_ref<'a>(&'a self) -> &'a str {
1243 let Lifetime(ref s) = *self;
1244 let s: &'a str = s;
1245 s
1246 }
1247
1248 pub fn statik() -> Lifetime {
1249 Lifetime("'static".to_string())
1250 }
1251 }
1252
1253 impl Clean<Lifetime> for hir::Lifetime {
1254 fn clean(&self, cx: &DocContext<'_>) -> Lifetime {
1255 if self.hir_id != hir::DUMMY_HIR_ID {
1256 let def = cx.tcx.named_region(self.hir_id);
1257 match def {
1258 Some(rl::Region::EarlyBound(_, node_id, _)) |
1259 Some(rl::Region::LateBound(_, node_id, _)) |
1260 Some(rl::Region::Free(_, node_id)) => {
1261 if let Some(lt) = cx.lt_substs.borrow().get(&node_id).cloned() {
1262 return lt;
1263 }
1264 }
1265 _ => {}
1266 }
1267 }
1268 Lifetime(self.name.ident().to_string())
1269 }
1270 }
1271
1272 impl Clean<Lifetime> for hir::GenericParam {
1273 fn clean(&self, _: &DocContext<'_>) -> Lifetime {
1274 match self.kind {
1275 hir::GenericParamKind::Lifetime { .. } => {
1276 if self.bounds.len() > 0 {
1277 let mut bounds = self.bounds.iter().map(|bound| match bound {
1278 hir::GenericBound::Outlives(lt) => lt,
1279 _ => panic!(),
1280 });
1281 let name = bounds.next().expect("no more bounds").name.ident();
1282 let mut s = format!("{}: {}", self.name.ident(), name);
1283 for bound in bounds {
1284 s.push_str(&format!(" + {}", bound.name.ident()));
1285 }
1286 Lifetime(s)
1287 } else {
1288 Lifetime(self.name.ident().to_string())
1289 }
1290 }
1291 _ => panic!(),
1292 }
1293 }
1294 }
1295
1296 impl Clean<Constant> for hir::ConstArg {
1297 fn clean(&self, cx: &DocContext<'_>) -> Constant {
1298 Constant {
1299 type_: cx.tcx.type_of(cx.tcx.hir().body_owner_def_id(self.value.body)).clean(cx),
1300 expr: print_const_expr(cx, self.value.body),
1301 }
1302 }
1303 }
1304
1305 impl Clean<Lifetime> for ty::GenericParamDef {
1306 fn clean(&self, _cx: &DocContext<'_>) -> Lifetime {
1307 Lifetime(self.name.to_string())
1308 }
1309 }
1310
1311 impl Clean<Option<Lifetime>> for ty::RegionKind {
1312 fn clean(&self, cx: &DocContext<'_>) -> Option<Lifetime> {
1313 match *self {
1314 ty::ReStatic => Some(Lifetime::statik()),
1315 ty::ReLateBound(_, ty::BrNamed(_, name)) => Some(Lifetime(name.to_string())),
1316 ty::ReEarlyBound(ref data) => Some(Lifetime(data.name.clean(cx))),
1317
1318 ty::ReLateBound(..) |
1319 ty::ReFree(..) |
1320 ty::ReScope(..) |
1321 ty::ReVar(..) |
1322 ty::RePlaceholder(..) |
1323 ty::ReEmpty |
1324 ty::ReClosureBound(_) |
1325 ty::ReErased => {
1326 debug!("cannot clean region {:?}", self);
1327 None
1328 }
1329 }
1330 }
1331 }
1332
1333 #[derive(Clone, Debug)]
1334 pub enum WherePredicate {
1335 BoundPredicate { ty: Type, bounds: Vec<GenericBound> },
1336 RegionPredicate { lifetime: Lifetime, bounds: Vec<GenericBound> },
1337 EqPredicate { lhs: Type, rhs: Type },
1338 }
1339
1340 impl WherePredicate {
1341 pub fn get_bounds(&self) -> Option<&[GenericBound]> {
1342 match *self {
1343 WherePredicate::BoundPredicate { ref bounds, .. } => Some(bounds),
1344 WherePredicate::RegionPredicate { ref bounds, .. } => Some(bounds),
1345 _ => None,
1346 }
1347 }
1348 }
1349
1350 impl Clean<WherePredicate> for hir::WherePredicate {
1351 fn clean(&self, cx: &DocContext<'_>) -> WherePredicate {
1352 match *self {
1353 hir::WherePredicate::BoundPredicate(ref wbp) => {
1354 WherePredicate::BoundPredicate {
1355 ty: wbp.bounded_ty.clean(cx),
1356 bounds: wbp.bounds.clean(cx)
1357 }
1358 }
1359
1360 hir::WherePredicate::RegionPredicate(ref wrp) => {
1361 WherePredicate::RegionPredicate {
1362 lifetime: wrp.lifetime.clean(cx),
1363 bounds: wrp.bounds.clean(cx)
1364 }
1365 }
1366
1367 hir::WherePredicate::EqPredicate(ref wrp) => {
1368 WherePredicate::EqPredicate {
1369 lhs: wrp.lhs_ty.clean(cx),
1370 rhs: wrp.rhs_ty.clean(cx)
1371 }
1372 }
1373 }
1374 }
1375 }
1376
1377 impl<'a> Clean<Option<WherePredicate>> for ty::Predicate<'a> {
1378 fn clean(&self, cx: &DocContext<'_>) -> Option<WherePredicate> {
1379 use rustc::ty::Predicate;
1380
1381 match *self {
1382 Predicate::Trait(ref pred) => Some(pred.clean(cx)),
1383 Predicate::Subtype(ref pred) => Some(pred.clean(cx)),
1384 Predicate::RegionOutlives(ref pred) => pred.clean(cx),
1385 Predicate::TypeOutlives(ref pred) => pred.clean(cx),
1386 Predicate::Projection(ref pred) => Some(pred.clean(cx)),
1387
1388 Predicate::WellFormed(..) |
1389 Predicate::ObjectSafe(..) |
1390 Predicate::ClosureKind(..) |
1391 Predicate::ConstEvaluatable(..) => panic!("not user writable"),
1392 }
1393 }
1394 }
1395
1396 impl<'a> Clean<WherePredicate> for ty::TraitPredicate<'a> {
1397 fn clean(&self, cx: &DocContext<'_>) -> WherePredicate {
1398 WherePredicate::BoundPredicate {
1399 ty: self.trait_ref.self_ty().clean(cx),
1400 bounds: vec![self.trait_ref.clean(cx)]
1401 }
1402 }
1403 }
1404
1405 impl<'tcx> Clean<WherePredicate> for ty::SubtypePredicate<'tcx> {
1406 fn clean(&self, _cx: &DocContext<'_>) -> WherePredicate {
1407 panic!("subtype predicates are an internal rustc artifact \
1408 and should not be seen by rustdoc")
1409 }
1410 }
1411
1412 impl<'tcx> Clean<Option<WherePredicate>> for
1413 ty::OutlivesPredicate<ty::Region<'tcx>,ty::Region<'tcx>> {
1414
1415 fn clean(&self, cx: &DocContext<'_>) -> Option<WherePredicate> {
1416 let ty::OutlivesPredicate(ref a, ref b) = *self;
1417
1418 match (a, b) {
1419 (ty::ReEmpty, ty::ReEmpty) => {
1420 return None;
1421 },
1422 _ => {}
1423 }
1424
1425 Some(WherePredicate::RegionPredicate {
1426 lifetime: a.clean(cx).expect("failed to clean lifetime"),
1427 bounds: vec![GenericBound::Outlives(b.clean(cx).expect("failed to clean bounds"))]
1428 })
1429 }
1430 }
1431
1432 impl<'tcx> Clean<Option<WherePredicate>> for ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>> {
1433 fn clean(&self, cx: &DocContext<'_>) -> Option<WherePredicate> {
1434 let ty::OutlivesPredicate(ref ty, ref lt) = *self;
1435
1436 match lt {
1437 ty::ReEmpty => return None,
1438 _ => {}
1439 }
1440
1441 Some(WherePredicate::BoundPredicate {
1442 ty: ty.clean(cx),
1443 bounds: vec![GenericBound::Outlives(lt.clean(cx).expect("failed to clean lifetimes"))]
1444 })
1445 }
1446 }
1447
1448 impl<'tcx> Clean<WherePredicate> for ty::ProjectionPredicate<'tcx> {
1449 fn clean(&self, cx: &DocContext<'_>) -> WherePredicate {
1450 WherePredicate::EqPredicate {
1451 lhs: self.projection_ty.clean(cx),
1452 rhs: self.ty.clean(cx)
1453 }
1454 }
1455 }
1456
1457 impl<'tcx> Clean<Type> for ty::ProjectionTy<'tcx> {
1458 fn clean(&self, cx: &DocContext<'_>) -> Type {
1459 let trait_ = match self.trait_ref(cx.tcx).clean(cx) {
1460 GenericBound::TraitBound(t, _) => t.trait_,
1461 GenericBound::Outlives(_) => panic!("cleaning a trait got a lifetime"),
1462 };
1463 Type::QPath {
1464 name: cx.tcx.associated_item(self.item_def_id).ident.name.clean(cx),
1465 self_type: box self.self_ty().clean(cx),
1466 trait_: box trait_
1467 }
1468 }
1469 }
1470
1471 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
1472 pub enum GenericParamDefKind {
1473 Lifetime,
1474 Type {
1475 did: DefId,
1476 bounds: Vec<GenericBound>,
1477 default: Option<Type>,
1478 synthetic: Option<hir::SyntheticTyParamKind>,
1479 },
1480 Const {
1481 did: DefId,
1482 ty: Type,
1483 },
1484 }
1485
1486 impl GenericParamDefKind {
1487 pub fn is_type(&self) -> bool {
1488 match *self {
1489 GenericParamDefKind::Type { .. } => true,
1490 _ => false,
1491 }
1492 }
1493
1494 pub fn get_type(&self, cx: &DocContext<'_>) -> Option<Type> {
1495 match *self {
1496 GenericParamDefKind::Type { did, .. } => {
1497 rustc_typeck::checked_type_of(cx.tcx, did, false).map(|t| t.clean(cx))
1498 }
1499 GenericParamDefKind::Const { ref ty, .. } => Some(ty.clone()),
1500 GenericParamDefKind::Lifetime => None,
1501 }
1502 }
1503 }
1504
1505 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
1506 pub struct GenericParamDef {
1507 pub name: String,
1508
1509 pub kind: GenericParamDefKind,
1510 }
1511
1512 impl GenericParamDef {
1513 pub fn is_synthetic_type_param(&self) -> bool {
1514 match self.kind {
1515 GenericParamDefKind::Lifetime |
1516 GenericParamDefKind::Const { .. } => false,
1517 GenericParamDefKind::Type { ref synthetic, .. } => synthetic.is_some(),
1518 }
1519 }
1520
1521 pub fn is_type(&self) -> bool {
1522 self.kind.is_type()
1523 }
1524
1525 pub fn get_type(&self, cx: &DocContext<'_>) -> Option<Type> {
1526 self.kind.get_type(cx)
1527 }
1528
1529 pub fn get_bounds(&self) -> Option<&[GenericBound]> {
1530 match self.kind {
1531 GenericParamDefKind::Type { ref bounds, .. } => Some(bounds),
1532 _ => None,
1533 }
1534 }
1535 }
1536
1537 impl Clean<GenericParamDef> for ty::GenericParamDef {
1538 fn clean(&self, cx: &DocContext<'_>) -> GenericParamDef {
1539 let (name, kind) = match self.kind {
1540 ty::GenericParamDefKind::Lifetime => {
1541 (self.name.to_string(), GenericParamDefKind::Lifetime)
1542 }
1543 ty::GenericParamDefKind::Type { has_default, synthetic, .. } => {
1544 let default = if has_default {
1545 Some(cx.tcx.type_of(self.def_id).clean(cx))
1546 } else {
1547 None
1548 };
1549 (self.name.clean(cx), GenericParamDefKind::Type {
1550 did: self.def_id,
1551 bounds: vec![], // These are filled in from the where-clauses.
1552 default,
1553 synthetic,
1554 })
1555 }
1556 ty::GenericParamDefKind::Const { .. } => {
1557 (self.name.clean(cx), GenericParamDefKind::Const {
1558 did: self.def_id,
1559 ty: cx.tcx.type_of(self.def_id).clean(cx),
1560 })
1561 }
1562 };
1563
1564 GenericParamDef {
1565 name,
1566 kind,
1567 }
1568 }
1569 }
1570
1571 impl Clean<GenericParamDef> for hir::GenericParam {
1572 fn clean(&self, cx: &DocContext<'_>) -> GenericParamDef {
1573 let (name, kind) = match self.kind {
1574 hir::GenericParamKind::Lifetime { .. } => {
1575 let name = if self.bounds.len() > 0 {
1576 let mut bounds = self.bounds.iter().map(|bound| match bound {
1577 hir::GenericBound::Outlives(lt) => lt,
1578 _ => panic!(),
1579 });
1580 let name = bounds.next().expect("no more bounds").name.ident();
1581 let mut s = format!("{}: {}", self.name.ident(), name);
1582 for bound in bounds {
1583 s.push_str(&format!(" + {}", bound.name.ident()));
1584 }
1585 s
1586 } else {
1587 self.name.ident().to_string()
1588 };
1589 (name, GenericParamDefKind::Lifetime)
1590 }
1591 hir::GenericParamKind::Type { ref default, synthetic } => {
1592 (self.name.ident().name.clean(cx), GenericParamDefKind::Type {
1593 did: cx.tcx.hir().local_def_id(self.hir_id),
1594 bounds: self.bounds.clean(cx),
1595 default: default.clean(cx),
1596 synthetic,
1597 })
1598 }
1599 hir::GenericParamKind::Const { ref ty } => {
1600 (self.name.ident().name.clean(cx), GenericParamDefKind::Const {
1601 did: cx.tcx.hir().local_def_id(self.hir_id),
1602 ty: ty.clean(cx),
1603 })
1604 }
1605 };
1606
1607 GenericParamDef {
1608 name,
1609 kind,
1610 }
1611 }
1612 }
1613
1614 // maybe use a Generic enum and use Vec<Generic>?
1615 #[derive(Clone, Debug, Default)]
1616 pub struct Generics {
1617 pub params: Vec<GenericParamDef>,
1618 pub where_predicates: Vec<WherePredicate>,
1619 }
1620
1621 impl Clean<Generics> for hir::Generics {
1622 fn clean(&self, cx: &DocContext<'_>) -> Generics {
1623 // Synthetic type-parameters are inserted after normal ones.
1624 // In order for normal parameters to be able to refer to synthetic ones,
1625 // scans them first.
1626 fn is_impl_trait(param: &hir::GenericParam) -> bool {
1627 match param.kind {
1628 hir::GenericParamKind::Type { synthetic, .. } => {
1629 synthetic == Some(hir::SyntheticTyParamKind::ImplTrait)
1630 }
1631 _ => false,
1632 }
1633 }
1634 let impl_trait_params = self.params
1635 .iter()
1636 .filter(|param| is_impl_trait(param))
1637 .map(|param| {
1638 let param: GenericParamDef = param.clean(cx);
1639 match param.kind {
1640 GenericParamDefKind::Lifetime => unreachable!(),
1641 GenericParamDefKind::Type { did, ref bounds, .. } => {
1642 cx.impl_trait_bounds.borrow_mut().insert(did.into(), bounds.clone());
1643 }
1644 GenericParamDefKind::Const { .. } => unreachable!(),
1645 }
1646 param
1647 })
1648 .collect::<Vec<_>>();
1649
1650 let mut params = Vec::with_capacity(self.params.len());
1651 for p in self.params.iter().filter(|p| !is_impl_trait(p)) {
1652 let p = p.clean(cx);
1653 params.push(p);
1654 }
1655 params.extend(impl_trait_params);
1656
1657 let mut generics = Generics {
1658 params,
1659 where_predicates: self.where_clause.predicates.clean(cx),
1660 };
1661
1662 // Some duplicates are generated for ?Sized bounds between type params and where
1663 // predicates. The point in here is to move the bounds definitions from type params
1664 // to where predicates when such cases occur.
1665 for where_pred in &mut generics.where_predicates {
1666 match *where_pred {
1667 WherePredicate::BoundPredicate { ty: Generic(ref name), ref mut bounds } => {
1668 if bounds.is_empty() {
1669 for param in &mut generics.params {
1670 match param.kind {
1671 GenericParamDefKind::Lifetime => {}
1672 GenericParamDefKind::Type { bounds: ref mut ty_bounds, .. } => {
1673 if &param.name == name {
1674 mem::swap(bounds, ty_bounds);
1675 break
1676 }
1677 }
1678 GenericParamDefKind::Const { .. } => {}
1679 }
1680 }
1681 }
1682 }
1683 _ => continue,
1684 }
1685 }
1686 generics
1687 }
1688 }
1689
1690 impl<'a, 'tcx> Clean<Generics> for (&'a ty::Generics, ty::GenericPredicates<'tcx>) {
1691 fn clean(&self, cx: &DocContext<'_>) -> Generics {
1692 use self::WherePredicate as WP;
1693 use std::collections::BTreeMap;
1694
1695 let (gens, preds) = *self;
1696
1697 // Don't populate `cx.impl_trait_bounds` before `clean`ning `where` clauses,
1698 // since `Clean for ty::Predicate` would consume them.
1699 let mut impl_trait = BTreeMap::<ImplTraitParam, Vec<GenericBound>>::default();
1700
1701 // Bounds in the type_params and lifetimes fields are repeated in the
1702 // predicates field (see rustc_typeck::collect::ty_generics), so remove
1703 // them.
1704 let stripped_typarams = gens.params.iter()
1705 .filter_map(|param| match param.kind {
1706 ty::GenericParamDefKind::Lifetime => None,
1707 ty::GenericParamDefKind::Type { synthetic, .. } => {
1708 if param.name == kw::SelfUpper {
1709 assert_eq!(param.index, 0);
1710 return None;
1711 }
1712 if synthetic == Some(hir::SyntheticTyParamKind::ImplTrait) {
1713 impl_trait.insert(param.index.into(), vec![]);
1714 return None;
1715 }
1716 Some(param.clean(cx))
1717 }
1718 ty::GenericParamDefKind::Const { .. } => None,
1719 }).collect::<Vec<GenericParamDef>>();
1720
1721 // param index -> [(DefId of trait, associated type name, type)]
1722 let mut impl_trait_proj =
1723 FxHashMap::<u32, Vec<(DefId, String, Ty<'tcx>)>>::default();
1724
1725 let where_predicates = preds.predicates.iter()
1726 .flat_map(|(p, _)| {
1727 let mut projection = None;
1728 let param_idx = (|| {
1729 if let Some(trait_ref) = p.to_opt_poly_trait_ref() {
1730 if let ty::Param(param) = trait_ref.self_ty().kind {
1731 return Some(param.index);
1732 }
1733 } else if let Some(outlives) = p.to_opt_type_outlives() {
1734 if let ty::Param(param) = outlives.skip_binder().0.kind {
1735 return Some(param.index);
1736 }
1737 } else if let ty::Predicate::Projection(p) = p {
1738 if let ty::Param(param) = p.skip_binder().projection_ty.self_ty().kind {
1739 projection = Some(p);
1740 return Some(param.index);
1741 }
1742 }
1743
1744 None
1745 })();
1746
1747 if let Some(param_idx) = param_idx {
1748 if let Some(b) = impl_trait.get_mut(&param_idx.into()) {
1749 let p = p.clean(cx)?;
1750
1751 b.extend(
1752 p.get_bounds()
1753 .into_iter()
1754 .flatten()
1755 .cloned()
1756 .filter(|b| !b.is_sized_bound(cx))
1757 );
1758
1759 let proj = projection
1760 .map(|p| (p.skip_binder().projection_ty.clean(cx), p.skip_binder().ty));
1761 if let Some(((_, trait_did, name), rhs)) =
1762 proj.as_ref().and_then(|(lhs, rhs)| Some((lhs.projection()?, rhs)))
1763 {
1764 impl_trait_proj
1765 .entry(param_idx)
1766 .or_default()
1767 .push((trait_did, name.to_string(), rhs));
1768 }
1769
1770 return None;
1771 }
1772 }
1773
1774 Some(p)
1775 })
1776 .collect::<Vec<_>>();
1777
1778 for (param, mut bounds) in impl_trait {
1779 // Move trait bounds to the front.
1780 bounds.sort_by_key(|b| if let GenericBound::TraitBound(..) = b {
1781 false
1782 } else {
1783 true
1784 });
1785
1786 if let crate::core::ImplTraitParam::ParamIndex(idx) = param {
1787 if let Some(proj) = impl_trait_proj.remove(&idx) {
1788 for (trait_did, name, rhs) in proj {
1789 simplify::merge_bounds(
1790 cx,
1791 &mut bounds,
1792 trait_did,
1793 &name,
1794 &rhs.clean(cx),
1795 );
1796 }
1797 }
1798 } else {
1799 unreachable!();
1800 }
1801
1802 cx.impl_trait_bounds.borrow_mut().insert(param, bounds);
1803 }
1804
1805 // Now that `cx.impl_trait_bounds` is populated, we can process
1806 // remaining predicates which could contain `impl Trait`.
1807 let mut where_predicates = where_predicates
1808 .into_iter()
1809 .flat_map(|p| p.clean(cx))
1810 .collect::<Vec<_>>();
1811
1812 // Type parameters and have a Sized bound by default unless removed with
1813 // ?Sized. Scan through the predicates and mark any type parameter with
1814 // a Sized bound, removing the bounds as we find them.
1815 //
1816 // Note that associated types also have a sized bound by default, but we
1817 // don't actually know the set of associated types right here so that's
1818 // handled in cleaning associated types
1819 let mut sized_params = FxHashSet::default();
1820 where_predicates.retain(|pred| {
1821 match *pred {
1822 WP::BoundPredicate { ty: Generic(ref g), ref bounds } => {
1823 if bounds.iter().any(|b| b.is_sized_bound(cx)) {
1824 sized_params.insert(g.clone());
1825 false
1826 } else {
1827 true
1828 }
1829 }
1830 _ => true,
1831 }
1832 });
1833
1834 // Run through the type parameters again and insert a ?Sized
1835 // unbound for any we didn't find to be Sized.
1836 for tp in &stripped_typarams {
1837 if !sized_params.contains(&tp.name) {
1838 where_predicates.push(WP::BoundPredicate {
1839 ty: Type::Generic(tp.name.clone()),
1840 bounds: vec![GenericBound::maybe_sized(cx)],
1841 })
1842 }
1843 }
1844
1845 // It would be nice to collect all of the bounds on a type and recombine
1846 // them if possible, to avoid e.g., `where T: Foo, T: Bar, T: Sized, T: 'a`
1847 // and instead see `where T: Foo + Bar + Sized + 'a`
1848
1849 Generics {
1850 params: gens.params
1851 .iter()
1852 .flat_map(|param| match param.kind {
1853 ty::GenericParamDefKind::Lifetime => Some(param.clean(cx)),
1854 ty::GenericParamDefKind::Type { .. } => None,
1855 ty::GenericParamDefKind::Const { .. } => Some(param.clean(cx)),
1856 }).chain(simplify::ty_params(stripped_typarams).into_iter())
1857 .collect(),
1858 where_predicates: simplify::where_clauses(cx, where_predicates),
1859 }
1860 }
1861 }
1862
1863 /// The point of this function is to replace bounds with types.
1864 ///
1865 /// i.e. `[T, U]` when you have the following bounds: `T: Display, U: Option<T>` will return
1866 /// `[Display, Option]` (we just returns the list of the types, we don't care about the
1867 /// wrapped types in here).
1868 fn get_real_types(
1869 generics: &Generics,
1870 arg: &Type,
1871 cx: &DocContext<'_>,
1872 recurse: i32,
1873 ) -> FxHashSet<Type> {
1874 let arg_s = arg.print().to_string();
1875 let mut res = FxHashSet::default();
1876 if recurse >= 10 { // FIXME: remove this whole recurse thing when the recursion bug is fixed
1877 return res;
1878 }
1879 if arg.is_full_generic() {
1880 if let Some(where_pred) = generics.where_predicates.iter().find(|g| {
1881 match g {
1882 &WherePredicate::BoundPredicate { ref ty, .. } => ty.def_id() == arg.def_id(),
1883 _ => false,
1884 }
1885 }) {
1886 let bounds = where_pred.get_bounds().unwrap_or_else(|| &[]);
1887 for bound in bounds.iter() {
1888 match *bound {
1889 GenericBound::TraitBound(ref poly_trait, _) => {
1890 for x in poly_trait.generic_params.iter() {
1891 if !x.is_type() {
1892 continue
1893 }
1894 if let Some(ty) = x.get_type(cx) {
1895 let adds = get_real_types(generics, &ty, cx, recurse + 1);
1896 if !adds.is_empty() {
1897 res.extend(adds);
1898 } else if !ty.is_full_generic() {
1899 res.insert(ty);
1900 }
1901 }
1902 }
1903 }
1904 _ => {}
1905 }
1906 }
1907 }
1908 if let Some(bound) = generics.params.iter().find(|g| {
1909 g.is_type() && g.name == arg_s
1910 }) {
1911 for bound in bound.get_bounds().unwrap_or_else(|| &[]) {
1912 if let Some(ty) = bound.get_trait_type() {
1913 let adds = get_real_types(generics, &ty, cx, recurse + 1);
1914 if !adds.is_empty() {
1915 res.extend(adds);
1916 } else if !ty.is_full_generic() {
1917 res.insert(ty.clone());
1918 }
1919 }
1920 }
1921 }
1922 } else {
1923 res.insert(arg.clone());
1924 if let Some(gens) = arg.generics() {
1925 for gen in gens.iter() {
1926 if gen.is_full_generic() {
1927 let adds = get_real_types(generics, gen, cx, recurse + 1);
1928 if !adds.is_empty() {
1929 res.extend(adds);
1930 }
1931 } else {
1932 res.insert(gen.clone());
1933 }
1934 }
1935 }
1936 }
1937 res
1938 }
1939
1940 /// Return the full list of types when bounds have been resolved.
1941 ///
1942 /// i.e. `fn foo<A: Display, B: Option<A>>(x: u32, y: B)` will return
1943 /// `[u32, Display, Option]`.
1944 pub fn get_all_types(
1945 generics: &Generics,
1946 decl: &FnDecl,
1947 cx: &DocContext<'_>,
1948 ) -> (Vec<Type>, Vec<Type>) {
1949 let mut all_types = FxHashSet::default();
1950 for arg in decl.inputs.values.iter() {
1951 if arg.type_.is_self_type() {
1952 continue;
1953 }
1954 let args = get_real_types(generics, &arg.type_, cx, 0);
1955 if !args.is_empty() {
1956 all_types.extend(args);
1957 } else {
1958 all_types.insert(arg.type_.clone());
1959 }
1960 }
1961
1962 let ret_types = match decl.output {
1963 FunctionRetTy::Return(ref return_type) => {
1964 let mut ret = get_real_types(generics, &return_type, cx, 0);
1965 if ret.is_empty() {
1966 ret.insert(return_type.clone());
1967 }
1968 ret.into_iter().collect()
1969 }
1970 _ => Vec::new(),
1971 };
1972 (all_types.into_iter().collect(), ret_types)
1973 }
1974
1975 #[derive(Clone, Debug)]
1976 pub struct Method {
1977 pub generics: Generics,
1978 pub decl: FnDecl,
1979 pub header: hir::FnHeader,
1980 pub defaultness: Option<hir::Defaultness>,
1981 pub all_types: Vec<Type>,
1982 pub ret_types: Vec<Type>,
1983 }
1984
1985 impl<'a> Clean<Method> for (&'a hir::MethodSig, &'a hir::Generics, hir::BodyId,
1986 Option<hir::Defaultness>) {
1987 fn clean(&self, cx: &DocContext<'_>) -> Method {
1988 let (generics, decl) = enter_impl_trait(cx, || {
1989 (self.1.clean(cx), (&*self.0.decl, self.2).clean(cx))
1990 });
1991 let (all_types, ret_types) = get_all_types(&generics, &decl, cx);
1992 Method {
1993 decl,
1994 generics,
1995 header: self.0.header,
1996 defaultness: self.3,
1997 all_types,
1998 ret_types,
1999 }
2000 }
2001 }
2002
2003 #[derive(Clone, Debug)]
2004 pub struct TyMethod {
2005 pub header: hir::FnHeader,
2006 pub decl: FnDecl,
2007 pub generics: Generics,
2008 pub all_types: Vec<Type>,
2009 pub ret_types: Vec<Type>,
2010 }
2011
2012 #[derive(Clone, Debug)]
2013 pub struct Function {
2014 pub decl: FnDecl,
2015 pub generics: Generics,
2016 pub header: hir::FnHeader,
2017 pub all_types: Vec<Type>,
2018 pub ret_types: Vec<Type>,
2019 }
2020
2021 impl Clean<Item> for doctree::Function<'_> {
2022 fn clean(&self, cx: &DocContext<'_>) -> Item {
2023 let (generics, decl) = enter_impl_trait(cx, || {
2024 (self.generics.clean(cx), (self.decl, self.body).clean(cx))
2025 });
2026
2027 let did = cx.tcx.hir().local_def_id(self.id);
2028 let constness = if cx.tcx.is_min_const_fn(did) {
2029 hir::Constness::Const
2030 } else {
2031 hir::Constness::NotConst
2032 };
2033 let (all_types, ret_types) = get_all_types(&generics, &decl, cx);
2034 Item {
2035 name: Some(self.name.clean(cx)),
2036 attrs: self.attrs.clean(cx),
2037 source: self.whence.clean(cx),
2038 visibility: self.vis.clean(cx),
2039 stability: cx.stability(self.id).clean(cx),
2040 deprecation: cx.deprecation(self.id).clean(cx),
2041 def_id: did,
2042 inner: FunctionItem(Function {
2043 decl,
2044 generics,
2045 header: hir::FnHeader { constness, ..self.header },
2046 all_types,
2047 ret_types,
2048 }),
2049 }
2050 }
2051 }
2052
2053 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
2054 pub struct FnDecl {
2055 pub inputs: Arguments,
2056 pub output: FunctionRetTy,
2057 pub c_variadic: bool,
2058 pub attrs: Attributes,
2059 }
2060
2061 impl FnDecl {
2062 pub fn self_type(&self) -> Option<SelfTy> {
2063 self.inputs.values.get(0).and_then(|v| v.to_self())
2064 }
2065
2066 /// Returns the sugared return type for an async function.
2067 ///
2068 /// For example, if the return type is `impl std::future::Future<Output = i32>`, this function
2069 /// will return `i32`.
2070 ///
2071 /// # Panics
2072 ///
2073 /// This function will panic if the return type does not match the expected sugaring for async
2074 /// functions.
2075 pub fn sugared_async_return_type(&self) -> FunctionRetTy {
2076 match &self.output {
2077 FunctionRetTy::Return(Type::ImplTrait(bounds)) => {
2078 match &bounds[0] {
2079 GenericBound::TraitBound(PolyTrait { trait_, .. }, ..) => {
2080 let bindings = trait_.bindings().unwrap();
2081 FunctionRetTy::Return(bindings[0].ty().clone())
2082 }
2083 _ => panic!("unexpected desugaring of async function"),
2084 }
2085 }
2086 _ => panic!("unexpected desugaring of async function"),
2087 }
2088 }
2089 }
2090
2091 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
2092 pub struct Arguments {
2093 pub values: Vec<Argument>,
2094 }
2095
2096 impl<'a> Clean<Arguments> for (&'a [hir::Ty], &'a [ast::Ident]) {
2097 fn clean(&self, cx: &DocContext<'_>) -> Arguments {
2098 Arguments {
2099 values: self.0.iter().enumerate().map(|(i, ty)| {
2100 let mut name = self.1.get(i).map(|ident| ident.to_string())
2101 .unwrap_or(String::new());
2102 if name.is_empty() {
2103 name = "_".to_string();
2104 }
2105 Argument {
2106 name,
2107 type_: ty.clean(cx),
2108 }
2109 }).collect()
2110 }
2111 }
2112 }
2113
2114 impl<'a> Clean<Arguments> for (&'a [hir::Ty], hir::BodyId) {
2115 fn clean(&self, cx: &DocContext<'_>) -> Arguments {
2116 let body = cx.tcx.hir().body(self.1);
2117
2118 Arguments {
2119 values: self.0.iter().enumerate().map(|(i, ty)| {
2120 Argument {
2121 name: name_from_pat(&body.params[i].pat),
2122 type_: ty.clean(cx),
2123 }
2124 }).collect()
2125 }
2126 }
2127 }
2128
2129 impl<'a, A: Copy> Clean<FnDecl> for (&'a hir::FnDecl, A)
2130 where (&'a [hir::Ty], A): Clean<Arguments>
2131 {
2132 fn clean(&self, cx: &DocContext<'_>) -> FnDecl {
2133 FnDecl {
2134 inputs: (&self.0.inputs[..], self.1).clean(cx),
2135 output: self.0.output.clean(cx),
2136 c_variadic: self.0.c_variadic,
2137 attrs: Attributes::default(),
2138 }
2139 }
2140 }
2141
2142 impl<'tcx> Clean<FnDecl> for (DefId, ty::PolyFnSig<'tcx>) {
2143 fn clean(&self, cx: &DocContext<'_>) -> FnDecl {
2144 let (did, sig) = *self;
2145 let mut names = if cx.tcx.hir().as_local_hir_id(did).is_some() {
2146 vec![].into_iter()
2147 } else {
2148 cx.tcx.fn_arg_names(did).into_iter()
2149 };
2150
2151 FnDecl {
2152 output: Return(sig.skip_binder().output().clean(cx)),
2153 attrs: Attributes::default(),
2154 c_variadic: sig.skip_binder().c_variadic,
2155 inputs: Arguments {
2156 values: sig.skip_binder().inputs().iter().map(|t| {
2157 Argument {
2158 type_: t.clean(cx),
2159 name: names.next().map_or(String::new(), |name| name.to_string()),
2160 }
2161 }).collect(),
2162 },
2163 }
2164 }
2165 }
2166
2167 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
2168 pub struct Argument {
2169 pub type_: Type,
2170 pub name: String,
2171 }
2172
2173 #[derive(Clone, PartialEq, Debug)]
2174 pub enum SelfTy {
2175 SelfValue,
2176 SelfBorrowed(Option<Lifetime>, Mutability),
2177 SelfExplicit(Type),
2178 }
2179
2180 impl Argument {
2181 pub fn to_self(&self) -> Option<SelfTy> {
2182 if self.name != "self" {
2183 return None;
2184 }
2185 if self.type_.is_self_type() {
2186 return Some(SelfValue);
2187 }
2188 match self.type_ {
2189 BorrowedRef{ref lifetime, mutability, ref type_} if type_.is_self_type() => {
2190 Some(SelfBorrowed(lifetime.clone(), mutability))
2191 }
2192 _ => Some(SelfExplicit(self.type_.clone()))
2193 }
2194 }
2195 }
2196
2197 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
2198 pub enum FunctionRetTy {
2199 Return(Type),
2200 DefaultReturn,
2201 }
2202
2203 impl Clean<FunctionRetTy> for hir::FunctionRetTy {
2204 fn clean(&self, cx: &DocContext<'_>) -> FunctionRetTy {
2205 match *self {
2206 hir::Return(ref typ) => Return(typ.clean(cx)),
2207 hir::DefaultReturn(..) => DefaultReturn,
2208 }
2209 }
2210 }
2211
2212 impl GetDefId for FunctionRetTy {
2213 fn def_id(&self) -> Option<DefId> {
2214 match *self {
2215 Return(ref ty) => ty.def_id(),
2216 DefaultReturn => None,
2217 }
2218 }
2219 }
2220
2221 #[derive(Clone, Debug)]
2222 pub struct Trait {
2223 pub auto: bool,
2224 pub unsafety: hir::Unsafety,
2225 pub items: Vec<Item>,
2226 pub generics: Generics,
2227 pub bounds: Vec<GenericBound>,
2228 pub is_spotlight: bool,
2229 pub is_auto: bool,
2230 }
2231
2232 impl Clean<Item> for doctree::Trait<'_> {
2233 fn clean(&self, cx: &DocContext<'_>) -> Item {
2234 let attrs = self.attrs.clean(cx);
2235 let is_spotlight = attrs.has_doc_flag(sym::spotlight);
2236 Item {
2237 name: Some(self.name.clean(cx)),
2238 attrs,
2239 source: self.whence.clean(cx),
2240 def_id: cx.tcx.hir().local_def_id(self.id),
2241 visibility: self.vis.clean(cx),
2242 stability: cx.stability(self.id).clean(cx),
2243 deprecation: cx.deprecation(self.id).clean(cx),
2244 inner: TraitItem(Trait {
2245 auto: self.is_auto.clean(cx),
2246 unsafety: self.unsafety,
2247 items: self.items.iter().map(|ti| ti.clean(cx)).collect(),
2248 generics: self.generics.clean(cx),
2249 bounds: self.bounds.clean(cx),
2250 is_spotlight,
2251 is_auto: self.is_auto.clean(cx),
2252 }),
2253 }
2254 }
2255 }
2256
2257 #[derive(Clone, Debug)]
2258 pub struct TraitAlias {
2259 pub generics: Generics,
2260 pub bounds: Vec<GenericBound>,
2261 }
2262
2263 impl Clean<Item> for doctree::TraitAlias<'_> {
2264 fn clean(&self, cx: &DocContext<'_>) -> Item {
2265 let attrs = self.attrs.clean(cx);
2266 Item {
2267 name: Some(self.name.clean(cx)),
2268 attrs,
2269 source: self.whence.clean(cx),
2270 def_id: cx.tcx.hir().local_def_id(self.id),
2271 visibility: self.vis.clean(cx),
2272 stability: cx.stability(self.id).clean(cx),
2273 deprecation: cx.deprecation(self.id).clean(cx),
2274 inner: TraitAliasItem(TraitAlias {
2275 generics: self.generics.clean(cx),
2276 bounds: self.bounds.clean(cx),
2277 }),
2278 }
2279 }
2280 }
2281
2282 impl Clean<bool> for hir::IsAuto {
2283 fn clean(&self, _: &DocContext<'_>) -> bool {
2284 match *self {
2285 hir::IsAuto::Yes => true,
2286 hir::IsAuto::No => false,
2287 }
2288 }
2289 }
2290
2291 impl Clean<Type> for hir::TraitRef {
2292 fn clean(&self, cx: &DocContext<'_>) -> Type {
2293 resolve_type(cx, self.path.clean(cx), self.hir_ref_id)
2294 }
2295 }
2296
2297 impl Clean<PolyTrait> for hir::PolyTraitRef {
2298 fn clean(&self, cx: &DocContext<'_>) -> PolyTrait {
2299 PolyTrait {
2300 trait_: self.trait_ref.clean(cx),
2301 generic_params: self.bound_generic_params.clean(cx)
2302 }
2303 }
2304 }
2305
2306 impl Clean<Item> for hir::TraitItem {
2307 fn clean(&self, cx: &DocContext<'_>) -> Item {
2308 let inner = match self.kind {
2309 hir::TraitItemKind::Const(ref ty, default) => {
2310 AssocConstItem(ty.clean(cx),
2311 default.map(|e| print_const_expr(cx, e)))
2312 }
2313 hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Provided(body)) => {
2314 MethodItem((sig, &self.generics, body, None).clean(cx))
2315 }
2316 hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Required(ref names)) => {
2317 let (generics, decl) = enter_impl_trait(cx, || {
2318 (self.generics.clean(cx), (&*sig.decl, &names[..]).clean(cx))
2319 });
2320 let (all_types, ret_types) = get_all_types(&generics, &decl, cx);
2321 TyMethodItem(TyMethod {
2322 header: sig.header,
2323 decl,
2324 generics,
2325 all_types,
2326 ret_types,
2327 })
2328 }
2329 hir::TraitItemKind::Type(ref bounds, ref default) => {
2330 AssocTypeItem(bounds.clean(cx), default.clean(cx))
2331 }
2332 };
2333 let local_did = cx.tcx.hir().local_def_id(self.hir_id);
2334 Item {
2335 name: Some(self.ident.name.clean(cx)),
2336 attrs: self.attrs.clean(cx),
2337 source: self.span.clean(cx),
2338 def_id: local_did,
2339 visibility: Visibility::Inherited,
2340 stability: get_stability(cx, local_did),
2341 deprecation: get_deprecation(cx, local_did),
2342 inner,
2343 }
2344 }
2345 }
2346
2347 impl Clean<Item> for hir::ImplItem {
2348 fn clean(&self, cx: &DocContext<'_>) -> Item {
2349 let inner = match self.kind {
2350 hir::ImplItemKind::Const(ref ty, expr) => {
2351 AssocConstItem(ty.clean(cx),
2352 Some(print_const_expr(cx, expr)))
2353 }
2354 hir::ImplItemKind::Method(ref sig, body) => {
2355 MethodItem((sig, &self.generics, body, Some(self.defaultness)).clean(cx))
2356 }
2357 hir::ImplItemKind::TyAlias(ref ty) => TypedefItem(Typedef {
2358 type_: ty.clean(cx),
2359 generics: Generics::default(),
2360 }, true),
2361 hir::ImplItemKind::OpaqueTy(ref bounds) => OpaqueTyItem(OpaqueTy {
2362 bounds: bounds.clean(cx),
2363 generics: Generics::default(),
2364 }, true),
2365 };
2366 let local_did = cx.tcx.hir().local_def_id(self.hir_id);
2367 Item {
2368 name: Some(self.ident.name.clean(cx)),
2369 source: self.span.clean(cx),
2370 attrs: self.attrs.clean(cx),
2371 def_id: local_did,
2372 visibility: self.vis.clean(cx),
2373 stability: get_stability(cx, local_did),
2374 deprecation: get_deprecation(cx, local_did),
2375 inner,
2376 }
2377 }
2378 }
2379
2380 impl Clean<Item> for ty::AssocItem {
2381 fn clean(&self, cx: &DocContext<'_>) -> Item {
2382 let inner = match self.kind {
2383 ty::AssocKind::Const => {
2384 let ty = cx.tcx.type_of(self.def_id);
2385 let default = if self.defaultness.has_value() {
2386 Some(inline::print_inlined_const(cx, self.def_id))
2387 } else {
2388 None
2389 };
2390 AssocConstItem(ty.clean(cx), default)
2391 }
2392 ty::AssocKind::Method => {
2393 let generics = (cx.tcx.generics_of(self.def_id),
2394 cx.tcx.explicit_predicates_of(self.def_id)).clean(cx);
2395 let sig = cx.tcx.fn_sig(self.def_id);
2396 let mut decl = (self.def_id, sig).clean(cx);
2397
2398 if self.method_has_self_argument {
2399 let self_ty = match self.container {
2400 ty::ImplContainer(def_id) => {
2401 cx.tcx.type_of(def_id)
2402 }
2403 ty::TraitContainer(_) => cx.tcx.types.self_param,
2404 };
2405 let self_arg_ty = *sig.input(0).skip_binder();
2406 if self_arg_ty == self_ty {
2407 decl.inputs.values[0].type_ = Generic(String::from("Self"));
2408 } else if let ty::Ref(_, ty, _) = self_arg_ty.kind {
2409 if ty == self_ty {
2410 match decl.inputs.values[0].type_ {
2411 BorrowedRef{ref mut type_, ..} => {
2412 **type_ = Generic(String::from("Self"))
2413 }
2414 _ => unreachable!(),
2415 }
2416 }
2417 }
2418 }
2419
2420 let provided = match self.container {
2421 ty::ImplContainer(_) => true,
2422 ty::TraitContainer(_) => self.defaultness.has_value()
2423 };
2424 let (all_types, ret_types) = get_all_types(&generics, &decl, cx);
2425 if provided {
2426 let constness = if cx.tcx.is_min_const_fn(self.def_id) {
2427 hir::Constness::Const
2428 } else {
2429 hir::Constness::NotConst
2430 };
2431 let asyncness = cx.tcx.asyncness(self.def_id);
2432 let defaultness = match self.container {
2433 ty::ImplContainer(_) => Some(self.defaultness),
2434 ty::TraitContainer(_) => None,
2435 };
2436 MethodItem(Method {
2437 generics,
2438 decl,
2439 header: hir::FnHeader {
2440 unsafety: sig.unsafety(),
2441 abi: sig.abi(),
2442 constness,
2443 asyncness,
2444 },
2445 defaultness,
2446 all_types,
2447 ret_types,
2448 })
2449 } else {
2450 TyMethodItem(TyMethod {
2451 generics,
2452 decl,
2453 header: hir::FnHeader {
2454 unsafety: sig.unsafety(),
2455 abi: sig.abi(),
2456 constness: hir::Constness::NotConst,
2457 asyncness: hir::IsAsync::NotAsync,
2458 },
2459 all_types,
2460 ret_types,
2461 })
2462 }
2463 }
2464 ty::AssocKind::Type => {
2465 let my_name = self.ident.name.clean(cx);
2466
2467 if let ty::TraitContainer(did) = self.container {
2468 // When loading a cross-crate associated type, the bounds for this type
2469 // are actually located on the trait/impl itself, so we need to load
2470 // all of the generics from there and then look for bounds that are
2471 // applied to this associated type in question.
2472 let predicates = cx.tcx.explicit_predicates_of(did);
2473 let generics = (cx.tcx.generics_of(did), predicates).clean(cx);
2474 let mut bounds = generics.where_predicates.iter().filter_map(|pred| {
2475 let (name, self_type, trait_, bounds) = match *pred {
2476 WherePredicate::BoundPredicate {
2477 ty: QPath { ref name, ref self_type, ref trait_ },
2478 ref bounds
2479 } => (name, self_type, trait_, bounds),
2480 _ => return None,
2481 };
2482 if *name != my_name { return None }
2483 match **trait_ {
2484 ResolvedPath { did, .. } if did == self.container.id() => {}
2485 _ => return None,
2486 }
2487 match **self_type {
2488 Generic(ref s) if *s == "Self" => {}
2489 _ => return None,
2490 }
2491 Some(bounds)
2492 }).flat_map(|i| i.iter().cloned()).collect::<Vec<_>>();
2493 // Our Sized/?Sized bound didn't get handled when creating the generics
2494 // because we didn't actually get our whole set of bounds until just now
2495 // (some of them may have come from the trait). If we do have a sized
2496 // bound, we remove it, and if we don't then we add the `?Sized` bound
2497 // at the end.
2498 match bounds.iter().position(|b| b.is_sized_bound(cx)) {
2499 Some(i) => { bounds.remove(i); }
2500 None => bounds.push(GenericBound::maybe_sized(cx)),
2501 }
2502
2503 let ty = if self.defaultness.has_value() {
2504 Some(cx.tcx.type_of(self.def_id))
2505 } else {
2506 None
2507 };
2508
2509 AssocTypeItem(bounds, ty.clean(cx))
2510 } else {
2511 TypedefItem(Typedef {
2512 type_: cx.tcx.type_of(self.def_id).clean(cx),
2513 generics: Generics {
2514 params: Vec::new(),
2515 where_predicates: Vec::new(),
2516 },
2517 }, true)
2518 }
2519 }
2520 ty::AssocKind::OpaqueTy => unimplemented!(),
2521 };
2522
2523 let visibility = match self.container {
2524 ty::ImplContainer(_) => self.vis.clean(cx),
2525 ty::TraitContainer(_) => Inherited,
2526 };
2527
2528 Item {
2529 name: Some(self.ident.name.clean(cx)),
2530 visibility,
2531 stability: get_stability(cx, self.def_id),
2532 deprecation: get_deprecation(cx, self.def_id),
2533 def_id: self.def_id,
2534 attrs: inline::load_attrs(cx, self.def_id).clean(cx),
2535 source: cx.tcx.def_span(self.def_id).clean(cx),
2536 inner,
2537 }
2538 }
2539 }
2540
2541 /// A trait reference, which may have higher ranked lifetimes.
2542 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
2543 pub struct PolyTrait {
2544 pub trait_: Type,
2545 pub generic_params: Vec<GenericParamDef>,
2546 }
2547
2548 /// A representation of a type suitable for hyperlinking purposes. Ideally, one can get the original
2549 /// type out of the AST/`TyCtxt` given one of these, if more information is needed. Most
2550 /// importantly, it does not preserve mutability or boxes.
2551 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
2552 pub enum Type {
2553 /// Structs/enums/traits (most that would be an `hir::TyKind::Path`).
2554 ResolvedPath {
2555 path: Path,
2556 param_names: Option<Vec<GenericBound>>,
2557 did: DefId,
2558 /// `true` if is a `T::Name` path for associated types.
2559 is_generic: bool,
2560 },
2561 /// For parameterized types, so the consumer of the JSON don't go
2562 /// looking for types which don't exist anywhere.
2563 Generic(String),
2564 /// Primitives are the fixed-size numeric types (plus int/usize/float), char,
2565 /// arrays, slices, and tuples.
2566 Primitive(PrimitiveType),
2567 /// `extern "ABI" fn`
2568 BareFunction(Box<BareFunctionDecl>),
2569 Tuple(Vec<Type>),
2570 Slice(Box<Type>),
2571 Array(Box<Type>, String),
2572 Never,
2573 RawPointer(Mutability, Box<Type>),
2574 BorrowedRef {
2575 lifetime: Option<Lifetime>,
2576 mutability: Mutability,
2577 type_: Box<Type>,
2578 },
2579
2580 // `<Type as Trait>::Name`
2581 QPath {
2582 name: String,
2583 self_type: Box<Type>,
2584 trait_: Box<Type>
2585 },
2586
2587 // `_`
2588 Infer,
2589
2590 // `impl TraitA + TraitB + ...`
2591 ImplTrait(Vec<GenericBound>),
2592 }
2593
2594 #[derive(Clone, PartialEq, Eq, Hash, Copy, Debug)]
2595 pub enum PrimitiveType {
2596 Isize, I8, I16, I32, I64, I128,
2597 Usize, U8, U16, U32, U64, U128,
2598 F32, F64,
2599 Char,
2600 Bool,
2601 Str,
2602 Slice,
2603 Array,
2604 Tuple,
2605 Unit,
2606 RawPointer,
2607 Reference,
2608 Fn,
2609 Never,
2610 }
2611
2612 #[derive(Clone, Copy, Debug)]
2613 pub enum TypeKind {
2614 Enum,
2615 Function,
2616 Module,
2617 Const,
2618 Static,
2619 Struct,
2620 Union,
2621 Trait,
2622 Typedef,
2623 Foreign,
2624 Macro,
2625 Attr,
2626 Derive,
2627 TraitAlias,
2628 }
2629
2630 pub trait GetDefId {
2631 fn def_id(&self) -> Option<DefId>;
2632 }
2633
2634 impl<T: GetDefId> GetDefId for Option<T> {
2635 fn def_id(&self) -> Option<DefId> {
2636 self.as_ref().and_then(|d| d.def_id())
2637 }
2638 }
2639
2640 impl Type {
2641 pub fn primitive_type(&self) -> Option<PrimitiveType> {
2642 match *self {
2643 Primitive(p) | BorrowedRef { type_: box Primitive(p), ..} => Some(p),
2644 Slice(..) | BorrowedRef { type_: box Slice(..), .. } => Some(PrimitiveType::Slice),
2645 Array(..) | BorrowedRef { type_: box Array(..), .. } => Some(PrimitiveType::Array),
2646 Tuple(ref tys) => if tys.is_empty() {
2647 Some(PrimitiveType::Unit)
2648 } else {
2649 Some(PrimitiveType::Tuple)
2650 },
2651 RawPointer(..) => Some(PrimitiveType::RawPointer),
2652 BorrowedRef { type_: box Generic(..), .. } => Some(PrimitiveType::Reference),
2653 BareFunction(..) => Some(PrimitiveType::Fn),
2654 Never => Some(PrimitiveType::Never),
2655 _ => None,
2656 }
2657 }
2658
2659 pub fn is_generic(&self) -> bool {
2660 match *self {
2661 ResolvedPath { is_generic, .. } => is_generic,
2662 _ => false,
2663 }
2664 }
2665
2666 pub fn is_self_type(&self) -> bool {
2667 match *self {
2668 Generic(ref name) => name == "Self",
2669 _ => false
2670 }
2671 }
2672
2673 pub fn generics(&self) -> Option<Vec<Type>> {
2674 match *self {
2675 ResolvedPath { ref path, .. } => {
2676 path.segments.last().and_then(|seg| {
2677 if let GenericArgs::AngleBracketed { ref args, .. } = seg.args {
2678 Some(args.iter().filter_map(|arg| match arg {
2679 GenericArg::Type(ty) => Some(ty.clone()),
2680 _ => None,
2681 }).collect())
2682 } else {
2683 None
2684 }
2685 })
2686 }
2687 _ => None,
2688 }
2689 }
2690
2691 pub fn bindings(&self) -> Option<&[TypeBinding]> {
2692 match *self {
2693 ResolvedPath { ref path, .. } => {
2694 path.segments.last().and_then(|seg| {
2695 if let GenericArgs::AngleBracketed { ref bindings, .. } = seg.args {
2696 Some(&**bindings)
2697 } else {
2698 None
2699 }
2700 })
2701 }
2702 _ => None
2703 }
2704 }
2705
2706 pub fn is_full_generic(&self) -> bool {
2707 match *self {
2708 Type::Generic(_) => true,
2709 _ => false,
2710 }
2711 }
2712
2713 pub fn projection(&self) -> Option<(&Type, DefId, &str)> {
2714 let (self_, trait_, name) = match self {
2715 QPath { ref self_type, ref trait_, ref name } => {
2716 (self_type, trait_, name)
2717 }
2718 _ => return None,
2719 };
2720 let trait_did = match **trait_ {
2721 ResolvedPath { did, .. } => did,
2722 _ => return None,
2723 };
2724 Some((&self_, trait_did, name))
2725 }
2726
2727 }
2728
2729 impl GetDefId for Type {
2730 fn def_id(&self) -> Option<DefId> {
2731 match *self {
2732 ResolvedPath { did, .. } => Some(did),
2733 Primitive(p) => crate::html::render::cache().primitive_locations.get(&p).cloned(),
2734 BorrowedRef { type_: box Generic(..), .. } =>
2735 Primitive(PrimitiveType::Reference).def_id(),
2736 BorrowedRef { ref type_, .. } => type_.def_id(),
2737 Tuple(ref tys) => if tys.is_empty() {
2738 Primitive(PrimitiveType::Unit).def_id()
2739 } else {
2740 Primitive(PrimitiveType::Tuple).def_id()
2741 },
2742 BareFunction(..) => Primitive(PrimitiveType::Fn).def_id(),
2743 Never => Primitive(PrimitiveType::Never).def_id(),
2744 Slice(..) => Primitive(PrimitiveType::Slice).def_id(),
2745 Array(..) => Primitive(PrimitiveType::Array).def_id(),
2746 RawPointer(..) => Primitive(PrimitiveType::RawPointer).def_id(),
2747 QPath { ref self_type, .. } => self_type.def_id(),
2748 _ => None,
2749 }
2750 }
2751 }
2752
2753 impl PrimitiveType {
2754 fn from_str(s: &str) -> Option<PrimitiveType> {
2755 match s {
2756 "isize" => Some(PrimitiveType::Isize),
2757 "i8" => Some(PrimitiveType::I8),
2758 "i16" => Some(PrimitiveType::I16),
2759 "i32" => Some(PrimitiveType::I32),
2760 "i64" => Some(PrimitiveType::I64),
2761 "i128" => Some(PrimitiveType::I128),
2762 "usize" => Some(PrimitiveType::Usize),
2763 "u8" => Some(PrimitiveType::U8),
2764 "u16" => Some(PrimitiveType::U16),
2765 "u32" => Some(PrimitiveType::U32),
2766 "u64" => Some(PrimitiveType::U64),
2767 "u128" => Some(PrimitiveType::U128),
2768 "bool" => Some(PrimitiveType::Bool),
2769 "char" => Some(PrimitiveType::Char),
2770 "str" => Some(PrimitiveType::Str),
2771 "f32" => Some(PrimitiveType::F32),
2772 "f64" => Some(PrimitiveType::F64),
2773 "array" => Some(PrimitiveType::Array),
2774 "slice" => Some(PrimitiveType::Slice),
2775 "tuple" => Some(PrimitiveType::Tuple),
2776 "unit" => Some(PrimitiveType::Unit),
2777 "pointer" => Some(PrimitiveType::RawPointer),
2778 "reference" => Some(PrimitiveType::Reference),
2779 "fn" => Some(PrimitiveType::Fn),
2780 "never" => Some(PrimitiveType::Never),
2781 _ => None,
2782 }
2783 }
2784
2785 pub fn as_str(&self) -> &'static str {
2786 use self::PrimitiveType::*;
2787 match *self {
2788 Isize => "isize",
2789 I8 => "i8",
2790 I16 => "i16",
2791 I32 => "i32",
2792 I64 => "i64",
2793 I128 => "i128",
2794 Usize => "usize",
2795 U8 => "u8",
2796 U16 => "u16",
2797 U32 => "u32",
2798 U64 => "u64",
2799 U128 => "u128",
2800 F32 => "f32",
2801 F64 => "f64",
2802 Str => "str",
2803 Bool => "bool",
2804 Char => "char",
2805 Array => "array",
2806 Slice => "slice",
2807 Tuple => "tuple",
2808 Unit => "unit",
2809 RawPointer => "pointer",
2810 Reference => "reference",
2811 Fn => "fn",
2812 Never => "never",
2813 }
2814 }
2815
2816 pub fn to_url_str(&self) -> &'static str {
2817 self.as_str()
2818 }
2819 }
2820
2821 impl From<ast::IntTy> for PrimitiveType {
2822 fn from(int_ty: ast::IntTy) -> PrimitiveType {
2823 match int_ty {
2824 ast::IntTy::Isize => PrimitiveType::Isize,
2825 ast::IntTy::I8 => PrimitiveType::I8,
2826 ast::IntTy::I16 => PrimitiveType::I16,
2827 ast::IntTy::I32 => PrimitiveType::I32,
2828 ast::IntTy::I64 => PrimitiveType::I64,
2829 ast::IntTy::I128 => PrimitiveType::I128,
2830 }
2831 }
2832 }
2833
2834 impl From<ast::UintTy> for PrimitiveType {
2835 fn from(uint_ty: ast::UintTy) -> PrimitiveType {
2836 match uint_ty {
2837 ast::UintTy::Usize => PrimitiveType::Usize,
2838 ast::UintTy::U8 => PrimitiveType::U8,
2839 ast::UintTy::U16 => PrimitiveType::U16,
2840 ast::UintTy::U32 => PrimitiveType::U32,
2841 ast::UintTy::U64 => PrimitiveType::U64,
2842 ast::UintTy::U128 => PrimitiveType::U128,
2843 }
2844 }
2845 }
2846
2847 impl From<ast::FloatTy> for PrimitiveType {
2848 fn from(float_ty: ast::FloatTy) -> PrimitiveType {
2849 match float_ty {
2850 ast::FloatTy::F32 => PrimitiveType::F32,
2851 ast::FloatTy::F64 => PrimitiveType::F64,
2852 }
2853 }
2854 }
2855
2856 impl Clean<Type> for hir::Ty {
2857 fn clean(&self, cx: &DocContext<'_>) -> Type {
2858 use rustc::hir::*;
2859
2860 match self.kind {
2861 TyKind::Never => Never,
2862 TyKind::Ptr(ref m) => RawPointer(m.mutbl.clean(cx), box m.ty.clean(cx)),
2863 TyKind::Rptr(ref l, ref m) => {
2864 let lifetime = if l.is_elided() {
2865 None
2866 } else {
2867 Some(l.clean(cx))
2868 };
2869 BorrowedRef {lifetime, mutability: m.mutbl.clean(cx),
2870 type_: box m.ty.clean(cx)}
2871 }
2872 TyKind::Slice(ref ty) => Slice(box ty.clean(cx)),
2873 TyKind::Array(ref ty, ref length) => {
2874 let def_id = cx.tcx.hir().local_def_id(length.hir_id);
2875 let param_env = cx.tcx.param_env(def_id);
2876 let substs = InternalSubsts::identity_for_item(cx.tcx, def_id);
2877 let cid = GlobalId {
2878 instance: ty::Instance::new(def_id, substs),
2879 promoted: None
2880 };
2881 let length = match cx.tcx.const_eval(param_env.and(cid)) {
2882 Ok(length) => print_const(cx, length),
2883 Err(_) => cx.sess()
2884 .source_map()
2885 .span_to_snippet(cx.tcx.def_span(def_id))
2886 .unwrap_or_else(|_| "_".to_string()),
2887 };
2888 Array(box ty.clean(cx), length)
2889 },
2890 TyKind::Tup(ref tys) => Tuple(tys.clean(cx)),
2891 TyKind::Def(item_id, _) => {
2892 let item = cx.tcx.hir().expect_item(item_id.id);
2893 if let hir::ItemKind::OpaqueTy(ref ty) = item.kind {
2894 ImplTrait(ty.bounds.clean(cx))
2895 } else {
2896 unreachable!()
2897 }
2898 }
2899 TyKind::Path(hir::QPath::Resolved(None, ref path)) => {
2900 if let Res::Def(DefKind::TyParam, did) = path.res {
2901 if let Some(new_ty) = cx.ty_substs.borrow().get(&did).cloned() {
2902 return new_ty;
2903 }
2904 if let Some(bounds) = cx.impl_trait_bounds.borrow_mut().remove(&did.into()) {
2905 return ImplTrait(bounds);
2906 }
2907 }
2908
2909 let mut alias = None;
2910 if let Res::Def(DefKind::TyAlias, def_id) = path.res {
2911 // Substitute private type aliases
2912 if let Some(hir_id) = cx.tcx.hir().as_local_hir_id(def_id) {
2913 if !cx.renderinfo.borrow().access_levels.is_exported(def_id) {
2914 alias = Some(&cx.tcx.hir().expect_item(hir_id).kind);
2915 }
2916 }
2917 };
2918
2919 if let Some(&hir::ItemKind::TyAlias(ref ty, ref generics)) = alias {
2920 let provided_params = &path.segments.last().expect("segments were empty");
2921 let mut ty_substs = FxHashMap::default();
2922 let mut lt_substs = FxHashMap::default();
2923 let mut ct_substs = FxHashMap::default();
2924 let generic_args = provided_params.generic_args();
2925 {
2926 let mut indices: GenericParamCount = Default::default();
2927 for param in generics.params.iter() {
2928 match param.kind {
2929 hir::GenericParamKind::Lifetime { .. } => {
2930 let mut j = 0;
2931 let lifetime = generic_args.args.iter().find_map(|arg| {
2932 match arg {
2933 hir::GenericArg::Lifetime(lt) => {
2934 if indices.lifetimes == j {
2935 return Some(lt);
2936 }
2937 j += 1;
2938 None
2939 }
2940 _ => None,
2941 }
2942 });
2943 if let Some(lt) = lifetime.cloned() {
2944 if !lt.is_elided() {
2945 let lt_def_id =
2946 cx.tcx.hir().local_def_id(param.hir_id);
2947 lt_substs.insert(lt_def_id, lt.clean(cx));
2948 }
2949 }
2950 indices.lifetimes += 1;
2951 }
2952 hir::GenericParamKind::Type { ref default, .. } => {
2953 let ty_param_def_id =
2954 cx.tcx.hir().local_def_id(param.hir_id);
2955 let mut j = 0;
2956 let type_ = generic_args.args.iter().find_map(|arg| {
2957 match arg {
2958 hir::GenericArg::Type(ty) => {
2959 if indices.types == j {
2960 return Some(ty);
2961 }
2962 j += 1;
2963 None
2964 }
2965 _ => None,
2966 }
2967 });
2968 if let Some(ty) = type_ {
2969 ty_substs.insert(ty_param_def_id, ty.clean(cx));
2970 } else if let Some(default) = default.clone() {
2971 ty_substs.insert(ty_param_def_id,
2972 default.clean(cx));
2973 }
2974 indices.types += 1;
2975 }
2976 hir::GenericParamKind::Const { .. } => {
2977 let const_param_def_id =
2978 cx.tcx.hir().local_def_id(param.hir_id);
2979 let mut j = 0;
2980 let const_ = generic_args.args.iter().find_map(|arg| {
2981 match arg {
2982 hir::GenericArg::Const(ct) => {
2983 if indices.consts == j {
2984 return Some(ct);
2985 }
2986 j += 1;
2987 None
2988 }
2989 _ => None,
2990 }
2991 });
2992 if let Some(ct) = const_ {
2993 ct_substs.insert(const_param_def_id, ct.clean(cx));
2994 }
2995 // FIXME(const_generics:defaults)
2996 indices.consts += 1;
2997 }
2998 }
2999 }
3000 }
3001 return cx.enter_alias(ty_substs, lt_substs, ct_substs, || ty.clean(cx));
3002 }
3003 resolve_type(cx, path.clean(cx), self.hir_id)
3004 }
3005 TyKind::Path(hir::QPath::Resolved(Some(ref qself), ref p)) => {
3006 let segments = if p.is_global() { &p.segments[1..] } else { &p.segments };
3007 let trait_segments = &segments[..segments.len() - 1];
3008 let trait_path = self::Path {
3009 global: p.is_global(),
3010 res: Res::Def(
3011 DefKind::Trait,
3012 cx.tcx.associated_item(p.res.def_id()).container.id(),
3013 ),
3014 segments: trait_segments.clean(cx),
3015 };
3016 Type::QPath {
3017 name: p.segments.last().expect("segments were empty").ident.name.clean(cx),
3018 self_type: box qself.clean(cx),
3019 trait_: box resolve_type(cx, trait_path, self.hir_id)
3020 }
3021 }
3022 TyKind::Path(hir::QPath::TypeRelative(ref qself, ref segment)) => {
3023 let mut res = Res::Err;
3024 let ty = hir_ty_to_ty(cx.tcx, self);
3025 if let ty::Projection(proj) = ty.kind {
3026 res = Res::Def(DefKind::Trait, proj.trait_ref(cx.tcx).def_id);
3027 }
3028 let trait_path = hir::Path {
3029 span: self.span,
3030 res,
3031 segments: vec![].into(),
3032 };
3033 Type::QPath {
3034 name: segment.ident.name.clean(cx),
3035 self_type: box qself.clean(cx),
3036 trait_: box resolve_type(cx, trait_path.clean(cx), self.hir_id)
3037 }
3038 }
3039 TyKind::TraitObject(ref bounds, ref lifetime) => {
3040 match bounds[0].clean(cx).trait_ {
3041 ResolvedPath { path, param_names: None, did, is_generic } => {
3042 let mut bounds: Vec<self::GenericBound> = bounds[1..].iter().map(|bound| {
3043 self::GenericBound::TraitBound(bound.clean(cx),
3044 hir::TraitBoundModifier::None)
3045 }).collect();
3046 if !lifetime.is_elided() {
3047 bounds.push(self::GenericBound::Outlives(lifetime.clean(cx)));
3048 }
3049 ResolvedPath { path, param_names: Some(bounds), did, is_generic, }
3050 }
3051 _ => Infer, // shouldn't happen
3052 }
3053 }
3054 TyKind::BareFn(ref barefn) => BareFunction(box barefn.clean(cx)),
3055 TyKind::Infer | TyKind::Err => Infer,
3056 TyKind::Typeof(..) => panic!("unimplemented type {:?}", self.kind),
3057 }
3058 }
3059 }
3060
3061 impl<'tcx> Clean<Type> for Ty<'tcx> {
3062 fn clean(&self, cx: &DocContext<'_>) -> Type {
3063 debug!("cleaning type: {:?}", self);
3064 match self.kind {
3065 ty::Never => Never,
3066 ty::Bool => Primitive(PrimitiveType::Bool),
3067 ty::Char => Primitive(PrimitiveType::Char),
3068 ty::Int(int_ty) => Primitive(int_ty.into()),
3069 ty::Uint(uint_ty) => Primitive(uint_ty.into()),
3070 ty::Float(float_ty) => Primitive(float_ty.into()),
3071 ty::Str => Primitive(PrimitiveType::Str),
3072 ty::Slice(ty) => Slice(box ty.clean(cx)),
3073 ty::Array(ty, n) => {
3074 let mut n = cx.tcx.lift(&n).expect("array lift failed");
3075 if let ConstValue::Unevaluated(def_id, substs) = n.val {
3076 let param_env = cx.tcx.param_env(def_id);
3077 let cid = GlobalId {
3078 instance: ty::Instance::new(def_id, substs),
3079 promoted: None
3080 };
3081 if let Ok(new_n) = cx.tcx.const_eval(param_env.and(cid)) {
3082 n = new_n;
3083 }
3084 };
3085 let n = print_const(cx, n);
3086 Array(box ty.clean(cx), n)
3087 }
3088 ty::RawPtr(mt) => RawPointer(mt.mutbl.clean(cx), box mt.ty.clean(cx)),
3089 ty::Ref(r, ty, mutbl) => BorrowedRef {
3090 lifetime: r.clean(cx),
3091 mutability: mutbl.clean(cx),
3092 type_: box ty.clean(cx),
3093 },
3094 ty::FnDef(..) |
3095 ty::FnPtr(_) => {
3096 let ty = cx.tcx.lift(self).expect("FnPtr lift failed");
3097 let sig = ty.fn_sig(cx.tcx);
3098 let local_def_id = cx.tcx.hir().local_def_id_from_node_id(ast::CRATE_NODE_ID);
3099 BareFunction(box BareFunctionDecl {
3100 unsafety: sig.unsafety(),
3101 generic_params: Vec::new(),
3102 decl: (local_def_id, sig).clean(cx),
3103 abi: sig.abi(),
3104 })
3105 }
3106 ty::Adt(def, substs) => {
3107 let did = def.did;
3108 let kind = match def.adt_kind() {
3109 AdtKind::Struct => TypeKind::Struct,
3110 AdtKind::Union => TypeKind::Union,
3111 AdtKind::Enum => TypeKind::Enum,
3112 };
3113 inline::record_extern_fqn(cx, did, kind);
3114 let path = external_path(cx, cx.tcx.item_name(did), None, false, vec![], substs);
3115 ResolvedPath {
3116 path,
3117 param_names: None,
3118 did,
3119 is_generic: false,
3120 }
3121 }
3122 ty::Foreign(did) => {
3123 inline::record_extern_fqn(cx, did, TypeKind::Foreign);
3124 let path = external_path(cx, cx.tcx.item_name(did),
3125 None, false, vec![], InternalSubsts::empty());
3126 ResolvedPath {
3127 path,
3128 param_names: None,
3129 did,
3130 is_generic: false,
3131 }
3132 }
3133 ty::Dynamic(ref obj, ref reg) => {
3134 // HACK: pick the first `did` as the `did` of the trait object. Someone
3135 // might want to implement "native" support for marker-trait-only
3136 // trait objects.
3137 let mut dids = obj.principal_def_id().into_iter().chain(obj.auto_traits());
3138 let did = dids.next().unwrap_or_else(|| {
3139 panic!("found trait object `{:?}` with no traits?", self)
3140 });
3141 let substs = match obj.principal() {
3142 Some(principal) => principal.skip_binder().substs,
3143 // marker traits have no substs.
3144 _ => cx.tcx.intern_substs(&[])
3145 };
3146
3147 inline::record_extern_fqn(cx, did, TypeKind::Trait);
3148
3149 let mut param_names = vec![];
3150 reg.clean(cx).map(|b| param_names.push(GenericBound::Outlives(b)));
3151 for did in dids {
3152 let empty = cx.tcx.intern_substs(&[]);
3153 let path = external_path(cx, cx.tcx.item_name(did),
3154 Some(did), false, vec![], empty);
3155 inline::record_extern_fqn(cx, did, TypeKind::Trait);
3156 let bound = GenericBound::TraitBound(PolyTrait {
3157 trait_: ResolvedPath {
3158 path,
3159 param_names: None,
3160 did,
3161 is_generic: false,
3162 },
3163 generic_params: Vec::new(),
3164 }, hir::TraitBoundModifier::None);
3165 param_names.push(bound);
3166 }
3167
3168 let mut bindings = vec![];
3169 for pb in obj.projection_bounds() {
3170 bindings.push(TypeBinding {
3171 name: cx.tcx.associated_item(pb.item_def_id()).ident.name.clean(cx),
3172 kind: TypeBindingKind::Equality {
3173 ty: pb.skip_binder().ty.clean(cx)
3174 },
3175 });
3176 }
3177
3178 let path = external_path(cx, cx.tcx.item_name(did), Some(did),
3179 false, bindings, substs);
3180 ResolvedPath {
3181 path,
3182 param_names: Some(param_names),
3183 did,
3184 is_generic: false,
3185 }
3186 }
3187 ty::Tuple(ref t) => {
3188 Tuple(t.iter().map(|t| t.expect_ty()).collect::<Vec<_>>().clean(cx))
3189 }
3190
3191 ty::Projection(ref data) => data.clean(cx),
3192
3193 ty::Param(ref p) => {
3194 if let Some(bounds) = cx.impl_trait_bounds.borrow_mut().remove(&p.index.into()) {
3195 ImplTrait(bounds)
3196 } else {
3197 Generic(p.name.to_string())
3198 }
3199 }
3200
3201 ty::Opaque(def_id, substs) => {
3202 // Grab the "TraitA + TraitB" from `impl TraitA + TraitB`,
3203 // by looking up the projections associated with the def_id.
3204 let predicates_of = cx.tcx.explicit_predicates_of(def_id);
3205 let substs = cx.tcx.lift(&substs).expect("Opaque lift failed");
3206 let bounds = predicates_of.instantiate(cx.tcx, substs);
3207 let mut regions = vec![];
3208 let mut has_sized = false;
3209 let mut bounds = bounds.predicates.iter().filter_map(|predicate| {
3210 let trait_ref = if let Some(tr) = predicate.to_opt_poly_trait_ref() {
3211 tr
3212 } else if let ty::Predicate::TypeOutlives(pred) = *predicate {
3213 // these should turn up at the end
3214 pred.skip_binder().1.clean(cx).map(|r| {
3215 regions.push(GenericBound::Outlives(r))
3216 });
3217 return None;
3218 } else {
3219 return None;
3220 };
3221
3222 if let Some(sized) = cx.tcx.lang_items().sized_trait() {
3223 if trait_ref.def_id() == sized {
3224 has_sized = true;
3225 return None;
3226 }
3227 }
3228
3229 let bounds = bounds.predicates.iter().filter_map(|pred|
3230 if let ty::Predicate::Projection(proj) = *pred {
3231 let proj = proj.skip_binder();
3232 if proj.projection_ty.trait_ref(cx.tcx) == *trait_ref.skip_binder() {
3233 Some(TypeBinding {
3234 name: cx.tcx.associated_item(proj.projection_ty.item_def_id)
3235 .ident.name.clean(cx),
3236 kind: TypeBindingKind::Equality {
3237 ty: proj.ty.clean(cx),
3238 },
3239 })
3240 } else {
3241 None
3242 }
3243 } else {
3244 None
3245 }
3246 ).collect();
3247
3248 Some((trait_ref.skip_binder(), bounds).clean(cx))
3249 }).collect::<Vec<_>>();
3250 bounds.extend(regions);
3251 if !has_sized && !bounds.is_empty() {
3252 bounds.insert(0, GenericBound::maybe_sized(cx));
3253 }
3254 ImplTrait(bounds)
3255 }
3256
3257 ty::Closure(..) | ty::Generator(..) => Tuple(vec![]), // FIXME(pcwalton)
3258
3259 ty::Bound(..) => panic!("Bound"),
3260 ty::Placeholder(..) => panic!("Placeholder"),
3261 ty::UnnormalizedProjection(..) => panic!("UnnormalizedProjection"),
3262 ty::GeneratorWitness(..) => panic!("GeneratorWitness"),
3263 ty::Infer(..) => panic!("Infer"),
3264 ty::Error => panic!("Error"),
3265 }
3266 }
3267 }
3268
3269 impl<'tcx> Clean<Constant> for ty::Const<'tcx> {
3270 fn clean(&self, cx: &DocContext<'_>) -> Constant {
3271 Constant {
3272 type_: self.ty.clean(cx),
3273 expr: format!("{}", self),
3274 }
3275 }
3276 }
3277
3278 impl Clean<Item> for hir::StructField {
3279 fn clean(&self, cx: &DocContext<'_>) -> Item {
3280 let local_did = cx.tcx.hir().local_def_id(self.hir_id);
3281
3282 Item {
3283 name: Some(self.ident.name).clean(cx),
3284 attrs: self.attrs.clean(cx),
3285 source: self.span.clean(cx),
3286 visibility: self.vis.clean(cx),
3287 stability: get_stability(cx, local_did),
3288 deprecation: get_deprecation(cx, local_did),
3289 def_id: local_did,
3290 inner: StructFieldItem(self.ty.clean(cx)),
3291 }
3292 }
3293 }
3294
3295 impl Clean<Item> for ty::FieldDef {
3296 fn clean(&self, cx: &DocContext<'_>) -> Item {
3297 Item {
3298 name: Some(self.ident.name).clean(cx),
3299 attrs: cx.tcx.get_attrs(self.did).clean(cx),
3300 source: cx.tcx.def_span(self.did).clean(cx),
3301 visibility: self.vis.clean(cx),
3302 stability: get_stability(cx, self.did),
3303 deprecation: get_deprecation(cx, self.did),
3304 def_id: self.did,
3305 inner: StructFieldItem(cx.tcx.type_of(self.did).clean(cx)),
3306 }
3307 }
3308 }
3309
3310 #[derive(Clone, PartialEq, Eq, Debug)]
3311 pub enum Visibility {
3312 Public,
3313 Inherited,
3314 Crate,
3315 Restricted(DefId, Path),
3316 }
3317
3318 impl Clean<Visibility> for hir::Visibility {
3319 fn clean(&self, cx: &DocContext<'_>) -> Visibility {
3320 match self.node {
3321 hir::VisibilityKind::Public => Visibility::Public,
3322 hir::VisibilityKind::Inherited => Visibility::Inherited,
3323 hir::VisibilityKind::Crate(_) => Visibility::Crate,
3324 hir::VisibilityKind::Restricted { ref path, .. } => {
3325 let path = path.clean(cx);
3326 let did = register_res(cx, path.res);
3327 Visibility::Restricted(did, path)
3328 }
3329 }
3330 }
3331 }
3332
3333 impl Clean<Visibility> for ty::Visibility {
3334 fn clean(&self, _: &DocContext<'_>) -> Visibility {
3335 if *self == ty::Visibility::Public { Public } else { Inherited }
3336 }
3337 }
3338
3339 #[derive(Clone, Debug)]
3340 pub struct Struct {
3341 pub struct_type: doctree::StructType,
3342 pub generics: Generics,
3343 pub fields: Vec<Item>,
3344 pub fields_stripped: bool,
3345 }
3346
3347 #[derive(Clone, Debug)]
3348 pub struct Union {
3349 pub struct_type: doctree::StructType,
3350 pub generics: Generics,
3351 pub fields: Vec<Item>,
3352 pub fields_stripped: bool,
3353 }
3354
3355 impl Clean<Item> for doctree::Struct<'_> {
3356 fn clean(&self, cx: &DocContext<'_>) -> Item {
3357 Item {
3358 name: Some(self.name.clean(cx)),
3359 attrs: self.attrs.clean(cx),
3360 source: self.whence.clean(cx),
3361 def_id: cx.tcx.hir().local_def_id(self.id),
3362 visibility: self.vis.clean(cx),
3363 stability: cx.stability(self.id).clean(cx),
3364 deprecation: cx.deprecation(self.id).clean(cx),
3365 inner: StructItem(Struct {
3366 struct_type: self.struct_type,
3367 generics: self.generics.clean(cx),
3368 fields: self.fields.clean(cx),
3369 fields_stripped: false,
3370 }),
3371 }
3372 }
3373 }
3374
3375 impl Clean<Item> for doctree::Union<'_> {
3376 fn clean(&self, cx: &DocContext<'_>) -> Item {
3377 Item {
3378 name: Some(self.name.clean(cx)),
3379 attrs: self.attrs.clean(cx),
3380 source: self.whence.clean(cx),
3381 def_id: cx.tcx.hir().local_def_id(self.id),
3382 visibility: self.vis.clean(cx),
3383 stability: cx.stability(self.id).clean(cx),
3384 deprecation: cx.deprecation(self.id).clean(cx),
3385 inner: UnionItem(Union {
3386 struct_type: self.struct_type,
3387 generics: self.generics.clean(cx),
3388 fields: self.fields.clean(cx),
3389 fields_stripped: false,
3390 }),
3391 }
3392 }
3393 }
3394
3395 /// This is a more limited form of the standard Struct, different in that
3396 /// it lacks the things most items have (name, id, parameterization). Found
3397 /// only as a variant in an enum.
3398 #[derive(Clone, Debug)]
3399 pub struct VariantStruct {
3400 pub struct_type: doctree::StructType,
3401 pub fields: Vec<Item>,
3402 pub fields_stripped: bool,
3403 }
3404
3405 impl Clean<VariantStruct> for ::rustc::hir::VariantData {
3406 fn clean(&self, cx: &DocContext<'_>) -> VariantStruct {
3407 VariantStruct {
3408 struct_type: doctree::struct_type_from_def(self),
3409 fields: self.fields().iter().map(|x| x.clean(cx)).collect(),
3410 fields_stripped: false,
3411 }
3412 }
3413 }
3414
3415 #[derive(Clone, Debug)]
3416 pub struct Enum {
3417 pub variants: IndexVec<VariantIdx, Item>,
3418 pub generics: Generics,
3419 pub variants_stripped: bool,
3420 }
3421
3422 impl Clean<Item> for doctree::Enum<'_> {
3423 fn clean(&self, cx: &DocContext<'_>) -> Item {
3424 Item {
3425 name: Some(self.name.clean(cx)),
3426 attrs: self.attrs.clean(cx),
3427 source: self.whence.clean(cx),
3428 def_id: cx.tcx.hir().local_def_id(self.id),
3429 visibility: self.vis.clean(cx),
3430 stability: cx.stability(self.id).clean(cx),
3431 deprecation: cx.deprecation(self.id).clean(cx),
3432 inner: EnumItem(Enum {
3433 variants: self.variants.iter().map(|v| v.clean(cx)).collect(),
3434 generics: self.generics.clean(cx),
3435 variants_stripped: false,
3436 }),
3437 }
3438 }
3439 }
3440
3441 #[derive(Clone, Debug)]
3442 pub struct Variant {
3443 pub kind: VariantKind,
3444 }
3445
3446 impl Clean<Item> for doctree::Variant<'_> {
3447 fn clean(&self, cx: &DocContext<'_>) -> Item {
3448 Item {
3449 name: Some(self.name.clean(cx)),
3450 attrs: self.attrs.clean(cx),
3451 source: self.whence.clean(cx),
3452 visibility: Inherited,
3453 stability: cx.stability(self.id).clean(cx),
3454 deprecation: cx.deprecation(self.id).clean(cx),
3455 def_id: cx.tcx.hir().local_def_id(self.id),
3456 inner: VariantItem(Variant {
3457 kind: self.def.clean(cx),
3458 }),
3459 }
3460 }
3461 }
3462
3463 impl Clean<Item> for ty::VariantDef {
3464 fn clean(&self, cx: &DocContext<'_>) -> Item {
3465 let kind = match self.ctor_kind {
3466 CtorKind::Const => VariantKind::CLike,
3467 CtorKind::Fn => {
3468 VariantKind::Tuple(
3469 self.fields.iter().map(|f| cx.tcx.type_of(f.did).clean(cx)).collect()
3470 )
3471 }
3472 CtorKind::Fictive => {
3473 VariantKind::Struct(VariantStruct {
3474 struct_type: doctree::Plain,
3475 fields_stripped: false,
3476 fields: self.fields.iter().map(|field| {
3477 Item {
3478 source: cx.tcx.def_span(field.did).clean(cx),
3479 name: Some(field.ident.name.clean(cx)),
3480 attrs: cx.tcx.get_attrs(field.did).clean(cx),
3481 visibility: field.vis.clean(cx),
3482 def_id: field.did,
3483 stability: get_stability(cx, field.did),
3484 deprecation: get_deprecation(cx, field.did),
3485 inner: StructFieldItem(cx.tcx.type_of(field.did).clean(cx))
3486 }
3487 }).collect()
3488 })
3489 }
3490 };
3491 Item {
3492 name: Some(self.ident.clean(cx)),
3493 attrs: inline::load_attrs(cx, self.def_id).clean(cx),
3494 source: cx.tcx.def_span(self.def_id).clean(cx),
3495 visibility: Inherited,
3496 def_id: self.def_id,
3497 inner: VariantItem(Variant { kind }),
3498 stability: get_stability(cx, self.def_id),
3499 deprecation: get_deprecation(cx, self.def_id),
3500 }
3501 }
3502 }
3503
3504 #[derive(Clone, Debug)]
3505 pub enum VariantKind {
3506 CLike,
3507 Tuple(Vec<Type>),
3508 Struct(VariantStruct),
3509 }
3510
3511 impl Clean<VariantKind> for hir::VariantData {
3512 fn clean(&self, cx: &DocContext<'_>) -> VariantKind {
3513 match self {
3514 hir::VariantData::Struct(..) => VariantKind::Struct(self.clean(cx)),
3515 hir::VariantData::Tuple(..) =>
3516 VariantKind::Tuple(self.fields().iter().map(|x| x.ty.clean(cx)).collect()),
3517 hir::VariantData::Unit(..) => VariantKind::CLike,
3518 }
3519 }
3520 }
3521
3522 #[derive(Clone, Debug)]
3523 pub struct Span {
3524 pub filename: FileName,
3525 pub loline: usize,
3526 pub locol: usize,
3527 pub hiline: usize,
3528 pub hicol: usize,
3529 pub original: syntax_pos::Span,
3530 }
3531
3532 impl Span {
3533 pub fn empty() -> Span {
3534 Span {
3535 filename: FileName::Anon(0),
3536 loline: 0, locol: 0,
3537 hiline: 0, hicol: 0,
3538 original: syntax_pos::DUMMY_SP,
3539 }
3540 }
3541
3542 pub fn span(&self) -> syntax_pos::Span {
3543 self.original
3544 }
3545 }
3546
3547 impl Clean<Span> for syntax_pos::Span {
3548 fn clean(&self, cx: &DocContext<'_>) -> Span {
3549 if self.is_dummy() {
3550 return Span::empty();
3551 }
3552
3553 let cm = cx.sess().source_map();
3554 let filename = cm.span_to_filename(*self);
3555 let lo = cm.lookup_char_pos(self.lo());
3556 let hi = cm.lookup_char_pos(self.hi());
3557 Span {
3558 filename,
3559 loline: lo.line,
3560 locol: lo.col.to_usize(),
3561 hiline: hi.line,
3562 hicol: hi.col.to_usize(),
3563 original: *self,
3564 }
3565 }
3566 }
3567
3568 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
3569 pub struct Path {
3570 pub global: bool,
3571 pub res: Res,
3572 pub segments: Vec<PathSegment>,
3573 }
3574
3575 impl Path {
3576 pub fn last_name(&self) -> &str {
3577 self.segments.last().expect("segments were empty").name.as_str()
3578 }
3579 }
3580
3581 impl Clean<Path> for hir::Path {
3582 fn clean(&self, cx: &DocContext<'_>) -> Path {
3583 Path {
3584 global: self.is_global(),
3585 res: self.res,
3586 segments: if self.is_global() { &self.segments[1..] } else { &self.segments }.clean(cx),
3587 }
3588 }
3589 }
3590
3591 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
3592 pub enum GenericArg {
3593 Lifetime(Lifetime),
3594 Type(Type),
3595 Const(Constant),
3596 }
3597
3598 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
3599 pub enum GenericArgs {
3600 AngleBracketed {
3601 args: Vec<GenericArg>,
3602 bindings: Vec<TypeBinding>,
3603 },
3604 Parenthesized {
3605 inputs: Vec<Type>,
3606 output: Option<Type>,
3607 }
3608 }
3609
3610 impl Clean<GenericArgs> for hir::GenericArgs {
3611 fn clean(&self, cx: &DocContext<'_>) -> GenericArgs {
3612 if self.parenthesized {
3613 let output = self.bindings[0].ty().clean(cx);
3614 GenericArgs::Parenthesized {
3615 inputs: self.inputs().clean(cx),
3616 output: if output != Type::Tuple(Vec::new()) { Some(output) } else { None }
3617 }
3618 } else {
3619 let elide_lifetimes = self.args.iter().all(|arg| match arg {
3620 hir::GenericArg::Lifetime(lt) => lt.is_elided(),
3621 _ => true,
3622 });
3623 GenericArgs::AngleBracketed {
3624 args: self.args.iter().filter_map(|arg| match arg {
3625 hir::GenericArg::Lifetime(lt) if !elide_lifetimes => {
3626 Some(GenericArg::Lifetime(lt.clean(cx)))
3627 }
3628 hir::GenericArg::Lifetime(_) => None,
3629 hir::GenericArg::Type(ty) => Some(GenericArg::Type(ty.clean(cx))),
3630 hir::GenericArg::Const(ct) => Some(GenericArg::Const(ct.clean(cx))),
3631 }).collect(),
3632 bindings: self.bindings.clean(cx),
3633 }
3634 }
3635 }
3636 }
3637
3638 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
3639 pub struct PathSegment {
3640 pub name: String,
3641 pub args: GenericArgs,
3642 }
3643
3644 impl Clean<PathSegment> for hir::PathSegment {
3645 fn clean(&self, cx: &DocContext<'_>) -> PathSegment {
3646 PathSegment {
3647 name: self.ident.name.clean(cx),
3648 args: self.generic_args().clean(cx),
3649 }
3650 }
3651 }
3652
3653 fn strip_type(ty: Type) -> Type {
3654 match ty {
3655 Type::ResolvedPath { path, param_names, did, is_generic } => {
3656 Type::ResolvedPath { path: strip_path(&path), param_names, did, is_generic }
3657 }
3658 Type::Tuple(inner_tys) => {
3659 Type::Tuple(inner_tys.iter().map(|t| strip_type(t.clone())).collect())
3660 }
3661 Type::Slice(inner_ty) => Type::Slice(Box::new(strip_type(*inner_ty))),
3662 Type::Array(inner_ty, s) => Type::Array(Box::new(strip_type(*inner_ty)), s),
3663 Type::RawPointer(m, inner_ty) => Type::RawPointer(m, Box::new(strip_type(*inner_ty))),
3664 Type::BorrowedRef { lifetime, mutability, type_ } => {
3665 Type::BorrowedRef { lifetime, mutability, type_: Box::new(strip_type(*type_)) }
3666 }
3667 Type::QPath { name, self_type, trait_ } => {
3668 Type::QPath {
3669 name,
3670 self_type: Box::new(strip_type(*self_type)), trait_: Box::new(strip_type(*trait_))
3671 }
3672 }
3673 _ => ty
3674 }
3675 }
3676
3677 fn strip_path(path: &Path) -> Path {
3678 let segments = path.segments.iter().map(|s| {
3679 PathSegment {
3680 name: s.name.clone(),
3681 args: GenericArgs::AngleBracketed {
3682 args: vec![],
3683 bindings: vec![],
3684 }
3685 }
3686 }).collect();
3687
3688 Path {
3689 global: path.global,
3690 res: path.res.clone(),
3691 segments,
3692 }
3693 }
3694
3695 fn qpath_to_string(p: &hir::QPath) -> String {
3696 let segments = match *p {
3697 hir::QPath::Resolved(_, ref path) => &path.segments,
3698 hir::QPath::TypeRelative(_, ref segment) => return segment.ident.to_string(),
3699 };
3700
3701 let mut s = String::new();
3702 for (i, seg) in segments.iter().enumerate() {
3703 if i > 0 {
3704 s.push_str("::");
3705 }
3706 if seg.ident.name != kw::PathRoot {
3707 s.push_str(&*seg.ident.as_str());
3708 }
3709 }
3710 s
3711 }
3712
3713 impl Clean<String> for Ident {
3714 #[inline]
3715 fn clean(&self, cx: &DocContext<'_>) -> String {
3716 self.name.clean(cx)
3717 }
3718 }
3719
3720 impl Clean<String> for ast::Name {
3721 #[inline]
3722 fn clean(&self, _: &DocContext<'_>) -> String {
3723 self.to_string()
3724 }
3725 }
3726
3727 #[derive(Clone, Debug)]
3728 pub struct Typedef {
3729 pub type_: Type,
3730 pub generics: Generics,
3731 }
3732
3733 impl Clean<Item> for doctree::Typedef<'_> {
3734 fn clean(&self, cx: &DocContext<'_>) -> Item {
3735 Item {
3736 name: Some(self.name.clean(cx)),
3737 attrs: self.attrs.clean(cx),
3738 source: self.whence.clean(cx),
3739 def_id: cx.tcx.hir().local_def_id(self.id),
3740 visibility: self.vis.clean(cx),
3741 stability: cx.stability(self.id).clean(cx),
3742 deprecation: cx.deprecation(self.id).clean(cx),
3743 inner: TypedefItem(Typedef {
3744 type_: self.ty.clean(cx),
3745 generics: self.gen.clean(cx),
3746 }, false),
3747 }
3748 }
3749 }
3750
3751 #[derive(Clone, Debug)]
3752 pub struct OpaqueTy {
3753 pub bounds: Vec<GenericBound>,
3754 pub generics: Generics,
3755 }
3756
3757 impl Clean<Item> for doctree::OpaqueTy<'_> {
3758 fn clean(&self, cx: &DocContext<'_>) -> Item {
3759 Item {
3760 name: Some(self.name.clean(cx)),
3761 attrs: self.attrs.clean(cx),
3762 source: self.whence.clean(cx),
3763 def_id: cx.tcx.hir().local_def_id(self.id),
3764 visibility: self.vis.clean(cx),
3765 stability: cx.stability(self.id).clean(cx),
3766 deprecation: cx.deprecation(self.id).clean(cx),
3767 inner: OpaqueTyItem(OpaqueTy {
3768 bounds: self.opaque_ty.bounds.clean(cx),
3769 generics: self.opaque_ty.generics.clean(cx),
3770 }, false),
3771 }
3772 }
3773 }
3774
3775 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
3776 pub struct BareFunctionDecl {
3777 pub unsafety: hir::Unsafety,
3778 pub generic_params: Vec<GenericParamDef>,
3779 pub decl: FnDecl,
3780 pub abi: Abi,
3781 }
3782
3783 impl Clean<BareFunctionDecl> for hir::BareFnTy {
3784 fn clean(&self, cx: &DocContext<'_>) -> BareFunctionDecl {
3785 let (generic_params, decl) = enter_impl_trait(cx, || {
3786 (self.generic_params.clean(cx), (&*self.decl, &self.param_names[..]).clean(cx))
3787 });
3788 BareFunctionDecl {
3789 unsafety: self.unsafety,
3790 abi: self.abi,
3791 decl,
3792 generic_params,
3793 }
3794 }
3795 }
3796
3797 #[derive(Clone, Debug)]
3798 pub struct Static {
3799 pub type_: Type,
3800 pub mutability: Mutability,
3801 /// It's useful to have the value of a static documented, but I have no
3802 /// desire to represent expressions (that'd basically be all of the AST,
3803 /// which is huge!). So, have a string.
3804 pub expr: String,
3805 }
3806
3807 impl Clean<Item> for doctree::Static<'_> {
3808 fn clean(&self, cx: &DocContext<'_>) -> Item {
3809 debug!("cleaning static {}: {:?}", self.name.clean(cx), self);
3810 Item {
3811 name: Some(self.name.clean(cx)),
3812 attrs: self.attrs.clean(cx),
3813 source: self.whence.clean(cx),
3814 def_id: cx.tcx.hir().local_def_id(self.id),
3815 visibility: self.vis.clean(cx),
3816 stability: cx.stability(self.id).clean(cx),
3817 deprecation: cx.deprecation(self.id).clean(cx),
3818 inner: StaticItem(Static {
3819 type_: self.type_.clean(cx),
3820 mutability: self.mutability.clean(cx),
3821 expr: print_const_expr(cx, self.expr),
3822 }),
3823 }
3824 }
3825 }
3826
3827 #[derive(Clone, PartialEq, Eq, Hash, Debug)]
3828 pub struct Constant {
3829 pub type_: Type,
3830 pub expr: String,
3831 }
3832
3833 impl Clean<Item> for doctree::Constant<'_> {
3834 fn clean(&self, cx: &DocContext<'_>) -> Item {
3835 Item {
3836 name: Some(self.name.clean(cx)),
3837 attrs: self.attrs.clean(cx),
3838 source: self.whence.clean(cx),
3839 def_id: cx.tcx.hir().local_def_id(self.id),
3840 visibility: self.vis.clean(cx),
3841 stability: cx.stability(self.id).clean(cx),
3842 deprecation: cx.deprecation(self.id).clean(cx),
3843 inner: ConstantItem(Constant {
3844 type_: self.type_.clean(cx),
3845 expr: print_const_expr(cx, self.expr),
3846 }),
3847 }
3848 }
3849 }
3850
3851 #[derive(Debug, Clone, PartialEq, Eq, Copy, Hash)]
3852 pub enum Mutability {
3853 Mutable,
3854 Immutable,
3855 }
3856
3857 impl Clean<Mutability> for hir::Mutability {
3858 fn clean(&self, _: &DocContext<'_>) -> Mutability {
3859 match self {
3860 &hir::MutMutable => Mutable,
3861 &hir::MutImmutable => Immutable,
3862 }
3863 }
3864 }
3865
3866 #[derive(Clone, PartialEq, Debug)]
3867 pub enum ImplPolarity {
3868 Positive,
3869 Negative,
3870 }
3871
3872 impl Clean<ImplPolarity> for ty::ImplPolarity {
3873 fn clean(&self, _: &DocContext<'_>) -> ImplPolarity {
3874 match self {
3875 &ty::ImplPolarity::Positive |
3876 // FIXME: do we want to do something else here?
3877 &ty::ImplPolarity::Reservation => ImplPolarity::Positive,
3878 &ty::ImplPolarity::Negative => ImplPolarity::Negative,
3879 }
3880 }
3881 }
3882
3883 #[derive(Clone, Debug)]
3884 pub struct Impl {
3885 pub unsafety: hir::Unsafety,
3886 pub generics: Generics,
3887 pub provided_trait_methods: FxHashSet<String>,
3888 pub trait_: Option<Type>,
3889 pub for_: Type,
3890 pub items: Vec<Item>,
3891 pub polarity: Option<ImplPolarity>,
3892 pub synthetic: bool,
3893 pub blanket_impl: Option<Type>,
3894 }
3895
3896 pub fn get_auto_trait_and_blanket_impls(
3897 cx: &DocContext<'tcx>,
3898 ty: Ty<'tcx>,
3899 param_env_def_id: DefId,
3900 ) -> impl Iterator<Item = Item> {
3901 AutoTraitFinder::new(cx).get_auto_trait_impls(ty, param_env_def_id).into_iter()
3902 .chain(BlanketImplFinder::new(cx).get_blanket_impls(ty, param_env_def_id))
3903 }
3904
3905 impl Clean<Vec<Item>> for doctree::Impl<'_> {
3906 fn clean(&self, cx: &DocContext<'_>) -> Vec<Item> {
3907 let mut ret = Vec::new();
3908 let trait_ = self.trait_.clean(cx);
3909 let items = self.items.iter().map(|ii| ii.clean(cx)).collect::<Vec<_>>();
3910 let def_id = cx.tcx.hir().local_def_id(self.id);
3911
3912 // If this impl block is an implementation of the Deref trait, then we
3913 // need to try inlining the target's inherent impl blocks as well.
3914 if trait_.def_id() == cx.tcx.lang_items().deref_trait() {
3915 build_deref_target_impls(cx, &items, &mut ret);
3916 }
3917
3918 let provided = trait_.def_id().map(|did| {
3919 cx.tcx.provided_trait_methods(did)
3920 .into_iter()
3921 .map(|meth| meth.ident.to_string())
3922 .collect()
3923 }).unwrap_or_default();
3924
3925 ret.push(Item {
3926 name: None,
3927 attrs: self.attrs.clean(cx),
3928 source: self.whence.clean(cx),
3929 def_id,
3930 visibility: self.vis.clean(cx),
3931 stability: cx.stability(self.id).clean(cx),
3932 deprecation: cx.deprecation(self.id).clean(cx),
3933 inner: ImplItem(Impl {
3934 unsafety: self.unsafety,
3935 generics: self.generics.clean(cx),
3936 provided_trait_methods: provided,
3937 trait_,
3938 for_: self.for_.clean(cx),
3939 items,
3940 polarity: Some(cx.tcx.impl_polarity(def_id).clean(cx)),
3941 synthetic: false,
3942 blanket_impl: None,
3943 })
3944 });
3945 ret
3946 }
3947 }
3948
3949 fn build_deref_target_impls(cx: &DocContext<'_>,
3950 items: &[Item],
3951 ret: &mut Vec<Item>) {
3952 use self::PrimitiveType::*;
3953 let tcx = cx.tcx;
3954
3955 for item in items {
3956 let target = match item.inner {
3957 TypedefItem(ref t, true) => &t.type_,
3958 _ => continue,
3959 };
3960 let primitive = match *target {
3961 ResolvedPath { did, .. } if did.is_local() => continue,
3962 ResolvedPath { did, .. } => {
3963 ret.extend(inline::build_impls(cx, did, None));
3964 continue
3965 }
3966 _ => match target.primitive_type() {
3967 Some(prim) => prim,
3968 None => continue,
3969 }
3970 };
3971 let did = match primitive {
3972 Isize => tcx.lang_items().isize_impl(),
3973 I8 => tcx.lang_items().i8_impl(),
3974 I16 => tcx.lang_items().i16_impl(),
3975 I32 => tcx.lang_items().i32_impl(),
3976 I64 => tcx.lang_items().i64_impl(),
3977 I128 => tcx.lang_items().i128_impl(),
3978 Usize => tcx.lang_items().usize_impl(),
3979 U8 => tcx.lang_items().u8_impl(),
3980 U16 => tcx.lang_items().u16_impl(),
3981 U32 => tcx.lang_items().u32_impl(),
3982 U64 => tcx.lang_items().u64_impl(),
3983 U128 => tcx.lang_items().u128_impl(),
3984 F32 => tcx.lang_items().f32_impl(),
3985 F64 => tcx.lang_items().f64_impl(),
3986 Char => tcx.lang_items().char_impl(),
3987 Bool => tcx.lang_items().bool_impl(),
3988 Str => tcx.lang_items().str_impl(),
3989 Slice => tcx.lang_items().slice_impl(),
3990 Array => tcx.lang_items().slice_impl(),
3991 Tuple => None,
3992 Unit => None,
3993 RawPointer => tcx.lang_items().const_ptr_impl(),
3994 Reference => None,
3995 Fn => None,
3996 Never => None,
3997 };
3998 if let Some(did) = did {
3999 if !did.is_local() {
4000 inline::build_impl(cx, did, None, ret);
4001 }
4002 }
4003 }
4004 }
4005
4006 impl Clean<Vec<Item>> for doctree::ExternCrate<'_> {
4007 fn clean(&self, cx: &DocContext<'_>) -> Vec<Item> {
4008
4009 let please_inline = self.vis.node.is_pub() && self.attrs.iter().any(|a| {
4010 a.check_name(sym::doc) && match a.meta_item_list() {
4011 Some(l) => attr::list_contains_name(&l, sym::inline),
4012 None => false,
4013 }
4014 });
4015
4016 if please_inline {
4017 let mut visited = FxHashSet::default();
4018
4019 let res = Res::Def(
4020 DefKind::Mod,
4021 DefId {
4022 krate: self.cnum,
4023 index: CRATE_DEF_INDEX,
4024 },
4025 );
4026
4027 if let Some(items) = inline::try_inline(
4028 cx, res, self.name,
4029 Some(rustc::ty::Attributes::Borrowed(self.attrs)),
4030 &mut visited
4031 ) {
4032 return items;
4033 }
4034 }
4035
4036 vec![Item {
4037 name: None,
4038 attrs: self.attrs.clean(cx),
4039 source: self.whence.clean(cx),
4040 def_id: DefId { krate: self.cnum, index: CRATE_DEF_INDEX },
4041 visibility: self.vis.clean(cx),
4042 stability: None,
4043 deprecation: None,
4044 inner: ExternCrateItem(self.name.clean(cx), self.path.clone())
4045 }]
4046 }
4047 }
4048
4049 impl Clean<Vec<Item>> for doctree::Import<'_> {
4050 fn clean(&self, cx: &DocContext<'_>) -> Vec<Item> {
4051 // We consider inlining the documentation of `pub use` statements, but we
4052 // forcefully don't inline if this is not public or if the
4053 // #[doc(no_inline)] attribute is present.
4054 // Don't inline doc(hidden) imports so they can be stripped at a later stage.
4055 let mut denied = !self.vis.node.is_pub() || self.attrs.iter().any(|a| {
4056 a.check_name(sym::doc) && match a.meta_item_list() {
4057 Some(l) => attr::list_contains_name(&l, sym::no_inline) ||
4058 attr::list_contains_name(&l, sym::hidden),
4059 None => false,
4060 }
4061 });
4062 // Also check whether imports were asked to be inlined, in case we're trying to re-export a
4063 // crate in Rust 2018+
4064 let please_inline = self.attrs.lists(sym::doc).has_word(sym::inline);
4065 let path = self.path.clean(cx);
4066 let inner = if self.glob {
4067 if !denied {
4068 let mut visited = FxHashSet::default();
4069 if let Some(items) = inline::try_inline_glob(cx, path.res, &mut visited) {
4070 return items;
4071 }
4072 }
4073
4074 Import::Glob(resolve_use_source(cx, path))
4075 } else {
4076 let name = self.name;
4077 if !please_inline {
4078 match path.res {
4079 Res::Def(DefKind::Mod, did) => {
4080 if !did.is_local() && did.index == CRATE_DEF_INDEX {
4081 // if we're `pub use`ing an extern crate root, don't inline it unless we
4082 // were specifically asked for it
4083 denied = true;
4084 }
4085 }
4086 _ => {}
4087 }
4088 }
4089 if !denied {
4090 let mut visited = FxHashSet::default();
4091 if let Some(items) = inline::try_inline(
4092 cx, path.res, name,
4093 Some(rustc::ty::Attributes::Borrowed(self.attrs)),
4094 &mut visited
4095 ) {
4096 return items;
4097 }
4098 }
4099 Import::Simple(name.clean(cx), resolve_use_source(cx, path))
4100 };
4101
4102 vec![Item {
4103 name: None,
4104 attrs: self.attrs.clean(cx),
4105 source: self.whence.clean(cx),
4106 def_id: cx.tcx.hir().local_def_id_from_node_id(ast::CRATE_NODE_ID),
4107 visibility: self.vis.clean(cx),
4108 stability: None,
4109 deprecation: None,
4110 inner: ImportItem(inner)
4111 }]
4112 }
4113 }
4114
4115 #[derive(Clone, Debug)]
4116 pub enum Import {
4117 // use source as str;
4118 Simple(String, ImportSource),
4119 // use source::*;
4120 Glob(ImportSource)
4121 }
4122
4123 #[derive(Clone, Debug)]
4124 pub struct ImportSource {
4125 pub path: Path,
4126 pub did: Option<DefId>,
4127 }
4128
4129 impl Clean<Item> for doctree::ForeignItem<'_> {
4130 fn clean(&self, cx: &DocContext<'_>) -> Item {
4131 let inner = match self.kind {
4132 hir::ForeignItemKind::Fn(ref decl, ref names, ref generics) => {
4133 let abi = cx.tcx.hir().get_foreign_abi(self.id);
4134 let (generics, decl) = enter_impl_trait(cx, || {
4135 (generics.clean(cx), (&**decl, &names[..]).clean(cx))
4136 });
4137 let (all_types, ret_types) = get_all_types(&generics, &decl, cx);
4138 ForeignFunctionItem(Function {
4139 decl,
4140 generics,
4141 header: hir::FnHeader {
4142 unsafety: hir::Unsafety::Unsafe,
4143 abi,
4144 constness: hir::Constness::NotConst,
4145 asyncness: hir::IsAsync::NotAsync,
4146 },
4147 all_types,
4148 ret_types,
4149 })
4150 }
4151 hir::ForeignItemKind::Static(ref ty, mutbl) => {
4152 ForeignStaticItem(Static {
4153 type_: ty.clean(cx),
4154 mutability: mutbl.clean(cx),
4155 expr: String::new(),
4156 })
4157 }
4158 hir::ForeignItemKind::Type => {
4159 ForeignTypeItem
4160 }
4161 };
4162
4163 Item {
4164 name: Some(self.name.clean(cx)),
4165 attrs: self.attrs.clean(cx),
4166 source: self.whence.clean(cx),
4167 def_id: cx.tcx.hir().local_def_id(self.id),
4168 visibility: self.vis.clean(cx),
4169 stability: cx.stability(self.id).clean(cx),
4170 deprecation: cx.deprecation(self.id).clean(cx),
4171 inner,
4172 }
4173 }
4174 }
4175
4176 // Utilities
4177
4178 pub trait ToSource {
4179 fn to_src(&self, cx: &DocContext<'_>) -> String;
4180 }
4181
4182 impl ToSource for syntax_pos::Span {
4183 fn to_src(&self, cx: &DocContext<'_>) -> String {
4184 debug!("converting span {:?} to snippet", self.clean(cx));
4185 let sn = match cx.sess().source_map().span_to_snippet(*self) {
4186 Ok(x) => x,
4187 Err(_) => String::new()
4188 };
4189 debug!("got snippet {}", sn);
4190 sn
4191 }
4192 }
4193
4194 fn name_from_pat(p: &hir::Pat) -> String {
4195 use rustc::hir::*;
4196 debug!("trying to get a name from pattern: {:?}", p);
4197
4198 match p.kind {
4199 PatKind::Wild => "_".to_string(),
4200 PatKind::Binding(_, _, ident, _) => ident.to_string(),
4201 PatKind::TupleStruct(ref p, ..) | PatKind::Path(ref p) => qpath_to_string(p),
4202 PatKind::Struct(ref name, ref fields, etc) => {
4203 format!("{} {{ {}{} }}", qpath_to_string(name),
4204 fields.iter().map(|fp| format!("{}: {}", fp.ident, name_from_pat(&fp.pat)))
4205 .collect::<Vec<String>>().join(", "),
4206 if etc { ", .." } else { "" }
4207 )
4208 }
4209 PatKind::Or(ref pats) => {
4210 pats.iter().map(|p| name_from_pat(&**p)).collect::<Vec<String>>().join(" | ")
4211 }
4212 PatKind::Tuple(ref elts, _) => format!("({})", elts.iter().map(|p| name_from_pat(&**p))
4213 .collect::<Vec<String>>().join(", ")),
4214 PatKind::Box(ref p) => name_from_pat(&**p),
4215 PatKind::Ref(ref p, _) => name_from_pat(&**p),
4216 PatKind::Lit(..) => {
4217 warn!("tried to get argument name from PatKind::Lit, \
4218 which is silly in function arguments");
4219 "()".to_string()
4220 },
4221 PatKind::Range(..) => panic!("tried to get argument name from PatKind::Range, \
4222 which is not allowed in function arguments"),
4223 PatKind::Slice(ref begin, ref mid, ref end) => {
4224 let begin = begin.iter().map(|p| name_from_pat(&**p));
4225 let mid = mid.as_ref().map(|p| format!("..{}", name_from_pat(&**p))).into_iter();
4226 let end = end.iter().map(|p| name_from_pat(&**p));
4227 format!("[{}]", begin.chain(mid).chain(end).collect::<Vec<_>>().join(", "))
4228 },
4229 }
4230 }
4231
4232 fn print_const(cx: &DocContext<'_>, n: &ty::Const<'_>) -> String {
4233 match n.val {
4234 ConstValue::Unevaluated(def_id, _) => {
4235 if let Some(hir_id) = cx.tcx.hir().as_local_hir_id(def_id) {
4236 print_const_expr(cx, cx.tcx.hir().body_owned_by(hir_id))
4237 } else {
4238 inline::print_inlined_const(cx, def_id)
4239 }
4240 },
4241 _ => {
4242 let mut s = n.to_string();
4243 // array lengths are obviously usize
4244 if s.ends_with("usize") {
4245 let n = s.len() - "usize".len();
4246 s.truncate(n);
4247 if s.ends_with(": ") {
4248 let n = s.len() - ": ".len();
4249 s.truncate(n);
4250 }
4251 }
4252 s
4253 },
4254 }
4255 }
4256
4257 fn print_const_expr(cx: &DocContext<'_>, body: hir::BodyId) -> String {
4258 cx.tcx.hir().hir_to_pretty_string(body.hir_id)
4259 }
4260
4261 /// Given a type Path, resolve it to a Type using the TyCtxt
4262 fn resolve_type(cx: &DocContext<'_>,
4263 path: Path,
4264 id: hir::HirId) -> Type {
4265 if id == hir::DUMMY_HIR_ID {
4266 debug!("resolve_type({:?})", path);
4267 } else {
4268 debug!("resolve_type({:?},{:?})", path, id);
4269 }
4270
4271 let is_generic = match path.res {
4272 Res::PrimTy(p) => match p {
4273 hir::Str => return Primitive(PrimitiveType::Str),
4274 hir::Bool => return Primitive(PrimitiveType::Bool),
4275 hir::Char => return Primitive(PrimitiveType::Char),
4276 hir::Int(int_ty) => return Primitive(int_ty.into()),
4277 hir::Uint(uint_ty) => return Primitive(uint_ty.into()),
4278 hir::Float(float_ty) => return Primitive(float_ty.into()),
4279 },
4280 Res::SelfTy(..) if path.segments.len() == 1 => {
4281 return Generic(kw::SelfUpper.to_string());
4282 }
4283 Res::Def(DefKind::TyParam, _) if path.segments.len() == 1 => {
4284 return Generic(format!("{:#}", path.print()));
4285 }
4286 Res::SelfTy(..)
4287 | Res::Def(DefKind::TyParam, _)
4288 | Res::Def(DefKind::AssocTy, _) => true,
4289 _ => false,
4290 };
4291 let did = register_res(&*cx, path.res);
4292 ResolvedPath { path, param_names: None, did, is_generic }
4293 }
4294
4295 pub fn register_res(cx: &DocContext<'_>, res: Res) -> DefId {
4296 debug!("register_res({:?})", res);
4297
4298 let (did, kind) = match res {
4299 Res::Def(DefKind::Fn, i) => (i, TypeKind::Function),
4300 Res::Def(DefKind::TyAlias, i) => (i, TypeKind::Typedef),
4301 Res::Def(DefKind::Enum, i) => (i, TypeKind::Enum),
4302 Res::Def(DefKind::Trait, i) => (i, TypeKind::Trait),
4303 Res::Def(DefKind::Struct, i) => (i, TypeKind::Struct),
4304 Res::Def(DefKind::Union, i) => (i, TypeKind::Union),
4305 Res::Def(DefKind::Mod, i) => (i, TypeKind::Module),
4306 Res::Def(DefKind::ForeignTy, i) => (i, TypeKind::Foreign),
4307 Res::Def(DefKind::Const, i) => (i, TypeKind::Const),
4308 Res::Def(DefKind::Static, i) => (i, TypeKind::Static),
4309 Res::Def(DefKind::Variant, i) => (cx.tcx.parent(i).expect("cannot get parent def id"),
4310 TypeKind::Enum),
4311 Res::Def(DefKind::Macro(mac_kind), i) => match mac_kind {
4312 MacroKind::Bang => (i, TypeKind::Macro),
4313 MacroKind::Attr => (i, TypeKind::Attr),
4314 MacroKind::Derive => (i, TypeKind::Derive),
4315 },
4316 Res::Def(DefKind::TraitAlias, i) => (i, TypeKind::TraitAlias),
4317 Res::SelfTy(Some(def_id), _) => (def_id, TypeKind::Trait),
4318 Res::SelfTy(_, Some(impl_def_id)) => return impl_def_id,
4319 _ => return res.def_id()
4320 };
4321 if did.is_local() { return did }
4322 inline::record_extern_fqn(cx, did, kind);
4323 if let TypeKind::Trait = kind {
4324 inline::record_extern_trait(cx, did);
4325 }
4326 did
4327 }
4328
4329 fn resolve_use_source(cx: &DocContext<'_>, path: Path) -> ImportSource {
4330 ImportSource {
4331 did: if path.res.opt_def_id().is_none() {
4332 None
4333 } else {
4334 Some(register_res(cx, path.res))
4335 },
4336 path,
4337 }
4338 }
4339
4340 #[derive(Clone, Debug)]
4341 pub struct Macro {
4342 pub source: String,
4343 pub imported_from: Option<String>,
4344 }
4345
4346 impl Clean<Item> for doctree::Macro<'_> {
4347 fn clean(&self, cx: &DocContext<'_>) -> Item {
4348 let name = self.name.clean(cx);
4349 Item {
4350 name: Some(name.clone()),
4351 attrs: self.attrs.clean(cx),
4352 source: self.whence.clean(cx),
4353 visibility: Public,
4354 stability: cx.stability(self.hid).clean(cx),
4355 deprecation: cx.deprecation(self.hid).clean(cx),
4356 def_id: self.def_id,
4357 inner: MacroItem(Macro {
4358 source: format!("macro_rules! {} {{\n{}}}",
4359 name,
4360 self.matchers.iter().map(|span| {
4361 format!(" {} => {{ ... }};\n", span.to_src(cx))
4362 }).collect::<String>()),
4363 imported_from: self.imported_from.clean(cx),
4364 }),
4365 }
4366 }
4367 }
4368
4369 #[derive(Clone, Debug)]
4370 pub struct ProcMacro {
4371 pub kind: MacroKind,
4372 pub helpers: Vec<String>,
4373 }
4374
4375 impl Clean<Item> for doctree::ProcMacro<'_> {
4376 fn clean(&self, cx: &DocContext<'_>) -> Item {
4377 Item {
4378 name: Some(self.name.clean(cx)),
4379 attrs: self.attrs.clean(cx),
4380 source: self.whence.clean(cx),
4381 visibility: Public,
4382 stability: cx.stability(self.id).clean(cx),
4383 deprecation: cx.deprecation(self.id).clean(cx),
4384 def_id: cx.tcx.hir().local_def_id(self.id),
4385 inner: ProcMacroItem(ProcMacro {
4386 kind: self.kind,
4387 helpers: self.helpers.clean(cx),
4388 }),
4389 }
4390 }
4391 }
4392
4393 #[derive(Clone, Debug)]
4394 pub struct Stability {
4395 pub level: stability::StabilityLevel,
4396 pub feature: Option<String>,
4397 pub since: String,
4398 pub deprecation: Option<Deprecation>,
4399 pub unstable_reason: Option<String>,
4400 pub issue: Option<u32>,
4401 }
4402
4403 #[derive(Clone, Debug)]
4404 pub struct Deprecation {
4405 pub since: Option<String>,
4406 pub note: Option<String>,
4407 }
4408
4409 impl Clean<Stability> for attr::Stability {
4410 fn clean(&self, _: &DocContext<'_>) -> Stability {
4411 Stability {
4412 level: stability::StabilityLevel::from_attr_level(&self.level),
4413 feature: Some(self.feature.to_string()).filter(|f| !f.is_empty()),
4414 since: match self.level {
4415 attr::Stable {ref since} => since.to_string(),
4416 _ => String::new(),
4417 },
4418 deprecation: self.rustc_depr.as_ref().map(|d| {
4419 Deprecation {
4420 note: Some(d.reason.to_string()).filter(|r| !r.is_empty()),
4421 since: Some(d.since.to_string()).filter(|d| !d.is_empty()),
4422 }
4423 }),
4424 unstable_reason: match self.level {
4425 attr::Unstable { reason: Some(ref reason), .. } => Some(reason.to_string()),
4426 _ => None,
4427 },
4428 issue: match self.level {
4429 attr::Unstable {issue, ..} => Some(issue),
4430 _ => None,
4431 }
4432 }
4433 }
4434 }
4435
4436 impl<'a> Clean<Stability> for &'a attr::Stability {
4437 fn clean(&self, dc: &DocContext<'_>) -> Stability {
4438 (**self).clean(dc)
4439 }
4440 }
4441
4442 impl Clean<Deprecation> for attr::Deprecation {
4443 fn clean(&self, _: &DocContext<'_>) -> Deprecation {
4444 Deprecation {
4445 since: self.since.map(|s| s.to_string()).filter(|s| !s.is_empty()),
4446 note: self.note.map(|n| n.to_string()).filter(|n| !n.is_empty()),
4447 }
4448 }
4449 }
4450
4451 /// An type binding on an associated type (e.g., `A = Bar` in `Foo<A = Bar>` or
4452 /// `A: Send + Sync` in `Foo<A: Send + Sync>`).
4453 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
4454 pub struct TypeBinding {
4455 pub name: String,
4456 pub kind: TypeBindingKind,
4457 }
4458
4459 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
4460 pub enum TypeBindingKind {
4461 Equality {
4462 ty: Type,
4463 },
4464 Constraint {
4465 bounds: Vec<GenericBound>,
4466 },
4467 }
4468
4469 impl TypeBinding {
4470 pub fn ty(&self) -> &Type {
4471 match self.kind {
4472 TypeBindingKind::Equality { ref ty } => ty,
4473 _ => panic!("expected equality type binding for parenthesized generic args"),
4474 }
4475 }
4476 }
4477
4478 impl Clean<TypeBinding> for hir::TypeBinding {
4479 fn clean(&self, cx: &DocContext<'_>) -> TypeBinding {
4480 TypeBinding {
4481 name: self.ident.name.clean(cx),
4482 kind: self.kind.clean(cx),
4483 }
4484 }
4485 }
4486
4487 impl Clean<TypeBindingKind> for hir::TypeBindingKind {
4488 fn clean(&self, cx: &DocContext<'_>) -> TypeBindingKind {
4489 match *self {
4490 hir::TypeBindingKind::Equality { ref ty } =>
4491 TypeBindingKind::Equality {
4492 ty: ty.clean(cx),
4493 },
4494 hir::TypeBindingKind::Constraint { ref bounds } =>
4495 TypeBindingKind::Constraint {
4496 bounds: bounds.into_iter().map(|b| b.clean(cx)).collect(),
4497 },
4498 }
4499 }
4500 }
4501
4502 pub fn enter_impl_trait<F, R>(cx: &DocContext<'_>, f: F) -> R
4503 where
4504 F: FnOnce() -> R,
4505 {
4506 let old_bounds = mem::take(&mut *cx.impl_trait_bounds.borrow_mut());
4507 let r = f();
4508 assert!(cx.impl_trait_bounds.borrow().is_empty());
4509 *cx.impl_trait_bounds.borrow_mut() = old_bounds;
4510 r
4511 }
4512
4513 #[derive(Eq, PartialEq, Hash, Copy, Clone, Debug)]
4514 enum RegionTarget<'tcx> {
4515 Region(Region<'tcx>),
4516 RegionVid(RegionVid)
4517 }
4518
4519 #[derive(Default, Debug, Clone)]
4520 struct RegionDeps<'tcx> {
4521 larger: FxHashSet<RegionTarget<'tcx>>,
4522 smaller: FxHashSet<RegionTarget<'tcx>>
4523 }
4524
4525 enum SimpleBound {
4526 TraitBound(Vec<PathSegment>, Vec<SimpleBound>, Vec<GenericParamDef>, hir::TraitBoundModifier),
4527 Outlives(Lifetime),
4528 }
4529
4530 impl From<GenericBound> for SimpleBound {
4531 fn from(bound: GenericBound) -> Self {
4532 match bound.clone() {
4533 GenericBound::Outlives(l) => SimpleBound::Outlives(l),
4534 GenericBound::TraitBound(t, mod_) => match t.trait_ {
4535 Type::ResolvedPath { path, param_names, .. } => {
4536 SimpleBound::TraitBound(path.segments,
4537 param_names
4538 .map_or_else(|| Vec::new(), |v| v.iter()
4539 .map(|p| SimpleBound::from(p.clone()))
4540 .collect()),
4541 t.generic_params,
4542 mod_)
4543 }
4544 _ => panic!("Unexpected bound {:?}", bound),
4545 }
4546 }
4547 }
4548 }