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) = find_attr!(attrs, AttributeKind::TargetFeature(features, _) => features)
1091 {
1092 for (feature, _) in features {
1093 cfg &= Cfg::Cfg(sym::target_feature, Some(*feature));
1094 }
1095 }
1096
1097 if cfg == Cfg::True { None } else { Some(Arc::new(cfg)) }
1098}
1099
1100pub(crate) trait NestedAttributesExt {
1101 fn has_word(self, word: Symbol) -> bool
1103 where
1104 Self: Sized,
1105 {
1106 <Self as NestedAttributesExt>::get_word_attr(self, word).is_some()
1107 }
1108
1109 fn get_word_attr(self, word: Symbol) -> Option<ast::MetaItemInner>;
1112}
1113
1114impl<I: Iterator<Item = ast::MetaItemInner>> NestedAttributesExt for I {
1115 fn get_word_attr(mut self, word: Symbol) -> Option<ast::MetaItemInner> {
1116 self.find(|attr| attr.is_word() && attr.has_name(word))
1117 }
1118}
1119
1120#[derive(Clone, Debug, PartialEq, Eq, Hash)]
1124pub(crate) struct ItemLink {
1125 pub(crate) link: Box<str>,
1127 pub(crate) link_text: Box<str>,
1132 pub(crate) page_id: DefId,
1136 pub(crate) fragment: Option<UrlFragment>,
1138}
1139
1140pub struct RenderedLink {
1141 pub(crate) original_text: Box<str>,
1145 pub(crate) new_text: Box<str>,
1147 pub(crate) href: String,
1149 pub(crate) tooltip: String,
1151}
1152
1153#[derive(Clone, Debug, Default)]
1156pub(crate) struct Attributes {
1157 pub(crate) doc_strings: Vec<DocFragment>,
1158 pub(crate) other_attrs: ThinVec<hir::Attribute>,
1159}
1160
1161impl Attributes {
1162 pub(crate) fn lists(&self, name: Symbol) -> impl Iterator<Item = ast::MetaItemInner> {
1163 hir_attr_lists(&self.other_attrs[..], name)
1164 }
1165
1166 pub(crate) fn has_doc_flag(&self, flag: Symbol) -> bool {
1167 for attr in &self.other_attrs {
1168 if !attr.has_name(sym::doc) {
1169 continue;
1170 }
1171
1172 if let Some(items) = attr.meta_item_list()
1173 && items.iter().filter_map(|i| i.meta_item()).any(|it| it.has_name(flag))
1174 {
1175 return true;
1176 }
1177 }
1178
1179 false
1180 }
1181
1182 pub(crate) fn is_doc_hidden(&self) -> bool {
1183 self.has_doc_flag(sym::hidden)
1184 }
1185
1186 pub(crate) fn from_hir(attrs: &[hir::Attribute]) -> Attributes {
1187 Attributes::from_hir_iter(attrs.iter().map(|attr| (attr, None)), false)
1188 }
1189
1190 pub(crate) fn from_hir_with_additional(
1191 attrs: &[hir::Attribute],
1192 (additional_attrs, def_id): (&[hir::Attribute], DefId),
1193 ) -> Attributes {
1194 let attrs1 = additional_attrs.iter().map(|attr| (attr, Some(def_id)));
1196 let attrs2 = attrs.iter().map(|attr| (attr, None));
1197 Attributes::from_hir_iter(attrs1.chain(attrs2), false)
1198 }
1199
1200 pub(crate) fn from_hir_iter<'a>(
1201 attrs: impl Iterator<Item = (&'a hir::Attribute, Option<DefId>)>,
1202 doc_only: bool,
1203 ) -> Attributes {
1204 let (doc_strings, other_attrs) = attrs_to_doc_fragments(attrs, doc_only);
1205 Attributes { doc_strings, other_attrs }
1206 }
1207
1208 pub(crate) fn doc_value(&self) -> String {
1210 self.opt_doc_value().unwrap_or_default()
1211 }
1212
1213 pub(crate) fn opt_doc_value(&self) -> Option<String> {
1217 (!self.doc_strings.is_empty()).then(|| {
1218 let mut res = String::new();
1219 for frag in &self.doc_strings {
1220 add_doc_fragment(&mut res, frag);
1221 }
1222 res.pop();
1223 res
1224 })
1225 }
1226
1227 pub(crate) fn get_doc_aliases(&self) -> Box<[Symbol]> {
1228 let mut aliases = FxIndexSet::default();
1229
1230 for attr in
1231 hir_attr_lists(&self.other_attrs[..], sym::doc).filter(|a| a.has_name(sym::alias))
1232 {
1233 if let Some(values) = attr.meta_item_list() {
1234 for l in values {
1235 if let Some(lit) = l.lit()
1236 && let ast::LitKind::Str(s, _) = lit.kind
1237 {
1238 aliases.insert(s);
1239 }
1240 }
1241 } else if let Some(value) = attr.value_str() {
1242 aliases.insert(value);
1243 }
1244 }
1245 aliases.into_iter().collect::<Vec<_>>().into()
1246 }
1247}
1248
1249#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1250pub(crate) enum GenericBound {
1251 TraitBound(PolyTrait, hir::TraitBoundModifiers),
1252 Outlives(Lifetime),
1253 Use(Vec<PreciseCapturingArg>),
1255}
1256
1257impl GenericBound {
1258 pub(crate) fn sized(cx: &mut DocContext<'_>) -> GenericBound {
1259 Self::sized_with(cx, hir::TraitBoundModifiers::NONE)
1260 }
1261
1262 pub(crate) fn maybe_sized(cx: &mut DocContext<'_>) -> GenericBound {
1263 Self::sized_with(
1264 cx,
1265 hir::TraitBoundModifiers {
1266 polarity: hir::BoundPolarity::Maybe(DUMMY_SP),
1267 constness: hir::BoundConstness::Never,
1268 },
1269 )
1270 }
1271
1272 fn sized_with(cx: &mut DocContext<'_>, modifiers: hir::TraitBoundModifiers) -> GenericBound {
1273 let did = cx.tcx.require_lang_item(LangItem::Sized, DUMMY_SP);
1274 let empty = ty::Binder::dummy(ty::GenericArgs::empty());
1275 let path = clean_middle_path(cx, did, false, ThinVec::new(), empty);
1276 inline::record_extern_fqn(cx, did, ItemType::Trait);
1277 GenericBound::TraitBound(PolyTrait { trait_: path, generic_params: Vec::new() }, modifiers)
1278 }
1279
1280 pub(crate) fn is_trait_bound(&self) -> bool {
1281 matches!(self, Self::TraitBound(..))
1282 }
1283
1284 pub(crate) fn is_sized_bound(&self, cx: &DocContext<'_>) -> bool {
1285 self.is_bounded_by_lang_item(cx, LangItem::Sized)
1286 }
1287
1288 pub(crate) fn is_meta_sized_bound(&self, cx: &DocContext<'_>) -> bool {
1289 self.is_bounded_by_lang_item(cx, LangItem::MetaSized)
1290 }
1291
1292 fn is_bounded_by_lang_item(&self, cx: &DocContext<'_>, lang_item: LangItem) -> bool {
1293 if let GenericBound::TraitBound(
1294 PolyTrait { ref trait_, .. },
1295 rustc_hir::TraitBoundModifiers::NONE,
1296 ) = *self
1297 && cx.tcx.is_lang_item(trait_.def_id(), lang_item)
1298 {
1299 return true;
1300 }
1301 false
1302 }
1303
1304 pub(crate) fn get_trait_path(&self) -> Option<Path> {
1305 if let GenericBound::TraitBound(PolyTrait { ref trait_, .. }, _) = *self {
1306 Some(trait_.clone())
1307 } else {
1308 None
1309 }
1310 }
1311}
1312
1313#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
1314pub(crate) struct Lifetime(pub Symbol);
1315
1316impl Lifetime {
1317 pub(crate) fn statik() -> Lifetime {
1318 Lifetime(kw::StaticLifetime)
1319 }
1320
1321 pub(crate) fn elided() -> Lifetime {
1322 Lifetime(kw::UnderscoreLifetime)
1323 }
1324}
1325
1326#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
1327pub(crate) enum PreciseCapturingArg {
1328 Lifetime(Lifetime),
1329 Param(Symbol),
1330}
1331
1332impl PreciseCapturingArg {
1333 pub(crate) fn name(self) -> Symbol {
1334 match self {
1335 PreciseCapturingArg::Lifetime(lt) => lt.0,
1336 PreciseCapturingArg::Param(param) => param,
1337 }
1338 }
1339}
1340
1341#[derive(Clone, PartialEq, Eq, Hash, Debug)]
1342pub(crate) enum WherePredicate {
1343 BoundPredicate { ty: Type, bounds: Vec<GenericBound>, bound_params: Vec<GenericParamDef> },
1344 RegionPredicate { lifetime: Lifetime, bounds: Vec<GenericBound> },
1345 EqPredicate { lhs: QPathData, rhs: Term },
1346}
1347
1348impl WherePredicate {
1349 pub(crate) fn get_bounds(&self) -> Option<&[GenericBound]> {
1350 match self {
1351 WherePredicate::BoundPredicate { bounds, .. } => Some(bounds),
1352 WherePredicate::RegionPredicate { bounds, .. } => Some(bounds),
1353 _ => None,
1354 }
1355 }
1356}
1357
1358#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1359pub(crate) enum GenericParamDefKind {
1360 Lifetime { outlives: ThinVec<Lifetime> },
1361 Type { bounds: ThinVec<GenericBound>, default: Option<Box<Type>>, synthetic: bool },
1362 Const { ty: Box<Type>, default: Option<Box<String>>, synthetic: bool },
1364}
1365
1366impl GenericParamDefKind {
1367 pub(crate) fn is_type(&self) -> bool {
1368 matches!(self, GenericParamDefKind::Type { .. })
1369 }
1370}
1371
1372#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1373pub(crate) struct GenericParamDef {
1374 pub(crate) name: Symbol,
1375 pub(crate) def_id: DefId,
1376 pub(crate) kind: GenericParamDefKind,
1377}
1378
1379impl GenericParamDef {
1380 pub(crate) fn lifetime(def_id: DefId, name: Symbol) -> Self {
1381 Self { name, def_id, kind: GenericParamDefKind::Lifetime { outlives: ThinVec::new() } }
1382 }
1383
1384 pub(crate) fn is_synthetic_param(&self) -> bool {
1385 match self.kind {
1386 GenericParamDefKind::Lifetime { .. } | GenericParamDefKind::Const { .. } => false,
1387 GenericParamDefKind::Type { synthetic, .. } => synthetic,
1388 }
1389 }
1390
1391 pub(crate) fn is_type(&self) -> bool {
1392 self.kind.is_type()
1393 }
1394
1395 pub(crate) fn get_bounds(&self) -> Option<&[GenericBound]> {
1396 match self.kind {
1397 GenericParamDefKind::Type { ref bounds, .. } => Some(bounds),
1398 _ => None,
1399 }
1400 }
1401}
1402
1403#[derive(Clone, PartialEq, Eq, Hash, Debug, Default)]
1405pub(crate) struct Generics {
1406 pub(crate) params: ThinVec<GenericParamDef>,
1407 pub(crate) where_predicates: ThinVec<WherePredicate>,
1408}
1409
1410impl Generics {
1411 pub(crate) fn is_empty(&self) -> bool {
1412 self.params.is_empty() && self.where_predicates.is_empty()
1413 }
1414}
1415
1416#[derive(Clone, Debug)]
1417pub(crate) struct Function {
1418 pub(crate) decl: FnDecl,
1419 pub(crate) generics: Generics,
1420}
1421
1422#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1423pub(crate) struct FnDecl {
1424 pub(crate) inputs: Vec<Parameter>,
1425 pub(crate) output: Type,
1426 pub(crate) c_variadic: bool,
1427}
1428
1429impl FnDecl {
1430 pub(crate) fn receiver_type(&self) -> Option<&Type> {
1431 self.inputs.first().and_then(|v| v.to_receiver())
1432 }
1433}
1434
1435#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1437pub(crate) struct Parameter {
1438 pub(crate) name: Option<Symbol>,
1439 pub(crate) type_: Type,
1440 pub(crate) is_const: bool,
1443}
1444
1445impl Parameter {
1446 pub(crate) fn to_receiver(&self) -> Option<&Type> {
1447 if self.name == Some(kw::SelfLower) { Some(&self.type_) } else { None }
1448 }
1449}
1450
1451#[derive(Clone, Debug)]
1452pub(crate) struct Trait {
1453 pub(crate) def_id: DefId,
1454 pub(crate) items: Vec<Item>,
1455 pub(crate) generics: Generics,
1456 pub(crate) bounds: Vec<GenericBound>,
1457}
1458
1459impl Trait {
1460 pub(crate) fn is_auto(&self, tcx: TyCtxt<'_>) -> bool {
1461 tcx.trait_is_auto(self.def_id)
1462 }
1463 pub(crate) fn is_notable_trait(&self, tcx: TyCtxt<'_>) -> bool {
1464 tcx.is_doc_notable_trait(self.def_id)
1465 }
1466 pub(crate) fn safety(&self, tcx: TyCtxt<'_>) -> hir::Safety {
1467 tcx.trait_def(self.def_id).safety
1468 }
1469 pub(crate) fn is_dyn_compatible(&self, tcx: TyCtxt<'_>) -> bool {
1470 tcx.is_dyn_compatible(self.def_id)
1471 }
1472}
1473
1474#[derive(Clone, Debug)]
1475pub(crate) struct TraitAlias {
1476 pub(crate) generics: Generics,
1477 pub(crate) bounds: Vec<GenericBound>,
1478}
1479
1480#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1482pub(crate) struct PolyTrait {
1483 pub(crate) trait_: Path,
1484 pub(crate) generic_params: Vec<GenericParamDef>,
1485}
1486
1487#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1489pub(crate) enum Type {
1490 Path {
1495 path: Path,
1496 },
1497 DynTrait(Vec<PolyTrait>, Option<Lifetime>),
1499 Generic(Symbol),
1501 SelfTy,
1503 Primitive(PrimitiveType),
1505 BareFunction(Box<BareFunctionDecl>),
1507 Tuple(Vec<Type>),
1509 Slice(Box<Type>),
1511 Array(Box<Type>, Box<str>),
1515 Pat(Box<Type>, Box<str>),
1516 RawPointer(Mutability, Box<Type>),
1518 BorrowedRef {
1520 lifetime: Option<Lifetime>,
1521 mutability: Mutability,
1522 type_: Box<Type>,
1523 },
1524
1525 QPath(Box<QPathData>),
1527
1528 Infer,
1530
1531 ImplTrait(Vec<GenericBound>),
1533
1534 UnsafeBinder(Box<UnsafeBinderTy>),
1535}
1536
1537impl Type {
1538 pub(crate) fn without_borrowed_ref(&self) -> &Type {
1540 let mut result = self;
1541 while let Type::BorrowedRef { type_, .. } = result {
1542 result = type_;
1543 }
1544 result
1545 }
1546
1547 pub(crate) fn is_borrowed_ref(&self) -> bool {
1548 matches!(self, Type::BorrowedRef { .. })
1549 }
1550
1551 fn is_type_alias(&self) -> bool {
1552 matches!(self, Type::Path { path: Path { res: Res::Def(DefKind::TyAlias, _), .. } })
1553 }
1554
1555 pub(crate) fn is_doc_subtype_of(&self, other: &Self, cache: &Cache) -> bool {
1576 let (self_cleared, other_cleared) = if !self.is_borrowed_ref() || !other.is_borrowed_ref() {
1579 (self.without_borrowed_ref(), other.without_borrowed_ref())
1580 } else {
1581 (self, other)
1582 };
1583
1584 if self_cleared.is_type_alias() || other_cleared.is_type_alias() {
1590 return true;
1591 }
1592
1593 match (self_cleared, other_cleared) {
1594 (Type::Tuple(a), Type::Tuple(b)) => {
1596 a.len() == b.len() && a.iter().zip(b).all(|(a, b)| a.is_doc_subtype_of(b, cache))
1597 }
1598 (Type::Slice(a), Type::Slice(b)) => a.is_doc_subtype_of(b, cache),
1599 (Type::Array(a, al), Type::Array(b, bl)) => al == bl && a.is_doc_subtype_of(b, cache),
1600 (Type::RawPointer(mutability, type_), Type::RawPointer(b_mutability, b_type_)) => {
1601 mutability == b_mutability && type_.is_doc_subtype_of(b_type_, cache)
1602 }
1603 (
1604 Type::BorrowedRef { mutability, type_, .. },
1605 Type::BorrowedRef { mutability: b_mutability, type_: b_type_, .. },
1606 ) => mutability == b_mutability && type_.is_doc_subtype_of(b_type_, cache),
1607 (Type::Infer, _) | (_, Type::Infer) => true,
1609 (_, Type::Generic(_)) => true,
1612 (Type::Generic(_), _) => false,
1613 (Type::SelfTy, Type::SelfTy) => true,
1615 (Type::Path { path: a }, Type::Path { path: b }) => {
1617 a.def_id() == b.def_id()
1618 && a.generics()
1619 .zip(b.generics())
1620 .map(|(ag, bg)| ag.zip(bg).all(|(at, bt)| at.is_doc_subtype_of(bt, cache)))
1621 .unwrap_or(true)
1622 }
1623 (a, b) => a
1625 .def_id(cache)
1626 .and_then(|a| Some((a, b.def_id(cache)?)))
1627 .map(|(a, b)| a == b)
1628 .unwrap_or(false),
1629 }
1630 }
1631
1632 pub(crate) fn primitive_type(&self) -> Option<PrimitiveType> {
1633 match *self {
1634 Primitive(p) | BorrowedRef { type_: box Primitive(p), .. } => Some(p),
1635 Slice(..) | BorrowedRef { type_: box Slice(..), .. } => Some(PrimitiveType::Slice),
1636 Array(..) | BorrowedRef { type_: box Array(..), .. } => Some(PrimitiveType::Array),
1637 Tuple(ref tys) => {
1638 if tys.is_empty() {
1639 Some(PrimitiveType::Unit)
1640 } else {
1641 Some(PrimitiveType::Tuple)
1642 }
1643 }
1644 RawPointer(..) => Some(PrimitiveType::RawPointer),
1645 BareFunction(..) => Some(PrimitiveType::Fn),
1646 _ => None,
1647 }
1648 }
1649
1650 pub(crate) fn sugared_async_return_type(self) -> Type {
1660 if let Type::ImplTrait(mut v) = self
1661 && let Some(GenericBound::TraitBound(PolyTrait { mut trait_, .. }, _)) = v.pop()
1662 && let Some(segment) = trait_.segments.pop()
1663 && let GenericArgs::AngleBracketed { mut constraints, .. } = segment.args
1664 && let Some(constraint) = constraints.pop()
1665 && let AssocItemConstraintKind::Equality { term } = constraint.kind
1666 && let Term::Type(ty) = term
1667 {
1668 ty
1669 } else {
1670 panic!("unexpected async fn return type")
1671 }
1672 }
1673
1674 pub(crate) fn is_assoc_ty(&self) -> bool {
1676 match self {
1677 Type::Path { path, .. } => path.is_assoc_ty(),
1678 _ => false,
1679 }
1680 }
1681
1682 pub(crate) fn is_self_type(&self) -> bool {
1683 matches!(*self, Type::SelfTy)
1684 }
1685
1686 pub(crate) fn generic_args(&self) -> Option<&GenericArgs> {
1687 match self {
1688 Type::Path { path, .. } => path.generic_args(),
1689 _ => None,
1690 }
1691 }
1692
1693 pub(crate) fn generics(&self) -> Option<impl Iterator<Item = &Type>> {
1694 match self {
1695 Type::Path { path, .. } => path.generics(),
1696 _ => None,
1697 }
1698 }
1699
1700 pub(crate) fn is_full_generic(&self) -> bool {
1701 matches!(self, Type::Generic(_))
1702 }
1703
1704 pub(crate) fn is_unit(&self) -> bool {
1705 matches!(self, Type::Tuple(v) if v.is_empty())
1706 }
1707
1708 pub(crate) fn def_id(&self, cache: &Cache) -> Option<DefId> {
1712 let t: PrimitiveType = match self {
1713 Type::Path { path } => return Some(path.def_id()),
1714 DynTrait(bounds, _) => return bounds.first().map(|b| b.trait_.def_id()),
1715 Primitive(p) => return cache.primitive_locations.get(p).cloned(),
1716 BorrowedRef { type_: box Generic(..), .. } => PrimitiveType::Reference,
1717 BorrowedRef { type_, .. } => return type_.def_id(cache),
1718 Tuple(tys) => {
1719 if tys.is_empty() {
1720 PrimitiveType::Unit
1721 } else {
1722 PrimitiveType::Tuple
1723 }
1724 }
1725 BareFunction(..) => PrimitiveType::Fn,
1726 Slice(..) => PrimitiveType::Slice,
1727 Array(..) => PrimitiveType::Array,
1728 Type::Pat(..) => PrimitiveType::Pat,
1729 RawPointer(..) => PrimitiveType::RawPointer,
1730 QPath(box QPathData { self_type, .. }) => return self_type.def_id(cache),
1731 Generic(_) | SelfTy | Infer | ImplTrait(_) | UnsafeBinder(_) => return None,
1732 };
1733 Primitive(t).def_id(cache)
1734 }
1735}
1736
1737#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1738pub(crate) struct QPathData {
1739 pub assoc: PathSegment,
1740 pub self_type: Type,
1741 pub should_fully_qualify: bool,
1743 pub trait_: Option<Path>,
1744}
1745
1746#[derive(Clone, PartialEq, Eq, Hash, Copy, Debug)]
1753pub(crate) enum PrimitiveType {
1754 Isize,
1755 I8,
1756 I16,
1757 I32,
1758 I64,
1759 I128,
1760 Usize,
1761 U8,
1762 U16,
1763 U32,
1764 U64,
1765 U128,
1766 F16,
1767 F32,
1768 F64,
1769 F128,
1770 Char,
1771 Bool,
1772 Str,
1773 Slice,
1774 Array,
1775 Pat,
1776 Tuple,
1777 Unit,
1778 RawPointer,
1779 Reference,
1780 Fn,
1781 Never,
1782}
1783
1784type SimplifiedTypes = FxIndexMap<PrimitiveType, ArrayVec<SimplifiedType, 3>>;
1785impl PrimitiveType {
1786 pub(crate) fn from_hir(prim: hir::PrimTy) -> PrimitiveType {
1787 use ast::{FloatTy, IntTy, UintTy};
1788 match prim {
1789 hir::PrimTy::Int(IntTy::Isize) => PrimitiveType::Isize,
1790 hir::PrimTy::Int(IntTy::I8) => PrimitiveType::I8,
1791 hir::PrimTy::Int(IntTy::I16) => PrimitiveType::I16,
1792 hir::PrimTy::Int(IntTy::I32) => PrimitiveType::I32,
1793 hir::PrimTy::Int(IntTy::I64) => PrimitiveType::I64,
1794 hir::PrimTy::Int(IntTy::I128) => PrimitiveType::I128,
1795 hir::PrimTy::Uint(UintTy::Usize) => PrimitiveType::Usize,
1796 hir::PrimTy::Uint(UintTy::U8) => PrimitiveType::U8,
1797 hir::PrimTy::Uint(UintTy::U16) => PrimitiveType::U16,
1798 hir::PrimTy::Uint(UintTy::U32) => PrimitiveType::U32,
1799 hir::PrimTy::Uint(UintTy::U64) => PrimitiveType::U64,
1800 hir::PrimTy::Uint(UintTy::U128) => PrimitiveType::U128,
1801 hir::PrimTy::Float(FloatTy::F16) => PrimitiveType::F16,
1802 hir::PrimTy::Float(FloatTy::F32) => PrimitiveType::F32,
1803 hir::PrimTy::Float(FloatTy::F64) => PrimitiveType::F64,
1804 hir::PrimTy::Float(FloatTy::F128) => PrimitiveType::F128,
1805 hir::PrimTy::Str => PrimitiveType::Str,
1806 hir::PrimTy::Bool => PrimitiveType::Bool,
1807 hir::PrimTy::Char => PrimitiveType::Char,
1808 }
1809 }
1810
1811 pub(crate) fn from_symbol(s: Symbol) -> Option<PrimitiveType> {
1812 match s {
1813 sym::isize => Some(PrimitiveType::Isize),
1814 sym::i8 => Some(PrimitiveType::I8),
1815 sym::i16 => Some(PrimitiveType::I16),
1816 sym::i32 => Some(PrimitiveType::I32),
1817 sym::i64 => Some(PrimitiveType::I64),
1818 sym::i128 => Some(PrimitiveType::I128),
1819 sym::usize => Some(PrimitiveType::Usize),
1820 sym::u8 => Some(PrimitiveType::U8),
1821 sym::u16 => Some(PrimitiveType::U16),
1822 sym::u32 => Some(PrimitiveType::U32),
1823 sym::u64 => Some(PrimitiveType::U64),
1824 sym::u128 => Some(PrimitiveType::U128),
1825 sym::bool => Some(PrimitiveType::Bool),
1826 sym::char => Some(PrimitiveType::Char),
1827 sym::str => Some(PrimitiveType::Str),
1828 sym::f16 => Some(PrimitiveType::F16),
1829 sym::f32 => Some(PrimitiveType::F32),
1830 sym::f64 => Some(PrimitiveType::F64),
1831 sym::f128 => Some(PrimitiveType::F128),
1832 sym::array => Some(PrimitiveType::Array),
1833 sym::slice => Some(PrimitiveType::Slice),
1834 sym::tuple => Some(PrimitiveType::Tuple),
1835 sym::unit => Some(PrimitiveType::Unit),
1836 sym::pointer => Some(PrimitiveType::RawPointer),
1837 sym::reference => Some(PrimitiveType::Reference),
1838 kw::Fn => Some(PrimitiveType::Fn),
1839 sym::never => Some(PrimitiveType::Never),
1840 _ => None,
1841 }
1842 }
1843
1844 pub(crate) fn simplified_types() -> &'static SimplifiedTypes {
1845 use PrimitiveType::*;
1846 use ty::{FloatTy, IntTy, UintTy};
1847 static CELL: OnceCell<SimplifiedTypes> = OnceCell::new();
1848
1849 let single = |x| iter::once(x).collect();
1850 CELL.get_or_init(move || {
1851 map! {
1852 Isize => single(SimplifiedType::Int(IntTy::Isize)),
1853 I8 => single(SimplifiedType::Int(IntTy::I8)),
1854 I16 => single(SimplifiedType::Int(IntTy::I16)),
1855 I32 => single(SimplifiedType::Int(IntTy::I32)),
1856 I64 => single(SimplifiedType::Int(IntTy::I64)),
1857 I128 => single(SimplifiedType::Int(IntTy::I128)),
1858 Usize => single(SimplifiedType::Uint(UintTy::Usize)),
1859 U8 => single(SimplifiedType::Uint(UintTy::U8)),
1860 U16 => single(SimplifiedType::Uint(UintTy::U16)),
1861 U32 => single(SimplifiedType::Uint(UintTy::U32)),
1862 U64 => single(SimplifiedType::Uint(UintTy::U64)),
1863 U128 => single(SimplifiedType::Uint(UintTy::U128)),
1864 F16 => single(SimplifiedType::Float(FloatTy::F16)),
1865 F32 => single(SimplifiedType::Float(FloatTy::F32)),
1866 F64 => single(SimplifiedType::Float(FloatTy::F64)),
1867 F128 => single(SimplifiedType::Float(FloatTy::F128)),
1868 Str => single(SimplifiedType::Str),
1869 Bool => single(SimplifiedType::Bool),
1870 Char => single(SimplifiedType::Char),
1871 Array => single(SimplifiedType::Array),
1872 Slice => single(SimplifiedType::Slice),
1873 Tuple => [SimplifiedType::Tuple(1), SimplifiedType::Tuple(2), SimplifiedType::Tuple(3)].into(),
1879 Unit => single(SimplifiedType::Tuple(0)),
1880 RawPointer => [SimplifiedType::Ptr(Mutability::Not), SimplifiedType::Ptr(Mutability::Mut)].into_iter().collect(),
1881 Reference => [SimplifiedType::Ref(Mutability::Not), SimplifiedType::Ref(Mutability::Mut)].into_iter().collect(),
1882 Fn => single(SimplifiedType::Function(1)),
1885 Never => single(SimplifiedType::Never),
1886 }
1887 })
1888 }
1889
1890 pub(crate) fn impls<'tcx>(&self, tcx: TyCtxt<'tcx>) -> impl Iterator<Item = DefId> + 'tcx {
1891 Self::simplified_types()
1892 .get(self)
1893 .into_iter()
1894 .flatten()
1895 .flat_map(move |&simp| tcx.incoherent_impls(simp).iter())
1896 .copied()
1897 }
1898
1899 pub(crate) fn all_impls(tcx: TyCtxt<'_>) -> impl Iterator<Item = DefId> {
1900 Self::simplified_types()
1901 .values()
1902 .flatten()
1903 .flat_map(move |&simp| tcx.incoherent_impls(simp).iter())
1904 .copied()
1905 }
1906
1907 pub(crate) fn as_sym(&self) -> Symbol {
1908 use PrimitiveType::*;
1909 match self {
1910 Isize => sym::isize,
1911 I8 => sym::i8,
1912 I16 => sym::i16,
1913 I32 => sym::i32,
1914 I64 => sym::i64,
1915 I128 => sym::i128,
1916 Usize => sym::usize,
1917 U8 => sym::u8,
1918 U16 => sym::u16,
1919 U32 => sym::u32,
1920 U64 => sym::u64,
1921 U128 => sym::u128,
1922 F16 => sym::f16,
1923 F32 => sym::f32,
1924 F64 => sym::f64,
1925 F128 => sym::f128,
1926 Str => sym::str,
1927 Bool => sym::bool,
1928 Char => sym::char,
1929 Array => sym::array,
1930 Pat => sym::pat,
1931 Slice => sym::slice,
1932 Tuple => sym::tuple,
1933 Unit => sym::unit,
1934 RawPointer => sym::pointer,
1935 Reference => sym::reference,
1936 Fn => kw::Fn,
1937 Never => sym::never,
1938 }
1939 }
1940
1941 pub(crate) fn primitive_locations(tcx: TyCtxt<'_>) -> &FxIndexMap<PrimitiveType, DefId> {
1953 static PRIMITIVE_LOCATIONS: OnceCell<FxIndexMap<PrimitiveType, DefId>> = OnceCell::new();
1954 PRIMITIVE_LOCATIONS.get_or_init(|| {
1955 let mut primitive_locations = FxIndexMap::default();
1956 for &crate_num in tcx.crates(()) {
1959 let e = ExternalCrate { crate_num };
1960 let crate_name = e.name(tcx);
1961 debug!(?crate_num, ?crate_name);
1962 for (def_id, prim) in e.primitives(tcx) {
1963 if crate_name == sym::core && primitive_locations.contains_key(&prim) {
1965 continue;
1966 }
1967 primitive_locations.insert(prim, def_id);
1968 }
1969 }
1970 let local_primitives = ExternalCrate { crate_num: LOCAL_CRATE }.primitives(tcx);
1971 for (def_id, prim) in local_primitives {
1972 primitive_locations.insert(prim, def_id);
1973 }
1974 primitive_locations
1975 })
1976 }
1977}
1978
1979impl From<ty::IntTy> for PrimitiveType {
1980 fn from(int_ty: ty::IntTy) -> PrimitiveType {
1981 match int_ty {
1982 ty::IntTy::Isize => PrimitiveType::Isize,
1983 ty::IntTy::I8 => PrimitiveType::I8,
1984 ty::IntTy::I16 => PrimitiveType::I16,
1985 ty::IntTy::I32 => PrimitiveType::I32,
1986 ty::IntTy::I64 => PrimitiveType::I64,
1987 ty::IntTy::I128 => PrimitiveType::I128,
1988 }
1989 }
1990}
1991
1992impl From<ty::UintTy> for PrimitiveType {
1993 fn from(uint_ty: ty::UintTy) -> PrimitiveType {
1994 match uint_ty {
1995 ty::UintTy::Usize => PrimitiveType::Usize,
1996 ty::UintTy::U8 => PrimitiveType::U8,
1997 ty::UintTy::U16 => PrimitiveType::U16,
1998 ty::UintTy::U32 => PrimitiveType::U32,
1999 ty::UintTy::U64 => PrimitiveType::U64,
2000 ty::UintTy::U128 => PrimitiveType::U128,
2001 }
2002 }
2003}
2004
2005impl From<ty::FloatTy> for PrimitiveType {
2006 fn from(float_ty: ty::FloatTy) -> PrimitiveType {
2007 match float_ty {
2008 ty::FloatTy::F16 => PrimitiveType::F16,
2009 ty::FloatTy::F32 => PrimitiveType::F32,
2010 ty::FloatTy::F64 => PrimitiveType::F64,
2011 ty::FloatTy::F128 => PrimitiveType::F128,
2012 }
2013 }
2014}
2015
2016impl From<hir::PrimTy> for PrimitiveType {
2017 fn from(prim_ty: hir::PrimTy) -> PrimitiveType {
2018 match prim_ty {
2019 hir::PrimTy::Int(int_ty) => int_ty.into(),
2020 hir::PrimTy::Uint(uint_ty) => uint_ty.into(),
2021 hir::PrimTy::Float(float_ty) => float_ty.into(),
2022 hir::PrimTy::Str => PrimitiveType::Str,
2023 hir::PrimTy::Bool => PrimitiveType::Bool,
2024 hir::PrimTy::Char => PrimitiveType::Char,
2025 }
2026 }
2027}
2028
2029#[derive(Clone, Debug)]
2030pub(crate) struct Struct {
2031 pub(crate) ctor_kind: Option<CtorKind>,
2032 pub(crate) generics: Generics,
2033 pub(crate) fields: ThinVec<Item>,
2034}
2035
2036impl Struct {
2037 pub(crate) fn has_stripped_entries(&self) -> bool {
2038 self.fields.iter().any(|f| f.is_stripped())
2039 }
2040}
2041
2042#[derive(Clone, Debug)]
2043pub(crate) struct Union {
2044 pub(crate) generics: Generics,
2045 pub(crate) fields: Vec<Item>,
2046}
2047
2048impl Union {
2049 pub(crate) fn has_stripped_entries(&self) -> bool {
2050 self.fields.iter().any(|f| f.is_stripped())
2051 }
2052}
2053
2054#[derive(Clone, Debug)]
2058pub(crate) struct VariantStruct {
2059 pub(crate) fields: ThinVec<Item>,
2060}
2061
2062impl VariantStruct {
2063 pub(crate) fn has_stripped_entries(&self) -> bool {
2064 self.fields.iter().any(|f| f.is_stripped())
2065 }
2066}
2067
2068#[derive(Clone, Debug)]
2069pub(crate) struct Enum {
2070 pub(crate) variants: IndexVec<VariantIdx, Item>,
2071 pub(crate) generics: Generics,
2072}
2073
2074impl Enum {
2075 pub(crate) fn has_stripped_entries(&self) -> bool {
2076 self.variants.iter().any(|f| f.is_stripped())
2077 }
2078
2079 pub(crate) fn non_stripped_variants(&self) -> impl Iterator<Item = &Item> {
2080 self.variants.iter().filter(|v| !v.is_stripped())
2081 }
2082}
2083
2084#[derive(Clone, Debug)]
2085pub(crate) struct Variant {
2086 pub kind: VariantKind,
2087 pub discriminant: Option<Discriminant>,
2088}
2089
2090#[derive(Clone, Debug)]
2091pub(crate) enum VariantKind {
2092 CLike,
2093 Tuple(ThinVec<Item>),
2094 Struct(VariantStruct),
2095}
2096
2097impl Variant {
2098 pub(crate) fn has_stripped_entries(&self) -> Option<bool> {
2099 match &self.kind {
2100 VariantKind::Struct(struct_) => Some(struct_.has_stripped_entries()),
2101 VariantKind::CLike | VariantKind::Tuple(_) => None,
2102 }
2103 }
2104}
2105
2106#[derive(Clone, Debug)]
2107pub(crate) struct Discriminant {
2108 pub(super) expr: Option<BodyId>,
2111 pub(super) value: DefId,
2112}
2113
2114impl Discriminant {
2115 pub(crate) fn expr(&self, tcx: TyCtxt<'_>) -> Option<String> {
2118 self.expr
2119 .map(|body| rendered_const(tcx, tcx.hir_body(body), tcx.hir_body_owner_def_id(body)))
2120 }
2121 pub(crate) fn value(&self, tcx: TyCtxt<'_>, with_underscores: bool) -> String {
2122 print_evaluated_const(tcx, self.value, with_underscores, false).unwrap()
2123 }
2124}
2125
2126#[derive(Copy, Clone, Debug)]
2129pub(crate) struct Span(rustc_span::Span);
2130
2131impl Span {
2132 pub(crate) fn new(sp: rustc_span::Span) -> Self {
2137 Self(sp.source_callsite())
2138 }
2139
2140 pub(crate) fn inner(&self) -> rustc_span::Span {
2141 self.0
2142 }
2143
2144 pub(crate) fn filename(&self, sess: &Session) -> FileName {
2145 sess.source_map().span_to_filename(self.0)
2146 }
2147
2148 pub(crate) fn lo(&self, sess: &Session) -> Loc {
2149 sess.source_map().lookup_char_pos(self.0.lo())
2150 }
2151
2152 pub(crate) fn hi(&self, sess: &Session) -> Loc {
2153 sess.source_map().lookup_char_pos(self.0.hi())
2154 }
2155
2156 pub(crate) fn cnum(&self, sess: &Session) -> CrateNum {
2157 self.lo(sess).file.cnum
2159 }
2160}
2161
2162#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2163pub(crate) struct Path {
2164 pub(crate) res: Res,
2165 pub(crate) segments: ThinVec<PathSegment>,
2166}
2167
2168impl Path {
2169 pub(crate) fn def_id(&self) -> DefId {
2170 self.res.def_id()
2171 }
2172
2173 pub(crate) fn last_opt(&self) -> Option<Symbol> {
2174 self.segments.last().map(|s| s.name)
2175 }
2176
2177 pub(crate) fn last(&self) -> Symbol {
2178 self.last_opt().expect("segments were empty")
2179 }
2180
2181 pub(crate) fn whole_name(&self) -> String {
2182 self.segments
2183 .iter()
2184 .map(|s| if s.name == kw::PathRoot { "" } else { s.name.as_str() })
2185 .intersperse("::")
2186 .collect()
2187 }
2188
2189 pub(crate) fn is_assoc_ty(&self) -> bool {
2191 match self.res {
2192 Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } | Res::Def(DefKind::TyParam, _)
2193 if self.segments.len() != 1 =>
2194 {
2195 true
2196 }
2197 Res::Def(DefKind::AssocTy, _) => true,
2198 _ => false,
2199 }
2200 }
2201
2202 pub(crate) fn generic_args(&self) -> Option<&GenericArgs> {
2203 self.segments.last().map(|seg| &seg.args)
2204 }
2205
2206 pub(crate) fn generics(&self) -> Option<impl Iterator<Item = &Type>> {
2207 self.segments.last().and_then(|seg| {
2208 if let GenericArgs::AngleBracketed { ref args, .. } = seg.args {
2209 Some(args.iter().filter_map(|arg| match arg {
2210 GenericArg::Type(ty) => Some(ty),
2211 _ => None,
2212 }))
2213 } else {
2214 None
2215 }
2216 })
2217 }
2218}
2219
2220#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2221pub(crate) enum GenericArg {
2222 Lifetime(Lifetime),
2223 Type(Type),
2224 Const(Box<ConstantKind>),
2225 Infer,
2226}
2227
2228impl GenericArg {
2229 pub(crate) fn as_lt(&self) -> Option<&Lifetime> {
2230 if let Self::Lifetime(lt) = self { Some(lt) } else { None }
2231 }
2232
2233 pub(crate) fn as_ty(&self) -> Option<&Type> {
2234 if let Self::Type(ty) = self { Some(ty) } else { None }
2235 }
2236}
2237
2238#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2239pub(crate) enum GenericArgs {
2240 AngleBracketed { args: ThinVec<GenericArg>, constraints: ThinVec<AssocItemConstraint> },
2242 Parenthesized { inputs: ThinVec<Type>, output: Option<Box<Type>> },
2244 ReturnTypeNotation,
2246}
2247
2248impl GenericArgs {
2249 pub(crate) fn is_empty(&self) -> bool {
2250 match self {
2251 GenericArgs::AngleBracketed { args, constraints } => {
2252 args.is_empty() && constraints.is_empty()
2253 }
2254 GenericArgs::Parenthesized { inputs, output } => inputs.is_empty() && output.is_none(),
2255 GenericArgs::ReturnTypeNotation => false,
2256 }
2257 }
2258 pub(crate) fn constraints(&self) -> Box<dyn Iterator<Item = AssocItemConstraint> + '_> {
2259 match self {
2260 GenericArgs::AngleBracketed { constraints, .. } => {
2261 Box::new(constraints.iter().cloned())
2262 }
2263 GenericArgs::Parenthesized { output, .. } => Box::new(
2264 output
2265 .as_ref()
2266 .map(|ty| AssocItemConstraint {
2267 assoc: PathSegment {
2268 name: sym::Output,
2269 args: GenericArgs::AngleBracketed {
2270 args: ThinVec::new(),
2271 constraints: ThinVec::new(),
2272 },
2273 },
2274 kind: AssocItemConstraintKind::Equality {
2275 term: Term::Type((**ty).clone()),
2276 },
2277 })
2278 .into_iter(),
2279 ),
2280 GenericArgs::ReturnTypeNotation => Box::new([].into_iter()),
2281 }
2282 }
2283}
2284
2285impl<'a> IntoIterator for &'a GenericArgs {
2286 type IntoIter = Box<dyn Iterator<Item = GenericArg> + 'a>;
2287 type Item = GenericArg;
2288 fn into_iter(self) -> Self::IntoIter {
2289 match self {
2290 GenericArgs::AngleBracketed { args, .. } => Box::new(args.iter().cloned()),
2291 GenericArgs::Parenthesized { inputs, .. } => {
2292 Box::new(inputs.iter().cloned().map(GenericArg::Type))
2294 }
2295 GenericArgs::ReturnTypeNotation => Box::new([].into_iter()),
2296 }
2297 }
2298}
2299
2300#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2301pub(crate) struct PathSegment {
2302 pub(crate) name: Symbol,
2303 pub(crate) args: GenericArgs,
2304}
2305
2306#[derive(Clone, Debug)]
2307pub(crate) enum TypeAliasInnerType {
2308 Enum { variants: IndexVec<VariantIdx, Item>, is_non_exhaustive: bool },
2309 Union { fields: Vec<Item> },
2310 Struct { ctor_kind: Option<CtorKind>, fields: Vec<Item> },
2311}
2312
2313impl TypeAliasInnerType {
2314 fn has_stripped_entries(&self) -> Option<bool> {
2315 Some(match self {
2316 Self::Enum { variants, .. } => variants.iter().any(|v| v.is_stripped()),
2317 Self::Union { fields } | Self::Struct { fields, .. } => {
2318 fields.iter().any(|f| f.is_stripped())
2319 }
2320 })
2321 }
2322}
2323
2324#[derive(Clone, Debug)]
2325pub(crate) struct TypeAlias {
2326 pub(crate) type_: Type,
2327 pub(crate) generics: Generics,
2328 pub(crate) inner_type: Option<TypeAliasInnerType>,
2331 pub(crate) item_type: Option<Type>,
2338}
2339
2340#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2341pub(crate) struct BareFunctionDecl {
2342 pub(crate) safety: hir::Safety,
2343 pub(crate) generic_params: Vec<GenericParamDef>,
2344 pub(crate) decl: FnDecl,
2345 pub(crate) abi: ExternAbi,
2346}
2347
2348#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2349pub(crate) struct UnsafeBinderTy {
2350 pub(crate) generic_params: Vec<GenericParamDef>,
2351 pub(crate) ty: Type,
2352}
2353
2354#[derive(Clone, Debug)]
2355pub(crate) struct Static {
2356 pub(crate) type_: Box<Type>,
2357 pub(crate) mutability: Mutability,
2358 pub(crate) expr: Option<BodyId>,
2359}
2360
2361#[derive(Clone, PartialEq, Eq, Hash, Debug)]
2362pub(crate) struct Constant {
2363 pub(crate) generics: Generics,
2364 pub(crate) kind: ConstantKind,
2365 pub(crate) type_: Type,
2366}
2367
2368#[derive(Clone, PartialEq, Eq, Hash, Debug)]
2369pub(crate) enum Term {
2370 Type(Type),
2371 Constant(ConstantKind),
2372}
2373
2374impl Term {
2375 pub(crate) fn ty(&self) -> Option<&Type> {
2376 if let Term::Type(ty) = self { Some(ty) } else { None }
2377 }
2378}
2379
2380impl From<Type> for Term {
2381 fn from(ty: Type) -> Self {
2382 Term::Type(ty)
2383 }
2384}
2385
2386#[derive(Clone, PartialEq, Eq, Hash, Debug)]
2387pub(crate) enum ConstantKind {
2388 TyConst { expr: Box<str> },
2394 Path { path: Box<str> },
2397 Anonymous { body: BodyId },
2401 Extern { def_id: DefId },
2403 Local { def_id: DefId, body: BodyId },
2405 Infer,
2407}
2408
2409impl ConstantKind {
2410 pub(crate) fn expr(&self, tcx: TyCtxt<'_>) -> String {
2411 match *self {
2412 ConstantKind::TyConst { ref expr } => expr.to_string(),
2413 ConstantKind::Path { ref path } => path.to_string(),
2414 ConstantKind::Extern { def_id } => print_inlined_const(tcx, def_id),
2415 ConstantKind::Local { body, .. } | ConstantKind::Anonymous { body } => {
2416 rendered_const(tcx, tcx.hir_body(body), tcx.hir_body_owner_def_id(body))
2417 }
2418 ConstantKind::Infer => "_".to_string(),
2419 }
2420 }
2421
2422 pub(crate) fn value(&self, tcx: TyCtxt<'_>) -> Option<String> {
2423 match *self {
2424 ConstantKind::TyConst { .. }
2425 | ConstantKind::Path { .. }
2426 | ConstantKind::Anonymous { .. }
2427 | ConstantKind::Infer => None,
2428 ConstantKind::Extern { def_id } | ConstantKind::Local { def_id, .. } => {
2429 print_evaluated_const(tcx, def_id, true, true)
2430 }
2431 }
2432 }
2433
2434 pub(crate) fn is_literal(&self, tcx: TyCtxt<'_>) -> bool {
2435 match *self {
2436 ConstantKind::TyConst { .. }
2437 | ConstantKind::Extern { .. }
2438 | ConstantKind::Path { .. }
2439 | ConstantKind::Infer => false,
2440 ConstantKind::Local { body, .. } | ConstantKind::Anonymous { body } => {
2441 is_literal_expr(tcx, body.hir_id)
2442 }
2443 }
2444 }
2445}
2446
2447#[derive(Clone, Debug)]
2448pub(crate) struct Impl {
2449 pub(crate) safety: hir::Safety,
2450 pub(crate) generics: Generics,
2451 pub(crate) trait_: Option<Path>,
2452 pub(crate) for_: Type,
2453 pub(crate) items: Vec<Item>,
2454 pub(crate) polarity: ty::ImplPolarity,
2455 pub(crate) kind: ImplKind,
2456}
2457
2458impl Impl {
2459 pub(crate) fn provided_trait_methods(&self, tcx: TyCtxt<'_>) -> FxIndexSet<Symbol> {
2460 self.trait_
2461 .as_ref()
2462 .map(|t| t.def_id())
2463 .map(|did| tcx.provided_trait_methods(did).map(|meth| meth.name()).collect())
2464 .unwrap_or_default()
2465 }
2466
2467 pub(crate) fn is_negative_trait_impl(&self) -> bool {
2468 matches!(self.polarity, ty::ImplPolarity::Negative)
2469 }
2470}
2471
2472#[derive(Clone, Debug)]
2473pub(crate) enum ImplKind {
2474 Normal,
2475 Auto,
2476 FakeVariadic,
2477 Blanket(Box<Type>),
2478}
2479
2480impl ImplKind {
2481 pub(crate) fn is_auto(&self) -> bool {
2482 matches!(self, ImplKind::Auto)
2483 }
2484
2485 pub(crate) fn is_blanket(&self) -> bool {
2486 matches!(self, ImplKind::Blanket(_))
2487 }
2488
2489 pub(crate) fn is_fake_variadic(&self) -> bool {
2490 matches!(self, ImplKind::FakeVariadic)
2491 }
2492
2493 pub(crate) fn as_blanket_ty(&self) -> Option<&Type> {
2494 match self {
2495 ImplKind::Blanket(ty) => Some(ty),
2496 _ => None,
2497 }
2498 }
2499}
2500
2501#[derive(Clone, Debug)]
2502pub(crate) struct Import {
2503 pub(crate) kind: ImportKind,
2504 pub(crate) source: ImportSource,
2506 pub(crate) should_be_displayed: bool,
2507}
2508
2509impl Import {
2510 pub(crate) fn new_simple(
2511 name: Symbol,
2512 source: ImportSource,
2513 should_be_displayed: bool,
2514 ) -> Self {
2515 Self { kind: ImportKind::Simple(name), source, should_be_displayed }
2516 }
2517
2518 pub(crate) fn new_glob(source: ImportSource, should_be_displayed: bool) -> Self {
2519 Self { kind: ImportKind::Glob, source, should_be_displayed }
2520 }
2521
2522 pub(crate) fn imported_item_is_doc_hidden(&self, tcx: TyCtxt<'_>) -> bool {
2523 self.source.did.is_some_and(|did| tcx.is_doc_hidden(did))
2524 }
2525}
2526
2527#[derive(Clone, Debug)]
2528pub(crate) enum ImportKind {
2529 Simple(Symbol),
2531 Glob,
2533}
2534
2535#[derive(Clone, Debug)]
2536pub(crate) struct ImportSource {
2537 pub(crate) path: Path,
2538 pub(crate) did: Option<DefId>,
2539}
2540
2541#[derive(Clone, Debug)]
2542pub(crate) struct Macro {
2543 pub(crate) source: String,
2544 pub(crate) macro_rules: bool,
2546}
2547
2548#[derive(Clone, Debug)]
2549pub(crate) struct ProcMacro {
2550 pub(crate) kind: MacroKind,
2551 pub(crate) helpers: Vec<Symbol>,
2552}
2553
2554#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2565pub(crate) struct AssocItemConstraint {
2566 pub(crate) assoc: PathSegment,
2567 pub(crate) kind: AssocItemConstraintKind,
2568}
2569
2570#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2572pub(crate) enum AssocItemConstraintKind {
2573 Equality { term: Term },
2574 Bound { bounds: Vec<GenericBound> },
2575}
2576
2577#[cfg(target_pointer_width = "64")]
2579mod size_asserts {
2580 use rustc_data_structures::static_assert_size;
2581
2582 use super::*;
2583 static_assert_size!(Crate, 16); static_assert_size!(DocFragment, 32);
2586 static_assert_size!(GenericArg, 32);
2587 static_assert_size!(GenericArgs, 24);
2588 static_assert_size!(GenericParamDef, 40);
2589 static_assert_size!(Generics, 16);
2590 static_assert_size!(Item, 8);
2591 static_assert_size!(ItemInner, 144);
2592 static_assert_size!(ItemKind, 48);
2593 static_assert_size!(PathSegment, 32);
2594 static_assert_size!(Type, 32);
2595 }