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