1use std::hash::Hash;
2use std::path::PathBuf;
3use std::sync::{Arc, OnceLock as OnceCell};
4use std::{fmt, iter};
5
6use arrayvec::ArrayVec;
7use rustc_abi::{ExternAbi, VariantIdx};
8use rustc_attr_parsing::{AttributeKind, ConstStability, Deprecation, Stability, StableSince};
9use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
10use rustc_hir::def::{CtorKind, DefKind, Res};
11use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId};
12use rustc_hir::lang_items::LangItem;
13use rustc_hir::{BodyId, Mutability};
14use rustc_hir_analysis::check::intrinsic::intrinsic_operation_unsafety;
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::{Ident, 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(Clone, 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 pub(crate) fn keywords(&self, tcx: TyCtxt<'_>) -> ThinVec<(DefId, Symbol)> {
202 let root = self.def_id();
203
204 let as_keyword = |res: Res<!>| {
205 if let Res::Def(DefKind::Mod, def_id) = res {
206 let mut keyword = None;
207 let meta_items = tcx
208 .get_attrs(def_id, sym::doc)
209 .flat_map(|attr| attr.meta_item_list().unwrap_or_default());
210 for meta in meta_items {
211 if meta.has_name(sym::keyword)
212 && let Some(v) = meta.value_str()
213 {
214 keyword = Some(v);
215 break;
216 }
217 }
218 return keyword.map(|p| (def_id, p));
219 }
220 None
221 };
222 if root.is_local() {
223 tcx.hir_root_module()
224 .item_ids
225 .iter()
226 .filter_map(|&id| {
227 let item = tcx.hir_item(id);
228 match item.kind {
229 hir::ItemKind::Mod(..) => {
230 as_keyword(Res::Def(DefKind::Mod, id.owner_id.to_def_id()))
231 }
232 _ => None,
233 }
234 })
235 .collect()
236 } else {
237 tcx.module_children(root).iter().map(|item| item.res).filter_map(as_keyword).collect()
238 }
239 }
240
241 pub(crate) fn primitives(&self, tcx: TyCtxt<'_>) -> ThinVec<(DefId, PrimitiveType)> {
242 let root = self.def_id();
243
244 let as_primitive = |res: Res<!>| {
262 let Res::Def(DefKind::Mod, def_id) = res else { return None };
263 tcx.get_attrs(def_id, sym::rustc_doc_primitive)
264 .map(|attr| {
265 let attr_value = attr.value_str().expect("syntax should already be validated");
266 let Some(prim) = PrimitiveType::from_symbol(attr_value) else {
267 span_bug!(
268 attr.span(),
269 "primitive `{attr_value}` is not a member of `PrimitiveType`"
270 );
271 };
272
273 (def_id, prim)
274 })
275 .next()
276 };
277
278 if root.is_local() {
279 tcx.hir_root_module()
280 .item_ids
281 .iter()
282 .filter_map(|&id| {
283 let item = tcx.hir_item(id);
284 match item.kind {
285 hir::ItemKind::Mod(..) => {
286 as_primitive(Res::Def(DefKind::Mod, id.owner_id.to_def_id()))
287 }
288 _ => None,
289 }
290 })
291 .collect()
292 } else {
293 tcx.module_children(root).iter().map(|item| item.res).filter_map(as_primitive).collect()
294 }
295 }
296}
297
298#[derive(Debug)]
300pub(crate) enum ExternalLocation {
301 Remote(String),
303 Local,
305 Unknown,
307}
308
309#[derive(Clone)]
313pub(crate) struct Item {
314 pub(crate) inner: Box<ItemInner>,
315}
316
317#[derive(Clone)]
323pub(crate) struct ItemInner {
324 pub(crate) name: Option<Symbol>,
327 pub(crate) kind: ItemKind,
330 pub(crate) attrs: Attributes,
331 pub(crate) stability: Option<Stability>,
333 pub(crate) item_id: ItemId,
334 pub(crate) inline_stmt_id: Option<LocalDefId>,
338 pub(crate) cfg: Option<Arc<Cfg>>,
339}
340
341impl std::ops::Deref for Item {
342 type Target = ItemInner;
343 fn deref(&self) -> &ItemInner {
344 &self.inner
345 }
346}
347
348impl fmt::Debug for Item {
351 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
352 let alternate = f.alternate();
353 let mut fmt = f.debug_struct("Item");
355 fmt.field("name", &self.name).field("item_id", &self.item_id);
356 if alternate {
358 fmt.field("attrs", &self.attrs).field("kind", &self.kind).field("cfg", &self.cfg);
359 } else {
360 fmt.field("kind", &self.type_());
361 fmt.field("docs", &self.doc_value());
362 }
363 fmt.finish()
364 }
365}
366
367pub(crate) fn rustc_span(def_id: DefId, tcx: TyCtxt<'_>) -> Span {
368 Span::new(def_id.as_local().map_or_else(
369 || tcx.def_span(def_id),
370 |local| {
371 let hir = tcx.hir();
372 hir.span_with_body(tcx.local_def_id_to_hir_id(local))
373 },
374 ))
375}
376
377fn is_field_vis_inherited(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
378 let parent = tcx.parent(def_id);
379 match tcx.def_kind(parent) {
380 DefKind::Struct | DefKind::Union => false,
381 DefKind::Variant => true,
382 parent_kind => panic!("unexpected parent kind: {parent_kind:?}"),
383 }
384}
385
386impl Item {
387 pub(crate) fn stability(&self, tcx: TyCtxt<'_>) -> Option<Stability> {
391 let stability = self.inner.stability;
392 debug_assert!(
393 stability.is_some()
394 || self.def_id().is_none_or(|did| tcx.lookup_stability(did).is_none()),
395 "missing stability for cleaned item: {self:?}",
396 );
397 stability
398 }
399
400 pub(crate) fn const_stability(&self, tcx: TyCtxt<'_>) -> Option<ConstStability> {
401 self.def_id().and_then(|did| tcx.lookup_const_stability(did))
402 }
403
404 pub(crate) fn deprecation(&self, tcx: TyCtxt<'_>) -> Option<Deprecation> {
405 self.def_id().and_then(|did| tcx.lookup_deprecation(did)).or_else(|| {
406 let stab = self.stability(tcx)?;
410 if let rustc_attr_parsing::StabilityLevel::Stable {
411 allowed_through_unstable_modules: Some(note),
412 ..
413 } = stab.level
414 {
415 Some(Deprecation {
416 since: rustc_attr_parsing::DeprecatedSince::Unspecified,
417 note: Some(note),
418 suggestion: None,
419 })
420 } else {
421 None
422 }
423 })
424 }
425
426 pub(crate) fn inner_docs(&self, tcx: TyCtxt<'_>) -> bool {
427 self.item_id
428 .as_def_id()
429 .map(|did| inner_docs(tcx.get_attrs_unchecked(did)))
430 .unwrap_or(false)
431 }
432
433 pub(crate) fn span(&self, tcx: TyCtxt<'_>) -> Option<Span> {
434 let kind = match &self.kind {
435 ItemKind::StrippedItem(k) => k,
436 _ => &self.kind,
437 };
438 match kind {
439 ItemKind::ModuleItem(Module { span, .. }) => Some(*span),
440 ItemKind::ImplItem(box Impl { kind: ImplKind::Auto, .. }) => None,
441 ItemKind::ImplItem(box Impl { kind: ImplKind::Blanket(_), .. }) => {
442 if let ItemId::Blanket { impl_id, .. } = self.item_id {
443 Some(rustc_span(impl_id, tcx))
444 } else {
445 panic!("blanket impl item has non-blanket ID")
446 }
447 }
448 _ => self.def_id().map(|did| rustc_span(did, tcx)),
449 }
450 }
451
452 pub(crate) fn attr_span(&self, tcx: TyCtxt<'_>) -> rustc_span::Span {
453 span_of_fragments(&self.attrs.doc_strings)
454 .unwrap_or_else(|| self.span(tcx).map_or(DUMMY_SP, |span| span.inner()))
455 }
456
457 pub(crate) fn doc_value(&self) -> String {
459 self.attrs.doc_value()
460 }
461
462 pub(crate) fn opt_doc_value(&self) -> Option<String> {
466 self.attrs.opt_doc_value()
467 }
468
469 pub(crate) fn from_def_id_and_parts(
470 def_id: DefId,
471 name: Option<Symbol>,
472 kind: ItemKind,
473 cx: &mut DocContext<'_>,
474 ) -> Item {
475 let hir_attrs = cx.tcx.get_attrs_unchecked(def_id);
476
477 Self::from_def_id_and_attrs_and_parts(
478 def_id,
479 name,
480 kind,
481 Attributes::from_hir(hir_attrs),
482 extract_cfg_from_attrs(hir_attrs.iter(), cx.tcx, &cx.cache.hidden_cfg),
483 )
484 }
485
486 pub(crate) fn from_def_id_and_attrs_and_parts(
487 def_id: DefId,
488 name: Option<Symbol>,
489 kind: ItemKind,
490 attrs: Attributes,
491 cfg: Option<Arc<Cfg>>,
492 ) -> Item {
493 trace!("name={name:?}, def_id={def_id:?} cfg={cfg:?}");
494
495 Item {
496 inner: Box::new(ItemInner {
497 item_id: def_id.into(),
498 kind,
499 attrs,
500 stability: None,
501 name,
502 cfg,
503 inline_stmt_id: None,
504 }),
505 }
506 }
507
508 pub(crate) fn links(&self, cx: &Context<'_>) -> Vec<RenderedLink> {
509 use crate::html::format::{href, link_tooltip};
510
511 let Some(links) = cx.cache().intra_doc_links.get(&self.item_id) else { return vec![] };
512 links
513 .iter()
514 .filter_map(|ItemLink { link: s, link_text, page_id: id, fragment }| {
515 debug!(?id);
516 if let Ok((mut href, ..)) = href(*id, cx) {
517 debug!(?href);
518 if let Some(ref fragment) = *fragment {
519 fragment.render(&mut href, cx.tcx())
520 }
521 Some(RenderedLink {
522 original_text: s.clone(),
523 new_text: link_text.clone(),
524 tooltip: link_tooltip(*id, fragment, cx),
525 href,
526 })
527 } else {
528 None
529 }
530 })
531 .collect()
532 }
533
534 pub(crate) fn link_names(&self, cache: &Cache) -> Vec<RenderedLink> {
540 let Some(links) = cache.intra_doc_links.get(&self.item_id) else {
541 return vec![];
542 };
543 links
544 .iter()
545 .map(|ItemLink { link: s, link_text, .. }| RenderedLink {
546 original_text: s.clone(),
547 new_text: link_text.clone(),
548 href: String::new(),
549 tooltip: String::new(),
550 })
551 .collect()
552 }
553
554 pub(crate) fn is_crate(&self) -> bool {
555 self.is_mod() && self.def_id().is_some_and(|did| did.is_crate_root())
556 }
557 pub(crate) fn is_mod(&self) -> bool {
558 self.type_() == ItemType::Module
559 }
560 pub(crate) fn is_struct(&self) -> bool {
561 self.type_() == ItemType::Struct
562 }
563 pub(crate) fn is_enum(&self) -> bool {
564 self.type_() == ItemType::Enum
565 }
566 pub(crate) fn is_variant(&self) -> bool {
567 self.type_() == ItemType::Variant
568 }
569 pub(crate) fn is_associated_type(&self) -> bool {
570 matches!(self.kind, AssocTypeItem(..) | StrippedItem(box AssocTypeItem(..)))
571 }
572 pub(crate) fn is_required_associated_type(&self) -> bool {
573 matches!(self.kind, RequiredAssocTypeItem(..) | StrippedItem(box RequiredAssocTypeItem(..)))
574 }
575 pub(crate) fn is_associated_const(&self) -> bool {
576 matches!(self.kind, ProvidedAssocConstItem(..) | ImplAssocConstItem(..) | StrippedItem(box (ProvidedAssocConstItem(..) | ImplAssocConstItem(..))))
577 }
578 pub(crate) fn is_required_associated_const(&self) -> bool {
579 matches!(self.kind, RequiredAssocConstItem(..) | StrippedItem(box RequiredAssocConstItem(..)))
580 }
581 pub(crate) fn is_method(&self) -> bool {
582 self.type_() == ItemType::Method
583 }
584 pub(crate) fn is_ty_method(&self) -> bool {
585 self.type_() == ItemType::TyMethod
586 }
587 pub(crate) fn is_primitive(&self) -> bool {
588 self.type_() == ItemType::Primitive
589 }
590 pub(crate) fn is_union(&self) -> bool {
591 self.type_() == ItemType::Union
592 }
593 pub(crate) fn is_import(&self) -> bool {
594 self.type_() == ItemType::Import
595 }
596 pub(crate) fn is_extern_crate(&self) -> bool {
597 self.type_() == ItemType::ExternCrate
598 }
599 pub(crate) fn is_keyword(&self) -> bool {
600 self.type_() == ItemType::Keyword
601 }
602 pub(crate) fn is_stripped(&self) -> bool {
603 match self.kind {
604 StrippedItem(..) => true,
605 ImportItem(ref i) => !i.should_be_displayed,
606 _ => false,
607 }
608 }
609 pub(crate) fn has_stripped_entries(&self) -> Option<bool> {
610 match self.kind {
611 StructItem(ref struct_) => Some(struct_.has_stripped_entries()),
612 UnionItem(ref union_) => Some(union_.has_stripped_entries()),
613 EnumItem(ref enum_) => Some(enum_.has_stripped_entries()),
614 VariantItem(ref v) => v.has_stripped_entries(),
615 _ => None,
616 }
617 }
618
619 pub(crate) fn stability_class(&self, tcx: TyCtxt<'_>) -> Option<String> {
620 self.stability(tcx).as_ref().and_then(|s| {
621 let mut classes = Vec::with_capacity(2);
622
623 if s.is_unstable() {
624 classes.push("unstable");
625 }
626
627 if self.deprecation(tcx).is_some() {
629 classes.push("deprecated");
630 }
631
632 if !classes.is_empty() { Some(classes.join(" ")) } else { None }
633 })
634 }
635
636 pub(crate) fn stable_since(&self, tcx: TyCtxt<'_>) -> Option<StableSince> {
637 self.stability(tcx).and_then(|stability| stability.stable_since())
638 }
639
640 pub(crate) fn is_non_exhaustive(&self) -> bool {
641 self.attrs.other_attrs.iter().any(|a| a.has_name(sym::non_exhaustive))
642 }
643
644 pub(crate) fn type_(&self) -> ItemType {
646 ItemType::from(self)
647 }
648
649 pub(crate) fn is_default(&self) -> bool {
650 match self.kind {
651 ItemKind::MethodItem(_, Some(defaultness)) => {
652 defaultness.has_value() && !defaultness.is_final()
653 }
654 _ => false,
655 }
656 }
657
658 pub(crate) fn fn_header(&self, tcx: TyCtxt<'_>) -> Option<hir::FnHeader> {
660 fn build_fn_header(
661 def_id: DefId,
662 tcx: TyCtxt<'_>,
663 asyncness: ty::Asyncness,
664 ) -> hir::FnHeader {
665 let sig = tcx.fn_sig(def_id).skip_binder();
666 let constness = if tcx.is_const_fn(def_id) {
667 hir::Constness::Const
668 } else {
669 hir::Constness::NotConst
670 };
671 let asyncness = match asyncness {
672 ty::Asyncness::Yes => hir::IsAsync::Async(DUMMY_SP),
673 ty::Asyncness::No => hir::IsAsync::NotAsync,
674 };
675 hir::FnHeader {
676 safety: if tcx.codegen_fn_attrs(def_id).safe_target_features {
677 hir::HeaderSafety::SafeTargetFeatures
678 } else {
679 sig.safety().into()
680 },
681 abi: sig.abi(),
682 constness,
683 asyncness,
684 }
685 }
686 let header = match self.kind {
687 ItemKind::ForeignFunctionItem(_, safety) => {
688 let def_id = self.def_id().unwrap();
689 let abi = tcx.fn_sig(def_id).skip_binder().abi();
690 hir::FnHeader {
691 safety: if tcx.codegen_fn_attrs(def_id).safe_target_features {
692 hir::HeaderSafety::SafeTargetFeatures
693 } else if abi == ExternAbi::RustIntrinsic {
694 intrinsic_operation_unsafety(tcx, def_id.expect_local()).into()
695 } else {
696 safety.into()
697 },
698 abi,
699 constness: if tcx.is_const_fn(def_id) {
700 hir::Constness::Const
701 } else {
702 hir::Constness::NotConst
703 },
704 asyncness: hir::IsAsync::NotAsync,
705 }
706 }
707 ItemKind::FunctionItem(_)
708 | ItemKind::MethodItem(_, _)
709 | ItemKind::RequiredMethodItem(_) => {
710 let def_id = self.def_id().unwrap();
711 build_fn_header(def_id, tcx, tcx.asyncness(def_id))
712 }
713 _ => return None,
714 };
715 Some(header)
716 }
717
718 pub(crate) fn visibility(&self, tcx: TyCtxt<'_>) -> Option<Visibility<DefId>> {
721 let def_id = match self.item_id {
722 ItemId::Auto { .. } | ItemId::Blanket { .. } => return None,
724 ItemId::DefId(def_id) => def_id,
725 };
726
727 match self.kind {
728 ItemKind::KeywordItem | ItemKind::PrimitiveItem(_) => return Some(Visibility::Public),
732 StructFieldItem(..) if is_field_vis_inherited(tcx, def_id) => {
734 return None;
735 }
736 VariantItem(..) | ImplItem(..) => return None,
738 RequiredAssocConstItem(..)
740 | ProvidedAssocConstItem(..)
741 | ImplAssocConstItem(..)
742 | AssocTypeItem(..)
743 | RequiredAssocTypeItem(..)
744 | RequiredMethodItem(..)
745 | MethodItem(..) => {
746 let assoc_item = tcx.associated_item(def_id);
747 let is_trait_item = match assoc_item.container {
748 ty::AssocItemContainer::Trait => true,
749 ty::AssocItemContainer::Impl => {
750 tcx.impl_trait_ref(tcx.parent(assoc_item.def_id)).is_some()
753 }
754 };
755 if is_trait_item {
756 return None;
757 }
758 }
759 _ => {}
760 }
761 let def_id = match self.inline_stmt_id {
762 Some(inlined) => inlined.to_def_id(),
763 None => def_id,
764 };
765 Some(tcx.visibility(def_id))
766 }
767
768 pub(crate) fn attributes(&self, tcx: TyCtxt<'_>, cache: &Cache, is_json: bool) -> Vec<String> {
769 const ALLOWED_ATTRIBUTES: &[Symbol] =
770 &[sym::export_name, sym::link_section, sym::no_mangle, sym::non_exhaustive];
771
772 use rustc_abi::IntegerType;
773
774 let mut attrs: Vec<String> = self
775 .attrs
776 .other_attrs
777 .iter()
778 .filter_map(|attr| {
779 if is_json {
780 match attr {
781 hir::Attribute::Parsed(AttributeKind::Deprecation { .. }) => {
782 None
785 }
786 rustc_hir::Attribute::Parsed(rustc_attr_parsing::AttributeKind::Repr(
787 ..,
788 )) => {
789 None
794 }
795 _ => Some(rustc_hir_pretty::attribute_to_string(&tcx, attr)),
796 }
797 } else if ALLOWED_ATTRIBUTES.contains(&attr.name_or_empty()) {
798 Some(
799 rustc_hir_pretty::attribute_to_string(&tcx, attr)
800 .replace("\\\n", "")
801 .replace('\n', "")
802 .replace(" ", " "),
803 )
804 } else {
805 None
806 }
807 })
808 .collect();
809
810 if let Some(def_id) = self.def_id()
812 && let ItemType::Struct | ItemType::Enum | ItemType::Union = self.type_()
813 {
814 let adt = tcx.adt_def(def_id);
815 let repr = adt.repr();
816 let mut out = Vec::new();
817 if repr.c() {
818 out.push("C");
819 }
820 if repr.transparent() {
821 let render_transparent = cache.document_private
824 || adt
825 .all_fields()
826 .find(|field| {
827 let ty =
828 field.ty(tcx, ty::GenericArgs::identity_for_item(tcx, field.did));
829 tcx.layout_of(
830 ty::TypingEnv::post_analysis(tcx, field.did).as_query_input(ty),
831 )
832 .is_ok_and(|layout| !layout.is_1zst())
833 })
834 .map_or_else(
835 || adt.all_fields().any(|field| field.vis.is_public()),
836 |field| field.vis.is_public(),
837 );
838
839 if render_transparent {
840 out.push("transparent");
841 }
842 }
843 if repr.simd() {
844 out.push("simd");
845 }
846 let pack_s;
847 if let Some(pack) = repr.pack {
848 pack_s = format!("packed({})", pack.bytes());
849 out.push(&pack_s);
850 }
851 let align_s;
852 if let Some(align) = repr.align {
853 align_s = format!("align({})", align.bytes());
854 out.push(&align_s);
855 }
856 let int_s;
857 if let Some(int) = repr.int {
858 int_s = match int {
859 IntegerType::Pointer(is_signed) => {
860 format!("{}size", if is_signed { 'i' } else { 'u' })
861 }
862 IntegerType::Fixed(size, is_signed) => {
863 format!("{}{}", if is_signed { 'i' } else { 'u' }, size.size().bytes() * 8)
864 }
865 };
866 out.push(&int_s);
867 }
868 if !out.is_empty() {
869 attrs.push(format!("#[repr({})]", out.join(", ")));
870 }
871 }
872 attrs
873 }
874
875 pub fn is_doc_hidden(&self) -> bool {
876 self.attrs.is_doc_hidden()
877 }
878
879 pub fn def_id(&self) -> Option<DefId> {
880 self.item_id.as_def_id()
881 }
882}
883
884#[derive(Clone, Debug)]
885pub(crate) enum ItemKind {
886 ExternCrateItem {
887 src: Option<Symbol>,
889 },
890 ImportItem(Import),
891 StructItem(Struct),
892 UnionItem(Union),
893 EnumItem(Enum),
894 FunctionItem(Box<Function>),
895 ModuleItem(Module),
896 TypeAliasItem(Box<TypeAlias>),
897 StaticItem(Static),
898 TraitItem(Box<Trait>),
899 TraitAliasItem(TraitAlias),
900 ImplItem(Box<Impl>),
901 RequiredMethodItem(Box<Function>),
903 MethodItem(Box<Function>, Option<hir::Defaultness>),
907 StructFieldItem(Type),
908 VariantItem(Variant),
909 ForeignFunctionItem(Box<Function>, hir::Safety),
911 ForeignStaticItem(Static, hir::Safety),
913 ForeignTypeItem,
915 MacroItem(Macro),
916 ProcMacroItem(ProcMacro),
917 PrimitiveItem(PrimitiveType),
918 RequiredAssocConstItem(Generics, Box<Type>),
920 ConstantItem(Box<Constant>),
921 ProvidedAssocConstItem(Box<Constant>),
923 ImplAssocConstItem(Box<Constant>),
925 RequiredAssocTypeItem(Generics, Vec<GenericBound>),
929 AssocTypeItem(Box<TypeAlias>, Vec<GenericBound>),
931 StrippedItem(Box<ItemKind>),
933 KeywordItem,
934}
935
936impl ItemKind {
937 pub(crate) fn inner_items(&self) -> impl Iterator<Item = &Item> {
940 match self {
941 StructItem(s) => s.fields.iter(),
942 UnionItem(u) => u.fields.iter(),
943 VariantItem(v) => match &v.kind {
944 VariantKind::CLike => [].iter(),
945 VariantKind::Tuple(t) => t.iter(),
946 VariantKind::Struct(s) => s.fields.iter(),
947 },
948 EnumItem(e) => e.variants.iter(),
949 TraitItem(t) => t.items.iter(),
950 ImplItem(i) => i.items.iter(),
951 ModuleItem(m) => m.items.iter(),
952 ExternCrateItem { .. }
953 | ImportItem(_)
954 | FunctionItem(_)
955 | TypeAliasItem(_)
956 | StaticItem(_)
957 | ConstantItem(_)
958 | TraitAliasItem(_)
959 | RequiredMethodItem(_)
960 | MethodItem(_, _)
961 | StructFieldItem(_)
962 | ForeignFunctionItem(_, _)
963 | ForeignStaticItem(_, _)
964 | ForeignTypeItem
965 | MacroItem(_)
966 | ProcMacroItem(_)
967 | PrimitiveItem(_)
968 | RequiredAssocConstItem(..)
969 | ProvidedAssocConstItem(..)
970 | ImplAssocConstItem(..)
971 | RequiredAssocTypeItem(..)
972 | AssocTypeItem(..)
973 | StrippedItem(_)
974 | KeywordItem => [].iter(),
975 }
976 }
977
978 pub(crate) fn is_non_assoc(&self) -> bool {
980 matches!(
981 self,
982 StructItem(_)
983 | UnionItem(_)
984 | EnumItem(_)
985 | TraitItem(_)
986 | ModuleItem(_)
987 | ExternCrateItem { .. }
988 | FunctionItem(_)
989 | TypeAliasItem(_)
990 | StaticItem(_)
991 | ConstantItem(_)
992 | TraitAliasItem(_)
993 | ForeignFunctionItem(_, _)
994 | ForeignStaticItem(_, _)
995 | ForeignTypeItem
996 | MacroItem(_)
997 | ProcMacroItem(_)
998 | PrimitiveItem(_)
999 )
1000 }
1001}
1002
1003#[derive(Clone, Debug)]
1004pub(crate) struct Module {
1005 pub(crate) items: Vec<Item>,
1006 pub(crate) span: Span,
1007}
1008
1009pub(crate) fn hir_attr_lists<'a, I: IntoIterator<Item = &'a hir::Attribute>>(
1010 attrs: I,
1011 name: Symbol,
1012) -> impl Iterator<Item = ast::MetaItemInner> + use<'a, I> {
1013 attrs
1014 .into_iter()
1015 .filter(move |attr| attr.has_name(name))
1016 .filter_map(ast::attr::AttributeExt::meta_item_list)
1017 .flatten()
1018}
1019
1020pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator<Item = &'a hir::Attribute> + Clone>(
1021 attrs: I,
1022 tcx: TyCtxt<'_>,
1023 hidden_cfg: &FxHashSet<Cfg>,
1024) -> Option<Arc<Cfg>> {
1025 let doc_cfg_active = tcx.features().doc_cfg();
1026 let doc_auto_cfg_active = tcx.features().doc_auto_cfg();
1027
1028 fn single<T: IntoIterator>(it: T) -> Option<T::Item> {
1029 let mut iter = it.into_iter();
1030 let item = iter.next()?;
1031 if iter.next().is_some() {
1032 return None;
1033 }
1034 Some(item)
1035 }
1036
1037 let mut cfg = if doc_cfg_active || doc_auto_cfg_active {
1038 let mut doc_cfg = attrs
1039 .clone()
1040 .filter(|attr| attr.has_name(sym::doc))
1041 .flat_map(|attr| attr.meta_item_list().unwrap_or_default())
1042 .filter(|attr| attr.has_name(sym::cfg))
1043 .peekable();
1044 if doc_cfg.peek().is_some() && doc_cfg_active {
1045 let sess = tcx.sess;
1046 doc_cfg.fold(Cfg::True, |mut cfg, item| {
1047 if let Some(cfg_mi) =
1048 item.meta_item().and_then(|item| rustc_expand::config::parse_cfg(item, sess))
1049 {
1050 rustc_attr_parsing::cfg_matches(
1052 cfg_mi,
1053 tcx.sess,
1054 rustc_ast::CRATE_NODE_ID,
1055 Some(tcx.features()),
1056 );
1057 match Cfg::parse(cfg_mi) {
1058 Ok(new_cfg) => cfg &= new_cfg,
1059 Err(e) => {
1060 sess.dcx().span_err(e.span, e.msg);
1061 }
1062 }
1063 }
1064 cfg
1065 })
1066 } else if doc_auto_cfg_active {
1067 attrs
1070 .clone()
1071 .filter(|attr| attr.has_name(sym::cfg_trace))
1072 .filter_map(|attr| single(attr.meta_item_list()?))
1073 .filter_map(|attr| Cfg::parse_without(attr.meta_item()?, hidden_cfg).ok().flatten())
1074 .fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg)
1075 } else {
1076 Cfg::True
1077 }
1078 } else {
1079 Cfg::True
1080 };
1081
1082 for attr in hir_attr_lists(attrs, sym::target_feature) {
1085 if attr.has_name(sym::enable) && attr.value_str().is_some() {
1086 let mut meta = attr.meta_item().unwrap().clone();
1089 meta.path = ast::Path::from_ident(Ident::with_dummy_span(sym::target_feature));
1090
1091 if let Ok(feat_cfg) = Cfg::parse(&ast::MetaItemInner::MetaItem(meta)) {
1092 cfg &= feat_cfg;
1093 }
1094 }
1095 }
1096
1097 if cfg == Cfg::True { None } else { Some(Arc::new(cfg)) }
1098}
1099
1100pub(crate) trait NestedAttributesExt {
1101 fn has_word(self, word: Symbol) -> bool
1103 where
1104 Self: Sized,
1105 {
1106 <Self as NestedAttributesExt>::get_word_attr(self, word).is_some()
1107 }
1108
1109 fn get_word_attr(self, word: Symbol) -> Option<ast::MetaItemInner>;
1112}
1113
1114impl<I: Iterator<Item = ast::MetaItemInner>> NestedAttributesExt for I {
1115 fn get_word_attr(mut self, word: Symbol) -> Option<ast::MetaItemInner> {
1116 self.find(|attr| attr.is_word() && attr.has_name(word))
1117 }
1118}
1119
1120#[derive(Clone, Debug, PartialEq, Eq, Hash)]
1124pub(crate) struct ItemLink {
1125 pub(crate) link: Box<str>,
1127 pub(crate) link_text: Box<str>,
1132 pub(crate) page_id: DefId,
1136 pub(crate) fragment: Option<UrlFragment>,
1138}
1139
1140pub struct RenderedLink {
1141 pub(crate) original_text: Box<str>,
1145 pub(crate) new_text: Box<str>,
1147 pub(crate) href: String,
1149 pub(crate) tooltip: String,
1151}
1152
1153#[derive(Clone, Debug, Default)]
1156pub(crate) struct Attributes {
1157 pub(crate) doc_strings: Vec<DocFragment>,
1158 pub(crate) other_attrs: ThinVec<hir::Attribute>,
1159}
1160
1161impl Attributes {
1162 pub(crate) fn lists(&self, name: Symbol) -> impl Iterator<Item = ast::MetaItemInner> {
1163 hir_attr_lists(&self.other_attrs[..], name)
1164 }
1165
1166 pub(crate) fn has_doc_flag(&self, flag: Symbol) -> bool {
1167 for attr in &self.other_attrs {
1168 if !attr.has_name(sym::doc) {
1169 continue;
1170 }
1171
1172 if let Some(items) = attr.meta_item_list()
1173 && items.iter().filter_map(|i| i.meta_item()).any(|it| it.has_name(flag))
1174 {
1175 return true;
1176 }
1177 }
1178
1179 false
1180 }
1181
1182 pub(crate) fn is_doc_hidden(&self) -> bool {
1183 self.has_doc_flag(sym::hidden)
1184 }
1185
1186 pub(crate) fn from_hir(attrs: &[hir::Attribute]) -> Attributes {
1187 Attributes::from_hir_iter(attrs.iter().map(|attr| (attr, None)), false)
1188 }
1189
1190 pub(crate) fn from_hir_with_additional(
1191 attrs: &[hir::Attribute],
1192 (additional_attrs, def_id): (&[hir::Attribute], DefId),
1193 ) -> Attributes {
1194 let attrs1 = additional_attrs.iter().map(|attr| (attr, Some(def_id)));
1196 let attrs2 = attrs.iter().map(|attr| (attr, None));
1197 Attributes::from_hir_iter(attrs1.chain(attrs2), false)
1198 }
1199
1200 pub(crate) fn from_hir_iter<'a>(
1201 attrs: impl Iterator<Item = (&'a hir::Attribute, Option<DefId>)>,
1202 doc_only: bool,
1203 ) -> Attributes {
1204 let (doc_strings, other_attrs) = attrs_to_doc_fragments(attrs, doc_only);
1205 Attributes { doc_strings, other_attrs }
1206 }
1207
1208 pub(crate) fn doc_value(&self) -> String {
1210 self.opt_doc_value().unwrap_or_default()
1211 }
1212
1213 pub(crate) fn opt_doc_value(&self) -> Option<String> {
1217 (!self.doc_strings.is_empty()).then(|| {
1218 let mut res = String::new();
1219 for frag in &self.doc_strings {
1220 add_doc_fragment(&mut res, frag);
1221 }
1222 res.pop();
1223 res
1224 })
1225 }
1226
1227 pub(crate) fn get_doc_aliases(&self) -> Box<[Symbol]> {
1228 let mut aliases = FxIndexSet::default();
1229
1230 for attr in
1231 hir_attr_lists(&self.other_attrs[..], sym::doc).filter(|a| a.has_name(sym::alias))
1232 {
1233 if let Some(values) = attr.meta_item_list() {
1234 for l in values {
1235 if let Some(lit) = l.lit()
1236 && let ast::LitKind::Str(s, _) = lit.kind
1237 {
1238 aliases.insert(s);
1239 }
1240 }
1241 } else if let Some(value) = attr.value_str() {
1242 aliases.insert(value);
1243 }
1244 }
1245 aliases.into_iter().collect::<Vec<_>>().into()
1246 }
1247}
1248
1249#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1250pub(crate) enum GenericBound {
1251 TraitBound(PolyTrait, hir::TraitBoundModifiers),
1252 Outlives(Lifetime),
1253 Use(Vec<PreciseCapturingArg>),
1255}
1256
1257impl GenericBound {
1258 pub(crate) fn sized(cx: &mut DocContext<'_>) -> GenericBound {
1259 Self::sized_with(cx, hir::TraitBoundModifiers::NONE)
1260 }
1261
1262 pub(crate) fn maybe_sized(cx: &mut DocContext<'_>) -> GenericBound {
1263 Self::sized_with(
1264 cx,
1265 hir::TraitBoundModifiers {
1266 polarity: hir::BoundPolarity::Maybe(DUMMY_SP),
1267 constness: hir::BoundConstness::Never,
1268 },
1269 )
1270 }
1271
1272 fn sized_with(cx: &mut DocContext<'_>, modifiers: hir::TraitBoundModifiers) -> GenericBound {
1273 let did = cx.tcx.require_lang_item(LangItem::Sized, None);
1274 let empty = ty::Binder::dummy(ty::GenericArgs::empty());
1275 let path = clean_middle_path(cx, did, false, ThinVec::new(), empty);
1276 inline::record_extern_fqn(cx, did, ItemType::Trait);
1277 GenericBound::TraitBound(PolyTrait { trait_: path, generic_params: Vec::new() }, modifiers)
1278 }
1279
1280 pub(crate) fn is_trait_bound(&self) -> bool {
1281 matches!(self, Self::TraitBound(..))
1282 }
1283
1284 pub(crate) fn is_sized_bound(&self, cx: &DocContext<'_>) -> bool {
1285 if let GenericBound::TraitBound(
1286 PolyTrait { ref trait_, .. },
1287 rustc_hir::TraitBoundModifiers::NONE,
1288 ) = *self
1289 && Some(trait_.def_id()) == cx.tcx.lang_items().sized_trait()
1290 {
1291 return true;
1292 }
1293 false
1294 }
1295
1296 pub(crate) fn get_trait_path(&self) -> Option<Path> {
1297 if let GenericBound::TraitBound(PolyTrait { ref trait_, .. }, _) = *self {
1298 Some(trait_.clone())
1299 } else {
1300 None
1301 }
1302 }
1303}
1304
1305#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
1306pub(crate) struct Lifetime(pub Symbol);
1307
1308impl Lifetime {
1309 pub(crate) fn statik() -> Lifetime {
1310 Lifetime(kw::StaticLifetime)
1311 }
1312
1313 pub(crate) fn elided() -> Lifetime {
1314 Lifetime(kw::UnderscoreLifetime)
1315 }
1316}
1317
1318#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
1319pub(crate) enum PreciseCapturingArg {
1320 Lifetime(Lifetime),
1321 Param(Symbol),
1322}
1323
1324impl PreciseCapturingArg {
1325 pub(crate) fn name(self) -> Symbol {
1326 match self {
1327 PreciseCapturingArg::Lifetime(lt) => lt.0,
1328 PreciseCapturingArg::Param(param) => param,
1329 }
1330 }
1331}
1332
1333#[derive(Clone, PartialEq, Eq, Hash, Debug)]
1334pub(crate) enum WherePredicate {
1335 BoundPredicate { ty: Type, bounds: Vec<GenericBound>, bound_params: Vec<GenericParamDef> },
1336 RegionPredicate { lifetime: Lifetime, bounds: Vec<GenericBound> },
1337 EqPredicate { lhs: Type, rhs: Term },
1338}
1339
1340impl WherePredicate {
1341 pub(crate) fn get_bounds(&self) -> Option<&[GenericBound]> {
1342 match *self {
1343 WherePredicate::BoundPredicate { ref bounds, .. } => Some(bounds),
1344 WherePredicate::RegionPredicate { ref bounds, .. } => Some(bounds),
1345 _ => None,
1346 }
1347 }
1348}
1349
1350#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1351pub(crate) enum GenericParamDefKind {
1352 Lifetime { outlives: ThinVec<Lifetime> },
1353 Type { bounds: ThinVec<GenericBound>, default: Option<Box<Type>>, synthetic: bool },
1354 Const { ty: Box<Type>, default: Option<Box<String>>, synthetic: bool },
1356}
1357
1358impl GenericParamDefKind {
1359 pub(crate) fn is_type(&self) -> bool {
1360 matches!(self, GenericParamDefKind::Type { .. })
1361 }
1362}
1363
1364#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1365pub(crate) struct GenericParamDef {
1366 pub(crate) name: Symbol,
1367 pub(crate) def_id: DefId,
1368 pub(crate) kind: GenericParamDefKind,
1369}
1370
1371impl GenericParamDef {
1372 pub(crate) fn lifetime(def_id: DefId, name: Symbol) -> Self {
1373 Self { name, def_id, kind: GenericParamDefKind::Lifetime { outlives: ThinVec::new() } }
1374 }
1375
1376 pub(crate) fn is_synthetic_param(&self) -> bool {
1377 match self.kind {
1378 GenericParamDefKind::Lifetime { .. } | GenericParamDefKind::Const { .. } => false,
1379 GenericParamDefKind::Type { synthetic, .. } => synthetic,
1380 }
1381 }
1382
1383 pub(crate) fn is_type(&self) -> bool {
1384 self.kind.is_type()
1385 }
1386
1387 pub(crate) fn get_bounds(&self) -> Option<&[GenericBound]> {
1388 match self.kind {
1389 GenericParamDefKind::Type { ref bounds, .. } => Some(bounds),
1390 _ => None,
1391 }
1392 }
1393}
1394
1395#[derive(Clone, PartialEq, Eq, Hash, Debug, Default)]
1397pub(crate) struct Generics {
1398 pub(crate) params: ThinVec<GenericParamDef>,
1399 pub(crate) where_predicates: ThinVec<WherePredicate>,
1400}
1401
1402impl Generics {
1403 pub(crate) fn is_empty(&self) -> bool {
1404 self.params.is_empty() && self.where_predicates.is_empty()
1405 }
1406}
1407
1408#[derive(Clone, Debug)]
1409pub(crate) struct Function {
1410 pub(crate) decl: FnDecl,
1411 pub(crate) generics: Generics,
1412}
1413
1414#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1415pub(crate) struct FnDecl {
1416 pub(crate) inputs: Arguments,
1417 pub(crate) output: Type,
1418 pub(crate) c_variadic: bool,
1419}
1420
1421impl FnDecl {
1422 pub(crate) fn receiver_type(&self) -> Option<&Type> {
1423 self.inputs.values.first().and_then(|v| v.to_receiver())
1424 }
1425}
1426
1427#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1428pub(crate) struct Arguments {
1429 pub(crate) values: Vec<Argument>,
1430}
1431
1432#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1433pub(crate) struct Argument {
1434 pub(crate) type_: Type,
1435 pub(crate) name: Symbol,
1436 pub(crate) is_const: bool,
1439}
1440
1441impl Argument {
1442 pub(crate) fn to_receiver(&self) -> Option<&Type> {
1443 if self.name == kw::SelfLower { Some(&self.type_) } else { None }
1444 }
1445}
1446
1447#[derive(Clone, Debug)]
1448pub(crate) struct Trait {
1449 pub(crate) def_id: DefId,
1450 pub(crate) items: Vec<Item>,
1451 pub(crate) generics: Generics,
1452 pub(crate) bounds: Vec<GenericBound>,
1453}
1454
1455impl Trait {
1456 pub(crate) fn is_auto(&self, tcx: TyCtxt<'_>) -> bool {
1457 tcx.trait_is_auto(self.def_id)
1458 }
1459 pub(crate) fn is_notable_trait(&self, tcx: TyCtxt<'_>) -> bool {
1460 tcx.is_doc_notable_trait(self.def_id)
1461 }
1462 pub(crate) fn safety(&self, tcx: TyCtxt<'_>) -> hir::Safety {
1463 tcx.trait_def(self.def_id).safety
1464 }
1465 pub(crate) fn is_dyn_compatible(&self, tcx: TyCtxt<'_>) -> bool {
1466 tcx.is_dyn_compatible(self.def_id)
1467 }
1468}
1469
1470#[derive(Clone, Debug)]
1471pub(crate) struct TraitAlias {
1472 pub(crate) generics: Generics,
1473 pub(crate) bounds: Vec<GenericBound>,
1474}
1475
1476#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1478pub(crate) struct PolyTrait {
1479 pub(crate) trait_: Path,
1480 pub(crate) generic_params: Vec<GenericParamDef>,
1481}
1482
1483#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1485pub(crate) enum Type {
1486 Path {
1491 path: Path,
1492 },
1493 DynTrait(Vec<PolyTrait>, Option<Lifetime>),
1495 Generic(Symbol),
1497 SelfTy,
1499 Primitive(PrimitiveType),
1501 BareFunction(Box<BareFunctionDecl>),
1503 Tuple(Vec<Type>),
1505 Slice(Box<Type>),
1507 Array(Box<Type>, Box<str>),
1511 Pat(Box<Type>, Box<str>),
1512 RawPointer(Mutability, Box<Type>),
1514 BorrowedRef {
1516 lifetime: Option<Lifetime>,
1517 mutability: Mutability,
1518 type_: Box<Type>,
1519 },
1520
1521 QPath(Box<QPathData>),
1523
1524 Infer,
1526
1527 ImplTrait(Vec<GenericBound>),
1529
1530 UnsafeBinder(Box<UnsafeBinderTy>),
1531}
1532
1533impl Type {
1534 pub(crate) fn without_borrowed_ref(&self) -> &Type {
1536 let mut result = self;
1537 while let Type::BorrowedRef { type_, .. } = result {
1538 result = type_;
1539 }
1540 result
1541 }
1542
1543 pub(crate) fn is_borrowed_ref(&self) -> bool {
1544 matches!(self, Type::BorrowedRef { .. })
1545 }
1546
1547 fn is_type_alias(&self) -> bool {
1548 matches!(self, Type::Path { path: Path { res: Res::Def(DefKind::TyAlias, _), .. } })
1549 }
1550
1551 pub(crate) fn is_doc_subtype_of(&self, other: &Self, cache: &Cache) -> bool {
1572 let (self_cleared, other_cleared) = if !self.is_borrowed_ref() || !other.is_borrowed_ref() {
1575 (self.without_borrowed_ref(), other.without_borrowed_ref())
1576 } else {
1577 (self, other)
1578 };
1579
1580 if self_cleared.is_type_alias() || other_cleared.is_type_alias() {
1586 return true;
1587 }
1588
1589 match (self_cleared, other_cleared) {
1590 (Type::Tuple(a), Type::Tuple(b)) => {
1592 a.len() == b.len() && a.iter().zip(b).all(|(a, b)| a.is_doc_subtype_of(b, cache))
1593 }
1594 (Type::Slice(a), Type::Slice(b)) => a.is_doc_subtype_of(b, cache),
1595 (Type::Array(a, al), Type::Array(b, bl)) => al == bl && a.is_doc_subtype_of(b, cache),
1596 (Type::RawPointer(mutability, type_), Type::RawPointer(b_mutability, b_type_)) => {
1597 mutability == b_mutability && type_.is_doc_subtype_of(b_type_, cache)
1598 }
1599 (
1600 Type::BorrowedRef { mutability, type_, .. },
1601 Type::BorrowedRef { mutability: b_mutability, type_: b_type_, .. },
1602 ) => mutability == b_mutability && type_.is_doc_subtype_of(b_type_, cache),
1603 (Type::Infer, _) | (_, Type::Infer) => true,
1605 (_, Type::Generic(_)) => true,
1608 (Type::Generic(_), _) => false,
1609 (Type::SelfTy, Type::SelfTy) => true,
1611 (Type::Path { path: a }, Type::Path { path: b }) => {
1613 a.def_id() == b.def_id()
1614 && a.generics()
1615 .zip(b.generics())
1616 .map(|(ag, bg)| {
1617 ag.iter().zip(bg.iter()).all(|(at, bt)| at.is_doc_subtype_of(bt, cache))
1618 })
1619 .unwrap_or(true)
1620 }
1621 (a, b) => a
1623 .def_id(cache)
1624 .and_then(|a| Some((a, b.def_id(cache)?)))
1625 .map(|(a, b)| a == b)
1626 .unwrap_or(false),
1627 }
1628 }
1629
1630 pub(crate) fn primitive_type(&self) -> Option<PrimitiveType> {
1631 match *self {
1632 Primitive(p) | BorrowedRef { type_: box Primitive(p), .. } => Some(p),
1633 Slice(..) | BorrowedRef { type_: box Slice(..), .. } => Some(PrimitiveType::Slice),
1634 Array(..) | BorrowedRef { type_: box Array(..), .. } => Some(PrimitiveType::Array),
1635 Tuple(ref tys) => {
1636 if tys.is_empty() {
1637 Some(PrimitiveType::Unit)
1638 } else {
1639 Some(PrimitiveType::Tuple)
1640 }
1641 }
1642 RawPointer(..) => Some(PrimitiveType::RawPointer),
1643 BareFunction(..) => Some(PrimitiveType::Fn),
1644 _ => None,
1645 }
1646 }
1647
1648 pub(crate) fn sugared_async_return_type(self) -> Type {
1658 if let Type::ImplTrait(mut v) = self
1659 && let Some(GenericBound::TraitBound(PolyTrait { mut trait_, .. }, _)) = v.pop()
1660 && let Some(segment) = trait_.segments.pop()
1661 && let GenericArgs::AngleBracketed { mut constraints, .. } = segment.args
1662 && let Some(constraint) = constraints.pop()
1663 && let AssocItemConstraintKind::Equality { term } = constraint.kind
1664 && let Term::Type(ty) = term
1665 {
1666 ty
1667 } else {
1668 panic!("unexpected async fn return type")
1669 }
1670 }
1671
1672 pub(crate) fn is_assoc_ty(&self) -> bool {
1674 match self {
1675 Type::Path { path, .. } => path.is_assoc_ty(),
1676 _ => false,
1677 }
1678 }
1679
1680 pub(crate) fn is_self_type(&self) -> bool {
1681 matches!(*self, Type::SelfTy)
1682 }
1683
1684 pub(crate) fn generic_args(&self) -> Option<&GenericArgs> {
1685 match self {
1686 Type::Path { path, .. } => path.generic_args(),
1687 _ => None,
1688 }
1689 }
1690
1691 pub(crate) fn generics(&self) -> Option<Vec<&Type>> {
1692 match self {
1693 Type::Path { path, .. } => path.generics(),
1694 _ => None,
1695 }
1696 }
1697
1698 pub(crate) fn is_full_generic(&self) -> bool {
1699 matches!(self, Type::Generic(_))
1700 }
1701
1702 pub(crate) fn is_unit(&self) -> bool {
1703 matches!(self, Type::Tuple(v) if v.is_empty())
1704 }
1705
1706 pub(crate) fn projection(&self) -> Option<(&Type, DefId, PathSegment)> {
1707 if let QPath(box QPathData { self_type, trait_, assoc, .. }) = self {
1708 Some((self_type, trait_.as_ref()?.def_id(), assoc.clone()))
1709 } else {
1710 None
1711 }
1712 }
1713
1714 pub(crate) fn def_id(&self, cache: &Cache) -> Option<DefId> {
1718 let t: PrimitiveType = match *self {
1719 Type::Path { ref path } => return Some(path.def_id()),
1720 DynTrait(ref bounds, _) => return bounds.first().map(|b| b.trait_.def_id()),
1721 Primitive(p) => return cache.primitive_locations.get(&p).cloned(),
1722 BorrowedRef { type_: box Generic(..), .. } => PrimitiveType::Reference,
1723 BorrowedRef { ref type_, .. } => return type_.def_id(cache),
1724 Tuple(ref tys) => {
1725 if tys.is_empty() {
1726 PrimitiveType::Unit
1727 } else {
1728 PrimitiveType::Tuple
1729 }
1730 }
1731 BareFunction(..) => PrimitiveType::Fn,
1732 Slice(..) => PrimitiveType::Slice,
1733 Array(..) => PrimitiveType::Array,
1734 Type::Pat(..) => PrimitiveType::Pat,
1735 RawPointer(..) => PrimitiveType::RawPointer,
1736 QPath(box QPathData { ref self_type, .. }) => return self_type.def_id(cache),
1737 Generic(_) | SelfTy | Infer | ImplTrait(_) | UnsafeBinder(_) => return None,
1738 };
1739 Primitive(t).def_id(cache)
1740 }
1741}
1742
1743#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1744pub(crate) struct QPathData {
1745 pub assoc: PathSegment,
1746 pub self_type: Type,
1747 pub should_show_cast: bool,
1749 pub trait_: Option<Path>,
1750}
1751
1752#[derive(Clone, PartialEq, Eq, Hash, Copy, Debug)]
1759pub(crate) enum PrimitiveType {
1760 Isize,
1761 I8,
1762 I16,
1763 I32,
1764 I64,
1765 I128,
1766 Usize,
1767 U8,
1768 U16,
1769 U32,
1770 U64,
1771 U128,
1772 F16,
1773 F32,
1774 F64,
1775 F128,
1776 Char,
1777 Bool,
1778 Str,
1779 Slice,
1780 Array,
1781 Pat,
1782 Tuple,
1783 Unit,
1784 RawPointer,
1785 Reference,
1786 Fn,
1787 Never,
1788}
1789
1790type SimplifiedTypes = FxIndexMap<PrimitiveType, ArrayVec<SimplifiedType, 3>>;
1791impl PrimitiveType {
1792 pub(crate) fn from_hir(prim: hir::PrimTy) -> PrimitiveType {
1793 use ast::{FloatTy, IntTy, UintTy};
1794 match prim {
1795 hir::PrimTy::Int(IntTy::Isize) => PrimitiveType::Isize,
1796 hir::PrimTy::Int(IntTy::I8) => PrimitiveType::I8,
1797 hir::PrimTy::Int(IntTy::I16) => PrimitiveType::I16,
1798 hir::PrimTy::Int(IntTy::I32) => PrimitiveType::I32,
1799 hir::PrimTy::Int(IntTy::I64) => PrimitiveType::I64,
1800 hir::PrimTy::Int(IntTy::I128) => PrimitiveType::I128,
1801 hir::PrimTy::Uint(UintTy::Usize) => PrimitiveType::Usize,
1802 hir::PrimTy::Uint(UintTy::U8) => PrimitiveType::U8,
1803 hir::PrimTy::Uint(UintTy::U16) => PrimitiveType::U16,
1804 hir::PrimTy::Uint(UintTy::U32) => PrimitiveType::U32,
1805 hir::PrimTy::Uint(UintTy::U64) => PrimitiveType::U64,
1806 hir::PrimTy::Uint(UintTy::U128) => PrimitiveType::U128,
1807 hir::PrimTy::Float(FloatTy::F16) => PrimitiveType::F16,
1808 hir::PrimTy::Float(FloatTy::F32) => PrimitiveType::F32,
1809 hir::PrimTy::Float(FloatTy::F64) => PrimitiveType::F64,
1810 hir::PrimTy::Float(FloatTy::F128) => PrimitiveType::F128,
1811 hir::PrimTy::Str => PrimitiveType::Str,
1812 hir::PrimTy::Bool => PrimitiveType::Bool,
1813 hir::PrimTy::Char => PrimitiveType::Char,
1814 }
1815 }
1816
1817 pub(crate) fn from_symbol(s: Symbol) -> Option<PrimitiveType> {
1818 match s {
1819 sym::isize => Some(PrimitiveType::Isize),
1820 sym::i8 => Some(PrimitiveType::I8),
1821 sym::i16 => Some(PrimitiveType::I16),
1822 sym::i32 => Some(PrimitiveType::I32),
1823 sym::i64 => Some(PrimitiveType::I64),
1824 sym::i128 => Some(PrimitiveType::I128),
1825 sym::usize => Some(PrimitiveType::Usize),
1826 sym::u8 => Some(PrimitiveType::U8),
1827 sym::u16 => Some(PrimitiveType::U16),
1828 sym::u32 => Some(PrimitiveType::U32),
1829 sym::u64 => Some(PrimitiveType::U64),
1830 sym::u128 => Some(PrimitiveType::U128),
1831 sym::bool => Some(PrimitiveType::Bool),
1832 sym::char => Some(PrimitiveType::Char),
1833 sym::str => Some(PrimitiveType::Str),
1834 sym::f16 => Some(PrimitiveType::F16),
1835 sym::f32 => Some(PrimitiveType::F32),
1836 sym::f64 => Some(PrimitiveType::F64),
1837 sym::f128 => Some(PrimitiveType::F128),
1838 sym::array => Some(PrimitiveType::Array),
1839 sym::slice => Some(PrimitiveType::Slice),
1840 sym::tuple => Some(PrimitiveType::Tuple),
1841 sym::unit => Some(PrimitiveType::Unit),
1842 sym::pointer => Some(PrimitiveType::RawPointer),
1843 sym::reference => Some(PrimitiveType::Reference),
1844 kw::Fn => Some(PrimitiveType::Fn),
1845 sym::never => Some(PrimitiveType::Never),
1846 _ => None,
1847 }
1848 }
1849
1850 pub(crate) fn simplified_types() -> &'static SimplifiedTypes {
1851 use PrimitiveType::*;
1852 use ty::{FloatTy, IntTy, UintTy};
1853 static CELL: OnceCell<SimplifiedTypes> = OnceCell::new();
1854
1855 let single = |x| iter::once(x).collect();
1856 CELL.get_or_init(move || {
1857 map! {
1858 Isize => single(SimplifiedType::Int(IntTy::Isize)),
1859 I8 => single(SimplifiedType::Int(IntTy::I8)),
1860 I16 => single(SimplifiedType::Int(IntTy::I16)),
1861 I32 => single(SimplifiedType::Int(IntTy::I32)),
1862 I64 => single(SimplifiedType::Int(IntTy::I64)),
1863 I128 => single(SimplifiedType::Int(IntTy::I128)),
1864 Usize => single(SimplifiedType::Uint(UintTy::Usize)),
1865 U8 => single(SimplifiedType::Uint(UintTy::U8)),
1866 U16 => single(SimplifiedType::Uint(UintTy::U16)),
1867 U32 => single(SimplifiedType::Uint(UintTy::U32)),
1868 U64 => single(SimplifiedType::Uint(UintTy::U64)),
1869 U128 => single(SimplifiedType::Uint(UintTy::U128)),
1870 F16 => single(SimplifiedType::Float(FloatTy::F16)),
1871 F32 => single(SimplifiedType::Float(FloatTy::F32)),
1872 F64 => single(SimplifiedType::Float(FloatTy::F64)),
1873 F128 => single(SimplifiedType::Float(FloatTy::F128)),
1874 Str => single(SimplifiedType::Str),
1875 Bool => single(SimplifiedType::Bool),
1876 Char => single(SimplifiedType::Char),
1877 Array => single(SimplifiedType::Array),
1878 Slice => single(SimplifiedType::Slice),
1879 Tuple => [SimplifiedType::Tuple(1), SimplifiedType::Tuple(2), SimplifiedType::Tuple(3)].into(),
1885 Unit => single(SimplifiedType::Tuple(0)),
1886 RawPointer => [SimplifiedType::Ptr(Mutability::Not), SimplifiedType::Ptr(Mutability::Mut)].into_iter().collect(),
1887 Reference => [SimplifiedType::Ref(Mutability::Not), SimplifiedType::Ref(Mutability::Mut)].into_iter().collect(),
1888 Fn => single(SimplifiedType::Function(1)),
1891 Never => single(SimplifiedType::Never),
1892 }
1893 })
1894 }
1895
1896 pub(crate) fn impls<'tcx>(&self, tcx: TyCtxt<'tcx>) -> impl Iterator<Item = DefId> + 'tcx {
1897 Self::simplified_types()
1898 .get(self)
1899 .into_iter()
1900 .flatten()
1901 .flat_map(move |&simp| tcx.incoherent_impls(simp).iter())
1902 .copied()
1903 }
1904
1905 pub(crate) fn all_impls(tcx: TyCtxt<'_>) -> impl Iterator<Item = DefId> {
1906 Self::simplified_types()
1907 .values()
1908 .flatten()
1909 .flat_map(move |&simp| tcx.incoherent_impls(simp).iter())
1910 .copied()
1911 }
1912
1913 pub(crate) fn as_sym(&self) -> Symbol {
1914 use PrimitiveType::*;
1915 match self {
1916 Isize => sym::isize,
1917 I8 => sym::i8,
1918 I16 => sym::i16,
1919 I32 => sym::i32,
1920 I64 => sym::i64,
1921 I128 => sym::i128,
1922 Usize => sym::usize,
1923 U8 => sym::u8,
1924 U16 => sym::u16,
1925 U32 => sym::u32,
1926 U64 => sym::u64,
1927 U128 => sym::u128,
1928 F16 => sym::f16,
1929 F32 => sym::f32,
1930 F64 => sym::f64,
1931 F128 => sym::f128,
1932 Str => sym::str,
1933 Bool => sym::bool,
1934 Char => sym::char,
1935 Array => sym::array,
1936 Pat => sym::pat,
1937 Slice => sym::slice,
1938 Tuple => sym::tuple,
1939 Unit => sym::unit,
1940 RawPointer => sym::pointer,
1941 Reference => sym::reference,
1942 Fn => kw::Fn,
1943 Never => sym::never,
1944 }
1945 }
1946
1947 pub(crate) fn primitive_locations(tcx: TyCtxt<'_>) -> &FxIndexMap<PrimitiveType, DefId> {
1959 static PRIMITIVE_LOCATIONS: OnceCell<FxIndexMap<PrimitiveType, DefId>> = OnceCell::new();
1960 PRIMITIVE_LOCATIONS.get_or_init(|| {
1961 let mut primitive_locations = FxIndexMap::default();
1962 for &crate_num in tcx.crates(()) {
1965 let e = ExternalCrate { crate_num };
1966 let crate_name = e.name(tcx);
1967 debug!(?crate_num, ?crate_name);
1968 for &(def_id, prim) in &e.primitives(tcx) {
1969 if crate_name == sym::core && primitive_locations.contains_key(&prim) {
1971 continue;
1972 }
1973 primitive_locations.insert(prim, def_id);
1974 }
1975 }
1976 let local_primitives = ExternalCrate { crate_num: LOCAL_CRATE }.primitives(tcx);
1977 for (def_id, prim) in local_primitives {
1978 primitive_locations.insert(prim, def_id);
1979 }
1980 primitive_locations
1981 })
1982 }
1983}
1984
1985impl From<ast::IntTy> for PrimitiveType {
1986 fn from(int_ty: ast::IntTy) -> PrimitiveType {
1987 match int_ty {
1988 ast::IntTy::Isize => PrimitiveType::Isize,
1989 ast::IntTy::I8 => PrimitiveType::I8,
1990 ast::IntTy::I16 => PrimitiveType::I16,
1991 ast::IntTy::I32 => PrimitiveType::I32,
1992 ast::IntTy::I64 => PrimitiveType::I64,
1993 ast::IntTy::I128 => PrimitiveType::I128,
1994 }
1995 }
1996}
1997
1998impl From<ast::UintTy> for PrimitiveType {
1999 fn from(uint_ty: ast::UintTy) -> PrimitiveType {
2000 match uint_ty {
2001 ast::UintTy::Usize => PrimitiveType::Usize,
2002 ast::UintTy::U8 => PrimitiveType::U8,
2003 ast::UintTy::U16 => PrimitiveType::U16,
2004 ast::UintTy::U32 => PrimitiveType::U32,
2005 ast::UintTy::U64 => PrimitiveType::U64,
2006 ast::UintTy::U128 => PrimitiveType::U128,
2007 }
2008 }
2009}
2010
2011impl From<ast::FloatTy> for PrimitiveType {
2012 fn from(float_ty: ast::FloatTy) -> PrimitiveType {
2013 match float_ty {
2014 ast::FloatTy::F16 => PrimitiveType::F16,
2015 ast::FloatTy::F32 => PrimitiveType::F32,
2016 ast::FloatTy::F64 => PrimitiveType::F64,
2017 ast::FloatTy::F128 => PrimitiveType::F128,
2018 }
2019 }
2020}
2021
2022impl From<ty::IntTy> for PrimitiveType {
2023 fn from(int_ty: ty::IntTy) -> PrimitiveType {
2024 match int_ty {
2025 ty::IntTy::Isize => PrimitiveType::Isize,
2026 ty::IntTy::I8 => PrimitiveType::I8,
2027 ty::IntTy::I16 => PrimitiveType::I16,
2028 ty::IntTy::I32 => PrimitiveType::I32,
2029 ty::IntTy::I64 => PrimitiveType::I64,
2030 ty::IntTy::I128 => PrimitiveType::I128,
2031 }
2032 }
2033}
2034
2035impl From<ty::UintTy> for PrimitiveType {
2036 fn from(uint_ty: ty::UintTy) -> PrimitiveType {
2037 match uint_ty {
2038 ty::UintTy::Usize => PrimitiveType::Usize,
2039 ty::UintTy::U8 => PrimitiveType::U8,
2040 ty::UintTy::U16 => PrimitiveType::U16,
2041 ty::UintTy::U32 => PrimitiveType::U32,
2042 ty::UintTy::U64 => PrimitiveType::U64,
2043 ty::UintTy::U128 => PrimitiveType::U128,
2044 }
2045 }
2046}
2047
2048impl From<ty::FloatTy> for PrimitiveType {
2049 fn from(float_ty: ty::FloatTy) -> PrimitiveType {
2050 match float_ty {
2051 ty::FloatTy::F16 => PrimitiveType::F16,
2052 ty::FloatTy::F32 => PrimitiveType::F32,
2053 ty::FloatTy::F64 => PrimitiveType::F64,
2054 ty::FloatTy::F128 => PrimitiveType::F128,
2055 }
2056 }
2057}
2058
2059impl From<hir::PrimTy> for PrimitiveType {
2060 fn from(prim_ty: hir::PrimTy) -> PrimitiveType {
2061 match prim_ty {
2062 hir::PrimTy::Int(int_ty) => int_ty.into(),
2063 hir::PrimTy::Uint(uint_ty) => uint_ty.into(),
2064 hir::PrimTy::Float(float_ty) => float_ty.into(),
2065 hir::PrimTy::Str => PrimitiveType::Str,
2066 hir::PrimTy::Bool => PrimitiveType::Bool,
2067 hir::PrimTy::Char => PrimitiveType::Char,
2068 }
2069 }
2070}
2071
2072#[derive(Clone, Debug)]
2073pub(crate) struct Struct {
2074 pub(crate) ctor_kind: Option<CtorKind>,
2075 pub(crate) generics: Generics,
2076 pub(crate) fields: ThinVec<Item>,
2077}
2078
2079impl Struct {
2080 pub(crate) fn has_stripped_entries(&self) -> bool {
2081 self.fields.iter().any(|f| f.is_stripped())
2082 }
2083}
2084
2085#[derive(Clone, Debug)]
2086pub(crate) struct Union {
2087 pub(crate) generics: Generics,
2088 pub(crate) fields: Vec<Item>,
2089}
2090
2091impl Union {
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)]
2101pub(crate) struct VariantStruct {
2102 pub(crate) fields: ThinVec<Item>,
2103}
2104
2105impl VariantStruct {
2106 pub(crate) fn has_stripped_entries(&self) -> bool {
2107 self.fields.iter().any(|f| f.is_stripped())
2108 }
2109}
2110
2111#[derive(Clone, Debug)]
2112pub(crate) struct Enum {
2113 pub(crate) variants: IndexVec<VariantIdx, Item>,
2114 pub(crate) generics: Generics,
2115}
2116
2117impl Enum {
2118 pub(crate) fn has_stripped_entries(&self) -> bool {
2119 self.variants.iter().any(|f| f.is_stripped())
2120 }
2121
2122 pub(crate) fn variants(&self) -> impl Iterator<Item = &Item> {
2123 self.variants.iter().filter(|v| !v.is_stripped())
2124 }
2125}
2126
2127#[derive(Clone, Debug)]
2128pub(crate) struct Variant {
2129 pub kind: VariantKind,
2130 pub discriminant: Option<Discriminant>,
2131}
2132
2133#[derive(Clone, Debug)]
2134pub(crate) enum VariantKind {
2135 CLike,
2136 Tuple(ThinVec<Item>),
2137 Struct(VariantStruct),
2138}
2139
2140impl Variant {
2141 pub(crate) fn has_stripped_entries(&self) -> Option<bool> {
2142 match &self.kind {
2143 VariantKind::Struct(struct_) => Some(struct_.has_stripped_entries()),
2144 VariantKind::CLike | VariantKind::Tuple(_) => None,
2145 }
2146 }
2147}
2148
2149#[derive(Clone, Debug)]
2150pub(crate) struct Discriminant {
2151 pub(super) expr: Option<BodyId>,
2154 pub(super) value: DefId,
2155}
2156
2157impl Discriminant {
2158 pub(crate) fn expr(&self, tcx: TyCtxt<'_>) -> Option<String> {
2161 self.expr
2162 .map(|body| rendered_const(tcx, tcx.hir_body(body), tcx.hir_body_owner_def_id(body)))
2163 }
2164 pub(crate) fn value(&self, tcx: TyCtxt<'_>, with_underscores: bool) -> String {
2165 print_evaluated_const(tcx, self.value, with_underscores, false).unwrap()
2166 }
2167}
2168
2169#[derive(Copy, Clone, Debug)]
2172pub(crate) struct Span(rustc_span::Span);
2173
2174impl Span {
2175 pub(crate) fn new(sp: rustc_span::Span) -> Self {
2180 Self(sp.source_callsite())
2181 }
2182
2183 pub(crate) fn inner(&self) -> rustc_span::Span {
2184 self.0
2185 }
2186
2187 pub(crate) fn filename(&self, sess: &Session) -> FileName {
2188 sess.source_map().span_to_filename(self.0)
2189 }
2190
2191 pub(crate) fn lo(&self, sess: &Session) -> Loc {
2192 sess.source_map().lookup_char_pos(self.0.lo())
2193 }
2194
2195 pub(crate) fn hi(&self, sess: &Session) -> Loc {
2196 sess.source_map().lookup_char_pos(self.0.hi())
2197 }
2198
2199 pub(crate) fn cnum(&self, sess: &Session) -> CrateNum {
2200 self.lo(sess).file.cnum
2202 }
2203}
2204
2205#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2206pub(crate) struct Path {
2207 pub(crate) res: Res,
2208 pub(crate) segments: ThinVec<PathSegment>,
2209}
2210
2211impl Path {
2212 pub(crate) fn def_id(&self) -> DefId {
2213 self.res.def_id()
2214 }
2215
2216 pub(crate) fn last_opt(&self) -> Option<Symbol> {
2217 self.segments.last().map(|s| s.name)
2218 }
2219
2220 pub(crate) fn last(&self) -> Symbol {
2221 self.last_opt().expect("segments were empty")
2222 }
2223
2224 pub(crate) fn whole_name(&self) -> String {
2225 self.segments
2226 .iter()
2227 .map(|s| if s.name == kw::PathRoot { "" } else { s.name.as_str() })
2228 .intersperse("::")
2229 .collect()
2230 }
2231
2232 pub(crate) fn is_assoc_ty(&self) -> bool {
2234 match self.res {
2235 Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } | Res::Def(DefKind::TyParam, _)
2236 if self.segments.len() != 1 =>
2237 {
2238 true
2239 }
2240 Res::Def(DefKind::AssocTy, _) => true,
2241 _ => false,
2242 }
2243 }
2244
2245 pub(crate) fn generic_args(&self) -> Option<&GenericArgs> {
2246 self.segments.last().map(|seg| &seg.args)
2247 }
2248
2249 pub(crate) fn generics(&self) -> Option<Vec<&Type>> {
2250 self.segments.last().and_then(|seg| {
2251 if let GenericArgs::AngleBracketed { ref args, .. } = seg.args {
2252 Some(
2253 args.iter()
2254 .filter_map(|arg| match arg {
2255 GenericArg::Type(ty) => Some(ty),
2256 _ => None,
2257 })
2258 .collect(),
2259 )
2260 } else {
2261 None
2262 }
2263 })
2264 }
2265}
2266
2267#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2268pub(crate) enum GenericArg {
2269 Lifetime(Lifetime),
2270 Type(Type),
2271 Const(Box<ConstantKind>),
2272 Infer,
2273}
2274
2275impl GenericArg {
2276 pub(crate) fn as_lt(&self) -> Option<&Lifetime> {
2277 if let Self::Lifetime(lt) = self { Some(lt) } else { None }
2278 }
2279
2280 pub(crate) fn as_ty(&self) -> Option<&Type> {
2281 if let Self::Type(ty) = self { Some(ty) } else { None }
2282 }
2283}
2284
2285#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2286pub(crate) enum GenericArgs {
2287 AngleBracketed { args: ThinVec<GenericArg>, constraints: ThinVec<AssocItemConstraint> },
2289 Parenthesized { inputs: ThinVec<Type>, output: Option<Box<Type>> },
2291 ReturnTypeNotation,
2293}
2294
2295impl GenericArgs {
2296 pub(crate) fn is_empty(&self) -> bool {
2297 match self {
2298 GenericArgs::AngleBracketed { args, constraints } => {
2299 args.is_empty() && constraints.is_empty()
2300 }
2301 GenericArgs::Parenthesized { inputs, output } => inputs.is_empty() && output.is_none(),
2302 GenericArgs::ReturnTypeNotation => false,
2303 }
2304 }
2305 pub(crate) fn constraints(&self) -> Box<dyn Iterator<Item = AssocItemConstraint> + '_> {
2306 match self {
2307 GenericArgs::AngleBracketed { constraints, .. } => {
2308 Box::new(constraints.iter().cloned())
2309 }
2310 GenericArgs::Parenthesized { output, .. } => Box::new(
2311 output
2312 .as_ref()
2313 .map(|ty| AssocItemConstraint {
2314 assoc: PathSegment {
2315 name: sym::Output,
2316 args: GenericArgs::AngleBracketed {
2317 args: ThinVec::new(),
2318 constraints: ThinVec::new(),
2319 },
2320 },
2321 kind: AssocItemConstraintKind::Equality {
2322 term: Term::Type((**ty).clone()),
2323 },
2324 })
2325 .into_iter(),
2326 ),
2327 GenericArgs::ReturnTypeNotation => Box::new([].into_iter()),
2328 }
2329 }
2330}
2331
2332impl<'a> IntoIterator for &'a GenericArgs {
2333 type IntoIter = Box<dyn Iterator<Item = GenericArg> + 'a>;
2334 type Item = GenericArg;
2335 fn into_iter(self) -> Self::IntoIter {
2336 match self {
2337 GenericArgs::AngleBracketed { args, .. } => Box::new(args.iter().cloned()),
2338 GenericArgs::Parenthesized { inputs, .. } => {
2339 Box::new(inputs.iter().cloned().map(GenericArg::Type))
2341 }
2342 GenericArgs::ReturnTypeNotation => Box::new([].into_iter()),
2343 }
2344 }
2345}
2346
2347#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2348pub(crate) struct PathSegment {
2349 pub(crate) name: Symbol,
2350 pub(crate) args: GenericArgs,
2351}
2352
2353#[derive(Clone, Debug)]
2354pub(crate) enum TypeAliasInnerType {
2355 Enum { variants: IndexVec<VariantIdx, Item>, is_non_exhaustive: bool },
2356 Union { fields: Vec<Item> },
2357 Struct { ctor_kind: Option<CtorKind>, fields: Vec<Item> },
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 Constant {
2446 pub(crate) fn expr(&self, tcx: TyCtxt<'_>) -> String {
2447 self.kind.expr(tcx)
2448 }
2449
2450 pub(crate) fn value(&self, tcx: TyCtxt<'_>) -> Option<String> {
2451 self.kind.value(tcx)
2452 }
2453
2454 pub(crate) fn is_literal(&self, tcx: TyCtxt<'_>) -> bool {
2455 self.kind.is_literal(tcx)
2456 }
2457}
2458
2459impl ConstantKind {
2460 pub(crate) fn expr(&self, tcx: TyCtxt<'_>) -> String {
2461 match *self {
2462 ConstantKind::TyConst { ref expr } => expr.to_string(),
2463 ConstantKind::Path { ref path } => path.to_string(),
2464 ConstantKind::Extern { def_id } => print_inlined_const(tcx, def_id),
2465 ConstantKind::Local { body, .. } | ConstantKind::Anonymous { body } => {
2466 rendered_const(tcx, tcx.hir_body(body), tcx.hir_body_owner_def_id(body))
2467 }
2468 ConstantKind::Infer => "_".to_string(),
2469 }
2470 }
2471
2472 pub(crate) fn value(&self, tcx: TyCtxt<'_>) -> Option<String> {
2473 match *self {
2474 ConstantKind::TyConst { .. }
2475 | ConstantKind::Path { .. }
2476 | ConstantKind::Anonymous { .. }
2477 | ConstantKind::Infer => None,
2478 ConstantKind::Extern { def_id } | ConstantKind::Local { def_id, .. } => {
2479 print_evaluated_const(tcx, def_id, true, true)
2480 }
2481 }
2482 }
2483
2484 pub(crate) fn is_literal(&self, tcx: TyCtxt<'_>) -> bool {
2485 match *self {
2486 ConstantKind::TyConst { .. }
2487 | ConstantKind::Extern { .. }
2488 | ConstantKind::Path { .. }
2489 | ConstantKind::Infer => false,
2490 ConstantKind::Local { body, .. } | ConstantKind::Anonymous { body } => {
2491 is_literal_expr(tcx, body.hir_id)
2492 }
2493 }
2494 }
2495}
2496
2497#[derive(Clone, Debug)]
2498pub(crate) struct Impl {
2499 pub(crate) safety: hir::Safety,
2500 pub(crate) generics: Generics,
2501 pub(crate) trait_: Option<Path>,
2502 pub(crate) for_: Type,
2503 pub(crate) items: Vec<Item>,
2504 pub(crate) polarity: ty::ImplPolarity,
2505 pub(crate) kind: ImplKind,
2506}
2507
2508impl Impl {
2509 pub(crate) fn provided_trait_methods(&self, tcx: TyCtxt<'_>) -> FxIndexSet<Symbol> {
2510 self.trait_
2511 .as_ref()
2512 .map(|t| t.def_id())
2513 .map(|did| tcx.provided_trait_methods(did).map(|meth| meth.name).collect())
2514 .unwrap_or_default()
2515 }
2516
2517 pub(crate) fn is_negative_trait_impl(&self) -> bool {
2518 matches!(self.polarity, ty::ImplPolarity::Negative)
2519 }
2520}
2521
2522#[derive(Clone, Debug)]
2523pub(crate) enum ImplKind {
2524 Normal,
2525 Auto,
2526 FakeVariadic,
2527 Blanket(Box<Type>),
2528}
2529
2530impl ImplKind {
2531 pub(crate) fn is_auto(&self) -> bool {
2532 matches!(self, ImplKind::Auto)
2533 }
2534
2535 pub(crate) fn is_blanket(&self) -> bool {
2536 matches!(self, ImplKind::Blanket(_))
2537 }
2538
2539 pub(crate) fn is_fake_variadic(&self) -> bool {
2540 matches!(self, ImplKind::FakeVariadic)
2541 }
2542
2543 pub(crate) fn as_blanket_ty(&self) -> Option<&Type> {
2544 match self {
2545 ImplKind::Blanket(ty) => Some(ty),
2546 _ => None,
2547 }
2548 }
2549}
2550
2551#[derive(Clone, Debug)]
2552pub(crate) struct Import {
2553 pub(crate) kind: ImportKind,
2554 pub(crate) source: ImportSource,
2556 pub(crate) should_be_displayed: bool,
2557}
2558
2559impl Import {
2560 pub(crate) fn new_simple(
2561 name: Symbol,
2562 source: ImportSource,
2563 should_be_displayed: bool,
2564 ) -> Self {
2565 Self { kind: ImportKind::Simple(name), source, should_be_displayed }
2566 }
2567
2568 pub(crate) fn new_glob(source: ImportSource, should_be_displayed: bool) -> Self {
2569 Self { kind: ImportKind::Glob, source, should_be_displayed }
2570 }
2571
2572 pub(crate) fn imported_item_is_doc_hidden(&self, tcx: TyCtxt<'_>) -> bool {
2573 self.source.did.is_some_and(|did| tcx.is_doc_hidden(did))
2574 }
2575}
2576
2577#[derive(Clone, Debug)]
2578pub(crate) enum ImportKind {
2579 Simple(Symbol),
2581 Glob,
2583}
2584
2585#[derive(Clone, Debug)]
2586pub(crate) struct ImportSource {
2587 pub(crate) path: Path,
2588 pub(crate) did: Option<DefId>,
2589}
2590
2591#[derive(Clone, Debug)]
2592pub(crate) struct Macro {
2593 pub(crate) source: String,
2594 pub(crate) macro_rules: bool,
2596}
2597
2598#[derive(Clone, Debug)]
2599pub(crate) struct ProcMacro {
2600 pub(crate) kind: MacroKind,
2601 pub(crate) helpers: Vec<Symbol>,
2602}
2603
2604#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2615pub(crate) struct AssocItemConstraint {
2616 pub(crate) assoc: PathSegment,
2617 pub(crate) kind: AssocItemConstraintKind,
2618}
2619
2620#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2622pub(crate) enum AssocItemConstraintKind {
2623 Equality { term: Term },
2624 Bound { bounds: Vec<GenericBound> },
2625}
2626
2627#[cfg(target_pointer_width = "64")]
2629mod size_asserts {
2630 use rustc_data_structures::static_assert_size;
2631
2632 use super::*;
2633 static_assert_size!(Crate, 16); static_assert_size!(DocFragment, 32);
2636 static_assert_size!(GenericArg, 32);
2637 static_assert_size!(GenericArgs, 24);
2638 static_assert_size!(GenericParamDef, 40);
2639 static_assert_size!(Generics, 16);
2640 static_assert_size!(Item, 8);
2641 static_assert_size!(ItemInner, 136);
2642 static_assert_size!(ItemKind, 48);
2643 static_assert_size!(PathSegment, 32);
2644 static_assert_size!(Type, 32);
2645 }