1use std::fmt::Write;
2use std::hash::Hash;
3use std::path::PathBuf;
4use std::sync::{Arc, OnceLock as OnceCell};
5use std::{fmt, iter};
6
7use arrayvec::ArrayVec;
8use itertools::Either;
9use rustc_abi::{ExternAbi, VariantIdx};
10use rustc_ast as ast;
11use rustc_attr_ir::lang_items::LangItem;
12use rustc_attr_ir::{
13 AttributeKind, ConstStability, DeprecatedSince, Deprecation, DocAttribute, Stability,
14 StableSince, find_attr,
15};
16use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
17use rustc_data_structures::thin_vec::ThinVec;
18use rustc_hir as hir;
19use rustc_hir::def::{CtorKind, DefKind, MacroKinds, Res};
20use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId};
21use rustc_hir::{BodyId, Mutability};
22use rustc_index::IndexVec;
23use rustc_metadata::rendered_const;
24use rustc_middle::ty::fast_reject::SimplifiedType;
25use rustc_middle::ty::{self, Ty, TyCtxt, Visibility};
26use rustc_resolve::rustdoc::{
27 DocFragment, add_doc_fragment, attrs_to_doc_fragments, span_of_fragments,
28};
29use rustc_session::Session;
30use rustc_span::def_id::{CRATE_DEF_ID, ModId};
31use rustc_span::hygiene::MacroKind;
32use rustc_span::symbol::{Symbol, kw, sym};
33use rustc_span::{DUMMY_SP, FileName, Ident, Loc, RemapPathScopeComponents, span_bug};
34use tracing::{debug, trace};
35
36pub(crate) use self::ItemKind::*;
37pub(crate) use self::Type::{
38 Array, BareFunction, BorrowedRef, DynTrait, Generic, ImplTrait, Infer, Primitive, QPath,
39 RawPointer, SelfTy, Slice, Tuple, UnsafeBinder,
40};
41use crate::clean::cfg::Cfg;
42use crate::clean::clean_middle_path;
43use crate::clean::inline::{self, print_inlined_const};
44use crate::clean::utils::{is_literal_expr, print_evaluated_const};
45use crate::core::DocContext;
46use crate::formats::cache::Cache;
47use crate::formats::item_type::ItemType;
48use crate::html::format::HrefInfo;
49use crate::html::render::Context;
50use crate::passes::collect_intra_doc_links::UrlFragment;
51
52#[cfg(test)]
53mod tests;
54
55pub(crate) type ItemIdSet = FxHashSet<ItemId>;
56
57#[derive(Debug, Clone, PartialEq, Eq, Hash, Copy)]
58pub(crate) enum ItemId {
59 DefId(DefId),
61 Auto { trait_: DefId, for_: DefId },
63 Blanket { impl_id: DefId, for_: DefId },
65}
66
67#[derive(Debug, Copy, Clone, PartialEq, Eq)]
68pub(crate) enum Defaultness {
69 Implicit,
70 Default,
71 Final,
72}
73
74impl Defaultness {
75 pub(crate) fn from_trait_item(defaultness: hir::Defaultness) -> Self {
76 match defaultness {
77 hir::Defaultness::Default { .. } => Self::Implicit,
78 hir::Defaultness::Final => Self::Final,
79 }
80 }
81
82 pub(crate) fn from_impl_item(defaultness: hir::Defaultness) -> Self {
83 match defaultness {
84 hir::Defaultness::Default { .. } => Self::Default,
85 hir::Defaultness::Final => Self::Implicit,
86 }
87 }
88}
89
90impl ItemId {
91 #[inline]
92 pub(crate) fn is_local(self) -> bool {
93 match self {
94 ItemId::Auto { for_: id, .. }
95 | ItemId::Blanket { for_: id, .. }
96 | ItemId::DefId(id) => id.is_local(),
97 }
98 }
99
100 #[inline]
101 #[track_caller]
102 pub(crate) fn expect_def_id(self) -> DefId {
103 self.as_def_id()
104 .unwrap_or_else(|| panic!("ItemId::expect_def_id: `{self:?}` isn't a DefId"))
105 }
106
107 #[inline]
108 pub(crate) fn as_def_id(self) -> Option<DefId> {
109 match self {
110 ItemId::DefId(id) => Some(id),
111 _ => None,
112 }
113 }
114
115 #[inline]
116 pub(crate) fn as_local_def_id(self) -> Option<LocalDefId> {
117 self.as_def_id().and_then(|id| id.as_local())
118 }
119
120 #[inline]
121 pub(crate) fn krate(self) -> CrateNum {
122 match self {
123 ItemId::Auto { for_: id, .. }
124 | ItemId::Blanket { for_: id, .. }
125 | ItemId::DefId(id) => id.krate,
126 }
127 }
128}
129
130impl From<DefId> for ItemId {
131 fn from(id: DefId) -> Self {
132 Self::DefId(id)
133 }
134}
135
136#[derive(Debug)]
138pub(crate) struct Crate {
139 pub(crate) module: Item,
140 pub(crate) external_traits: Box<FxIndexMap<DefId, Trait>>,
142}
143
144impl Crate {
145 pub(crate) fn name(&self, tcx: TyCtxt<'_>) -> Symbol {
146 ExternalCrate::LOCAL.name(tcx)
147 }
148
149 pub(crate) fn src(&self, tcx: TyCtxt<'_>) -> FileName {
150 ExternalCrate::LOCAL.src(tcx)
151 }
152}
153
154#[derive(Copy, Clone, Debug)]
155pub(crate) struct ExternalCrate {
156 pub(crate) crate_num: CrateNum,
157}
158
159impl ExternalCrate {
160 const LOCAL: Self = Self { crate_num: LOCAL_CRATE };
161
162 #[inline]
163 pub(crate) fn def_id(&self) -> DefId {
164 self.crate_num.as_def_id()
165 }
166
167 pub(crate) fn src(&self, tcx: TyCtxt<'_>) -> FileName {
168 let krate_span = tcx.def_span(self.def_id());
169 tcx.sess.source_map().span_to_filename(krate_span)
170 }
171
172 pub(crate) fn name(&self, tcx: TyCtxt<'_>) -> Symbol {
173 tcx.crate_name(self.crate_num)
174 }
175
176 pub(crate) fn src_root(&self, tcx: TyCtxt<'_>) -> PathBuf {
177 match self.src(tcx) {
178 FileName::Real(ref p) => {
179 match p
180 .local_path()
181 .or(Some(p.path(RemapPathScopeComponents::DOCUMENTATION)))
182 .unwrap()
183 .parent()
184 {
185 Some(p) => p.to_path_buf(),
186 None => PathBuf::new(),
187 }
188 }
189 _ => PathBuf::new(),
190 }
191 }
192
193 pub(crate) fn location(
196 &self,
197 extern_url: Option<&str>,
198 extern_url_takes_precedence: bool,
199 dst: &std::path::Path,
200 tcx: TyCtxt<'_>,
201 ) -> ExternalLocation {
202 use ExternalLocation::*;
203
204 fn to_remote(url: impl ToString) -> ExternalLocation {
205 let mut url = url.to_string();
206 if !url.ends_with('/') {
207 url.push('/');
208 }
209 let is_absolute = url.starts_with('/')
210 || url.split_once(':').is_some_and(|(scheme, _)| {
211 scheme.bytes().next().is_some_and(|b| b.is_ascii_alphabetic())
212 && scheme
213 .bytes()
214 .all(|b| b.is_ascii_alphanumeric() || matches!(b, b'+' | b'-' | b'.'))
215 });
216 Remote { url, is_absolute }
217 }
218
219 let local_location = dst.join(self.name(tcx).as_str());
223 if local_location.is_dir() {
224 return Local;
225 }
226
227 if extern_url_takes_precedence && let Some(url) = extern_url {
228 return to_remote(url);
229 }
230
231 let did = self.crate_num.as_def_id();
234 find_attr!(tcx, did, Doc(d) =>d.html_root_url.map(|(url, _)| url))
235 .flatten()
236 .map(to_remote)
237 .or_else(|| extern_url.map(to_remote)) .unwrap_or(Unknown) }
240
241 fn fake_doc_items<T>(
242 &self,
243 tcx: TyCtxt<'_>,
244 f: impl Fn(DefId, TyCtxt<'_>) -> Option<(DefId, T)>,
245 ) -> impl Iterator<Item = (DefId, T)> {
246 tcx.fake_doc_items(self.crate_num).into_iter().filter_map(move |did| f(*did, tcx))
247 }
248
249 pub(crate) fn keywords(&self, tcx: TyCtxt<'_>) -> impl Iterator<Item = (DefId, Symbol)> {
250 self.retrieve_keywords_or_documented_attributes(tcx, |d| d.keyword.map(|(v, _)| v))
251 }
252 pub(crate) fn documented_attributes(
253 &self,
254 tcx: TyCtxt<'_>,
255 ) -> impl Iterator<Item = (DefId, Symbol)> {
256 self.retrieve_keywords_or_documented_attributes(tcx, |d| d.attribute.map(|(v, _)| v))
257 }
258
259 fn retrieve_keywords_or_documented_attributes<F: Fn(&DocAttribute) -> Option<Symbol>>(
260 &self,
261 tcx: TyCtxt<'_>,
262 callback: F,
263 ) -> impl Iterator<Item = (DefId, Symbol)> {
264 let as_target = move |did: DefId, tcx: TyCtxt<'_>| -> Option<(DefId, Symbol)> {
265 find_attr!(tcx, did, Doc(d) => callback(d)).flatten().map(|value| (did, value))
266 };
267 self.fake_doc_items(tcx, as_target)
268 }
269
270 pub(crate) fn primitives(
271 &self,
272 tcx: TyCtxt<'_>,
273 ) -> impl Iterator<Item = (DefId, PrimitiveType)> {
274 fn as_primitive(def_id: DefId, tcx: TyCtxt<'_>) -> Option<(DefId, PrimitiveType)> {
292 let (attr_span, prim_sym) = find_attr!(
293 tcx, def_id,
294 RustcDocPrimitive(span, prim) => (*span, *prim)
295 )?;
296 let Some(prim) = PrimitiveType::from_symbol(prim_sym) else {
297 span_bug!(attr_span, "primitive `{prim_sym}` is not a member of `PrimitiveType`");
298 };
299 Some((def_id, prim))
300 }
301
302 self.fake_doc_items(tcx, as_primitive)
303 }
304}
305
306#[derive(Debug)]
308pub(crate) enum ExternalLocation {
309 Remote { url: String, is_absolute: bool },
311 Local,
313 Unknown,
315}
316
317#[derive(Clone)]
321pub(crate) struct Item {
322 pub(crate) inner: Box<ItemInner>,
323}
324
325#[derive(Clone)]
331pub(crate) struct ItemInner {
332 pub(crate) name: Option<Symbol>,
335 pub(crate) kind: ItemKind,
338 pub(crate) attrs: Attributes,
339 pub(crate) stability: Option<Stability>,
341 pub(crate) item_id: ItemId,
342 pub(crate) inline_stmt_id: Option<LocalDefId>,
346 pub(crate) cfg: Option<Arc<Cfg>>,
347}
348
349impl std::ops::Deref for Item {
350 type Target = ItemInner;
351 fn deref(&self) -> &ItemInner {
352 &self.inner
353 }
354}
355
356impl fmt::Debug for Item {
359 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
360 let alternate = f.alternate();
361 let mut fmt = f.debug_struct("Item");
363 fmt.field("name", &self.name).field("item_id", &self.item_id);
364 if alternate {
366 fmt.field("attrs", &self.attrs).field("kind", &self.kind).field("cfg", &self.cfg);
367 } else {
368 fmt.field("kind", &self.type_());
369 fmt.field("docs", &self.doc_value());
370 }
371 fmt.finish()
372 }
373}
374
375pub(crate) fn rustc_span(def_id: DefId, tcx: TyCtxt<'_>) -> Span {
376 Span::new(def_id.as_local().map_or_else(
377 || tcx.def_span(def_id),
378 |local| tcx.hir_span_with_body(tcx.local_def_id_to_hir_id(local)),
379 ))
380}
381
382fn is_field_vis_inherited(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
383 let parent = tcx.parent(def_id);
384 match tcx.def_kind(parent) {
385 DefKind::Struct | DefKind::Union => false,
386 DefKind::Variant => true,
387 parent_kind => panic!("unexpected parent kind: {parent_kind:?}"),
388 }
389}
390
391impl Item {
392 pub(crate) fn cfg_parent_ids_for_detached_item(&self, tcx: TyCtxt<'_>) -> Vec<LocalDefId> {
393 let Some(def_id) = self.inline_stmt_id.or(self.item_id.as_local_def_id()) else {
394 return Vec::new();
395 };
396 let mut ids = Vec::new();
397 let mut next = def_id;
398 while let Some(parent) = tcx.opt_local_parent(next) {
399 if parent == CRATE_DEF_ID {
400 break;
401 }
402 ids.push(parent);
403 next = parent;
404 }
405 ids.reverse();
406 ids
407 }
408
409 pub(crate) fn stability(&self, tcx: TyCtxt<'_>) -> Option<Stability> {
413 let stability = self.inner.stability;
414 debug_assert!(
415 stability.is_some()
416 || self.def_id().is_none_or(|did| tcx.lookup_stability(did).is_none()),
417 "missing stability for cleaned item: {self:?}",
418 );
419 stability
420 }
421
422 pub(crate) fn const_stability(&self, tcx: TyCtxt<'_>) -> Option<ConstStability> {
423 self.def_id().and_then(|did| tcx.lookup_const_stability(did))
424 }
425
426 pub(crate) fn deprecation(&self, tcx: TyCtxt<'_>) -> Option<Deprecation> {
427 self.def_id().and_then(|did| tcx.lookup_deprecation(did)).or_else(|| {
428 let stab = self.stability(tcx)?;
432 if let rustc_attr_ir::StabilityLevel::Stable {
433 allowed_through_unstable_modules: Some((note, _)),
434 ..
435 } = stab.level
436 {
437 Some(Deprecation {
438 since: DeprecatedSince::Unspecified,
439 note: Some(Ident { name: note, span: DUMMY_SP }),
440 suggestion: None,
441 })
442 } else {
443 None
444 }
445 })
446 }
447
448 pub(crate) fn is_deprecated(&self, tcx: TyCtxt<'_>) -> bool {
449 self.deprecation(tcx).is_some_and(|deprecation| deprecation.is_in_effect())
450 }
451
452 pub(crate) fn is_unstable(&self) -> bool {
453 self.stability.is_some_and(|x| x.is_unstable())
454 }
455
456 pub(crate) fn is_exported_macro(&self) -> bool {
457 match self.kind {
458 ItemKind::MacroItem(..) => find_attr!(&self.attrs.other_attrs, MacroExport { .. }),
459 _ => false,
460 }
461 }
462
463 pub(crate) fn inner_docs(&self, tcx: TyCtxt<'_>) -> bool {
464 use rustc_ast::attr::AttributeExt;
465
466 self.item_id
467 .as_def_id()
468 .map(|did| {
469 #[allow(deprecated)]
470 tcx.get_all_attrs(did).iter().any(|attr| {
471 attr.doc_resolution_scope().is_some_and(|style| style == ast::AttrStyle::Inner)
472 })
473 })
474 .unwrap_or(false)
475 }
476
477 pub(crate) fn has_self_param(&self) -> bool {
479 if let ItemKind::MethodItem(Function { decl, .. }, _) = &self.inner.kind {
480 decl.receiver_type().is_some()
481 } else {
482 false
483 }
484 }
485
486 pub(crate) fn span(&self, tcx: TyCtxt<'_>) -> Option<Span> {
487 let kind = match &self.kind {
488 ItemKind::StrippedItem(k) => k,
489 _ => &self.kind,
490 };
491 match kind {
492 ItemKind::ModuleItem(Module { span, .. }) => Some(*span),
493 ItemKind::ImplItem(Impl { kind: ImplKind::Auto, .. }) => None,
494 ItemKind::ImplItem(Impl { kind: ImplKind::Blanket(_), .. }) => {
495 if let ItemId::Blanket { impl_id, .. } = self.item_id {
496 Some(rustc_span(impl_id, tcx))
497 } else {
498 panic!("blanket impl item has non-blanket ID")
499 }
500 }
501 _ => self.def_id().map(|did| rustc_span(did, tcx)),
502 }
503 }
504
505 pub(crate) fn attr_span(&self, tcx: TyCtxt<'_>) -> rustc_span::Span {
506 let deprecation_notes = find_attr!(&self.attrs.other_attrs, Deprecated { deprecation, .. } => deprecation.note.map(|note| note.span)).flatten();
507
508 span_of_fragments(&self.attrs.doc_strings)
509 .into_iter()
510 .chain(deprecation_notes)
511 .reduce(|a, b| a.to(b))
512 .unwrap_or_else(|| self.span(tcx).map_or(DUMMY_SP, |span| span.inner()))
513 }
514
515 pub(crate) fn doc_value(&self) -> String {
517 self.attrs.doc_value()
518 }
519
520 pub(crate) fn opt_doc_value(&self) -> Option<String> {
524 self.attrs.opt_doc_value()
525 }
526
527 pub(crate) fn from_def_id_and_parts(
528 def_id: DefId,
529 name: Option<Symbol>,
530 kind: ItemKind,
531 tcx: TyCtxt<'_>,
532 ) -> Item {
533 #[allow(deprecated)]
534 let hir_attrs = tcx.get_all_attrs(def_id);
535
536 Self::from_def_id_and_attrs_and_parts(
537 def_id,
538 name,
539 kind,
540 Attributes::from_hir(hir_attrs),
541 None,
542 )
543 }
544
545 pub(crate) fn from_def_id_and_attrs_and_parts(
546 def_id: DefId,
547 name: Option<Symbol>,
548 kind: ItemKind,
549 attrs: Attributes,
550 cfg: Option<Arc<Cfg>>,
551 ) -> Item {
552 trace!("name={name:?}, def_id={def_id:?} cfg={cfg:?}");
553
554 Item {
555 inner: Box::new(ItemInner {
556 item_id: def_id.into(),
557 kind,
558 attrs,
559 stability: None,
560 name,
561 cfg,
562 inline_stmt_id: None,
563 }),
564 }
565 }
566
567 pub(crate) fn item_or_reexport_id(&self) -> ItemId {
573 self.attrs
575 .doc_strings
576 .first()
577 .map(|x| x.item_id)
578 .flatten()
579 .map(ItemId::from)
580 .unwrap_or(self.item_id)
581 }
582
583 pub(crate) fn links(&self, cx: &Context<'_>) -> Vec<RenderedLink> {
584 use crate::html::format::{href_with_path_check, link_tooltip};
585
586 let Some(links) = cx.cache().intra_doc_links.get(&self.item_or_reexport_id()) else {
587 return vec![];
588 };
589 links
590 .iter()
591 .filter_map(|ItemLink { link: s, link_text, page_id: id, fragment }| {
592 debug!(?id);
593 if let Ok(HrefInfo { mut url, .. }) = href_with_path_check(*id, cx, link_text) {
594 debug!(?url);
595 match fragment {
596 Some(UrlFragment::Item(def_id)) => {
597 write!(url, "{}", crate::html::format::fragment(*def_id, cx.tcx()))
598 .unwrap();
599 }
600 Some(UrlFragment::UserWritten(raw)) => {
601 url.push('#');
602 url.push_str(raw);
603 }
604 None => {}
605 }
606 Some(RenderedLink {
607 original_text: s.clone(),
608 new_text: link_text.clone(),
609 tooltip: link_tooltip(*id, fragment, cx, Some(link_text)).to_string(),
610 href: url,
611 })
612 } else {
613 None
614 }
615 })
616 .collect()
617 }
618
619 pub(crate) fn link_names(&self, cache: &Cache) -> Vec<RenderedLink> {
625 let Some(links) = cache.intra_doc_links.get(&self.item_id) else {
626 return vec![];
627 };
628 links
629 .iter()
630 .map(|ItemLink { link: s, link_text, .. }| RenderedLink {
631 original_text: s.clone(),
632 new_text: link_text.clone(),
633 href: String::new(),
634 tooltip: String::new(),
635 })
636 .collect()
637 }
638
639 pub(crate) fn is_crate(&self) -> bool {
640 self.is_mod() && self.def_id().is_some_and(|did| did.is_crate_root())
641 }
642 pub(crate) fn is_mod(&self) -> bool {
643 self.type_() == ItemType::Module
644 }
645 pub(crate) fn is_struct(&self) -> bool {
646 self.type_() == ItemType::Struct
647 }
648 pub(crate) fn is_enum(&self) -> bool {
649 self.type_() == ItemType::Enum
650 }
651 pub(crate) fn is_variant(&self) -> bool {
652 self.type_() == ItemType::Variant
653 }
654 pub(crate) fn is_associated_type(&self) -> bool {
655 matches!(self.kind, AssocTypeItem(..) | StrippedItem(AssocTypeItem(..)))
656 }
657 pub(crate) fn is_required_associated_type(&self) -> bool {
658 matches!(self.kind, RequiredAssocTypeItem(..) | StrippedItem(RequiredAssocTypeItem(..)))
659 }
660 pub(crate) fn is_associated_const(&self) -> bool {
661 matches!(
662 self.kind,
663 ProvidedAssocConstItem(..)
664 | ImplAssocConstItem(..)
665 | StrippedItem(ProvidedAssocConstItem(..) | ImplAssocConstItem(..))
666 )
667 }
668 pub(crate) fn is_required_associated_const(&self) -> bool {
669 matches!(self.kind, RequiredAssocConstItem(..) | StrippedItem(RequiredAssocConstItem(..)))
670 }
671 pub(crate) fn is_method(&self) -> bool {
672 self.type_() == ItemType::Method
673 }
674 pub(crate) fn is_ty_method(&self) -> bool {
675 self.type_() == ItemType::TyMethod
676 }
677 pub(crate) fn is_primitive(&self) -> bool {
678 self.type_() == ItemType::Primitive
679 }
680 pub(crate) fn is_union(&self) -> bool {
681 self.type_() == ItemType::Union
682 }
683 pub(crate) fn is_import(&self) -> bool {
684 self.type_() == ItemType::Import
685 }
686 pub(crate) fn is_extern_crate(&self) -> bool {
687 self.type_() == ItemType::ExternCrate
688 }
689 pub(crate) fn is_keyword(&self) -> bool {
690 self.type_() == ItemType::Keyword
691 }
692 pub(crate) fn is_attribute(&self) -> bool {
693 self.type_() == ItemType::Attribute
694 }
695 pub(crate) fn is_fake_item(&self) -> bool {
704 matches!(self.type_(), ItemType::Primitive | ItemType::Keyword | ItemType::Attribute)
705 }
706 pub(crate) fn is_stripped(&self) -> bool {
707 match self.kind {
708 StrippedItem(..) => true,
709 ImportItem(ref i) => !i.should_be_displayed,
710 _ => false,
711 }
712 }
713 pub(crate) fn has_stripped_entries(&self) -> Option<bool> {
714 match self.kind {
715 StructItem(ref struct_) => Some(struct_.has_stripped_entries()),
716 UnionItem(ref union_) => Some(union_.has_stripped_entries()),
717 EnumItem(ref enum_) => Some(enum_.has_stripped_entries()),
718 VariantItem(ref v) => v.has_stripped_entries(),
719 TypeAliasItem(ref type_alias) => {
720 type_alias.inner_type.as_ref().and_then(|t| t.has_stripped_entries())
721 }
722 _ => None,
723 }
724 }
725
726 pub(crate) fn stability_class(&self, tcx: TyCtxt<'_>) -> Option<String> {
727 self.stability(tcx).as_ref().and_then(|s| {
728 let mut classes = Vec::with_capacity(2);
729
730 if s.is_unstable() {
731 classes.push("unstable");
732 }
733
734 if self.deprecation(tcx).is_some() {
736 classes.push("deprecated");
737 }
738
739 if !classes.is_empty() { Some(classes.join(" ")) } else { None }
740 })
741 }
742
743 pub(crate) fn stable_since(&self, tcx: TyCtxt<'_>) -> Option<StableSince> {
744 self.stability(tcx).and_then(|stability| stability.stable_since())
745 }
746
747 pub(crate) fn is_non_exhaustive(&self) -> bool {
748 find_attr!(&self.attrs.other_attrs, NonExhaustive(..))
749 }
750
751 pub(crate) fn type_(&self) -> ItemType {
755 ItemType::from(self)
756 }
757
758 pub(crate) fn types(&self) -> impl Iterator<Item = ItemType> {
761 if let ItemKind::MacroItem(_, macro_kinds) = self.kind {
762 Either::Right(macro_kinds.iter().map(|kind| match kind {
763 MacroKinds::ATTR => ItemType::DeclMacroAttribute,
764 MacroKinds::DERIVE => ItemType::DeclMacroDerive,
765 MacroKinds::BANG => ItemType::Macro,
766 _ => panic!("unsupported macro kind {kind:?}"),
767 }))
768 } else {
769 Either::Left(std::iter::once(self.type_()))
770 }
771 }
772
773 pub(crate) fn is_decl_macro(&self) -> bool {
775 matches!(self.kind, ItemKind::MacroItem(..))
776 }
777
778 pub(crate) fn defaultness(&self) -> Option<Defaultness> {
779 match self.kind {
780 ItemKind::MethodItem(_, defaultness) | ItemKind::RequiredMethodItem(_, defaultness) => {
781 Some(defaultness)
782 }
783 _ => None,
784 }
785 }
786
787 pub(crate) fn html_filename(&self) -> String {
789 format!("{type_}.{name}.html", type_ = self.type_(), name = self.name.unwrap())
790 }
791
792 pub(crate) fn fn_header(&self, tcx: TyCtxt<'_>) -> Option<hir::FnHeader> {
794 fn build_fn_header(
795 def_id: DefId,
796 tcx: TyCtxt<'_>,
797 asyncness: ty::Asyncness,
798 ) -> hir::FnHeader {
799 let sig = tcx.fn_sig(def_id).skip_binder();
800 let constness = if tcx.is_const_fn(def_id) {
801 if let Some(assoc) = tcx.opt_associated_item(def_id)
805 && let ty::AssocContainer::Trait | ty::AssocContainer::TraitImpl(_) =
806 assoc.container
807 {
808 hir::Constness::NotConst
809 } else {
810 hir::Constness::Const { always: false }
811 }
812 } else {
813 hir::Constness::NotConst
814 };
815 let asyncness = match asyncness {
816 ty::Asyncness::Yes => hir::IsAsync::Async(DUMMY_SP),
817 ty::Asyncness::No => hir::IsAsync::NotAsync,
818 };
819 hir::FnHeader {
820 safety: if tcx.codegen_fn_attrs(def_id).safe_target_features {
821 hir::HeaderSafety::SafeTargetFeatures
822 } else {
823 sig.safety().into()
824 },
825 abi: sig.abi(),
826 constness,
827 asyncness,
828 }
829 }
830 let header = match self.kind {
831 ItemKind::ForeignFunctionItem(_, safety) => {
832 let def_id = self.def_id().unwrap();
833 let abi = tcx.fn_sig(def_id).skip_binder().abi();
834 hir::FnHeader {
835 safety: if tcx.codegen_fn_attrs(def_id).safe_target_features {
836 hir::HeaderSafety::SafeTargetFeatures
837 } else {
838 safety.into()
839 },
840 abi,
841 constness: hir::Constness::NotConst,
843 asyncness: hir::IsAsync::NotAsync,
844 }
845 }
846 ItemKind::FunctionItem(_)
847 | ItemKind::MethodItem(..)
848 | ItemKind::RequiredMethodItem(..) => {
849 let def_id = self.def_id().unwrap();
850 build_fn_header(def_id, tcx, tcx.asyncness(def_id))
851 }
852 _ => return None,
853 };
854 Some(header)
855 }
856
857 pub(crate) fn visibility(&self, tcx: TyCtxt<'_>) -> Option<Visibility<ModId>> {
860 let def_id = match self.item_id {
861 ItemId::Auto { .. } | ItemId::Blanket { .. } => return None,
863 ItemId::DefId(def_id) => def_id,
864 };
865
866 match self.kind {
867 ItemKind::KeywordItem | ItemKind::PrimitiveItem(_) | ItemKind::AttributeItem => {
871 return Some(Visibility::Public);
872 }
873 StructFieldItem(..) if is_field_vis_inherited(tcx, def_id) => {
875 return None;
876 }
877 VariantItem(..) | ImplItem(..) => return None,
879 RequiredAssocConstItem(..)
881 | ProvidedAssocConstItem(..)
882 | ImplAssocConstItem(..)
883 | AssocTypeItem(..)
884 | RequiredAssocTypeItem(..)
885 | RequiredMethodItem(..)
886 | MethodItem(..) => {
887 match tcx.associated_item(def_id).container {
888 ty::AssocContainer::Trait | ty::AssocContainer::TraitImpl(_) => {
891 return None;
892 }
893 ty::AssocContainer::InherentImpl => {}
894 }
895 }
896 _ => {}
897 }
898 let def_id = match self.inline_stmt_id {
899 Some(inlined) => inlined.to_def_id(),
900 None => def_id,
901 };
902 Some(tcx.visibility(def_id))
903 }
904
905 pub fn is_doc_hidden(&self) -> bool {
906 self.attrs.is_doc_hidden()
907 }
908
909 pub fn def_id(&self) -> Option<DefId> {
910 self.item_id.as_def_id()
911 }
912}
913
914#[derive(Clone, Debug)]
915pub(crate) enum ItemKind {
916 ExternCrateItem {
917 src: Option<Symbol>,
919 },
920 ImportItem(Import),
921 StructItem(Struct),
922 UnionItem(Union),
923 EnumItem(Enum),
924 FunctionItem(Box<Function>),
925 ModuleItem(Module),
926 TypeAliasItem(Box<TypeAlias>),
927 StaticItem(Static),
928 TraitItem(Box<Trait>),
929 TraitAliasItem(TraitAlias),
930 ImplItem(Box<Impl>),
931 PlaceholderImplItem,
934 RequiredMethodItem(Box<Function>, Defaultness),
936 MethodItem(Box<Function>, Defaultness),
940 StructFieldItem(Type),
941 VariantItem(Variant),
942 ForeignFunctionItem(Box<Function>, hir::Safety),
944 ForeignStaticItem(Static, hir::Safety),
946 ForeignTypeItem,
948 MacroItem(Macro, MacroKinds),
955 ProcMacroItem(ProcMacro),
956 PrimitiveItem(PrimitiveType),
957 RequiredAssocConstItem(Generics, Box<Type>),
959 ConstantItem(Box<Constant>),
960 ProvidedAssocConstItem(Box<Constant>),
962 ImplAssocConstItem(Box<Constant>),
964 RequiredAssocTypeItem(Generics, Vec<GenericBound>),
968 AssocTypeItem(Box<TypeAlias>, Vec<GenericBound>),
970 StrippedItem(Box<ItemKind>),
972 KeywordItem,
975 AttributeItem,
978}
979
980impl ItemKind {
981 pub(crate) fn inner_items(&self) -> impl Iterator<Item = &Item> {
984 match self {
985 StructItem(s) => s.fields.iter(),
986 UnionItem(u) => u.fields.iter(),
987 VariantItem(v) => match &v.kind {
988 VariantKind::CLike => [].iter(),
989 VariantKind::Tuple(t) => t.iter(),
990 VariantKind::Struct(s) => s.fields.iter(),
991 },
992 EnumItem(e) => e.variants.iter(),
993 TraitItem(t) => t.items.iter(),
994 ImplItem(i) => i.items.iter(),
995 ModuleItem(m) => m.items.iter(),
996 ExternCrateItem { .. }
997 | ImportItem(_)
998 | FunctionItem(_)
999 | TypeAliasItem(_)
1000 | StaticItem(_)
1001 | ConstantItem(_)
1002 | TraitAliasItem(_)
1003 | RequiredMethodItem(..)
1004 | MethodItem(..)
1005 | StructFieldItem(_)
1006 | ForeignFunctionItem(_, _)
1007 | ForeignStaticItem(_, _)
1008 | ForeignTypeItem
1009 | MacroItem(..)
1010 | ProcMacroItem(_)
1011 | PrimitiveItem(_)
1012 | RequiredAssocConstItem(..)
1013 | ProvidedAssocConstItem(..)
1014 | ImplAssocConstItem(..)
1015 | RequiredAssocTypeItem(..)
1016 | AssocTypeItem(..)
1017 | StrippedItem(_)
1018 | KeywordItem
1019 | AttributeItem
1020 | PlaceholderImplItem => [].iter(),
1021 }
1022 }
1023}
1024
1025#[derive(Clone, Debug)]
1026pub(crate) struct Module {
1027 pub(crate) items: Vec<Item>,
1028 pub(crate) span: Span,
1029}
1030
1031#[derive(Clone, Debug, PartialEq, Eq, Hash)]
1035pub(crate) struct ItemLink {
1036 pub(crate) link: Box<str>,
1038 pub(crate) link_text: Box<str>,
1043 pub(crate) page_id: DefId,
1047 pub(crate) fragment: Option<UrlFragment>,
1049}
1050
1051pub struct RenderedLink {
1052 pub(crate) original_text: Box<str>,
1056 pub(crate) new_text: Box<str>,
1058 pub(crate) href: String,
1060 pub(crate) tooltip: String,
1062}
1063
1064#[derive(Clone, Debug, Default)]
1067pub(crate) struct Attributes {
1068 pub(crate) doc_strings: Vec<DocFragment>,
1069 pub(crate) other_attrs: ThinVec<rustc_attr_ir::Attribute>,
1070}
1071
1072impl Attributes {
1073 pub(crate) fn has_doc_flag<F: Fn(&DocAttribute) -> bool>(&self, callback: F) -> bool {
1074 find_attr!(&self.other_attrs, Doc(d) if callback(d))
1075 }
1076
1077 pub(crate) fn is_doc_hidden(&self) -> bool {
1078 find_attr!(&self.other_attrs, Doc(d) if d.hidden.is_some())
1079 }
1080
1081 pub(crate) fn from_hir(attrs: &[rustc_attr_ir::Attribute]) -> Attributes {
1082 Attributes::from_hir_iter(attrs.iter().map(|attr| (attr, None)), false)
1083 }
1084
1085 pub(crate) fn from_hir_with_additional(
1086 attrs: &[rustc_attr_ir::Attribute],
1087 (additional_attrs, def_id): (&[rustc_attr_ir::Attribute], DefId),
1088 ) -> Attributes {
1089 let attrs1 = additional_attrs.iter().map(|attr| (attr, Some(def_id)));
1091 let attrs2 = attrs.iter().map(|attr| (attr, None));
1092 Attributes::from_hir_iter(attrs1.chain(attrs2), false)
1093 }
1094
1095 pub(crate) fn from_hir_iter<'a>(
1096 attrs: impl Iterator<Item = (&'a rustc_attr_ir::Attribute, Option<DefId>)>,
1097 doc_only: bool,
1098 ) -> Attributes {
1099 let (doc_strings, other_attrs) = attrs_to_doc_fragments(attrs, doc_only);
1100 Attributes { doc_strings, other_attrs }
1101 }
1102
1103 pub(crate) fn doc_value(&self) -> String {
1105 self.opt_doc_value().unwrap_or_default()
1106 }
1107
1108 pub(crate) fn opt_doc_value(&self) -> Option<String> {
1112 (!self.doc_strings.is_empty()).then(|| {
1113 let mut res = String::new();
1114 for frag in &self.doc_strings {
1115 add_doc_fragment(&mut res, frag);
1116 }
1117 res.pop();
1118 res
1119 })
1120 }
1121
1122 pub(crate) fn get_doc_aliases(&self) -> Box<[Symbol]> {
1123 let mut aliases = FxIndexSet::default();
1124
1125 for attr in &self.other_attrs {
1126 if let rustc_attr_ir::Attribute::Parsed(AttributeKind::Doc(d)) = attr {
1127 for (alias, _) in &d.aliases {
1128 aliases.insert(*alias);
1129 }
1130 }
1131 }
1132 aliases.into_iter().collect::<Vec<_>>().into()
1133 }
1134
1135 pub(crate) fn merge_with(&mut self, other: Self) {
1136 let Self { doc_strings, other_attrs } = other;
1137 self.doc_strings.extend(doc_strings);
1138 self.other_attrs.extend(other_attrs);
1139 }
1140}
1141
1142#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1143pub(crate) enum GenericBound {
1144 TraitBound(PolyTrait, hir::TraitBoundModifiers),
1145 Outlives(Lifetime),
1146 Use(Vec<PreciseCapturingArg>),
1148}
1149
1150impl GenericBound {
1151 pub(crate) fn sized(cx: &mut DocContext<'_>) -> GenericBound {
1152 Self::sized_with(cx, hir::TraitBoundModifiers::NONE)
1153 }
1154
1155 pub(crate) fn maybe_sized(cx: &mut DocContext<'_>) -> GenericBound {
1156 Self::sized_with(
1157 cx,
1158 hir::TraitBoundModifiers {
1159 polarity: hir::BoundPolarity::Maybe(DUMMY_SP),
1160 constness: hir::BoundConstness::Never,
1161 },
1162 )
1163 }
1164
1165 fn sized_with(cx: &mut DocContext<'_>, modifiers: hir::TraitBoundModifiers) -> GenericBound {
1166 let did = cx.tcx.require_lang_item(LangItem::Sized, DUMMY_SP);
1167 let empty = ty::Binder::dummy(ty::GenericArgs::empty());
1168 let path = clean_middle_path(cx, did, false, ThinVec::new(), empty);
1169 inline::record_extern_fqn(cx, did, ItemType::Trait);
1170 GenericBound::TraitBound(PolyTrait { trait_: path, generic_params: Vec::new() }, modifiers)
1171 }
1172
1173 pub(crate) fn is_trait_bound(&self) -> bool {
1174 matches!(self, Self::TraitBound(..))
1175 }
1176
1177 pub(crate) fn is_sized_bound(&self, tcx: TyCtxt<'_>) -> bool {
1178 self.is_bounded_by_lang_item(tcx, LangItem::Sized)
1179 }
1180
1181 pub(crate) fn is_meta_sized_bound(&self, tcx: TyCtxt<'_>) -> bool {
1182 self.is_bounded_by_lang_item(tcx, LangItem::MetaSized)
1183 }
1184
1185 fn is_bounded_by_lang_item(&self, tcx: TyCtxt<'_>, lang_item: LangItem) -> bool {
1186 if let GenericBound::TraitBound(poly_trait_ref, rustc_hir::TraitBoundModifiers::NONE) = self
1187 && tcx.is_lang_item(poly_trait_ref.trait_.def_id(), lang_item)
1188 {
1189 return true;
1190 }
1191 false
1192 }
1193
1194 pub(crate) fn get_trait_path(&self) -> Option<Path> {
1195 if let GenericBound::TraitBound(poly_trait_ref, _) = self {
1196 Some(poly_trait_ref.trait_.clone())
1197 } else {
1198 None
1199 }
1200 }
1201}
1202
1203#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
1204pub(crate) struct Lifetime(pub Symbol);
1205
1206impl Lifetime {
1207 pub(crate) fn statik() -> Lifetime {
1208 Lifetime(kw::StaticLifetime)
1209 }
1210
1211 pub(crate) fn elided() -> Lifetime {
1212 Lifetime(kw::UnderscoreLifetime)
1213 }
1214}
1215
1216#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
1217pub(crate) enum PreciseCapturingArg {
1218 Lifetime(Lifetime),
1219 Param(Symbol),
1220}
1221
1222impl PreciseCapturingArg {
1223 pub(crate) fn name(self) -> Symbol {
1224 match self {
1225 PreciseCapturingArg::Lifetime(lt) => lt.0,
1226 PreciseCapturingArg::Param(param) => param,
1227 }
1228 }
1229}
1230
1231#[derive(Clone, PartialEq, Eq, Hash, Debug)]
1232pub(crate) enum WherePredicate {
1233 BoundPredicate { ty: Type, bounds: Vec<GenericBound>, bound_params: Vec<GenericParamDef> },
1234 RegionPredicate { lifetime: Lifetime, bounds: Vec<GenericBound> },
1235 ProjectionPredicate { lhs: QPathData, rhs: Term },
1236}
1237
1238impl WherePredicate {
1239 pub(crate) fn get_bounds(&self) -> Option<&[GenericBound]> {
1240 match self {
1241 WherePredicate::BoundPredicate { bounds, .. } => Some(bounds),
1242 WherePredicate::RegionPredicate { bounds, .. } => Some(bounds),
1243 _ => None,
1244 }
1245 }
1246}
1247
1248#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1249pub(crate) enum GenericParamDefKind {
1250 Lifetime { outlives: ThinVec<Lifetime> },
1251 Type { bounds: ThinVec<GenericBound>, default: Option<Box<Type>>, synthetic: bool },
1252 Const { ty: Box<Type>, default: Option<Box<String>> },
1254}
1255
1256impl GenericParamDefKind {
1257 pub(crate) fn is_type(&self) -> bool {
1258 matches!(self, GenericParamDefKind::Type { .. })
1259 }
1260}
1261
1262#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1263pub(crate) struct GenericParamDef {
1264 pub(crate) name: Symbol,
1265 pub(crate) def_id: DefId,
1266 pub(crate) kind: GenericParamDefKind,
1267}
1268
1269impl GenericParamDef {
1270 pub(crate) fn lifetime(def_id: DefId, name: Symbol) -> Self {
1271 Self { name, def_id, kind: GenericParamDefKind::Lifetime { outlives: ThinVec::new() } }
1272 }
1273
1274 pub(crate) fn is_synthetic_param(&self) -> bool {
1275 match self.kind {
1276 GenericParamDefKind::Lifetime { .. } | GenericParamDefKind::Const { .. } => false,
1277 GenericParamDefKind::Type { synthetic, .. } => synthetic,
1278 }
1279 }
1280
1281 pub(crate) fn is_type(&self) -> bool {
1282 self.kind.is_type()
1283 }
1284
1285 pub(crate) fn get_bounds(&self) -> Option<&[GenericBound]> {
1286 match self.kind {
1287 GenericParamDefKind::Type { ref bounds, .. } => Some(bounds),
1288 _ => None,
1289 }
1290 }
1291}
1292
1293#[derive(Clone, PartialEq, Eq, Hash, Debug, Default)]
1295pub(crate) struct Generics {
1296 pub(crate) params: ThinVec<GenericParamDef>,
1297 pub(crate) where_predicates: ThinVec<WherePredicate>,
1298}
1299
1300impl Generics {
1301 pub(crate) fn is_empty(&self) -> bool {
1302 self.params.is_empty() && self.where_predicates.is_empty()
1303 }
1304}
1305
1306#[derive(Clone, Debug)]
1307pub(crate) struct Function {
1308 pub(crate) decl: FnDecl,
1309 pub(crate) generics: Generics,
1310}
1311
1312#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1313pub(crate) struct FnDecl {
1314 pub(crate) inputs: Vec<Parameter>,
1315 pub(crate) output: Type,
1316 pub(crate) c_variadic: bool,
1317}
1318
1319impl FnDecl {
1320 pub(crate) fn receiver_type(&self) -> Option<&Type> {
1321 self.inputs.first().and_then(|v| v.to_receiver())
1322 }
1323}
1324
1325#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1327pub(crate) struct Parameter {
1328 pub(crate) name: Option<Symbol>,
1329 pub(crate) type_: Type,
1330 pub(crate) is_const: bool,
1333 pub(crate) is_splat: bool,
1336}
1337
1338impl Parameter {
1339 pub(crate) fn to_receiver(&self) -> Option<&Type> {
1340 if self.name == Some(kw::SelfLower) { Some(&self.type_) } else { None }
1341 }
1342}
1343
1344#[derive(Clone, Debug)]
1345pub(crate) struct Trait {
1346 pub(crate) def_id: DefId,
1347 pub(crate) items: Vec<Item>,
1348 pub(crate) generics: Generics,
1349 pub(crate) bounds: Vec<GenericBound>,
1350}
1351
1352impl Trait {
1353 pub(crate) fn is_auto(&self, tcx: TyCtxt<'_>) -> bool {
1354 tcx.trait_is_auto(self.def_id)
1355 }
1356 pub(crate) fn is_notable_trait(&self, tcx: TyCtxt<'_>) -> bool {
1357 tcx.is_doc_notable_trait(self.def_id)
1358 }
1359 pub(crate) fn safety(&self, tcx: TyCtxt<'_>) -> hir::Safety {
1360 tcx.trait_def(self.def_id).safety
1361 }
1362 pub(crate) fn is_dyn_compatible(&self, tcx: TyCtxt<'_>) -> bool {
1363 tcx.is_dyn_compatible(self.def_id)
1364 }
1365 pub(crate) fn is_deprecated(&self, tcx: TyCtxt<'_>) -> bool {
1366 tcx.lookup_deprecation(self.def_id).is_some_and(|deprecation| deprecation.is_in_effect())
1367 }
1368}
1369
1370#[derive(Clone, Debug)]
1371pub(crate) struct TraitAlias {
1372 pub(crate) generics: Generics,
1373 pub(crate) bounds: Vec<GenericBound>,
1374}
1375
1376#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1378pub(crate) struct PolyTrait {
1379 pub(crate) trait_: Path,
1380 pub(crate) generic_params: Vec<GenericParamDef>,
1381}
1382
1383#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1385pub(crate) enum Type {
1386 Path {
1391 path: Path,
1392 },
1393 DynTrait(Vec<PolyTrait>, Option<Lifetime>),
1395 Generic(Symbol),
1397 SelfTy,
1399 Primitive(PrimitiveType),
1401 BareFunction(Box<BareFunctionDecl>),
1403 Tuple(Vec<Type>),
1405 Slice(Box<Type>),
1407 Array(Box<Type>, Box<str>),
1411 Pat(Box<Type>, Box<str>),
1412 FieldOf(Box<Type>, Box<str>),
1413 RawPointer(Mutability, Box<Type>),
1415 BorrowedRef {
1417 lifetime: Option<Lifetime>,
1418 mutability: Mutability,
1419 type_: Box<Type>,
1420 },
1421
1422 QPath(Box<QPathData>),
1424
1425 Infer,
1427
1428 ImplTrait(Vec<GenericBound>),
1430
1431 UnsafeBinder(Box<UnsafeBinderTy>),
1432}
1433
1434impl Type {
1435 pub(crate) fn without_borrowed_ref(&self) -> &Type {
1437 let mut result = self;
1438 while let Type::BorrowedRef { type_, .. } = result {
1439 result = type_;
1440 }
1441 result
1442 }
1443
1444 pub(crate) fn is_borrowed_ref(&self) -> bool {
1445 matches!(self, Type::BorrowedRef { .. })
1446 }
1447
1448 fn is_type_alias(&self) -> bool {
1449 matches!(self, Type::Path { path: Path { res: Res::Def(DefKind::TyAlias, _), .. } })
1450 }
1451
1452 pub(crate) fn is_doc_subtype_of(&self, other: &Self, cache: &Cache) -> bool {
1473 let (self_cleared, other_cleared) = if !self.is_borrowed_ref() || !other.is_borrowed_ref() {
1476 (self.without_borrowed_ref(), other.without_borrowed_ref())
1477 } else {
1478 (self, other)
1479 };
1480
1481 if self_cleared.is_type_alias() || other_cleared.is_type_alias() {
1487 return true;
1488 }
1489
1490 match (self_cleared, other_cleared) {
1491 (Type::Tuple(a), Type::Tuple(b)) => {
1493 a.iter().eq_by(b, |a, b| a.is_doc_subtype_of(b, cache))
1494 }
1495 (Type::Slice(a), Type::Slice(b)) => a.is_doc_subtype_of(b, cache),
1496 (Type::Array(a, al), Type::Array(b, bl)) => al == bl && a.is_doc_subtype_of(b, cache),
1497 (Type::RawPointer(mutability, type_), Type::RawPointer(b_mutability, b_type_)) => {
1498 mutability == b_mutability && type_.is_doc_subtype_of(b_type_, cache)
1499 }
1500 (
1501 Type::BorrowedRef { mutability, type_, .. },
1502 Type::BorrowedRef { mutability: b_mutability, type_: b_type_, .. },
1503 ) => mutability == b_mutability && type_.is_doc_subtype_of(b_type_, cache),
1504 (Type::Infer, _) | (_, Type::Infer) => true,
1506 (_, Type::Generic(_)) => true,
1509 (Type::Generic(_), _) => false,
1510 (Type::SelfTy, Type::SelfTy) => true,
1512 (Type::Path { path: a }, Type::Path { path: b }) => {
1514 a.def_id() == b.def_id()
1515 && a.generics()
1516 .zip(b.generics())
1517 .map(|(ag, bg)| ag.zip(bg).all(|(at, bt)| at.is_doc_subtype_of(bt, cache)))
1518 .unwrap_or(true)
1519 }
1520 (a, b) => a
1522 .def_id(cache)
1523 .and_then(|a| Some((a, b.def_id(cache)?)))
1524 .map(|(a, b)| a == b)
1525 .unwrap_or(false),
1526 }
1527 }
1528
1529 pub(crate) fn primitive_type(&self) -> Option<PrimitiveType> {
1530 match *self {
1531 Primitive(p) | BorrowedRef { type_: Primitive(p), .. } => Some(p),
1532 Slice(..) | BorrowedRef { type_: Slice(..), .. } => Some(PrimitiveType::Slice),
1533 Array(..) | BorrowedRef { type_: Array(..), .. } => Some(PrimitiveType::Array),
1534 Tuple(ref tys) => {
1535 if tys.is_empty() {
1536 Some(PrimitiveType::Unit)
1537 } else {
1538 Some(PrimitiveType::Tuple)
1539 }
1540 }
1541 RawPointer(..) => Some(PrimitiveType::RawPointer),
1542 BareFunction(..) => Some(PrimitiveType::Fn),
1543 _ => None,
1544 }
1545 }
1546
1547 pub(crate) fn sugared_async_return_type(self) -> Type {
1557 if let Type::ImplTrait(mut v) = self
1558 && let Some(GenericBound::TraitBound(PolyTrait { mut trait_, .. }, _)) = v.pop()
1559 && let Some(segment) = trait_.segments.pop()
1560 && let GenericArgs::AngleBracketed { mut constraints, .. } = segment.args
1561 && let Some(constraint) = constraints.pop()
1562 && let AssocItemConstraintKind::Equality { term } = constraint.kind
1563 && let Term::Type(ty) = term
1564 {
1565 ty
1566 } else {
1567 panic!("unexpected async fn return type")
1568 }
1569 }
1570
1571 pub(crate) fn is_assoc_ty(&self) -> bool {
1573 match self {
1574 Type::Path { path, .. } => path.is_assoc_ty(),
1575 _ => false,
1576 }
1577 }
1578
1579 pub(crate) fn is_self_type(&self) -> bool {
1580 matches!(*self, Type::SelfTy)
1581 }
1582
1583 pub(crate) fn generic_args(&self) -> Option<&GenericArgs> {
1584 match self {
1585 Type::Path { path, .. } => path.generic_args(),
1586 _ => None,
1587 }
1588 }
1589
1590 pub(crate) fn generics(&self) -> Option<impl Iterator<Item = &Type>> {
1591 match self {
1592 Type::Path { path, .. } => path.generics(),
1593 _ => None,
1594 }
1595 }
1596
1597 pub(crate) fn is_full_generic(&self) -> bool {
1598 matches!(self, Type::Generic(_))
1599 }
1600
1601 pub(crate) fn is_unit(&self) -> bool {
1602 matches!(self, Type::Tuple(v) if v.is_empty())
1603 }
1604
1605 pub(crate) fn def_id(&self, cache: &Cache) -> Option<DefId> {
1609 let t: PrimitiveType = match self {
1610 Type::Path { path } => return Some(path.def_id()),
1611 DynTrait(bounds, _) => return bounds.first().map(|b| b.trait_.def_id()),
1612 Primitive(p) => return cache.primitive_locations.get(p).cloned(),
1613 BorrowedRef { type_: Generic(..), .. } => PrimitiveType::Reference,
1614 BorrowedRef { type_, .. } => return type_.def_id(cache),
1615 Tuple(tys) => {
1616 if tys.is_empty() {
1617 PrimitiveType::Unit
1618 } else {
1619 PrimitiveType::Tuple
1620 }
1621 }
1622 BareFunction(..) => PrimitiveType::Fn,
1623 Slice(..) => PrimitiveType::Slice,
1624 Array(..) => PrimitiveType::Array,
1625 Type::Pat(..) => PrimitiveType::Pat,
1626 Type::FieldOf(..) => PrimitiveType::FieldOf,
1627 RawPointer(..) => PrimitiveType::RawPointer,
1628 QPath(QPathData { self_type, .. }) => return self_type.def_id(cache),
1629 Generic(_) | SelfTy | Infer | ImplTrait(_) | UnsafeBinder(_) => return None,
1630 };
1631 Primitive(t).def_id(cache)
1632 }
1633}
1634
1635#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1636pub(crate) struct QPathData {
1637 pub assoc: PathSegment,
1638 pub self_type: Type,
1639 pub should_fully_qualify: bool,
1641 pub trait_: Option<Path>,
1642}
1643
1644#[derive(Clone, PartialEq, Eq, Hash, Copy, Debug)]
1651pub(crate) enum PrimitiveType {
1652 Isize,
1653 I8,
1654 I16,
1655 I32,
1656 I64,
1657 I128,
1658 Usize,
1659 U8,
1660 U16,
1661 U32,
1662 U64,
1663 U128,
1664 F16,
1665 F32,
1666 F64,
1667 F128,
1668 Char,
1669 Bool,
1670 Str,
1671 Slice,
1672 Array,
1673 Pat,
1674 FieldOf,
1675 Tuple,
1676 Unit,
1677 RawPointer,
1678 Reference,
1679 Fn,
1680 Never,
1681}
1682
1683type SimplifiedTypes = FxIndexMap<PrimitiveType, ArrayVec<SimplifiedType, 3>>;
1684impl PrimitiveType {
1685 pub(crate) fn from_hir(prim: hir::PrimTy) -> PrimitiveType {
1686 use ast::{FloatTy, IntTy, UintTy};
1687 match prim {
1688 hir::PrimTy::Int(IntTy::Isize) => PrimitiveType::Isize,
1689 hir::PrimTy::Int(IntTy::I8) => PrimitiveType::I8,
1690 hir::PrimTy::Int(IntTy::I16) => PrimitiveType::I16,
1691 hir::PrimTy::Int(IntTy::I32) => PrimitiveType::I32,
1692 hir::PrimTy::Int(IntTy::I64) => PrimitiveType::I64,
1693 hir::PrimTy::Int(IntTy::I128) => PrimitiveType::I128,
1694 hir::PrimTy::Uint(UintTy::Usize) => PrimitiveType::Usize,
1695 hir::PrimTy::Uint(UintTy::U8) => PrimitiveType::U8,
1696 hir::PrimTy::Uint(UintTy::U16) => PrimitiveType::U16,
1697 hir::PrimTy::Uint(UintTy::U32) => PrimitiveType::U32,
1698 hir::PrimTy::Uint(UintTy::U64) => PrimitiveType::U64,
1699 hir::PrimTy::Uint(UintTy::U128) => PrimitiveType::U128,
1700 hir::PrimTy::Float(FloatTy::F16) => PrimitiveType::F16,
1701 hir::PrimTy::Float(FloatTy::F32) => PrimitiveType::F32,
1702 hir::PrimTy::Float(FloatTy::F64) => PrimitiveType::F64,
1703 hir::PrimTy::Float(FloatTy::F128) => PrimitiveType::F128,
1704 hir::PrimTy::Str => PrimitiveType::Str,
1705 hir::PrimTy::Bool => PrimitiveType::Bool,
1706 hir::PrimTy::Char => PrimitiveType::Char,
1707 }
1708 }
1709
1710 pub(crate) fn from_symbol(s: Symbol) -> Option<PrimitiveType> {
1711 match s {
1712 sym::isize => Some(PrimitiveType::Isize),
1713 sym::i8 => Some(PrimitiveType::I8),
1714 sym::i16 => Some(PrimitiveType::I16),
1715 sym::i32 => Some(PrimitiveType::I32),
1716 sym::i64 => Some(PrimitiveType::I64),
1717 sym::i128 => Some(PrimitiveType::I128),
1718 sym::usize => Some(PrimitiveType::Usize),
1719 sym::u8 => Some(PrimitiveType::U8),
1720 sym::u16 => Some(PrimitiveType::U16),
1721 sym::u32 => Some(PrimitiveType::U32),
1722 sym::u64 => Some(PrimitiveType::U64),
1723 sym::u128 => Some(PrimitiveType::U128),
1724 sym::bool => Some(PrimitiveType::Bool),
1725 sym::char => Some(PrimitiveType::Char),
1726 sym::str => Some(PrimitiveType::Str),
1727 sym::f16 => Some(PrimitiveType::F16),
1728 sym::f32 => Some(PrimitiveType::F32),
1729 sym::f64 => Some(PrimitiveType::F64),
1730 sym::f128 => Some(PrimitiveType::F128),
1731 sym::array => Some(PrimitiveType::Array),
1732 sym::slice => Some(PrimitiveType::Slice),
1733 sym::tuple => Some(PrimitiveType::Tuple),
1734 sym::unit => Some(PrimitiveType::Unit),
1735 sym::pointer => Some(PrimitiveType::RawPointer),
1736 sym::reference => Some(PrimitiveType::Reference),
1737 kw::Fn => Some(PrimitiveType::Fn),
1738 sym::never => Some(PrimitiveType::Never),
1739 _ => None,
1740 }
1741 }
1742
1743 pub(crate) fn from_ty(ty: Ty<'_>) -> Option<Self> {
1744 match ty.kind() {
1745 ty::Array(..) => Some(Self::Array),
1746 ty::Bool => Some(Self::Bool),
1747 ty::Char => Some(Self::Char),
1748 ty::FnDef(..) | ty::FnPtr(..) => Some(Self::Fn),
1749 ty::Int(int) => Some(Self::from(*int)),
1750 ty::Uint(uint) => Some(Self::from(*uint)),
1751 ty::Float(float) => Some(Self::from(*float)),
1752 ty::Never => Some(Self::Never),
1753 ty::Pat(..) => Some(Self::Pat),
1754 ty::RawPtr(..) => Some(Self::RawPointer),
1755 ty::Ref(..) => Some(Self::Reference),
1756 ty::Slice(..) => Some(Self::Slice),
1757 ty::Str => Some(Self::Str),
1758 ty::Tuple(elems) if elems.is_empty() => Some(Self::Unit),
1759 ty::Tuple(_) => Some(Self::Tuple),
1760 ty::Adt(..)
1761 | ty::Alias(_, ..)
1762 | ty::Bound(..)
1763 | ty::Closure(..)
1764 | ty::Coroutine(..)
1765 | ty::CoroutineClosure(..)
1766 | ty::CoroutineWitness(..)
1767 | ty::Dynamic(..)
1768 | ty::Error(..)
1769 | ty::Foreign(..)
1770 | ty::Infer(..)
1771 | ty::Param(..)
1772 | ty::Placeholder(..)
1773 | ty::UnsafeBinder(..) => None,
1774 }
1775 }
1776
1777 pub(crate) fn simplified_types() -> &'static SimplifiedTypes {
1778 use PrimitiveType::*;
1779 use ty::{FloatTy, IntTy, UintTy};
1780 static CELL: OnceCell<SimplifiedTypes> = OnceCell::new();
1781
1782 let single = |x| iter::once(x).collect();
1783 CELL.get_or_init(move || {
1784 map! {
1785 Isize => single(SimplifiedType::Int(IntTy::Isize)),
1786 I8 => single(SimplifiedType::Int(IntTy::I8)),
1787 I16 => single(SimplifiedType::Int(IntTy::I16)),
1788 I32 => single(SimplifiedType::Int(IntTy::I32)),
1789 I64 => single(SimplifiedType::Int(IntTy::I64)),
1790 I128 => single(SimplifiedType::Int(IntTy::I128)),
1791 Usize => single(SimplifiedType::Uint(UintTy::Usize)),
1792 U8 => single(SimplifiedType::Uint(UintTy::U8)),
1793 U16 => single(SimplifiedType::Uint(UintTy::U16)),
1794 U32 => single(SimplifiedType::Uint(UintTy::U32)),
1795 U64 => single(SimplifiedType::Uint(UintTy::U64)),
1796 U128 => single(SimplifiedType::Uint(UintTy::U128)),
1797 F16 => single(SimplifiedType::Float(FloatTy::F16)),
1798 F32 => single(SimplifiedType::Float(FloatTy::F32)),
1799 F64 => single(SimplifiedType::Float(FloatTy::F64)),
1800 F128 => single(SimplifiedType::Float(FloatTy::F128)),
1801 Str => single(SimplifiedType::Str),
1802 Bool => single(SimplifiedType::Bool),
1803 Char => single(SimplifiedType::Char),
1804 Array => single(SimplifiedType::Array),
1805 Slice => single(SimplifiedType::Slice),
1806 Tuple => [SimplifiedType::Tuple(1), SimplifiedType::Tuple(2), SimplifiedType::Tuple(3)].into(),
1812 Unit => single(SimplifiedType::Tuple(0)),
1813 RawPointer => [SimplifiedType::Ptr(Mutability::Not), SimplifiedType::Ptr(Mutability::Mut)].into_iter().collect(),
1814 Reference => [SimplifiedType::Ref(Mutability::Not), SimplifiedType::Ref(Mutability::Mut)].into_iter().collect(),
1815 Fn => single(SimplifiedType::Function(1)),
1818 Never => single(SimplifiedType::Never),
1819 }
1820 })
1821 }
1822
1823 pub(crate) fn impls<'tcx>(&self, tcx: TyCtxt<'tcx>) -> impl Iterator<Item = DefId> + 'tcx {
1824 Self::simplified_types()
1825 .get(self)
1826 .into_iter()
1827 .flatten()
1828 .flat_map(move |&simp| tcx.incoherent_impls(simp).iter())
1829 .copied()
1830 }
1831
1832 pub(crate) fn as_sym(&self) -> Symbol {
1833 use PrimitiveType::*;
1834 match self {
1835 Isize => sym::isize,
1836 I8 => sym::i8,
1837 I16 => sym::i16,
1838 I32 => sym::i32,
1839 I64 => sym::i64,
1840 I128 => sym::i128,
1841 Usize => sym::usize,
1842 U8 => sym::u8,
1843 U16 => sym::u16,
1844 U32 => sym::u32,
1845 U64 => sym::u64,
1846 U128 => sym::u128,
1847 F16 => sym::f16,
1848 F32 => sym::f32,
1849 F64 => sym::f64,
1850 F128 => sym::f128,
1851 Str => sym::str,
1852 Bool => sym::bool,
1853 Char => sym::char,
1854 Array => sym::array,
1855 Pat => sym::pat,
1856 FieldOf => sym::field_of,
1857 Slice => sym::slice,
1858 Tuple => sym::tuple,
1859 Unit => sym::unit,
1860 RawPointer => sym::pointer,
1861 Reference => sym::reference,
1862 Fn => kw::Fn,
1863 Never => sym::never,
1864 }
1865 }
1866
1867 pub(crate) fn primitive_locations(tcx: TyCtxt<'_>) -> &FxIndexMap<PrimitiveType, DefId> {
1879 fn as_primitive(def_id: DefId, tcx: TyCtxt<'_>) -> Option<PrimitiveType> {
1880 let (attr_span, prim_sym) = find_attr!(
1881 tcx, def_id,
1882 RustcDocPrimitive(span, prim) => (*span, *prim)
1883 )?;
1884 let Some(prim) = PrimitiveType::from_symbol(prim_sym) else {
1885 span_bug!(attr_span, "primitive `{prim_sym}` is not a member of `PrimitiveType`");
1886 };
1887 Some(prim)
1888 }
1889
1890 static PRIMITIVE_LOCATIONS: OnceCell<FxIndexMap<PrimitiveType, DefId>> = OnceCell::new();
1891 PRIMITIVE_LOCATIONS.get_or_init(|| {
1892 let mut primitive_locations = FxIndexMap::default();
1893 let mut ids = tcx.all_fake_doc_items(()).clone();
1897
1898 ids.iter_mut().partition_in_place(|id| tcx.crate_name(id.krate) == sym::core);
1902 for def_id in ids {
1903 if let Some(prim) = as_primitive(def_id, tcx) {
1904 primitive_locations.insert(prim, def_id);
1905 }
1906 }
1907
1908 primitive_locations
1909 })
1910 }
1911}
1912
1913impl From<ty::IntTy> for PrimitiveType {
1914 fn from(int_ty: ty::IntTy) -> PrimitiveType {
1915 match int_ty {
1916 ty::IntTy::Isize => PrimitiveType::Isize,
1917 ty::IntTy::I8 => PrimitiveType::I8,
1918 ty::IntTy::I16 => PrimitiveType::I16,
1919 ty::IntTy::I32 => PrimitiveType::I32,
1920 ty::IntTy::I64 => PrimitiveType::I64,
1921 ty::IntTy::I128 => PrimitiveType::I128,
1922 }
1923 }
1924}
1925
1926impl From<ty::UintTy> for PrimitiveType {
1927 fn from(uint_ty: ty::UintTy) -> PrimitiveType {
1928 match uint_ty {
1929 ty::UintTy::Usize => PrimitiveType::Usize,
1930 ty::UintTy::U8 => PrimitiveType::U8,
1931 ty::UintTy::U16 => PrimitiveType::U16,
1932 ty::UintTy::U32 => PrimitiveType::U32,
1933 ty::UintTy::U64 => PrimitiveType::U64,
1934 ty::UintTy::U128 => PrimitiveType::U128,
1935 }
1936 }
1937}
1938
1939impl From<ty::FloatTy> for PrimitiveType {
1940 fn from(float_ty: ty::FloatTy) -> PrimitiveType {
1941 match float_ty {
1942 ty::FloatTy::F16 => PrimitiveType::F16,
1943 ty::FloatTy::F32 => PrimitiveType::F32,
1944 ty::FloatTy::F64 => PrimitiveType::F64,
1945 ty::FloatTy::F128 => PrimitiveType::F128,
1946 }
1947 }
1948}
1949
1950impl From<hir::PrimTy> for PrimitiveType {
1951 fn from(prim_ty: hir::PrimTy) -> PrimitiveType {
1952 match prim_ty {
1953 hir::PrimTy::Int(int_ty) => int_ty.into(),
1954 hir::PrimTy::Uint(uint_ty) => uint_ty.into(),
1955 hir::PrimTy::Float(float_ty) => float_ty.into(),
1956 hir::PrimTy::Str => PrimitiveType::Str,
1957 hir::PrimTy::Bool => PrimitiveType::Bool,
1958 hir::PrimTy::Char => PrimitiveType::Char,
1959 }
1960 }
1961}
1962
1963#[derive(Clone, Debug)]
1964pub(crate) struct Struct {
1965 pub(crate) ctor_kind: Option<CtorKind>,
1966 pub(crate) generics: Generics,
1967 pub(crate) fields: ThinVec<Item>,
1968}
1969
1970impl Struct {
1971 pub(crate) fn has_stripped_entries(&self) -> bool {
1972 self.fields.iter().any(|f| f.is_stripped())
1973 }
1974}
1975
1976#[derive(Clone, Debug)]
1977pub(crate) struct Union {
1978 pub(crate) generics: Generics,
1979 pub(crate) fields: Vec<Item>,
1980}
1981
1982impl Union {
1983 pub(crate) fn has_stripped_entries(&self) -> bool {
1984 self.fields.iter().any(|f| f.is_stripped())
1985 }
1986}
1987
1988#[derive(Clone, Debug)]
1992pub(crate) struct VariantStruct {
1993 pub(crate) fields: ThinVec<Item>,
1994}
1995
1996impl VariantStruct {
1997 pub(crate) fn has_stripped_entries(&self) -> bool {
1998 self.fields.iter().any(|f| f.is_stripped())
1999 }
2000}
2001
2002#[derive(Clone, Debug)]
2003pub(crate) struct Enum {
2004 pub(crate) variants: IndexVec<VariantIdx, Item>,
2005 pub(crate) generics: Generics,
2006}
2007
2008impl Enum {
2009 pub(crate) fn has_stripped_entries(&self) -> bool {
2010 self.variants.iter().any(|f| f.is_stripped())
2011 }
2012
2013 pub(crate) fn non_stripped_variants(&self) -> impl Iterator<Item = &Item> {
2014 self.variants.iter().filter(|v| !v.is_stripped())
2015 }
2016}
2017
2018#[derive(Clone, Debug)]
2019pub(crate) struct Variant {
2020 pub kind: VariantKind,
2021 pub discriminant: Option<Discriminant>,
2022}
2023
2024#[derive(Clone, Debug)]
2025pub(crate) enum VariantKind {
2026 CLike,
2027 Tuple(ThinVec<Item>),
2028 Struct(VariantStruct),
2029}
2030
2031impl Variant {
2032 pub(crate) fn has_stripped_entries(&self) -> Option<bool> {
2033 match &self.kind {
2034 VariantKind::Struct(struct_) => Some(struct_.has_stripped_entries()),
2035 VariantKind::CLike | VariantKind::Tuple(_) => None,
2036 }
2037 }
2038}
2039
2040#[derive(Clone, Debug)]
2041pub(crate) struct Discriminant {
2042 pub(super) expr: Option<BodyId>,
2045 pub(super) value: DefId,
2046}
2047
2048impl Discriminant {
2049 pub(crate) fn expr(&self, tcx: TyCtxt<'_>) -> Option<String> {
2052 self.expr
2053 .map(|body| rendered_const(tcx, tcx.hir_body(body), tcx.hir_body_owner_def_id(body)))
2054 }
2055 pub(crate) fn value(&self, tcx: TyCtxt<'_>, with_underscores: bool) -> String {
2056 print_evaluated_const(tcx, self.value, with_underscores, false).unwrap()
2057 }
2058}
2059
2060#[derive(Copy, Clone, Debug)]
2063pub(crate) struct Span(rustc_span::Span);
2064
2065impl Span {
2066 pub(crate) fn new(sp: rustc_span::Span) -> Self {
2071 Self(sp.source_callsite())
2072 }
2073
2074 pub(crate) fn inner(&self) -> rustc_span::Span {
2075 self.0
2076 }
2077
2078 pub(crate) fn filename(&self, sess: &Session) -> FileName {
2079 sess.source_map().span_to_filename(self.0)
2080 }
2081
2082 pub(crate) fn lo(&self, sess: &Session) -> Loc {
2083 sess.source_map().lookup_char_pos(self.0.lo())
2084 }
2085
2086 pub(crate) fn hi(&self, sess: &Session) -> Loc {
2087 sess.source_map().lookup_char_pos(self.0.hi())
2088 }
2089
2090 pub(crate) fn cnum(&self, sess: &Session) -> CrateNum {
2091 self.lo(sess).file.cnum
2093 }
2094}
2095
2096#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2097pub(crate) struct Path {
2098 pub(crate) res: Res,
2099 pub(crate) segments: ThinVec<PathSegment>,
2100}
2101
2102impl Path {
2103 pub(crate) fn def_id(&self) -> DefId {
2104 self.res.def_id()
2105 }
2106
2107 pub(crate) fn last_opt(&self) -> Option<Symbol> {
2108 self.segments.last().map(|s| s.name)
2109 }
2110
2111 pub(crate) fn last(&self) -> Symbol {
2112 self.last_opt().expect("segments were empty")
2113 }
2114
2115 pub(crate) fn whole_name(&self) -> String {
2116 self.segments
2117 .iter()
2118 .map(|s| if s.name == kw::PathRoot { "" } else { s.name.as_str() })
2119 .intersperse("::")
2120 .collect()
2121 }
2122
2123 pub(crate) fn is_assoc_ty(&self) -> bool {
2125 match self.res {
2126 Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } | Res::Def(DefKind::TyParam, _)
2127 if self.segments.len() != 1 =>
2128 {
2129 true
2130 }
2131 Res::Def(DefKind::AssocTy, _) => true,
2132 _ => false,
2133 }
2134 }
2135
2136 pub(crate) fn generic_args(&self) -> Option<&GenericArgs> {
2137 self.segments.last().map(|seg| &seg.args)
2138 }
2139
2140 pub(crate) fn generics(&self) -> Option<impl Iterator<Item = &Type>> {
2141 self.segments.last().and_then(|seg| {
2142 if let GenericArgs::AngleBracketed { ref args, .. } = seg.args {
2143 Some(args.iter().filter_map(|arg| match arg {
2144 GenericArg::Type(ty) => Some(ty),
2145 _ => None,
2146 }))
2147 } else {
2148 None
2149 }
2150 })
2151 }
2152}
2153
2154#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2155pub(crate) enum GenericArg {
2156 Lifetime(Lifetime),
2157 Type(Type),
2158 Const(Box<ConstantKind>),
2159 Infer,
2160}
2161
2162impl GenericArg {
2163 pub(crate) fn as_lt(&self) -> Option<&Lifetime> {
2164 if let Self::Lifetime(lt) = self { Some(lt) } else { None }
2165 }
2166
2167 pub(crate) fn as_ty(&self) -> Option<&Type> {
2168 if let Self::Type(ty) = self { Some(ty) } else { None }
2169 }
2170}
2171
2172#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2173pub(crate) enum GenericArgs {
2174 AngleBracketed { args: ThinVec<GenericArg>, constraints: ThinVec<AssocItemConstraint> },
2176 Parenthesized { inputs: ThinVec<Type>, output: Option<Box<Type>> },
2178 ReturnTypeNotation,
2180}
2181
2182impl GenericArgs {
2183 pub(crate) fn is_empty(&self) -> bool {
2184 match self {
2185 GenericArgs::AngleBracketed { args, constraints } => {
2186 args.is_empty() && constraints.is_empty()
2187 }
2188 GenericArgs::Parenthesized { inputs, output } => inputs.is_empty() && output.is_none(),
2189 GenericArgs::ReturnTypeNotation => false,
2190 }
2191 }
2192 pub(crate) fn constraints(&self) -> Box<dyn Iterator<Item = AssocItemConstraint> + '_> {
2193 match self {
2194 GenericArgs::AngleBracketed { constraints, .. } => {
2195 Box::new(constraints.iter().cloned())
2196 }
2197 GenericArgs::Parenthesized { output, .. } => Box::new(
2198 output
2199 .as_ref()
2200 .map(|ty| AssocItemConstraint {
2201 assoc: PathSegment {
2202 name: sym::Output,
2203 args: GenericArgs::AngleBracketed {
2204 args: ThinVec::new(),
2205 constraints: ThinVec::new(),
2206 },
2207 },
2208 kind: AssocItemConstraintKind::Equality {
2209 term: Term::Type((**ty).clone()),
2210 },
2211 })
2212 .into_iter(),
2213 ),
2214 GenericArgs::ReturnTypeNotation => Box::new([].into_iter()),
2215 }
2216 }
2217}
2218
2219impl<'a> IntoIterator for &'a GenericArgs {
2220 type IntoIter = Box<dyn Iterator<Item = GenericArg> + 'a>;
2221 type Item = GenericArg;
2222 fn into_iter(self) -> Self::IntoIter {
2223 match self {
2224 GenericArgs::AngleBracketed { args, .. } => Box::new(args.iter().cloned()),
2225 GenericArgs::Parenthesized { inputs, .. } => {
2226 Box::new(inputs.iter().cloned().map(GenericArg::Type))
2228 }
2229 GenericArgs::ReturnTypeNotation => Box::new([].into_iter()),
2230 }
2231 }
2232}
2233
2234#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2235pub(crate) struct PathSegment {
2236 pub(crate) name: Symbol,
2237 pub(crate) args: GenericArgs,
2238}
2239
2240#[derive(Clone, Debug)]
2241pub(crate) enum TypeAliasInnerType {
2242 Enum { variants: IndexVec<VariantIdx, Item>, is_non_exhaustive: bool },
2243 Union { fields: Vec<Item> },
2244 Struct { ctor_kind: Option<CtorKind>, fields: Vec<Item> },
2245}
2246
2247impl TypeAliasInnerType {
2248 fn has_stripped_entries(&self) -> Option<bool> {
2249 Some(match self {
2250 Self::Enum { variants, .. } => variants.iter().any(|v| v.is_stripped()),
2251 Self::Union { fields } | Self::Struct { fields, .. } => {
2252 fields.iter().any(|f| f.is_stripped())
2253 }
2254 })
2255 }
2256}
2257
2258#[derive(Clone, Debug)]
2259pub(crate) struct TypeAlias {
2260 pub(crate) type_: Type,
2261 pub(crate) generics: Generics,
2262 pub(crate) inner_type: Option<TypeAliasInnerType>,
2265 pub(crate) item_type: Option<Type>,
2272}
2273
2274#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2275pub(crate) struct BareFunctionDecl {
2276 pub(crate) safety: hir::Safety,
2277 pub(crate) generic_params: Vec<GenericParamDef>,
2278 pub(crate) decl: FnDecl,
2279 pub(crate) abi: ExternAbi,
2280}
2281
2282#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2283pub(crate) struct UnsafeBinderTy {
2284 pub(crate) generic_params: Vec<GenericParamDef>,
2285 pub(crate) ty: Type,
2286}
2287
2288#[derive(Clone, Debug)]
2289pub(crate) struct Static {
2290 pub(crate) type_: Box<Type>,
2291 pub(crate) mutability: Mutability,
2292 pub(crate) expr: Option<BodyId>,
2293}
2294
2295#[derive(Clone, PartialEq, Eq, Hash, Debug)]
2296pub(crate) struct Constant {
2297 pub(crate) generics: Generics,
2298 pub(crate) kind: ConstantKind,
2299 pub(crate) type_: Type,
2300}
2301
2302#[derive(Clone, PartialEq, Eq, Hash, Debug)]
2303pub(crate) enum Term {
2304 Type(Type),
2305 Constant(ConstantKind),
2306}
2307
2308impl Term {
2309 pub(crate) fn ty(&self) -> Option<&Type> {
2310 if let Term::Type(ty) = self { Some(ty) } else { None }
2311 }
2312}
2313
2314impl From<Type> for Term {
2315 fn from(ty: Type) -> Self {
2316 Term::Type(ty)
2317 }
2318}
2319
2320#[derive(Clone, PartialEq, Eq, Hash, Debug)]
2321pub(crate) enum ConstantKind {
2322 TyConst { expr: Box<str> },
2328 Path { path: Box<str> },
2331 Anonymous { body: BodyId },
2335 Extern { def_id: DefId },
2337 Local { def_id: DefId, body: BodyId },
2339 Infer,
2341}
2342
2343impl ConstantKind {
2344 pub(crate) fn expr(&self, tcx: TyCtxt<'_>) -> String {
2345 match *self {
2346 ConstantKind::TyConst { ref expr } => expr.to_string(),
2347 ConstantKind::Path { ref path } => path.to_string(),
2348 ConstantKind::Extern { def_id } => print_inlined_const(tcx, def_id),
2349 ConstantKind::Local { body, .. } | ConstantKind::Anonymous { body } => {
2350 rendered_const(tcx, tcx.hir_body(body), tcx.hir_body_owner_def_id(body))
2351 }
2352 ConstantKind::Infer => "_".to_string(),
2353 }
2354 }
2355
2356 pub(crate) fn value(&self, tcx: TyCtxt<'_>) -> Option<String> {
2357 match *self {
2358 ConstantKind::TyConst { .. }
2359 | ConstantKind::Path { .. }
2360 | ConstantKind::Anonymous { .. }
2361 | ConstantKind::Infer => None,
2362 ConstantKind::Extern { def_id } | ConstantKind::Local { def_id, .. } => {
2363 print_evaluated_const(tcx, def_id, true, true)
2364 }
2365 }
2366 }
2367
2368 pub(crate) fn is_literal(&self, tcx: TyCtxt<'_>) -> bool {
2369 match *self {
2370 ConstantKind::TyConst { .. }
2371 | ConstantKind::Extern { .. }
2372 | ConstantKind::Path { .. }
2373 | ConstantKind::Infer => false,
2374 ConstantKind::Local { body, .. } | ConstantKind::Anonymous { body } => {
2375 is_literal_expr(tcx, body.hir_id)
2376 }
2377 }
2378 }
2379}
2380
2381#[derive(Clone, Debug)]
2382pub(crate) struct Impl {
2383 pub(crate) safety: hir::Safety,
2384 pub(crate) generics: Generics,
2385 pub(crate) trait_: Option<Path>,
2386 pub(crate) for_: Type,
2387 pub(crate) items: Vec<Item>,
2388 pub(crate) polarity: ty::ImplPolarity,
2389 pub(crate) kind: ImplKind,
2390 pub(crate) is_deprecated: bool,
2391}
2392
2393impl Impl {
2394 pub(crate) fn provided_trait_methods(&self, tcx: TyCtxt<'_>) -> FxIndexSet<Symbol> {
2395 self.trait_
2396 .as_ref()
2397 .map(|t| t.def_id())
2398 .map(|did| tcx.provided_trait_methods(did).map(|meth| meth.name()).collect())
2399 .unwrap_or_default()
2400 }
2401
2402 pub(crate) fn is_negative_trait_impl(&self) -> bool {
2403 matches!(self.polarity, ty::ImplPolarity::Negative)
2404 }
2405}
2406
2407#[derive(Clone, Debug)]
2408pub(crate) enum ImplKind {
2409 Normal,
2410 Auto,
2411 FakeVariadic,
2412 Blanket(Box<Type>),
2413}
2414
2415impl ImplKind {
2416 pub(crate) fn is_auto(&self) -> bool {
2417 matches!(self, ImplKind::Auto)
2418 }
2419
2420 pub(crate) fn is_blanket(&self) -> bool {
2421 matches!(self, ImplKind::Blanket(_))
2422 }
2423
2424 pub(crate) fn is_fake_variadic(&self) -> bool {
2425 matches!(self, ImplKind::FakeVariadic)
2426 }
2427
2428 pub(crate) fn as_blanket_ty(&self) -> Option<&Type> {
2429 match self {
2430 ImplKind::Blanket(ty) => Some(ty),
2431 _ => None,
2432 }
2433 }
2434}
2435
2436#[derive(Clone, Debug)]
2437pub(crate) struct Import {
2438 pub(crate) kind: ImportKind,
2439 pub(crate) source: ImportSource,
2441 pub(crate) should_be_displayed: bool,
2442}
2443
2444impl Import {
2445 pub(crate) fn new_simple(
2446 name: Symbol,
2447 source: ImportSource,
2448 should_be_displayed: bool,
2449 ) -> Self {
2450 Self { kind: ImportKind::Simple(name), source, should_be_displayed }
2451 }
2452
2453 pub(crate) fn new_glob(source: ImportSource, should_be_displayed: bool) -> Self {
2454 Self { kind: ImportKind::Glob, source, should_be_displayed }
2455 }
2456
2457 pub(crate) fn imported_item_is_doc_hidden(&self, tcx: TyCtxt<'_>) -> bool {
2458 self.source.did.is_some_and(|did| tcx.is_doc_hidden(did))
2459 }
2460}
2461
2462#[derive(Clone, Debug)]
2463pub(crate) enum ImportKind {
2464 Simple(Symbol),
2466 Glob,
2468}
2469
2470#[derive(Clone, Debug)]
2471pub(crate) struct ImportSource {
2472 pub(crate) path: Path,
2473 pub(crate) did: Option<DefId>,
2474}
2475
2476#[derive(Clone, Debug)]
2477pub(crate) struct Macro {
2478 pub(crate) source: String,
2479 pub(crate) macro_rules: bool,
2481}
2482
2483#[derive(Clone, Debug)]
2484pub(crate) struct ProcMacro {
2485 pub(crate) kind: MacroKind,
2486 pub(crate) helpers: Vec<Symbol>,
2487}
2488
2489#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2500pub(crate) struct AssocItemConstraint {
2501 pub(crate) assoc: PathSegment,
2502 pub(crate) kind: AssocItemConstraintKind,
2503}
2504
2505#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2507pub(crate) enum AssocItemConstraintKind {
2508 Equality { term: Term },
2509 Bound { bounds: Vec<GenericBound> },
2510}
2511
2512#[cfg(target_pointer_width = "64")]
2514mod size_asserts {
2515 use rustc_data_structures::static_assert_size;
2516
2517 use super::*;
2518 static_assert_size!(Crate, 16); static_assert_size!(DocFragment, 48);
2521 static_assert_size!(GenericArg, 32);
2522 static_assert_size!(GenericArgs, 24);
2523 static_assert_size!(GenericParamDef, 40);
2524 static_assert_size!(Generics, 16);
2525 static_assert_size!(Item, 8);
2526 static_assert_size!(ItemInner, 144);
2527 static_assert_size!(ItemKind, 48);
2528 static_assert_size!(PathSegment, 32);
2529 static_assert_size!(Type, 32);
2530 }