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