1use std::hash::Hash;
2use std::path::PathBuf;
3use std::sync::{Arc, OnceLock as OnceCell};
4use std::{fmt, iter};
5
6use arrayvec::ArrayVec;
7use itertools::Either;
8use rustc_abi::{ExternAbi, VariantIdx};
9use rustc_attr_data_structures::{
10 AttributeKind, ConstStability, Deprecation, Stability, StableSince, find_attr,
11};
12use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
13use rustc_hir::def::{CtorKind, DefKind, Res};
14use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId};
15use rustc_hir::lang_items::LangItem;
16use rustc_hir::{BodyId, Mutability};
17use rustc_index::IndexVec;
18use rustc_metadata::rendered_const;
19use rustc_middle::span_bug;
20use rustc_middle::ty::fast_reject::SimplifiedType;
21use rustc_middle::ty::{self, TyCtxt, Visibility};
22use rustc_resolve::rustdoc::{
23 DocFragment, add_doc_fragment, attrs_to_doc_fragments, inner_docs, span_of_fragments,
24};
25use rustc_session::Session;
26use rustc_span::hygiene::MacroKind;
27use rustc_span::symbol::{Symbol, kw, sym};
28use rustc_span::{DUMMY_SP, FileName, Loc};
29use thin_vec::ThinVec;
30use tracing::{debug, trace};
31use {rustc_ast as ast, rustc_hir as hir};
32
33pub(crate) use self::ItemKind::*;
34pub(crate) use self::Type::{
35 Array, BareFunction, BorrowedRef, DynTrait, Generic, ImplTrait, Infer, Primitive, QPath,
36 RawPointer, SelfTy, Slice, Tuple, UnsafeBinder,
37};
38use crate::clean::cfg::Cfg;
39use crate::clean::clean_middle_path;
40use crate::clean::inline::{self, print_inlined_const};
41use crate::clean::utils::{is_literal_expr, print_evaluated_const};
42use crate::core::DocContext;
43use crate::formats::cache::Cache;
44use crate::formats::item_type::ItemType;
45use crate::html::render::Context;
46use crate::passes::collect_intra_doc_links::UrlFragment;
47
48#[cfg(test)]
49mod tests;
50
51pub(crate) type ItemIdSet = FxHashSet<ItemId>;
52
53#[derive(Debug, Clone, PartialEq, Eq, Hash, Copy)]
54pub(crate) enum ItemId {
55 DefId(DefId),
57 Auto { trait_: DefId, for_: DefId },
59 Blanket { impl_id: DefId, for_: DefId },
61}
62
63impl ItemId {
64 #[inline]
65 pub(crate) fn is_local(self) -> bool {
66 match self {
67 ItemId::Auto { for_: id, .. }
68 | ItemId::Blanket { for_: id, .. }
69 | ItemId::DefId(id) => id.is_local(),
70 }
71 }
72
73 #[inline]
74 #[track_caller]
75 pub(crate) fn expect_def_id(self) -> DefId {
76 self.as_def_id()
77 .unwrap_or_else(|| panic!("ItemId::expect_def_id: `{self:?}` isn't a DefId"))
78 }
79
80 #[inline]
81 pub(crate) fn as_def_id(self) -> Option<DefId> {
82 match self {
83 ItemId::DefId(id) => Some(id),
84 _ => None,
85 }
86 }
87
88 #[inline]
89 pub(crate) fn as_local_def_id(self) -> Option<LocalDefId> {
90 self.as_def_id().and_then(|id| id.as_local())
91 }
92
93 #[inline]
94 pub(crate) fn krate(self) -> CrateNum {
95 match self {
96 ItemId::Auto { for_: id, .. }
97 | ItemId::Blanket { for_: id, .. }
98 | ItemId::DefId(id) => id.krate,
99 }
100 }
101}
102
103impl From<DefId> for ItemId {
104 fn from(id: DefId) -> Self {
105 Self::DefId(id)
106 }
107}
108
109#[derive(Debug)]
111pub(crate) struct Crate {
112 pub(crate) module: Item,
113 pub(crate) external_traits: Box<FxIndexMap<DefId, Trait>>,
115}
116
117impl Crate {
118 pub(crate) fn name(&self, tcx: TyCtxt<'_>) -> Symbol {
119 ExternalCrate::LOCAL.name(tcx)
120 }
121
122 pub(crate) fn src(&self, tcx: TyCtxt<'_>) -> FileName {
123 ExternalCrate::LOCAL.src(tcx)
124 }
125}
126
127#[derive(Copy, Clone, Debug)]
128pub(crate) struct ExternalCrate {
129 pub(crate) crate_num: CrateNum,
130}
131
132impl ExternalCrate {
133 const LOCAL: Self = Self { crate_num: LOCAL_CRATE };
134
135 #[inline]
136 pub(crate) fn def_id(&self) -> DefId {
137 self.crate_num.as_def_id()
138 }
139
140 pub(crate) fn src(&self, tcx: TyCtxt<'_>) -> FileName {
141 let krate_span = tcx.def_span(self.def_id());
142 tcx.sess.source_map().span_to_filename(krate_span)
143 }
144
145 pub(crate) fn name(&self, tcx: TyCtxt<'_>) -> Symbol {
146 tcx.crate_name(self.crate_num)
147 }
148
149 pub(crate) fn src_root(&self, tcx: TyCtxt<'_>) -> PathBuf {
150 match self.src(tcx) {
151 FileName::Real(ref p) => match p.local_path_if_available().parent() {
152 Some(p) => p.to_path_buf(),
153 None => PathBuf::new(),
154 },
155 _ => PathBuf::new(),
156 }
157 }
158
159 pub(crate) fn location(
162 &self,
163 extern_url: Option<&str>,
164 extern_url_takes_precedence: bool,
165 dst: &std::path::Path,
166 tcx: TyCtxt<'_>,
167 ) -> ExternalLocation {
168 use ExternalLocation::*;
169
170 fn to_remote(url: impl ToString) -> ExternalLocation {
171 let mut url = url.to_string();
172 if !url.ends_with('/') {
173 url.push('/');
174 }
175 Remote(url)
176 }
177
178 let local_location = dst.join(self.name(tcx).as_str());
182 if local_location.is_dir() {
183 return Local;
184 }
185
186 if extern_url_takes_precedence && let Some(url) = extern_url {
187 return to_remote(url);
188 }
189
190 let did = self.crate_num.as_def_id();
193 tcx.get_attrs(did, sym::doc)
194 .flat_map(|attr| attr.meta_item_list().unwrap_or_default())
195 .filter(|a| a.has_name(sym::html_root_url))
196 .filter_map(|a| a.value_str())
197 .map(to_remote)
198 .next()
199 .or_else(|| extern_url.map(to_remote)) .unwrap_or(Unknown) }
202
203 fn mapped_root_modules<T>(
204 &self,
205 tcx: TyCtxt<'_>,
206 f: impl Fn(DefId, TyCtxt<'_>) -> Option<(DefId, T)>,
207 ) -> impl Iterator<Item = (DefId, T)> {
208 let root = self.def_id();
209
210 if root.is_local() {
211 Either::Left(
212 tcx.hir_root_module()
213 .item_ids
214 .iter()
215 .filter(move |&&id| matches!(tcx.hir_item(id).kind, hir::ItemKind::Mod(..)))
216 .filter_map(move |&id| f(id.owner_id.into(), tcx)),
217 )
218 } else {
219 Either::Right(
220 tcx.module_children(root)
221 .iter()
222 .filter_map(|item| {
223 if let Res::Def(DefKind::Mod, did) = item.res { Some(did) } else { None }
224 })
225 .filter_map(move |did| f(did, tcx)),
226 )
227 }
228 }
229
230 pub(crate) fn keywords(&self, tcx: TyCtxt<'_>) -> impl Iterator<Item = (DefId, Symbol)> {
231 fn as_keyword(did: DefId, tcx: TyCtxt<'_>) -> Option<(DefId, Symbol)> {
232 tcx.get_attrs(did, sym::doc)
233 .flat_map(|attr| attr.meta_item_list().unwrap_or_default())
234 .filter(|meta| meta.has_name(sym::keyword))
235 .find_map(|meta| meta.value_str())
236 .map(|value| (did, value))
237 }
238
239 self.mapped_root_modules(tcx, as_keyword)
240 }
241
242 pub(crate) fn primitives(
243 &self,
244 tcx: TyCtxt<'_>,
245 ) -> impl Iterator<Item = (DefId, PrimitiveType)> {
246 fn as_primitive(def_id: DefId, tcx: TyCtxt<'_>) -> Option<(DefId, PrimitiveType)> {
264 tcx.get_attrs(def_id, sym::rustc_doc_primitive).next().map(|attr| {
265 let attr_value = attr.value_str().expect("syntax should already be validated");
266 let Some(prim) = PrimitiveType::from_symbol(attr_value) else {
267 span_bug!(
268 attr.span(),
269 "primitive `{attr_value}` is not a member of `PrimitiveType`"
270 );
271 };
272
273 (def_id, prim)
274 })
275 }
276
277 self.mapped_root_modules(tcx, as_primitive)
278 }
279}
280
281#[derive(Debug)]
283pub(crate) enum ExternalLocation {
284 Remote(String),
286 Local,
288 Unknown,
290}
291
292#[derive(Clone)]
296pub(crate) struct Item {
297 pub(crate) inner: Box<ItemInner>,
298}
299
300#[derive(Clone)]
306pub(crate) struct ItemInner {
307 pub(crate) name: Option<Symbol>,
310 pub(crate) kind: ItemKind,
313 pub(crate) attrs: Attributes,
314 pub(crate) stability: Option<Stability>,
316 pub(crate) item_id: ItemId,
317 pub(crate) inline_stmt_id: Option<LocalDefId>,
321 pub(crate) cfg: Option<Arc<Cfg>>,
322}
323
324impl std::ops::Deref for Item {
325 type Target = ItemInner;
326 fn deref(&self) -> &ItemInner {
327 &self.inner
328 }
329}
330
331impl fmt::Debug for Item {
334 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
335 let alternate = f.alternate();
336 let mut fmt = f.debug_struct("Item");
338 fmt.field("name", &self.name).field("item_id", &self.item_id);
339 if alternate {
341 fmt.field("attrs", &self.attrs).field("kind", &self.kind).field("cfg", &self.cfg);
342 } else {
343 fmt.field("kind", &self.type_());
344 fmt.field("docs", &self.doc_value());
345 }
346 fmt.finish()
347 }
348}
349
350pub(crate) fn rustc_span(def_id: DefId, tcx: TyCtxt<'_>) -> Span {
351 Span::new(def_id.as_local().map_or_else(
352 || tcx.def_span(def_id),
353 |local| tcx.hir_span_with_body(tcx.local_def_id_to_hir_id(local)),
354 ))
355}
356
357fn is_field_vis_inherited(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
358 let parent = tcx.parent(def_id);
359 match tcx.def_kind(parent) {
360 DefKind::Struct | DefKind::Union => false,
361 DefKind::Variant => true,
362 parent_kind => panic!("unexpected parent kind: {parent_kind:?}"),
363 }
364}
365
366impl Item {
367 pub(crate) fn stability(&self, tcx: TyCtxt<'_>) -> Option<Stability> {
371 let stability = self.inner.stability;
372 debug_assert!(
373 stability.is_some()
374 || self.def_id().is_none_or(|did| tcx.lookup_stability(did).is_none()),
375 "missing stability for cleaned item: {self:?}",
376 );
377 stability
378 }
379
380 pub(crate) fn const_stability(&self, tcx: TyCtxt<'_>) -> Option<ConstStability> {
381 self.def_id().and_then(|did| tcx.lookup_const_stability(did))
382 }
383
384 pub(crate) fn deprecation(&self, tcx: TyCtxt<'_>) -> Option<Deprecation> {
385 self.def_id().and_then(|did| tcx.lookup_deprecation(did)).or_else(|| {
386 let stab = self.stability(tcx)?;
390 if let rustc_attr_data_structures::StabilityLevel::Stable {
391 allowed_through_unstable_modules: Some(note),
392 ..
393 } = stab.level
394 {
395 Some(Deprecation {
396 since: rustc_attr_data_structures::DeprecatedSince::Unspecified,
397 note: Some(note),
398 suggestion: None,
399 })
400 } else {
401 None
402 }
403 })
404 }
405
406 pub(crate) fn inner_docs(&self, tcx: TyCtxt<'_>) -> bool {
407 self.item_id
408 .as_def_id()
409 .map(|did| inner_docs(tcx.get_attrs_unchecked(did)))
410 .unwrap_or(false)
411 }
412
413 pub(crate) fn span(&self, tcx: TyCtxt<'_>) -> Option<Span> {
414 let kind = match &self.kind {
415 ItemKind::StrippedItem(k) => k,
416 _ => &self.kind,
417 };
418 match kind {
419 ItemKind::ModuleItem(Module { span, .. }) => Some(*span),
420 ItemKind::ImplItem(box Impl { kind: ImplKind::Auto, .. }) => None,
421 ItemKind::ImplItem(box Impl { kind: ImplKind::Blanket(_), .. }) => {
422 if let ItemId::Blanket { impl_id, .. } = self.item_id {
423 Some(rustc_span(impl_id, tcx))
424 } else {
425 panic!("blanket impl item has non-blanket ID")
426 }
427 }
428 _ => self.def_id().map(|did| rustc_span(did, tcx)),
429 }
430 }
431
432 pub(crate) fn attr_span(&self, tcx: TyCtxt<'_>) -> rustc_span::Span {
433 span_of_fragments(&self.attrs.doc_strings)
434 .unwrap_or_else(|| self.span(tcx).map_or(DUMMY_SP, |span| span.inner()))
435 }
436
437 pub(crate) fn doc_value(&self) -> String {
439 self.attrs.doc_value()
440 }
441
442 pub(crate) fn opt_doc_value(&self) -> Option<String> {
446 self.attrs.opt_doc_value()
447 }
448
449 pub(crate) fn from_def_id_and_parts(
450 def_id: DefId,
451 name: Option<Symbol>,
452 kind: ItemKind,
453 cx: &mut DocContext<'_>,
454 ) -> Item {
455 let hir_attrs = cx.tcx.get_attrs_unchecked(def_id);
456
457 Self::from_def_id_and_attrs_and_parts(
458 def_id,
459 name,
460 kind,
461 Attributes::from_hir(hir_attrs),
462 extract_cfg_from_attrs(hir_attrs.iter(), cx.tcx, &cx.cache.hidden_cfg),
463 )
464 }
465
466 pub(crate) fn from_def_id_and_attrs_and_parts(
467 def_id: DefId,
468 name: Option<Symbol>,
469 kind: ItemKind,
470 attrs: Attributes,
471 cfg: Option<Arc<Cfg>>,
472 ) -> Item {
473 trace!("name={name:?}, def_id={def_id:?} cfg={cfg:?}");
474
475 Item {
476 inner: Box::new(ItemInner {
477 item_id: def_id.into(),
478 kind,
479 attrs,
480 stability: None,
481 name,
482 cfg,
483 inline_stmt_id: None,
484 }),
485 }
486 }
487
488 pub(crate) fn links(&self, cx: &Context<'_>) -> Vec<RenderedLink> {
489 use crate::html::format::{href, link_tooltip};
490
491 let Some(links) = cx.cache().intra_doc_links.get(&self.item_id) else { return vec![] };
492 links
493 .iter()
494 .filter_map(|ItemLink { link: s, link_text, page_id: id, fragment }| {
495 debug!(?id);
496 if let Ok((mut href, ..)) = href(*id, cx) {
497 debug!(?href);
498 if let Some(ref fragment) = *fragment {
499 fragment.render(&mut href, cx.tcx())
500 }
501 Some(RenderedLink {
502 original_text: s.clone(),
503 new_text: link_text.clone(),
504 tooltip: link_tooltip(*id, fragment, cx).to_string(),
505 href,
506 })
507 } else {
508 None
509 }
510 })
511 .collect()
512 }
513
514 pub(crate) fn link_names(&self, cache: &Cache) -> Vec<RenderedLink> {
520 let Some(links) = cache.intra_doc_links.get(&self.item_id) else {
521 return vec![];
522 };
523 links
524 .iter()
525 .map(|ItemLink { link: s, link_text, .. }| RenderedLink {
526 original_text: s.clone(),
527 new_text: link_text.clone(),
528 href: String::new(),
529 tooltip: String::new(),
530 })
531 .collect()
532 }
533
534 pub(crate) fn is_crate(&self) -> bool {
535 self.is_mod() && self.def_id().is_some_and(|did| did.is_crate_root())
536 }
537 pub(crate) fn is_mod(&self) -> bool {
538 self.type_() == ItemType::Module
539 }
540 pub(crate) fn is_struct(&self) -> bool {
541 self.type_() == ItemType::Struct
542 }
543 pub(crate) fn is_enum(&self) -> bool {
544 self.type_() == ItemType::Enum
545 }
546 pub(crate) fn is_variant(&self) -> bool {
547 self.type_() == ItemType::Variant
548 }
549 pub(crate) fn is_associated_type(&self) -> bool {
550 matches!(self.kind, AssocTypeItem(..) | StrippedItem(box AssocTypeItem(..)))
551 }
552 pub(crate) fn is_required_associated_type(&self) -> bool {
553 matches!(self.kind, RequiredAssocTypeItem(..) | StrippedItem(box RequiredAssocTypeItem(..)))
554 }
555 pub(crate) fn is_associated_const(&self) -> bool {
556 matches!(self.kind, ProvidedAssocConstItem(..) | ImplAssocConstItem(..) | StrippedItem(box (ProvidedAssocConstItem(..) | ImplAssocConstItem(..))))
557 }
558 pub(crate) fn is_required_associated_const(&self) -> bool {
559 matches!(self.kind, RequiredAssocConstItem(..) | StrippedItem(box RequiredAssocConstItem(..)))
560 }
561 pub(crate) fn is_method(&self) -> bool {
562 self.type_() == ItemType::Method
563 }
564 pub(crate) fn is_ty_method(&self) -> bool {
565 self.type_() == ItemType::TyMethod
566 }
567 pub(crate) fn is_primitive(&self) -> bool {
568 self.type_() == ItemType::Primitive
569 }
570 pub(crate) fn is_union(&self) -> bool {
571 self.type_() == ItemType::Union
572 }
573 pub(crate) fn is_import(&self) -> bool {
574 self.type_() == ItemType::Import
575 }
576 pub(crate) fn is_extern_crate(&self) -> bool {
577 self.type_() == ItemType::ExternCrate
578 }
579 pub(crate) fn is_keyword(&self) -> bool {
580 self.type_() == ItemType::Keyword
581 }
582 pub(crate) fn is_stripped(&self) -> bool {
583 match self.kind {
584 StrippedItem(..) => true,
585 ImportItem(ref i) => !i.should_be_displayed,
586 _ => false,
587 }
588 }
589 pub(crate) fn has_stripped_entries(&self) -> Option<bool> {
590 match self.kind {
591 StructItem(ref struct_) => Some(struct_.has_stripped_entries()),
592 UnionItem(ref union_) => Some(union_.has_stripped_entries()),
593 EnumItem(ref enum_) => Some(enum_.has_stripped_entries()),
594 VariantItem(ref v) => v.has_stripped_entries(),
595 TypeAliasItem(ref type_alias) => {
596 type_alias.inner_type.as_ref().and_then(|t| t.has_stripped_entries())
597 }
598 _ => None,
599 }
600 }
601
602 pub(crate) fn stability_class(&self, tcx: TyCtxt<'_>) -> Option<String> {
603 self.stability(tcx).as_ref().and_then(|s| {
604 let mut classes = Vec::with_capacity(2);
605
606 if s.is_unstable() {
607 classes.push("unstable");
608 }
609
610 if self.deprecation(tcx).is_some() {
612 classes.push("deprecated");
613 }
614
615 if !classes.is_empty() { Some(classes.join(" ")) } else { None }
616 })
617 }
618
619 pub(crate) fn stable_since(&self, tcx: TyCtxt<'_>) -> Option<StableSince> {
620 self.stability(tcx).and_then(|stability| stability.stable_since())
621 }
622
623 pub(crate) fn is_non_exhaustive(&self) -> bool {
624 find_attr!(&self.attrs.other_attrs, AttributeKind::NonExhaustive(..))
625 }
626
627 pub(crate) fn type_(&self) -> ItemType {
629 ItemType::from(self)
630 }
631
632 pub(crate) fn is_default(&self) -> bool {
633 match self.kind {
634 ItemKind::MethodItem(_, Some(defaultness)) => {
635 defaultness.has_value() && !defaultness.is_final()
636 }
637 _ => false,
638 }
639 }
640
641 pub(crate) fn fn_header(&self, tcx: TyCtxt<'_>) -> Option<hir::FnHeader> {
643 fn build_fn_header(
644 def_id: DefId,
645 tcx: TyCtxt<'_>,
646 asyncness: ty::Asyncness,
647 ) -> hir::FnHeader {
648 let sig = tcx.fn_sig(def_id).skip_binder();
649 let constness = if tcx.is_const_fn(def_id) {
650 match tcx.opt_associated_item(def_id) {
654 Some(ty::AssocItem {
655 container: ty::AssocItemContainer::Impl,
656 trait_item_def_id: Some(_),
657 ..
658 })
659 | Some(ty::AssocItem { container: ty::AssocItemContainer::Trait, .. }) => {
660 hir::Constness::NotConst
661 }
662 None | Some(_) => hir::Constness::Const,
663 }
664 } else {
665 hir::Constness::NotConst
666 };
667 let asyncness = match asyncness {
668 ty::Asyncness::Yes => hir::IsAsync::Async(DUMMY_SP),
669 ty::Asyncness::No => hir::IsAsync::NotAsync,
670 };
671 hir::FnHeader {
672 safety: if tcx.codegen_fn_attrs(def_id).safe_target_features {
673 hir::HeaderSafety::SafeTargetFeatures
674 } else {
675 sig.safety().into()
676 },
677 abi: sig.abi(),
678 constness,
679 asyncness,
680 }
681 }
682 let header = match self.kind {
683 ItemKind::ForeignFunctionItem(_, safety) => {
684 let def_id = self.def_id().unwrap();
685 let abi = tcx.fn_sig(def_id).skip_binder().abi();
686 hir::FnHeader {
687 safety: if tcx.codegen_fn_attrs(def_id).safe_target_features {
688 hir::HeaderSafety::SafeTargetFeatures
689 } else {
690 safety.into()
691 },
692 abi,
693 constness: if tcx.is_const_fn(def_id) {
694 hir::Constness::Const
695 } else {
696 hir::Constness::NotConst
697 },
698 asyncness: hir::IsAsync::NotAsync,
699 }
700 }
701 ItemKind::FunctionItem(_)
702 | ItemKind::MethodItem(_, _)
703 | ItemKind::RequiredMethodItem(_) => {
704 let def_id = self.def_id().unwrap();
705 build_fn_header(def_id, tcx, tcx.asyncness(def_id))
706 }
707 _ => return None,
708 };
709 Some(header)
710 }
711
712 pub(crate) fn visibility(&self, tcx: TyCtxt<'_>) -> Option<Visibility<DefId>> {
715 let def_id = match self.item_id {
716 ItemId::Auto { .. } | ItemId::Blanket { .. } => return None,
718 ItemId::DefId(def_id) => def_id,
719 };
720
721 match self.kind {
722 ItemKind::KeywordItem | ItemKind::PrimitiveItem(_) => return Some(Visibility::Public),
726 StructFieldItem(..) if is_field_vis_inherited(tcx, def_id) => {
728 return None;
729 }
730 VariantItem(..) | ImplItem(..) => return None,
732 RequiredAssocConstItem(..)
734 | ProvidedAssocConstItem(..)
735 | ImplAssocConstItem(..)
736 | AssocTypeItem(..)
737 | RequiredAssocTypeItem(..)
738 | RequiredMethodItem(..)
739 | MethodItem(..) => {
740 let assoc_item = tcx.associated_item(def_id);
741 let is_trait_item = match assoc_item.container {
742 ty::AssocItemContainer::Trait => true,
743 ty::AssocItemContainer::Impl => {
744 tcx.impl_trait_ref(tcx.parent(assoc_item.def_id)).is_some()
747 }
748 };
749 if is_trait_item {
750 return None;
751 }
752 }
753 _ => {}
754 }
755 let def_id = match self.inline_stmt_id {
756 Some(inlined) => inlined.to_def_id(),
757 None => def_id,
758 };
759 Some(tcx.visibility(def_id))
760 }
761
762 fn attributes_without_repr(&self, tcx: TyCtxt<'_>, is_json: bool) -> Vec<String> {
763 const ALLOWED_ATTRIBUTES: &[Symbol] =
764 &[sym::export_name, sym::link_section, sym::no_mangle, sym::non_exhaustive];
765 self.attrs
766 .other_attrs
767 .iter()
768 .filter_map(|attr| {
769 if let hir::Attribute::Parsed(AttributeKind::LinkSection { name, .. }) = attr {
770 Some(format!("#[link_section = \"{name}\"]"))
771 }
772 else if let hir::Attribute::Parsed(AttributeKind::NoMangle(..)) = attr {
775 Some("#[no_mangle]".to_string())
776 } else if let hir::Attribute::Parsed(AttributeKind::ExportName { name, .. }) = attr
777 {
778 Some(format!("#[export_name = \"{name}\"]"))
779 } else if let hir::Attribute::Parsed(AttributeKind::NonExhaustive(..)) = attr {
780 Some("#[non_exhaustive]".to_string())
781 } else if is_json {
782 match attr {
783 hir::Attribute::Parsed(AttributeKind::Deprecation { .. }) => None,
786 hir::Attribute::Parsed(AttributeKind::Repr { .. }) => None,
788 hir::Attribute::Parsed(AttributeKind::TargetFeature(features, _)) => {
790 let mut output = String::new();
791 for (i, (feature, _)) in features.iter().enumerate() {
792 if i != 0 {
793 output.push_str(", ");
794 }
795 output.push_str(&format!("enable=\"{}\"", feature.as_str()));
796 }
797 Some(format!("#[target_feature({output})]"))
798 }
799 hir::Attribute::Parsed(AttributeKind::AutomaticallyDerived(..)) => {
800 Some("#[automatically_derived]".to_string())
801 }
802 _ => Some({
803 let mut s = rustc_hir_pretty::attribute_to_string(&tcx, attr);
804 assert_eq!(s.pop(), Some('\n'));
805 s
806 }),
807 }
808 } else {
809 if !attr.has_any_name(ALLOWED_ATTRIBUTES) {
810 return None;
811 }
812 Some(
813 rustc_hir_pretty::attribute_to_string(&tcx, attr)
814 .replace("\\\n", "")
815 .replace('\n', "")
816 .replace(" ", " "),
817 )
818 }
819 })
820 .collect()
821 }
822
823 pub(crate) fn attributes(&self, tcx: TyCtxt<'_>, cache: &Cache, is_json: bool) -> Vec<String> {
824 let mut attrs = self.attributes_without_repr(tcx, is_json);
825
826 if let Some(repr_attr) = self.repr(tcx, cache, is_json) {
827 attrs.push(repr_attr);
828 }
829 attrs
830 }
831
832 pub(crate) fn repr(&self, tcx: TyCtxt<'_>, cache: &Cache, is_json: bool) -> Option<String> {
834 repr_attributes(tcx, cache, self.def_id()?, self.type_(), is_json)
835 }
836
837 pub fn is_doc_hidden(&self) -> bool {
838 self.attrs.is_doc_hidden()
839 }
840
841 pub fn def_id(&self) -> Option<DefId> {
842 self.item_id.as_def_id()
843 }
844}
845
846pub(crate) fn repr_attributes(
847 tcx: TyCtxt<'_>,
848 cache: &Cache,
849 def_id: DefId,
850 item_type: ItemType,
851 is_json: bool,
852) -> Option<String> {
853 use rustc_abi::IntegerType;
854
855 if !matches!(item_type, ItemType::Struct | ItemType::Enum | ItemType::Union) {
856 return None;
857 }
858 let adt = tcx.adt_def(def_id);
859 let repr = adt.repr();
860 let mut out = Vec::new();
861 if repr.c() {
862 out.push("C");
863 }
864 if repr.transparent() {
865 let render_transparent = cache.document_private
868 || is_json
869 || adt
870 .all_fields()
871 .find(|field| {
872 let ty = field.ty(tcx, ty::GenericArgs::identity_for_item(tcx, field.did));
873 tcx.layout_of(ty::TypingEnv::post_analysis(tcx, field.did).as_query_input(ty))
874 .is_ok_and(|layout| !layout.is_1zst())
875 })
876 .map_or_else(
877 || adt.all_fields().any(|field| field.vis.is_public()),
878 |field| field.vis.is_public(),
879 );
880
881 if render_transparent {
882 out.push("transparent");
883 }
884 }
885 if repr.simd() {
886 out.push("simd");
887 }
888 let pack_s;
889 if let Some(pack) = repr.pack {
890 pack_s = format!("packed({})", pack.bytes());
891 out.push(&pack_s);
892 }
893 let align_s;
894 if let Some(align) = repr.align {
895 align_s = format!("align({})", align.bytes());
896 out.push(&align_s);
897 }
898 let int_s;
899 if let Some(int) = repr.int {
900 int_s = match int {
901 IntegerType::Pointer(is_signed) => {
902 format!("{}size", if is_signed { 'i' } else { 'u' })
903 }
904 IntegerType::Fixed(size, is_signed) => {
905 format!("{}{}", if is_signed { 'i' } else { 'u' }, size.size().bytes() * 8)
906 }
907 };
908 out.push(&int_s);
909 }
910 if !out.is_empty() { Some(format!("#[repr({})]", out.join(", "))) } else { None }
911}
912
913#[derive(Clone, Debug)]
914pub(crate) enum ItemKind {
915 ExternCrateItem {
916 src: Option<Symbol>,
918 },
919 ImportItem(Import),
920 StructItem(Struct),
921 UnionItem(Union),
922 EnumItem(Enum),
923 FunctionItem(Box<Function>),
924 ModuleItem(Module),
925 TypeAliasItem(Box<TypeAlias>),
926 StaticItem(Static),
927 TraitItem(Box<Trait>),
928 TraitAliasItem(TraitAlias),
929 ImplItem(Box<Impl>),
930 RequiredMethodItem(Box<Function>),
932 MethodItem(Box<Function>, Option<hir::Defaultness>),
936 StructFieldItem(Type),
937 VariantItem(Variant),
938 ForeignFunctionItem(Box<Function>, hir::Safety),
940 ForeignStaticItem(Static, hir::Safety),
942 ForeignTypeItem,
944 MacroItem(Macro),
945 ProcMacroItem(ProcMacro),
946 PrimitiveItem(PrimitiveType),
947 RequiredAssocConstItem(Generics, Box<Type>),
949 ConstantItem(Box<Constant>),
950 ProvidedAssocConstItem(Box<Constant>),
952 ImplAssocConstItem(Box<Constant>),
954 RequiredAssocTypeItem(Generics, Vec<GenericBound>),
958 AssocTypeItem(Box<TypeAlias>, Vec<GenericBound>),
960 StrippedItem(Box<ItemKind>),
962 KeywordItem,
963}
964
965impl ItemKind {
966 pub(crate) fn inner_items(&self) -> impl Iterator<Item = &Item> {
969 match self {
970 StructItem(s) => s.fields.iter(),
971 UnionItem(u) => u.fields.iter(),
972 VariantItem(v) => match &v.kind {
973 VariantKind::CLike => [].iter(),
974 VariantKind::Tuple(t) => t.iter(),
975 VariantKind::Struct(s) => s.fields.iter(),
976 },
977 EnumItem(e) => e.variants.iter(),
978 TraitItem(t) => t.items.iter(),
979 ImplItem(i) => i.items.iter(),
980 ModuleItem(m) => m.items.iter(),
981 ExternCrateItem { .. }
982 | ImportItem(_)
983 | FunctionItem(_)
984 | TypeAliasItem(_)
985 | StaticItem(_)
986 | ConstantItem(_)
987 | TraitAliasItem(_)
988 | RequiredMethodItem(_)
989 | MethodItem(_, _)
990 | StructFieldItem(_)
991 | ForeignFunctionItem(_, _)
992 | ForeignStaticItem(_, _)
993 | ForeignTypeItem
994 | MacroItem(_)
995 | ProcMacroItem(_)
996 | PrimitiveItem(_)
997 | RequiredAssocConstItem(..)
998 | ProvidedAssocConstItem(..)
999 | ImplAssocConstItem(..)
1000 | RequiredAssocTypeItem(..)
1001 | AssocTypeItem(..)
1002 | StrippedItem(_)
1003 | KeywordItem => [].iter(),
1004 }
1005 }
1006
1007 pub(crate) fn is_non_assoc(&self) -> bool {
1009 matches!(
1010 self,
1011 StructItem(_)
1012 | UnionItem(_)
1013 | EnumItem(_)
1014 | TraitItem(_)
1015 | ModuleItem(_)
1016 | ExternCrateItem { .. }
1017 | FunctionItem(_)
1018 | TypeAliasItem(_)
1019 | StaticItem(_)
1020 | ConstantItem(_)
1021 | TraitAliasItem(_)
1022 | ForeignFunctionItem(_, _)
1023 | ForeignStaticItem(_, _)
1024 | ForeignTypeItem
1025 | MacroItem(_)
1026 | ProcMacroItem(_)
1027 | PrimitiveItem(_)
1028 )
1029 }
1030}
1031
1032#[derive(Clone, Debug)]
1033pub(crate) struct Module {
1034 pub(crate) items: Vec<Item>,
1035 pub(crate) span: Span,
1036}
1037
1038pub(crate) fn hir_attr_lists<'a, I: IntoIterator<Item = &'a hir::Attribute>>(
1039 attrs: I,
1040 name: Symbol,
1041) -> impl Iterator<Item = ast::MetaItemInner> + use<'a, I> {
1042 attrs
1043 .into_iter()
1044 .filter(move |attr| attr.has_name(name))
1045 .filter_map(ast::attr::AttributeExt::meta_item_list)
1046 .flatten()
1047}
1048
1049pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator<Item = &'a hir::Attribute> + Clone>(
1050 attrs: I,
1051 tcx: TyCtxt<'_>,
1052 hidden_cfg: &FxHashSet<Cfg>,
1053) -> Option<Arc<Cfg>> {
1054 let doc_cfg_active = tcx.features().doc_cfg();
1055 let doc_auto_cfg_active = tcx.features().doc_auto_cfg();
1056
1057 fn single<T: IntoIterator>(it: T) -> Option<T::Item> {
1058 let mut iter = it.into_iter();
1059 let item = iter.next()?;
1060 if iter.next().is_some() {
1061 return None;
1062 }
1063 Some(item)
1064 }
1065
1066 let mut cfg = if doc_cfg_active || doc_auto_cfg_active {
1067 let mut doc_cfg = attrs
1068 .clone()
1069 .filter(|attr| attr.has_name(sym::doc))
1070 .flat_map(|attr| attr.meta_item_list().unwrap_or_default())
1071 .filter(|attr| attr.has_name(sym::cfg))
1072 .peekable();
1073 if doc_cfg.peek().is_some() && doc_cfg_active {
1074 let sess = tcx.sess;
1075
1076 doc_cfg.fold(Cfg::True, |mut cfg, item| {
1077 if let Some(cfg_mi) =
1078 item.meta_item().and_then(|item| rustc_expand::config::parse_cfg(item, sess))
1079 {
1080 match Cfg::parse(cfg_mi) {
1081 Ok(new_cfg) => cfg &= new_cfg,
1082 Err(e) => {
1083 sess.dcx().span_err(e.span, e.msg);
1084 }
1085 }
1086 }
1087 cfg
1088 })
1089 } else if doc_auto_cfg_active {
1090 attrs
1093 .clone()
1094 .filter(|attr| attr.has_name(sym::cfg_trace))
1095 .filter_map(|attr| single(attr.meta_item_list()?))
1096 .filter_map(|attr| Cfg::parse_without(attr.meta_item()?, hidden_cfg).ok().flatten())
1097 .fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg)
1098 } else {
1099 Cfg::True
1100 }
1101 } else {
1102 Cfg::True
1103 };
1104
1105 if let Some(features) = find_attr!(attrs, AttributeKind::TargetFeature(features, _) => features)
1108 {
1109 for (feature, _) in features {
1110 cfg &= Cfg::Cfg(sym::target_feature, Some(*feature));
1111 }
1112 }
1113
1114 if cfg == Cfg::True { None } else { Some(Arc::new(cfg)) }
1115}
1116
1117pub(crate) trait NestedAttributesExt {
1118 fn has_word(self, word: Symbol) -> bool
1120 where
1121 Self: Sized,
1122 {
1123 <Self as NestedAttributesExt>::get_word_attr(self, word).is_some()
1124 }
1125
1126 fn get_word_attr(self, word: Symbol) -> Option<ast::MetaItemInner>;
1129}
1130
1131impl<I: Iterator<Item = ast::MetaItemInner>> NestedAttributesExt for I {
1132 fn get_word_attr(mut self, word: Symbol) -> Option<ast::MetaItemInner> {
1133 self.find(|attr| attr.is_word() && attr.has_name(word))
1134 }
1135}
1136
1137#[derive(Clone, Debug, PartialEq, Eq, Hash)]
1141pub(crate) struct ItemLink {
1142 pub(crate) link: Box<str>,
1144 pub(crate) link_text: Box<str>,
1149 pub(crate) page_id: DefId,
1153 pub(crate) fragment: Option<UrlFragment>,
1155}
1156
1157pub struct RenderedLink {
1158 pub(crate) original_text: Box<str>,
1162 pub(crate) new_text: Box<str>,
1164 pub(crate) href: String,
1166 pub(crate) tooltip: String,
1168}
1169
1170#[derive(Clone, Debug, Default)]
1173pub(crate) struct Attributes {
1174 pub(crate) doc_strings: Vec<DocFragment>,
1175 pub(crate) other_attrs: ThinVec<hir::Attribute>,
1176}
1177
1178impl Attributes {
1179 pub(crate) fn lists(&self, name: Symbol) -> impl Iterator<Item = ast::MetaItemInner> {
1180 hir_attr_lists(&self.other_attrs[..], name)
1181 }
1182
1183 pub(crate) fn has_doc_flag(&self, flag: Symbol) -> bool {
1184 for attr in &self.other_attrs {
1185 if !attr.has_name(sym::doc) {
1186 continue;
1187 }
1188
1189 if let Some(items) = attr.meta_item_list()
1190 && items.iter().filter_map(|i| i.meta_item()).any(|it| it.has_name(flag))
1191 {
1192 return true;
1193 }
1194 }
1195
1196 false
1197 }
1198
1199 pub(crate) fn is_doc_hidden(&self) -> bool {
1200 self.has_doc_flag(sym::hidden)
1201 }
1202
1203 pub(crate) fn from_hir(attrs: &[hir::Attribute]) -> Attributes {
1204 Attributes::from_hir_iter(attrs.iter().map(|attr| (attr, None)), false)
1205 }
1206
1207 pub(crate) fn from_hir_with_additional(
1208 attrs: &[hir::Attribute],
1209 (additional_attrs, def_id): (&[hir::Attribute], DefId),
1210 ) -> Attributes {
1211 let attrs1 = additional_attrs.iter().map(|attr| (attr, Some(def_id)));
1213 let attrs2 = attrs.iter().map(|attr| (attr, None));
1214 Attributes::from_hir_iter(attrs1.chain(attrs2), false)
1215 }
1216
1217 pub(crate) fn from_hir_iter<'a>(
1218 attrs: impl Iterator<Item = (&'a hir::Attribute, Option<DefId>)>,
1219 doc_only: bool,
1220 ) -> Attributes {
1221 let (doc_strings, other_attrs) = attrs_to_doc_fragments(attrs, doc_only);
1222 Attributes { doc_strings, other_attrs }
1223 }
1224
1225 pub(crate) fn doc_value(&self) -> String {
1227 self.opt_doc_value().unwrap_or_default()
1228 }
1229
1230 pub(crate) fn opt_doc_value(&self) -> Option<String> {
1234 (!self.doc_strings.is_empty()).then(|| {
1235 let mut res = String::new();
1236 for frag in &self.doc_strings {
1237 add_doc_fragment(&mut res, frag);
1238 }
1239 res.pop();
1240 res
1241 })
1242 }
1243
1244 pub(crate) fn get_doc_aliases(&self) -> Box<[Symbol]> {
1245 let mut aliases = FxIndexSet::default();
1246
1247 for attr in
1248 hir_attr_lists(&self.other_attrs[..], sym::doc).filter(|a| a.has_name(sym::alias))
1249 {
1250 if let Some(values) = attr.meta_item_list() {
1251 for l in values {
1252 if let Some(lit) = l.lit()
1253 && let ast::LitKind::Str(s, _) = lit.kind
1254 {
1255 aliases.insert(s);
1256 }
1257 }
1258 } else if let Some(value) = attr.value_str() {
1259 aliases.insert(value);
1260 }
1261 }
1262 aliases.into_iter().collect::<Vec<_>>().into()
1263 }
1264}
1265
1266#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1267pub(crate) enum GenericBound {
1268 TraitBound(PolyTrait, hir::TraitBoundModifiers),
1269 Outlives(Lifetime),
1270 Use(Vec<PreciseCapturingArg>),
1272}
1273
1274impl GenericBound {
1275 pub(crate) fn sized(cx: &mut DocContext<'_>) -> GenericBound {
1276 Self::sized_with(cx, hir::TraitBoundModifiers::NONE)
1277 }
1278
1279 pub(crate) fn maybe_sized(cx: &mut DocContext<'_>) -> GenericBound {
1280 Self::sized_with(
1281 cx,
1282 hir::TraitBoundModifiers {
1283 polarity: hir::BoundPolarity::Maybe(DUMMY_SP),
1284 constness: hir::BoundConstness::Never,
1285 },
1286 )
1287 }
1288
1289 fn sized_with(cx: &mut DocContext<'_>, modifiers: hir::TraitBoundModifiers) -> GenericBound {
1290 let did = cx.tcx.require_lang_item(LangItem::Sized, DUMMY_SP);
1291 let empty = ty::Binder::dummy(ty::GenericArgs::empty());
1292 let path = clean_middle_path(cx, did, false, ThinVec::new(), empty);
1293 inline::record_extern_fqn(cx, did, ItemType::Trait);
1294 GenericBound::TraitBound(PolyTrait { trait_: path, generic_params: Vec::new() }, modifiers)
1295 }
1296
1297 pub(crate) fn is_trait_bound(&self) -> bool {
1298 matches!(self, Self::TraitBound(..))
1299 }
1300
1301 pub(crate) fn is_sized_bound(&self, cx: &DocContext<'_>) -> bool {
1302 self.is_bounded_by_lang_item(cx, LangItem::Sized)
1303 }
1304
1305 pub(crate) fn is_meta_sized_bound(&self, cx: &DocContext<'_>) -> bool {
1306 self.is_bounded_by_lang_item(cx, LangItem::MetaSized)
1307 }
1308
1309 fn is_bounded_by_lang_item(&self, cx: &DocContext<'_>, lang_item: LangItem) -> bool {
1310 if let GenericBound::TraitBound(
1311 PolyTrait { ref trait_, .. },
1312 rustc_hir::TraitBoundModifiers::NONE,
1313 ) = *self
1314 && cx.tcx.is_lang_item(trait_.def_id(), lang_item)
1315 {
1316 return true;
1317 }
1318 false
1319 }
1320
1321 pub(crate) fn get_trait_path(&self) -> Option<Path> {
1322 if let GenericBound::TraitBound(PolyTrait { ref trait_, .. }, _) = *self {
1323 Some(trait_.clone())
1324 } else {
1325 None
1326 }
1327 }
1328}
1329
1330#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
1331pub(crate) struct Lifetime(pub Symbol);
1332
1333impl Lifetime {
1334 pub(crate) fn statik() -> Lifetime {
1335 Lifetime(kw::StaticLifetime)
1336 }
1337
1338 pub(crate) fn elided() -> Lifetime {
1339 Lifetime(kw::UnderscoreLifetime)
1340 }
1341}
1342
1343#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
1344pub(crate) enum PreciseCapturingArg {
1345 Lifetime(Lifetime),
1346 Param(Symbol),
1347}
1348
1349impl PreciseCapturingArg {
1350 pub(crate) fn name(self) -> Symbol {
1351 match self {
1352 PreciseCapturingArg::Lifetime(lt) => lt.0,
1353 PreciseCapturingArg::Param(param) => param,
1354 }
1355 }
1356}
1357
1358#[derive(Clone, PartialEq, Eq, Hash, Debug)]
1359pub(crate) enum WherePredicate {
1360 BoundPredicate { ty: Type, bounds: Vec<GenericBound>, bound_params: Vec<GenericParamDef> },
1361 RegionPredicate { lifetime: Lifetime, bounds: Vec<GenericBound> },
1362 EqPredicate { lhs: QPathData, rhs: Term },
1363}
1364
1365impl WherePredicate {
1366 pub(crate) fn get_bounds(&self) -> Option<&[GenericBound]> {
1367 match self {
1368 WherePredicate::BoundPredicate { bounds, .. } => Some(bounds),
1369 WherePredicate::RegionPredicate { bounds, .. } => Some(bounds),
1370 _ => None,
1371 }
1372 }
1373}
1374
1375#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1376pub(crate) enum GenericParamDefKind {
1377 Lifetime { outlives: ThinVec<Lifetime> },
1378 Type { bounds: ThinVec<GenericBound>, default: Option<Box<Type>>, synthetic: bool },
1379 Const { ty: Box<Type>, default: Option<Box<String>>, synthetic: bool },
1381}
1382
1383impl GenericParamDefKind {
1384 pub(crate) fn is_type(&self) -> bool {
1385 matches!(self, GenericParamDefKind::Type { .. })
1386 }
1387}
1388
1389#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1390pub(crate) struct GenericParamDef {
1391 pub(crate) name: Symbol,
1392 pub(crate) def_id: DefId,
1393 pub(crate) kind: GenericParamDefKind,
1394}
1395
1396impl GenericParamDef {
1397 pub(crate) fn lifetime(def_id: DefId, name: Symbol) -> Self {
1398 Self { name, def_id, kind: GenericParamDefKind::Lifetime { outlives: ThinVec::new() } }
1399 }
1400
1401 pub(crate) fn is_synthetic_param(&self) -> bool {
1402 match self.kind {
1403 GenericParamDefKind::Lifetime { .. } | GenericParamDefKind::Const { .. } => false,
1404 GenericParamDefKind::Type { synthetic, .. } => synthetic,
1405 }
1406 }
1407
1408 pub(crate) fn is_type(&self) -> bool {
1409 self.kind.is_type()
1410 }
1411
1412 pub(crate) fn get_bounds(&self) -> Option<&[GenericBound]> {
1413 match self.kind {
1414 GenericParamDefKind::Type { ref bounds, .. } => Some(bounds),
1415 _ => None,
1416 }
1417 }
1418}
1419
1420#[derive(Clone, PartialEq, Eq, Hash, Debug, Default)]
1422pub(crate) struct Generics {
1423 pub(crate) params: ThinVec<GenericParamDef>,
1424 pub(crate) where_predicates: ThinVec<WherePredicate>,
1425}
1426
1427impl Generics {
1428 pub(crate) fn is_empty(&self) -> bool {
1429 self.params.is_empty() && self.where_predicates.is_empty()
1430 }
1431}
1432
1433#[derive(Clone, Debug)]
1434pub(crate) struct Function {
1435 pub(crate) decl: FnDecl,
1436 pub(crate) generics: Generics,
1437}
1438
1439#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1440pub(crate) struct FnDecl {
1441 pub(crate) inputs: Vec<Parameter>,
1442 pub(crate) output: Type,
1443 pub(crate) c_variadic: bool,
1444}
1445
1446impl FnDecl {
1447 pub(crate) fn receiver_type(&self) -> Option<&Type> {
1448 self.inputs.first().and_then(|v| v.to_receiver())
1449 }
1450}
1451
1452#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1454pub(crate) struct Parameter {
1455 pub(crate) name: Option<Symbol>,
1456 pub(crate) type_: Type,
1457 pub(crate) is_const: bool,
1460}
1461
1462impl Parameter {
1463 pub(crate) fn to_receiver(&self) -> Option<&Type> {
1464 if self.name == Some(kw::SelfLower) { Some(&self.type_) } else { None }
1465 }
1466}
1467
1468#[derive(Clone, Debug)]
1469pub(crate) struct Trait {
1470 pub(crate) def_id: DefId,
1471 pub(crate) items: Vec<Item>,
1472 pub(crate) generics: Generics,
1473 pub(crate) bounds: Vec<GenericBound>,
1474}
1475
1476impl Trait {
1477 pub(crate) fn is_auto(&self, tcx: TyCtxt<'_>) -> bool {
1478 tcx.trait_is_auto(self.def_id)
1479 }
1480 pub(crate) fn is_notable_trait(&self, tcx: TyCtxt<'_>) -> bool {
1481 tcx.is_doc_notable_trait(self.def_id)
1482 }
1483 pub(crate) fn safety(&self, tcx: TyCtxt<'_>) -> hir::Safety {
1484 tcx.trait_def(self.def_id).safety
1485 }
1486 pub(crate) fn is_dyn_compatible(&self, tcx: TyCtxt<'_>) -> bool {
1487 tcx.is_dyn_compatible(self.def_id)
1488 }
1489}
1490
1491#[derive(Clone, Debug)]
1492pub(crate) struct TraitAlias {
1493 pub(crate) generics: Generics,
1494 pub(crate) bounds: Vec<GenericBound>,
1495}
1496
1497#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1499pub(crate) struct PolyTrait {
1500 pub(crate) trait_: Path,
1501 pub(crate) generic_params: Vec<GenericParamDef>,
1502}
1503
1504#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1506pub(crate) enum Type {
1507 Path {
1512 path: Path,
1513 },
1514 DynTrait(Vec<PolyTrait>, Option<Lifetime>),
1516 Generic(Symbol),
1518 SelfTy,
1520 Primitive(PrimitiveType),
1522 BareFunction(Box<BareFunctionDecl>),
1524 Tuple(Vec<Type>),
1526 Slice(Box<Type>),
1528 Array(Box<Type>, Box<str>),
1532 Pat(Box<Type>, Box<str>),
1533 RawPointer(Mutability, Box<Type>),
1535 BorrowedRef {
1537 lifetime: Option<Lifetime>,
1538 mutability: Mutability,
1539 type_: Box<Type>,
1540 },
1541
1542 QPath(Box<QPathData>),
1544
1545 Infer,
1547
1548 ImplTrait(Vec<GenericBound>),
1550
1551 UnsafeBinder(Box<UnsafeBinderTy>),
1552}
1553
1554impl Type {
1555 pub(crate) fn without_borrowed_ref(&self) -> &Type {
1557 let mut result = self;
1558 while let Type::BorrowedRef { type_, .. } = result {
1559 result = type_;
1560 }
1561 result
1562 }
1563
1564 pub(crate) fn is_borrowed_ref(&self) -> bool {
1565 matches!(self, Type::BorrowedRef { .. })
1566 }
1567
1568 fn is_type_alias(&self) -> bool {
1569 matches!(self, Type::Path { path: Path { res: Res::Def(DefKind::TyAlias, _), .. } })
1570 }
1571
1572 pub(crate) fn is_doc_subtype_of(&self, other: &Self, cache: &Cache) -> bool {
1593 let (self_cleared, other_cleared) = if !self.is_borrowed_ref() || !other.is_borrowed_ref() {
1596 (self.without_borrowed_ref(), other.without_borrowed_ref())
1597 } else {
1598 (self, other)
1599 };
1600
1601 if self_cleared.is_type_alias() || other_cleared.is_type_alias() {
1607 return true;
1608 }
1609
1610 match (self_cleared, other_cleared) {
1611 (Type::Tuple(a), Type::Tuple(b)) => {
1613 a.len() == b.len() && a.iter().zip(b).all(|(a, b)| a.is_doc_subtype_of(b, cache))
1614 }
1615 (Type::Slice(a), Type::Slice(b)) => a.is_doc_subtype_of(b, cache),
1616 (Type::Array(a, al), Type::Array(b, bl)) => al == bl && a.is_doc_subtype_of(b, cache),
1617 (Type::RawPointer(mutability, type_), Type::RawPointer(b_mutability, b_type_)) => {
1618 mutability == b_mutability && type_.is_doc_subtype_of(b_type_, cache)
1619 }
1620 (
1621 Type::BorrowedRef { mutability, type_, .. },
1622 Type::BorrowedRef { mutability: b_mutability, type_: b_type_, .. },
1623 ) => mutability == b_mutability && type_.is_doc_subtype_of(b_type_, cache),
1624 (Type::Infer, _) | (_, Type::Infer) => true,
1626 (_, Type::Generic(_)) => true,
1629 (Type::Generic(_), _) => false,
1630 (Type::SelfTy, Type::SelfTy) => true,
1632 (Type::Path { path: a }, Type::Path { path: b }) => {
1634 a.def_id() == b.def_id()
1635 && a.generics()
1636 .zip(b.generics())
1637 .map(|(ag, bg)| ag.zip(bg).all(|(at, bt)| at.is_doc_subtype_of(bt, cache)))
1638 .unwrap_or(true)
1639 }
1640 (a, b) => a
1642 .def_id(cache)
1643 .and_then(|a| Some((a, b.def_id(cache)?)))
1644 .map(|(a, b)| a == b)
1645 .unwrap_or(false),
1646 }
1647 }
1648
1649 pub(crate) fn primitive_type(&self) -> Option<PrimitiveType> {
1650 match *self {
1651 Primitive(p) | BorrowedRef { type_: box Primitive(p), .. } => Some(p),
1652 Slice(..) | BorrowedRef { type_: box Slice(..), .. } => Some(PrimitiveType::Slice),
1653 Array(..) | BorrowedRef { type_: box Array(..), .. } => Some(PrimitiveType::Array),
1654 Tuple(ref tys) => {
1655 if tys.is_empty() {
1656 Some(PrimitiveType::Unit)
1657 } else {
1658 Some(PrimitiveType::Tuple)
1659 }
1660 }
1661 RawPointer(..) => Some(PrimitiveType::RawPointer),
1662 BareFunction(..) => Some(PrimitiveType::Fn),
1663 _ => None,
1664 }
1665 }
1666
1667 pub(crate) fn sugared_async_return_type(self) -> Type {
1677 if let Type::ImplTrait(mut v) = self
1678 && let Some(GenericBound::TraitBound(PolyTrait { mut trait_, .. }, _)) = v.pop()
1679 && let Some(segment) = trait_.segments.pop()
1680 && let GenericArgs::AngleBracketed { mut constraints, .. } = segment.args
1681 && let Some(constraint) = constraints.pop()
1682 && let AssocItemConstraintKind::Equality { term } = constraint.kind
1683 && let Term::Type(ty) = term
1684 {
1685 ty
1686 } else {
1687 panic!("unexpected async fn return type")
1688 }
1689 }
1690
1691 pub(crate) fn is_assoc_ty(&self) -> bool {
1693 match self {
1694 Type::Path { path, .. } => path.is_assoc_ty(),
1695 _ => false,
1696 }
1697 }
1698
1699 pub(crate) fn is_self_type(&self) -> bool {
1700 matches!(*self, Type::SelfTy)
1701 }
1702
1703 pub(crate) fn generic_args(&self) -> Option<&GenericArgs> {
1704 match self {
1705 Type::Path { path, .. } => path.generic_args(),
1706 _ => None,
1707 }
1708 }
1709
1710 pub(crate) fn generics<'a>(&'a self) -> Option<impl Iterator<Item = &'a Type>> {
1711 match self {
1712 Type::Path { path, .. } => path.generics(),
1713 _ => None,
1714 }
1715 }
1716
1717 pub(crate) fn is_full_generic(&self) -> bool {
1718 matches!(self, Type::Generic(_))
1719 }
1720
1721 pub(crate) fn is_unit(&self) -> bool {
1722 matches!(self, Type::Tuple(v) if v.is_empty())
1723 }
1724
1725 pub(crate) fn def_id(&self, cache: &Cache) -> Option<DefId> {
1729 let t: PrimitiveType = match self {
1730 Type::Path { path } => return Some(path.def_id()),
1731 DynTrait(bounds, _) => return bounds.first().map(|b| b.trait_.def_id()),
1732 Primitive(p) => return cache.primitive_locations.get(p).cloned(),
1733 BorrowedRef { type_: box Generic(..), .. } => PrimitiveType::Reference,
1734 BorrowedRef { type_, .. } => return type_.def_id(cache),
1735 Tuple(tys) => {
1736 if tys.is_empty() {
1737 PrimitiveType::Unit
1738 } else {
1739 PrimitiveType::Tuple
1740 }
1741 }
1742 BareFunction(..) => PrimitiveType::Fn,
1743 Slice(..) => PrimitiveType::Slice,
1744 Array(..) => PrimitiveType::Array,
1745 Type::Pat(..) => PrimitiveType::Pat,
1746 RawPointer(..) => PrimitiveType::RawPointer,
1747 QPath(box QPathData { self_type, .. }) => return self_type.def_id(cache),
1748 Generic(_) | SelfTy | Infer | ImplTrait(_) | UnsafeBinder(_) => return None,
1749 };
1750 Primitive(t).def_id(cache)
1751 }
1752}
1753
1754#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1755pub(crate) struct QPathData {
1756 pub assoc: PathSegment,
1757 pub self_type: Type,
1758 pub should_fully_qualify: bool,
1760 pub trait_: Option<Path>,
1761}
1762
1763#[derive(Clone, PartialEq, Eq, Hash, Copy, Debug)]
1770pub(crate) enum PrimitiveType {
1771 Isize,
1772 I8,
1773 I16,
1774 I32,
1775 I64,
1776 I128,
1777 Usize,
1778 U8,
1779 U16,
1780 U32,
1781 U64,
1782 U128,
1783 F16,
1784 F32,
1785 F64,
1786 F128,
1787 Char,
1788 Bool,
1789 Str,
1790 Slice,
1791 Array,
1792 Pat,
1793 Tuple,
1794 Unit,
1795 RawPointer,
1796 Reference,
1797 Fn,
1798 Never,
1799}
1800
1801type SimplifiedTypes = FxIndexMap<PrimitiveType, ArrayVec<SimplifiedType, 3>>;
1802impl PrimitiveType {
1803 pub(crate) fn from_hir(prim: hir::PrimTy) -> PrimitiveType {
1804 use ast::{FloatTy, IntTy, UintTy};
1805 match prim {
1806 hir::PrimTy::Int(IntTy::Isize) => PrimitiveType::Isize,
1807 hir::PrimTy::Int(IntTy::I8) => PrimitiveType::I8,
1808 hir::PrimTy::Int(IntTy::I16) => PrimitiveType::I16,
1809 hir::PrimTy::Int(IntTy::I32) => PrimitiveType::I32,
1810 hir::PrimTy::Int(IntTy::I64) => PrimitiveType::I64,
1811 hir::PrimTy::Int(IntTy::I128) => PrimitiveType::I128,
1812 hir::PrimTy::Uint(UintTy::Usize) => PrimitiveType::Usize,
1813 hir::PrimTy::Uint(UintTy::U8) => PrimitiveType::U8,
1814 hir::PrimTy::Uint(UintTy::U16) => PrimitiveType::U16,
1815 hir::PrimTy::Uint(UintTy::U32) => PrimitiveType::U32,
1816 hir::PrimTy::Uint(UintTy::U64) => PrimitiveType::U64,
1817 hir::PrimTy::Uint(UintTy::U128) => PrimitiveType::U128,
1818 hir::PrimTy::Float(FloatTy::F16) => PrimitiveType::F16,
1819 hir::PrimTy::Float(FloatTy::F32) => PrimitiveType::F32,
1820 hir::PrimTy::Float(FloatTy::F64) => PrimitiveType::F64,
1821 hir::PrimTy::Float(FloatTy::F128) => PrimitiveType::F128,
1822 hir::PrimTy::Str => PrimitiveType::Str,
1823 hir::PrimTy::Bool => PrimitiveType::Bool,
1824 hir::PrimTy::Char => PrimitiveType::Char,
1825 }
1826 }
1827
1828 pub(crate) fn from_symbol(s: Symbol) -> Option<PrimitiveType> {
1829 match s {
1830 sym::isize => Some(PrimitiveType::Isize),
1831 sym::i8 => Some(PrimitiveType::I8),
1832 sym::i16 => Some(PrimitiveType::I16),
1833 sym::i32 => Some(PrimitiveType::I32),
1834 sym::i64 => Some(PrimitiveType::I64),
1835 sym::i128 => Some(PrimitiveType::I128),
1836 sym::usize => Some(PrimitiveType::Usize),
1837 sym::u8 => Some(PrimitiveType::U8),
1838 sym::u16 => Some(PrimitiveType::U16),
1839 sym::u32 => Some(PrimitiveType::U32),
1840 sym::u64 => Some(PrimitiveType::U64),
1841 sym::u128 => Some(PrimitiveType::U128),
1842 sym::bool => Some(PrimitiveType::Bool),
1843 sym::char => Some(PrimitiveType::Char),
1844 sym::str => Some(PrimitiveType::Str),
1845 sym::f16 => Some(PrimitiveType::F16),
1846 sym::f32 => Some(PrimitiveType::F32),
1847 sym::f64 => Some(PrimitiveType::F64),
1848 sym::f128 => Some(PrimitiveType::F128),
1849 sym::array => Some(PrimitiveType::Array),
1850 sym::slice => Some(PrimitiveType::Slice),
1851 sym::tuple => Some(PrimitiveType::Tuple),
1852 sym::unit => Some(PrimitiveType::Unit),
1853 sym::pointer => Some(PrimitiveType::RawPointer),
1854 sym::reference => Some(PrimitiveType::Reference),
1855 kw::Fn => Some(PrimitiveType::Fn),
1856 sym::never => Some(PrimitiveType::Never),
1857 _ => None,
1858 }
1859 }
1860
1861 pub(crate) fn simplified_types() -> &'static SimplifiedTypes {
1862 use PrimitiveType::*;
1863 use ty::{FloatTy, IntTy, UintTy};
1864 static CELL: OnceCell<SimplifiedTypes> = OnceCell::new();
1865
1866 let single = |x| iter::once(x).collect();
1867 CELL.get_or_init(move || {
1868 map! {
1869 Isize => single(SimplifiedType::Int(IntTy::Isize)),
1870 I8 => single(SimplifiedType::Int(IntTy::I8)),
1871 I16 => single(SimplifiedType::Int(IntTy::I16)),
1872 I32 => single(SimplifiedType::Int(IntTy::I32)),
1873 I64 => single(SimplifiedType::Int(IntTy::I64)),
1874 I128 => single(SimplifiedType::Int(IntTy::I128)),
1875 Usize => single(SimplifiedType::Uint(UintTy::Usize)),
1876 U8 => single(SimplifiedType::Uint(UintTy::U8)),
1877 U16 => single(SimplifiedType::Uint(UintTy::U16)),
1878 U32 => single(SimplifiedType::Uint(UintTy::U32)),
1879 U64 => single(SimplifiedType::Uint(UintTy::U64)),
1880 U128 => single(SimplifiedType::Uint(UintTy::U128)),
1881 F16 => single(SimplifiedType::Float(FloatTy::F16)),
1882 F32 => single(SimplifiedType::Float(FloatTy::F32)),
1883 F64 => single(SimplifiedType::Float(FloatTy::F64)),
1884 F128 => single(SimplifiedType::Float(FloatTy::F128)),
1885 Str => single(SimplifiedType::Str),
1886 Bool => single(SimplifiedType::Bool),
1887 Char => single(SimplifiedType::Char),
1888 Array => single(SimplifiedType::Array),
1889 Slice => single(SimplifiedType::Slice),
1890 Tuple => [SimplifiedType::Tuple(1), SimplifiedType::Tuple(2), SimplifiedType::Tuple(3)].into(),
1896 Unit => single(SimplifiedType::Tuple(0)),
1897 RawPointer => [SimplifiedType::Ptr(Mutability::Not), SimplifiedType::Ptr(Mutability::Mut)].into_iter().collect(),
1898 Reference => [SimplifiedType::Ref(Mutability::Not), SimplifiedType::Ref(Mutability::Mut)].into_iter().collect(),
1899 Fn => single(SimplifiedType::Function(1)),
1902 Never => single(SimplifiedType::Never),
1903 }
1904 })
1905 }
1906
1907 pub(crate) fn impls<'tcx>(&self, tcx: TyCtxt<'tcx>) -> impl Iterator<Item = DefId> + 'tcx {
1908 Self::simplified_types()
1909 .get(self)
1910 .into_iter()
1911 .flatten()
1912 .flat_map(move |&simp| tcx.incoherent_impls(simp).iter())
1913 .copied()
1914 }
1915
1916 pub(crate) fn all_impls(tcx: TyCtxt<'_>) -> impl Iterator<Item = DefId> {
1917 Self::simplified_types()
1918 .values()
1919 .flatten()
1920 .flat_map(move |&simp| tcx.incoherent_impls(simp).iter())
1921 .copied()
1922 }
1923
1924 pub(crate) fn as_sym(&self) -> Symbol {
1925 use PrimitiveType::*;
1926 match self {
1927 Isize => sym::isize,
1928 I8 => sym::i8,
1929 I16 => sym::i16,
1930 I32 => sym::i32,
1931 I64 => sym::i64,
1932 I128 => sym::i128,
1933 Usize => sym::usize,
1934 U8 => sym::u8,
1935 U16 => sym::u16,
1936 U32 => sym::u32,
1937 U64 => sym::u64,
1938 U128 => sym::u128,
1939 F16 => sym::f16,
1940 F32 => sym::f32,
1941 F64 => sym::f64,
1942 F128 => sym::f128,
1943 Str => sym::str,
1944 Bool => sym::bool,
1945 Char => sym::char,
1946 Array => sym::array,
1947 Pat => sym::pat,
1948 Slice => sym::slice,
1949 Tuple => sym::tuple,
1950 Unit => sym::unit,
1951 RawPointer => sym::pointer,
1952 Reference => sym::reference,
1953 Fn => kw::Fn,
1954 Never => sym::never,
1955 }
1956 }
1957
1958 pub(crate) fn primitive_locations(tcx: TyCtxt<'_>) -> &FxIndexMap<PrimitiveType, DefId> {
1970 static PRIMITIVE_LOCATIONS: OnceCell<FxIndexMap<PrimitiveType, DefId>> = OnceCell::new();
1971 PRIMITIVE_LOCATIONS.get_or_init(|| {
1972 let mut primitive_locations = FxIndexMap::default();
1973 for &crate_num in tcx.crates(()) {
1976 let e = ExternalCrate { crate_num };
1977 let crate_name = e.name(tcx);
1978 debug!(?crate_num, ?crate_name);
1979 for (def_id, prim) in e.primitives(tcx) {
1980 if crate_name == sym::core && primitive_locations.contains_key(&prim) {
1982 continue;
1983 }
1984 primitive_locations.insert(prim, def_id);
1985 }
1986 }
1987 let local_primitives = ExternalCrate { crate_num: LOCAL_CRATE }.primitives(tcx);
1988 for (def_id, prim) in local_primitives {
1989 primitive_locations.insert(prim, def_id);
1990 }
1991 primitive_locations
1992 })
1993 }
1994}
1995
1996impl From<ast::IntTy> for PrimitiveType {
1997 fn from(int_ty: ast::IntTy) -> PrimitiveType {
1998 match int_ty {
1999 ast::IntTy::Isize => PrimitiveType::Isize,
2000 ast::IntTy::I8 => PrimitiveType::I8,
2001 ast::IntTy::I16 => PrimitiveType::I16,
2002 ast::IntTy::I32 => PrimitiveType::I32,
2003 ast::IntTy::I64 => PrimitiveType::I64,
2004 ast::IntTy::I128 => PrimitiveType::I128,
2005 }
2006 }
2007}
2008
2009impl From<ast::UintTy> for PrimitiveType {
2010 fn from(uint_ty: ast::UintTy) -> PrimitiveType {
2011 match uint_ty {
2012 ast::UintTy::Usize => PrimitiveType::Usize,
2013 ast::UintTy::U8 => PrimitiveType::U8,
2014 ast::UintTy::U16 => PrimitiveType::U16,
2015 ast::UintTy::U32 => PrimitiveType::U32,
2016 ast::UintTy::U64 => PrimitiveType::U64,
2017 ast::UintTy::U128 => PrimitiveType::U128,
2018 }
2019 }
2020}
2021
2022impl From<ast::FloatTy> for PrimitiveType {
2023 fn from(float_ty: ast::FloatTy) -> PrimitiveType {
2024 match float_ty {
2025 ast::FloatTy::F16 => PrimitiveType::F16,
2026 ast::FloatTy::F32 => PrimitiveType::F32,
2027 ast::FloatTy::F64 => PrimitiveType::F64,
2028 ast::FloatTy::F128 => PrimitiveType::F128,
2029 }
2030 }
2031}
2032
2033impl From<ty::IntTy> for PrimitiveType {
2034 fn from(int_ty: ty::IntTy) -> PrimitiveType {
2035 match int_ty {
2036 ty::IntTy::Isize => PrimitiveType::Isize,
2037 ty::IntTy::I8 => PrimitiveType::I8,
2038 ty::IntTy::I16 => PrimitiveType::I16,
2039 ty::IntTy::I32 => PrimitiveType::I32,
2040 ty::IntTy::I64 => PrimitiveType::I64,
2041 ty::IntTy::I128 => PrimitiveType::I128,
2042 }
2043 }
2044}
2045
2046impl From<ty::UintTy> for PrimitiveType {
2047 fn from(uint_ty: ty::UintTy) -> PrimitiveType {
2048 match uint_ty {
2049 ty::UintTy::Usize => PrimitiveType::Usize,
2050 ty::UintTy::U8 => PrimitiveType::U8,
2051 ty::UintTy::U16 => PrimitiveType::U16,
2052 ty::UintTy::U32 => PrimitiveType::U32,
2053 ty::UintTy::U64 => PrimitiveType::U64,
2054 ty::UintTy::U128 => PrimitiveType::U128,
2055 }
2056 }
2057}
2058
2059impl From<ty::FloatTy> for PrimitiveType {
2060 fn from(float_ty: ty::FloatTy) -> PrimitiveType {
2061 match float_ty {
2062 ty::FloatTy::F16 => PrimitiveType::F16,
2063 ty::FloatTy::F32 => PrimitiveType::F32,
2064 ty::FloatTy::F64 => PrimitiveType::F64,
2065 ty::FloatTy::F128 => PrimitiveType::F128,
2066 }
2067 }
2068}
2069
2070impl From<hir::PrimTy> for PrimitiveType {
2071 fn from(prim_ty: hir::PrimTy) -> PrimitiveType {
2072 match prim_ty {
2073 hir::PrimTy::Int(int_ty) => int_ty.into(),
2074 hir::PrimTy::Uint(uint_ty) => uint_ty.into(),
2075 hir::PrimTy::Float(float_ty) => float_ty.into(),
2076 hir::PrimTy::Str => PrimitiveType::Str,
2077 hir::PrimTy::Bool => PrimitiveType::Bool,
2078 hir::PrimTy::Char => PrimitiveType::Char,
2079 }
2080 }
2081}
2082
2083#[derive(Clone, Debug)]
2084pub(crate) struct Struct {
2085 pub(crate) ctor_kind: Option<CtorKind>,
2086 pub(crate) generics: Generics,
2087 pub(crate) fields: ThinVec<Item>,
2088}
2089
2090impl Struct {
2091 pub(crate) fn has_stripped_entries(&self) -> bool {
2092 self.fields.iter().any(|f| f.is_stripped())
2093 }
2094}
2095
2096#[derive(Clone, Debug)]
2097pub(crate) struct Union {
2098 pub(crate) generics: Generics,
2099 pub(crate) fields: Vec<Item>,
2100}
2101
2102impl Union {
2103 pub(crate) fn has_stripped_entries(&self) -> bool {
2104 self.fields.iter().any(|f| f.is_stripped())
2105 }
2106}
2107
2108#[derive(Clone, Debug)]
2112pub(crate) struct VariantStruct {
2113 pub(crate) fields: ThinVec<Item>,
2114}
2115
2116impl VariantStruct {
2117 pub(crate) fn has_stripped_entries(&self) -> bool {
2118 self.fields.iter().any(|f| f.is_stripped())
2119 }
2120}
2121
2122#[derive(Clone, Debug)]
2123pub(crate) struct Enum {
2124 pub(crate) variants: IndexVec<VariantIdx, Item>,
2125 pub(crate) generics: Generics,
2126}
2127
2128impl Enum {
2129 pub(crate) fn has_stripped_entries(&self) -> bool {
2130 self.variants.iter().any(|f| f.is_stripped())
2131 }
2132
2133 pub(crate) fn non_stripped_variants(&self) -> impl Iterator<Item = &Item> {
2134 self.variants.iter().filter(|v| !v.is_stripped())
2135 }
2136}
2137
2138#[derive(Clone, Debug)]
2139pub(crate) struct Variant {
2140 pub kind: VariantKind,
2141 pub discriminant: Option<Discriminant>,
2142}
2143
2144#[derive(Clone, Debug)]
2145pub(crate) enum VariantKind {
2146 CLike,
2147 Tuple(ThinVec<Item>),
2148 Struct(VariantStruct),
2149}
2150
2151impl Variant {
2152 pub(crate) fn has_stripped_entries(&self) -> Option<bool> {
2153 match &self.kind {
2154 VariantKind::Struct(struct_) => Some(struct_.has_stripped_entries()),
2155 VariantKind::CLike | VariantKind::Tuple(_) => None,
2156 }
2157 }
2158}
2159
2160#[derive(Clone, Debug)]
2161pub(crate) struct Discriminant {
2162 pub(super) expr: Option<BodyId>,
2165 pub(super) value: DefId,
2166}
2167
2168impl Discriminant {
2169 pub(crate) fn expr(&self, tcx: TyCtxt<'_>) -> Option<String> {
2172 self.expr
2173 .map(|body| rendered_const(tcx, tcx.hir_body(body), tcx.hir_body_owner_def_id(body)))
2174 }
2175 pub(crate) fn value(&self, tcx: TyCtxt<'_>, with_underscores: bool) -> String {
2176 print_evaluated_const(tcx, self.value, with_underscores, false).unwrap()
2177 }
2178}
2179
2180#[derive(Copy, Clone, Debug)]
2183pub(crate) struct Span(rustc_span::Span);
2184
2185impl Span {
2186 pub(crate) fn new(sp: rustc_span::Span) -> Self {
2191 Self(sp.source_callsite())
2192 }
2193
2194 pub(crate) fn inner(&self) -> rustc_span::Span {
2195 self.0
2196 }
2197
2198 pub(crate) fn filename(&self, sess: &Session) -> FileName {
2199 sess.source_map().span_to_filename(self.0)
2200 }
2201
2202 pub(crate) fn lo(&self, sess: &Session) -> Loc {
2203 sess.source_map().lookup_char_pos(self.0.lo())
2204 }
2205
2206 pub(crate) fn hi(&self, sess: &Session) -> Loc {
2207 sess.source_map().lookup_char_pos(self.0.hi())
2208 }
2209
2210 pub(crate) fn cnum(&self, sess: &Session) -> CrateNum {
2211 self.lo(sess).file.cnum
2213 }
2214}
2215
2216#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2217pub(crate) struct Path {
2218 pub(crate) res: Res,
2219 pub(crate) segments: ThinVec<PathSegment>,
2220}
2221
2222impl Path {
2223 pub(crate) fn def_id(&self) -> DefId {
2224 self.res.def_id()
2225 }
2226
2227 pub(crate) fn last_opt(&self) -> Option<Symbol> {
2228 self.segments.last().map(|s| s.name)
2229 }
2230
2231 pub(crate) fn last(&self) -> Symbol {
2232 self.last_opt().expect("segments were empty")
2233 }
2234
2235 pub(crate) fn whole_name(&self) -> String {
2236 self.segments
2237 .iter()
2238 .map(|s| if s.name == kw::PathRoot { "" } else { s.name.as_str() })
2239 .intersperse("::")
2240 .collect()
2241 }
2242
2243 pub(crate) fn is_assoc_ty(&self) -> bool {
2245 match self.res {
2246 Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } | Res::Def(DefKind::TyParam, _)
2247 if self.segments.len() != 1 =>
2248 {
2249 true
2250 }
2251 Res::Def(DefKind::AssocTy, _) => true,
2252 _ => false,
2253 }
2254 }
2255
2256 pub(crate) fn generic_args(&self) -> Option<&GenericArgs> {
2257 self.segments.last().map(|seg| &seg.args)
2258 }
2259
2260 pub(crate) fn generics<'a>(&'a self) -> Option<impl Iterator<Item = &'a Type>> {
2261 self.segments.last().and_then(|seg| {
2262 if let GenericArgs::AngleBracketed { ref args, .. } = seg.args {
2263 Some(args.iter().filter_map(|arg| match arg {
2264 GenericArg::Type(ty) => Some(ty),
2265 _ => None,
2266 }))
2267 } else {
2268 None
2269 }
2270 })
2271 }
2272}
2273
2274#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2275pub(crate) enum GenericArg {
2276 Lifetime(Lifetime),
2277 Type(Type),
2278 Const(Box<ConstantKind>),
2279 Infer,
2280}
2281
2282impl GenericArg {
2283 pub(crate) fn as_lt(&self) -> Option<&Lifetime> {
2284 if let Self::Lifetime(lt) = self { Some(lt) } else { None }
2285 }
2286
2287 pub(crate) fn as_ty(&self) -> Option<&Type> {
2288 if let Self::Type(ty) = self { Some(ty) } else { None }
2289 }
2290}
2291
2292#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2293pub(crate) enum GenericArgs {
2294 AngleBracketed { args: ThinVec<GenericArg>, constraints: ThinVec<AssocItemConstraint> },
2296 Parenthesized { inputs: ThinVec<Type>, output: Option<Box<Type>> },
2298 ReturnTypeNotation,
2300}
2301
2302impl GenericArgs {
2303 pub(crate) fn is_empty(&self) -> bool {
2304 match self {
2305 GenericArgs::AngleBracketed { args, constraints } => {
2306 args.is_empty() && constraints.is_empty()
2307 }
2308 GenericArgs::Parenthesized { inputs, output } => inputs.is_empty() && output.is_none(),
2309 GenericArgs::ReturnTypeNotation => false,
2310 }
2311 }
2312 pub(crate) fn constraints(&self) -> Box<dyn Iterator<Item = AssocItemConstraint> + '_> {
2313 match self {
2314 GenericArgs::AngleBracketed { constraints, .. } => {
2315 Box::new(constraints.iter().cloned())
2316 }
2317 GenericArgs::Parenthesized { output, .. } => Box::new(
2318 output
2319 .as_ref()
2320 .map(|ty| AssocItemConstraint {
2321 assoc: PathSegment {
2322 name: sym::Output,
2323 args: GenericArgs::AngleBracketed {
2324 args: ThinVec::new(),
2325 constraints: ThinVec::new(),
2326 },
2327 },
2328 kind: AssocItemConstraintKind::Equality {
2329 term: Term::Type((**ty).clone()),
2330 },
2331 })
2332 .into_iter(),
2333 ),
2334 GenericArgs::ReturnTypeNotation => Box::new([].into_iter()),
2335 }
2336 }
2337}
2338
2339impl<'a> IntoIterator for &'a GenericArgs {
2340 type IntoIter = Box<dyn Iterator<Item = GenericArg> + 'a>;
2341 type Item = GenericArg;
2342 fn into_iter(self) -> Self::IntoIter {
2343 match self {
2344 GenericArgs::AngleBracketed { args, .. } => Box::new(args.iter().cloned()),
2345 GenericArgs::Parenthesized { inputs, .. } => {
2346 Box::new(inputs.iter().cloned().map(GenericArg::Type))
2348 }
2349 GenericArgs::ReturnTypeNotation => Box::new([].into_iter()),
2350 }
2351 }
2352}
2353
2354#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2355pub(crate) struct PathSegment {
2356 pub(crate) name: Symbol,
2357 pub(crate) args: GenericArgs,
2358}
2359
2360#[derive(Clone, Debug)]
2361pub(crate) enum TypeAliasInnerType {
2362 Enum { variants: IndexVec<VariantIdx, Item>, is_non_exhaustive: bool },
2363 Union { fields: Vec<Item> },
2364 Struct { ctor_kind: Option<CtorKind>, fields: Vec<Item> },
2365}
2366
2367impl TypeAliasInnerType {
2368 fn has_stripped_entries(&self) -> Option<bool> {
2369 Some(match self {
2370 Self::Enum { variants, .. } => variants.iter().any(|v| v.is_stripped()),
2371 Self::Union { fields } | Self::Struct { fields, .. } => {
2372 fields.iter().any(|f| f.is_stripped())
2373 }
2374 })
2375 }
2376}
2377
2378#[derive(Clone, Debug)]
2379pub(crate) struct TypeAlias {
2380 pub(crate) type_: Type,
2381 pub(crate) generics: Generics,
2382 pub(crate) inner_type: Option<TypeAliasInnerType>,
2385 pub(crate) item_type: Option<Type>,
2392}
2393
2394#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2395pub(crate) struct BareFunctionDecl {
2396 pub(crate) safety: hir::Safety,
2397 pub(crate) generic_params: Vec<GenericParamDef>,
2398 pub(crate) decl: FnDecl,
2399 pub(crate) abi: ExternAbi,
2400}
2401
2402#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2403pub(crate) struct UnsafeBinderTy {
2404 pub(crate) generic_params: Vec<GenericParamDef>,
2405 pub(crate) ty: Type,
2406}
2407
2408#[derive(Clone, Debug)]
2409pub(crate) struct Static {
2410 pub(crate) type_: Box<Type>,
2411 pub(crate) mutability: Mutability,
2412 pub(crate) expr: Option<BodyId>,
2413}
2414
2415#[derive(Clone, PartialEq, Eq, Hash, Debug)]
2416pub(crate) struct Constant {
2417 pub(crate) generics: Generics,
2418 pub(crate) kind: ConstantKind,
2419 pub(crate) type_: Type,
2420}
2421
2422#[derive(Clone, PartialEq, Eq, Hash, Debug)]
2423pub(crate) enum Term {
2424 Type(Type),
2425 Constant(ConstantKind),
2426}
2427
2428impl Term {
2429 pub(crate) fn ty(&self) -> Option<&Type> {
2430 if let Term::Type(ty) = self { Some(ty) } else { None }
2431 }
2432}
2433
2434impl From<Type> for Term {
2435 fn from(ty: Type) -> Self {
2436 Term::Type(ty)
2437 }
2438}
2439
2440#[derive(Clone, PartialEq, Eq, Hash, Debug)]
2441pub(crate) enum ConstantKind {
2442 TyConst { expr: Box<str> },
2448 Path { path: Box<str> },
2451 Anonymous { body: BodyId },
2455 Extern { def_id: DefId },
2457 Local { def_id: DefId, body: BodyId },
2459 Infer,
2461}
2462
2463impl ConstantKind {
2464 pub(crate) fn expr(&self, tcx: TyCtxt<'_>) -> String {
2465 match *self {
2466 ConstantKind::TyConst { ref expr } => expr.to_string(),
2467 ConstantKind::Path { ref path } => path.to_string(),
2468 ConstantKind::Extern { def_id } => print_inlined_const(tcx, def_id),
2469 ConstantKind::Local { body, .. } | ConstantKind::Anonymous { body } => {
2470 rendered_const(tcx, tcx.hir_body(body), tcx.hir_body_owner_def_id(body))
2471 }
2472 ConstantKind::Infer => "_".to_string(),
2473 }
2474 }
2475
2476 pub(crate) fn value(&self, tcx: TyCtxt<'_>) -> Option<String> {
2477 match *self {
2478 ConstantKind::TyConst { .. }
2479 | ConstantKind::Path { .. }
2480 | ConstantKind::Anonymous { .. }
2481 | ConstantKind::Infer => None,
2482 ConstantKind::Extern { def_id } | ConstantKind::Local { def_id, .. } => {
2483 print_evaluated_const(tcx, def_id, true, true)
2484 }
2485 }
2486 }
2487
2488 pub(crate) fn is_literal(&self, tcx: TyCtxt<'_>) -> bool {
2489 match *self {
2490 ConstantKind::TyConst { .. }
2491 | ConstantKind::Extern { .. }
2492 | ConstantKind::Path { .. }
2493 | ConstantKind::Infer => false,
2494 ConstantKind::Local { body, .. } | ConstantKind::Anonymous { body } => {
2495 is_literal_expr(tcx, body.hir_id)
2496 }
2497 }
2498 }
2499}
2500
2501#[derive(Clone, Debug)]
2502pub(crate) struct Impl {
2503 pub(crate) safety: hir::Safety,
2504 pub(crate) generics: Generics,
2505 pub(crate) trait_: Option<Path>,
2506 pub(crate) for_: Type,
2507 pub(crate) items: Vec<Item>,
2508 pub(crate) polarity: ty::ImplPolarity,
2509 pub(crate) kind: ImplKind,
2510}
2511
2512impl Impl {
2513 pub(crate) fn provided_trait_methods(&self, tcx: TyCtxt<'_>) -> FxIndexSet<Symbol> {
2514 self.trait_
2515 .as_ref()
2516 .map(|t| t.def_id())
2517 .map(|did| tcx.provided_trait_methods(did).map(|meth| meth.name()).collect())
2518 .unwrap_or_default()
2519 }
2520
2521 pub(crate) fn is_negative_trait_impl(&self) -> bool {
2522 matches!(self.polarity, ty::ImplPolarity::Negative)
2523 }
2524}
2525
2526#[derive(Clone, Debug)]
2527pub(crate) enum ImplKind {
2528 Normal,
2529 Auto,
2530 FakeVariadic,
2531 Blanket(Box<Type>),
2532}
2533
2534impl ImplKind {
2535 pub(crate) fn is_auto(&self) -> bool {
2536 matches!(self, ImplKind::Auto)
2537 }
2538
2539 pub(crate) fn is_blanket(&self) -> bool {
2540 matches!(self, ImplKind::Blanket(_))
2541 }
2542
2543 pub(crate) fn is_fake_variadic(&self) -> bool {
2544 matches!(self, ImplKind::FakeVariadic)
2545 }
2546
2547 pub(crate) fn as_blanket_ty(&self) -> Option<&Type> {
2548 match self {
2549 ImplKind::Blanket(ty) => Some(ty),
2550 _ => None,
2551 }
2552 }
2553}
2554
2555#[derive(Clone, Debug)]
2556pub(crate) struct Import {
2557 pub(crate) kind: ImportKind,
2558 pub(crate) source: ImportSource,
2560 pub(crate) should_be_displayed: bool,
2561}
2562
2563impl Import {
2564 pub(crate) fn new_simple(
2565 name: Symbol,
2566 source: ImportSource,
2567 should_be_displayed: bool,
2568 ) -> Self {
2569 Self { kind: ImportKind::Simple(name), source, should_be_displayed }
2570 }
2571
2572 pub(crate) fn new_glob(source: ImportSource, should_be_displayed: bool) -> Self {
2573 Self { kind: ImportKind::Glob, source, should_be_displayed }
2574 }
2575
2576 pub(crate) fn imported_item_is_doc_hidden(&self, tcx: TyCtxt<'_>) -> bool {
2577 self.source.did.is_some_and(|did| tcx.is_doc_hidden(did))
2578 }
2579}
2580
2581#[derive(Clone, Debug)]
2582pub(crate) enum ImportKind {
2583 Simple(Symbol),
2585 Glob,
2587}
2588
2589#[derive(Clone, Debug)]
2590pub(crate) struct ImportSource {
2591 pub(crate) path: Path,
2592 pub(crate) did: Option<DefId>,
2593}
2594
2595#[derive(Clone, Debug)]
2596pub(crate) struct Macro {
2597 pub(crate) source: String,
2598 pub(crate) macro_rules: bool,
2600}
2601
2602#[derive(Clone, Debug)]
2603pub(crate) struct ProcMacro {
2604 pub(crate) kind: MacroKind,
2605 pub(crate) helpers: Vec<Symbol>,
2606}
2607
2608#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2619pub(crate) struct AssocItemConstraint {
2620 pub(crate) assoc: PathSegment,
2621 pub(crate) kind: AssocItemConstraintKind,
2622}
2623
2624#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2626pub(crate) enum AssocItemConstraintKind {
2627 Equality { term: Term },
2628 Bound { bounds: Vec<GenericBound> },
2629}
2630
2631#[cfg(target_pointer_width = "64")]
2633mod size_asserts {
2634 use rustc_data_structures::static_assert_size;
2635
2636 use super::*;
2637 static_assert_size!(Crate, 16); static_assert_size!(DocFragment, 32);
2640 static_assert_size!(GenericArg, 32);
2641 static_assert_size!(GenericArgs, 24);
2642 static_assert_size!(GenericParamDef, 40);
2643 static_assert_size!(Generics, 16);
2644 static_assert_size!(Item, 8);
2645 static_assert_size!(ItemInner, 144);
2646 static_assert_size!(ItemKind, 48);
2647 static_assert_size!(PathSegment, 32);
2648 static_assert_size!(Type, 32);
2649 }