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