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 self.retrieve_keywords_or_documented_attributes(tcx, sym::keyword)
230 }
231 pub(crate) fn documented_attributes(
232 &self,
233 tcx: TyCtxt<'_>,
234 ) -> impl Iterator<Item = (DefId, Symbol)> {
235 self.retrieve_keywords_or_documented_attributes(tcx, sym::attribute)
236 }
237
238 fn retrieve_keywords_or_documented_attributes(
239 &self,
240 tcx: TyCtxt<'_>,
241 name: Symbol,
242 ) -> impl Iterator<Item = (DefId, Symbol)> {
243 let as_target = move |did: DefId, tcx: TyCtxt<'_>| -> Option<(DefId, Symbol)> {
244 tcx.get_attrs(did, sym::doc)
245 .flat_map(|attr| attr.meta_item_list().unwrap_or_default())
246 .filter(|meta| meta.has_name(name))
247 .find_map(|meta| meta.value_str())
248 .map(|value| (did, value))
249 };
250 self.mapped_root_modules(tcx, as_target)
251 }
252
253 pub(crate) fn primitives(
254 &self,
255 tcx: TyCtxt<'_>,
256 ) -> impl Iterator<Item = (DefId, PrimitiveType)> {
257 fn as_primitive(def_id: DefId, tcx: TyCtxt<'_>) -> Option<(DefId, PrimitiveType)> {
275 tcx.get_attrs(def_id, sym::rustc_doc_primitive).next().map(|attr| {
276 let attr_value = attr.value_str().expect("syntax should already be validated");
277 let Some(prim) = PrimitiveType::from_symbol(attr_value) else {
278 span_bug!(
279 attr.span(),
280 "primitive `{attr_value}` is not a member of `PrimitiveType`"
281 );
282 };
283
284 (def_id, prim)
285 })
286 }
287
288 self.mapped_root_modules(tcx, as_primitive)
289 }
290}
291
292#[derive(Debug)]
294pub(crate) enum ExternalLocation {
295 Remote(String),
297 Local,
299 Unknown,
301}
302
303#[derive(Clone)]
307pub(crate) struct Item {
308 pub(crate) inner: Box<ItemInner>,
309}
310
311#[derive(Clone)]
317pub(crate) struct ItemInner {
318 pub(crate) name: Option<Symbol>,
321 pub(crate) kind: ItemKind,
324 pub(crate) attrs: Attributes,
325 pub(crate) stability: Option<Stability>,
327 pub(crate) item_id: ItemId,
328 pub(crate) inline_stmt_id: Option<LocalDefId>,
332 pub(crate) cfg: Option<Arc<Cfg>>,
333}
334
335impl std::ops::Deref for Item {
336 type Target = ItemInner;
337 fn deref(&self) -> &ItemInner {
338 &self.inner
339 }
340}
341
342impl fmt::Debug for Item {
345 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
346 let alternate = f.alternate();
347 let mut fmt = f.debug_struct("Item");
349 fmt.field("name", &self.name).field("item_id", &self.item_id);
350 if alternate {
352 fmt.field("attrs", &self.attrs).field("kind", &self.kind).field("cfg", &self.cfg);
353 } else {
354 fmt.field("kind", &self.type_());
355 fmt.field("docs", &self.doc_value());
356 }
357 fmt.finish()
358 }
359}
360
361pub(crate) fn rustc_span(def_id: DefId, tcx: TyCtxt<'_>) -> Span {
362 Span::new(def_id.as_local().map_or_else(
363 || tcx.def_span(def_id),
364 |local| tcx.hir_span_with_body(tcx.local_def_id_to_hir_id(local)),
365 ))
366}
367
368fn is_field_vis_inherited(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
369 let parent = tcx.parent(def_id);
370 match tcx.def_kind(parent) {
371 DefKind::Struct | DefKind::Union => false,
372 DefKind::Variant => true,
373 parent_kind => panic!("unexpected parent kind: {parent_kind:?}"),
374 }
375}
376
377impl Item {
378 pub(crate) fn stability(&self, tcx: TyCtxt<'_>) -> Option<Stability> {
382 let stability = self.inner.stability;
383 debug_assert!(
384 stability.is_some()
385 || self.def_id().is_none_or(|did| tcx.lookup_stability(did).is_none()),
386 "missing stability for cleaned item: {self:?}",
387 );
388 stability
389 }
390
391 pub(crate) fn const_stability(&self, tcx: TyCtxt<'_>) -> Option<ConstStability> {
392 self.def_id().and_then(|did| tcx.lookup_const_stability(did))
393 }
394
395 pub(crate) fn deprecation(&self, tcx: TyCtxt<'_>) -> Option<Deprecation> {
396 self.def_id().and_then(|did| tcx.lookup_deprecation(did)).or_else(|| {
397 let stab = self.stability(tcx)?;
401 if let rustc_hir::StabilityLevel::Stable {
402 allowed_through_unstable_modules: Some(note),
403 ..
404 } = stab.level
405 {
406 Some(Deprecation {
407 since: DeprecatedSince::Unspecified,
408 note: Some(note),
409 suggestion: None,
410 })
411 } else {
412 None
413 }
414 })
415 }
416
417 pub(crate) fn inner_docs(&self, tcx: TyCtxt<'_>) -> bool {
418 self.item_id.as_def_id().map(|did| inner_docs(tcx.get_all_attrs(did))).unwrap_or(false)
419 }
420
421 pub(crate) fn span(&self, tcx: TyCtxt<'_>) -> Option<Span> {
422 let kind = match &self.kind {
423 ItemKind::StrippedItem(k) => k,
424 _ => &self.kind,
425 };
426 match kind {
427 ItemKind::ModuleItem(Module { span, .. }) => Some(*span),
428 ItemKind::ImplItem(box Impl { kind: ImplKind::Auto, .. }) => None,
429 ItemKind::ImplItem(box Impl { kind: ImplKind::Blanket(_), .. }) => {
430 if let ItemId::Blanket { impl_id, .. } = self.item_id {
431 Some(rustc_span(impl_id, tcx))
432 } else {
433 panic!("blanket impl item has non-blanket ID")
434 }
435 }
436 _ => self.def_id().map(|did| rustc_span(did, tcx)),
437 }
438 }
439
440 pub(crate) fn attr_span(&self, tcx: TyCtxt<'_>) -> rustc_span::Span {
441 span_of_fragments(&self.attrs.doc_strings)
442 .unwrap_or_else(|| self.span(tcx).map_or(DUMMY_SP, |span| span.inner()))
443 }
444
445 pub(crate) fn doc_value(&self) -> String {
447 self.attrs.doc_value()
448 }
449
450 pub(crate) fn opt_doc_value(&self) -> Option<String> {
454 self.attrs.opt_doc_value()
455 }
456
457 pub(crate) fn from_def_id_and_parts(
458 def_id: DefId,
459 name: Option<Symbol>,
460 kind: ItemKind,
461 cx: &mut DocContext<'_>,
462 ) -> Item {
463 let hir_attrs = cx.tcx.get_all_attrs(def_id);
464
465 Self::from_def_id_and_attrs_and_parts(
466 def_id,
467 name,
468 kind,
469 Attributes::from_hir(hir_attrs),
470 extract_cfg_from_attrs(hir_attrs.iter(), cx.tcx, &cx.cache.hidden_cfg),
471 )
472 }
473
474 pub(crate) fn from_def_id_and_attrs_and_parts(
475 def_id: DefId,
476 name: Option<Symbol>,
477 kind: ItemKind,
478 attrs: Attributes,
479 cfg: Option<Arc<Cfg>>,
480 ) -> Item {
481 trace!("name={name:?}, def_id={def_id:?} cfg={cfg:?}");
482
483 Item {
484 inner: Box::new(ItemInner {
485 item_id: def_id.into(),
486 kind,
487 attrs,
488 stability: None,
489 name,
490 cfg,
491 inline_stmt_id: None,
492 }),
493 }
494 }
495
496 pub(crate) fn item_or_reexport_id(&self) -> ItemId {
502 self.attrs
504 .doc_strings
505 .first()
506 .map(|x| x.item_id)
507 .flatten()
508 .map(ItemId::from)
509 .unwrap_or(self.item_id)
510 }
511
512 pub(crate) fn links(&self, cx: &Context<'_>) -> Vec<RenderedLink> {
513 use crate::html::format::{href, link_tooltip};
514
515 let Some(links) = cx.cache().intra_doc_links.get(&self.item_or_reexport_id()) else {
516 return vec![];
517 };
518 links
519 .iter()
520 .filter_map(|ItemLink { link: s, link_text, page_id: id, fragment }| {
521 debug!(?id);
522 if let Ok((mut href, ..)) = href(*id, cx) {
523 debug!(?href);
524 if let Some(ref fragment) = *fragment {
525 fragment.render(&mut href, cx.tcx())
526 }
527 Some(RenderedLink {
528 original_text: s.clone(),
529 new_text: link_text.clone(),
530 tooltip: link_tooltip(*id, fragment, cx).to_string(),
531 href,
532 })
533 } else {
534 None
535 }
536 })
537 .collect()
538 }
539
540 pub(crate) fn link_names(&self, cache: &Cache) -> Vec<RenderedLink> {
546 let Some(links) = cache.intra_doc_links.get(&self.item_id) else {
547 return vec![];
548 };
549 links
550 .iter()
551 .map(|ItemLink { link: s, link_text, .. }| RenderedLink {
552 original_text: s.clone(),
553 new_text: link_text.clone(),
554 href: String::new(),
555 tooltip: String::new(),
556 })
557 .collect()
558 }
559
560 pub(crate) fn is_crate(&self) -> bool {
561 self.is_mod() && self.def_id().is_some_and(|did| did.is_crate_root())
562 }
563 pub(crate) fn is_mod(&self) -> bool {
564 self.type_() == ItemType::Module
565 }
566 pub(crate) fn is_struct(&self) -> bool {
567 self.type_() == ItemType::Struct
568 }
569 pub(crate) fn is_enum(&self) -> bool {
570 self.type_() == ItemType::Enum
571 }
572 pub(crate) fn is_variant(&self) -> bool {
573 self.type_() == ItemType::Variant
574 }
575 pub(crate) fn is_associated_type(&self) -> bool {
576 matches!(self.kind, AssocTypeItem(..) | StrippedItem(box AssocTypeItem(..)))
577 }
578 pub(crate) fn is_required_associated_type(&self) -> bool {
579 matches!(self.kind, RequiredAssocTypeItem(..) | StrippedItem(box RequiredAssocTypeItem(..)))
580 }
581 pub(crate) fn is_associated_const(&self) -> bool {
582 matches!(self.kind, ProvidedAssocConstItem(..) | ImplAssocConstItem(..) | StrippedItem(box (ProvidedAssocConstItem(..) | ImplAssocConstItem(..))))
583 }
584 pub(crate) fn is_required_associated_const(&self) -> bool {
585 matches!(self.kind, RequiredAssocConstItem(..) | StrippedItem(box RequiredAssocConstItem(..)))
586 }
587 pub(crate) fn is_method(&self) -> bool {
588 self.type_() == ItemType::Method
589 }
590 pub(crate) fn is_ty_method(&self) -> bool {
591 self.type_() == ItemType::TyMethod
592 }
593 pub(crate) fn is_primitive(&self) -> bool {
594 self.type_() == ItemType::Primitive
595 }
596 pub(crate) fn is_union(&self) -> bool {
597 self.type_() == ItemType::Union
598 }
599 pub(crate) fn is_import(&self) -> bool {
600 self.type_() == ItemType::Import
601 }
602 pub(crate) fn is_extern_crate(&self) -> bool {
603 self.type_() == ItemType::ExternCrate
604 }
605 pub(crate) fn is_keyword(&self) -> bool {
606 self.type_() == ItemType::Keyword
607 }
608 pub(crate) fn is_attribute(&self) -> bool {
609 self.type_() == ItemType::Attribute
610 }
611 pub(crate) fn is_fake_item(&self) -> bool {
620 matches!(self.type_(), ItemType::Primitive | ItemType::Keyword | ItemType::Attribute)
621 }
622 pub(crate) fn is_stripped(&self) -> bool {
623 match self.kind {
624 StrippedItem(..) => true,
625 ImportItem(ref i) => !i.should_be_displayed,
626 _ => false,
627 }
628 }
629 pub(crate) fn has_stripped_entries(&self) -> Option<bool> {
630 match self.kind {
631 StructItem(ref struct_) => Some(struct_.has_stripped_entries()),
632 UnionItem(ref union_) => Some(union_.has_stripped_entries()),
633 EnumItem(ref enum_) => Some(enum_.has_stripped_entries()),
634 VariantItem(ref v) => v.has_stripped_entries(),
635 TypeAliasItem(ref type_alias) => {
636 type_alias.inner_type.as_ref().and_then(|t| t.has_stripped_entries())
637 }
638 _ => None,
639 }
640 }
641
642 pub(crate) fn stability_class(&self, tcx: TyCtxt<'_>) -> Option<String> {
643 self.stability(tcx).as_ref().and_then(|s| {
644 let mut classes = Vec::with_capacity(2);
645
646 if s.is_unstable() {
647 classes.push("unstable");
648 }
649
650 if self.deprecation(tcx).is_some() {
652 classes.push("deprecated");
653 }
654
655 if !classes.is_empty() { Some(classes.join(" ")) } else { None }
656 })
657 }
658
659 pub(crate) fn stable_since(&self, tcx: TyCtxt<'_>) -> Option<StableSince> {
660 self.stability(tcx).and_then(|stability| stability.stable_since())
661 }
662
663 pub(crate) fn is_non_exhaustive(&self) -> bool {
664 find_attr!(&self.attrs.other_attrs, AttributeKind::NonExhaustive(..))
665 }
666
667 pub(crate) fn type_(&self) -> ItemType {
669 ItemType::from(self)
670 }
671
672 pub(crate) fn is_default(&self) -> bool {
673 match self.kind {
674 ItemKind::MethodItem(_, Some(defaultness)) => {
675 defaultness.has_value() && !defaultness.is_final()
676 }
677 _ => false,
678 }
679 }
680
681 pub(crate) fn fn_header(&self, tcx: TyCtxt<'_>) -> Option<hir::FnHeader> {
683 fn build_fn_header(
684 def_id: DefId,
685 tcx: TyCtxt<'_>,
686 asyncness: ty::Asyncness,
687 ) -> hir::FnHeader {
688 let sig = tcx.fn_sig(def_id).skip_binder();
689 let constness = if tcx.is_const_fn(def_id) {
690 if let Some(assoc) = tcx.opt_associated_item(def_id)
694 && let ty::AssocContainer::Trait | ty::AssocContainer::TraitImpl(_) =
695 assoc.container
696 {
697 hir::Constness::NotConst
698 } else {
699 hir::Constness::Const
700 }
701 } else {
702 hir::Constness::NotConst
703 };
704 let asyncness = match asyncness {
705 ty::Asyncness::Yes => hir::IsAsync::Async(DUMMY_SP),
706 ty::Asyncness::No => hir::IsAsync::NotAsync,
707 };
708 hir::FnHeader {
709 safety: if tcx.codegen_fn_attrs(def_id).safe_target_features {
710 hir::HeaderSafety::SafeTargetFeatures
711 } else {
712 sig.safety().into()
713 },
714 abi: sig.abi(),
715 constness,
716 asyncness,
717 }
718 }
719 let header = match self.kind {
720 ItemKind::ForeignFunctionItem(_, safety) => {
721 let def_id = self.def_id().unwrap();
722 let abi = tcx.fn_sig(def_id).skip_binder().abi();
723 hir::FnHeader {
724 safety: if tcx.codegen_fn_attrs(def_id).safe_target_features {
725 hir::HeaderSafety::SafeTargetFeatures
726 } else {
727 safety.into()
728 },
729 abi,
730 constness: if tcx.is_const_fn(def_id) {
731 hir::Constness::Const
732 } else {
733 hir::Constness::NotConst
734 },
735 asyncness: hir::IsAsync::NotAsync,
736 }
737 }
738 ItemKind::FunctionItem(_)
739 | ItemKind::MethodItem(_, _)
740 | ItemKind::RequiredMethodItem(_) => {
741 let def_id = self.def_id().unwrap();
742 build_fn_header(def_id, tcx, tcx.asyncness(def_id))
743 }
744 _ => return None,
745 };
746 Some(header)
747 }
748
749 pub(crate) fn visibility(&self, tcx: TyCtxt<'_>) -> Option<Visibility<DefId>> {
752 let def_id = match self.item_id {
753 ItemId::Auto { .. } | ItemId::Blanket { .. } => return None,
755 ItemId::DefId(def_id) => def_id,
756 };
757
758 match self.kind {
759 ItemKind::KeywordItem | ItemKind::PrimitiveItem(_) | ItemKind::AttributeItem => {
763 return Some(Visibility::Public);
764 }
765 StructFieldItem(..) if is_field_vis_inherited(tcx, def_id) => {
767 return None;
768 }
769 VariantItem(..) | ImplItem(..) => return None,
771 RequiredAssocConstItem(..)
773 | ProvidedAssocConstItem(..)
774 | ImplAssocConstItem(..)
775 | AssocTypeItem(..)
776 | RequiredAssocTypeItem(..)
777 | RequiredMethodItem(..)
778 | MethodItem(..) => {
779 match tcx.associated_item(def_id).container {
780 ty::AssocContainer::Trait | ty::AssocContainer::TraitImpl(_) => {
783 return None;
784 }
785 ty::AssocContainer::InherentImpl => {}
786 }
787 }
788 _ => {}
789 }
790 let def_id = match self.inline_stmt_id {
791 Some(inlined) => inlined.to_def_id(),
792 None => def_id,
793 };
794 Some(tcx.visibility(def_id))
795 }
796
797 fn attributes_without_repr(&self) -> Vec<String> {
801 self.attrs
802 .other_attrs
803 .iter()
804 .filter_map(|attr| match attr {
805 hir::Attribute::Parsed(AttributeKind::LinkSection { name, .. }) => {
806 Some(format!("#[unsafe(link_section = \"{name}\")]"))
807 }
808 hir::Attribute::Parsed(AttributeKind::NoMangle(..)) => {
809 Some("#[unsafe(no_mangle)]".to_string())
810 }
811 hir::Attribute::Parsed(AttributeKind::ExportName { name, .. }) => {
812 Some(format!("#[unsafe(export_name = \"{name}\")]"))
813 }
814 hir::Attribute::Parsed(AttributeKind::NonExhaustive(..)) => {
815 Some("#[non_exhaustive]".to_string())
816 }
817 _ => None,
818 })
819 .collect()
820 }
821
822 pub(crate) fn attributes(&self, tcx: TyCtxt<'_>, cache: &Cache) -> Vec<String> {
826 let mut attrs = self.attributes_without_repr();
827
828 if let Some(repr_attr) = self.repr(tcx, cache) {
829 attrs.push(repr_attr);
830 }
831 attrs
832 }
833
834 pub(crate) fn repr(&self, tcx: TyCtxt<'_>, cache: &Cache) -> Option<String> {
838 repr_attributes(tcx, cache, self.def_id()?, self.type_())
839 }
840
841 pub fn is_doc_hidden(&self) -> bool {
842 self.attrs.is_doc_hidden()
843 }
844
845 pub fn def_id(&self) -> Option<DefId> {
846 self.item_id.as_def_id()
847 }
848}
849
850pub(crate) fn repr_attributes(
854 tcx: TyCtxt<'_>,
855 cache: &Cache,
856 def_id: DefId,
857 item_type: ItemType,
858) -> Option<String> {
859 use rustc_abi::IntegerType;
860
861 if !matches!(item_type, ItemType::Struct | ItemType::Enum | ItemType::Union) {
862 return None;
863 }
864 let adt = tcx.adt_def(def_id);
865 let repr = adt.repr();
866 let mut out = Vec::new();
867 if repr.c() {
868 out.push("C");
869 }
870 if repr.transparent() {
871 let render_transparent = cache.document_private
874 || adt
875 .all_fields()
876 .find(|field| {
877 let ty = field.ty(tcx, ty::GenericArgs::identity_for_item(tcx, field.did));
878 tcx.layout_of(ty::TypingEnv::post_analysis(tcx, field.did).as_query_input(ty))
879 .is_ok_and(|layout| !layout.is_1zst())
880 })
881 .map_or_else(
882 || adt.all_fields().any(|field| field.vis.is_public()),
883 |field| field.vis.is_public(),
884 );
885
886 if render_transparent {
887 out.push("transparent");
888 }
889 }
890 if repr.simd() {
891 out.push("simd");
892 }
893 let pack_s;
894 if let Some(pack) = repr.pack {
895 pack_s = format!("packed({})", pack.bytes());
896 out.push(&pack_s);
897 }
898 let align_s;
899 if let Some(align) = repr.align {
900 align_s = format!("align({})", align.bytes());
901 out.push(&align_s);
902 }
903 let int_s;
904 if let Some(int) = repr.int {
905 int_s = match int {
906 IntegerType::Pointer(is_signed) => {
907 format!("{}size", if is_signed { 'i' } else { 'u' })
908 }
909 IntegerType::Fixed(size, is_signed) => {
910 format!("{}{}", if is_signed { 'i' } else { 'u' }, size.size().bytes() * 8)
911 }
912 };
913 out.push(&int_s);
914 }
915 if !out.is_empty() { Some(format!("#[repr({})]", out.join(", "))) } else { None }
916}
917
918#[derive(Clone, Debug)]
919pub(crate) enum ItemKind {
920 ExternCrateItem {
921 src: Option<Symbol>,
923 },
924 ImportItem(Import),
925 StructItem(Struct),
926 UnionItem(Union),
927 EnumItem(Enum),
928 FunctionItem(Box<Function>),
929 ModuleItem(Module),
930 TypeAliasItem(Box<TypeAlias>),
931 StaticItem(Static),
932 TraitItem(Box<Trait>),
933 TraitAliasItem(TraitAlias),
934 ImplItem(Box<Impl>),
935 RequiredMethodItem(Box<Function>),
937 MethodItem(Box<Function>, Option<hir::Defaultness>),
941 StructFieldItem(Type),
942 VariantItem(Variant),
943 ForeignFunctionItem(Box<Function>, hir::Safety),
945 ForeignStaticItem(Static, hir::Safety),
947 ForeignTypeItem,
949 MacroItem(Macro),
950 ProcMacroItem(ProcMacro),
951 PrimitiveItem(PrimitiveType),
952 RequiredAssocConstItem(Generics, Box<Type>),
954 ConstantItem(Box<Constant>),
955 ProvidedAssocConstItem(Box<Constant>),
957 ImplAssocConstItem(Box<Constant>),
959 RequiredAssocTypeItem(Generics, Vec<GenericBound>),
963 AssocTypeItem(Box<TypeAlias>, Vec<GenericBound>),
965 StrippedItem(Box<ItemKind>),
967 KeywordItem,
970 AttributeItem,
973}
974
975impl ItemKind {
976 pub(crate) fn inner_items(&self) -> impl Iterator<Item = &Item> {
979 match self {
980 StructItem(s) => s.fields.iter(),
981 UnionItem(u) => u.fields.iter(),
982 VariantItem(v) => match &v.kind {
983 VariantKind::CLike => [].iter(),
984 VariantKind::Tuple(t) => t.iter(),
985 VariantKind::Struct(s) => s.fields.iter(),
986 },
987 EnumItem(e) => e.variants.iter(),
988 TraitItem(t) => t.items.iter(),
989 ImplItem(i) => i.items.iter(),
990 ModuleItem(m) => m.items.iter(),
991 ExternCrateItem { .. }
992 | ImportItem(_)
993 | FunctionItem(_)
994 | TypeAliasItem(_)
995 | StaticItem(_)
996 | ConstantItem(_)
997 | TraitAliasItem(_)
998 | RequiredMethodItem(_)
999 | MethodItem(_, _)
1000 | StructFieldItem(_)
1001 | ForeignFunctionItem(_, _)
1002 | ForeignStaticItem(_, _)
1003 | ForeignTypeItem
1004 | MacroItem(_)
1005 | ProcMacroItem(_)
1006 | PrimitiveItem(_)
1007 | RequiredAssocConstItem(..)
1008 | ProvidedAssocConstItem(..)
1009 | ImplAssocConstItem(..)
1010 | RequiredAssocTypeItem(..)
1011 | AssocTypeItem(..)
1012 | StrippedItem(_)
1013 | KeywordItem
1014 | AttributeItem => [].iter(),
1015 }
1016 }
1017
1018 pub(crate) fn is_non_assoc(&self) -> bool {
1020 matches!(
1021 self,
1022 StructItem(_)
1023 | UnionItem(_)
1024 | EnumItem(_)
1025 | TraitItem(_)
1026 | ModuleItem(_)
1027 | ExternCrateItem { .. }
1028 | FunctionItem(_)
1029 | TypeAliasItem(_)
1030 | StaticItem(_)
1031 | ConstantItem(_)
1032 | TraitAliasItem(_)
1033 | ForeignFunctionItem(_, _)
1034 | ForeignStaticItem(_, _)
1035 | ForeignTypeItem
1036 | MacroItem(_)
1037 | ProcMacroItem(_)
1038 | PrimitiveItem(_)
1039 )
1040 }
1041}
1042
1043#[derive(Clone, Debug)]
1044pub(crate) struct Module {
1045 pub(crate) items: Vec<Item>,
1046 pub(crate) span: Span,
1047}
1048
1049pub(crate) fn hir_attr_lists<'a, I: IntoIterator<Item = &'a hir::Attribute>>(
1050 attrs: I,
1051 name: Symbol,
1052) -> impl Iterator<Item = ast::MetaItemInner> + use<'a, I> {
1053 attrs
1054 .into_iter()
1055 .filter(move |attr| attr.has_name(name))
1056 .filter_map(ast::attr::AttributeExt::meta_item_list)
1057 .flatten()
1058}
1059
1060pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator<Item = &'a hir::Attribute> + Clone>(
1061 attrs: I,
1062 tcx: TyCtxt<'_>,
1063 hidden_cfg: &FxHashSet<Cfg>,
1064) -> Option<Arc<Cfg>> {
1065 let doc_cfg_active = tcx.features().doc_cfg();
1066 let doc_auto_cfg_active = tcx.features().doc_auto_cfg();
1067
1068 fn single<T: IntoIterator>(it: T) -> Option<T::Item> {
1069 let mut iter = it.into_iter();
1070 let item = iter.next()?;
1071 if iter.next().is_some() {
1072 return None;
1073 }
1074 Some(item)
1075 }
1076
1077 let mut cfg = if doc_cfg_active || doc_auto_cfg_active {
1078 let mut doc_cfg = attrs
1079 .clone()
1080 .filter(|attr| attr.has_name(sym::doc))
1081 .flat_map(|attr| attr.meta_item_list().unwrap_or_default())
1082 .filter(|attr| attr.has_name(sym::cfg))
1083 .peekable();
1084 if doc_cfg.peek().is_some() && doc_cfg_active {
1085 let sess = tcx.sess;
1086
1087 doc_cfg.fold(Cfg::True, |mut cfg, item| {
1088 if let Some(cfg_mi) =
1089 item.meta_item().and_then(|item| rustc_expand::config::parse_cfg(item, sess))
1090 {
1091 match Cfg::parse(cfg_mi) {
1092 Ok(new_cfg) => cfg &= new_cfg,
1093 Err(e) => {
1094 sess.dcx().span_err(e.span, e.msg);
1095 }
1096 }
1097 }
1098 cfg
1099 })
1100 } else if doc_auto_cfg_active {
1101 attrs
1104 .clone()
1105 .filter(|attr| attr.has_name(sym::cfg_trace))
1106 .filter_map(|attr| single(attr.meta_item_list()?))
1107 .filter_map(|attr| Cfg::parse_without(attr.meta_item()?, hidden_cfg).ok().flatten())
1108 .fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg)
1109 } else {
1110 Cfg::True
1111 }
1112 } else {
1113 Cfg::True
1114 };
1115
1116 if let Some(features) =
1119 find_attr!(attrs, AttributeKind::TargetFeature { features, .. } => features)
1120 {
1121 for (feature, _) in features {
1122 cfg &= Cfg::Cfg(sym::target_feature, Some(*feature));
1123 }
1124 }
1125
1126 if cfg == Cfg::True { None } else { Some(Arc::new(cfg)) }
1127}
1128
1129pub(crate) trait NestedAttributesExt {
1130 fn has_word(self, word: Symbol) -> bool
1132 where
1133 Self: Sized,
1134 {
1135 <Self as NestedAttributesExt>::get_word_attr(self, word).is_some()
1136 }
1137
1138 fn get_word_attr(self, word: Symbol) -> Option<ast::MetaItemInner>;
1141}
1142
1143impl<I: Iterator<Item = ast::MetaItemInner>> NestedAttributesExt for I {
1144 fn get_word_attr(mut self, word: Symbol) -> Option<ast::MetaItemInner> {
1145 self.find(|attr| attr.is_word() && attr.has_name(word))
1146 }
1147}
1148
1149#[derive(Clone, Debug, PartialEq, Eq, Hash)]
1153pub(crate) struct ItemLink {
1154 pub(crate) link: Box<str>,
1156 pub(crate) link_text: Box<str>,
1161 pub(crate) page_id: DefId,
1165 pub(crate) fragment: Option<UrlFragment>,
1167}
1168
1169pub struct RenderedLink {
1170 pub(crate) original_text: Box<str>,
1174 pub(crate) new_text: Box<str>,
1176 pub(crate) href: String,
1178 pub(crate) tooltip: String,
1180}
1181
1182#[derive(Clone, Debug, Default)]
1185pub(crate) struct Attributes {
1186 pub(crate) doc_strings: Vec<DocFragment>,
1187 pub(crate) other_attrs: ThinVec<hir::Attribute>,
1188}
1189
1190impl Attributes {
1191 pub(crate) fn lists(&self, name: Symbol) -> impl Iterator<Item = ast::MetaItemInner> {
1192 hir_attr_lists(&self.other_attrs[..], name)
1193 }
1194
1195 pub(crate) fn has_doc_flag(&self, flag: Symbol) -> bool {
1196 for attr in &self.other_attrs {
1197 if !attr.has_name(sym::doc) {
1198 continue;
1199 }
1200
1201 if let Some(items) = attr.meta_item_list()
1202 && items.iter().filter_map(|i| i.meta_item()).any(|it| it.has_name(flag))
1203 {
1204 return true;
1205 }
1206 }
1207
1208 false
1209 }
1210
1211 pub(crate) fn is_doc_hidden(&self) -> bool {
1212 self.has_doc_flag(sym::hidden)
1213 }
1214
1215 pub(crate) fn from_hir(attrs: &[hir::Attribute]) -> Attributes {
1216 Attributes::from_hir_iter(attrs.iter().map(|attr| (attr, None)), false)
1217 }
1218
1219 pub(crate) fn from_hir_with_additional(
1220 attrs: &[hir::Attribute],
1221 (additional_attrs, def_id): (&[hir::Attribute], DefId),
1222 ) -> Attributes {
1223 let attrs1 = additional_attrs.iter().map(|attr| (attr, Some(def_id)));
1225 let attrs2 = attrs.iter().map(|attr| (attr, None));
1226 Attributes::from_hir_iter(attrs1.chain(attrs2), false)
1227 }
1228
1229 pub(crate) fn from_hir_iter<'a>(
1230 attrs: impl Iterator<Item = (&'a hir::Attribute, Option<DefId>)>,
1231 doc_only: bool,
1232 ) -> Attributes {
1233 let (doc_strings, other_attrs) = attrs_to_doc_fragments(attrs, doc_only);
1234 Attributes { doc_strings, other_attrs }
1235 }
1236
1237 pub(crate) fn doc_value(&self) -> String {
1239 self.opt_doc_value().unwrap_or_default()
1240 }
1241
1242 pub(crate) fn opt_doc_value(&self) -> Option<String> {
1246 (!self.doc_strings.is_empty()).then(|| {
1247 let mut res = String::new();
1248 for frag in &self.doc_strings {
1249 add_doc_fragment(&mut res, frag);
1250 }
1251 res.pop();
1252 res
1253 })
1254 }
1255
1256 pub(crate) fn get_doc_aliases(&self) -> Box<[Symbol]> {
1257 let mut aliases = FxIndexSet::default();
1258
1259 for attr in
1260 hir_attr_lists(&self.other_attrs[..], sym::doc).filter(|a| a.has_name(sym::alias))
1261 {
1262 if let Some(values) = attr.meta_item_list() {
1263 for l in values {
1264 if let Some(lit) = l.lit()
1265 && let ast::LitKind::Str(s, _) = lit.kind
1266 {
1267 aliases.insert(s);
1268 }
1269 }
1270 } else if let Some(value) = attr.value_str() {
1271 aliases.insert(value);
1272 }
1273 }
1274 aliases.into_iter().collect::<Vec<_>>().into()
1275 }
1276}
1277
1278#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1279pub(crate) enum GenericBound {
1280 TraitBound(PolyTrait, hir::TraitBoundModifiers),
1281 Outlives(Lifetime),
1282 Use(Vec<PreciseCapturingArg>),
1284}
1285
1286impl GenericBound {
1287 pub(crate) fn sized(cx: &mut DocContext<'_>) -> GenericBound {
1288 Self::sized_with(cx, hir::TraitBoundModifiers::NONE)
1289 }
1290
1291 pub(crate) fn maybe_sized(cx: &mut DocContext<'_>) -> GenericBound {
1292 Self::sized_with(
1293 cx,
1294 hir::TraitBoundModifiers {
1295 polarity: hir::BoundPolarity::Maybe(DUMMY_SP),
1296 constness: hir::BoundConstness::Never,
1297 },
1298 )
1299 }
1300
1301 fn sized_with(cx: &mut DocContext<'_>, modifiers: hir::TraitBoundModifiers) -> GenericBound {
1302 let did = cx.tcx.require_lang_item(LangItem::Sized, DUMMY_SP);
1303 let empty = ty::Binder::dummy(ty::GenericArgs::empty());
1304 let path = clean_middle_path(cx, did, false, ThinVec::new(), empty);
1305 inline::record_extern_fqn(cx, did, ItemType::Trait);
1306 GenericBound::TraitBound(PolyTrait { trait_: path, generic_params: Vec::new() }, modifiers)
1307 }
1308
1309 pub(crate) fn is_trait_bound(&self) -> bool {
1310 matches!(self, Self::TraitBound(..))
1311 }
1312
1313 pub(crate) fn is_sized_bound(&self, cx: &DocContext<'_>) -> bool {
1314 self.is_bounded_by_lang_item(cx, LangItem::Sized)
1315 }
1316
1317 pub(crate) fn is_meta_sized_bound(&self, cx: &DocContext<'_>) -> bool {
1318 self.is_bounded_by_lang_item(cx, LangItem::MetaSized)
1319 }
1320
1321 fn is_bounded_by_lang_item(&self, cx: &DocContext<'_>, lang_item: LangItem) -> bool {
1322 if let GenericBound::TraitBound(
1323 PolyTrait { ref trait_, .. },
1324 rustc_hir::TraitBoundModifiers::NONE,
1325 ) = *self
1326 && cx.tcx.is_lang_item(trait_.def_id(), lang_item)
1327 {
1328 return true;
1329 }
1330 false
1331 }
1332
1333 pub(crate) fn get_trait_path(&self) -> Option<Path> {
1334 if let GenericBound::TraitBound(PolyTrait { ref trait_, .. }, _) = *self {
1335 Some(trait_.clone())
1336 } else {
1337 None
1338 }
1339 }
1340}
1341
1342#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
1343pub(crate) struct Lifetime(pub Symbol);
1344
1345impl Lifetime {
1346 pub(crate) fn statik() -> Lifetime {
1347 Lifetime(kw::StaticLifetime)
1348 }
1349
1350 pub(crate) fn elided() -> Lifetime {
1351 Lifetime(kw::UnderscoreLifetime)
1352 }
1353}
1354
1355#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
1356pub(crate) enum PreciseCapturingArg {
1357 Lifetime(Lifetime),
1358 Param(Symbol),
1359}
1360
1361impl PreciseCapturingArg {
1362 pub(crate) fn name(self) -> Symbol {
1363 match self {
1364 PreciseCapturingArg::Lifetime(lt) => lt.0,
1365 PreciseCapturingArg::Param(param) => param,
1366 }
1367 }
1368}
1369
1370#[derive(Clone, PartialEq, Eq, Hash, Debug)]
1371pub(crate) enum WherePredicate {
1372 BoundPredicate { ty: Type, bounds: Vec<GenericBound>, bound_params: Vec<GenericParamDef> },
1373 RegionPredicate { lifetime: Lifetime, bounds: Vec<GenericBound> },
1374 EqPredicate { lhs: QPathData, rhs: Term },
1375}
1376
1377impl WherePredicate {
1378 pub(crate) fn get_bounds(&self) -> Option<&[GenericBound]> {
1379 match self {
1380 WherePredicate::BoundPredicate { bounds, .. } => Some(bounds),
1381 WherePredicate::RegionPredicate { bounds, .. } => Some(bounds),
1382 _ => None,
1383 }
1384 }
1385}
1386
1387#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1388pub(crate) enum GenericParamDefKind {
1389 Lifetime { outlives: ThinVec<Lifetime> },
1390 Type { bounds: ThinVec<GenericBound>, default: Option<Box<Type>>, synthetic: bool },
1391 Const { ty: Box<Type>, default: Option<Box<String>> },
1393}
1394
1395impl GenericParamDefKind {
1396 pub(crate) fn is_type(&self) -> bool {
1397 matches!(self, GenericParamDefKind::Type { .. })
1398 }
1399}
1400
1401#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1402pub(crate) struct GenericParamDef {
1403 pub(crate) name: Symbol,
1404 pub(crate) def_id: DefId,
1405 pub(crate) kind: GenericParamDefKind,
1406}
1407
1408impl GenericParamDef {
1409 pub(crate) fn lifetime(def_id: DefId, name: Symbol) -> Self {
1410 Self { name, def_id, kind: GenericParamDefKind::Lifetime { outlives: ThinVec::new() } }
1411 }
1412
1413 pub(crate) fn is_synthetic_param(&self) -> bool {
1414 match self.kind {
1415 GenericParamDefKind::Lifetime { .. } | GenericParamDefKind::Const { .. } => false,
1416 GenericParamDefKind::Type { synthetic, .. } => synthetic,
1417 }
1418 }
1419
1420 pub(crate) fn is_type(&self) -> bool {
1421 self.kind.is_type()
1422 }
1423
1424 pub(crate) fn get_bounds(&self) -> Option<&[GenericBound]> {
1425 match self.kind {
1426 GenericParamDefKind::Type { ref bounds, .. } => Some(bounds),
1427 _ => None,
1428 }
1429 }
1430}
1431
1432#[derive(Clone, PartialEq, Eq, Hash, Debug, Default)]
1434pub(crate) struct Generics {
1435 pub(crate) params: ThinVec<GenericParamDef>,
1436 pub(crate) where_predicates: ThinVec<WherePredicate>,
1437}
1438
1439impl Generics {
1440 pub(crate) fn is_empty(&self) -> bool {
1441 self.params.is_empty() && self.where_predicates.is_empty()
1442 }
1443}
1444
1445#[derive(Clone, Debug)]
1446pub(crate) struct Function {
1447 pub(crate) decl: FnDecl,
1448 pub(crate) generics: Generics,
1449}
1450
1451#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1452pub(crate) struct FnDecl {
1453 pub(crate) inputs: Vec<Parameter>,
1454 pub(crate) output: Type,
1455 pub(crate) c_variadic: bool,
1456}
1457
1458impl FnDecl {
1459 pub(crate) fn receiver_type(&self) -> Option<&Type> {
1460 self.inputs.first().and_then(|v| v.to_receiver())
1461 }
1462}
1463
1464#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1466pub(crate) struct Parameter {
1467 pub(crate) name: Option<Symbol>,
1468 pub(crate) type_: Type,
1469 pub(crate) is_const: bool,
1472}
1473
1474impl Parameter {
1475 pub(crate) fn to_receiver(&self) -> Option<&Type> {
1476 if self.name == Some(kw::SelfLower) { Some(&self.type_) } else { None }
1477 }
1478}
1479
1480#[derive(Clone, Debug)]
1481pub(crate) struct Trait {
1482 pub(crate) def_id: DefId,
1483 pub(crate) items: Vec<Item>,
1484 pub(crate) generics: Generics,
1485 pub(crate) bounds: Vec<GenericBound>,
1486}
1487
1488impl Trait {
1489 pub(crate) fn is_auto(&self, tcx: TyCtxt<'_>) -> bool {
1490 tcx.trait_is_auto(self.def_id)
1491 }
1492 pub(crate) fn is_notable_trait(&self, tcx: TyCtxt<'_>) -> bool {
1493 tcx.is_doc_notable_trait(self.def_id)
1494 }
1495 pub(crate) fn safety(&self, tcx: TyCtxt<'_>) -> hir::Safety {
1496 tcx.trait_def(self.def_id).safety
1497 }
1498 pub(crate) fn is_dyn_compatible(&self, tcx: TyCtxt<'_>) -> bool {
1499 tcx.is_dyn_compatible(self.def_id)
1500 }
1501}
1502
1503#[derive(Clone, Debug)]
1504pub(crate) struct TraitAlias {
1505 pub(crate) generics: Generics,
1506 pub(crate) bounds: Vec<GenericBound>,
1507}
1508
1509#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1511pub(crate) struct PolyTrait {
1512 pub(crate) trait_: Path,
1513 pub(crate) generic_params: Vec<GenericParamDef>,
1514}
1515
1516#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1518pub(crate) enum Type {
1519 Path {
1524 path: Path,
1525 },
1526 DynTrait(Vec<PolyTrait>, Option<Lifetime>),
1528 Generic(Symbol),
1530 SelfTy,
1532 Primitive(PrimitiveType),
1534 BareFunction(Box<BareFunctionDecl>),
1536 Tuple(Vec<Type>),
1538 Slice(Box<Type>),
1540 Array(Box<Type>, Box<str>),
1544 Pat(Box<Type>, Box<str>),
1545 RawPointer(Mutability, Box<Type>),
1547 BorrowedRef {
1549 lifetime: Option<Lifetime>,
1550 mutability: Mutability,
1551 type_: Box<Type>,
1552 },
1553
1554 QPath(Box<QPathData>),
1556
1557 Infer,
1559
1560 ImplTrait(Vec<GenericBound>),
1562
1563 UnsafeBinder(Box<UnsafeBinderTy>),
1564}
1565
1566impl Type {
1567 pub(crate) fn without_borrowed_ref(&self) -> &Type {
1569 let mut result = self;
1570 while let Type::BorrowedRef { type_, .. } = result {
1571 result = type_;
1572 }
1573 result
1574 }
1575
1576 pub(crate) fn is_borrowed_ref(&self) -> bool {
1577 matches!(self, Type::BorrowedRef { .. })
1578 }
1579
1580 fn is_type_alias(&self) -> bool {
1581 matches!(self, Type::Path { path: Path { res: Res::Def(DefKind::TyAlias, _), .. } })
1582 }
1583
1584 pub(crate) fn is_doc_subtype_of(&self, other: &Self, cache: &Cache) -> bool {
1605 let (self_cleared, other_cleared) = if !self.is_borrowed_ref() || !other.is_borrowed_ref() {
1608 (self.without_borrowed_ref(), other.without_borrowed_ref())
1609 } else {
1610 (self, other)
1611 };
1612
1613 if self_cleared.is_type_alias() || other_cleared.is_type_alias() {
1619 return true;
1620 }
1621
1622 match (self_cleared, other_cleared) {
1623 (Type::Tuple(a), Type::Tuple(b)) => {
1625 a.len() == b.len() && a.iter().zip(b).all(|(a, b)| a.is_doc_subtype_of(b, cache))
1626 }
1627 (Type::Slice(a), Type::Slice(b)) => a.is_doc_subtype_of(b, cache),
1628 (Type::Array(a, al), Type::Array(b, bl)) => al == bl && a.is_doc_subtype_of(b, cache),
1629 (Type::RawPointer(mutability, type_), Type::RawPointer(b_mutability, b_type_)) => {
1630 mutability == b_mutability && type_.is_doc_subtype_of(b_type_, cache)
1631 }
1632 (
1633 Type::BorrowedRef { mutability, type_, .. },
1634 Type::BorrowedRef { mutability: b_mutability, type_: b_type_, .. },
1635 ) => mutability == b_mutability && type_.is_doc_subtype_of(b_type_, cache),
1636 (Type::Infer, _) | (_, Type::Infer) => true,
1638 (_, Type::Generic(_)) => true,
1641 (Type::Generic(_), _) => false,
1642 (Type::SelfTy, Type::SelfTy) => true,
1644 (Type::Path { path: a }, Type::Path { path: b }) => {
1646 a.def_id() == b.def_id()
1647 && a.generics()
1648 .zip(b.generics())
1649 .map(|(ag, bg)| ag.zip(bg).all(|(at, bt)| at.is_doc_subtype_of(bt, cache)))
1650 .unwrap_or(true)
1651 }
1652 (a, b) => a
1654 .def_id(cache)
1655 .and_then(|a| Some((a, b.def_id(cache)?)))
1656 .map(|(a, b)| a == b)
1657 .unwrap_or(false),
1658 }
1659 }
1660
1661 pub(crate) fn primitive_type(&self) -> Option<PrimitiveType> {
1662 match *self {
1663 Primitive(p) | BorrowedRef { type_: box Primitive(p), .. } => Some(p),
1664 Slice(..) | BorrowedRef { type_: box Slice(..), .. } => Some(PrimitiveType::Slice),
1665 Array(..) | BorrowedRef { type_: box Array(..), .. } => Some(PrimitiveType::Array),
1666 Tuple(ref tys) => {
1667 if tys.is_empty() {
1668 Some(PrimitiveType::Unit)
1669 } else {
1670 Some(PrimitiveType::Tuple)
1671 }
1672 }
1673 RawPointer(..) => Some(PrimitiveType::RawPointer),
1674 BareFunction(..) => Some(PrimitiveType::Fn),
1675 _ => None,
1676 }
1677 }
1678
1679 pub(crate) fn sugared_async_return_type(self) -> Type {
1689 if let Type::ImplTrait(mut v) = self
1690 && let Some(GenericBound::TraitBound(PolyTrait { mut trait_, .. }, _)) = v.pop()
1691 && let Some(segment) = trait_.segments.pop()
1692 && let GenericArgs::AngleBracketed { mut constraints, .. } = segment.args
1693 && let Some(constraint) = constraints.pop()
1694 && let AssocItemConstraintKind::Equality { term } = constraint.kind
1695 && let Term::Type(ty) = term
1696 {
1697 ty
1698 } else {
1699 panic!("unexpected async fn return type")
1700 }
1701 }
1702
1703 pub(crate) fn is_assoc_ty(&self) -> bool {
1705 match self {
1706 Type::Path { path, .. } => path.is_assoc_ty(),
1707 _ => false,
1708 }
1709 }
1710
1711 pub(crate) fn is_self_type(&self) -> bool {
1712 matches!(*self, Type::SelfTy)
1713 }
1714
1715 pub(crate) fn generic_args(&self) -> Option<&GenericArgs> {
1716 match self {
1717 Type::Path { path, .. } => path.generic_args(),
1718 _ => None,
1719 }
1720 }
1721
1722 pub(crate) fn generics(&self) -> Option<impl Iterator<Item = &Type>> {
1723 match self {
1724 Type::Path { path, .. } => path.generics(),
1725 _ => None,
1726 }
1727 }
1728
1729 pub(crate) fn is_full_generic(&self) -> bool {
1730 matches!(self, Type::Generic(_))
1731 }
1732
1733 pub(crate) fn is_unit(&self) -> bool {
1734 matches!(self, Type::Tuple(v) if v.is_empty())
1735 }
1736
1737 pub(crate) fn def_id(&self, cache: &Cache) -> Option<DefId> {
1741 let t: PrimitiveType = match self {
1742 Type::Path { path } => return Some(path.def_id()),
1743 DynTrait(bounds, _) => return bounds.first().map(|b| b.trait_.def_id()),
1744 Primitive(p) => return cache.primitive_locations.get(p).cloned(),
1745 BorrowedRef { type_: box Generic(..), .. } => PrimitiveType::Reference,
1746 BorrowedRef { type_, .. } => return type_.def_id(cache),
1747 Tuple(tys) => {
1748 if tys.is_empty() {
1749 PrimitiveType::Unit
1750 } else {
1751 PrimitiveType::Tuple
1752 }
1753 }
1754 BareFunction(..) => PrimitiveType::Fn,
1755 Slice(..) => PrimitiveType::Slice,
1756 Array(..) => PrimitiveType::Array,
1757 Type::Pat(..) => PrimitiveType::Pat,
1758 RawPointer(..) => PrimitiveType::RawPointer,
1759 QPath(box QPathData { self_type, .. }) => return self_type.def_id(cache),
1760 Generic(_) | SelfTy | Infer | ImplTrait(_) | UnsafeBinder(_) => return None,
1761 };
1762 Primitive(t).def_id(cache)
1763 }
1764}
1765
1766#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1767pub(crate) struct QPathData {
1768 pub assoc: PathSegment,
1769 pub self_type: Type,
1770 pub should_fully_qualify: bool,
1772 pub trait_: Option<Path>,
1773}
1774
1775#[derive(Clone, PartialEq, Eq, Hash, Copy, Debug)]
1782pub(crate) enum PrimitiveType {
1783 Isize,
1784 I8,
1785 I16,
1786 I32,
1787 I64,
1788 I128,
1789 Usize,
1790 U8,
1791 U16,
1792 U32,
1793 U64,
1794 U128,
1795 F16,
1796 F32,
1797 F64,
1798 F128,
1799 Char,
1800 Bool,
1801 Str,
1802 Slice,
1803 Array,
1804 Pat,
1805 Tuple,
1806 Unit,
1807 RawPointer,
1808 Reference,
1809 Fn,
1810 Never,
1811}
1812
1813type SimplifiedTypes = FxIndexMap<PrimitiveType, ArrayVec<SimplifiedType, 3>>;
1814impl PrimitiveType {
1815 pub(crate) fn from_hir(prim: hir::PrimTy) -> PrimitiveType {
1816 use ast::{FloatTy, IntTy, UintTy};
1817 match prim {
1818 hir::PrimTy::Int(IntTy::Isize) => PrimitiveType::Isize,
1819 hir::PrimTy::Int(IntTy::I8) => PrimitiveType::I8,
1820 hir::PrimTy::Int(IntTy::I16) => PrimitiveType::I16,
1821 hir::PrimTy::Int(IntTy::I32) => PrimitiveType::I32,
1822 hir::PrimTy::Int(IntTy::I64) => PrimitiveType::I64,
1823 hir::PrimTy::Int(IntTy::I128) => PrimitiveType::I128,
1824 hir::PrimTy::Uint(UintTy::Usize) => PrimitiveType::Usize,
1825 hir::PrimTy::Uint(UintTy::U8) => PrimitiveType::U8,
1826 hir::PrimTy::Uint(UintTy::U16) => PrimitiveType::U16,
1827 hir::PrimTy::Uint(UintTy::U32) => PrimitiveType::U32,
1828 hir::PrimTy::Uint(UintTy::U64) => PrimitiveType::U64,
1829 hir::PrimTy::Uint(UintTy::U128) => PrimitiveType::U128,
1830 hir::PrimTy::Float(FloatTy::F16) => PrimitiveType::F16,
1831 hir::PrimTy::Float(FloatTy::F32) => PrimitiveType::F32,
1832 hir::PrimTy::Float(FloatTy::F64) => PrimitiveType::F64,
1833 hir::PrimTy::Float(FloatTy::F128) => PrimitiveType::F128,
1834 hir::PrimTy::Str => PrimitiveType::Str,
1835 hir::PrimTy::Bool => PrimitiveType::Bool,
1836 hir::PrimTy::Char => PrimitiveType::Char,
1837 }
1838 }
1839
1840 pub(crate) fn from_symbol(s: Symbol) -> Option<PrimitiveType> {
1841 match s {
1842 sym::isize => Some(PrimitiveType::Isize),
1843 sym::i8 => Some(PrimitiveType::I8),
1844 sym::i16 => Some(PrimitiveType::I16),
1845 sym::i32 => Some(PrimitiveType::I32),
1846 sym::i64 => Some(PrimitiveType::I64),
1847 sym::i128 => Some(PrimitiveType::I128),
1848 sym::usize => Some(PrimitiveType::Usize),
1849 sym::u8 => Some(PrimitiveType::U8),
1850 sym::u16 => Some(PrimitiveType::U16),
1851 sym::u32 => Some(PrimitiveType::U32),
1852 sym::u64 => Some(PrimitiveType::U64),
1853 sym::u128 => Some(PrimitiveType::U128),
1854 sym::bool => Some(PrimitiveType::Bool),
1855 sym::char => Some(PrimitiveType::Char),
1856 sym::str => Some(PrimitiveType::Str),
1857 sym::f16 => Some(PrimitiveType::F16),
1858 sym::f32 => Some(PrimitiveType::F32),
1859 sym::f64 => Some(PrimitiveType::F64),
1860 sym::f128 => Some(PrimitiveType::F128),
1861 sym::array => Some(PrimitiveType::Array),
1862 sym::slice => Some(PrimitiveType::Slice),
1863 sym::tuple => Some(PrimitiveType::Tuple),
1864 sym::unit => Some(PrimitiveType::Unit),
1865 sym::pointer => Some(PrimitiveType::RawPointer),
1866 sym::reference => Some(PrimitiveType::Reference),
1867 kw::Fn => Some(PrimitiveType::Fn),
1868 sym::never => Some(PrimitiveType::Never),
1869 _ => None,
1870 }
1871 }
1872
1873 pub(crate) fn simplified_types() -> &'static SimplifiedTypes {
1874 use PrimitiveType::*;
1875 use ty::{FloatTy, IntTy, UintTy};
1876 static CELL: OnceCell<SimplifiedTypes> = OnceCell::new();
1877
1878 let single = |x| iter::once(x).collect();
1879 CELL.get_or_init(move || {
1880 map! {
1881 Isize => single(SimplifiedType::Int(IntTy::Isize)),
1882 I8 => single(SimplifiedType::Int(IntTy::I8)),
1883 I16 => single(SimplifiedType::Int(IntTy::I16)),
1884 I32 => single(SimplifiedType::Int(IntTy::I32)),
1885 I64 => single(SimplifiedType::Int(IntTy::I64)),
1886 I128 => single(SimplifiedType::Int(IntTy::I128)),
1887 Usize => single(SimplifiedType::Uint(UintTy::Usize)),
1888 U8 => single(SimplifiedType::Uint(UintTy::U8)),
1889 U16 => single(SimplifiedType::Uint(UintTy::U16)),
1890 U32 => single(SimplifiedType::Uint(UintTy::U32)),
1891 U64 => single(SimplifiedType::Uint(UintTy::U64)),
1892 U128 => single(SimplifiedType::Uint(UintTy::U128)),
1893 F16 => single(SimplifiedType::Float(FloatTy::F16)),
1894 F32 => single(SimplifiedType::Float(FloatTy::F32)),
1895 F64 => single(SimplifiedType::Float(FloatTy::F64)),
1896 F128 => single(SimplifiedType::Float(FloatTy::F128)),
1897 Str => single(SimplifiedType::Str),
1898 Bool => single(SimplifiedType::Bool),
1899 Char => single(SimplifiedType::Char),
1900 Array => single(SimplifiedType::Array),
1901 Slice => single(SimplifiedType::Slice),
1902 Tuple => [SimplifiedType::Tuple(1), SimplifiedType::Tuple(2), SimplifiedType::Tuple(3)].into(),
1908 Unit => single(SimplifiedType::Tuple(0)),
1909 RawPointer => [SimplifiedType::Ptr(Mutability::Not), SimplifiedType::Ptr(Mutability::Mut)].into_iter().collect(),
1910 Reference => [SimplifiedType::Ref(Mutability::Not), SimplifiedType::Ref(Mutability::Mut)].into_iter().collect(),
1911 Fn => single(SimplifiedType::Function(1)),
1914 Never => single(SimplifiedType::Never),
1915 }
1916 })
1917 }
1918
1919 pub(crate) fn impls<'tcx>(&self, tcx: TyCtxt<'tcx>) -> impl Iterator<Item = DefId> + 'tcx {
1920 Self::simplified_types()
1921 .get(self)
1922 .into_iter()
1923 .flatten()
1924 .flat_map(move |&simp| tcx.incoherent_impls(simp).iter())
1925 .copied()
1926 }
1927
1928 pub(crate) fn all_impls(tcx: TyCtxt<'_>) -> impl Iterator<Item = DefId> {
1929 Self::simplified_types()
1930 .values()
1931 .flatten()
1932 .flat_map(move |&simp| tcx.incoherent_impls(simp).iter())
1933 .copied()
1934 }
1935
1936 pub(crate) fn as_sym(&self) -> Symbol {
1937 use PrimitiveType::*;
1938 match self {
1939 Isize => sym::isize,
1940 I8 => sym::i8,
1941 I16 => sym::i16,
1942 I32 => sym::i32,
1943 I64 => sym::i64,
1944 I128 => sym::i128,
1945 Usize => sym::usize,
1946 U8 => sym::u8,
1947 U16 => sym::u16,
1948 U32 => sym::u32,
1949 U64 => sym::u64,
1950 U128 => sym::u128,
1951 F16 => sym::f16,
1952 F32 => sym::f32,
1953 F64 => sym::f64,
1954 F128 => sym::f128,
1955 Str => sym::str,
1956 Bool => sym::bool,
1957 Char => sym::char,
1958 Array => sym::array,
1959 Pat => sym::pat,
1960 Slice => sym::slice,
1961 Tuple => sym::tuple,
1962 Unit => sym::unit,
1963 RawPointer => sym::pointer,
1964 Reference => sym::reference,
1965 Fn => kw::Fn,
1966 Never => sym::never,
1967 }
1968 }
1969
1970 pub(crate) fn primitive_locations(tcx: TyCtxt<'_>) -> &FxIndexMap<PrimitiveType, DefId> {
1982 static PRIMITIVE_LOCATIONS: OnceCell<FxIndexMap<PrimitiveType, DefId>> = OnceCell::new();
1983 PRIMITIVE_LOCATIONS.get_or_init(|| {
1984 let mut primitive_locations = FxIndexMap::default();
1985 for &crate_num in tcx.crates(()) {
1988 let e = ExternalCrate { crate_num };
1989 let crate_name = e.name(tcx);
1990 debug!(?crate_num, ?crate_name);
1991 for (def_id, prim) in e.primitives(tcx) {
1992 if crate_name == sym::core && primitive_locations.contains_key(&prim) {
1994 continue;
1995 }
1996 primitive_locations.insert(prim, def_id);
1997 }
1998 }
1999 let local_primitives = ExternalCrate { crate_num: LOCAL_CRATE }.primitives(tcx);
2000 for (def_id, prim) in local_primitives {
2001 primitive_locations.insert(prim, def_id);
2002 }
2003 primitive_locations
2004 })
2005 }
2006}
2007
2008impl From<ty::IntTy> for PrimitiveType {
2009 fn from(int_ty: ty::IntTy) -> PrimitiveType {
2010 match int_ty {
2011 ty::IntTy::Isize => PrimitiveType::Isize,
2012 ty::IntTy::I8 => PrimitiveType::I8,
2013 ty::IntTy::I16 => PrimitiveType::I16,
2014 ty::IntTy::I32 => PrimitiveType::I32,
2015 ty::IntTy::I64 => PrimitiveType::I64,
2016 ty::IntTy::I128 => PrimitiveType::I128,
2017 }
2018 }
2019}
2020
2021impl From<ty::UintTy> for PrimitiveType {
2022 fn from(uint_ty: ty::UintTy) -> PrimitiveType {
2023 match uint_ty {
2024 ty::UintTy::Usize => PrimitiveType::Usize,
2025 ty::UintTy::U8 => PrimitiveType::U8,
2026 ty::UintTy::U16 => PrimitiveType::U16,
2027 ty::UintTy::U32 => PrimitiveType::U32,
2028 ty::UintTy::U64 => PrimitiveType::U64,
2029 ty::UintTy::U128 => PrimitiveType::U128,
2030 }
2031 }
2032}
2033
2034impl From<ty::FloatTy> for PrimitiveType {
2035 fn from(float_ty: ty::FloatTy) -> PrimitiveType {
2036 match float_ty {
2037 ty::FloatTy::F16 => PrimitiveType::F16,
2038 ty::FloatTy::F32 => PrimitiveType::F32,
2039 ty::FloatTy::F64 => PrimitiveType::F64,
2040 ty::FloatTy::F128 => PrimitiveType::F128,
2041 }
2042 }
2043}
2044
2045impl From<hir::PrimTy> for PrimitiveType {
2046 fn from(prim_ty: hir::PrimTy) -> PrimitiveType {
2047 match prim_ty {
2048 hir::PrimTy::Int(int_ty) => int_ty.into(),
2049 hir::PrimTy::Uint(uint_ty) => uint_ty.into(),
2050 hir::PrimTy::Float(float_ty) => float_ty.into(),
2051 hir::PrimTy::Str => PrimitiveType::Str,
2052 hir::PrimTy::Bool => PrimitiveType::Bool,
2053 hir::PrimTy::Char => PrimitiveType::Char,
2054 }
2055 }
2056}
2057
2058#[derive(Clone, Debug)]
2059pub(crate) struct Struct {
2060 pub(crate) ctor_kind: Option<CtorKind>,
2061 pub(crate) generics: Generics,
2062 pub(crate) fields: ThinVec<Item>,
2063}
2064
2065impl Struct {
2066 pub(crate) fn has_stripped_entries(&self) -> bool {
2067 self.fields.iter().any(|f| f.is_stripped())
2068 }
2069}
2070
2071#[derive(Clone, Debug)]
2072pub(crate) struct Union {
2073 pub(crate) generics: Generics,
2074 pub(crate) fields: Vec<Item>,
2075}
2076
2077impl Union {
2078 pub(crate) fn has_stripped_entries(&self) -> bool {
2079 self.fields.iter().any(|f| f.is_stripped())
2080 }
2081}
2082
2083#[derive(Clone, Debug)]
2087pub(crate) struct VariantStruct {
2088 pub(crate) fields: ThinVec<Item>,
2089}
2090
2091impl VariantStruct {
2092 pub(crate) fn has_stripped_entries(&self) -> bool {
2093 self.fields.iter().any(|f| f.is_stripped())
2094 }
2095}
2096
2097#[derive(Clone, Debug)]
2098pub(crate) struct Enum {
2099 pub(crate) variants: IndexVec<VariantIdx, Item>,
2100 pub(crate) generics: Generics,
2101}
2102
2103impl Enum {
2104 pub(crate) fn has_stripped_entries(&self) -> bool {
2105 self.variants.iter().any(|f| f.is_stripped())
2106 }
2107
2108 pub(crate) fn non_stripped_variants(&self) -> impl Iterator<Item = &Item> {
2109 self.variants.iter().filter(|v| !v.is_stripped())
2110 }
2111}
2112
2113#[derive(Clone, Debug)]
2114pub(crate) struct Variant {
2115 pub kind: VariantKind,
2116 pub discriminant: Option<Discriminant>,
2117}
2118
2119#[derive(Clone, Debug)]
2120pub(crate) enum VariantKind {
2121 CLike,
2122 Tuple(ThinVec<Item>),
2123 Struct(VariantStruct),
2124}
2125
2126impl Variant {
2127 pub(crate) fn has_stripped_entries(&self) -> Option<bool> {
2128 match &self.kind {
2129 VariantKind::Struct(struct_) => Some(struct_.has_stripped_entries()),
2130 VariantKind::CLike | VariantKind::Tuple(_) => None,
2131 }
2132 }
2133}
2134
2135#[derive(Clone, Debug)]
2136pub(crate) struct Discriminant {
2137 pub(super) expr: Option<BodyId>,
2140 pub(super) value: DefId,
2141}
2142
2143impl Discriminant {
2144 pub(crate) fn expr(&self, tcx: TyCtxt<'_>) -> Option<String> {
2147 self.expr
2148 .map(|body| rendered_const(tcx, tcx.hir_body(body), tcx.hir_body_owner_def_id(body)))
2149 }
2150 pub(crate) fn value(&self, tcx: TyCtxt<'_>, with_underscores: bool) -> String {
2151 print_evaluated_const(tcx, self.value, with_underscores, false).unwrap()
2152 }
2153}
2154
2155#[derive(Copy, Clone, Debug)]
2158pub(crate) struct Span(rustc_span::Span);
2159
2160impl Span {
2161 pub(crate) fn new(sp: rustc_span::Span) -> Self {
2166 Self(sp.source_callsite())
2167 }
2168
2169 pub(crate) fn inner(&self) -> rustc_span::Span {
2170 self.0
2171 }
2172
2173 pub(crate) fn filename(&self, sess: &Session) -> FileName {
2174 sess.source_map().span_to_filename(self.0)
2175 }
2176
2177 pub(crate) fn lo(&self, sess: &Session) -> Loc {
2178 sess.source_map().lookup_char_pos(self.0.lo())
2179 }
2180
2181 pub(crate) fn hi(&self, sess: &Session) -> Loc {
2182 sess.source_map().lookup_char_pos(self.0.hi())
2183 }
2184
2185 pub(crate) fn cnum(&self, sess: &Session) -> CrateNum {
2186 self.lo(sess).file.cnum
2188 }
2189}
2190
2191#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2192pub(crate) struct Path {
2193 pub(crate) res: Res,
2194 pub(crate) segments: ThinVec<PathSegment>,
2195}
2196
2197impl Path {
2198 pub(crate) fn def_id(&self) -> DefId {
2199 self.res.def_id()
2200 }
2201
2202 pub(crate) fn last_opt(&self) -> Option<Symbol> {
2203 self.segments.last().map(|s| s.name)
2204 }
2205
2206 pub(crate) fn last(&self) -> Symbol {
2207 self.last_opt().expect("segments were empty")
2208 }
2209
2210 pub(crate) fn whole_name(&self) -> String {
2211 self.segments
2212 .iter()
2213 .map(|s| if s.name == kw::PathRoot { "" } else { s.name.as_str() })
2214 .intersperse("::")
2215 .collect()
2216 }
2217
2218 pub(crate) fn is_assoc_ty(&self) -> bool {
2220 match self.res {
2221 Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } | Res::Def(DefKind::TyParam, _)
2222 if self.segments.len() != 1 =>
2223 {
2224 true
2225 }
2226 Res::Def(DefKind::AssocTy, _) => true,
2227 _ => false,
2228 }
2229 }
2230
2231 pub(crate) fn generic_args(&self) -> Option<&GenericArgs> {
2232 self.segments.last().map(|seg| &seg.args)
2233 }
2234
2235 pub(crate) fn generics(&self) -> Option<impl Iterator<Item = &Type>> {
2236 self.segments.last().and_then(|seg| {
2237 if let GenericArgs::AngleBracketed { ref args, .. } = seg.args {
2238 Some(args.iter().filter_map(|arg| match arg {
2239 GenericArg::Type(ty) => Some(ty),
2240 _ => None,
2241 }))
2242 } else {
2243 None
2244 }
2245 })
2246 }
2247}
2248
2249#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2250pub(crate) enum GenericArg {
2251 Lifetime(Lifetime),
2252 Type(Type),
2253 Const(Box<ConstantKind>),
2254 Infer,
2255}
2256
2257impl GenericArg {
2258 pub(crate) fn as_lt(&self) -> Option<&Lifetime> {
2259 if let Self::Lifetime(lt) = self { Some(lt) } else { None }
2260 }
2261
2262 pub(crate) fn as_ty(&self) -> Option<&Type> {
2263 if let Self::Type(ty) = self { Some(ty) } else { None }
2264 }
2265}
2266
2267#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2268pub(crate) enum GenericArgs {
2269 AngleBracketed { args: ThinVec<GenericArg>, constraints: ThinVec<AssocItemConstraint> },
2271 Parenthesized { inputs: ThinVec<Type>, output: Option<Box<Type>> },
2273 ReturnTypeNotation,
2275}
2276
2277impl GenericArgs {
2278 pub(crate) fn is_empty(&self) -> bool {
2279 match self {
2280 GenericArgs::AngleBracketed { args, constraints } => {
2281 args.is_empty() && constraints.is_empty()
2282 }
2283 GenericArgs::Parenthesized { inputs, output } => inputs.is_empty() && output.is_none(),
2284 GenericArgs::ReturnTypeNotation => false,
2285 }
2286 }
2287 pub(crate) fn constraints(&self) -> Box<dyn Iterator<Item = AssocItemConstraint> + '_> {
2288 match self {
2289 GenericArgs::AngleBracketed { constraints, .. } => {
2290 Box::new(constraints.iter().cloned())
2291 }
2292 GenericArgs::Parenthesized { output, .. } => Box::new(
2293 output
2294 .as_ref()
2295 .map(|ty| AssocItemConstraint {
2296 assoc: PathSegment {
2297 name: sym::Output,
2298 args: GenericArgs::AngleBracketed {
2299 args: ThinVec::new(),
2300 constraints: ThinVec::new(),
2301 },
2302 },
2303 kind: AssocItemConstraintKind::Equality {
2304 term: Term::Type((**ty).clone()),
2305 },
2306 })
2307 .into_iter(),
2308 ),
2309 GenericArgs::ReturnTypeNotation => Box::new([].into_iter()),
2310 }
2311 }
2312}
2313
2314impl<'a> IntoIterator for &'a GenericArgs {
2315 type IntoIter = Box<dyn Iterator<Item = GenericArg> + 'a>;
2316 type Item = GenericArg;
2317 fn into_iter(self) -> Self::IntoIter {
2318 match self {
2319 GenericArgs::AngleBracketed { args, .. } => Box::new(args.iter().cloned()),
2320 GenericArgs::Parenthesized { inputs, .. } => {
2321 Box::new(inputs.iter().cloned().map(GenericArg::Type))
2323 }
2324 GenericArgs::ReturnTypeNotation => Box::new([].into_iter()),
2325 }
2326 }
2327}
2328
2329#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2330pub(crate) struct PathSegment {
2331 pub(crate) name: Symbol,
2332 pub(crate) args: GenericArgs,
2333}
2334
2335#[derive(Clone, Debug)]
2336pub(crate) enum TypeAliasInnerType {
2337 Enum { variants: IndexVec<VariantIdx, Item>, is_non_exhaustive: bool },
2338 Union { fields: Vec<Item> },
2339 Struct { ctor_kind: Option<CtorKind>, fields: Vec<Item> },
2340}
2341
2342impl TypeAliasInnerType {
2343 fn has_stripped_entries(&self) -> Option<bool> {
2344 Some(match self {
2345 Self::Enum { variants, .. } => variants.iter().any(|v| v.is_stripped()),
2346 Self::Union { fields } | Self::Struct { fields, .. } => {
2347 fields.iter().any(|f| f.is_stripped())
2348 }
2349 })
2350 }
2351}
2352
2353#[derive(Clone, Debug)]
2354pub(crate) struct TypeAlias {
2355 pub(crate) type_: Type,
2356 pub(crate) generics: Generics,
2357 pub(crate) inner_type: Option<TypeAliasInnerType>,
2360 pub(crate) item_type: Option<Type>,
2367}
2368
2369#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2370pub(crate) struct BareFunctionDecl {
2371 pub(crate) safety: hir::Safety,
2372 pub(crate) generic_params: Vec<GenericParamDef>,
2373 pub(crate) decl: FnDecl,
2374 pub(crate) abi: ExternAbi,
2375}
2376
2377#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2378pub(crate) struct UnsafeBinderTy {
2379 pub(crate) generic_params: Vec<GenericParamDef>,
2380 pub(crate) ty: Type,
2381}
2382
2383#[derive(Clone, Debug)]
2384pub(crate) struct Static {
2385 pub(crate) type_: Box<Type>,
2386 pub(crate) mutability: Mutability,
2387 pub(crate) expr: Option<BodyId>,
2388}
2389
2390#[derive(Clone, PartialEq, Eq, Hash, Debug)]
2391pub(crate) struct Constant {
2392 pub(crate) generics: Generics,
2393 pub(crate) kind: ConstantKind,
2394 pub(crate) type_: Type,
2395}
2396
2397#[derive(Clone, PartialEq, Eq, Hash, Debug)]
2398pub(crate) enum Term {
2399 Type(Type),
2400 Constant(ConstantKind),
2401}
2402
2403impl Term {
2404 pub(crate) fn ty(&self) -> Option<&Type> {
2405 if let Term::Type(ty) = self { Some(ty) } else { None }
2406 }
2407}
2408
2409impl From<Type> for Term {
2410 fn from(ty: Type) -> Self {
2411 Term::Type(ty)
2412 }
2413}
2414
2415#[derive(Clone, PartialEq, Eq, Hash, Debug)]
2416pub(crate) enum ConstantKind {
2417 TyConst { expr: Box<str> },
2423 Path { path: Box<str> },
2426 Anonymous { body: BodyId },
2430 Extern { def_id: DefId },
2432 Local { def_id: DefId, body: BodyId },
2434 Infer,
2436}
2437
2438impl ConstantKind {
2439 pub(crate) fn expr(&self, tcx: TyCtxt<'_>) -> String {
2440 match *self {
2441 ConstantKind::TyConst { ref expr } => expr.to_string(),
2442 ConstantKind::Path { ref path } => path.to_string(),
2443 ConstantKind::Extern { def_id } => print_inlined_const(tcx, def_id),
2444 ConstantKind::Local { body, .. } | ConstantKind::Anonymous { body } => {
2445 rendered_const(tcx, tcx.hir_body(body), tcx.hir_body_owner_def_id(body))
2446 }
2447 ConstantKind::Infer => "_".to_string(),
2448 }
2449 }
2450
2451 pub(crate) fn value(&self, tcx: TyCtxt<'_>) -> Option<String> {
2452 match *self {
2453 ConstantKind::TyConst { .. }
2454 | ConstantKind::Path { .. }
2455 | ConstantKind::Anonymous { .. }
2456 | ConstantKind::Infer => None,
2457 ConstantKind::Extern { def_id } | ConstantKind::Local { def_id, .. } => {
2458 print_evaluated_const(tcx, def_id, true, true)
2459 }
2460 }
2461 }
2462
2463 pub(crate) fn is_literal(&self, tcx: TyCtxt<'_>) -> bool {
2464 match *self {
2465 ConstantKind::TyConst { .. }
2466 | ConstantKind::Extern { .. }
2467 | ConstantKind::Path { .. }
2468 | ConstantKind::Infer => false,
2469 ConstantKind::Local { body, .. } | ConstantKind::Anonymous { body } => {
2470 is_literal_expr(tcx, body.hir_id)
2471 }
2472 }
2473 }
2474}
2475
2476#[derive(Clone, Debug)]
2477pub(crate) struct Impl {
2478 pub(crate) safety: hir::Safety,
2479 pub(crate) generics: Generics,
2480 pub(crate) trait_: Option<Path>,
2481 pub(crate) for_: Type,
2482 pub(crate) items: Vec<Item>,
2483 pub(crate) polarity: ty::ImplPolarity,
2484 pub(crate) kind: ImplKind,
2485}
2486
2487impl Impl {
2488 pub(crate) fn provided_trait_methods(&self, tcx: TyCtxt<'_>) -> FxIndexSet<Symbol> {
2489 self.trait_
2490 .as_ref()
2491 .map(|t| t.def_id())
2492 .map(|did| tcx.provided_trait_methods(did).map(|meth| meth.name()).collect())
2493 .unwrap_or_default()
2494 }
2495
2496 pub(crate) fn is_negative_trait_impl(&self) -> bool {
2497 matches!(self.polarity, ty::ImplPolarity::Negative)
2498 }
2499}
2500
2501#[derive(Clone, Debug)]
2502pub(crate) enum ImplKind {
2503 Normal,
2504 Auto,
2505 FakeVariadic,
2506 Blanket(Box<Type>),
2507}
2508
2509impl ImplKind {
2510 pub(crate) fn is_auto(&self) -> bool {
2511 matches!(self, ImplKind::Auto)
2512 }
2513
2514 pub(crate) fn is_blanket(&self) -> bool {
2515 matches!(self, ImplKind::Blanket(_))
2516 }
2517
2518 pub(crate) fn is_fake_variadic(&self) -> bool {
2519 matches!(self, ImplKind::FakeVariadic)
2520 }
2521
2522 pub(crate) fn as_blanket_ty(&self) -> Option<&Type> {
2523 match self {
2524 ImplKind::Blanket(ty) => Some(ty),
2525 _ => None,
2526 }
2527 }
2528}
2529
2530#[derive(Clone, Debug)]
2531pub(crate) struct Import {
2532 pub(crate) kind: ImportKind,
2533 pub(crate) source: ImportSource,
2535 pub(crate) should_be_displayed: bool,
2536}
2537
2538impl Import {
2539 pub(crate) fn new_simple(
2540 name: Symbol,
2541 source: ImportSource,
2542 should_be_displayed: bool,
2543 ) -> Self {
2544 Self { kind: ImportKind::Simple(name), source, should_be_displayed }
2545 }
2546
2547 pub(crate) fn new_glob(source: ImportSource, should_be_displayed: bool) -> Self {
2548 Self { kind: ImportKind::Glob, source, should_be_displayed }
2549 }
2550
2551 pub(crate) fn imported_item_is_doc_hidden(&self, tcx: TyCtxt<'_>) -> bool {
2552 self.source.did.is_some_and(|did| tcx.is_doc_hidden(did))
2553 }
2554}
2555
2556#[derive(Clone, Debug)]
2557pub(crate) enum ImportKind {
2558 Simple(Symbol),
2560 Glob,
2562}
2563
2564#[derive(Clone, Debug)]
2565pub(crate) struct ImportSource {
2566 pub(crate) path: Path,
2567 pub(crate) did: Option<DefId>,
2568}
2569
2570#[derive(Clone, Debug)]
2571pub(crate) struct Macro {
2572 pub(crate) source: String,
2573 pub(crate) macro_rules: bool,
2575}
2576
2577#[derive(Clone, Debug)]
2578pub(crate) struct ProcMacro {
2579 pub(crate) kind: MacroKind,
2580 pub(crate) helpers: Vec<Symbol>,
2581}
2582
2583#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2594pub(crate) struct AssocItemConstraint {
2595 pub(crate) assoc: PathSegment,
2596 pub(crate) kind: AssocItemConstraintKind,
2597}
2598
2599#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2601pub(crate) enum AssocItemConstraintKind {
2602 Equality { term: Term },
2603 Bound { bounds: Vec<GenericBound> },
2604}
2605
2606#[cfg(target_pointer_width = "64")]
2608mod size_asserts {
2609 use rustc_data_structures::static_assert_size;
2610
2611 use super::*;
2612 static_assert_size!(Crate, 16); static_assert_size!(DocFragment, 32);
2615 static_assert_size!(GenericArg, 32);
2616 static_assert_size!(GenericArgs, 24);
2617 static_assert_size!(GenericParamDef, 40);
2618 static_assert_size!(Generics, 16);
2619 static_assert_size!(Item, 8);
2620 static_assert_size!(ItemInner, 144);
2621 static_assert_size!(ItemKind, 48);
2622 static_assert_size!(PathSegment, 32);
2623 static_assert_size!(Type, 32);
2624 }