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 match tcx.opt_associated_item(def_id) {
694 Some(ty::AssocItem {
695 container: ty::AssocItemContainer::Impl,
696 trait_item_def_id: Some(_),
697 ..
698 })
699 | Some(ty::AssocItem { container: ty::AssocItemContainer::Trait, .. }) => {
700 hir::Constness::NotConst
701 }
702 None | Some(_) => hir::Constness::Const,
703 }
704 } else {
705 hir::Constness::NotConst
706 };
707 let asyncness = match asyncness {
708 ty::Asyncness::Yes => hir::IsAsync::Async(DUMMY_SP),
709 ty::Asyncness::No => hir::IsAsync::NotAsync,
710 };
711 hir::FnHeader {
712 safety: if tcx.codegen_fn_attrs(def_id).safe_target_features {
713 hir::HeaderSafety::SafeTargetFeatures
714 } else {
715 sig.safety().into()
716 },
717 abi: sig.abi(),
718 constness,
719 asyncness,
720 }
721 }
722 let header = match self.kind {
723 ItemKind::ForeignFunctionItem(_, safety) => {
724 let def_id = self.def_id().unwrap();
725 let abi = tcx.fn_sig(def_id).skip_binder().abi();
726 hir::FnHeader {
727 safety: if tcx.codegen_fn_attrs(def_id).safe_target_features {
728 hir::HeaderSafety::SafeTargetFeatures
729 } else {
730 safety.into()
731 },
732 abi,
733 constness: if tcx.is_const_fn(def_id) {
734 hir::Constness::Const
735 } else {
736 hir::Constness::NotConst
737 },
738 asyncness: hir::IsAsync::NotAsync,
739 }
740 }
741 ItemKind::FunctionItem(_)
742 | ItemKind::MethodItem(_, _)
743 | ItemKind::RequiredMethodItem(_) => {
744 let def_id = self.def_id().unwrap();
745 build_fn_header(def_id, tcx, tcx.asyncness(def_id))
746 }
747 _ => return None,
748 };
749 Some(header)
750 }
751
752 pub(crate) fn visibility(&self, tcx: TyCtxt<'_>) -> Option<Visibility<DefId>> {
755 let def_id = match self.item_id {
756 ItemId::Auto { .. } | ItemId::Blanket { .. } => return None,
758 ItemId::DefId(def_id) => def_id,
759 };
760
761 match self.kind {
762 ItemKind::KeywordItem | ItemKind::PrimitiveItem(_) | ItemKind::AttributeItem => {
766 return Some(Visibility::Public);
767 }
768 StructFieldItem(..) if is_field_vis_inherited(tcx, def_id) => {
770 return None;
771 }
772 VariantItem(..) | ImplItem(..) => return None,
774 RequiredAssocConstItem(..)
776 | ProvidedAssocConstItem(..)
777 | ImplAssocConstItem(..)
778 | AssocTypeItem(..)
779 | RequiredAssocTypeItem(..)
780 | RequiredMethodItem(..)
781 | MethodItem(..) => {
782 let assoc_item = tcx.associated_item(def_id);
783 let is_trait_item = match assoc_item.container {
784 ty::AssocItemContainer::Trait => true,
785 ty::AssocItemContainer::Impl => {
786 tcx.impl_trait_ref(tcx.parent(assoc_item.def_id)).is_some()
789 }
790 };
791 if is_trait_item {
792 return None;
793 }
794 }
795 _ => {}
796 }
797 let def_id = match self.inline_stmt_id {
798 Some(inlined) => inlined.to_def_id(),
799 None => def_id,
800 };
801 Some(tcx.visibility(def_id))
802 }
803
804 fn attributes_without_repr(&self) -> Vec<String> {
808 self.attrs
809 .other_attrs
810 .iter()
811 .filter_map(|attr| match attr {
812 hir::Attribute::Parsed(AttributeKind::LinkSection { name, .. }) => {
813 Some(format!("#[unsafe(link_section = \"{name}\")]"))
814 }
815 hir::Attribute::Parsed(AttributeKind::NoMangle(..)) => {
816 Some("#[unsafe(no_mangle)]".to_string())
817 }
818 hir::Attribute::Parsed(AttributeKind::ExportName { name, .. }) => {
819 Some(format!("#[unsafe(export_name = \"{name}\")]"))
820 }
821 hir::Attribute::Parsed(AttributeKind::NonExhaustive(..)) => {
822 Some("#[non_exhaustive]".to_string())
823 }
824 _ => None,
825 })
826 .collect()
827 }
828
829 pub(crate) fn attributes(&self, tcx: TyCtxt<'_>, cache: &Cache) -> Vec<String> {
833 let mut attrs = self.attributes_without_repr();
834
835 if let Some(repr_attr) = self.repr(tcx, cache) {
836 attrs.push(repr_attr);
837 }
838 attrs
839 }
840
841 pub(crate) fn repr(&self, tcx: TyCtxt<'_>, cache: &Cache) -> Option<String> {
845 repr_attributes(tcx, cache, self.def_id()?, self.type_())
846 }
847
848 pub fn is_doc_hidden(&self) -> bool {
849 self.attrs.is_doc_hidden()
850 }
851
852 pub fn def_id(&self) -> Option<DefId> {
853 self.item_id.as_def_id()
854 }
855}
856
857pub(crate) fn repr_attributes(
861 tcx: TyCtxt<'_>,
862 cache: &Cache,
863 def_id: DefId,
864 item_type: ItemType,
865) -> Option<String> {
866 use rustc_abi::IntegerType;
867
868 if !matches!(item_type, ItemType::Struct | ItemType::Enum | ItemType::Union) {
869 return None;
870 }
871 let adt = tcx.adt_def(def_id);
872 let repr = adt.repr();
873 let mut out = Vec::new();
874 if repr.c() {
875 out.push("C");
876 }
877 if repr.transparent() {
878 let render_transparent = cache.document_private
881 || adt
882 .all_fields()
883 .find(|field| {
884 let ty = field.ty(tcx, ty::GenericArgs::identity_for_item(tcx, field.did));
885 tcx.layout_of(ty::TypingEnv::post_analysis(tcx, field.did).as_query_input(ty))
886 .is_ok_and(|layout| !layout.is_1zst())
887 })
888 .map_or_else(
889 || adt.all_fields().any(|field| field.vis.is_public()),
890 |field| field.vis.is_public(),
891 );
892
893 if render_transparent {
894 out.push("transparent");
895 }
896 }
897 if repr.simd() {
898 out.push("simd");
899 }
900 let pack_s;
901 if let Some(pack) = repr.pack {
902 pack_s = format!("packed({})", pack.bytes());
903 out.push(&pack_s);
904 }
905 let align_s;
906 if let Some(align) = repr.align {
907 align_s = format!("align({})", align.bytes());
908 out.push(&align_s);
909 }
910 let int_s;
911 if let Some(int) = repr.int {
912 int_s = match int {
913 IntegerType::Pointer(is_signed) => {
914 format!("{}size", if is_signed { 'i' } else { 'u' })
915 }
916 IntegerType::Fixed(size, is_signed) => {
917 format!("{}{}", if is_signed { 'i' } else { 'u' }, size.size().bytes() * 8)
918 }
919 };
920 out.push(&int_s);
921 }
922 if !out.is_empty() { Some(format!("#[repr({})]", out.join(", "))) } else { None }
923}
924
925#[derive(Clone, Debug)]
926pub(crate) enum ItemKind {
927 ExternCrateItem {
928 src: Option<Symbol>,
930 },
931 ImportItem(Import),
932 StructItem(Struct),
933 UnionItem(Union),
934 EnumItem(Enum),
935 FunctionItem(Box<Function>),
936 ModuleItem(Module),
937 TypeAliasItem(Box<TypeAlias>),
938 StaticItem(Static),
939 TraitItem(Box<Trait>),
940 TraitAliasItem(TraitAlias),
941 ImplItem(Box<Impl>),
942 RequiredMethodItem(Box<Function>),
944 MethodItem(Box<Function>, Option<hir::Defaultness>),
948 StructFieldItem(Type),
949 VariantItem(Variant),
950 ForeignFunctionItem(Box<Function>, hir::Safety),
952 ForeignStaticItem(Static, hir::Safety),
954 ForeignTypeItem,
956 MacroItem(Macro),
957 ProcMacroItem(ProcMacro),
958 PrimitiveItem(PrimitiveType),
959 RequiredAssocConstItem(Generics, Box<Type>),
961 ConstantItem(Box<Constant>),
962 ProvidedAssocConstItem(Box<Constant>),
964 ImplAssocConstItem(Box<Constant>),
966 RequiredAssocTypeItem(Generics, Vec<GenericBound>),
970 AssocTypeItem(Box<TypeAlias>, Vec<GenericBound>),
972 StrippedItem(Box<ItemKind>),
974 KeywordItem,
977 AttributeItem,
980}
981
982impl ItemKind {
983 pub(crate) fn inner_items(&self) -> impl Iterator<Item = &Item> {
986 match self {
987 StructItem(s) => s.fields.iter(),
988 UnionItem(u) => u.fields.iter(),
989 VariantItem(v) => match &v.kind {
990 VariantKind::CLike => [].iter(),
991 VariantKind::Tuple(t) => t.iter(),
992 VariantKind::Struct(s) => s.fields.iter(),
993 },
994 EnumItem(e) => e.variants.iter(),
995 TraitItem(t) => t.items.iter(),
996 ImplItem(i) => i.items.iter(),
997 ModuleItem(m) => m.items.iter(),
998 ExternCrateItem { .. }
999 | ImportItem(_)
1000 | FunctionItem(_)
1001 | TypeAliasItem(_)
1002 | StaticItem(_)
1003 | ConstantItem(_)
1004 | TraitAliasItem(_)
1005 | RequiredMethodItem(_)
1006 | MethodItem(_, _)
1007 | StructFieldItem(_)
1008 | ForeignFunctionItem(_, _)
1009 | ForeignStaticItem(_, _)
1010 | ForeignTypeItem
1011 | MacroItem(_)
1012 | ProcMacroItem(_)
1013 | PrimitiveItem(_)
1014 | RequiredAssocConstItem(..)
1015 | ProvidedAssocConstItem(..)
1016 | ImplAssocConstItem(..)
1017 | RequiredAssocTypeItem(..)
1018 | AssocTypeItem(..)
1019 | StrippedItem(_)
1020 | KeywordItem
1021 | AttributeItem => [].iter(),
1022 }
1023 }
1024
1025 pub(crate) fn is_non_assoc(&self) -> bool {
1027 matches!(
1028 self,
1029 StructItem(_)
1030 | UnionItem(_)
1031 | EnumItem(_)
1032 | TraitItem(_)
1033 | ModuleItem(_)
1034 | ExternCrateItem { .. }
1035 | FunctionItem(_)
1036 | TypeAliasItem(_)
1037 | StaticItem(_)
1038 | ConstantItem(_)
1039 | TraitAliasItem(_)
1040 | ForeignFunctionItem(_, _)
1041 | ForeignStaticItem(_, _)
1042 | ForeignTypeItem
1043 | MacroItem(_)
1044 | ProcMacroItem(_)
1045 | PrimitiveItem(_)
1046 )
1047 }
1048}
1049
1050#[derive(Clone, Debug)]
1051pub(crate) struct Module {
1052 pub(crate) items: Vec<Item>,
1053 pub(crate) span: Span,
1054}
1055
1056pub(crate) fn hir_attr_lists<'a, I: IntoIterator<Item = &'a hir::Attribute>>(
1057 attrs: I,
1058 name: Symbol,
1059) -> impl Iterator<Item = ast::MetaItemInner> + use<'a, I> {
1060 attrs
1061 .into_iter()
1062 .filter(move |attr| attr.has_name(name))
1063 .filter_map(ast::attr::AttributeExt::meta_item_list)
1064 .flatten()
1065}
1066
1067pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator<Item = &'a hir::Attribute> + Clone>(
1068 attrs: I,
1069 tcx: TyCtxt<'_>,
1070 hidden_cfg: &FxHashSet<Cfg>,
1071) -> Option<Arc<Cfg>> {
1072 let doc_cfg_active = tcx.features().doc_cfg();
1073 let doc_auto_cfg_active = tcx.features().doc_auto_cfg();
1074
1075 fn single<T: IntoIterator>(it: T) -> Option<T::Item> {
1076 let mut iter = it.into_iter();
1077 let item = iter.next()?;
1078 if iter.next().is_some() {
1079 return None;
1080 }
1081 Some(item)
1082 }
1083
1084 let mut cfg = if doc_cfg_active || doc_auto_cfg_active {
1085 let mut doc_cfg = attrs
1086 .clone()
1087 .filter(|attr| attr.has_name(sym::doc))
1088 .flat_map(|attr| attr.meta_item_list().unwrap_or_default())
1089 .filter(|attr| attr.has_name(sym::cfg))
1090 .peekable();
1091 if doc_cfg.peek().is_some() && doc_cfg_active {
1092 let sess = tcx.sess;
1093
1094 doc_cfg.fold(Cfg::True, |mut cfg, item| {
1095 if let Some(cfg_mi) =
1096 item.meta_item().and_then(|item| rustc_expand::config::parse_cfg(item, sess))
1097 {
1098 match Cfg::parse(cfg_mi) {
1099 Ok(new_cfg) => cfg &= new_cfg,
1100 Err(e) => {
1101 sess.dcx().span_err(e.span, e.msg);
1102 }
1103 }
1104 }
1105 cfg
1106 })
1107 } else if doc_auto_cfg_active {
1108 attrs
1111 .clone()
1112 .filter(|attr| attr.has_name(sym::cfg_trace))
1113 .filter_map(|attr| single(attr.meta_item_list()?))
1114 .filter_map(|attr| Cfg::parse_without(attr.meta_item()?, hidden_cfg).ok().flatten())
1115 .fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg)
1116 } else {
1117 Cfg::True
1118 }
1119 } else {
1120 Cfg::True
1121 };
1122
1123 if let Some(features) =
1126 find_attr!(attrs, AttributeKind::TargetFeature { features, .. } => features)
1127 {
1128 for (feature, _) in features {
1129 cfg &= Cfg::Cfg(sym::target_feature, Some(*feature));
1130 }
1131 }
1132
1133 if cfg == Cfg::True { None } else { Some(Arc::new(cfg)) }
1134}
1135
1136pub(crate) trait NestedAttributesExt {
1137 fn has_word(self, word: Symbol) -> bool
1139 where
1140 Self: Sized,
1141 {
1142 <Self as NestedAttributesExt>::get_word_attr(self, word).is_some()
1143 }
1144
1145 fn get_word_attr(self, word: Symbol) -> Option<ast::MetaItemInner>;
1148}
1149
1150impl<I: Iterator<Item = ast::MetaItemInner>> NestedAttributesExt for I {
1151 fn get_word_attr(mut self, word: Symbol) -> Option<ast::MetaItemInner> {
1152 self.find(|attr| attr.is_word() && attr.has_name(word))
1153 }
1154}
1155
1156#[derive(Clone, Debug, PartialEq, Eq, Hash)]
1160pub(crate) struct ItemLink {
1161 pub(crate) link: Box<str>,
1163 pub(crate) link_text: Box<str>,
1168 pub(crate) page_id: DefId,
1172 pub(crate) fragment: Option<UrlFragment>,
1174}
1175
1176pub struct RenderedLink {
1177 pub(crate) original_text: Box<str>,
1181 pub(crate) new_text: Box<str>,
1183 pub(crate) href: String,
1185 pub(crate) tooltip: String,
1187}
1188
1189#[derive(Clone, Debug, Default)]
1192pub(crate) struct Attributes {
1193 pub(crate) doc_strings: Vec<DocFragment>,
1194 pub(crate) other_attrs: ThinVec<hir::Attribute>,
1195}
1196
1197impl Attributes {
1198 pub(crate) fn lists(&self, name: Symbol) -> impl Iterator<Item = ast::MetaItemInner> {
1199 hir_attr_lists(&self.other_attrs[..], name)
1200 }
1201
1202 pub(crate) fn has_doc_flag(&self, flag: Symbol) -> bool {
1203 for attr in &self.other_attrs {
1204 if !attr.has_name(sym::doc) {
1205 continue;
1206 }
1207
1208 if let Some(items) = attr.meta_item_list()
1209 && items.iter().filter_map(|i| i.meta_item()).any(|it| it.has_name(flag))
1210 {
1211 return true;
1212 }
1213 }
1214
1215 false
1216 }
1217
1218 pub(crate) fn is_doc_hidden(&self) -> bool {
1219 self.has_doc_flag(sym::hidden)
1220 }
1221
1222 pub(crate) fn from_hir(attrs: &[hir::Attribute]) -> Attributes {
1223 Attributes::from_hir_iter(attrs.iter().map(|attr| (attr, None)), false)
1224 }
1225
1226 pub(crate) fn from_hir_with_additional(
1227 attrs: &[hir::Attribute],
1228 (additional_attrs, def_id): (&[hir::Attribute], DefId),
1229 ) -> Attributes {
1230 let attrs1 = additional_attrs.iter().map(|attr| (attr, Some(def_id)));
1232 let attrs2 = attrs.iter().map(|attr| (attr, None));
1233 Attributes::from_hir_iter(attrs1.chain(attrs2), false)
1234 }
1235
1236 pub(crate) fn from_hir_iter<'a>(
1237 attrs: impl Iterator<Item = (&'a hir::Attribute, Option<DefId>)>,
1238 doc_only: bool,
1239 ) -> Attributes {
1240 let (doc_strings, other_attrs) = attrs_to_doc_fragments(attrs, doc_only);
1241 Attributes { doc_strings, other_attrs }
1242 }
1243
1244 pub(crate) fn doc_value(&self) -> String {
1246 self.opt_doc_value().unwrap_or_default()
1247 }
1248
1249 pub(crate) fn opt_doc_value(&self) -> Option<String> {
1253 (!self.doc_strings.is_empty()).then(|| {
1254 let mut res = String::new();
1255 for frag in &self.doc_strings {
1256 add_doc_fragment(&mut res, frag);
1257 }
1258 res.pop();
1259 res
1260 })
1261 }
1262
1263 pub(crate) fn get_doc_aliases(&self) -> Box<[Symbol]> {
1264 let mut aliases = FxIndexSet::default();
1265
1266 for attr in
1267 hir_attr_lists(&self.other_attrs[..], sym::doc).filter(|a| a.has_name(sym::alias))
1268 {
1269 if let Some(values) = attr.meta_item_list() {
1270 for l in values {
1271 if let Some(lit) = l.lit()
1272 && let ast::LitKind::Str(s, _) = lit.kind
1273 {
1274 aliases.insert(s);
1275 }
1276 }
1277 } else if let Some(value) = attr.value_str() {
1278 aliases.insert(value);
1279 }
1280 }
1281 aliases.into_iter().collect::<Vec<_>>().into()
1282 }
1283}
1284
1285#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1286pub(crate) enum GenericBound {
1287 TraitBound(PolyTrait, hir::TraitBoundModifiers),
1288 Outlives(Lifetime),
1289 Use(Vec<PreciseCapturingArg>),
1291}
1292
1293impl GenericBound {
1294 pub(crate) fn sized(cx: &mut DocContext<'_>) -> GenericBound {
1295 Self::sized_with(cx, hir::TraitBoundModifiers::NONE)
1296 }
1297
1298 pub(crate) fn maybe_sized(cx: &mut DocContext<'_>) -> GenericBound {
1299 Self::sized_with(
1300 cx,
1301 hir::TraitBoundModifiers {
1302 polarity: hir::BoundPolarity::Maybe(DUMMY_SP),
1303 constness: hir::BoundConstness::Never,
1304 },
1305 )
1306 }
1307
1308 fn sized_with(cx: &mut DocContext<'_>, modifiers: hir::TraitBoundModifiers) -> GenericBound {
1309 let did = cx.tcx.require_lang_item(LangItem::Sized, DUMMY_SP);
1310 let empty = ty::Binder::dummy(ty::GenericArgs::empty());
1311 let path = clean_middle_path(cx, did, false, ThinVec::new(), empty);
1312 inline::record_extern_fqn(cx, did, ItemType::Trait);
1313 GenericBound::TraitBound(PolyTrait { trait_: path, generic_params: Vec::new() }, modifiers)
1314 }
1315
1316 pub(crate) fn is_trait_bound(&self) -> bool {
1317 matches!(self, Self::TraitBound(..))
1318 }
1319
1320 pub(crate) fn is_sized_bound(&self, cx: &DocContext<'_>) -> bool {
1321 self.is_bounded_by_lang_item(cx, LangItem::Sized)
1322 }
1323
1324 pub(crate) fn is_meta_sized_bound(&self, cx: &DocContext<'_>) -> bool {
1325 self.is_bounded_by_lang_item(cx, LangItem::MetaSized)
1326 }
1327
1328 fn is_bounded_by_lang_item(&self, cx: &DocContext<'_>, lang_item: LangItem) -> bool {
1329 if let GenericBound::TraitBound(
1330 PolyTrait { ref trait_, .. },
1331 rustc_hir::TraitBoundModifiers::NONE,
1332 ) = *self
1333 && cx.tcx.is_lang_item(trait_.def_id(), lang_item)
1334 {
1335 return true;
1336 }
1337 false
1338 }
1339
1340 pub(crate) fn get_trait_path(&self) -> Option<Path> {
1341 if let GenericBound::TraitBound(PolyTrait { ref trait_, .. }, _) = *self {
1342 Some(trait_.clone())
1343 } else {
1344 None
1345 }
1346 }
1347}
1348
1349#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
1350pub(crate) struct Lifetime(pub Symbol);
1351
1352impl Lifetime {
1353 pub(crate) fn statik() -> Lifetime {
1354 Lifetime(kw::StaticLifetime)
1355 }
1356
1357 pub(crate) fn elided() -> Lifetime {
1358 Lifetime(kw::UnderscoreLifetime)
1359 }
1360}
1361
1362#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
1363pub(crate) enum PreciseCapturingArg {
1364 Lifetime(Lifetime),
1365 Param(Symbol),
1366}
1367
1368impl PreciseCapturingArg {
1369 pub(crate) fn name(self) -> Symbol {
1370 match self {
1371 PreciseCapturingArg::Lifetime(lt) => lt.0,
1372 PreciseCapturingArg::Param(param) => param,
1373 }
1374 }
1375}
1376
1377#[derive(Clone, PartialEq, Eq, Hash, Debug)]
1378pub(crate) enum WherePredicate {
1379 BoundPredicate { ty: Type, bounds: Vec<GenericBound>, bound_params: Vec<GenericParamDef> },
1380 RegionPredicate { lifetime: Lifetime, bounds: Vec<GenericBound> },
1381 EqPredicate { lhs: QPathData, rhs: Term },
1382}
1383
1384impl WherePredicate {
1385 pub(crate) fn get_bounds(&self) -> Option<&[GenericBound]> {
1386 match self {
1387 WherePredicate::BoundPredicate { bounds, .. } => Some(bounds),
1388 WherePredicate::RegionPredicate { bounds, .. } => Some(bounds),
1389 _ => None,
1390 }
1391 }
1392}
1393
1394#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1395pub(crate) enum GenericParamDefKind {
1396 Lifetime { outlives: ThinVec<Lifetime> },
1397 Type { bounds: ThinVec<GenericBound>, default: Option<Box<Type>>, synthetic: bool },
1398 Const { ty: Box<Type>, default: Option<Box<String>> },
1400}
1401
1402impl GenericParamDefKind {
1403 pub(crate) fn is_type(&self) -> bool {
1404 matches!(self, GenericParamDefKind::Type { .. })
1405 }
1406}
1407
1408#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1409pub(crate) struct GenericParamDef {
1410 pub(crate) name: Symbol,
1411 pub(crate) def_id: DefId,
1412 pub(crate) kind: GenericParamDefKind,
1413}
1414
1415impl GenericParamDef {
1416 pub(crate) fn lifetime(def_id: DefId, name: Symbol) -> Self {
1417 Self { name, def_id, kind: GenericParamDefKind::Lifetime { outlives: ThinVec::new() } }
1418 }
1419
1420 pub(crate) fn is_synthetic_param(&self) -> bool {
1421 match self.kind {
1422 GenericParamDefKind::Lifetime { .. } | GenericParamDefKind::Const { .. } => false,
1423 GenericParamDefKind::Type { synthetic, .. } => synthetic,
1424 }
1425 }
1426
1427 pub(crate) fn is_type(&self) -> bool {
1428 self.kind.is_type()
1429 }
1430
1431 pub(crate) fn get_bounds(&self) -> Option<&[GenericBound]> {
1432 match self.kind {
1433 GenericParamDefKind::Type { ref bounds, .. } => Some(bounds),
1434 _ => None,
1435 }
1436 }
1437}
1438
1439#[derive(Clone, PartialEq, Eq, Hash, Debug, Default)]
1441pub(crate) struct Generics {
1442 pub(crate) params: ThinVec<GenericParamDef>,
1443 pub(crate) where_predicates: ThinVec<WherePredicate>,
1444}
1445
1446impl Generics {
1447 pub(crate) fn is_empty(&self) -> bool {
1448 self.params.is_empty() && self.where_predicates.is_empty()
1449 }
1450}
1451
1452#[derive(Clone, Debug)]
1453pub(crate) struct Function {
1454 pub(crate) decl: FnDecl,
1455 pub(crate) generics: Generics,
1456}
1457
1458#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1459pub(crate) struct FnDecl {
1460 pub(crate) inputs: Vec<Parameter>,
1461 pub(crate) output: Type,
1462 pub(crate) c_variadic: bool,
1463}
1464
1465impl FnDecl {
1466 pub(crate) fn receiver_type(&self) -> Option<&Type> {
1467 self.inputs.first().and_then(|v| v.to_receiver())
1468 }
1469}
1470
1471#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1473pub(crate) struct Parameter {
1474 pub(crate) name: Option<Symbol>,
1475 pub(crate) type_: Type,
1476 pub(crate) is_const: bool,
1479}
1480
1481impl Parameter {
1482 pub(crate) fn to_receiver(&self) -> Option<&Type> {
1483 if self.name == Some(kw::SelfLower) { Some(&self.type_) } else { None }
1484 }
1485}
1486
1487#[derive(Clone, Debug)]
1488pub(crate) struct Trait {
1489 pub(crate) def_id: DefId,
1490 pub(crate) items: Vec<Item>,
1491 pub(crate) generics: Generics,
1492 pub(crate) bounds: Vec<GenericBound>,
1493}
1494
1495impl Trait {
1496 pub(crate) fn is_auto(&self, tcx: TyCtxt<'_>) -> bool {
1497 tcx.trait_is_auto(self.def_id)
1498 }
1499 pub(crate) fn is_notable_trait(&self, tcx: TyCtxt<'_>) -> bool {
1500 tcx.is_doc_notable_trait(self.def_id)
1501 }
1502 pub(crate) fn safety(&self, tcx: TyCtxt<'_>) -> hir::Safety {
1503 tcx.trait_def(self.def_id).safety
1504 }
1505 pub(crate) fn is_dyn_compatible(&self, tcx: TyCtxt<'_>) -> bool {
1506 tcx.is_dyn_compatible(self.def_id)
1507 }
1508}
1509
1510#[derive(Clone, Debug)]
1511pub(crate) struct TraitAlias {
1512 pub(crate) generics: Generics,
1513 pub(crate) bounds: Vec<GenericBound>,
1514}
1515
1516#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1518pub(crate) struct PolyTrait {
1519 pub(crate) trait_: Path,
1520 pub(crate) generic_params: Vec<GenericParamDef>,
1521}
1522
1523#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1525pub(crate) enum Type {
1526 Path {
1531 path: Path,
1532 },
1533 DynTrait(Vec<PolyTrait>, Option<Lifetime>),
1535 Generic(Symbol),
1537 SelfTy,
1539 Primitive(PrimitiveType),
1541 BareFunction(Box<BareFunctionDecl>),
1543 Tuple(Vec<Type>),
1545 Slice(Box<Type>),
1547 Array(Box<Type>, Box<str>),
1551 Pat(Box<Type>, Box<str>),
1552 RawPointer(Mutability, Box<Type>),
1554 BorrowedRef {
1556 lifetime: Option<Lifetime>,
1557 mutability: Mutability,
1558 type_: Box<Type>,
1559 },
1560
1561 QPath(Box<QPathData>),
1563
1564 Infer,
1566
1567 ImplTrait(Vec<GenericBound>),
1569
1570 UnsafeBinder(Box<UnsafeBinderTy>),
1571}
1572
1573impl Type {
1574 pub(crate) fn without_borrowed_ref(&self) -> &Type {
1576 let mut result = self;
1577 while let Type::BorrowedRef { type_, .. } = result {
1578 result = type_;
1579 }
1580 result
1581 }
1582
1583 pub(crate) fn is_borrowed_ref(&self) -> bool {
1584 matches!(self, Type::BorrowedRef { .. })
1585 }
1586
1587 fn is_type_alias(&self) -> bool {
1588 matches!(self, Type::Path { path: Path { res: Res::Def(DefKind::TyAlias, _), .. } })
1589 }
1590
1591 pub(crate) fn is_doc_subtype_of(&self, other: &Self, cache: &Cache) -> bool {
1612 let (self_cleared, other_cleared) = if !self.is_borrowed_ref() || !other.is_borrowed_ref() {
1615 (self.without_borrowed_ref(), other.without_borrowed_ref())
1616 } else {
1617 (self, other)
1618 };
1619
1620 if self_cleared.is_type_alias() || other_cleared.is_type_alias() {
1626 return true;
1627 }
1628
1629 match (self_cleared, other_cleared) {
1630 (Type::Tuple(a), Type::Tuple(b)) => {
1632 a.len() == b.len() && a.iter().zip(b).all(|(a, b)| a.is_doc_subtype_of(b, cache))
1633 }
1634 (Type::Slice(a), Type::Slice(b)) => a.is_doc_subtype_of(b, cache),
1635 (Type::Array(a, al), Type::Array(b, bl)) => al == bl && a.is_doc_subtype_of(b, cache),
1636 (Type::RawPointer(mutability, type_), Type::RawPointer(b_mutability, b_type_)) => {
1637 mutability == b_mutability && type_.is_doc_subtype_of(b_type_, cache)
1638 }
1639 (
1640 Type::BorrowedRef { mutability, type_, .. },
1641 Type::BorrowedRef { mutability: b_mutability, type_: b_type_, .. },
1642 ) => mutability == b_mutability && type_.is_doc_subtype_of(b_type_, cache),
1643 (Type::Infer, _) | (_, Type::Infer) => true,
1645 (_, Type::Generic(_)) => true,
1648 (Type::Generic(_), _) => false,
1649 (Type::SelfTy, Type::SelfTy) => true,
1651 (Type::Path { path: a }, Type::Path { path: b }) => {
1653 a.def_id() == b.def_id()
1654 && a.generics()
1655 .zip(b.generics())
1656 .map(|(ag, bg)| ag.zip(bg).all(|(at, bt)| at.is_doc_subtype_of(bt, cache)))
1657 .unwrap_or(true)
1658 }
1659 (a, b) => a
1661 .def_id(cache)
1662 .and_then(|a| Some((a, b.def_id(cache)?)))
1663 .map(|(a, b)| a == b)
1664 .unwrap_or(false),
1665 }
1666 }
1667
1668 pub(crate) fn primitive_type(&self) -> Option<PrimitiveType> {
1669 match *self {
1670 Primitive(p) | BorrowedRef { type_: box Primitive(p), .. } => Some(p),
1671 Slice(..) | BorrowedRef { type_: box Slice(..), .. } => Some(PrimitiveType::Slice),
1672 Array(..) | BorrowedRef { type_: box Array(..), .. } => Some(PrimitiveType::Array),
1673 Tuple(ref tys) => {
1674 if tys.is_empty() {
1675 Some(PrimitiveType::Unit)
1676 } else {
1677 Some(PrimitiveType::Tuple)
1678 }
1679 }
1680 RawPointer(..) => Some(PrimitiveType::RawPointer),
1681 BareFunction(..) => Some(PrimitiveType::Fn),
1682 _ => None,
1683 }
1684 }
1685
1686 pub(crate) fn sugared_async_return_type(self) -> Type {
1696 if let Type::ImplTrait(mut v) = self
1697 && let Some(GenericBound::TraitBound(PolyTrait { mut trait_, .. }, _)) = v.pop()
1698 && let Some(segment) = trait_.segments.pop()
1699 && let GenericArgs::AngleBracketed { mut constraints, .. } = segment.args
1700 && let Some(constraint) = constraints.pop()
1701 && let AssocItemConstraintKind::Equality { term } = constraint.kind
1702 && let Term::Type(ty) = term
1703 {
1704 ty
1705 } else {
1706 panic!("unexpected async fn return type")
1707 }
1708 }
1709
1710 pub(crate) fn is_assoc_ty(&self) -> bool {
1712 match self {
1713 Type::Path { path, .. } => path.is_assoc_ty(),
1714 _ => false,
1715 }
1716 }
1717
1718 pub(crate) fn is_self_type(&self) -> bool {
1719 matches!(*self, Type::SelfTy)
1720 }
1721
1722 pub(crate) fn generic_args(&self) -> Option<&GenericArgs> {
1723 match self {
1724 Type::Path { path, .. } => path.generic_args(),
1725 _ => None,
1726 }
1727 }
1728
1729 pub(crate) fn generics(&self) -> Option<impl Iterator<Item = &Type>> {
1730 match self {
1731 Type::Path { path, .. } => path.generics(),
1732 _ => None,
1733 }
1734 }
1735
1736 pub(crate) fn is_full_generic(&self) -> bool {
1737 matches!(self, Type::Generic(_))
1738 }
1739
1740 pub(crate) fn is_unit(&self) -> bool {
1741 matches!(self, Type::Tuple(v) if v.is_empty())
1742 }
1743
1744 pub(crate) fn def_id(&self, cache: &Cache) -> Option<DefId> {
1748 let t: PrimitiveType = match self {
1749 Type::Path { path } => return Some(path.def_id()),
1750 DynTrait(bounds, _) => return bounds.first().map(|b| b.trait_.def_id()),
1751 Primitive(p) => return cache.primitive_locations.get(p).cloned(),
1752 BorrowedRef { type_: box Generic(..), .. } => PrimitiveType::Reference,
1753 BorrowedRef { type_, .. } => return type_.def_id(cache),
1754 Tuple(tys) => {
1755 if tys.is_empty() {
1756 PrimitiveType::Unit
1757 } else {
1758 PrimitiveType::Tuple
1759 }
1760 }
1761 BareFunction(..) => PrimitiveType::Fn,
1762 Slice(..) => PrimitiveType::Slice,
1763 Array(..) => PrimitiveType::Array,
1764 Type::Pat(..) => PrimitiveType::Pat,
1765 RawPointer(..) => PrimitiveType::RawPointer,
1766 QPath(box QPathData { self_type, .. }) => return self_type.def_id(cache),
1767 Generic(_) | SelfTy | Infer | ImplTrait(_) | UnsafeBinder(_) => return None,
1768 };
1769 Primitive(t).def_id(cache)
1770 }
1771}
1772
1773#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1774pub(crate) struct QPathData {
1775 pub assoc: PathSegment,
1776 pub self_type: Type,
1777 pub should_fully_qualify: bool,
1779 pub trait_: Option<Path>,
1780}
1781
1782#[derive(Clone, PartialEq, Eq, Hash, Copy, Debug)]
1789pub(crate) enum PrimitiveType {
1790 Isize,
1791 I8,
1792 I16,
1793 I32,
1794 I64,
1795 I128,
1796 Usize,
1797 U8,
1798 U16,
1799 U32,
1800 U64,
1801 U128,
1802 F16,
1803 F32,
1804 F64,
1805 F128,
1806 Char,
1807 Bool,
1808 Str,
1809 Slice,
1810 Array,
1811 Pat,
1812 Tuple,
1813 Unit,
1814 RawPointer,
1815 Reference,
1816 Fn,
1817 Never,
1818}
1819
1820type SimplifiedTypes = FxIndexMap<PrimitiveType, ArrayVec<SimplifiedType, 3>>;
1821impl PrimitiveType {
1822 pub(crate) fn from_hir(prim: hir::PrimTy) -> PrimitiveType {
1823 use ast::{FloatTy, IntTy, UintTy};
1824 match prim {
1825 hir::PrimTy::Int(IntTy::Isize) => PrimitiveType::Isize,
1826 hir::PrimTy::Int(IntTy::I8) => PrimitiveType::I8,
1827 hir::PrimTy::Int(IntTy::I16) => PrimitiveType::I16,
1828 hir::PrimTy::Int(IntTy::I32) => PrimitiveType::I32,
1829 hir::PrimTy::Int(IntTy::I64) => PrimitiveType::I64,
1830 hir::PrimTy::Int(IntTy::I128) => PrimitiveType::I128,
1831 hir::PrimTy::Uint(UintTy::Usize) => PrimitiveType::Usize,
1832 hir::PrimTy::Uint(UintTy::U8) => PrimitiveType::U8,
1833 hir::PrimTy::Uint(UintTy::U16) => PrimitiveType::U16,
1834 hir::PrimTy::Uint(UintTy::U32) => PrimitiveType::U32,
1835 hir::PrimTy::Uint(UintTy::U64) => PrimitiveType::U64,
1836 hir::PrimTy::Uint(UintTy::U128) => PrimitiveType::U128,
1837 hir::PrimTy::Float(FloatTy::F16) => PrimitiveType::F16,
1838 hir::PrimTy::Float(FloatTy::F32) => PrimitiveType::F32,
1839 hir::PrimTy::Float(FloatTy::F64) => PrimitiveType::F64,
1840 hir::PrimTy::Float(FloatTy::F128) => PrimitiveType::F128,
1841 hir::PrimTy::Str => PrimitiveType::Str,
1842 hir::PrimTy::Bool => PrimitiveType::Bool,
1843 hir::PrimTy::Char => PrimitiveType::Char,
1844 }
1845 }
1846
1847 pub(crate) fn from_symbol(s: Symbol) -> Option<PrimitiveType> {
1848 match s {
1849 sym::isize => Some(PrimitiveType::Isize),
1850 sym::i8 => Some(PrimitiveType::I8),
1851 sym::i16 => Some(PrimitiveType::I16),
1852 sym::i32 => Some(PrimitiveType::I32),
1853 sym::i64 => Some(PrimitiveType::I64),
1854 sym::i128 => Some(PrimitiveType::I128),
1855 sym::usize => Some(PrimitiveType::Usize),
1856 sym::u8 => Some(PrimitiveType::U8),
1857 sym::u16 => Some(PrimitiveType::U16),
1858 sym::u32 => Some(PrimitiveType::U32),
1859 sym::u64 => Some(PrimitiveType::U64),
1860 sym::u128 => Some(PrimitiveType::U128),
1861 sym::bool => Some(PrimitiveType::Bool),
1862 sym::char => Some(PrimitiveType::Char),
1863 sym::str => Some(PrimitiveType::Str),
1864 sym::f16 => Some(PrimitiveType::F16),
1865 sym::f32 => Some(PrimitiveType::F32),
1866 sym::f64 => Some(PrimitiveType::F64),
1867 sym::f128 => Some(PrimitiveType::F128),
1868 sym::array => Some(PrimitiveType::Array),
1869 sym::slice => Some(PrimitiveType::Slice),
1870 sym::tuple => Some(PrimitiveType::Tuple),
1871 sym::unit => Some(PrimitiveType::Unit),
1872 sym::pointer => Some(PrimitiveType::RawPointer),
1873 sym::reference => Some(PrimitiveType::Reference),
1874 kw::Fn => Some(PrimitiveType::Fn),
1875 sym::never => Some(PrimitiveType::Never),
1876 _ => None,
1877 }
1878 }
1879
1880 pub(crate) fn simplified_types() -> &'static SimplifiedTypes {
1881 use PrimitiveType::*;
1882 use ty::{FloatTy, IntTy, UintTy};
1883 static CELL: OnceCell<SimplifiedTypes> = OnceCell::new();
1884
1885 let single = |x| iter::once(x).collect();
1886 CELL.get_or_init(move || {
1887 map! {
1888 Isize => single(SimplifiedType::Int(IntTy::Isize)),
1889 I8 => single(SimplifiedType::Int(IntTy::I8)),
1890 I16 => single(SimplifiedType::Int(IntTy::I16)),
1891 I32 => single(SimplifiedType::Int(IntTy::I32)),
1892 I64 => single(SimplifiedType::Int(IntTy::I64)),
1893 I128 => single(SimplifiedType::Int(IntTy::I128)),
1894 Usize => single(SimplifiedType::Uint(UintTy::Usize)),
1895 U8 => single(SimplifiedType::Uint(UintTy::U8)),
1896 U16 => single(SimplifiedType::Uint(UintTy::U16)),
1897 U32 => single(SimplifiedType::Uint(UintTy::U32)),
1898 U64 => single(SimplifiedType::Uint(UintTy::U64)),
1899 U128 => single(SimplifiedType::Uint(UintTy::U128)),
1900 F16 => single(SimplifiedType::Float(FloatTy::F16)),
1901 F32 => single(SimplifiedType::Float(FloatTy::F32)),
1902 F64 => single(SimplifiedType::Float(FloatTy::F64)),
1903 F128 => single(SimplifiedType::Float(FloatTy::F128)),
1904 Str => single(SimplifiedType::Str),
1905 Bool => single(SimplifiedType::Bool),
1906 Char => single(SimplifiedType::Char),
1907 Array => single(SimplifiedType::Array),
1908 Slice => single(SimplifiedType::Slice),
1909 Tuple => [SimplifiedType::Tuple(1), SimplifiedType::Tuple(2), SimplifiedType::Tuple(3)].into(),
1915 Unit => single(SimplifiedType::Tuple(0)),
1916 RawPointer => [SimplifiedType::Ptr(Mutability::Not), SimplifiedType::Ptr(Mutability::Mut)].into_iter().collect(),
1917 Reference => [SimplifiedType::Ref(Mutability::Not), SimplifiedType::Ref(Mutability::Mut)].into_iter().collect(),
1918 Fn => single(SimplifiedType::Function(1)),
1921 Never => single(SimplifiedType::Never),
1922 }
1923 })
1924 }
1925
1926 pub(crate) fn impls<'tcx>(&self, tcx: TyCtxt<'tcx>) -> impl Iterator<Item = DefId> + 'tcx {
1927 Self::simplified_types()
1928 .get(self)
1929 .into_iter()
1930 .flatten()
1931 .flat_map(move |&simp| tcx.incoherent_impls(simp).iter())
1932 .copied()
1933 }
1934
1935 pub(crate) fn all_impls(tcx: TyCtxt<'_>) -> impl Iterator<Item = DefId> {
1936 Self::simplified_types()
1937 .values()
1938 .flatten()
1939 .flat_map(move |&simp| tcx.incoherent_impls(simp).iter())
1940 .copied()
1941 }
1942
1943 pub(crate) fn as_sym(&self) -> Symbol {
1944 use PrimitiveType::*;
1945 match self {
1946 Isize => sym::isize,
1947 I8 => sym::i8,
1948 I16 => sym::i16,
1949 I32 => sym::i32,
1950 I64 => sym::i64,
1951 I128 => sym::i128,
1952 Usize => sym::usize,
1953 U8 => sym::u8,
1954 U16 => sym::u16,
1955 U32 => sym::u32,
1956 U64 => sym::u64,
1957 U128 => sym::u128,
1958 F16 => sym::f16,
1959 F32 => sym::f32,
1960 F64 => sym::f64,
1961 F128 => sym::f128,
1962 Str => sym::str,
1963 Bool => sym::bool,
1964 Char => sym::char,
1965 Array => sym::array,
1966 Pat => sym::pat,
1967 Slice => sym::slice,
1968 Tuple => sym::tuple,
1969 Unit => sym::unit,
1970 RawPointer => sym::pointer,
1971 Reference => sym::reference,
1972 Fn => kw::Fn,
1973 Never => sym::never,
1974 }
1975 }
1976
1977 pub(crate) fn primitive_locations(tcx: TyCtxt<'_>) -> &FxIndexMap<PrimitiveType, DefId> {
1989 static PRIMITIVE_LOCATIONS: OnceCell<FxIndexMap<PrimitiveType, DefId>> = OnceCell::new();
1990 PRIMITIVE_LOCATIONS.get_or_init(|| {
1991 let mut primitive_locations = FxIndexMap::default();
1992 for &crate_num in tcx.crates(()) {
1995 let e = ExternalCrate { crate_num };
1996 let crate_name = e.name(tcx);
1997 debug!(?crate_num, ?crate_name);
1998 for (def_id, prim) in e.primitives(tcx) {
1999 if crate_name == sym::core && primitive_locations.contains_key(&prim) {
2001 continue;
2002 }
2003 primitive_locations.insert(prim, def_id);
2004 }
2005 }
2006 let local_primitives = ExternalCrate { crate_num: LOCAL_CRATE }.primitives(tcx);
2007 for (def_id, prim) in local_primitives {
2008 primitive_locations.insert(prim, def_id);
2009 }
2010 primitive_locations
2011 })
2012 }
2013}
2014
2015impl From<ty::IntTy> for PrimitiveType {
2016 fn from(int_ty: ty::IntTy) -> PrimitiveType {
2017 match int_ty {
2018 ty::IntTy::Isize => PrimitiveType::Isize,
2019 ty::IntTy::I8 => PrimitiveType::I8,
2020 ty::IntTy::I16 => PrimitiveType::I16,
2021 ty::IntTy::I32 => PrimitiveType::I32,
2022 ty::IntTy::I64 => PrimitiveType::I64,
2023 ty::IntTy::I128 => PrimitiveType::I128,
2024 }
2025 }
2026}
2027
2028impl From<ty::UintTy> for PrimitiveType {
2029 fn from(uint_ty: ty::UintTy) -> PrimitiveType {
2030 match uint_ty {
2031 ty::UintTy::Usize => PrimitiveType::Usize,
2032 ty::UintTy::U8 => PrimitiveType::U8,
2033 ty::UintTy::U16 => PrimitiveType::U16,
2034 ty::UintTy::U32 => PrimitiveType::U32,
2035 ty::UintTy::U64 => PrimitiveType::U64,
2036 ty::UintTy::U128 => PrimitiveType::U128,
2037 }
2038 }
2039}
2040
2041impl From<ty::FloatTy> for PrimitiveType {
2042 fn from(float_ty: ty::FloatTy) -> PrimitiveType {
2043 match float_ty {
2044 ty::FloatTy::F16 => PrimitiveType::F16,
2045 ty::FloatTy::F32 => PrimitiveType::F32,
2046 ty::FloatTy::F64 => PrimitiveType::F64,
2047 ty::FloatTy::F128 => PrimitiveType::F128,
2048 }
2049 }
2050}
2051
2052impl From<hir::PrimTy> for PrimitiveType {
2053 fn from(prim_ty: hir::PrimTy) -> PrimitiveType {
2054 match prim_ty {
2055 hir::PrimTy::Int(int_ty) => int_ty.into(),
2056 hir::PrimTy::Uint(uint_ty) => uint_ty.into(),
2057 hir::PrimTy::Float(float_ty) => float_ty.into(),
2058 hir::PrimTy::Str => PrimitiveType::Str,
2059 hir::PrimTy::Bool => PrimitiveType::Bool,
2060 hir::PrimTy::Char => PrimitiveType::Char,
2061 }
2062 }
2063}
2064
2065#[derive(Clone, Debug)]
2066pub(crate) struct Struct {
2067 pub(crate) ctor_kind: Option<CtorKind>,
2068 pub(crate) generics: Generics,
2069 pub(crate) fields: ThinVec<Item>,
2070}
2071
2072impl Struct {
2073 pub(crate) fn has_stripped_entries(&self) -> bool {
2074 self.fields.iter().any(|f| f.is_stripped())
2075 }
2076}
2077
2078#[derive(Clone, Debug)]
2079pub(crate) struct Union {
2080 pub(crate) generics: Generics,
2081 pub(crate) fields: Vec<Item>,
2082}
2083
2084impl Union {
2085 pub(crate) fn has_stripped_entries(&self) -> bool {
2086 self.fields.iter().any(|f| f.is_stripped())
2087 }
2088}
2089
2090#[derive(Clone, Debug)]
2094pub(crate) struct VariantStruct {
2095 pub(crate) fields: ThinVec<Item>,
2096}
2097
2098impl VariantStruct {
2099 pub(crate) fn has_stripped_entries(&self) -> bool {
2100 self.fields.iter().any(|f| f.is_stripped())
2101 }
2102}
2103
2104#[derive(Clone, Debug)]
2105pub(crate) struct Enum {
2106 pub(crate) variants: IndexVec<VariantIdx, Item>,
2107 pub(crate) generics: Generics,
2108}
2109
2110impl Enum {
2111 pub(crate) fn has_stripped_entries(&self) -> bool {
2112 self.variants.iter().any(|f| f.is_stripped())
2113 }
2114
2115 pub(crate) fn non_stripped_variants(&self) -> impl Iterator<Item = &Item> {
2116 self.variants.iter().filter(|v| !v.is_stripped())
2117 }
2118}
2119
2120#[derive(Clone, Debug)]
2121pub(crate) struct Variant {
2122 pub kind: VariantKind,
2123 pub discriminant: Option<Discriminant>,
2124}
2125
2126#[derive(Clone, Debug)]
2127pub(crate) enum VariantKind {
2128 CLike,
2129 Tuple(ThinVec<Item>),
2130 Struct(VariantStruct),
2131}
2132
2133impl Variant {
2134 pub(crate) fn has_stripped_entries(&self) -> Option<bool> {
2135 match &self.kind {
2136 VariantKind::Struct(struct_) => Some(struct_.has_stripped_entries()),
2137 VariantKind::CLike | VariantKind::Tuple(_) => None,
2138 }
2139 }
2140}
2141
2142#[derive(Clone, Debug)]
2143pub(crate) struct Discriminant {
2144 pub(super) expr: Option<BodyId>,
2147 pub(super) value: DefId,
2148}
2149
2150impl Discriminant {
2151 pub(crate) fn expr(&self, tcx: TyCtxt<'_>) -> Option<String> {
2154 self.expr
2155 .map(|body| rendered_const(tcx, tcx.hir_body(body), tcx.hir_body_owner_def_id(body)))
2156 }
2157 pub(crate) fn value(&self, tcx: TyCtxt<'_>, with_underscores: bool) -> String {
2158 print_evaluated_const(tcx, self.value, with_underscores, false).unwrap()
2159 }
2160}
2161
2162#[derive(Copy, Clone, Debug)]
2165pub(crate) struct Span(rustc_span::Span);
2166
2167impl Span {
2168 pub(crate) fn new(sp: rustc_span::Span) -> Self {
2173 Self(sp.source_callsite())
2174 }
2175
2176 pub(crate) fn inner(&self) -> rustc_span::Span {
2177 self.0
2178 }
2179
2180 pub(crate) fn filename(&self, sess: &Session) -> FileName {
2181 sess.source_map().span_to_filename(self.0)
2182 }
2183
2184 pub(crate) fn lo(&self, sess: &Session) -> Loc {
2185 sess.source_map().lookup_char_pos(self.0.lo())
2186 }
2187
2188 pub(crate) fn hi(&self, sess: &Session) -> Loc {
2189 sess.source_map().lookup_char_pos(self.0.hi())
2190 }
2191
2192 pub(crate) fn cnum(&self, sess: &Session) -> CrateNum {
2193 self.lo(sess).file.cnum
2195 }
2196}
2197
2198#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2199pub(crate) struct Path {
2200 pub(crate) res: Res,
2201 pub(crate) segments: ThinVec<PathSegment>,
2202}
2203
2204impl Path {
2205 pub(crate) fn def_id(&self) -> DefId {
2206 self.res.def_id()
2207 }
2208
2209 pub(crate) fn last_opt(&self) -> Option<Symbol> {
2210 self.segments.last().map(|s| s.name)
2211 }
2212
2213 pub(crate) fn last(&self) -> Symbol {
2214 self.last_opt().expect("segments were empty")
2215 }
2216
2217 pub(crate) fn whole_name(&self) -> String {
2218 self.segments
2219 .iter()
2220 .map(|s| if s.name == kw::PathRoot { "" } else { s.name.as_str() })
2221 .intersperse("::")
2222 .collect()
2223 }
2224
2225 pub(crate) fn is_assoc_ty(&self) -> bool {
2227 match self.res {
2228 Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } | Res::Def(DefKind::TyParam, _)
2229 if self.segments.len() != 1 =>
2230 {
2231 true
2232 }
2233 Res::Def(DefKind::AssocTy, _) => true,
2234 _ => false,
2235 }
2236 }
2237
2238 pub(crate) fn generic_args(&self) -> Option<&GenericArgs> {
2239 self.segments.last().map(|seg| &seg.args)
2240 }
2241
2242 pub(crate) fn generics(&self) -> Option<impl Iterator<Item = &Type>> {
2243 self.segments.last().and_then(|seg| {
2244 if let GenericArgs::AngleBracketed { ref args, .. } = seg.args {
2245 Some(args.iter().filter_map(|arg| match arg {
2246 GenericArg::Type(ty) => Some(ty),
2247 _ => None,
2248 }))
2249 } else {
2250 None
2251 }
2252 })
2253 }
2254}
2255
2256#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2257pub(crate) enum GenericArg {
2258 Lifetime(Lifetime),
2259 Type(Type),
2260 Const(Box<ConstantKind>),
2261 Infer,
2262}
2263
2264impl GenericArg {
2265 pub(crate) fn as_lt(&self) -> Option<&Lifetime> {
2266 if let Self::Lifetime(lt) = self { Some(lt) } else { None }
2267 }
2268
2269 pub(crate) fn as_ty(&self) -> Option<&Type> {
2270 if let Self::Type(ty) = self { Some(ty) } else { None }
2271 }
2272}
2273
2274#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2275pub(crate) enum GenericArgs {
2276 AngleBracketed { args: ThinVec<GenericArg>, constraints: ThinVec<AssocItemConstraint> },
2278 Parenthesized { inputs: ThinVec<Type>, output: Option<Box<Type>> },
2280 ReturnTypeNotation,
2282}
2283
2284impl GenericArgs {
2285 pub(crate) fn is_empty(&self) -> bool {
2286 match self {
2287 GenericArgs::AngleBracketed { args, constraints } => {
2288 args.is_empty() && constraints.is_empty()
2289 }
2290 GenericArgs::Parenthesized { inputs, output } => inputs.is_empty() && output.is_none(),
2291 GenericArgs::ReturnTypeNotation => false,
2292 }
2293 }
2294 pub(crate) fn constraints(&self) -> Box<dyn Iterator<Item = AssocItemConstraint> + '_> {
2295 match self {
2296 GenericArgs::AngleBracketed { constraints, .. } => {
2297 Box::new(constraints.iter().cloned())
2298 }
2299 GenericArgs::Parenthesized { output, .. } => Box::new(
2300 output
2301 .as_ref()
2302 .map(|ty| AssocItemConstraint {
2303 assoc: PathSegment {
2304 name: sym::Output,
2305 args: GenericArgs::AngleBracketed {
2306 args: ThinVec::new(),
2307 constraints: ThinVec::new(),
2308 },
2309 },
2310 kind: AssocItemConstraintKind::Equality {
2311 term: Term::Type((**ty).clone()),
2312 },
2313 })
2314 .into_iter(),
2315 ),
2316 GenericArgs::ReturnTypeNotation => Box::new([].into_iter()),
2317 }
2318 }
2319}
2320
2321impl<'a> IntoIterator for &'a GenericArgs {
2322 type IntoIter = Box<dyn Iterator<Item = GenericArg> + 'a>;
2323 type Item = GenericArg;
2324 fn into_iter(self) -> Self::IntoIter {
2325 match self {
2326 GenericArgs::AngleBracketed { args, .. } => Box::new(args.iter().cloned()),
2327 GenericArgs::Parenthesized { inputs, .. } => {
2328 Box::new(inputs.iter().cloned().map(GenericArg::Type))
2330 }
2331 GenericArgs::ReturnTypeNotation => Box::new([].into_iter()),
2332 }
2333 }
2334}
2335
2336#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2337pub(crate) struct PathSegment {
2338 pub(crate) name: Symbol,
2339 pub(crate) args: GenericArgs,
2340}
2341
2342#[derive(Clone, Debug)]
2343pub(crate) enum TypeAliasInnerType {
2344 Enum { variants: IndexVec<VariantIdx, Item>, is_non_exhaustive: bool },
2345 Union { fields: Vec<Item> },
2346 Struct { ctor_kind: Option<CtorKind>, fields: Vec<Item> },
2347}
2348
2349impl TypeAliasInnerType {
2350 fn has_stripped_entries(&self) -> Option<bool> {
2351 Some(match self {
2352 Self::Enum { variants, .. } => variants.iter().any(|v| v.is_stripped()),
2353 Self::Union { fields } | Self::Struct { fields, .. } => {
2354 fields.iter().any(|f| f.is_stripped())
2355 }
2356 })
2357 }
2358}
2359
2360#[derive(Clone, Debug)]
2361pub(crate) struct TypeAlias {
2362 pub(crate) type_: Type,
2363 pub(crate) generics: Generics,
2364 pub(crate) inner_type: Option<TypeAliasInnerType>,
2367 pub(crate) item_type: Option<Type>,
2374}
2375
2376#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2377pub(crate) struct BareFunctionDecl {
2378 pub(crate) safety: hir::Safety,
2379 pub(crate) generic_params: Vec<GenericParamDef>,
2380 pub(crate) decl: FnDecl,
2381 pub(crate) abi: ExternAbi,
2382}
2383
2384#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2385pub(crate) struct UnsafeBinderTy {
2386 pub(crate) generic_params: Vec<GenericParamDef>,
2387 pub(crate) ty: Type,
2388}
2389
2390#[derive(Clone, Debug)]
2391pub(crate) struct Static {
2392 pub(crate) type_: Box<Type>,
2393 pub(crate) mutability: Mutability,
2394 pub(crate) expr: Option<BodyId>,
2395}
2396
2397#[derive(Clone, PartialEq, Eq, Hash, Debug)]
2398pub(crate) struct Constant {
2399 pub(crate) generics: Generics,
2400 pub(crate) kind: ConstantKind,
2401 pub(crate) type_: Type,
2402}
2403
2404#[derive(Clone, PartialEq, Eq, Hash, Debug)]
2405pub(crate) enum Term {
2406 Type(Type),
2407 Constant(ConstantKind),
2408}
2409
2410impl Term {
2411 pub(crate) fn ty(&self) -> Option<&Type> {
2412 if let Term::Type(ty) = self { Some(ty) } else { None }
2413 }
2414}
2415
2416impl From<Type> for Term {
2417 fn from(ty: Type) -> Self {
2418 Term::Type(ty)
2419 }
2420}
2421
2422#[derive(Clone, PartialEq, Eq, Hash, Debug)]
2423pub(crate) enum ConstantKind {
2424 TyConst { expr: Box<str> },
2430 Path { path: Box<str> },
2433 Anonymous { body: BodyId },
2437 Extern { def_id: DefId },
2439 Local { def_id: DefId, body: BodyId },
2441 Infer,
2443}
2444
2445impl ConstantKind {
2446 pub(crate) fn expr(&self, tcx: TyCtxt<'_>) -> String {
2447 match *self {
2448 ConstantKind::TyConst { ref expr } => expr.to_string(),
2449 ConstantKind::Path { ref path } => path.to_string(),
2450 ConstantKind::Extern { def_id } => print_inlined_const(tcx, def_id),
2451 ConstantKind::Local { body, .. } | ConstantKind::Anonymous { body } => {
2452 rendered_const(tcx, tcx.hir_body(body), tcx.hir_body_owner_def_id(body))
2453 }
2454 ConstantKind::Infer => "_".to_string(),
2455 }
2456 }
2457
2458 pub(crate) fn value(&self, tcx: TyCtxt<'_>) -> Option<String> {
2459 match *self {
2460 ConstantKind::TyConst { .. }
2461 | ConstantKind::Path { .. }
2462 | ConstantKind::Anonymous { .. }
2463 | ConstantKind::Infer => None,
2464 ConstantKind::Extern { def_id } | ConstantKind::Local { def_id, .. } => {
2465 print_evaluated_const(tcx, def_id, true, true)
2466 }
2467 }
2468 }
2469
2470 pub(crate) fn is_literal(&self, tcx: TyCtxt<'_>) -> bool {
2471 match *self {
2472 ConstantKind::TyConst { .. }
2473 | ConstantKind::Extern { .. }
2474 | ConstantKind::Path { .. }
2475 | ConstantKind::Infer => false,
2476 ConstantKind::Local { body, .. } | ConstantKind::Anonymous { body } => {
2477 is_literal_expr(tcx, body.hir_id)
2478 }
2479 }
2480 }
2481}
2482
2483#[derive(Clone, Debug)]
2484pub(crate) struct Impl {
2485 pub(crate) safety: hir::Safety,
2486 pub(crate) generics: Generics,
2487 pub(crate) trait_: Option<Path>,
2488 pub(crate) for_: Type,
2489 pub(crate) items: Vec<Item>,
2490 pub(crate) polarity: ty::ImplPolarity,
2491 pub(crate) kind: ImplKind,
2492}
2493
2494impl Impl {
2495 pub(crate) fn provided_trait_methods(&self, tcx: TyCtxt<'_>) -> FxIndexSet<Symbol> {
2496 self.trait_
2497 .as_ref()
2498 .map(|t| t.def_id())
2499 .map(|did| tcx.provided_trait_methods(did).map(|meth| meth.name()).collect())
2500 .unwrap_or_default()
2501 }
2502
2503 pub(crate) fn is_negative_trait_impl(&self) -> bool {
2504 matches!(self.polarity, ty::ImplPolarity::Negative)
2505 }
2506}
2507
2508#[derive(Clone, Debug)]
2509pub(crate) enum ImplKind {
2510 Normal,
2511 Auto,
2512 FakeVariadic,
2513 Blanket(Box<Type>),
2514}
2515
2516impl ImplKind {
2517 pub(crate) fn is_auto(&self) -> bool {
2518 matches!(self, ImplKind::Auto)
2519 }
2520
2521 pub(crate) fn is_blanket(&self) -> bool {
2522 matches!(self, ImplKind::Blanket(_))
2523 }
2524
2525 pub(crate) fn is_fake_variadic(&self) -> bool {
2526 matches!(self, ImplKind::FakeVariadic)
2527 }
2528
2529 pub(crate) fn as_blanket_ty(&self) -> Option<&Type> {
2530 match self {
2531 ImplKind::Blanket(ty) => Some(ty),
2532 _ => None,
2533 }
2534 }
2535}
2536
2537#[derive(Clone, Debug)]
2538pub(crate) struct Import {
2539 pub(crate) kind: ImportKind,
2540 pub(crate) source: ImportSource,
2542 pub(crate) should_be_displayed: bool,
2543}
2544
2545impl Import {
2546 pub(crate) fn new_simple(
2547 name: Symbol,
2548 source: ImportSource,
2549 should_be_displayed: bool,
2550 ) -> Self {
2551 Self { kind: ImportKind::Simple(name), source, should_be_displayed }
2552 }
2553
2554 pub(crate) fn new_glob(source: ImportSource, should_be_displayed: bool) -> Self {
2555 Self { kind: ImportKind::Glob, source, should_be_displayed }
2556 }
2557
2558 pub(crate) fn imported_item_is_doc_hidden(&self, tcx: TyCtxt<'_>) -> bool {
2559 self.source.did.is_some_and(|did| tcx.is_doc_hidden(did))
2560 }
2561}
2562
2563#[derive(Clone, Debug)]
2564pub(crate) enum ImportKind {
2565 Simple(Symbol),
2567 Glob,
2569}
2570
2571#[derive(Clone, Debug)]
2572pub(crate) struct ImportSource {
2573 pub(crate) path: Path,
2574 pub(crate) did: Option<DefId>,
2575}
2576
2577#[derive(Clone, Debug)]
2578pub(crate) struct Macro {
2579 pub(crate) source: String,
2580 pub(crate) macro_rules: bool,
2582}
2583
2584#[derive(Clone, Debug)]
2585pub(crate) struct ProcMacro {
2586 pub(crate) kind: MacroKind,
2587 pub(crate) helpers: Vec<Symbol>,
2588}
2589
2590#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2601pub(crate) struct AssocItemConstraint {
2602 pub(crate) assoc: PathSegment,
2603 pub(crate) kind: AssocItemConstraintKind,
2604}
2605
2606#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2608pub(crate) enum AssocItemConstraintKind {
2609 Equality { term: Term },
2610 Bound { bounds: Vec<GenericBound> },
2611}
2612
2613#[cfg(target_pointer_width = "64")]
2615mod size_asserts {
2616 use rustc_data_structures::static_assert_size;
2617
2618 use super::*;
2619 static_assert_size!(Crate, 16); static_assert_size!(DocFragment, 32);
2622 static_assert_size!(GenericArg, 32);
2623 static_assert_size!(GenericArgs, 24);
2624 static_assert_size!(GenericParamDef, 40);
2625 static_assert_size!(Generics, 16);
2626 static_assert_size!(Item, 8);
2627 static_assert_size!(ItemInner, 144);
2628 static_assert_size!(ItemKind, 48);
2629 static_assert_size!(PathSegment, 32);
2630 static_assert_size!(Type, 32);
2631 }