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 links(&self, cx: &Context<'_>) -> Vec<RenderedLink> {
484 use crate::html::format::{href, link_tooltip};
485
486 let Some(links) = cx.cache().intra_doc_links.get(&self.item_id) else { return vec![] };
487 links
488 .iter()
489 .filter_map(|ItemLink { link: s, link_text, page_id: id, fragment }| {
490 debug!(?id);
491 if let Ok((mut href, ..)) = href(*id, cx) {
492 debug!(?href);
493 if let Some(ref fragment) = *fragment {
494 fragment.render(&mut href, cx.tcx())
495 }
496 Some(RenderedLink {
497 original_text: s.clone(),
498 new_text: link_text.clone(),
499 tooltip: link_tooltip(*id, fragment, cx).to_string(),
500 href,
501 })
502 } else {
503 None
504 }
505 })
506 .collect()
507 }
508
509 pub(crate) fn link_names(&self, cache: &Cache) -> Vec<RenderedLink> {
515 let Some(links) = cache.intra_doc_links.get(&self.item_id) else {
516 return vec![];
517 };
518 links
519 .iter()
520 .map(|ItemLink { link: s, link_text, .. }| RenderedLink {
521 original_text: s.clone(),
522 new_text: link_text.clone(),
523 href: String::new(),
524 tooltip: String::new(),
525 })
526 .collect()
527 }
528
529 pub(crate) fn is_crate(&self) -> bool {
530 self.is_mod() && self.def_id().is_some_and(|did| did.is_crate_root())
531 }
532 pub(crate) fn is_mod(&self) -> bool {
533 self.type_() == ItemType::Module
534 }
535 pub(crate) fn is_struct(&self) -> bool {
536 self.type_() == ItemType::Struct
537 }
538 pub(crate) fn is_enum(&self) -> bool {
539 self.type_() == ItemType::Enum
540 }
541 pub(crate) fn is_variant(&self) -> bool {
542 self.type_() == ItemType::Variant
543 }
544 pub(crate) fn is_associated_type(&self) -> bool {
545 matches!(self.kind, AssocTypeItem(..) | StrippedItem(box AssocTypeItem(..)))
546 }
547 pub(crate) fn is_required_associated_type(&self) -> bool {
548 matches!(self.kind, RequiredAssocTypeItem(..) | StrippedItem(box RequiredAssocTypeItem(..)))
549 }
550 pub(crate) fn is_associated_const(&self) -> bool {
551 matches!(self.kind, ProvidedAssocConstItem(..) | ImplAssocConstItem(..) | StrippedItem(box (ProvidedAssocConstItem(..) | ImplAssocConstItem(..))))
552 }
553 pub(crate) fn is_required_associated_const(&self) -> bool {
554 matches!(self.kind, RequiredAssocConstItem(..) | StrippedItem(box RequiredAssocConstItem(..)))
555 }
556 pub(crate) fn is_method(&self) -> bool {
557 self.type_() == ItemType::Method
558 }
559 pub(crate) fn is_ty_method(&self) -> bool {
560 self.type_() == ItemType::TyMethod
561 }
562 pub(crate) fn is_primitive(&self) -> bool {
563 self.type_() == ItemType::Primitive
564 }
565 pub(crate) fn is_union(&self) -> bool {
566 self.type_() == ItemType::Union
567 }
568 pub(crate) fn is_import(&self) -> bool {
569 self.type_() == ItemType::Import
570 }
571 pub(crate) fn is_extern_crate(&self) -> bool {
572 self.type_() == ItemType::ExternCrate
573 }
574 pub(crate) fn is_keyword(&self) -> bool {
575 self.type_() == ItemType::Keyword
576 }
577 pub(crate) fn is_stripped(&self) -> bool {
578 match self.kind {
579 StrippedItem(..) => true,
580 ImportItem(ref i) => !i.should_be_displayed,
581 _ => false,
582 }
583 }
584 pub(crate) fn has_stripped_entries(&self) -> Option<bool> {
585 match self.kind {
586 StructItem(ref struct_) => Some(struct_.has_stripped_entries()),
587 UnionItem(ref union_) => Some(union_.has_stripped_entries()),
588 EnumItem(ref enum_) => Some(enum_.has_stripped_entries()),
589 VariantItem(ref v) => v.has_stripped_entries(),
590 TypeAliasItem(ref type_alias) => {
591 type_alias.inner_type.as_ref().and_then(|t| t.has_stripped_entries())
592 }
593 _ => None,
594 }
595 }
596
597 pub(crate) fn stability_class(&self, tcx: TyCtxt<'_>) -> Option<String> {
598 self.stability(tcx).as_ref().and_then(|s| {
599 let mut classes = Vec::with_capacity(2);
600
601 if s.is_unstable() {
602 classes.push("unstable");
603 }
604
605 if self.deprecation(tcx).is_some() {
607 classes.push("deprecated");
608 }
609
610 if !classes.is_empty() { Some(classes.join(" ")) } else { None }
611 })
612 }
613
614 pub(crate) fn stable_since(&self, tcx: TyCtxt<'_>) -> Option<StableSince> {
615 self.stability(tcx).and_then(|stability| stability.stable_since())
616 }
617
618 pub(crate) fn is_non_exhaustive(&self) -> bool {
619 find_attr!(&self.attrs.other_attrs, AttributeKind::NonExhaustive(..))
620 }
621
622 pub(crate) fn type_(&self) -> ItemType {
624 ItemType::from(self)
625 }
626
627 pub(crate) fn is_default(&self) -> bool {
628 match self.kind {
629 ItemKind::MethodItem(_, Some(defaultness)) => {
630 defaultness.has_value() && !defaultness.is_final()
631 }
632 _ => false,
633 }
634 }
635
636 pub(crate) fn fn_header(&self, tcx: TyCtxt<'_>) -> Option<hir::FnHeader> {
638 fn build_fn_header(
639 def_id: DefId,
640 tcx: TyCtxt<'_>,
641 asyncness: ty::Asyncness,
642 ) -> hir::FnHeader {
643 let sig = tcx.fn_sig(def_id).skip_binder();
644 let constness = if tcx.is_const_fn(def_id) {
645 match tcx.opt_associated_item(def_id) {
649 Some(ty::AssocItem {
650 container: ty::AssocItemContainer::Impl,
651 trait_item_def_id: Some(_),
652 ..
653 })
654 | Some(ty::AssocItem { container: ty::AssocItemContainer::Trait, .. }) => {
655 hir::Constness::NotConst
656 }
657 None | Some(_) => hir::Constness::Const,
658 }
659 } else {
660 hir::Constness::NotConst
661 };
662 let asyncness = match asyncness {
663 ty::Asyncness::Yes => hir::IsAsync::Async(DUMMY_SP),
664 ty::Asyncness::No => hir::IsAsync::NotAsync,
665 };
666 hir::FnHeader {
667 safety: if tcx.codegen_fn_attrs(def_id).safe_target_features {
668 hir::HeaderSafety::SafeTargetFeatures
669 } else {
670 sig.safety().into()
671 },
672 abi: sig.abi(),
673 constness,
674 asyncness,
675 }
676 }
677 let header = match self.kind {
678 ItemKind::ForeignFunctionItem(_, safety) => {
679 let def_id = self.def_id().unwrap();
680 let abi = tcx.fn_sig(def_id).skip_binder().abi();
681 hir::FnHeader {
682 safety: if tcx.codegen_fn_attrs(def_id).safe_target_features {
683 hir::HeaderSafety::SafeTargetFeatures
684 } else {
685 safety.into()
686 },
687 abi,
688 constness: if tcx.is_const_fn(def_id) {
689 hir::Constness::Const
690 } else {
691 hir::Constness::NotConst
692 },
693 asyncness: hir::IsAsync::NotAsync,
694 }
695 }
696 ItemKind::FunctionItem(_)
697 | ItemKind::MethodItem(_, _)
698 | ItemKind::RequiredMethodItem(_) => {
699 let def_id = self.def_id().unwrap();
700 build_fn_header(def_id, tcx, tcx.asyncness(def_id))
701 }
702 _ => return None,
703 };
704 Some(header)
705 }
706
707 pub(crate) fn visibility(&self, tcx: TyCtxt<'_>) -> Option<Visibility<DefId>> {
710 let def_id = match self.item_id {
711 ItemId::Auto { .. } | ItemId::Blanket { .. } => return None,
713 ItemId::DefId(def_id) => def_id,
714 };
715
716 match self.kind {
717 ItemKind::KeywordItem | ItemKind::PrimitiveItem(_) => return Some(Visibility::Public),
721 StructFieldItem(..) if is_field_vis_inherited(tcx, def_id) => {
723 return None;
724 }
725 VariantItem(..) | ImplItem(..) => return None,
727 RequiredAssocConstItem(..)
729 | ProvidedAssocConstItem(..)
730 | ImplAssocConstItem(..)
731 | AssocTypeItem(..)
732 | RequiredAssocTypeItem(..)
733 | RequiredMethodItem(..)
734 | MethodItem(..) => {
735 let assoc_item = tcx.associated_item(def_id);
736 let is_trait_item = match assoc_item.container {
737 ty::AssocItemContainer::Trait => true,
738 ty::AssocItemContainer::Impl => {
739 tcx.impl_trait_ref(tcx.parent(assoc_item.def_id)).is_some()
742 }
743 };
744 if is_trait_item {
745 return None;
746 }
747 }
748 _ => {}
749 }
750 let def_id = match self.inline_stmt_id {
751 Some(inlined) => inlined.to_def_id(),
752 None => def_id,
753 };
754 Some(tcx.visibility(def_id))
755 }
756
757 fn attributes_without_repr(&self) -> Vec<String> {
761 self.attrs
762 .other_attrs
763 .iter()
764 .filter_map(|attr| match attr {
765 hir::Attribute::Parsed(AttributeKind::LinkSection { name, .. }) => {
766 Some(format!("#[link_section = \"{name}\"]"))
767 }
768 hir::Attribute::Parsed(AttributeKind::NoMangle(..)) => {
769 Some("#[no_mangle]".to_string())
770 }
771 hir::Attribute::Parsed(AttributeKind::ExportName { name, .. }) => {
772 Some(format!("#[export_name = \"{name}\"]"))
773 }
774 hir::Attribute::Parsed(AttributeKind::NonExhaustive(..)) => {
775 Some("#[non_exhaustive]".to_string())
776 }
777 _ => None,
778 })
779 .collect()
780 }
781
782 pub(crate) fn attributes(&self, tcx: TyCtxt<'_>, cache: &Cache) -> Vec<String> {
786 let mut attrs = self.attributes_without_repr();
787
788 if let Some(repr_attr) = self.repr(tcx, cache) {
789 attrs.push(repr_attr);
790 }
791 attrs
792 }
793
794 pub(crate) fn repr(&self, tcx: TyCtxt<'_>, cache: &Cache) -> Option<String> {
798 repr_attributes(tcx, cache, self.def_id()?, self.type_())
799 }
800
801 pub fn is_doc_hidden(&self) -> bool {
802 self.attrs.is_doc_hidden()
803 }
804
805 pub fn def_id(&self) -> Option<DefId> {
806 self.item_id.as_def_id()
807 }
808}
809
810pub(crate) fn repr_attributes(
814 tcx: TyCtxt<'_>,
815 cache: &Cache,
816 def_id: DefId,
817 item_type: ItemType,
818) -> Option<String> {
819 use rustc_abi::IntegerType;
820
821 if !matches!(item_type, ItemType::Struct | ItemType::Enum | ItemType::Union) {
822 return None;
823 }
824 let adt = tcx.adt_def(def_id);
825 let repr = adt.repr();
826 let mut out = Vec::new();
827 if repr.c() {
828 out.push("C");
829 }
830 if repr.transparent() {
831 let render_transparent = cache.document_private
834 || adt
835 .all_fields()
836 .find(|field| {
837 let ty = field.ty(tcx, ty::GenericArgs::identity_for_item(tcx, field.did));
838 tcx.layout_of(ty::TypingEnv::post_analysis(tcx, field.did).as_query_input(ty))
839 .is_ok_and(|layout| !layout.is_1zst())
840 })
841 .map_or_else(
842 || adt.all_fields().any(|field| field.vis.is_public()),
843 |field| field.vis.is_public(),
844 );
845
846 if render_transparent {
847 out.push("transparent");
848 }
849 }
850 if repr.simd() {
851 out.push("simd");
852 }
853 let pack_s;
854 if let Some(pack) = repr.pack {
855 pack_s = format!("packed({})", pack.bytes());
856 out.push(&pack_s);
857 }
858 let align_s;
859 if let Some(align) = repr.align {
860 align_s = format!("align({})", align.bytes());
861 out.push(&align_s);
862 }
863 let int_s;
864 if let Some(int) = repr.int {
865 int_s = match int {
866 IntegerType::Pointer(is_signed) => {
867 format!("{}size", if is_signed { 'i' } else { 'u' })
868 }
869 IntegerType::Fixed(size, is_signed) => {
870 format!("{}{}", if is_signed { 'i' } else { 'u' }, size.size().bytes() * 8)
871 }
872 };
873 out.push(&int_s);
874 }
875 if !out.is_empty() { Some(format!("#[repr({})]", out.join(", "))) } else { None }
876}
877
878#[derive(Clone, Debug)]
879pub(crate) enum ItemKind {
880 ExternCrateItem {
881 src: Option<Symbol>,
883 },
884 ImportItem(Import),
885 StructItem(Struct),
886 UnionItem(Union),
887 EnumItem(Enum),
888 FunctionItem(Box<Function>),
889 ModuleItem(Module),
890 TypeAliasItem(Box<TypeAlias>),
891 StaticItem(Static),
892 TraitItem(Box<Trait>),
893 TraitAliasItem(TraitAlias),
894 ImplItem(Box<Impl>),
895 RequiredMethodItem(Box<Function>),
897 MethodItem(Box<Function>, Option<hir::Defaultness>),
901 StructFieldItem(Type),
902 VariantItem(Variant),
903 ForeignFunctionItem(Box<Function>, hir::Safety),
905 ForeignStaticItem(Static, hir::Safety),
907 ForeignTypeItem,
909 MacroItem(Macro),
910 ProcMacroItem(ProcMacro),
911 PrimitiveItem(PrimitiveType),
912 RequiredAssocConstItem(Generics, Box<Type>),
914 ConstantItem(Box<Constant>),
915 ProvidedAssocConstItem(Box<Constant>),
917 ImplAssocConstItem(Box<Constant>),
919 RequiredAssocTypeItem(Generics, Vec<GenericBound>),
923 AssocTypeItem(Box<TypeAlias>, Vec<GenericBound>),
925 StrippedItem(Box<ItemKind>),
927 KeywordItem,
928}
929
930impl ItemKind {
931 pub(crate) fn inner_items(&self) -> impl Iterator<Item = &Item> {
934 match self {
935 StructItem(s) => s.fields.iter(),
936 UnionItem(u) => u.fields.iter(),
937 VariantItem(v) => match &v.kind {
938 VariantKind::CLike => [].iter(),
939 VariantKind::Tuple(t) => t.iter(),
940 VariantKind::Struct(s) => s.fields.iter(),
941 },
942 EnumItem(e) => e.variants.iter(),
943 TraitItem(t) => t.items.iter(),
944 ImplItem(i) => i.items.iter(),
945 ModuleItem(m) => m.items.iter(),
946 ExternCrateItem { .. }
947 | ImportItem(_)
948 | FunctionItem(_)
949 | TypeAliasItem(_)
950 | StaticItem(_)
951 | ConstantItem(_)
952 | TraitAliasItem(_)
953 | RequiredMethodItem(_)
954 | MethodItem(_, _)
955 | StructFieldItem(_)
956 | ForeignFunctionItem(_, _)
957 | ForeignStaticItem(_, _)
958 | ForeignTypeItem
959 | MacroItem(_)
960 | ProcMacroItem(_)
961 | PrimitiveItem(_)
962 | RequiredAssocConstItem(..)
963 | ProvidedAssocConstItem(..)
964 | ImplAssocConstItem(..)
965 | RequiredAssocTypeItem(..)
966 | AssocTypeItem(..)
967 | StrippedItem(_)
968 | KeywordItem => [].iter(),
969 }
970 }
971
972 pub(crate) fn is_non_assoc(&self) -> bool {
974 matches!(
975 self,
976 StructItem(_)
977 | UnionItem(_)
978 | EnumItem(_)
979 | TraitItem(_)
980 | ModuleItem(_)
981 | ExternCrateItem { .. }
982 | FunctionItem(_)
983 | TypeAliasItem(_)
984 | StaticItem(_)
985 | ConstantItem(_)
986 | TraitAliasItem(_)
987 | ForeignFunctionItem(_, _)
988 | ForeignStaticItem(_, _)
989 | ForeignTypeItem
990 | MacroItem(_)
991 | ProcMacroItem(_)
992 | PrimitiveItem(_)
993 )
994 }
995}
996
997#[derive(Clone, Debug)]
998pub(crate) struct Module {
999 pub(crate) items: Vec<Item>,
1000 pub(crate) span: Span,
1001}
1002
1003pub(crate) fn hir_attr_lists<'a, I: IntoIterator<Item = &'a hir::Attribute>>(
1004 attrs: I,
1005 name: Symbol,
1006) -> impl Iterator<Item = ast::MetaItemInner> + use<'a, I> {
1007 attrs
1008 .into_iter()
1009 .filter(move |attr| attr.has_name(name))
1010 .filter_map(ast::attr::AttributeExt::meta_item_list)
1011 .flatten()
1012}
1013
1014pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator<Item = &'a hir::Attribute> + Clone>(
1015 attrs: I,
1016 tcx: TyCtxt<'_>,
1017 hidden_cfg: &FxHashSet<Cfg>,
1018) -> Option<Arc<Cfg>> {
1019 let doc_cfg_active = tcx.features().doc_cfg();
1020 let doc_auto_cfg_active = tcx.features().doc_auto_cfg();
1021
1022 fn single<T: IntoIterator>(it: T) -> Option<T::Item> {
1023 let mut iter = it.into_iter();
1024 let item = iter.next()?;
1025 if iter.next().is_some() {
1026 return None;
1027 }
1028 Some(item)
1029 }
1030
1031 let mut cfg = if doc_cfg_active || doc_auto_cfg_active {
1032 let mut doc_cfg = attrs
1033 .clone()
1034 .filter(|attr| attr.has_name(sym::doc))
1035 .flat_map(|attr| attr.meta_item_list().unwrap_or_default())
1036 .filter(|attr| attr.has_name(sym::cfg))
1037 .peekable();
1038 if doc_cfg.peek().is_some() && doc_cfg_active {
1039 let sess = tcx.sess;
1040
1041 doc_cfg.fold(Cfg::True, |mut cfg, item| {
1042 if let Some(cfg_mi) =
1043 item.meta_item().and_then(|item| rustc_expand::config::parse_cfg(item, sess))
1044 {
1045 match Cfg::parse(cfg_mi) {
1046 Ok(new_cfg) => cfg &= new_cfg,
1047 Err(e) => {
1048 sess.dcx().span_err(e.span, e.msg);
1049 }
1050 }
1051 }
1052 cfg
1053 })
1054 } else if doc_auto_cfg_active {
1055 attrs
1058 .clone()
1059 .filter(|attr| attr.has_name(sym::cfg_trace))
1060 .filter_map(|attr| single(attr.meta_item_list()?))
1061 .filter_map(|attr| Cfg::parse_without(attr.meta_item()?, hidden_cfg).ok().flatten())
1062 .fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg)
1063 } else {
1064 Cfg::True
1065 }
1066 } else {
1067 Cfg::True
1068 };
1069
1070 if let Some(features) = find_attr!(attrs, AttributeKind::TargetFeature(features, _) => features)
1073 {
1074 for (feature, _) in features {
1075 cfg &= Cfg::Cfg(sym::target_feature, Some(*feature));
1076 }
1077 }
1078
1079 if cfg == Cfg::True { None } else { Some(Arc::new(cfg)) }
1080}
1081
1082pub(crate) trait NestedAttributesExt {
1083 fn has_word(self, word: Symbol) -> bool
1085 where
1086 Self: Sized,
1087 {
1088 <Self as NestedAttributesExt>::get_word_attr(self, word).is_some()
1089 }
1090
1091 fn get_word_attr(self, word: Symbol) -> Option<ast::MetaItemInner>;
1094}
1095
1096impl<I: Iterator<Item = ast::MetaItemInner>> NestedAttributesExt for I {
1097 fn get_word_attr(mut self, word: Symbol) -> Option<ast::MetaItemInner> {
1098 self.find(|attr| attr.is_word() && attr.has_name(word))
1099 }
1100}
1101
1102#[derive(Clone, Debug, PartialEq, Eq, Hash)]
1106pub(crate) struct ItemLink {
1107 pub(crate) link: Box<str>,
1109 pub(crate) link_text: Box<str>,
1114 pub(crate) page_id: DefId,
1118 pub(crate) fragment: Option<UrlFragment>,
1120}
1121
1122pub struct RenderedLink {
1123 pub(crate) original_text: Box<str>,
1127 pub(crate) new_text: Box<str>,
1129 pub(crate) href: String,
1131 pub(crate) tooltip: String,
1133}
1134
1135#[derive(Clone, Debug, Default)]
1138pub(crate) struct Attributes {
1139 pub(crate) doc_strings: Vec<DocFragment>,
1140 pub(crate) other_attrs: ThinVec<hir::Attribute>,
1141}
1142
1143impl Attributes {
1144 pub(crate) fn lists(&self, name: Symbol) -> impl Iterator<Item = ast::MetaItemInner> {
1145 hir_attr_lists(&self.other_attrs[..], name)
1146 }
1147
1148 pub(crate) fn has_doc_flag(&self, flag: Symbol) -> bool {
1149 for attr in &self.other_attrs {
1150 if !attr.has_name(sym::doc) {
1151 continue;
1152 }
1153
1154 if let Some(items) = attr.meta_item_list()
1155 && items.iter().filter_map(|i| i.meta_item()).any(|it| it.has_name(flag))
1156 {
1157 return true;
1158 }
1159 }
1160
1161 false
1162 }
1163
1164 pub(crate) fn is_doc_hidden(&self) -> bool {
1165 self.has_doc_flag(sym::hidden)
1166 }
1167
1168 pub(crate) fn from_hir(attrs: &[hir::Attribute]) -> Attributes {
1169 Attributes::from_hir_iter(attrs.iter().map(|attr| (attr, None)), false)
1170 }
1171
1172 pub(crate) fn from_hir_with_additional(
1173 attrs: &[hir::Attribute],
1174 (additional_attrs, def_id): (&[hir::Attribute], DefId),
1175 ) -> Attributes {
1176 let attrs1 = additional_attrs.iter().map(|attr| (attr, Some(def_id)));
1178 let attrs2 = attrs.iter().map(|attr| (attr, None));
1179 Attributes::from_hir_iter(attrs1.chain(attrs2), false)
1180 }
1181
1182 pub(crate) fn from_hir_iter<'a>(
1183 attrs: impl Iterator<Item = (&'a hir::Attribute, Option<DefId>)>,
1184 doc_only: bool,
1185 ) -> Attributes {
1186 let (doc_strings, other_attrs) = attrs_to_doc_fragments(attrs, doc_only);
1187 Attributes { doc_strings, other_attrs }
1188 }
1189
1190 pub(crate) fn doc_value(&self) -> String {
1192 self.opt_doc_value().unwrap_or_default()
1193 }
1194
1195 pub(crate) fn opt_doc_value(&self) -> Option<String> {
1199 (!self.doc_strings.is_empty()).then(|| {
1200 let mut res = String::new();
1201 for frag in &self.doc_strings {
1202 add_doc_fragment(&mut res, frag);
1203 }
1204 res.pop();
1205 res
1206 })
1207 }
1208
1209 pub(crate) fn get_doc_aliases(&self) -> Box<[Symbol]> {
1210 let mut aliases = FxIndexSet::default();
1211
1212 for attr in
1213 hir_attr_lists(&self.other_attrs[..], sym::doc).filter(|a| a.has_name(sym::alias))
1214 {
1215 if let Some(values) = attr.meta_item_list() {
1216 for l in values {
1217 if let Some(lit) = l.lit()
1218 && let ast::LitKind::Str(s, _) = lit.kind
1219 {
1220 aliases.insert(s);
1221 }
1222 }
1223 } else if let Some(value) = attr.value_str() {
1224 aliases.insert(value);
1225 }
1226 }
1227 aliases.into_iter().collect::<Vec<_>>().into()
1228 }
1229}
1230
1231#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1232pub(crate) enum GenericBound {
1233 TraitBound(PolyTrait, hir::TraitBoundModifiers),
1234 Outlives(Lifetime),
1235 Use(Vec<PreciseCapturingArg>),
1237}
1238
1239impl GenericBound {
1240 pub(crate) fn sized(cx: &mut DocContext<'_>) -> GenericBound {
1241 Self::sized_with(cx, hir::TraitBoundModifiers::NONE)
1242 }
1243
1244 pub(crate) fn maybe_sized(cx: &mut DocContext<'_>) -> GenericBound {
1245 Self::sized_with(
1246 cx,
1247 hir::TraitBoundModifiers {
1248 polarity: hir::BoundPolarity::Maybe(DUMMY_SP),
1249 constness: hir::BoundConstness::Never,
1250 },
1251 )
1252 }
1253
1254 fn sized_with(cx: &mut DocContext<'_>, modifiers: hir::TraitBoundModifiers) -> GenericBound {
1255 let did = cx.tcx.require_lang_item(LangItem::Sized, DUMMY_SP);
1256 let empty = ty::Binder::dummy(ty::GenericArgs::empty());
1257 let path = clean_middle_path(cx, did, false, ThinVec::new(), empty);
1258 inline::record_extern_fqn(cx, did, ItemType::Trait);
1259 GenericBound::TraitBound(PolyTrait { trait_: path, generic_params: Vec::new() }, modifiers)
1260 }
1261
1262 pub(crate) fn is_trait_bound(&self) -> bool {
1263 matches!(self, Self::TraitBound(..))
1264 }
1265
1266 pub(crate) fn is_sized_bound(&self, cx: &DocContext<'_>) -> bool {
1267 self.is_bounded_by_lang_item(cx, LangItem::Sized)
1268 }
1269
1270 pub(crate) fn is_meta_sized_bound(&self, cx: &DocContext<'_>) -> bool {
1271 self.is_bounded_by_lang_item(cx, LangItem::MetaSized)
1272 }
1273
1274 fn is_bounded_by_lang_item(&self, cx: &DocContext<'_>, lang_item: LangItem) -> bool {
1275 if let GenericBound::TraitBound(
1276 PolyTrait { ref trait_, .. },
1277 rustc_hir::TraitBoundModifiers::NONE,
1278 ) = *self
1279 && cx.tcx.is_lang_item(trait_.def_id(), lang_item)
1280 {
1281 return true;
1282 }
1283 false
1284 }
1285
1286 pub(crate) fn get_trait_path(&self) -> Option<Path> {
1287 if let GenericBound::TraitBound(PolyTrait { ref trait_, .. }, _) = *self {
1288 Some(trait_.clone())
1289 } else {
1290 None
1291 }
1292 }
1293}
1294
1295#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
1296pub(crate) struct Lifetime(pub Symbol);
1297
1298impl Lifetime {
1299 pub(crate) fn statik() -> Lifetime {
1300 Lifetime(kw::StaticLifetime)
1301 }
1302
1303 pub(crate) fn elided() -> Lifetime {
1304 Lifetime(kw::UnderscoreLifetime)
1305 }
1306}
1307
1308#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
1309pub(crate) enum PreciseCapturingArg {
1310 Lifetime(Lifetime),
1311 Param(Symbol),
1312}
1313
1314impl PreciseCapturingArg {
1315 pub(crate) fn name(self) -> Symbol {
1316 match self {
1317 PreciseCapturingArg::Lifetime(lt) => lt.0,
1318 PreciseCapturingArg::Param(param) => param,
1319 }
1320 }
1321}
1322
1323#[derive(Clone, PartialEq, Eq, Hash, Debug)]
1324pub(crate) enum WherePredicate {
1325 BoundPredicate { ty: Type, bounds: Vec<GenericBound>, bound_params: Vec<GenericParamDef> },
1326 RegionPredicate { lifetime: Lifetime, bounds: Vec<GenericBound> },
1327 EqPredicate { lhs: QPathData, rhs: Term },
1328}
1329
1330impl WherePredicate {
1331 pub(crate) fn get_bounds(&self) -> Option<&[GenericBound]> {
1332 match self {
1333 WherePredicate::BoundPredicate { bounds, .. } => Some(bounds),
1334 WherePredicate::RegionPredicate { bounds, .. } => Some(bounds),
1335 _ => None,
1336 }
1337 }
1338}
1339
1340#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1341pub(crate) enum GenericParamDefKind {
1342 Lifetime { outlives: ThinVec<Lifetime> },
1343 Type { bounds: ThinVec<GenericBound>, default: Option<Box<Type>>, synthetic: bool },
1344 Const { ty: Box<Type>, default: Option<Box<String>>, synthetic: bool },
1346}
1347
1348impl GenericParamDefKind {
1349 pub(crate) fn is_type(&self) -> bool {
1350 matches!(self, GenericParamDefKind::Type { .. })
1351 }
1352}
1353
1354#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1355pub(crate) struct GenericParamDef {
1356 pub(crate) name: Symbol,
1357 pub(crate) def_id: DefId,
1358 pub(crate) kind: GenericParamDefKind,
1359}
1360
1361impl GenericParamDef {
1362 pub(crate) fn lifetime(def_id: DefId, name: Symbol) -> Self {
1363 Self { name, def_id, kind: GenericParamDefKind::Lifetime { outlives: ThinVec::new() } }
1364 }
1365
1366 pub(crate) fn is_synthetic_param(&self) -> bool {
1367 match self.kind {
1368 GenericParamDefKind::Lifetime { .. } | GenericParamDefKind::Const { .. } => false,
1369 GenericParamDefKind::Type { synthetic, .. } => synthetic,
1370 }
1371 }
1372
1373 pub(crate) fn is_type(&self) -> bool {
1374 self.kind.is_type()
1375 }
1376
1377 pub(crate) fn get_bounds(&self) -> Option<&[GenericBound]> {
1378 match self.kind {
1379 GenericParamDefKind::Type { ref bounds, .. } => Some(bounds),
1380 _ => None,
1381 }
1382 }
1383}
1384
1385#[derive(Clone, PartialEq, Eq, Hash, Debug, Default)]
1387pub(crate) struct Generics {
1388 pub(crate) params: ThinVec<GenericParamDef>,
1389 pub(crate) where_predicates: ThinVec<WherePredicate>,
1390}
1391
1392impl Generics {
1393 pub(crate) fn is_empty(&self) -> bool {
1394 self.params.is_empty() && self.where_predicates.is_empty()
1395 }
1396}
1397
1398#[derive(Clone, Debug)]
1399pub(crate) struct Function {
1400 pub(crate) decl: FnDecl,
1401 pub(crate) generics: Generics,
1402}
1403
1404#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1405pub(crate) struct FnDecl {
1406 pub(crate) inputs: Vec<Parameter>,
1407 pub(crate) output: Type,
1408 pub(crate) c_variadic: bool,
1409}
1410
1411impl FnDecl {
1412 pub(crate) fn receiver_type(&self) -> Option<&Type> {
1413 self.inputs.first().and_then(|v| v.to_receiver())
1414 }
1415}
1416
1417#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1419pub(crate) struct Parameter {
1420 pub(crate) name: Option<Symbol>,
1421 pub(crate) type_: Type,
1422 pub(crate) is_const: bool,
1425}
1426
1427impl Parameter {
1428 pub(crate) fn to_receiver(&self) -> Option<&Type> {
1429 if self.name == Some(kw::SelfLower) { Some(&self.type_) } else { None }
1430 }
1431}
1432
1433#[derive(Clone, Debug)]
1434pub(crate) struct Trait {
1435 pub(crate) def_id: DefId,
1436 pub(crate) items: Vec<Item>,
1437 pub(crate) generics: Generics,
1438 pub(crate) bounds: Vec<GenericBound>,
1439}
1440
1441impl Trait {
1442 pub(crate) fn is_auto(&self, tcx: TyCtxt<'_>) -> bool {
1443 tcx.trait_is_auto(self.def_id)
1444 }
1445 pub(crate) fn is_notable_trait(&self, tcx: TyCtxt<'_>) -> bool {
1446 tcx.is_doc_notable_trait(self.def_id)
1447 }
1448 pub(crate) fn safety(&self, tcx: TyCtxt<'_>) -> hir::Safety {
1449 tcx.trait_def(self.def_id).safety
1450 }
1451 pub(crate) fn is_dyn_compatible(&self, tcx: TyCtxt<'_>) -> bool {
1452 tcx.is_dyn_compatible(self.def_id)
1453 }
1454}
1455
1456#[derive(Clone, Debug)]
1457pub(crate) struct TraitAlias {
1458 pub(crate) generics: Generics,
1459 pub(crate) bounds: Vec<GenericBound>,
1460}
1461
1462#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1464pub(crate) struct PolyTrait {
1465 pub(crate) trait_: Path,
1466 pub(crate) generic_params: Vec<GenericParamDef>,
1467}
1468
1469#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1471pub(crate) enum Type {
1472 Path {
1477 path: Path,
1478 },
1479 DynTrait(Vec<PolyTrait>, Option<Lifetime>),
1481 Generic(Symbol),
1483 SelfTy,
1485 Primitive(PrimitiveType),
1487 BareFunction(Box<BareFunctionDecl>),
1489 Tuple(Vec<Type>),
1491 Slice(Box<Type>),
1493 Array(Box<Type>, Box<str>),
1497 Pat(Box<Type>, Box<str>),
1498 RawPointer(Mutability, Box<Type>),
1500 BorrowedRef {
1502 lifetime: Option<Lifetime>,
1503 mutability: Mutability,
1504 type_: Box<Type>,
1505 },
1506
1507 QPath(Box<QPathData>),
1509
1510 Infer,
1512
1513 ImplTrait(Vec<GenericBound>),
1515
1516 UnsafeBinder(Box<UnsafeBinderTy>),
1517}
1518
1519impl Type {
1520 pub(crate) fn without_borrowed_ref(&self) -> &Type {
1522 let mut result = self;
1523 while let Type::BorrowedRef { type_, .. } = result {
1524 result = type_;
1525 }
1526 result
1527 }
1528
1529 pub(crate) fn is_borrowed_ref(&self) -> bool {
1530 matches!(self, Type::BorrowedRef { .. })
1531 }
1532
1533 fn is_type_alias(&self) -> bool {
1534 matches!(self, Type::Path { path: Path { res: Res::Def(DefKind::TyAlias, _), .. } })
1535 }
1536
1537 pub(crate) fn is_doc_subtype_of(&self, other: &Self, cache: &Cache) -> bool {
1558 let (self_cleared, other_cleared) = if !self.is_borrowed_ref() || !other.is_borrowed_ref() {
1561 (self.without_borrowed_ref(), other.without_borrowed_ref())
1562 } else {
1563 (self, other)
1564 };
1565
1566 if self_cleared.is_type_alias() || other_cleared.is_type_alias() {
1572 return true;
1573 }
1574
1575 match (self_cleared, other_cleared) {
1576 (Type::Tuple(a), Type::Tuple(b)) => {
1578 a.len() == b.len() && a.iter().zip(b).all(|(a, b)| a.is_doc_subtype_of(b, cache))
1579 }
1580 (Type::Slice(a), Type::Slice(b)) => a.is_doc_subtype_of(b, cache),
1581 (Type::Array(a, al), Type::Array(b, bl)) => al == bl && a.is_doc_subtype_of(b, cache),
1582 (Type::RawPointer(mutability, type_), Type::RawPointer(b_mutability, b_type_)) => {
1583 mutability == b_mutability && type_.is_doc_subtype_of(b_type_, cache)
1584 }
1585 (
1586 Type::BorrowedRef { mutability, type_, .. },
1587 Type::BorrowedRef { mutability: b_mutability, type_: b_type_, .. },
1588 ) => mutability == b_mutability && type_.is_doc_subtype_of(b_type_, cache),
1589 (Type::Infer, _) | (_, Type::Infer) => true,
1591 (_, Type::Generic(_)) => true,
1594 (Type::Generic(_), _) => false,
1595 (Type::SelfTy, Type::SelfTy) => true,
1597 (Type::Path { path: a }, Type::Path { path: b }) => {
1599 a.def_id() == b.def_id()
1600 && a.generics()
1601 .zip(b.generics())
1602 .map(|(ag, bg)| ag.zip(bg).all(|(at, bt)| at.is_doc_subtype_of(bt, cache)))
1603 .unwrap_or(true)
1604 }
1605 (a, b) => a
1607 .def_id(cache)
1608 .and_then(|a| Some((a, b.def_id(cache)?)))
1609 .map(|(a, b)| a == b)
1610 .unwrap_or(false),
1611 }
1612 }
1613
1614 pub(crate) fn primitive_type(&self) -> Option<PrimitiveType> {
1615 match *self {
1616 Primitive(p) | BorrowedRef { type_: box Primitive(p), .. } => Some(p),
1617 Slice(..) | BorrowedRef { type_: box Slice(..), .. } => Some(PrimitiveType::Slice),
1618 Array(..) | BorrowedRef { type_: box Array(..), .. } => Some(PrimitiveType::Array),
1619 Tuple(ref tys) => {
1620 if tys.is_empty() {
1621 Some(PrimitiveType::Unit)
1622 } else {
1623 Some(PrimitiveType::Tuple)
1624 }
1625 }
1626 RawPointer(..) => Some(PrimitiveType::RawPointer),
1627 BareFunction(..) => Some(PrimitiveType::Fn),
1628 _ => None,
1629 }
1630 }
1631
1632 pub(crate) fn sugared_async_return_type(self) -> Type {
1642 if let Type::ImplTrait(mut v) = self
1643 && let Some(GenericBound::TraitBound(PolyTrait { mut trait_, .. }, _)) = v.pop()
1644 && let Some(segment) = trait_.segments.pop()
1645 && let GenericArgs::AngleBracketed { mut constraints, .. } = segment.args
1646 && let Some(constraint) = constraints.pop()
1647 && let AssocItemConstraintKind::Equality { term } = constraint.kind
1648 && let Term::Type(ty) = term
1649 {
1650 ty
1651 } else {
1652 panic!("unexpected async fn return type")
1653 }
1654 }
1655
1656 pub(crate) fn is_assoc_ty(&self) -> bool {
1658 match self {
1659 Type::Path { path, .. } => path.is_assoc_ty(),
1660 _ => false,
1661 }
1662 }
1663
1664 pub(crate) fn is_self_type(&self) -> bool {
1665 matches!(*self, Type::SelfTy)
1666 }
1667
1668 pub(crate) fn generic_args(&self) -> Option<&GenericArgs> {
1669 match self {
1670 Type::Path { path, .. } => path.generic_args(),
1671 _ => None,
1672 }
1673 }
1674
1675 pub(crate) fn generics(&self) -> Option<impl Iterator<Item = &Type>> {
1676 match self {
1677 Type::Path { path, .. } => path.generics(),
1678 _ => None,
1679 }
1680 }
1681
1682 pub(crate) fn is_full_generic(&self) -> bool {
1683 matches!(self, Type::Generic(_))
1684 }
1685
1686 pub(crate) fn is_unit(&self) -> bool {
1687 matches!(self, Type::Tuple(v) if v.is_empty())
1688 }
1689
1690 pub(crate) fn def_id(&self, cache: &Cache) -> Option<DefId> {
1694 let t: PrimitiveType = match self {
1695 Type::Path { path } => return Some(path.def_id()),
1696 DynTrait(bounds, _) => return bounds.first().map(|b| b.trait_.def_id()),
1697 Primitive(p) => return cache.primitive_locations.get(p).cloned(),
1698 BorrowedRef { type_: box Generic(..), .. } => PrimitiveType::Reference,
1699 BorrowedRef { type_, .. } => return type_.def_id(cache),
1700 Tuple(tys) => {
1701 if tys.is_empty() {
1702 PrimitiveType::Unit
1703 } else {
1704 PrimitiveType::Tuple
1705 }
1706 }
1707 BareFunction(..) => PrimitiveType::Fn,
1708 Slice(..) => PrimitiveType::Slice,
1709 Array(..) => PrimitiveType::Array,
1710 Type::Pat(..) => PrimitiveType::Pat,
1711 RawPointer(..) => PrimitiveType::RawPointer,
1712 QPath(box QPathData { self_type, .. }) => return self_type.def_id(cache),
1713 Generic(_) | SelfTy | Infer | ImplTrait(_) | UnsafeBinder(_) => return None,
1714 };
1715 Primitive(t).def_id(cache)
1716 }
1717}
1718
1719#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1720pub(crate) struct QPathData {
1721 pub assoc: PathSegment,
1722 pub self_type: Type,
1723 pub should_fully_qualify: bool,
1725 pub trait_: Option<Path>,
1726}
1727
1728#[derive(Clone, PartialEq, Eq, Hash, Copy, Debug)]
1735pub(crate) enum PrimitiveType {
1736 Isize,
1737 I8,
1738 I16,
1739 I32,
1740 I64,
1741 I128,
1742 Usize,
1743 U8,
1744 U16,
1745 U32,
1746 U64,
1747 U128,
1748 F16,
1749 F32,
1750 F64,
1751 F128,
1752 Char,
1753 Bool,
1754 Str,
1755 Slice,
1756 Array,
1757 Pat,
1758 Tuple,
1759 Unit,
1760 RawPointer,
1761 Reference,
1762 Fn,
1763 Never,
1764}
1765
1766type SimplifiedTypes = FxIndexMap<PrimitiveType, ArrayVec<SimplifiedType, 3>>;
1767impl PrimitiveType {
1768 pub(crate) fn from_hir(prim: hir::PrimTy) -> PrimitiveType {
1769 use ast::{FloatTy, IntTy, UintTy};
1770 match prim {
1771 hir::PrimTy::Int(IntTy::Isize) => PrimitiveType::Isize,
1772 hir::PrimTy::Int(IntTy::I8) => PrimitiveType::I8,
1773 hir::PrimTy::Int(IntTy::I16) => PrimitiveType::I16,
1774 hir::PrimTy::Int(IntTy::I32) => PrimitiveType::I32,
1775 hir::PrimTy::Int(IntTy::I64) => PrimitiveType::I64,
1776 hir::PrimTy::Int(IntTy::I128) => PrimitiveType::I128,
1777 hir::PrimTy::Uint(UintTy::Usize) => PrimitiveType::Usize,
1778 hir::PrimTy::Uint(UintTy::U8) => PrimitiveType::U8,
1779 hir::PrimTy::Uint(UintTy::U16) => PrimitiveType::U16,
1780 hir::PrimTy::Uint(UintTy::U32) => PrimitiveType::U32,
1781 hir::PrimTy::Uint(UintTy::U64) => PrimitiveType::U64,
1782 hir::PrimTy::Uint(UintTy::U128) => PrimitiveType::U128,
1783 hir::PrimTy::Float(FloatTy::F16) => PrimitiveType::F16,
1784 hir::PrimTy::Float(FloatTy::F32) => PrimitiveType::F32,
1785 hir::PrimTy::Float(FloatTy::F64) => PrimitiveType::F64,
1786 hir::PrimTy::Float(FloatTy::F128) => PrimitiveType::F128,
1787 hir::PrimTy::Str => PrimitiveType::Str,
1788 hir::PrimTy::Bool => PrimitiveType::Bool,
1789 hir::PrimTy::Char => PrimitiveType::Char,
1790 }
1791 }
1792
1793 pub(crate) fn from_symbol(s: Symbol) -> Option<PrimitiveType> {
1794 match s {
1795 sym::isize => Some(PrimitiveType::Isize),
1796 sym::i8 => Some(PrimitiveType::I8),
1797 sym::i16 => Some(PrimitiveType::I16),
1798 sym::i32 => Some(PrimitiveType::I32),
1799 sym::i64 => Some(PrimitiveType::I64),
1800 sym::i128 => Some(PrimitiveType::I128),
1801 sym::usize => Some(PrimitiveType::Usize),
1802 sym::u8 => Some(PrimitiveType::U8),
1803 sym::u16 => Some(PrimitiveType::U16),
1804 sym::u32 => Some(PrimitiveType::U32),
1805 sym::u64 => Some(PrimitiveType::U64),
1806 sym::u128 => Some(PrimitiveType::U128),
1807 sym::bool => Some(PrimitiveType::Bool),
1808 sym::char => Some(PrimitiveType::Char),
1809 sym::str => Some(PrimitiveType::Str),
1810 sym::f16 => Some(PrimitiveType::F16),
1811 sym::f32 => Some(PrimitiveType::F32),
1812 sym::f64 => Some(PrimitiveType::F64),
1813 sym::f128 => Some(PrimitiveType::F128),
1814 sym::array => Some(PrimitiveType::Array),
1815 sym::slice => Some(PrimitiveType::Slice),
1816 sym::tuple => Some(PrimitiveType::Tuple),
1817 sym::unit => Some(PrimitiveType::Unit),
1818 sym::pointer => Some(PrimitiveType::RawPointer),
1819 sym::reference => Some(PrimitiveType::Reference),
1820 kw::Fn => Some(PrimitiveType::Fn),
1821 sym::never => Some(PrimitiveType::Never),
1822 _ => None,
1823 }
1824 }
1825
1826 pub(crate) fn simplified_types() -> &'static SimplifiedTypes {
1827 use PrimitiveType::*;
1828 use ty::{FloatTy, IntTy, UintTy};
1829 static CELL: OnceCell<SimplifiedTypes> = OnceCell::new();
1830
1831 let single = |x| iter::once(x).collect();
1832 CELL.get_or_init(move || {
1833 map! {
1834 Isize => single(SimplifiedType::Int(IntTy::Isize)),
1835 I8 => single(SimplifiedType::Int(IntTy::I8)),
1836 I16 => single(SimplifiedType::Int(IntTy::I16)),
1837 I32 => single(SimplifiedType::Int(IntTy::I32)),
1838 I64 => single(SimplifiedType::Int(IntTy::I64)),
1839 I128 => single(SimplifiedType::Int(IntTy::I128)),
1840 Usize => single(SimplifiedType::Uint(UintTy::Usize)),
1841 U8 => single(SimplifiedType::Uint(UintTy::U8)),
1842 U16 => single(SimplifiedType::Uint(UintTy::U16)),
1843 U32 => single(SimplifiedType::Uint(UintTy::U32)),
1844 U64 => single(SimplifiedType::Uint(UintTy::U64)),
1845 U128 => single(SimplifiedType::Uint(UintTy::U128)),
1846 F16 => single(SimplifiedType::Float(FloatTy::F16)),
1847 F32 => single(SimplifiedType::Float(FloatTy::F32)),
1848 F64 => single(SimplifiedType::Float(FloatTy::F64)),
1849 F128 => single(SimplifiedType::Float(FloatTy::F128)),
1850 Str => single(SimplifiedType::Str),
1851 Bool => single(SimplifiedType::Bool),
1852 Char => single(SimplifiedType::Char),
1853 Array => single(SimplifiedType::Array),
1854 Slice => single(SimplifiedType::Slice),
1855 Tuple => [SimplifiedType::Tuple(1), SimplifiedType::Tuple(2), SimplifiedType::Tuple(3)].into(),
1861 Unit => single(SimplifiedType::Tuple(0)),
1862 RawPointer => [SimplifiedType::Ptr(Mutability::Not), SimplifiedType::Ptr(Mutability::Mut)].into_iter().collect(),
1863 Reference => [SimplifiedType::Ref(Mutability::Not), SimplifiedType::Ref(Mutability::Mut)].into_iter().collect(),
1864 Fn => single(SimplifiedType::Function(1)),
1867 Never => single(SimplifiedType::Never),
1868 }
1869 })
1870 }
1871
1872 pub(crate) fn impls<'tcx>(&self, tcx: TyCtxt<'tcx>) -> impl Iterator<Item = DefId> + 'tcx {
1873 Self::simplified_types()
1874 .get(self)
1875 .into_iter()
1876 .flatten()
1877 .flat_map(move |&simp| tcx.incoherent_impls(simp).iter())
1878 .copied()
1879 }
1880
1881 pub(crate) fn all_impls(tcx: TyCtxt<'_>) -> impl Iterator<Item = DefId> {
1882 Self::simplified_types()
1883 .values()
1884 .flatten()
1885 .flat_map(move |&simp| tcx.incoherent_impls(simp).iter())
1886 .copied()
1887 }
1888
1889 pub(crate) fn as_sym(&self) -> Symbol {
1890 use PrimitiveType::*;
1891 match self {
1892 Isize => sym::isize,
1893 I8 => sym::i8,
1894 I16 => sym::i16,
1895 I32 => sym::i32,
1896 I64 => sym::i64,
1897 I128 => sym::i128,
1898 Usize => sym::usize,
1899 U8 => sym::u8,
1900 U16 => sym::u16,
1901 U32 => sym::u32,
1902 U64 => sym::u64,
1903 U128 => sym::u128,
1904 F16 => sym::f16,
1905 F32 => sym::f32,
1906 F64 => sym::f64,
1907 F128 => sym::f128,
1908 Str => sym::str,
1909 Bool => sym::bool,
1910 Char => sym::char,
1911 Array => sym::array,
1912 Pat => sym::pat,
1913 Slice => sym::slice,
1914 Tuple => sym::tuple,
1915 Unit => sym::unit,
1916 RawPointer => sym::pointer,
1917 Reference => sym::reference,
1918 Fn => kw::Fn,
1919 Never => sym::never,
1920 }
1921 }
1922
1923 pub(crate) fn primitive_locations(tcx: TyCtxt<'_>) -> &FxIndexMap<PrimitiveType, DefId> {
1935 static PRIMITIVE_LOCATIONS: OnceCell<FxIndexMap<PrimitiveType, DefId>> = OnceCell::new();
1936 PRIMITIVE_LOCATIONS.get_or_init(|| {
1937 let mut primitive_locations = FxIndexMap::default();
1938 for &crate_num in tcx.crates(()) {
1941 let e = ExternalCrate { crate_num };
1942 let crate_name = e.name(tcx);
1943 debug!(?crate_num, ?crate_name);
1944 for (def_id, prim) in e.primitives(tcx) {
1945 if crate_name == sym::core && primitive_locations.contains_key(&prim) {
1947 continue;
1948 }
1949 primitive_locations.insert(prim, def_id);
1950 }
1951 }
1952 let local_primitives = ExternalCrate { crate_num: LOCAL_CRATE }.primitives(tcx);
1953 for (def_id, prim) in local_primitives {
1954 primitive_locations.insert(prim, def_id);
1955 }
1956 primitive_locations
1957 })
1958 }
1959}
1960
1961impl From<ty::IntTy> for PrimitiveType {
1962 fn from(int_ty: ty::IntTy) -> PrimitiveType {
1963 match int_ty {
1964 ty::IntTy::Isize => PrimitiveType::Isize,
1965 ty::IntTy::I8 => PrimitiveType::I8,
1966 ty::IntTy::I16 => PrimitiveType::I16,
1967 ty::IntTy::I32 => PrimitiveType::I32,
1968 ty::IntTy::I64 => PrimitiveType::I64,
1969 ty::IntTy::I128 => PrimitiveType::I128,
1970 }
1971 }
1972}
1973
1974impl From<ty::UintTy> for PrimitiveType {
1975 fn from(uint_ty: ty::UintTy) -> PrimitiveType {
1976 match uint_ty {
1977 ty::UintTy::Usize => PrimitiveType::Usize,
1978 ty::UintTy::U8 => PrimitiveType::U8,
1979 ty::UintTy::U16 => PrimitiveType::U16,
1980 ty::UintTy::U32 => PrimitiveType::U32,
1981 ty::UintTy::U64 => PrimitiveType::U64,
1982 ty::UintTy::U128 => PrimitiveType::U128,
1983 }
1984 }
1985}
1986
1987impl From<ty::FloatTy> for PrimitiveType {
1988 fn from(float_ty: ty::FloatTy) -> PrimitiveType {
1989 match float_ty {
1990 ty::FloatTy::F16 => PrimitiveType::F16,
1991 ty::FloatTy::F32 => PrimitiveType::F32,
1992 ty::FloatTy::F64 => PrimitiveType::F64,
1993 ty::FloatTy::F128 => PrimitiveType::F128,
1994 }
1995 }
1996}
1997
1998impl From<hir::PrimTy> for PrimitiveType {
1999 fn from(prim_ty: hir::PrimTy) -> PrimitiveType {
2000 match prim_ty {
2001 hir::PrimTy::Int(int_ty) => int_ty.into(),
2002 hir::PrimTy::Uint(uint_ty) => uint_ty.into(),
2003 hir::PrimTy::Float(float_ty) => float_ty.into(),
2004 hir::PrimTy::Str => PrimitiveType::Str,
2005 hir::PrimTy::Bool => PrimitiveType::Bool,
2006 hir::PrimTy::Char => PrimitiveType::Char,
2007 }
2008 }
2009}
2010
2011#[derive(Clone, Debug)]
2012pub(crate) struct Struct {
2013 pub(crate) ctor_kind: Option<CtorKind>,
2014 pub(crate) generics: Generics,
2015 pub(crate) fields: ThinVec<Item>,
2016}
2017
2018impl Struct {
2019 pub(crate) fn has_stripped_entries(&self) -> bool {
2020 self.fields.iter().any(|f| f.is_stripped())
2021 }
2022}
2023
2024#[derive(Clone, Debug)]
2025pub(crate) struct Union {
2026 pub(crate) generics: Generics,
2027 pub(crate) fields: Vec<Item>,
2028}
2029
2030impl Union {
2031 pub(crate) fn has_stripped_entries(&self) -> bool {
2032 self.fields.iter().any(|f| f.is_stripped())
2033 }
2034}
2035
2036#[derive(Clone, Debug)]
2040pub(crate) struct VariantStruct {
2041 pub(crate) fields: ThinVec<Item>,
2042}
2043
2044impl VariantStruct {
2045 pub(crate) fn has_stripped_entries(&self) -> bool {
2046 self.fields.iter().any(|f| f.is_stripped())
2047 }
2048}
2049
2050#[derive(Clone, Debug)]
2051pub(crate) struct Enum {
2052 pub(crate) variants: IndexVec<VariantIdx, Item>,
2053 pub(crate) generics: Generics,
2054}
2055
2056impl Enum {
2057 pub(crate) fn has_stripped_entries(&self) -> bool {
2058 self.variants.iter().any(|f| f.is_stripped())
2059 }
2060
2061 pub(crate) fn non_stripped_variants(&self) -> impl Iterator<Item = &Item> {
2062 self.variants.iter().filter(|v| !v.is_stripped())
2063 }
2064}
2065
2066#[derive(Clone, Debug)]
2067pub(crate) struct Variant {
2068 pub kind: VariantKind,
2069 pub discriminant: Option<Discriminant>,
2070}
2071
2072#[derive(Clone, Debug)]
2073pub(crate) enum VariantKind {
2074 CLike,
2075 Tuple(ThinVec<Item>),
2076 Struct(VariantStruct),
2077}
2078
2079impl Variant {
2080 pub(crate) fn has_stripped_entries(&self) -> Option<bool> {
2081 match &self.kind {
2082 VariantKind::Struct(struct_) => Some(struct_.has_stripped_entries()),
2083 VariantKind::CLike | VariantKind::Tuple(_) => None,
2084 }
2085 }
2086}
2087
2088#[derive(Clone, Debug)]
2089pub(crate) struct Discriminant {
2090 pub(super) expr: Option<BodyId>,
2093 pub(super) value: DefId,
2094}
2095
2096impl Discriminant {
2097 pub(crate) fn expr(&self, tcx: TyCtxt<'_>) -> Option<String> {
2100 self.expr
2101 .map(|body| rendered_const(tcx, tcx.hir_body(body), tcx.hir_body_owner_def_id(body)))
2102 }
2103 pub(crate) fn value(&self, tcx: TyCtxt<'_>, with_underscores: bool) -> String {
2104 print_evaluated_const(tcx, self.value, with_underscores, false).unwrap()
2105 }
2106}
2107
2108#[derive(Copy, Clone, Debug)]
2111pub(crate) struct Span(rustc_span::Span);
2112
2113impl Span {
2114 pub(crate) fn new(sp: rustc_span::Span) -> Self {
2119 Self(sp.source_callsite())
2120 }
2121
2122 pub(crate) fn inner(&self) -> rustc_span::Span {
2123 self.0
2124 }
2125
2126 pub(crate) fn filename(&self, sess: &Session) -> FileName {
2127 sess.source_map().span_to_filename(self.0)
2128 }
2129
2130 pub(crate) fn lo(&self, sess: &Session) -> Loc {
2131 sess.source_map().lookup_char_pos(self.0.lo())
2132 }
2133
2134 pub(crate) fn hi(&self, sess: &Session) -> Loc {
2135 sess.source_map().lookup_char_pos(self.0.hi())
2136 }
2137
2138 pub(crate) fn cnum(&self, sess: &Session) -> CrateNum {
2139 self.lo(sess).file.cnum
2141 }
2142}
2143
2144#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2145pub(crate) struct Path {
2146 pub(crate) res: Res,
2147 pub(crate) segments: ThinVec<PathSegment>,
2148}
2149
2150impl Path {
2151 pub(crate) fn def_id(&self) -> DefId {
2152 self.res.def_id()
2153 }
2154
2155 pub(crate) fn last_opt(&self) -> Option<Symbol> {
2156 self.segments.last().map(|s| s.name)
2157 }
2158
2159 pub(crate) fn last(&self) -> Symbol {
2160 self.last_opt().expect("segments were empty")
2161 }
2162
2163 pub(crate) fn whole_name(&self) -> String {
2164 self.segments
2165 .iter()
2166 .map(|s| if s.name == kw::PathRoot { "" } else { s.name.as_str() })
2167 .intersperse("::")
2168 .collect()
2169 }
2170
2171 pub(crate) fn is_assoc_ty(&self) -> bool {
2173 match self.res {
2174 Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } | Res::Def(DefKind::TyParam, _)
2175 if self.segments.len() != 1 =>
2176 {
2177 true
2178 }
2179 Res::Def(DefKind::AssocTy, _) => true,
2180 _ => false,
2181 }
2182 }
2183
2184 pub(crate) fn generic_args(&self) -> Option<&GenericArgs> {
2185 self.segments.last().map(|seg| &seg.args)
2186 }
2187
2188 pub(crate) fn generics(&self) -> Option<impl Iterator<Item = &Type>> {
2189 self.segments.last().and_then(|seg| {
2190 if let GenericArgs::AngleBracketed { ref args, .. } = seg.args {
2191 Some(args.iter().filter_map(|arg| match arg {
2192 GenericArg::Type(ty) => Some(ty),
2193 _ => None,
2194 }))
2195 } else {
2196 None
2197 }
2198 })
2199 }
2200}
2201
2202#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2203pub(crate) enum GenericArg {
2204 Lifetime(Lifetime),
2205 Type(Type),
2206 Const(Box<ConstantKind>),
2207 Infer,
2208}
2209
2210impl GenericArg {
2211 pub(crate) fn as_lt(&self) -> Option<&Lifetime> {
2212 if let Self::Lifetime(lt) = self { Some(lt) } else { None }
2213 }
2214
2215 pub(crate) fn as_ty(&self) -> Option<&Type> {
2216 if let Self::Type(ty) = self { Some(ty) } else { None }
2217 }
2218}
2219
2220#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2221pub(crate) enum GenericArgs {
2222 AngleBracketed { args: ThinVec<GenericArg>, constraints: ThinVec<AssocItemConstraint> },
2224 Parenthesized { inputs: ThinVec<Type>, output: Option<Box<Type>> },
2226 ReturnTypeNotation,
2228}
2229
2230impl GenericArgs {
2231 pub(crate) fn is_empty(&self) -> bool {
2232 match self {
2233 GenericArgs::AngleBracketed { args, constraints } => {
2234 args.is_empty() && constraints.is_empty()
2235 }
2236 GenericArgs::Parenthesized { inputs, output } => inputs.is_empty() && output.is_none(),
2237 GenericArgs::ReturnTypeNotation => false,
2238 }
2239 }
2240 pub(crate) fn constraints(&self) -> Box<dyn Iterator<Item = AssocItemConstraint> + '_> {
2241 match self {
2242 GenericArgs::AngleBracketed { constraints, .. } => {
2243 Box::new(constraints.iter().cloned())
2244 }
2245 GenericArgs::Parenthesized { output, .. } => Box::new(
2246 output
2247 .as_ref()
2248 .map(|ty| AssocItemConstraint {
2249 assoc: PathSegment {
2250 name: sym::Output,
2251 args: GenericArgs::AngleBracketed {
2252 args: ThinVec::new(),
2253 constraints: ThinVec::new(),
2254 },
2255 },
2256 kind: AssocItemConstraintKind::Equality {
2257 term: Term::Type((**ty).clone()),
2258 },
2259 })
2260 .into_iter(),
2261 ),
2262 GenericArgs::ReturnTypeNotation => Box::new([].into_iter()),
2263 }
2264 }
2265}
2266
2267impl<'a> IntoIterator for &'a GenericArgs {
2268 type IntoIter = Box<dyn Iterator<Item = GenericArg> + 'a>;
2269 type Item = GenericArg;
2270 fn into_iter(self) -> Self::IntoIter {
2271 match self {
2272 GenericArgs::AngleBracketed { args, .. } => Box::new(args.iter().cloned()),
2273 GenericArgs::Parenthesized { inputs, .. } => {
2274 Box::new(inputs.iter().cloned().map(GenericArg::Type))
2276 }
2277 GenericArgs::ReturnTypeNotation => Box::new([].into_iter()),
2278 }
2279 }
2280}
2281
2282#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2283pub(crate) struct PathSegment {
2284 pub(crate) name: Symbol,
2285 pub(crate) args: GenericArgs,
2286}
2287
2288#[derive(Clone, Debug)]
2289pub(crate) enum TypeAliasInnerType {
2290 Enum { variants: IndexVec<VariantIdx, Item>, is_non_exhaustive: bool },
2291 Union { fields: Vec<Item> },
2292 Struct { ctor_kind: Option<CtorKind>, fields: Vec<Item> },
2293}
2294
2295impl TypeAliasInnerType {
2296 fn has_stripped_entries(&self) -> Option<bool> {
2297 Some(match self {
2298 Self::Enum { variants, .. } => variants.iter().any(|v| v.is_stripped()),
2299 Self::Union { fields } | Self::Struct { fields, .. } => {
2300 fields.iter().any(|f| f.is_stripped())
2301 }
2302 })
2303 }
2304}
2305
2306#[derive(Clone, Debug)]
2307pub(crate) struct TypeAlias {
2308 pub(crate) type_: Type,
2309 pub(crate) generics: Generics,
2310 pub(crate) inner_type: Option<TypeAliasInnerType>,
2313 pub(crate) item_type: Option<Type>,
2320}
2321
2322#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2323pub(crate) struct BareFunctionDecl {
2324 pub(crate) safety: hir::Safety,
2325 pub(crate) generic_params: Vec<GenericParamDef>,
2326 pub(crate) decl: FnDecl,
2327 pub(crate) abi: ExternAbi,
2328}
2329
2330#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2331pub(crate) struct UnsafeBinderTy {
2332 pub(crate) generic_params: Vec<GenericParamDef>,
2333 pub(crate) ty: Type,
2334}
2335
2336#[derive(Clone, Debug)]
2337pub(crate) struct Static {
2338 pub(crate) type_: Box<Type>,
2339 pub(crate) mutability: Mutability,
2340 pub(crate) expr: Option<BodyId>,
2341}
2342
2343#[derive(Clone, PartialEq, Eq, Hash, Debug)]
2344pub(crate) struct Constant {
2345 pub(crate) generics: Generics,
2346 pub(crate) kind: ConstantKind,
2347 pub(crate) type_: Type,
2348}
2349
2350#[derive(Clone, PartialEq, Eq, Hash, Debug)]
2351pub(crate) enum Term {
2352 Type(Type),
2353 Constant(ConstantKind),
2354}
2355
2356impl Term {
2357 pub(crate) fn ty(&self) -> Option<&Type> {
2358 if let Term::Type(ty) = self { Some(ty) } else { None }
2359 }
2360}
2361
2362impl From<Type> for Term {
2363 fn from(ty: Type) -> Self {
2364 Term::Type(ty)
2365 }
2366}
2367
2368#[derive(Clone, PartialEq, Eq, Hash, Debug)]
2369pub(crate) enum ConstantKind {
2370 TyConst { expr: Box<str> },
2376 Path { path: Box<str> },
2379 Anonymous { body: BodyId },
2383 Extern { def_id: DefId },
2385 Local { def_id: DefId, body: BodyId },
2387 Infer,
2389}
2390
2391impl ConstantKind {
2392 pub(crate) fn expr(&self, tcx: TyCtxt<'_>) -> String {
2393 match *self {
2394 ConstantKind::TyConst { ref expr } => expr.to_string(),
2395 ConstantKind::Path { ref path } => path.to_string(),
2396 ConstantKind::Extern { def_id } => print_inlined_const(tcx, def_id),
2397 ConstantKind::Local { body, .. } | ConstantKind::Anonymous { body } => {
2398 rendered_const(tcx, tcx.hir_body(body), tcx.hir_body_owner_def_id(body))
2399 }
2400 ConstantKind::Infer => "_".to_string(),
2401 }
2402 }
2403
2404 pub(crate) fn value(&self, tcx: TyCtxt<'_>) -> Option<String> {
2405 match *self {
2406 ConstantKind::TyConst { .. }
2407 | ConstantKind::Path { .. }
2408 | ConstantKind::Anonymous { .. }
2409 | ConstantKind::Infer => None,
2410 ConstantKind::Extern { def_id } | ConstantKind::Local { def_id, .. } => {
2411 print_evaluated_const(tcx, def_id, true, true)
2412 }
2413 }
2414 }
2415
2416 pub(crate) fn is_literal(&self, tcx: TyCtxt<'_>) -> bool {
2417 match *self {
2418 ConstantKind::TyConst { .. }
2419 | ConstantKind::Extern { .. }
2420 | ConstantKind::Path { .. }
2421 | ConstantKind::Infer => false,
2422 ConstantKind::Local { body, .. } | ConstantKind::Anonymous { body } => {
2423 is_literal_expr(tcx, body.hir_id)
2424 }
2425 }
2426 }
2427}
2428
2429#[derive(Clone, Debug)]
2430pub(crate) struct Impl {
2431 pub(crate) safety: hir::Safety,
2432 pub(crate) generics: Generics,
2433 pub(crate) trait_: Option<Path>,
2434 pub(crate) for_: Type,
2435 pub(crate) items: Vec<Item>,
2436 pub(crate) polarity: ty::ImplPolarity,
2437 pub(crate) kind: ImplKind,
2438}
2439
2440impl Impl {
2441 pub(crate) fn provided_trait_methods(&self, tcx: TyCtxt<'_>) -> FxIndexSet<Symbol> {
2442 self.trait_
2443 .as_ref()
2444 .map(|t| t.def_id())
2445 .map(|did| tcx.provided_trait_methods(did).map(|meth| meth.name()).collect())
2446 .unwrap_or_default()
2447 }
2448
2449 pub(crate) fn is_negative_trait_impl(&self) -> bool {
2450 matches!(self.polarity, ty::ImplPolarity::Negative)
2451 }
2452}
2453
2454#[derive(Clone, Debug)]
2455pub(crate) enum ImplKind {
2456 Normal,
2457 Auto,
2458 FakeVariadic,
2459 Blanket(Box<Type>),
2460}
2461
2462impl ImplKind {
2463 pub(crate) fn is_auto(&self) -> bool {
2464 matches!(self, ImplKind::Auto)
2465 }
2466
2467 pub(crate) fn is_blanket(&self) -> bool {
2468 matches!(self, ImplKind::Blanket(_))
2469 }
2470
2471 pub(crate) fn is_fake_variadic(&self) -> bool {
2472 matches!(self, ImplKind::FakeVariadic)
2473 }
2474
2475 pub(crate) fn as_blanket_ty(&self) -> Option<&Type> {
2476 match self {
2477 ImplKind::Blanket(ty) => Some(ty),
2478 _ => None,
2479 }
2480 }
2481}
2482
2483#[derive(Clone, Debug)]
2484pub(crate) struct Import {
2485 pub(crate) kind: ImportKind,
2486 pub(crate) source: ImportSource,
2488 pub(crate) should_be_displayed: bool,
2489}
2490
2491impl Import {
2492 pub(crate) fn new_simple(
2493 name: Symbol,
2494 source: ImportSource,
2495 should_be_displayed: bool,
2496 ) -> Self {
2497 Self { kind: ImportKind::Simple(name), source, should_be_displayed }
2498 }
2499
2500 pub(crate) fn new_glob(source: ImportSource, should_be_displayed: bool) -> Self {
2501 Self { kind: ImportKind::Glob, source, should_be_displayed }
2502 }
2503
2504 pub(crate) fn imported_item_is_doc_hidden(&self, tcx: TyCtxt<'_>) -> bool {
2505 self.source.did.is_some_and(|did| tcx.is_doc_hidden(did))
2506 }
2507}
2508
2509#[derive(Clone, Debug)]
2510pub(crate) enum ImportKind {
2511 Simple(Symbol),
2513 Glob,
2515}
2516
2517#[derive(Clone, Debug)]
2518pub(crate) struct ImportSource {
2519 pub(crate) path: Path,
2520 pub(crate) did: Option<DefId>,
2521}
2522
2523#[derive(Clone, Debug)]
2524pub(crate) struct Macro {
2525 pub(crate) source: String,
2526 pub(crate) macro_rules: bool,
2528}
2529
2530#[derive(Clone, Debug)]
2531pub(crate) struct ProcMacro {
2532 pub(crate) kind: MacroKind,
2533 pub(crate) helpers: Vec<Symbol>,
2534}
2535
2536#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2547pub(crate) struct AssocItemConstraint {
2548 pub(crate) assoc: PathSegment,
2549 pub(crate) kind: AssocItemConstraintKind,
2550}
2551
2552#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2554pub(crate) enum AssocItemConstraintKind {
2555 Equality { term: Term },
2556 Bound { bounds: Vec<GenericBound> },
2557}
2558
2559#[cfg(target_pointer_width = "64")]
2561mod size_asserts {
2562 use rustc_data_structures::static_assert_size;
2563
2564 use super::*;
2565 static_assert_size!(Crate, 16); static_assert_size!(DocFragment, 32);
2568 static_assert_size!(GenericArg, 32);
2569 static_assert_size!(GenericArgs, 24);
2570 static_assert_size!(GenericParamDef, 40);
2571 static_assert_size!(Generics, 16);
2572 static_assert_size!(Item, 8);
2573 static_assert_size!(ItemInner, 144);
2574 static_assert_size!(ItemKind, 48);
2575 static_assert_size!(PathSegment, 32);
2576 static_assert_size!(Type, 32);
2577 }