]> git.proxmox.com Git - rustc.git/blob - src/librustdoc/clean/types.rs
New upstream version 1.61.0+dfsg1
[rustc.git] / src / librustdoc / clean / types.rs
1 use std::cell::RefCell;
2 use std::default::Default;
3 use std::fmt;
4 use std::hash::Hash;
5 use std::iter;
6 use std::lazy::SyncOnceCell as OnceCell;
7 use std::path::PathBuf;
8 use std::rc::Rc;
9 use std::sync::Arc;
10 use std::vec;
11
12 use arrayvec::ArrayVec;
13
14 use rustc_ast::attr;
15 use rustc_ast::util::comments::beautify_doc_string;
16 use rustc_ast::{self as ast, AttrStyle};
17 use rustc_attr::{ConstStability, Deprecation, Stability, StabilityLevel};
18 use rustc_const_eval::const_eval::is_unstable_const_fn;
19 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
20 use rustc_data_structures::thin_vec::ThinVec;
21 use rustc_hir as hir;
22 use rustc_hir::def::{CtorKind, DefKind, Res};
23 use rustc_hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE};
24 use rustc_hir::lang_items::LangItem;
25 use rustc_hir::{BodyId, Mutability};
26 use rustc_index::vec::IndexVec;
27 use rustc_middle::ty::fast_reject::SimplifiedType;
28 use rustc_middle::ty::{self, TyCtxt};
29 use rustc_session::Session;
30 use rustc_span::hygiene::MacroKind;
31 use rustc_span::source_map::DUMMY_SP;
32 use rustc_span::symbol::{kw, sym, Ident, Symbol};
33 use rustc_span::{self, FileName, Loc};
34 use rustc_target::abi::VariantIdx;
35 use rustc_target::spec::abi::Abi;
36 use rustc_typeck::check::intrinsic::intrinsic_operation_unsafety;
37
38 use crate::clean::cfg::Cfg;
39 use crate::clean::external_path;
40 use crate::clean::inline::{self, print_inlined_const};
41 use crate::clean::utils::{is_literal_expr, print_const_expr, print_evaluated_const};
42 use crate::clean::Clean;
43 use crate::core::DocContext;
44 use crate::formats::cache::Cache;
45 use crate::formats::item_type::ItemType;
46 use crate::html::render::Context;
47 use crate::passes::collect_intra_doc_links::UrlFragment;
48
49 crate use self::FnRetTy::*;
50 crate use self::ItemKind::*;
51 crate use self::SelfTy::*;
52 crate use self::Type::{
53 Array, BareFunction, BorrowedRef, DynTrait, Generic, ImplTrait, Infer, Primitive, QPath,
54 RawPointer, Slice, Tuple,
55 };
56 crate use self::Visibility::{Inherited, Public};
57
58 crate type ItemIdSet = FxHashSet<ItemId>;
59
60 #[derive(Debug, Clone, PartialEq, Eq, Hash, Copy)]
61 crate enum ItemId {
62 /// A "normal" item that uses a [`DefId`] for identification.
63 DefId(DefId),
64 /// Identifier that is used for auto traits.
65 Auto { trait_: DefId, for_: DefId },
66 /// Identifier that is used for blanket implementations.
67 Blanket { impl_id: DefId, for_: DefId },
68 /// Identifier for primitive types.
69 Primitive(PrimitiveType, CrateNum),
70 }
71
72 impl ItemId {
73 #[inline]
74 crate fn is_local(self) -> bool {
75 match self {
76 ItemId::Auto { for_: id, .. }
77 | ItemId::Blanket { for_: id, .. }
78 | ItemId::DefId(id) => id.is_local(),
79 ItemId::Primitive(_, krate) => krate == LOCAL_CRATE,
80 }
81 }
82
83 #[inline]
84 #[track_caller]
85 crate fn expect_def_id(self) -> DefId {
86 self.as_def_id()
87 .unwrap_or_else(|| panic!("ItemId::expect_def_id: `{:?}` isn't a DefId", self))
88 }
89
90 #[inline]
91 crate fn as_def_id(self) -> Option<DefId> {
92 match self {
93 ItemId::DefId(id) => Some(id),
94 _ => None,
95 }
96 }
97
98 #[inline]
99 crate fn krate(self) -> CrateNum {
100 match self {
101 ItemId::Auto { for_: id, .. }
102 | ItemId::Blanket { for_: id, .. }
103 | ItemId::DefId(id) => id.krate,
104 ItemId::Primitive(_, krate) => krate,
105 }
106 }
107
108 #[inline]
109 crate fn index(self) -> Option<DefIndex> {
110 match self {
111 ItemId::DefId(id) => Some(id.index),
112 _ => None,
113 }
114 }
115 }
116
117 impl From<DefId> for ItemId {
118 fn from(id: DefId) -> Self {
119 Self::DefId(id)
120 }
121 }
122
123 /// The crate currently being documented.
124 #[derive(Clone, Debug)]
125 crate struct Crate {
126 crate module: Item,
127 crate primitives: ThinVec<(DefId, PrimitiveType)>,
128 /// Only here so that they can be filtered through the rustdoc passes.
129 crate external_traits: Rc<RefCell<FxHashMap<DefId, TraitWithExtraInfo>>>,
130 }
131
132 // `Crate` is frequently moved by-value. Make sure it doesn't unintentionally get bigger.
133 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
134 rustc_data_structures::static_assert_size!(Crate, 72);
135
136 impl Crate {
137 crate fn name(&self, tcx: TyCtxt<'_>) -> Symbol {
138 ExternalCrate::LOCAL.name(tcx)
139 }
140
141 crate fn src(&self, tcx: TyCtxt<'_>) -> FileName {
142 ExternalCrate::LOCAL.src(tcx)
143 }
144 }
145
146 /// This struct is used to wrap additional information added by rustdoc on a `trait` item.
147 #[derive(Clone, Debug)]
148 crate struct TraitWithExtraInfo {
149 crate trait_: Trait,
150 crate is_notable: bool,
151 }
152
153 #[derive(Copy, Clone, Debug)]
154 crate struct ExternalCrate {
155 crate crate_num: CrateNum,
156 }
157
158 impl ExternalCrate {
159 const LOCAL: Self = Self { crate_num: LOCAL_CRATE };
160
161 #[inline]
162 crate fn def_id(&self) -> DefId {
163 DefId { krate: self.crate_num, index: CRATE_DEF_INDEX }
164 }
165
166 crate fn src(&self, tcx: TyCtxt<'_>) -> FileName {
167 let krate_span = tcx.def_span(self.def_id());
168 tcx.sess.source_map().span_to_filename(krate_span)
169 }
170
171 crate fn name(&self, tcx: TyCtxt<'_>) -> Symbol {
172 tcx.crate_name(self.crate_num)
173 }
174
175 crate fn src_root(&self, tcx: TyCtxt<'_>) -> PathBuf {
176 match self.src(tcx) {
177 FileName::Real(ref p) => match p.local_path_if_available().parent() {
178 Some(p) => p.to_path_buf(),
179 None => PathBuf::new(),
180 },
181 _ => PathBuf::new(),
182 }
183 }
184
185 /// Attempts to find where an external crate is located, given that we're
186 /// rendering in to the specified source destination.
187 crate fn location(
188 &self,
189 extern_url: Option<&str>,
190 extern_url_takes_precedence: bool,
191 dst: &std::path::Path,
192 tcx: TyCtxt<'_>,
193 ) -> ExternalLocation {
194 use ExternalLocation::*;
195
196 fn to_remote(url: impl ToString) -> ExternalLocation {
197 let mut url = url.to_string();
198 if !url.ends_with('/') {
199 url.push('/');
200 }
201 Remote(url)
202 }
203
204 // See if there's documentation generated into the local directory
205 // WARNING: since rustdoc creates these directories as it generates documentation, this check is only accurate before rendering starts.
206 // Make sure to call `location()` by that time.
207 let local_location = dst.join(self.name(tcx).as_str());
208 if local_location.is_dir() {
209 return Local;
210 }
211
212 if extern_url_takes_precedence {
213 if let Some(url) = extern_url {
214 return to_remote(url);
215 }
216 }
217
218 // Failing that, see if there's an attribute specifying where to find this
219 // external crate
220 let did = DefId { krate: self.crate_num, index: CRATE_DEF_INDEX };
221 tcx.get_attrs(did)
222 .lists(sym::doc)
223 .filter(|a| a.has_name(sym::html_root_url))
224 .filter_map(|a| a.value_str())
225 .map(to_remote)
226 .next()
227 .or_else(|| extern_url.map(to_remote)) // NOTE: only matters if `extern_url_takes_precedence` is false
228 .unwrap_or(Unknown) // Well, at least we tried.
229 }
230
231 crate fn keywords(&self, tcx: TyCtxt<'_>) -> ThinVec<(DefId, Symbol)> {
232 let root = self.def_id();
233
234 let as_keyword = |res: Res<!>| {
235 if let Res::Def(DefKind::Mod, def_id) = res {
236 let attrs = tcx.get_attrs(def_id);
237 let mut keyword = None;
238 for attr in attrs.lists(sym::doc) {
239 if attr.has_name(sym::keyword) {
240 if let Some(v) = attr.value_str() {
241 keyword = Some(v);
242 break;
243 }
244 }
245 }
246 return keyword.map(|p| (def_id, p));
247 }
248 None
249 };
250 if root.is_local() {
251 tcx.hir()
252 .root_module()
253 .item_ids
254 .iter()
255 .filter_map(|&id| {
256 let item = tcx.hir().item(id);
257 match item.kind {
258 hir::ItemKind::Mod(_) => {
259 as_keyword(Res::Def(DefKind::Mod, id.def_id.to_def_id()))
260 }
261 hir::ItemKind::Use(path, hir::UseKind::Single)
262 if tcx.visibility(id.def_id).is_public() =>
263 {
264 as_keyword(path.res.expect_non_local())
265 .map(|(_, prim)| (id.def_id.to_def_id(), prim))
266 }
267 _ => None,
268 }
269 })
270 .collect()
271 } else {
272 tcx.module_children(root).iter().map(|item| item.res).filter_map(as_keyword).collect()
273 }
274 }
275
276 crate fn primitives(&self, tcx: TyCtxt<'_>) -> ThinVec<(DefId, PrimitiveType)> {
277 let root = self.def_id();
278
279 // Collect all inner modules which are tagged as implementations of
280 // primitives.
281 //
282 // Note that this loop only searches the top-level items of the crate,
283 // and this is intentional. If we were to search the entire crate for an
284 // item tagged with `#[doc(primitive)]` then we would also have to
285 // search the entirety of external modules for items tagged
286 // `#[doc(primitive)]`, which is a pretty inefficient process (decoding
287 // all that metadata unconditionally).
288 //
289 // In order to keep the metadata load under control, the
290 // `#[doc(primitive)]` feature is explicitly designed to only allow the
291 // primitive tags to show up as the top level items in a crate.
292 //
293 // Also note that this does not attempt to deal with modules tagged
294 // duplicately for the same primitive. This is handled later on when
295 // rendering by delegating everything to a hash map.
296 let as_primitive = |res: Res<!>| {
297 if let Res::Def(DefKind::Mod, def_id) = res {
298 let attrs = tcx.get_attrs(def_id);
299 let mut prim = None;
300 for attr in attrs.lists(sym::doc) {
301 if let Some(v) = attr.value_str() {
302 if attr.has_name(sym::primitive) {
303 prim = PrimitiveType::from_symbol(v);
304 if prim.is_some() {
305 break;
306 }
307 // FIXME: should warn on unknown primitives?
308 }
309 }
310 }
311 return prim.map(|p| (def_id, p));
312 }
313 None
314 };
315
316 if root.is_local() {
317 tcx.hir()
318 .root_module()
319 .item_ids
320 .iter()
321 .filter_map(|&id| {
322 let item = tcx.hir().item(id);
323 match item.kind {
324 hir::ItemKind::Mod(_) => {
325 as_primitive(Res::Def(DefKind::Mod, id.def_id.to_def_id()))
326 }
327 hir::ItemKind::Use(path, hir::UseKind::Single)
328 if tcx.visibility(id.def_id).is_public() =>
329 {
330 as_primitive(path.res.expect_non_local()).map(|(_, prim)| {
331 // Pretend the primitive is local.
332 (id.def_id.to_def_id(), prim)
333 })
334 }
335 _ => None,
336 }
337 })
338 .collect()
339 } else {
340 tcx.module_children(root).iter().map(|item| item.res).filter_map(as_primitive).collect()
341 }
342 }
343 }
344
345 /// Indicates where an external crate can be found.
346 #[derive(Debug)]
347 crate enum ExternalLocation {
348 /// Remote URL root of the external crate
349 Remote(String),
350 /// This external crate can be found in the local doc/ folder
351 Local,
352 /// The external crate could not be found.
353 Unknown,
354 }
355
356 /// Anything with a source location and set of attributes and, optionally, a
357 /// name. That is, anything that can be documented. This doesn't correspond
358 /// directly to the AST's concept of an item; it's a strict superset.
359 #[derive(Clone)]
360 crate struct Item {
361 /// The name of this item.
362 /// Optional because not every item has a name, e.g. impls.
363 crate name: Option<Symbol>,
364 crate attrs: Box<Attributes>,
365 crate visibility: Visibility,
366 /// Information about this item that is specific to what kind of item it is.
367 /// E.g., struct vs enum vs function.
368 crate kind: Box<ItemKind>,
369 crate def_id: ItemId,
370
371 crate cfg: Option<Arc<Cfg>>,
372 }
373
374 /// NOTE: this does NOT unconditionally print every item, to avoid thousands of lines of logs.
375 /// If you want to see the debug output for attributes and the `kind` as well, use `{:#?}` instead of `{:?}`.
376 impl fmt::Debug for Item {
377 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
378 let alternate = f.alternate();
379 // hand-picked fields that don't bloat the logs too much
380 let mut fmt = f.debug_struct("Item");
381 fmt.field("name", &self.name)
382 .field("visibility", &self.visibility)
383 .field("def_id", &self.def_id);
384 // allow printing the full item if someone really wants to
385 if alternate {
386 fmt.field("attrs", &self.attrs).field("kind", &self.kind).field("cfg", &self.cfg);
387 } else {
388 fmt.field("kind", &self.type_());
389 fmt.field("docs", &self.doc_value());
390 }
391 fmt.finish()
392 }
393 }
394
395 // `Item` is used a lot. Make sure it doesn't unintentionally get bigger.
396 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
397 rustc_data_structures::static_assert_size!(Item, 56);
398
399 crate fn rustc_span(def_id: DefId, tcx: TyCtxt<'_>) -> Span {
400 Span::new(def_id.as_local().map_or_else(
401 || tcx.def_span(def_id),
402 |local| {
403 let hir = tcx.hir();
404 hir.span_with_body(hir.local_def_id_to_hir_id(local))
405 },
406 ))
407 }
408
409 impl Item {
410 crate fn stability<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Option<Stability> {
411 self.def_id.as_def_id().and_then(|did| tcx.lookup_stability(did))
412 }
413
414 crate fn const_stability<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Option<ConstStability> {
415 self.def_id.as_def_id().and_then(|did| tcx.lookup_const_stability(did))
416 }
417
418 crate fn deprecation(&self, tcx: TyCtxt<'_>) -> Option<Deprecation> {
419 self.def_id.as_def_id().and_then(|did| tcx.lookup_deprecation(did))
420 }
421
422 crate fn inner_docs(&self, tcx: TyCtxt<'_>) -> bool {
423 self.def_id.as_def_id().map(|did| tcx.get_attrs(did).inner_docs()).unwrap_or(false)
424 }
425
426 crate fn span(&self, tcx: TyCtxt<'_>) -> Span {
427 let kind = match &*self.kind {
428 ItemKind::StrippedItem(k) => k,
429 _ => &*self.kind,
430 };
431 match kind {
432 ItemKind::ModuleItem(Module { span, .. }) => *span,
433 ItemKind::ImplItem(Impl { kind: ImplKind::Auto, .. }) => Span::dummy(),
434 ItemKind::ImplItem(Impl { kind: ImplKind::Blanket(_), .. }) => {
435 if let ItemId::Blanket { impl_id, .. } = self.def_id {
436 rustc_span(impl_id, tcx)
437 } else {
438 panic!("blanket impl item has non-blanket ID")
439 }
440 }
441 _ => {
442 self.def_id.as_def_id().map(|did| rustc_span(did, tcx)).unwrap_or_else(Span::dummy)
443 }
444 }
445 }
446
447 crate fn attr_span(&self, tcx: TyCtxt<'_>) -> rustc_span::Span {
448 crate::passes::span_of_attrs(&self.attrs).unwrap_or_else(|| self.span(tcx).inner())
449 }
450
451 /// Finds the `doc` attribute as a NameValue and returns the corresponding
452 /// value found.
453 crate fn doc_value(&self) -> Option<String> {
454 self.attrs.doc_value()
455 }
456
457 /// Convenience wrapper around [`Self::from_def_id_and_parts`] which converts
458 /// `hir_id` to a [`DefId`]
459 crate fn from_hir_id_and_parts(
460 hir_id: hir::HirId,
461 name: Option<Symbol>,
462 kind: ItemKind,
463 cx: &mut DocContext<'_>,
464 ) -> Item {
465 Item::from_def_id_and_parts(cx.tcx.hir().local_def_id(hir_id).to_def_id(), name, kind, cx)
466 }
467
468 crate fn from_def_id_and_parts(
469 def_id: DefId,
470 name: Option<Symbol>,
471 kind: ItemKind,
472 cx: &mut DocContext<'_>,
473 ) -> Item {
474 let ast_attrs = cx.tcx.get_attrs(def_id);
475
476 Self::from_def_id_and_attrs_and_parts(
477 def_id,
478 name,
479 kind,
480 box ast_attrs.clean(cx),
481 cx,
482 ast_attrs.cfg(cx.tcx, &cx.cache.hidden_cfg),
483 )
484 }
485
486 crate fn from_def_id_and_attrs_and_parts(
487 def_id: DefId,
488 name: Option<Symbol>,
489 kind: ItemKind,
490 attrs: Box<Attributes>,
491 cx: &mut DocContext<'_>,
492 cfg: Option<Arc<Cfg>>,
493 ) -> Item {
494 trace!("name={:?}, def_id={:?}", name, def_id);
495
496 // Primitives and Keywords are written in the source code as private modules.
497 // The modules need to be private so that nobody actually uses them, but the
498 // keywords and primitives that they are documenting are public.
499 let visibility = if matches!(&kind, ItemKind::KeywordItem(..) | ItemKind::PrimitiveItem(..))
500 {
501 Visibility::Public
502 } else {
503 cx.tcx.visibility(def_id).clean(cx)
504 };
505
506 Item { def_id: def_id.into(), kind: box kind, name, attrs, visibility, cfg }
507 }
508
509 /// Finds all `doc` attributes as NameValues and returns their corresponding values, joined
510 /// with newlines.
511 crate fn collapsed_doc_value(&self) -> Option<String> {
512 self.attrs.collapsed_doc_value()
513 }
514
515 crate fn links(&self, cx: &Context<'_>) -> Vec<RenderedLink> {
516 use crate::html::format::href;
517
518 cx.cache()
519 .intra_doc_links
520 .get(&self.def_id)
521 .map_or(&[][..], |v| v.as_slice())
522 .iter()
523 .filter_map(|ItemLink { link: s, link_text, did, ref fragment }| {
524 debug!(?did);
525 if let Ok((mut href, ..)) = href(*did, cx) {
526 debug!(?href);
527 if let Some(ref fragment) = *fragment {
528 fragment.render(&mut href, cx.tcx()).unwrap()
529 }
530 Some(RenderedLink {
531 original_text: s.clone(),
532 new_text: link_text.clone(),
533 href,
534 })
535 } else {
536 None
537 }
538 })
539 .collect()
540 }
541
542 /// Find a list of all link names, without finding their href.
543 ///
544 /// This is used for generating summary text, which does not include
545 /// the link text, but does need to know which `[]`-bracketed names
546 /// are actually links.
547 crate fn link_names(&self, cache: &Cache) -> Vec<RenderedLink> {
548 cache
549 .intra_doc_links
550 .get(&self.def_id)
551 .map_or(&[][..], |v| v.as_slice())
552 .iter()
553 .map(|ItemLink { link: s, link_text, .. }| RenderedLink {
554 original_text: s.clone(),
555 new_text: link_text.clone(),
556 href: String::new(),
557 })
558 .collect()
559 }
560
561 crate fn is_crate(&self) -> bool {
562 self.is_mod() && self.def_id.as_def_id().map_or(false, |did| did.index == CRATE_DEF_INDEX)
563 }
564 crate fn is_mod(&self) -> bool {
565 self.type_() == ItemType::Module
566 }
567 crate fn is_trait(&self) -> bool {
568 self.type_() == ItemType::Trait
569 }
570 crate fn is_struct(&self) -> bool {
571 self.type_() == ItemType::Struct
572 }
573 crate fn is_enum(&self) -> bool {
574 self.type_() == ItemType::Enum
575 }
576 crate fn is_variant(&self) -> bool {
577 self.type_() == ItemType::Variant
578 }
579 crate fn is_associated_type(&self) -> bool {
580 self.type_() == ItemType::AssocType
581 }
582 crate fn is_associated_const(&self) -> bool {
583 self.type_() == ItemType::AssocConst
584 }
585 crate fn is_method(&self) -> bool {
586 self.type_() == ItemType::Method
587 }
588 crate fn is_ty_method(&self) -> bool {
589 self.type_() == ItemType::TyMethod
590 }
591 crate fn is_typedef(&self) -> bool {
592 self.type_() == ItemType::Typedef
593 }
594 crate fn is_primitive(&self) -> bool {
595 self.type_() == ItemType::Primitive
596 }
597 crate fn is_union(&self) -> bool {
598 self.type_() == ItemType::Union
599 }
600 crate fn is_import(&self) -> bool {
601 self.type_() == ItemType::Import
602 }
603 crate fn is_extern_crate(&self) -> bool {
604 self.type_() == ItemType::ExternCrate
605 }
606 crate fn is_keyword(&self) -> bool {
607 self.type_() == ItemType::Keyword
608 }
609 crate fn is_stripped(&self) -> bool {
610 match *self.kind {
611 StrippedItem(..) => true,
612 ImportItem(ref i) => !i.should_be_displayed,
613 _ => false,
614 }
615 }
616 crate fn has_stripped_fields(&self) -> Option<bool> {
617 match *self.kind {
618 StructItem(ref _struct) => Some(_struct.fields_stripped),
619 UnionItem(ref union) => Some(union.fields_stripped),
620 VariantItem(Variant::Struct(ref vstruct)) => Some(vstruct.fields_stripped),
621 _ => None,
622 }
623 }
624
625 crate fn stability_class(&self, tcx: TyCtxt<'_>) -> Option<String> {
626 self.stability(tcx).as_ref().and_then(|s| {
627 let mut classes = Vec::with_capacity(2);
628
629 if s.level.is_unstable() {
630 classes.push("unstable");
631 }
632
633 // FIXME: what about non-staged API items that are deprecated?
634 if self.deprecation(tcx).is_some() {
635 classes.push("deprecated");
636 }
637
638 if !classes.is_empty() { Some(classes.join(" ")) } else { None }
639 })
640 }
641
642 crate fn stable_since(&self, tcx: TyCtxt<'_>) -> Option<Symbol> {
643 match self.stability(tcx)?.level {
644 StabilityLevel::Stable { since, .. } => Some(since),
645 StabilityLevel::Unstable { .. } => None,
646 }
647 }
648
649 crate fn const_stable_since(&self, tcx: TyCtxt<'_>) -> Option<Symbol> {
650 match self.const_stability(tcx)?.level {
651 StabilityLevel::Stable { since, .. } => Some(since),
652 StabilityLevel::Unstable { .. } => None,
653 }
654 }
655
656 crate fn is_non_exhaustive(&self) -> bool {
657 self.attrs.other_attrs.iter().any(|a| a.has_name(sym::non_exhaustive))
658 }
659
660 /// Returns a documentation-level item type from the item.
661 crate fn type_(&self) -> ItemType {
662 ItemType::from(self)
663 }
664
665 crate fn is_default(&self) -> bool {
666 match *self.kind {
667 ItemKind::MethodItem(_, Some(defaultness)) => {
668 defaultness.has_value() && !defaultness.is_final()
669 }
670 _ => false,
671 }
672 }
673
674 /// Returns a `FnHeader` if `self` is a function item, otherwise returns `None`.
675 crate fn fn_header(&self, tcx: TyCtxt<'_>) -> Option<hir::FnHeader> {
676 fn build_fn_header(
677 def_id: DefId,
678 tcx: TyCtxt<'_>,
679 asyncness: hir::IsAsync,
680 ) -> hir::FnHeader {
681 let sig = tcx.fn_sig(def_id);
682 let constness =
683 if tcx.is_const_fn(def_id) && is_unstable_const_fn(tcx, def_id).is_none() {
684 hir::Constness::Const
685 } else {
686 hir::Constness::NotConst
687 };
688 hir::FnHeader { unsafety: sig.unsafety(), abi: sig.abi(), constness, asyncness }
689 }
690 let header = match *self.kind {
691 ItemKind::ForeignFunctionItem(_) => {
692 let abi = tcx.fn_sig(self.def_id.as_def_id().unwrap()).abi();
693 hir::FnHeader {
694 unsafety: if abi == Abi::RustIntrinsic {
695 intrinsic_operation_unsafety(self.name.unwrap())
696 } else {
697 hir::Unsafety::Unsafe
698 },
699 abi,
700 constness: hir::Constness::NotConst,
701 asyncness: hir::IsAsync::NotAsync,
702 }
703 }
704 ItemKind::FunctionItem(_) | ItemKind::MethodItem(_, _) => {
705 let def_id = self.def_id.as_def_id().unwrap();
706 build_fn_header(def_id, tcx, tcx.asyncness(def_id))
707 }
708 ItemKind::TyMethodItem(_) => {
709 build_fn_header(self.def_id.as_def_id().unwrap(), tcx, hir::IsAsync::NotAsync)
710 }
711 _ => return None,
712 };
713 Some(header)
714 }
715 }
716
717 #[derive(Clone, Debug)]
718 crate enum ItemKind {
719 ExternCrateItem {
720 /// The crate's name, *not* the name it's imported as.
721 src: Option<Symbol>,
722 },
723 ImportItem(Import),
724 StructItem(Struct),
725 UnionItem(Union),
726 EnumItem(Enum),
727 FunctionItem(Function),
728 ModuleItem(Module),
729 TypedefItem(Typedef, bool /* is associated type */),
730 OpaqueTyItem(OpaqueTy),
731 StaticItem(Static),
732 ConstantItem(Constant),
733 TraitItem(Trait),
734 TraitAliasItem(TraitAlias),
735 ImplItem(Impl),
736 /// A method signature only. Used for required methods in traits (ie,
737 /// non-default-methods).
738 TyMethodItem(Function),
739 /// A method with a body.
740 MethodItem(Function, Option<hir::Defaultness>),
741 StructFieldItem(Type),
742 VariantItem(Variant),
743 /// `fn`s from an extern block
744 ForeignFunctionItem(Function),
745 /// `static`s from an extern block
746 ForeignStaticItem(Static),
747 /// `type`s from an extern block
748 ForeignTypeItem,
749 MacroItem(Macro),
750 ProcMacroItem(ProcMacro),
751 PrimitiveItem(PrimitiveType),
752 AssocConstItem(Type, Option<ConstantKind>),
753 /// An associated item in a trait or trait impl.
754 ///
755 /// The bounds may be non-empty if there is a `where` clause.
756 /// The `Option<Type>` is the default concrete type (e.g. `trait Trait { type Target = usize; }`)
757 AssocTypeItem(Box<Generics>, Vec<GenericBound>, Option<Type>),
758 /// An item that has been stripped by a rustdoc pass
759 StrippedItem(Box<ItemKind>),
760 KeywordItem(Symbol),
761 }
762
763 impl ItemKind {
764 /// Some items contain others such as structs (for their fields) and Enums
765 /// (for their variants). This method returns those contained items.
766 crate fn inner_items(&self) -> impl Iterator<Item = &Item> {
767 match self {
768 StructItem(s) => s.fields.iter(),
769 UnionItem(u) => u.fields.iter(),
770 VariantItem(Variant::Struct(v)) => v.fields.iter(),
771 VariantItem(Variant::Tuple(v)) => v.iter(),
772 EnumItem(e) => e.variants.iter(),
773 TraitItem(t) => t.items.iter(),
774 ImplItem(i) => i.items.iter(),
775 ModuleItem(m) => m.items.iter(),
776 ExternCrateItem { .. }
777 | ImportItem(_)
778 | FunctionItem(_)
779 | TypedefItem(_, _)
780 | OpaqueTyItem(_)
781 | StaticItem(_)
782 | ConstantItem(_)
783 | TraitAliasItem(_)
784 | TyMethodItem(_)
785 | MethodItem(_, _)
786 | StructFieldItem(_)
787 | VariantItem(_)
788 | ForeignFunctionItem(_)
789 | ForeignStaticItem(_)
790 | ForeignTypeItem
791 | MacroItem(_)
792 | ProcMacroItem(_)
793 | PrimitiveItem(_)
794 | AssocConstItem(_, _)
795 | AssocTypeItem(..)
796 | StrippedItem(_)
797 | KeywordItem(_) => [].iter(),
798 }
799 }
800 }
801
802 #[derive(Clone, Debug)]
803 crate struct Module {
804 crate items: Vec<Item>,
805 crate span: Span,
806 }
807
808 crate trait AttributesExt {
809 type AttributeIterator<'a>: Iterator<Item = ast::NestedMetaItem>
810 where
811 Self: 'a;
812
813 fn lists<'a>(&'a self, name: Symbol) -> Self::AttributeIterator<'a>;
814
815 fn span(&self) -> Option<rustc_span::Span>;
816
817 fn inner_docs(&self) -> bool;
818
819 fn other_attrs(&self) -> Vec<ast::Attribute>;
820
821 fn cfg(&self, tcx: TyCtxt<'_>, hidden_cfg: &FxHashSet<Cfg>) -> Option<Arc<Cfg>>;
822 }
823
824 impl AttributesExt for [ast::Attribute] {
825 type AttributeIterator<'a> = impl Iterator<Item = ast::NestedMetaItem> + 'a;
826
827 fn lists<'a>(&'a self, name: Symbol) -> Self::AttributeIterator<'a> {
828 self.iter()
829 .filter(move |attr| attr.has_name(name))
830 .filter_map(ast::Attribute::meta_item_list)
831 .flatten()
832 }
833
834 /// Return the span of the first doc-comment, if it exists.
835 fn span(&self) -> Option<rustc_span::Span> {
836 self.iter().find(|attr| attr.doc_str().is_some()).map(|attr| attr.span)
837 }
838
839 /// Returns whether the first doc-comment is an inner attribute.
840 ///
841 //// If there are no doc-comments, return true.
842 /// FIXME(#78591): Support both inner and outer attributes on the same item.
843 fn inner_docs(&self) -> bool {
844 self.iter().find(|a| a.doc_str().is_some()).map_or(true, |a| a.style == AttrStyle::Inner)
845 }
846
847 fn other_attrs(&self) -> Vec<ast::Attribute> {
848 self.iter().filter(|attr| attr.doc_str().is_none()).cloned().collect()
849 }
850
851 fn cfg(&self, tcx: TyCtxt<'_>, hidden_cfg: &FxHashSet<Cfg>) -> Option<Arc<Cfg>> {
852 let sess = tcx.sess;
853 let doc_cfg_active = tcx.features().doc_cfg;
854 let doc_auto_cfg_active = tcx.features().doc_auto_cfg;
855
856 fn single<T: IntoIterator>(it: T) -> Option<T::Item> {
857 let mut iter = it.into_iter();
858 let item = iter.next()?;
859 if iter.next().is_some() {
860 return None;
861 }
862 Some(item)
863 }
864
865 let mut cfg = if doc_cfg_active || doc_auto_cfg_active {
866 let mut doc_cfg = self
867 .iter()
868 .filter(|attr| attr.has_name(sym::doc))
869 .flat_map(|attr| attr.meta_item_list().unwrap_or_else(Vec::new))
870 .filter(|attr| attr.has_name(sym::cfg))
871 .peekable();
872 if doc_cfg.peek().is_some() && doc_cfg_active {
873 doc_cfg
874 .filter_map(|attr| Cfg::parse(attr.meta_item()?).ok())
875 .fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg)
876 } else if doc_auto_cfg_active {
877 self.iter()
878 .filter(|attr| attr.has_name(sym::cfg))
879 .filter_map(|attr| single(attr.meta_item_list()?))
880 .filter_map(|attr| {
881 Cfg::parse_without(attr.meta_item()?, hidden_cfg).ok().flatten()
882 })
883 .fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg)
884 } else {
885 Cfg::True
886 }
887 } else {
888 Cfg::True
889 };
890
891 for attr in self.iter() {
892 // #[doc]
893 if attr.doc_str().is_none() && attr.has_name(sym::doc) {
894 // #[doc(...)]
895 if let Some(list) = attr.meta().as_ref().and_then(|mi| mi.meta_item_list()) {
896 for item in list {
897 // #[doc(hidden)]
898 if !item.has_name(sym::cfg) {
899 continue;
900 }
901 // #[doc(cfg(...))]
902 if let Some(cfg_mi) = item
903 .meta_item()
904 .and_then(|item| rustc_expand::config::parse_cfg(item, sess))
905 {
906 match Cfg::parse(cfg_mi) {
907 Ok(new_cfg) => cfg &= new_cfg,
908 Err(e) => {
909 sess.span_err(e.span, e.msg);
910 }
911 }
912 }
913 }
914 }
915 }
916 }
917
918 // treat #[target_feature(enable = "feat")] attributes as if they were
919 // #[doc(cfg(target_feature = "feat"))] attributes as well
920 for attr in self.lists(sym::target_feature) {
921 if attr.has_name(sym::enable) {
922 if let Some(feat) = attr.value_str() {
923 let meta = attr::mk_name_value_item_str(
924 Ident::with_dummy_span(sym::target_feature),
925 feat,
926 DUMMY_SP,
927 );
928 if let Ok(feat_cfg) = Cfg::parse(&meta) {
929 cfg &= feat_cfg;
930 }
931 }
932 }
933 }
934
935 if cfg == Cfg::True { None } else { Some(Arc::new(cfg)) }
936 }
937 }
938
939 crate trait NestedAttributesExt {
940 /// Returns `true` if the attribute list contains a specific `word`
941 fn has_word(self, word: Symbol) -> bool
942 where
943 Self: std::marker::Sized,
944 {
945 <Self as NestedAttributesExt>::get_word_attr(self, word).is_some()
946 }
947
948 /// Returns `Some(attr)` if the attribute list contains 'attr'
949 /// corresponding to a specific `word`
950 fn get_word_attr(self, word: Symbol) -> Option<ast::NestedMetaItem>;
951 }
952
953 impl<I: Iterator<Item = ast::NestedMetaItem>> NestedAttributesExt for I {
954 fn get_word_attr(mut self, word: Symbol) -> Option<ast::NestedMetaItem> {
955 self.find(|attr| attr.is_word() && attr.has_name(word))
956 }
957 }
958
959 /// A portion of documentation, extracted from a `#[doc]` attribute.
960 ///
961 /// Each variant contains the line number within the complete doc-comment where the fragment
962 /// starts, as well as the Span where the corresponding doc comment or attribute is located.
963 ///
964 /// Included files are kept separate from inline doc comments so that proper line-number
965 /// information can be given when a doctest fails. Sugared doc comments and "raw" doc comments are
966 /// kept separate because of issue #42760.
967 #[derive(Clone, PartialEq, Eq, Debug)]
968 crate struct DocFragment {
969 crate span: rustc_span::Span,
970 /// The module this doc-comment came from.
971 ///
972 /// This allows distinguishing between the original documentation and a pub re-export.
973 /// If it is `None`, the item was not re-exported.
974 crate parent_module: Option<DefId>,
975 crate doc: Symbol,
976 crate kind: DocFragmentKind,
977 crate indent: usize,
978 }
979
980 // `DocFragment` is used a lot. Make sure it doesn't unintentionally get bigger.
981 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
982 rustc_data_structures::static_assert_size!(DocFragment, 32);
983
984 #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
985 crate enum DocFragmentKind {
986 /// A doc fragment created from a `///` or `//!` doc comment.
987 SugaredDoc,
988 /// A doc fragment created from a "raw" `#[doc=""]` attribute.
989 RawDoc,
990 }
991
992 /// The goal of this function is to apply the `DocFragment` transformation that is required when
993 /// transforming into the final Markdown, which is applying the computed indent to each line in
994 /// each doc fragment (a `DocFragment` can contain multiple lines in case of `#[doc = ""]`).
995 ///
996 /// Note: remove the trailing newline where appropriate
997 fn add_doc_fragment(out: &mut String, frag: &DocFragment) {
998 let s = frag.doc.as_str();
999 let mut iter = s.lines();
1000 if s == "" {
1001 out.push('\n');
1002 return;
1003 }
1004 while let Some(line) = iter.next() {
1005 if line.chars().any(|c| !c.is_whitespace()) {
1006 assert!(line.len() >= frag.indent);
1007 out.push_str(&line[frag.indent..]);
1008 } else {
1009 out.push_str(line);
1010 }
1011 out.push('\n');
1012 }
1013 }
1014
1015 /// Collapse a collection of [`DocFragment`]s into one string,
1016 /// handling indentation and newlines as needed.
1017 crate fn collapse_doc_fragments(doc_strings: &[DocFragment]) -> String {
1018 let mut acc = String::new();
1019 for frag in doc_strings {
1020 add_doc_fragment(&mut acc, frag);
1021 }
1022 acc.pop();
1023 acc
1024 }
1025
1026 /// A link that has not yet been rendered.
1027 ///
1028 /// This link will be turned into a rendered link by [`Item::links`].
1029 #[derive(Clone, Debug, PartialEq, Eq)]
1030 crate struct ItemLink {
1031 /// The original link written in the markdown
1032 crate link: String,
1033 /// The link text displayed in the HTML.
1034 ///
1035 /// This may not be the same as `link` if there was a disambiguator
1036 /// in an intra-doc link (e.g. \[`fn@f`\])
1037 crate link_text: String,
1038 crate did: DefId,
1039 /// The url fragment to append to the link
1040 crate fragment: Option<UrlFragment>,
1041 }
1042
1043 pub struct RenderedLink {
1044 /// The text the link was original written as.
1045 ///
1046 /// This could potentially include disambiguators and backticks.
1047 crate original_text: String,
1048 /// The text to display in the HTML
1049 crate new_text: String,
1050 /// The URL to put in the `href`
1051 crate href: String,
1052 }
1053
1054 /// The attributes on an [`Item`], including attributes like `#[derive(...)]` and `#[inline]`,
1055 /// as well as doc comments.
1056 #[derive(Clone, Debug, Default)]
1057 crate struct Attributes {
1058 crate doc_strings: Vec<DocFragment>,
1059 crate other_attrs: Vec<ast::Attribute>,
1060 }
1061
1062 impl Attributes {
1063 crate fn lists(&self, name: Symbol) -> impl Iterator<Item = ast::NestedMetaItem> + '_ {
1064 self.other_attrs.lists(name)
1065 }
1066
1067 crate fn has_doc_flag(&self, flag: Symbol) -> bool {
1068 for attr in &self.other_attrs {
1069 if !attr.has_name(sym::doc) {
1070 continue;
1071 }
1072
1073 if let Some(items) = attr.meta_item_list() {
1074 if items.iter().filter_map(|i| i.meta_item()).any(|it| it.has_name(flag)) {
1075 return true;
1076 }
1077 }
1078 }
1079
1080 false
1081 }
1082
1083 crate fn from_ast(
1084 attrs: &[ast::Attribute],
1085 additional_attrs: Option<(&[ast::Attribute], DefId)>,
1086 ) -> Attributes {
1087 let mut doc_strings: Vec<DocFragment> = vec![];
1088 let clean_attr = |(attr, parent_module): (&ast::Attribute, Option<DefId>)| {
1089 if let Some((value, kind)) = attr.doc_str_and_comment_kind() {
1090 trace!("got doc_str={:?}", value);
1091 let value = beautify_doc_string(value, kind);
1092 let kind = if attr.is_doc_comment() {
1093 DocFragmentKind::SugaredDoc
1094 } else {
1095 DocFragmentKind::RawDoc
1096 };
1097
1098 let frag =
1099 DocFragment { span: attr.span, doc: value, kind, parent_module, indent: 0 };
1100
1101 doc_strings.push(frag);
1102
1103 None
1104 } else {
1105 Some(attr.clone())
1106 }
1107 };
1108
1109 // Additional documentation should be shown before the original documentation
1110 let other_attrs = additional_attrs
1111 .into_iter()
1112 .flat_map(|(attrs, id)| attrs.iter().map(move |attr| (attr, Some(id))))
1113 .chain(attrs.iter().map(|attr| (attr, None)))
1114 .filter_map(clean_attr)
1115 .collect();
1116
1117 Attributes { doc_strings, other_attrs }
1118 }
1119
1120 /// Finds the `doc` attribute as a NameValue and returns the corresponding
1121 /// value found.
1122 crate fn doc_value(&self) -> Option<String> {
1123 let mut iter = self.doc_strings.iter();
1124
1125 let ori = iter.next()?;
1126 let mut out = String::new();
1127 add_doc_fragment(&mut out, ori);
1128 for new_frag in iter {
1129 add_doc_fragment(&mut out, new_frag);
1130 }
1131 out.pop();
1132 if out.is_empty() { None } else { Some(out) }
1133 }
1134
1135 /// Return the doc-comments on this item, grouped by the module they came from.
1136 ///
1137 /// The module can be different if this is a re-export with added documentation.
1138 crate fn collapsed_doc_value_by_module_level(&self) -> FxHashMap<Option<DefId>, String> {
1139 let mut ret = FxHashMap::default();
1140 if self.doc_strings.len() == 0 {
1141 return ret;
1142 }
1143 let last_index = self.doc_strings.len() - 1;
1144
1145 for (i, new_frag) in self.doc_strings.iter().enumerate() {
1146 let out = ret.entry(new_frag.parent_module).or_default();
1147 add_doc_fragment(out, new_frag);
1148 if i == last_index {
1149 out.pop();
1150 }
1151 }
1152 ret
1153 }
1154
1155 /// Finds all `doc` attributes as NameValues and returns their corresponding values, joined
1156 /// with newlines.
1157 crate fn collapsed_doc_value(&self) -> Option<String> {
1158 if self.doc_strings.is_empty() {
1159 None
1160 } else {
1161 Some(collapse_doc_fragments(&self.doc_strings))
1162 }
1163 }
1164
1165 crate fn get_doc_aliases(&self) -> Box<[Symbol]> {
1166 let mut aliases = FxHashSet::default();
1167
1168 for attr in self.other_attrs.lists(sym::doc).filter(|a| a.has_name(sym::alias)) {
1169 if let Some(values) = attr.meta_item_list() {
1170 for l in values {
1171 match l.literal().unwrap().kind {
1172 ast::LitKind::Str(s, _) => {
1173 aliases.insert(s);
1174 }
1175 _ => unreachable!(),
1176 }
1177 }
1178 } else {
1179 aliases.insert(attr.value_str().unwrap());
1180 }
1181 }
1182 aliases.into_iter().collect::<Vec<_>>().into()
1183 }
1184 }
1185
1186 impl PartialEq for Attributes {
1187 fn eq(&self, rhs: &Self) -> bool {
1188 self.doc_strings == rhs.doc_strings
1189 && self
1190 .other_attrs
1191 .iter()
1192 .map(|attr| attr.id)
1193 .eq(rhs.other_attrs.iter().map(|attr| attr.id))
1194 }
1195 }
1196
1197 impl Eq for Attributes {}
1198
1199 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
1200 crate enum GenericBound {
1201 TraitBound(PolyTrait, hir::TraitBoundModifier),
1202 Outlives(Lifetime),
1203 }
1204
1205 impl GenericBound {
1206 crate fn maybe_sized(cx: &mut DocContext<'_>) -> GenericBound {
1207 let did = cx.tcx.require_lang_item(LangItem::Sized, None);
1208 let empty = cx.tcx.intern_substs(&[]);
1209 let path = external_path(cx, did, false, vec![], empty);
1210 inline::record_extern_fqn(cx, did, ItemType::Trait);
1211 GenericBound::TraitBound(
1212 PolyTrait { trait_: path, generic_params: Vec::new() },
1213 hir::TraitBoundModifier::Maybe,
1214 )
1215 }
1216
1217 crate fn is_sized_bound(&self, cx: &DocContext<'_>) -> bool {
1218 use rustc_hir::TraitBoundModifier as TBM;
1219 if let GenericBound::TraitBound(PolyTrait { ref trait_, .. }, TBM::None) = *self {
1220 if Some(trait_.def_id()) == cx.tcx.lang_items().sized_trait() {
1221 return true;
1222 }
1223 }
1224 false
1225 }
1226
1227 crate fn get_poly_trait(&self) -> Option<PolyTrait> {
1228 if let GenericBound::TraitBound(ref p, _) = *self {
1229 return Some(p.clone());
1230 }
1231 None
1232 }
1233
1234 crate fn get_trait_path(&self) -> Option<Path> {
1235 if let GenericBound::TraitBound(PolyTrait { ref trait_, .. }, _) = *self {
1236 Some(trait_.clone())
1237 } else {
1238 None
1239 }
1240 }
1241 }
1242
1243 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
1244 crate struct Lifetime(pub Symbol);
1245
1246 impl Lifetime {
1247 crate fn statik() -> Lifetime {
1248 Lifetime(kw::StaticLifetime)
1249 }
1250
1251 crate fn elided() -> Lifetime {
1252 Lifetime(kw::UnderscoreLifetime)
1253 }
1254 }
1255
1256 #[derive(Clone, Debug)]
1257 crate enum WherePredicate {
1258 BoundPredicate { ty: Type, bounds: Vec<GenericBound>, bound_params: Vec<Lifetime> },
1259 RegionPredicate { lifetime: Lifetime, bounds: Vec<GenericBound> },
1260 EqPredicate { lhs: Type, rhs: Term },
1261 }
1262
1263 impl WherePredicate {
1264 crate fn get_bounds(&self) -> Option<&[GenericBound]> {
1265 match *self {
1266 WherePredicate::BoundPredicate { ref bounds, .. } => Some(bounds),
1267 WherePredicate::RegionPredicate { ref bounds, .. } => Some(bounds),
1268 _ => None,
1269 }
1270 }
1271 }
1272
1273 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
1274 crate enum GenericParamDefKind {
1275 Lifetime { outlives: Vec<Lifetime> },
1276 Type { did: DefId, bounds: Vec<GenericBound>, default: Option<Box<Type>>, synthetic: bool },
1277 Const { did: DefId, ty: Box<Type>, default: Option<Box<String>> },
1278 }
1279
1280 impl GenericParamDefKind {
1281 crate fn is_type(&self) -> bool {
1282 matches!(self, GenericParamDefKind::Type { .. })
1283 }
1284 }
1285
1286 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
1287 crate struct GenericParamDef {
1288 crate name: Symbol,
1289 crate kind: GenericParamDefKind,
1290 }
1291
1292 // `GenericParamDef` is used in many places. Make sure it doesn't unintentionally get bigger.
1293 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
1294 rustc_data_structures::static_assert_size!(GenericParamDef, 56);
1295
1296 impl GenericParamDef {
1297 crate fn is_synthetic_type_param(&self) -> bool {
1298 match self.kind {
1299 GenericParamDefKind::Lifetime { .. } | GenericParamDefKind::Const { .. } => false,
1300 GenericParamDefKind::Type { synthetic, .. } => synthetic,
1301 }
1302 }
1303
1304 crate fn is_type(&self) -> bool {
1305 self.kind.is_type()
1306 }
1307
1308 crate fn get_bounds(&self) -> Option<&[GenericBound]> {
1309 match self.kind {
1310 GenericParamDefKind::Type { ref bounds, .. } => Some(bounds),
1311 _ => None,
1312 }
1313 }
1314 }
1315
1316 // maybe use a Generic enum and use Vec<Generic>?
1317 #[derive(Clone, Debug, Default)]
1318 crate struct Generics {
1319 crate params: Vec<GenericParamDef>,
1320 crate where_predicates: Vec<WherePredicate>,
1321 }
1322
1323 #[derive(Clone, Debug)]
1324 crate struct Function {
1325 crate decl: FnDecl,
1326 crate generics: Generics,
1327 }
1328
1329 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
1330 crate struct FnDecl {
1331 crate inputs: Arguments,
1332 crate output: FnRetTy,
1333 crate c_variadic: bool,
1334 }
1335
1336 impl FnDecl {
1337 crate fn self_type(&self) -> Option<SelfTy> {
1338 self.inputs.values.get(0).and_then(|v| v.to_self())
1339 }
1340
1341 /// Returns the sugared return type for an async function.
1342 ///
1343 /// For example, if the return type is `impl std::future::Future<Output = i32>`, this function
1344 /// will return `i32`.
1345 ///
1346 /// # Panics
1347 ///
1348 /// This function will panic if the return type does not match the expected sugaring for async
1349 /// functions.
1350 crate fn sugared_async_return_type(&self) -> FnRetTy {
1351 match &self.output {
1352 FnRetTy::Return(Type::ImplTrait(bounds)) => match &bounds[0] {
1353 GenericBound::TraitBound(PolyTrait { trait_, .. }, ..) => {
1354 let bindings = trait_.bindings().unwrap();
1355 let ret_ty = bindings[0].term();
1356 let ty = ret_ty.ty().expect("Unexpected constant return term");
1357 FnRetTy::Return(ty.clone())
1358 }
1359 _ => panic!("unexpected desugaring of async function"),
1360 },
1361 _ => panic!("unexpected desugaring of async function"),
1362 }
1363 }
1364 }
1365
1366 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
1367 crate struct Arguments {
1368 crate values: Vec<Argument>,
1369 }
1370
1371 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
1372 crate struct Argument {
1373 crate type_: Type,
1374 crate name: Symbol,
1375 /// This field is used to represent "const" arguments from the `rustc_legacy_const_generics`
1376 /// feature. More information in <https://github.com/rust-lang/rust/issues/83167>.
1377 crate is_const: bool,
1378 }
1379
1380 #[derive(Clone, PartialEq, Debug)]
1381 crate enum SelfTy {
1382 SelfValue,
1383 SelfBorrowed(Option<Lifetime>, Mutability),
1384 SelfExplicit(Type),
1385 }
1386
1387 impl Argument {
1388 crate fn to_self(&self) -> Option<SelfTy> {
1389 if self.name != kw::SelfLower {
1390 return None;
1391 }
1392 if self.type_.is_self_type() {
1393 return Some(SelfValue);
1394 }
1395 match self.type_ {
1396 BorrowedRef { ref lifetime, mutability, ref type_ } if type_.is_self_type() => {
1397 Some(SelfBorrowed(lifetime.clone(), mutability))
1398 }
1399 _ => Some(SelfExplicit(self.type_.clone())),
1400 }
1401 }
1402 }
1403
1404 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
1405 crate enum FnRetTy {
1406 Return(Type),
1407 DefaultReturn,
1408 }
1409
1410 impl FnRetTy {
1411 crate fn as_return(&self) -> Option<&Type> {
1412 match self {
1413 Return(ret) => Some(ret),
1414 DefaultReturn => None,
1415 }
1416 }
1417 }
1418
1419 #[derive(Clone, Debug)]
1420 crate struct Trait {
1421 crate unsafety: hir::Unsafety,
1422 crate items: Vec<Item>,
1423 crate generics: Generics,
1424 crate bounds: Vec<GenericBound>,
1425 crate is_auto: bool,
1426 }
1427
1428 #[derive(Clone, Debug)]
1429 crate struct TraitAlias {
1430 crate generics: Generics,
1431 crate bounds: Vec<GenericBound>,
1432 }
1433
1434 /// A trait reference, which may have higher ranked lifetimes.
1435 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
1436 crate struct PolyTrait {
1437 crate trait_: Path,
1438 crate generic_params: Vec<GenericParamDef>,
1439 }
1440
1441 /// Rustdoc's representation of types, mostly based on the [`hir::Ty`].
1442 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
1443 crate enum Type {
1444 /// A named type, which could be a trait.
1445 ///
1446 /// This is mostly Rustdoc's version of [`hir::Path`].
1447 /// It has to be different because Rustdoc's [`PathSegment`] can contain cleaned generics.
1448 Path { path: Path },
1449 /// A `dyn Trait` object: `dyn for<'a> Trait<'a> + Send + 'static`
1450 DynTrait(Vec<PolyTrait>, Option<Lifetime>),
1451 /// A type parameter.
1452 Generic(Symbol),
1453 /// A primitive (aka, builtin) type.
1454 Primitive(PrimitiveType),
1455 /// A function pointer: `extern "ABI" fn(...) -> ...`
1456 BareFunction(Box<BareFunctionDecl>),
1457 /// A tuple type: `(i32, &str)`.
1458 Tuple(Vec<Type>),
1459 /// A slice type (does *not* include the `&`): `[i32]`
1460 Slice(Box<Type>),
1461 /// An array type.
1462 ///
1463 /// The `String` field is a stringified version of the array's length parameter.
1464 Array(Box<Type>, String),
1465 /// A raw pointer type: `*const i32`, `*mut i32`
1466 RawPointer(Mutability, Box<Type>),
1467 /// A reference type: `&i32`, `&'a mut Foo`
1468 BorrowedRef { lifetime: Option<Lifetime>, mutability: Mutability, type_: Box<Type> },
1469
1470 /// A qualified path to an associated item: `<Type as Trait>::Name`
1471 QPath {
1472 assoc: Box<PathSegment>,
1473 self_type: Box<Type>,
1474 /// FIXME: This is a hack that should be removed; see [this discussion][1].
1475 ///
1476 /// [1]: https://github.com/rust-lang/rust/pull/85479#discussion_r635729093
1477 self_def_id: Option<DefId>,
1478 trait_: Path,
1479 },
1480
1481 /// A type that is inferred: `_`
1482 Infer,
1483
1484 /// An `impl Trait`: `impl TraitA + TraitB + ...`
1485 ImplTrait(Vec<GenericBound>),
1486 }
1487
1488 // `Type` is used a lot. Make sure it doesn't unintentionally get bigger.
1489 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
1490 rustc_data_structures::static_assert_size!(Type, 80);
1491
1492 impl Type {
1493 /// When comparing types for equality, it can help to ignore `&` wrapping.
1494 crate fn without_borrowed_ref(&self) -> &Type {
1495 let mut result = self;
1496 while let Type::BorrowedRef { type_, .. } = result {
1497 result = &*type_;
1498 }
1499 result
1500 }
1501
1502 /// Check if two types are "potentially the same".
1503 /// This is different from `Eq`, because it knows that things like
1504 /// `Placeholder` are possible matches for everything.
1505 crate fn is_same(&self, other: &Self, cache: &Cache) -> bool {
1506 match (self, other) {
1507 // Recursive cases.
1508 (Type::Tuple(a), Type::Tuple(b)) => {
1509 a.len() == b.len() && a.iter().zip(b).all(|(a, b)| a.is_same(&b, cache))
1510 }
1511 (Type::Slice(a), Type::Slice(b)) => a.is_same(&b, cache),
1512 (Type::Array(a, al), Type::Array(b, bl)) => al == bl && a.is_same(&b, cache),
1513 (Type::RawPointer(mutability, type_), Type::RawPointer(b_mutability, b_type_)) => {
1514 mutability == b_mutability && type_.is_same(&b_type_, cache)
1515 }
1516 (
1517 Type::BorrowedRef { mutability, type_, .. },
1518 Type::BorrowedRef { mutability: b_mutability, type_: b_type_, .. },
1519 ) => mutability == b_mutability && type_.is_same(&b_type_, cache),
1520 // Placeholders and generics are equal to all other types.
1521 (Type::Infer, _) | (_, Type::Infer) => true,
1522 (Type::Generic(_), _) | (_, Type::Generic(_)) => true,
1523 // Other cases, such as primitives, just use recursion.
1524 (a, b) => a
1525 .def_id(cache)
1526 .and_then(|a| Some((a, b.def_id(cache)?)))
1527 .map(|(a, b)| a == b)
1528 .unwrap_or(false),
1529 }
1530 }
1531
1532 crate fn primitive_type(&self) -> Option<PrimitiveType> {
1533 match *self {
1534 Primitive(p) | BorrowedRef { type_: box Primitive(p), .. } => Some(p),
1535 Slice(..) | BorrowedRef { type_: box Slice(..), .. } => Some(PrimitiveType::Slice),
1536 Array(..) | BorrowedRef { type_: box Array(..), .. } => Some(PrimitiveType::Array),
1537 Tuple(ref tys) => {
1538 if tys.is_empty() {
1539 Some(PrimitiveType::Unit)
1540 } else {
1541 Some(PrimitiveType::Tuple)
1542 }
1543 }
1544 RawPointer(..) => Some(PrimitiveType::RawPointer),
1545 BareFunction(..) => Some(PrimitiveType::Fn),
1546 _ => None,
1547 }
1548 }
1549
1550 /// Checks if this is a `T::Name` path for an associated type.
1551 crate fn is_assoc_ty(&self) -> bool {
1552 match self {
1553 Type::Path { path, .. } => path.is_assoc_ty(),
1554 _ => false,
1555 }
1556 }
1557
1558 crate fn is_self_type(&self) -> bool {
1559 match *self {
1560 Generic(name) => name == kw::SelfUpper,
1561 _ => false,
1562 }
1563 }
1564
1565 crate fn generics(&self) -> Option<Vec<&Type>> {
1566 match self {
1567 Type::Path { path, .. } => path.generics(),
1568 _ => None,
1569 }
1570 }
1571
1572 crate fn is_full_generic(&self) -> bool {
1573 matches!(self, Type::Generic(_))
1574 }
1575
1576 crate fn is_primitive(&self) -> bool {
1577 self.primitive_type().is_some()
1578 }
1579
1580 crate fn projection(&self) -> Option<(&Type, DefId, PathSegment)> {
1581 if let QPath { self_type, trait_, assoc, .. } = self {
1582 Some((&self_type, trait_.def_id(), *assoc.clone()))
1583 } else {
1584 None
1585 }
1586 }
1587
1588 fn inner_def_id(&self, cache: Option<&Cache>) -> Option<DefId> {
1589 let t: PrimitiveType = match *self {
1590 Type::Path { ref path } => return Some(path.def_id()),
1591 DynTrait(ref bounds, _) => return Some(bounds[0].trait_.def_id()),
1592 Primitive(p) => return cache.and_then(|c| c.primitive_locations.get(&p).cloned()),
1593 BorrowedRef { type_: box Generic(..), .. } => PrimitiveType::Reference,
1594 BorrowedRef { ref type_, .. } => return type_.inner_def_id(cache),
1595 Tuple(ref tys) => {
1596 if tys.is_empty() {
1597 PrimitiveType::Unit
1598 } else {
1599 PrimitiveType::Tuple
1600 }
1601 }
1602 BareFunction(..) => PrimitiveType::Fn,
1603 Slice(..) => PrimitiveType::Slice,
1604 Array(..) => PrimitiveType::Array,
1605 RawPointer(..) => PrimitiveType::RawPointer,
1606 QPath { ref self_type, .. } => return self_type.inner_def_id(cache),
1607 Generic(_) | Infer | ImplTrait(_) => return None,
1608 };
1609 cache.and_then(|c| Primitive(t).def_id(c))
1610 }
1611
1612 /// Use this method to get the [DefId] of a [clean] AST node, including [PrimitiveType]s.
1613 ///
1614 /// [clean]: crate::clean
1615 crate fn def_id(&self, cache: &Cache) -> Option<DefId> {
1616 self.inner_def_id(Some(cache))
1617 }
1618 }
1619
1620 /// A primitive (aka, builtin) type.
1621 ///
1622 /// This represents things like `i32`, `str`, etc.
1623 ///
1624 /// N.B. This has to be different from [`hir::PrimTy`] because it also includes types that aren't
1625 /// paths, like [`Self::Unit`].
1626 #[derive(Clone, PartialEq, Eq, Hash, Copy, Debug)]
1627 crate enum PrimitiveType {
1628 Isize,
1629 I8,
1630 I16,
1631 I32,
1632 I64,
1633 I128,
1634 Usize,
1635 U8,
1636 U16,
1637 U32,
1638 U64,
1639 U128,
1640 F32,
1641 F64,
1642 Char,
1643 Bool,
1644 Str,
1645 Slice,
1646 Array,
1647 Tuple,
1648 Unit,
1649 RawPointer,
1650 Reference,
1651 Fn,
1652 Never,
1653 }
1654
1655 type SimplifiedTypes = FxHashMap<PrimitiveType, ArrayVec<SimplifiedType, 2>>;
1656 impl PrimitiveType {
1657 crate fn from_hir(prim: hir::PrimTy) -> PrimitiveType {
1658 use ast::{FloatTy, IntTy, UintTy};
1659 match prim {
1660 hir::PrimTy::Int(IntTy::Isize) => PrimitiveType::Isize,
1661 hir::PrimTy::Int(IntTy::I8) => PrimitiveType::I8,
1662 hir::PrimTy::Int(IntTy::I16) => PrimitiveType::I16,
1663 hir::PrimTy::Int(IntTy::I32) => PrimitiveType::I32,
1664 hir::PrimTy::Int(IntTy::I64) => PrimitiveType::I64,
1665 hir::PrimTy::Int(IntTy::I128) => PrimitiveType::I128,
1666 hir::PrimTy::Uint(UintTy::Usize) => PrimitiveType::Usize,
1667 hir::PrimTy::Uint(UintTy::U8) => PrimitiveType::U8,
1668 hir::PrimTy::Uint(UintTy::U16) => PrimitiveType::U16,
1669 hir::PrimTy::Uint(UintTy::U32) => PrimitiveType::U32,
1670 hir::PrimTy::Uint(UintTy::U64) => PrimitiveType::U64,
1671 hir::PrimTy::Uint(UintTy::U128) => PrimitiveType::U128,
1672 hir::PrimTy::Float(FloatTy::F32) => PrimitiveType::F32,
1673 hir::PrimTy::Float(FloatTy::F64) => PrimitiveType::F64,
1674 hir::PrimTy::Str => PrimitiveType::Str,
1675 hir::PrimTy::Bool => PrimitiveType::Bool,
1676 hir::PrimTy::Char => PrimitiveType::Char,
1677 }
1678 }
1679
1680 crate fn from_symbol(s: Symbol) -> Option<PrimitiveType> {
1681 match s {
1682 sym::isize => Some(PrimitiveType::Isize),
1683 sym::i8 => Some(PrimitiveType::I8),
1684 sym::i16 => Some(PrimitiveType::I16),
1685 sym::i32 => Some(PrimitiveType::I32),
1686 sym::i64 => Some(PrimitiveType::I64),
1687 sym::i128 => Some(PrimitiveType::I128),
1688 sym::usize => Some(PrimitiveType::Usize),
1689 sym::u8 => Some(PrimitiveType::U8),
1690 sym::u16 => Some(PrimitiveType::U16),
1691 sym::u32 => Some(PrimitiveType::U32),
1692 sym::u64 => Some(PrimitiveType::U64),
1693 sym::u128 => Some(PrimitiveType::U128),
1694 sym::bool => Some(PrimitiveType::Bool),
1695 sym::char => Some(PrimitiveType::Char),
1696 sym::str => Some(PrimitiveType::Str),
1697 sym::f32 => Some(PrimitiveType::F32),
1698 sym::f64 => Some(PrimitiveType::F64),
1699 sym::array => Some(PrimitiveType::Array),
1700 sym::slice => Some(PrimitiveType::Slice),
1701 sym::tuple => Some(PrimitiveType::Tuple),
1702 sym::unit => Some(PrimitiveType::Unit),
1703 sym::pointer => Some(PrimitiveType::RawPointer),
1704 sym::reference => Some(PrimitiveType::Reference),
1705 kw::Fn => Some(PrimitiveType::Fn),
1706 sym::never => Some(PrimitiveType::Never),
1707 _ => None,
1708 }
1709 }
1710
1711 crate fn simplified_types() -> &'static SimplifiedTypes {
1712 use ty::fast_reject::SimplifiedTypeGen::*;
1713 use ty::{FloatTy, IntTy, UintTy};
1714 use PrimitiveType::*;
1715 static CELL: OnceCell<SimplifiedTypes> = OnceCell::new();
1716
1717 let single = |x| iter::once(x).collect();
1718 CELL.get_or_init(move || {
1719 map! {
1720 Isize => single(IntSimplifiedType(IntTy::Isize)),
1721 I8 => single(IntSimplifiedType(IntTy::I8)),
1722 I16 => single(IntSimplifiedType(IntTy::I16)),
1723 I32 => single(IntSimplifiedType(IntTy::I32)),
1724 I64 => single(IntSimplifiedType(IntTy::I64)),
1725 I128 => single(IntSimplifiedType(IntTy::I128)),
1726 Usize => single(UintSimplifiedType(UintTy::Usize)),
1727 U8 => single(UintSimplifiedType(UintTy::U8)),
1728 U16 => single(UintSimplifiedType(UintTy::U16)),
1729 U32 => single(UintSimplifiedType(UintTy::U32)),
1730 U64 => single(UintSimplifiedType(UintTy::U64)),
1731 U128 => single(UintSimplifiedType(UintTy::U128)),
1732 F32 => single(FloatSimplifiedType(FloatTy::F32)),
1733 F64 => single(FloatSimplifiedType(FloatTy::F64)),
1734 Str => single(StrSimplifiedType),
1735 Bool => single(BoolSimplifiedType),
1736 Char => single(CharSimplifiedType),
1737 Array => single(ArraySimplifiedType),
1738 Slice => single(SliceSimplifiedType),
1739 // FIXME: If we ever add an inherent impl for tuples
1740 // with different lengths, they won't show in rustdoc.
1741 //
1742 // Either manually update this arrayvec at this point
1743 // or start with a more complex refactoring.
1744 Tuple => [TupleSimplifiedType(2), TupleSimplifiedType(3)].into(),
1745 Unit => single(TupleSimplifiedType(0)),
1746 RawPointer => [PtrSimplifiedType(Mutability::Not), PtrSimplifiedType(Mutability::Mut)].into(),
1747 Reference => [RefSimplifiedType(Mutability::Not), RefSimplifiedType(Mutability::Mut)].into(),
1748 // FIXME: This will be wrong if we ever add inherent impls
1749 // for function pointers.
1750 Fn => ArrayVec::new(),
1751 Never => single(NeverSimplifiedType),
1752 }
1753 })
1754 }
1755
1756 crate fn impls<'tcx>(&self, tcx: TyCtxt<'tcx>) -> impl Iterator<Item = DefId> + 'tcx {
1757 Self::simplified_types()
1758 .get(self)
1759 .into_iter()
1760 .flatten()
1761 .flat_map(move |&simp| tcx.incoherent_impls(simp))
1762 .copied()
1763 }
1764
1765 crate fn all_impls(tcx: TyCtxt<'_>) -> impl Iterator<Item = DefId> + '_ {
1766 Self::simplified_types()
1767 .values()
1768 .flatten()
1769 .flat_map(move |&simp| tcx.incoherent_impls(simp))
1770 .copied()
1771 }
1772
1773 crate fn as_sym(&self) -> Symbol {
1774 use PrimitiveType::*;
1775 match self {
1776 Isize => sym::isize,
1777 I8 => sym::i8,
1778 I16 => sym::i16,
1779 I32 => sym::i32,
1780 I64 => sym::i64,
1781 I128 => sym::i128,
1782 Usize => sym::usize,
1783 U8 => sym::u8,
1784 U16 => sym::u16,
1785 U32 => sym::u32,
1786 U64 => sym::u64,
1787 U128 => sym::u128,
1788 F32 => sym::f32,
1789 F64 => sym::f64,
1790 Str => sym::str,
1791 Bool => sym::bool,
1792 Char => sym::char,
1793 Array => sym::array,
1794 Slice => sym::slice,
1795 Tuple => sym::tuple,
1796 Unit => sym::unit,
1797 RawPointer => sym::pointer,
1798 Reference => sym::reference,
1799 Fn => kw::Fn,
1800 Never => sym::never,
1801 }
1802 }
1803
1804 /// Returns the DefId of the module with `doc(primitive)` for this primitive type.
1805 /// Panics if there is no such module.
1806 ///
1807 /// This gives precedence to primitives defined in the current crate, and deprioritizes primitives defined in `core`,
1808 /// but otherwise, if multiple crates define the same primitive, there is no guarantee of which will be picked.
1809 /// In particular, if a crate depends on both `std` and another crate that also defines `doc(primitive)`, then
1810 /// it's entirely random whether `std` or the other crate is picked. (no_std crates are usually fine unless multiple dependencies define a primitive.)
1811 crate fn primitive_locations(tcx: TyCtxt<'_>) -> &FxHashMap<PrimitiveType, DefId> {
1812 static PRIMITIVE_LOCATIONS: OnceCell<FxHashMap<PrimitiveType, DefId>> = OnceCell::new();
1813 PRIMITIVE_LOCATIONS.get_or_init(|| {
1814 let mut primitive_locations = FxHashMap::default();
1815 // NOTE: technically this misses crates that are only passed with `--extern` and not loaded when checking the crate.
1816 // This is a degenerate case that I don't plan to support.
1817 for &crate_num in tcx.crates(()) {
1818 let e = ExternalCrate { crate_num };
1819 let crate_name = e.name(tcx);
1820 debug!(?crate_num, ?crate_name);
1821 for &(def_id, prim) in &e.primitives(tcx) {
1822 // HACK: try to link to std instead where possible
1823 if crate_name == sym::core && primitive_locations.contains_key(&prim) {
1824 continue;
1825 }
1826 primitive_locations.insert(prim, def_id);
1827 }
1828 }
1829 let local_primitives = ExternalCrate { crate_num: LOCAL_CRATE }.primitives(tcx);
1830 for (def_id, prim) in local_primitives {
1831 primitive_locations.insert(prim, def_id);
1832 }
1833 primitive_locations
1834 })
1835 }
1836 }
1837
1838 impl From<ast::IntTy> for PrimitiveType {
1839 fn from(int_ty: ast::IntTy) -> PrimitiveType {
1840 match int_ty {
1841 ast::IntTy::Isize => PrimitiveType::Isize,
1842 ast::IntTy::I8 => PrimitiveType::I8,
1843 ast::IntTy::I16 => PrimitiveType::I16,
1844 ast::IntTy::I32 => PrimitiveType::I32,
1845 ast::IntTy::I64 => PrimitiveType::I64,
1846 ast::IntTy::I128 => PrimitiveType::I128,
1847 }
1848 }
1849 }
1850
1851 impl From<ast::UintTy> for PrimitiveType {
1852 fn from(uint_ty: ast::UintTy) -> PrimitiveType {
1853 match uint_ty {
1854 ast::UintTy::Usize => PrimitiveType::Usize,
1855 ast::UintTy::U8 => PrimitiveType::U8,
1856 ast::UintTy::U16 => PrimitiveType::U16,
1857 ast::UintTy::U32 => PrimitiveType::U32,
1858 ast::UintTy::U64 => PrimitiveType::U64,
1859 ast::UintTy::U128 => PrimitiveType::U128,
1860 }
1861 }
1862 }
1863
1864 impl From<ast::FloatTy> for PrimitiveType {
1865 fn from(float_ty: ast::FloatTy) -> PrimitiveType {
1866 match float_ty {
1867 ast::FloatTy::F32 => PrimitiveType::F32,
1868 ast::FloatTy::F64 => PrimitiveType::F64,
1869 }
1870 }
1871 }
1872
1873 impl From<ty::IntTy> for PrimitiveType {
1874 fn from(int_ty: ty::IntTy) -> PrimitiveType {
1875 match int_ty {
1876 ty::IntTy::Isize => PrimitiveType::Isize,
1877 ty::IntTy::I8 => PrimitiveType::I8,
1878 ty::IntTy::I16 => PrimitiveType::I16,
1879 ty::IntTy::I32 => PrimitiveType::I32,
1880 ty::IntTy::I64 => PrimitiveType::I64,
1881 ty::IntTy::I128 => PrimitiveType::I128,
1882 }
1883 }
1884 }
1885
1886 impl From<ty::UintTy> for PrimitiveType {
1887 fn from(uint_ty: ty::UintTy) -> PrimitiveType {
1888 match uint_ty {
1889 ty::UintTy::Usize => PrimitiveType::Usize,
1890 ty::UintTy::U8 => PrimitiveType::U8,
1891 ty::UintTy::U16 => PrimitiveType::U16,
1892 ty::UintTy::U32 => PrimitiveType::U32,
1893 ty::UintTy::U64 => PrimitiveType::U64,
1894 ty::UintTy::U128 => PrimitiveType::U128,
1895 }
1896 }
1897 }
1898
1899 impl From<ty::FloatTy> for PrimitiveType {
1900 fn from(float_ty: ty::FloatTy) -> PrimitiveType {
1901 match float_ty {
1902 ty::FloatTy::F32 => PrimitiveType::F32,
1903 ty::FloatTy::F64 => PrimitiveType::F64,
1904 }
1905 }
1906 }
1907
1908 impl From<hir::PrimTy> for PrimitiveType {
1909 fn from(prim_ty: hir::PrimTy) -> PrimitiveType {
1910 match prim_ty {
1911 hir::PrimTy::Int(int_ty) => int_ty.into(),
1912 hir::PrimTy::Uint(uint_ty) => uint_ty.into(),
1913 hir::PrimTy::Float(float_ty) => float_ty.into(),
1914 hir::PrimTy::Str => PrimitiveType::Str,
1915 hir::PrimTy::Bool => PrimitiveType::Bool,
1916 hir::PrimTy::Char => PrimitiveType::Char,
1917 }
1918 }
1919 }
1920
1921 #[derive(Copy, Clone, Debug)]
1922 crate enum Visibility {
1923 /// `pub`
1924 Public,
1925 /// Visibility inherited from parent.
1926 ///
1927 /// For example, this is the visibility of private items and of enum variants.
1928 Inherited,
1929 /// `pub(crate)`, `pub(super)`, or `pub(in path::to::somewhere)`
1930 Restricted(DefId),
1931 }
1932
1933 impl Visibility {
1934 crate fn is_public(&self) -> bool {
1935 matches!(self, Visibility::Public)
1936 }
1937 }
1938
1939 #[derive(Clone, Debug)]
1940 crate struct Struct {
1941 crate struct_type: CtorKind,
1942 crate generics: Generics,
1943 crate fields: Vec<Item>,
1944 crate fields_stripped: bool,
1945 }
1946
1947 #[derive(Clone, Debug)]
1948 crate struct Union {
1949 crate generics: Generics,
1950 crate fields: Vec<Item>,
1951 crate fields_stripped: bool,
1952 }
1953
1954 /// This is a more limited form of the standard Struct, different in that
1955 /// it lacks the things most items have (name, id, parameterization). Found
1956 /// only as a variant in an enum.
1957 #[derive(Clone, Debug)]
1958 crate struct VariantStruct {
1959 crate struct_type: CtorKind,
1960 crate fields: Vec<Item>,
1961 crate fields_stripped: bool,
1962 }
1963
1964 #[derive(Clone, Debug)]
1965 crate struct Enum {
1966 crate variants: IndexVec<VariantIdx, Item>,
1967 crate generics: Generics,
1968 crate variants_stripped: bool,
1969 }
1970
1971 #[derive(Clone, Debug)]
1972 crate enum Variant {
1973 CLike,
1974 Tuple(Vec<Item>),
1975 Struct(VariantStruct),
1976 }
1977
1978 /// Small wrapper around [`rustc_span::Span`] that adds helper methods
1979 /// and enforces calling [`rustc_span::Span::source_callsite()`].
1980 #[derive(Copy, Clone, Debug)]
1981 crate struct Span(rustc_span::Span);
1982
1983 impl Span {
1984 /// Wraps a [`rustc_span::Span`]. In case this span is the result of a macro expansion, the
1985 /// span will be updated to point to the macro invocation instead of the macro definition.
1986 ///
1987 /// (See rust-lang/rust#39726)
1988 crate fn new(sp: rustc_span::Span) -> Self {
1989 Self(sp.source_callsite())
1990 }
1991
1992 crate fn inner(&self) -> rustc_span::Span {
1993 self.0
1994 }
1995
1996 crate fn dummy() -> Self {
1997 Self(rustc_span::DUMMY_SP)
1998 }
1999
2000 crate fn is_dummy(&self) -> bool {
2001 self.0.is_dummy()
2002 }
2003
2004 crate fn filename(&self, sess: &Session) -> FileName {
2005 sess.source_map().span_to_filename(self.0)
2006 }
2007
2008 crate fn lo(&self, sess: &Session) -> Loc {
2009 sess.source_map().lookup_char_pos(self.0.lo())
2010 }
2011
2012 crate fn hi(&self, sess: &Session) -> Loc {
2013 sess.source_map().lookup_char_pos(self.0.hi())
2014 }
2015
2016 crate fn cnum(&self, sess: &Session) -> CrateNum {
2017 // FIXME: is there a time when the lo and hi crate would be different?
2018 self.lo(sess).file.cnum
2019 }
2020 }
2021
2022 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
2023 crate struct Path {
2024 crate res: Res,
2025 crate segments: Vec<PathSegment>,
2026 }
2027
2028 impl Path {
2029 crate fn def_id(&self) -> DefId {
2030 self.res.def_id()
2031 }
2032
2033 crate fn last(&self) -> Symbol {
2034 self.segments.last().expect("segments were empty").name
2035 }
2036
2037 crate fn whole_name(&self) -> String {
2038 self.segments
2039 .iter()
2040 .map(|s| if s.name == kw::PathRoot { String::new() } else { s.name.to_string() })
2041 .intersperse("::".into())
2042 .collect()
2043 }
2044
2045 /// Checks if this is a `T::Name` path for an associated type.
2046 crate fn is_assoc_ty(&self) -> bool {
2047 match self.res {
2048 Res::SelfTy { .. } if self.segments.len() != 1 => true,
2049 Res::Def(DefKind::TyParam, _) if self.segments.len() != 1 => true,
2050 Res::Def(DefKind::AssocTy, _) => true,
2051 _ => false,
2052 }
2053 }
2054
2055 crate fn generics(&self) -> Option<Vec<&Type>> {
2056 self.segments.last().and_then(|seg| {
2057 if let GenericArgs::AngleBracketed { ref args, .. } = seg.args {
2058 Some(
2059 args.iter()
2060 .filter_map(|arg| match arg {
2061 GenericArg::Type(ty) => Some(ty),
2062 _ => None,
2063 })
2064 .collect(),
2065 )
2066 } else {
2067 None
2068 }
2069 })
2070 }
2071
2072 crate fn bindings(&self) -> Option<&[TypeBinding]> {
2073 self.segments.last().and_then(|seg| {
2074 if let GenericArgs::AngleBracketed { ref bindings, .. } = seg.args {
2075 Some(&**bindings)
2076 } else {
2077 None
2078 }
2079 })
2080 }
2081 }
2082
2083 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
2084 crate enum GenericArg {
2085 Lifetime(Lifetime),
2086 Type(Type),
2087 Const(Box<Constant>),
2088 Infer,
2089 }
2090
2091 // `GenericArg` can occur many times in a single `Path`, so make sure it
2092 // doesn't increase in size unexpectedly.
2093 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
2094 rustc_data_structures::static_assert_size!(GenericArg, 88);
2095
2096 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
2097 crate enum GenericArgs {
2098 AngleBracketed { args: Vec<GenericArg>, bindings: ThinVec<TypeBinding> },
2099 Parenthesized { inputs: Vec<Type>, output: Option<Box<Type>> },
2100 }
2101
2102 // `GenericArgs` is in every `PathSegment`, so its size can significantly
2103 // affect rustdoc's memory usage.
2104 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
2105 rustc_data_structures::static_assert_size!(GenericArgs, 40);
2106
2107 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
2108 crate struct PathSegment {
2109 crate name: Symbol,
2110 crate args: GenericArgs,
2111 }
2112
2113 // `PathSegment` usually occurs multiple times in every `Path`, so its size can
2114 // significantly affect rustdoc's memory usage.
2115 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
2116 rustc_data_structures::static_assert_size!(PathSegment, 48);
2117
2118 #[derive(Clone, Debug)]
2119 crate struct Typedef {
2120 crate type_: Type,
2121 crate generics: Generics,
2122 /// `type_` can come from either the HIR or from metadata. If it comes from HIR, it may be a type
2123 /// alias instead of the final type. This will always have the final type, regardless of whether
2124 /// `type_` came from HIR or from metadata.
2125 ///
2126 /// If `item_type.is_none()`, `type_` is guaranteed to come from metadata (and therefore hold the
2127 /// final type).
2128 crate item_type: Option<Type>,
2129 }
2130
2131 #[derive(Clone, Debug)]
2132 crate struct OpaqueTy {
2133 crate bounds: Vec<GenericBound>,
2134 crate generics: Generics,
2135 }
2136
2137 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
2138 crate struct BareFunctionDecl {
2139 crate unsafety: hir::Unsafety,
2140 crate generic_params: Vec<GenericParamDef>,
2141 crate decl: FnDecl,
2142 crate abi: Abi,
2143 }
2144
2145 #[derive(Clone, Debug)]
2146 crate struct Static {
2147 crate type_: Type,
2148 crate mutability: Mutability,
2149 crate expr: Option<BodyId>,
2150 }
2151
2152 #[derive(Clone, PartialEq, Eq, Hash, Debug)]
2153 crate struct Constant {
2154 crate type_: Type,
2155 crate kind: ConstantKind,
2156 }
2157
2158 #[derive(Clone, PartialEq, Eq, Hash, Debug)]
2159 crate enum Term {
2160 Type(Type),
2161 Constant(Constant),
2162 }
2163
2164 impl Term {
2165 crate fn ty(&self) -> Option<&Type> {
2166 if let Term::Type(ty) = self { Some(ty) } else { None }
2167 }
2168 }
2169
2170 impl From<Type> for Term {
2171 fn from(ty: Type) -> Self {
2172 Term::Type(ty)
2173 }
2174 }
2175
2176 #[derive(Clone, PartialEq, Eq, Hash, Debug)]
2177 crate enum ConstantKind {
2178 /// This is the wrapper around `ty::Const` for a non-local constant. Because it doesn't have a
2179 /// `BodyId`, we need to handle it on its own.
2180 ///
2181 /// Note that `ty::Const` includes generic parameters, and may not always be uniquely identified
2182 /// by a DefId. So this field must be different from `Extern`.
2183 TyConst { expr: String },
2184 /// A constant (expression) that's not an item or associated item. These are usually found
2185 /// nested inside types (e.g., array lengths) or expressions (e.g., repeat counts), and also
2186 /// used to define explicit discriminant values for enum variants.
2187 Anonymous { body: BodyId },
2188 /// A constant from a different crate.
2189 Extern { def_id: DefId },
2190 /// `const FOO: u32 = ...;`
2191 Local { def_id: DefId, body: BodyId },
2192 }
2193
2194 impl Constant {
2195 crate fn expr(&self, tcx: TyCtxt<'_>) -> String {
2196 self.kind.expr(tcx)
2197 }
2198
2199 crate fn value(&self, tcx: TyCtxt<'_>) -> Option<String> {
2200 self.kind.value(tcx)
2201 }
2202
2203 crate fn is_literal(&self, tcx: TyCtxt<'_>) -> bool {
2204 self.kind.is_literal(tcx)
2205 }
2206 }
2207
2208 impl ConstantKind {
2209 crate fn expr(&self, tcx: TyCtxt<'_>) -> String {
2210 match *self {
2211 ConstantKind::TyConst { ref expr } => expr.clone(),
2212 ConstantKind::Extern { def_id } => print_inlined_const(tcx, def_id),
2213 ConstantKind::Local { body, .. } | ConstantKind::Anonymous { body } => {
2214 print_const_expr(tcx, body)
2215 }
2216 }
2217 }
2218
2219 crate fn value(&self, tcx: TyCtxt<'_>) -> Option<String> {
2220 match *self {
2221 ConstantKind::TyConst { .. } | ConstantKind::Anonymous { .. } => None,
2222 ConstantKind::Extern { def_id } | ConstantKind::Local { def_id, .. } => {
2223 print_evaluated_const(tcx, def_id)
2224 }
2225 }
2226 }
2227
2228 crate fn is_literal(&self, tcx: TyCtxt<'_>) -> bool {
2229 match *self {
2230 ConstantKind::TyConst { .. } => false,
2231 ConstantKind::Extern { def_id } => def_id.as_local().map_or(false, |def_id| {
2232 is_literal_expr(tcx, tcx.hir().local_def_id_to_hir_id(def_id))
2233 }),
2234 ConstantKind::Local { body, .. } | ConstantKind::Anonymous { body } => {
2235 is_literal_expr(tcx, body.hir_id)
2236 }
2237 }
2238 }
2239 }
2240
2241 #[derive(Clone, Debug)]
2242 crate struct Impl {
2243 crate unsafety: hir::Unsafety,
2244 crate generics: Generics,
2245 crate trait_: Option<Path>,
2246 crate for_: Type,
2247 crate items: Vec<Item>,
2248 crate polarity: ty::ImplPolarity,
2249 crate kind: ImplKind,
2250 }
2251
2252 impl Impl {
2253 crate fn provided_trait_methods(&self, tcx: TyCtxt<'_>) -> FxHashSet<Symbol> {
2254 self.trait_
2255 .as_ref()
2256 .map(|t| t.def_id())
2257 .map(|did| tcx.provided_trait_methods(did).map(|meth| meth.name).collect())
2258 .unwrap_or_default()
2259 }
2260 }
2261
2262 #[derive(Clone, Debug)]
2263 crate enum ImplKind {
2264 Normal,
2265 Auto,
2266 Blanket(Box<Type>),
2267 }
2268
2269 impl ImplKind {
2270 crate fn is_auto(&self) -> bool {
2271 matches!(self, ImplKind::Auto)
2272 }
2273
2274 crate fn is_blanket(&self) -> bool {
2275 matches!(self, ImplKind::Blanket(_))
2276 }
2277
2278 crate fn as_blanket_ty(&self) -> Option<&Type> {
2279 match self {
2280 ImplKind::Blanket(ty) => Some(ty),
2281 _ => None,
2282 }
2283 }
2284 }
2285
2286 #[derive(Clone, Debug)]
2287 crate struct Import {
2288 crate kind: ImportKind,
2289 crate source: ImportSource,
2290 crate should_be_displayed: bool,
2291 }
2292
2293 impl Import {
2294 crate fn new_simple(name: Symbol, source: ImportSource, should_be_displayed: bool) -> Self {
2295 Self { kind: ImportKind::Simple(name), source, should_be_displayed }
2296 }
2297
2298 crate fn new_glob(source: ImportSource, should_be_displayed: bool) -> Self {
2299 Self { kind: ImportKind::Glob, source, should_be_displayed }
2300 }
2301 }
2302
2303 #[derive(Clone, Debug)]
2304 crate enum ImportKind {
2305 // use source as str;
2306 Simple(Symbol),
2307 // use source::*;
2308 Glob,
2309 }
2310
2311 #[derive(Clone, Debug)]
2312 crate struct ImportSource {
2313 crate path: Path,
2314 crate did: Option<DefId>,
2315 }
2316
2317 #[derive(Clone, Debug)]
2318 crate struct Macro {
2319 crate source: String,
2320 }
2321
2322 #[derive(Clone, Debug)]
2323 crate struct ProcMacro {
2324 crate kind: MacroKind,
2325 crate helpers: Vec<Symbol>,
2326 }
2327
2328 /// An type binding on an associated type (e.g., `A = Bar` in `Foo<A = Bar>` or
2329 /// `A: Send + Sync` in `Foo<A: Send + Sync>`).
2330 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
2331 crate struct TypeBinding {
2332 crate assoc: PathSegment,
2333 crate kind: TypeBindingKind,
2334 }
2335
2336 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
2337 crate enum TypeBindingKind {
2338 Equality { term: Term },
2339 Constraint { bounds: Vec<GenericBound> },
2340 }
2341
2342 impl TypeBinding {
2343 crate fn term(&self) -> &Term {
2344 match self.kind {
2345 TypeBindingKind::Equality { ref term } => term,
2346 _ => panic!("expected equality type binding for parenthesized generic args"),
2347 }
2348 }
2349 }
2350
2351 /// The type, lifetime, or constant that a private type alias's parameter should be
2352 /// replaced with when expanding a use of that type alias.
2353 ///
2354 /// For example:
2355 ///
2356 /// ```
2357 /// type PrivAlias<T> = Vec<T>;
2358 ///
2359 /// pub fn public_fn() -> PrivAlias<i32> { vec![] }
2360 /// ```
2361 ///
2362 /// `public_fn`'s docs will show it as returning `Vec<i32>`, since `PrivAlias` is private.
2363 /// [`SubstParam`] is used to record that `T` should be mapped to `i32`.
2364 crate enum SubstParam {
2365 Type(Type),
2366 Lifetime(Lifetime),
2367 Constant(Constant),
2368 }
2369
2370 impl SubstParam {
2371 crate fn as_ty(&self) -> Option<&Type> {
2372 if let Self::Type(ty) = self { Some(ty) } else { None }
2373 }
2374
2375 crate fn as_lt(&self) -> Option<&Lifetime> {
2376 if let Self::Lifetime(lt) = self { Some(lt) } else { None }
2377 }
2378 }