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::LinkSection { name, .. }) = attr {
757 Some(format!("#[link_section = \"{name}\"]"))
758 }
759 else if let hir::Attribute::Parsed(AttributeKind::NoMangle(..)) = attr {
762 Some("#[no_mangle]".to_string())
763 } else if let hir::Attribute::Parsed(AttributeKind::ExportName { name, .. }) = attr
764 {
765 Some(format!("#[export_name = \"{name}\"]"))
766 } else if is_json {
767 match attr {
768 hir::Attribute::Parsed(AttributeKind::Deprecation { .. }) => None,
771 hir::Attribute::Parsed(AttributeKind::Repr(..)) => None,
773 _ => Some({
774 let mut s = rustc_hir_pretty::attribute_to_string(&tcx, attr);
775 assert_eq!(s.pop(), Some('\n'));
776 s
777 }),
778 }
779 } else {
780 if !attr.has_any_name(ALLOWED_ATTRIBUTES) {
781 return None;
782 }
783 Some(
784 rustc_hir_pretty::attribute_to_string(&tcx, attr)
785 .replace("\\\n", "")
786 .replace('\n', "")
787 .replace(" ", " "),
788 )
789 }
790 })
791 .collect()
792 }
793
794 pub(crate) fn attributes(&self, tcx: TyCtxt<'_>, cache: &Cache, is_json: bool) -> Vec<String> {
795 let mut attrs = self.attributes_without_repr(tcx, is_json);
796
797 if let Some(repr_attr) = self.repr(tcx, cache, is_json) {
798 attrs.push(repr_attr);
799 }
800 attrs
801 }
802
803 pub(crate) fn repr(&self, tcx: TyCtxt<'_>, cache: &Cache, is_json: bool) -> Option<String> {
805 repr_attributes(tcx, cache, self.def_id()?, self.type_(), is_json)
806 }
807
808 pub fn is_doc_hidden(&self) -> bool {
809 self.attrs.is_doc_hidden()
810 }
811
812 pub fn def_id(&self) -> Option<DefId> {
813 self.item_id.as_def_id()
814 }
815}
816
817pub(crate) fn repr_attributes(
818 tcx: TyCtxt<'_>,
819 cache: &Cache,
820 def_id: DefId,
821 item_type: ItemType,
822 is_json: bool,
823) -> Option<String> {
824 use rustc_abi::IntegerType;
825
826 if !matches!(item_type, ItemType::Struct | ItemType::Enum | ItemType::Union) {
827 return None;
828 }
829 let adt = tcx.adt_def(def_id);
830 let repr = adt.repr();
831 let mut out = Vec::new();
832 if repr.c() {
833 out.push("C");
834 }
835 if repr.transparent() {
836 let render_transparent = cache.document_private
839 || is_json
840 || adt
841 .all_fields()
842 .find(|field| {
843 let ty = field.ty(tcx, ty::GenericArgs::identity_for_item(tcx, field.did));
844 tcx.layout_of(ty::TypingEnv::post_analysis(tcx, field.did).as_query_input(ty))
845 .is_ok_and(|layout| !layout.is_1zst())
846 })
847 .map_or_else(
848 || adt.all_fields().any(|field| field.vis.is_public()),
849 |field| field.vis.is_public(),
850 );
851
852 if render_transparent {
853 out.push("transparent");
854 }
855 }
856 if repr.simd() {
857 out.push("simd");
858 }
859 let pack_s;
860 if let Some(pack) = repr.pack {
861 pack_s = format!("packed({})", pack.bytes());
862 out.push(&pack_s);
863 }
864 let align_s;
865 if let Some(align) = repr.align {
866 align_s = format!("align({})", align.bytes());
867 out.push(&align_s);
868 }
869 let int_s;
870 if let Some(int) = repr.int {
871 int_s = match int {
872 IntegerType::Pointer(is_signed) => {
873 format!("{}size", if is_signed { 'i' } else { 'u' })
874 }
875 IntegerType::Fixed(size, is_signed) => {
876 format!("{}{}", if is_signed { 'i' } else { 'u' }, size.size().bytes() * 8)
877 }
878 };
879 out.push(&int_s);
880 }
881 if !out.is_empty() { Some(format!("#[repr({})]", out.join(", "))) } else { None }
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
1047 doc_cfg.fold(Cfg::True, |mut cfg, item| {
1048 if let Some(cfg_mi) =
1049 item.meta_item().and_then(|item| rustc_expand::config::parse_cfg(item, sess))
1050 {
1051 match Cfg::parse(cfg_mi) {
1052 Ok(new_cfg) => cfg &= new_cfg,
1053 Err(e) => {
1054 sess.dcx().span_err(e.span, e.msg);
1055 }
1056 }
1057 }
1058 cfg
1059 })
1060 } else if doc_auto_cfg_active {
1061 attrs
1064 .clone()
1065 .filter(|attr| attr.has_name(sym::cfg_trace))
1066 .filter_map(|attr| single(attr.meta_item_list()?))
1067 .filter_map(|attr| Cfg::parse_without(attr.meta_item()?, hidden_cfg).ok().flatten())
1068 .fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg)
1069 } else {
1070 Cfg::True
1071 }
1072 } else {
1073 Cfg::True
1074 };
1075
1076 for attr in hir_attr_lists(attrs, sym::target_feature) {
1079 if attr.has_name(sym::enable) && attr.value_str().is_some() {
1080 let mut meta = attr.meta_item().unwrap().clone();
1083 meta.path = ast::Path::from_ident(Ident::with_dummy_span(sym::target_feature));
1084
1085 if let Ok(feat_cfg) = Cfg::parse(&ast::MetaItemInner::MetaItem(meta)) {
1086 cfg &= feat_cfg;
1087 }
1088 }
1089 }
1090
1091 if cfg == Cfg::True { None } else { Some(Arc::new(cfg)) }
1092}
1093
1094pub(crate) trait NestedAttributesExt {
1095 fn has_word(self, word: Symbol) -> bool
1097 where
1098 Self: Sized,
1099 {
1100 <Self as NestedAttributesExt>::get_word_attr(self, word).is_some()
1101 }
1102
1103 fn get_word_attr(self, word: Symbol) -> Option<ast::MetaItemInner>;
1106}
1107
1108impl<I: Iterator<Item = ast::MetaItemInner>> NestedAttributesExt for I {
1109 fn get_word_attr(mut self, word: Symbol) -> Option<ast::MetaItemInner> {
1110 self.find(|attr| attr.is_word() && attr.has_name(word))
1111 }
1112}
1113
1114#[derive(Clone, Debug, PartialEq, Eq, Hash)]
1118pub(crate) struct ItemLink {
1119 pub(crate) link: Box<str>,
1121 pub(crate) link_text: Box<str>,
1126 pub(crate) page_id: DefId,
1130 pub(crate) fragment: Option<UrlFragment>,
1132}
1133
1134pub struct RenderedLink {
1135 pub(crate) original_text: Box<str>,
1139 pub(crate) new_text: Box<str>,
1141 pub(crate) href: String,
1143 pub(crate) tooltip: String,
1145}
1146
1147#[derive(Clone, Debug, Default)]
1150pub(crate) struct Attributes {
1151 pub(crate) doc_strings: Vec<DocFragment>,
1152 pub(crate) other_attrs: ThinVec<hir::Attribute>,
1153}
1154
1155impl Attributes {
1156 pub(crate) fn lists(&self, name: Symbol) -> impl Iterator<Item = ast::MetaItemInner> {
1157 hir_attr_lists(&self.other_attrs[..], name)
1158 }
1159
1160 pub(crate) fn has_doc_flag(&self, flag: Symbol) -> bool {
1161 for attr in &self.other_attrs {
1162 if !attr.has_name(sym::doc) {
1163 continue;
1164 }
1165
1166 if let Some(items) = attr.meta_item_list()
1167 && items.iter().filter_map(|i| i.meta_item()).any(|it| it.has_name(flag))
1168 {
1169 return true;
1170 }
1171 }
1172
1173 false
1174 }
1175
1176 pub(crate) fn is_doc_hidden(&self) -> bool {
1177 self.has_doc_flag(sym::hidden)
1178 }
1179
1180 pub(crate) fn from_hir(attrs: &[hir::Attribute]) -> Attributes {
1181 Attributes::from_hir_iter(attrs.iter().map(|attr| (attr, None)), false)
1182 }
1183
1184 pub(crate) fn from_hir_with_additional(
1185 attrs: &[hir::Attribute],
1186 (additional_attrs, def_id): (&[hir::Attribute], DefId),
1187 ) -> Attributes {
1188 let attrs1 = additional_attrs.iter().map(|attr| (attr, Some(def_id)));
1190 let attrs2 = attrs.iter().map(|attr| (attr, None));
1191 Attributes::from_hir_iter(attrs1.chain(attrs2), false)
1192 }
1193
1194 pub(crate) fn from_hir_iter<'a>(
1195 attrs: impl Iterator<Item = (&'a hir::Attribute, Option<DefId>)>,
1196 doc_only: bool,
1197 ) -> Attributes {
1198 let (doc_strings, other_attrs) = attrs_to_doc_fragments(attrs, doc_only);
1199 Attributes { doc_strings, other_attrs }
1200 }
1201
1202 pub(crate) fn doc_value(&self) -> String {
1204 self.opt_doc_value().unwrap_or_default()
1205 }
1206
1207 pub(crate) fn opt_doc_value(&self) -> Option<String> {
1211 (!self.doc_strings.is_empty()).then(|| {
1212 let mut res = String::new();
1213 for frag in &self.doc_strings {
1214 add_doc_fragment(&mut res, frag);
1215 }
1216 res.pop();
1217 res
1218 })
1219 }
1220
1221 pub(crate) fn get_doc_aliases(&self) -> Box<[Symbol]> {
1222 let mut aliases = FxIndexSet::default();
1223
1224 for attr in
1225 hir_attr_lists(&self.other_attrs[..], sym::doc).filter(|a| a.has_name(sym::alias))
1226 {
1227 if let Some(values) = attr.meta_item_list() {
1228 for l in values {
1229 if let Some(lit) = l.lit()
1230 && let ast::LitKind::Str(s, _) = lit.kind
1231 {
1232 aliases.insert(s);
1233 }
1234 }
1235 } else if let Some(value) = attr.value_str() {
1236 aliases.insert(value);
1237 }
1238 }
1239 aliases.into_iter().collect::<Vec<_>>().into()
1240 }
1241}
1242
1243#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1244pub(crate) enum GenericBound {
1245 TraitBound(PolyTrait, hir::TraitBoundModifiers),
1246 Outlives(Lifetime),
1247 Use(Vec<PreciseCapturingArg>),
1249}
1250
1251impl GenericBound {
1252 pub(crate) fn sized(cx: &mut DocContext<'_>) -> GenericBound {
1253 Self::sized_with(cx, hir::TraitBoundModifiers::NONE)
1254 }
1255
1256 pub(crate) fn maybe_sized(cx: &mut DocContext<'_>) -> GenericBound {
1257 Self::sized_with(
1258 cx,
1259 hir::TraitBoundModifiers {
1260 polarity: hir::BoundPolarity::Maybe(DUMMY_SP),
1261 constness: hir::BoundConstness::Never,
1262 },
1263 )
1264 }
1265
1266 fn sized_with(cx: &mut DocContext<'_>, modifiers: hir::TraitBoundModifiers) -> GenericBound {
1267 let did = cx.tcx.require_lang_item(LangItem::Sized, DUMMY_SP);
1268 let empty = ty::Binder::dummy(ty::GenericArgs::empty());
1269 let path = clean_middle_path(cx, did, false, ThinVec::new(), empty);
1270 inline::record_extern_fqn(cx, did, ItemType::Trait);
1271 GenericBound::TraitBound(PolyTrait { trait_: path, generic_params: Vec::new() }, modifiers)
1272 }
1273
1274 pub(crate) fn is_trait_bound(&self) -> bool {
1275 matches!(self, Self::TraitBound(..))
1276 }
1277
1278 pub(crate) fn is_sized_bound(&self, cx: &DocContext<'_>) -> bool {
1279 self.is_bounded_by_lang_item(cx, LangItem::Sized)
1280 }
1281
1282 pub(crate) fn is_meta_sized_bound(&self, cx: &DocContext<'_>) -> bool {
1283 self.is_bounded_by_lang_item(cx, LangItem::MetaSized)
1284 }
1285
1286 fn is_bounded_by_lang_item(&self, cx: &DocContext<'_>, lang_item: LangItem) -> bool {
1287 if let GenericBound::TraitBound(
1288 PolyTrait { ref trait_, .. },
1289 rustc_hir::TraitBoundModifiers::NONE,
1290 ) = *self
1291 && cx.tcx.is_lang_item(trait_.def_id(), lang_item)
1292 {
1293 return true;
1294 }
1295 false
1296 }
1297
1298 pub(crate) fn get_trait_path(&self) -> Option<Path> {
1299 if let GenericBound::TraitBound(PolyTrait { ref trait_, .. }, _) = *self {
1300 Some(trait_.clone())
1301 } else {
1302 None
1303 }
1304 }
1305}
1306
1307#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
1308pub(crate) struct Lifetime(pub Symbol);
1309
1310impl Lifetime {
1311 pub(crate) fn statik() -> Lifetime {
1312 Lifetime(kw::StaticLifetime)
1313 }
1314
1315 pub(crate) fn elided() -> Lifetime {
1316 Lifetime(kw::UnderscoreLifetime)
1317 }
1318}
1319
1320#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
1321pub(crate) enum PreciseCapturingArg {
1322 Lifetime(Lifetime),
1323 Param(Symbol),
1324}
1325
1326impl PreciseCapturingArg {
1327 pub(crate) fn name(self) -> Symbol {
1328 match self {
1329 PreciseCapturingArg::Lifetime(lt) => lt.0,
1330 PreciseCapturingArg::Param(param) => param,
1331 }
1332 }
1333}
1334
1335#[derive(Clone, PartialEq, Eq, Hash, Debug)]
1336pub(crate) enum WherePredicate {
1337 BoundPredicate { ty: Type, bounds: Vec<GenericBound>, bound_params: Vec<GenericParamDef> },
1338 RegionPredicate { lifetime: Lifetime, bounds: Vec<GenericBound> },
1339 EqPredicate { lhs: QPathData, rhs: Term },
1340}
1341
1342impl WherePredicate {
1343 pub(crate) fn get_bounds(&self) -> Option<&[GenericBound]> {
1344 match self {
1345 WherePredicate::BoundPredicate { bounds, .. } => Some(bounds),
1346 WherePredicate::RegionPredicate { bounds, .. } => Some(bounds),
1347 _ => None,
1348 }
1349 }
1350}
1351
1352#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1353pub(crate) enum GenericParamDefKind {
1354 Lifetime { outlives: ThinVec<Lifetime> },
1355 Type { bounds: ThinVec<GenericBound>, default: Option<Box<Type>>, synthetic: bool },
1356 Const { ty: Box<Type>, default: Option<Box<String>>, synthetic: bool },
1358}
1359
1360impl GenericParamDefKind {
1361 pub(crate) fn is_type(&self) -> bool {
1362 matches!(self, GenericParamDefKind::Type { .. })
1363 }
1364}
1365
1366#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1367pub(crate) struct GenericParamDef {
1368 pub(crate) name: Symbol,
1369 pub(crate) def_id: DefId,
1370 pub(crate) kind: GenericParamDefKind,
1371}
1372
1373impl GenericParamDef {
1374 pub(crate) fn lifetime(def_id: DefId, name: Symbol) -> Self {
1375 Self { name, def_id, kind: GenericParamDefKind::Lifetime { outlives: ThinVec::new() } }
1376 }
1377
1378 pub(crate) fn is_synthetic_param(&self) -> bool {
1379 match self.kind {
1380 GenericParamDefKind::Lifetime { .. } | GenericParamDefKind::Const { .. } => false,
1381 GenericParamDefKind::Type { synthetic, .. } => synthetic,
1382 }
1383 }
1384
1385 pub(crate) fn is_type(&self) -> bool {
1386 self.kind.is_type()
1387 }
1388
1389 pub(crate) fn get_bounds(&self) -> Option<&[GenericBound]> {
1390 match self.kind {
1391 GenericParamDefKind::Type { ref bounds, .. } => Some(bounds),
1392 _ => None,
1393 }
1394 }
1395}
1396
1397#[derive(Clone, PartialEq, Eq, Hash, Debug, Default)]
1399pub(crate) struct Generics {
1400 pub(crate) params: ThinVec<GenericParamDef>,
1401 pub(crate) where_predicates: ThinVec<WherePredicate>,
1402}
1403
1404impl Generics {
1405 pub(crate) fn is_empty(&self) -> bool {
1406 self.params.is_empty() && self.where_predicates.is_empty()
1407 }
1408}
1409
1410#[derive(Clone, Debug)]
1411pub(crate) struct Function {
1412 pub(crate) decl: FnDecl,
1413 pub(crate) generics: Generics,
1414}
1415
1416#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1417pub(crate) struct FnDecl {
1418 pub(crate) inputs: Vec<Parameter>,
1419 pub(crate) output: Type,
1420 pub(crate) c_variadic: bool,
1421}
1422
1423impl FnDecl {
1424 pub(crate) fn receiver_type(&self) -> Option<&Type> {
1425 self.inputs.first().and_then(|v| v.to_receiver())
1426 }
1427}
1428
1429#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1431pub(crate) struct Parameter {
1432 pub(crate) name: Option<Symbol>,
1433 pub(crate) type_: Type,
1434 pub(crate) is_const: bool,
1437}
1438
1439impl Parameter {
1440 pub(crate) fn to_receiver(&self) -> Option<&Type> {
1441 if self.name == Some(kw::SelfLower) { Some(&self.type_) } else { None }
1442 }
1443}
1444
1445#[derive(Clone, Debug)]
1446pub(crate) struct Trait {
1447 pub(crate) def_id: DefId,
1448 pub(crate) items: Vec<Item>,
1449 pub(crate) generics: Generics,
1450 pub(crate) bounds: Vec<GenericBound>,
1451}
1452
1453impl Trait {
1454 pub(crate) fn is_auto(&self, tcx: TyCtxt<'_>) -> bool {
1455 tcx.trait_is_auto(self.def_id)
1456 }
1457 pub(crate) fn is_notable_trait(&self, tcx: TyCtxt<'_>) -> bool {
1458 tcx.is_doc_notable_trait(self.def_id)
1459 }
1460 pub(crate) fn safety(&self, tcx: TyCtxt<'_>) -> hir::Safety {
1461 tcx.trait_def(self.def_id).safety
1462 }
1463 pub(crate) fn is_dyn_compatible(&self, tcx: TyCtxt<'_>) -> bool {
1464 tcx.is_dyn_compatible(self.def_id)
1465 }
1466}
1467
1468#[derive(Clone, Debug)]
1469pub(crate) struct TraitAlias {
1470 pub(crate) generics: Generics,
1471 pub(crate) bounds: Vec<GenericBound>,
1472}
1473
1474#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1476pub(crate) struct PolyTrait {
1477 pub(crate) trait_: Path,
1478 pub(crate) generic_params: Vec<GenericParamDef>,
1479}
1480
1481#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1483pub(crate) enum Type {
1484 Path {
1489 path: Path,
1490 },
1491 DynTrait(Vec<PolyTrait>, Option<Lifetime>),
1493 Generic(Symbol),
1495 SelfTy,
1497 Primitive(PrimitiveType),
1499 BareFunction(Box<BareFunctionDecl>),
1501 Tuple(Vec<Type>),
1503 Slice(Box<Type>),
1505 Array(Box<Type>, Box<str>),
1509 Pat(Box<Type>, Box<str>),
1510 RawPointer(Mutability, Box<Type>),
1512 BorrowedRef {
1514 lifetime: Option<Lifetime>,
1515 mutability: Mutability,
1516 type_: Box<Type>,
1517 },
1518
1519 QPath(Box<QPathData>),
1521
1522 Infer,
1524
1525 ImplTrait(Vec<GenericBound>),
1527
1528 UnsafeBinder(Box<UnsafeBinderTy>),
1529}
1530
1531impl Type {
1532 pub(crate) fn without_borrowed_ref(&self) -> &Type {
1534 let mut result = self;
1535 while let Type::BorrowedRef { type_, .. } = result {
1536 result = type_;
1537 }
1538 result
1539 }
1540
1541 pub(crate) fn is_borrowed_ref(&self) -> bool {
1542 matches!(self, Type::BorrowedRef { .. })
1543 }
1544
1545 fn is_type_alias(&self) -> bool {
1546 matches!(self, Type::Path { path: Path { res: Res::Def(DefKind::TyAlias, _), .. } })
1547 }
1548
1549 pub(crate) fn is_doc_subtype_of(&self, other: &Self, cache: &Cache) -> bool {
1570 let (self_cleared, other_cleared) = if !self.is_borrowed_ref() || !other.is_borrowed_ref() {
1573 (self.without_borrowed_ref(), other.without_borrowed_ref())
1574 } else {
1575 (self, other)
1576 };
1577
1578 if self_cleared.is_type_alias() || other_cleared.is_type_alias() {
1584 return true;
1585 }
1586
1587 match (self_cleared, other_cleared) {
1588 (Type::Tuple(a), Type::Tuple(b)) => {
1590 a.len() == b.len() && a.iter().zip(b).all(|(a, b)| a.is_doc_subtype_of(b, cache))
1591 }
1592 (Type::Slice(a), Type::Slice(b)) => a.is_doc_subtype_of(b, cache),
1593 (Type::Array(a, al), Type::Array(b, bl)) => al == bl && a.is_doc_subtype_of(b, cache),
1594 (Type::RawPointer(mutability, type_), Type::RawPointer(b_mutability, b_type_)) => {
1595 mutability == b_mutability && type_.is_doc_subtype_of(b_type_, cache)
1596 }
1597 (
1598 Type::BorrowedRef { mutability, type_, .. },
1599 Type::BorrowedRef { mutability: b_mutability, type_: b_type_, .. },
1600 ) => mutability == b_mutability && type_.is_doc_subtype_of(b_type_, cache),
1601 (Type::Infer, _) | (_, Type::Infer) => true,
1603 (_, Type::Generic(_)) => true,
1606 (Type::Generic(_), _) => false,
1607 (Type::SelfTy, Type::SelfTy) => true,
1609 (Type::Path { path: a }, Type::Path { path: b }) => {
1611 a.def_id() == b.def_id()
1612 && a.generics()
1613 .zip(b.generics())
1614 .map(|(ag, bg)| ag.zip(bg).all(|(at, bt)| at.is_doc_subtype_of(bt, cache)))
1615 .unwrap_or(true)
1616 }
1617 (a, b) => a
1619 .def_id(cache)
1620 .and_then(|a| Some((a, b.def_id(cache)?)))
1621 .map(|(a, b)| a == b)
1622 .unwrap_or(false),
1623 }
1624 }
1625
1626 pub(crate) fn primitive_type(&self) -> Option<PrimitiveType> {
1627 match *self {
1628 Primitive(p) | BorrowedRef { type_: box Primitive(p), .. } => Some(p),
1629 Slice(..) | BorrowedRef { type_: box Slice(..), .. } => Some(PrimitiveType::Slice),
1630 Array(..) | BorrowedRef { type_: box Array(..), .. } => Some(PrimitiveType::Array),
1631 Tuple(ref tys) => {
1632 if tys.is_empty() {
1633 Some(PrimitiveType::Unit)
1634 } else {
1635 Some(PrimitiveType::Tuple)
1636 }
1637 }
1638 RawPointer(..) => Some(PrimitiveType::RawPointer),
1639 BareFunction(..) => Some(PrimitiveType::Fn),
1640 _ => None,
1641 }
1642 }
1643
1644 pub(crate) fn sugared_async_return_type(self) -> Type {
1654 if let Type::ImplTrait(mut v) = self
1655 && let Some(GenericBound::TraitBound(PolyTrait { mut trait_, .. }, _)) = v.pop()
1656 && let Some(segment) = trait_.segments.pop()
1657 && let GenericArgs::AngleBracketed { mut constraints, .. } = segment.args
1658 && let Some(constraint) = constraints.pop()
1659 && let AssocItemConstraintKind::Equality { term } = constraint.kind
1660 && let Term::Type(ty) = term
1661 {
1662 ty
1663 } else {
1664 panic!("unexpected async fn return type")
1665 }
1666 }
1667
1668 pub(crate) fn is_assoc_ty(&self) -> bool {
1670 match self {
1671 Type::Path { path, .. } => path.is_assoc_ty(),
1672 _ => false,
1673 }
1674 }
1675
1676 pub(crate) fn is_self_type(&self) -> bool {
1677 matches!(*self, Type::SelfTy)
1678 }
1679
1680 pub(crate) fn generic_args(&self) -> Option<&GenericArgs> {
1681 match self {
1682 Type::Path { path, .. } => path.generic_args(),
1683 _ => None,
1684 }
1685 }
1686
1687 pub(crate) fn generics<'a>(&'a self) -> Option<impl Iterator<Item = &'a Type>> {
1688 match self {
1689 Type::Path { path, .. } => path.generics(),
1690 _ => None,
1691 }
1692 }
1693
1694 pub(crate) fn is_full_generic(&self) -> bool {
1695 matches!(self, Type::Generic(_))
1696 }
1697
1698 pub(crate) fn is_unit(&self) -> bool {
1699 matches!(self, Type::Tuple(v) if v.is_empty())
1700 }
1701
1702 pub(crate) fn def_id(&self, cache: &Cache) -> Option<DefId> {
1706 let t: PrimitiveType = match self {
1707 Type::Path { path } => return Some(path.def_id()),
1708 DynTrait(bounds, _) => return bounds.first().map(|b| b.trait_.def_id()),
1709 Primitive(p) => return cache.primitive_locations.get(p).cloned(),
1710 BorrowedRef { type_: box Generic(..), .. } => PrimitiveType::Reference,
1711 BorrowedRef { type_, .. } => return type_.def_id(cache),
1712 Tuple(tys) => {
1713 if tys.is_empty() {
1714 PrimitiveType::Unit
1715 } else {
1716 PrimitiveType::Tuple
1717 }
1718 }
1719 BareFunction(..) => PrimitiveType::Fn,
1720 Slice(..) => PrimitiveType::Slice,
1721 Array(..) => PrimitiveType::Array,
1722 Type::Pat(..) => PrimitiveType::Pat,
1723 RawPointer(..) => PrimitiveType::RawPointer,
1724 QPath(box QPathData { self_type, .. }) => return self_type.def_id(cache),
1725 Generic(_) | SelfTy | Infer | ImplTrait(_) | UnsafeBinder(_) => return None,
1726 };
1727 Primitive(t).def_id(cache)
1728 }
1729}
1730
1731#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1732pub(crate) struct QPathData {
1733 pub assoc: PathSegment,
1734 pub self_type: Type,
1735 pub should_fully_qualify: bool,
1737 pub trait_: Option<Path>,
1738}
1739
1740#[derive(Clone, PartialEq, Eq, Hash, Copy, Debug)]
1747pub(crate) enum PrimitiveType {
1748 Isize,
1749 I8,
1750 I16,
1751 I32,
1752 I64,
1753 I128,
1754 Usize,
1755 U8,
1756 U16,
1757 U32,
1758 U64,
1759 U128,
1760 F16,
1761 F32,
1762 F64,
1763 F128,
1764 Char,
1765 Bool,
1766 Str,
1767 Slice,
1768 Array,
1769 Pat,
1770 Tuple,
1771 Unit,
1772 RawPointer,
1773 Reference,
1774 Fn,
1775 Never,
1776}
1777
1778type SimplifiedTypes = FxIndexMap<PrimitiveType, ArrayVec<SimplifiedType, 3>>;
1779impl PrimitiveType {
1780 pub(crate) fn from_hir(prim: hir::PrimTy) -> PrimitiveType {
1781 use ast::{FloatTy, IntTy, UintTy};
1782 match prim {
1783 hir::PrimTy::Int(IntTy::Isize) => PrimitiveType::Isize,
1784 hir::PrimTy::Int(IntTy::I8) => PrimitiveType::I8,
1785 hir::PrimTy::Int(IntTy::I16) => PrimitiveType::I16,
1786 hir::PrimTy::Int(IntTy::I32) => PrimitiveType::I32,
1787 hir::PrimTy::Int(IntTy::I64) => PrimitiveType::I64,
1788 hir::PrimTy::Int(IntTy::I128) => PrimitiveType::I128,
1789 hir::PrimTy::Uint(UintTy::Usize) => PrimitiveType::Usize,
1790 hir::PrimTy::Uint(UintTy::U8) => PrimitiveType::U8,
1791 hir::PrimTy::Uint(UintTy::U16) => PrimitiveType::U16,
1792 hir::PrimTy::Uint(UintTy::U32) => PrimitiveType::U32,
1793 hir::PrimTy::Uint(UintTy::U64) => PrimitiveType::U64,
1794 hir::PrimTy::Uint(UintTy::U128) => PrimitiveType::U128,
1795 hir::PrimTy::Float(FloatTy::F16) => PrimitiveType::F16,
1796 hir::PrimTy::Float(FloatTy::F32) => PrimitiveType::F32,
1797 hir::PrimTy::Float(FloatTy::F64) => PrimitiveType::F64,
1798 hir::PrimTy::Float(FloatTy::F128) => PrimitiveType::F128,
1799 hir::PrimTy::Str => PrimitiveType::Str,
1800 hir::PrimTy::Bool => PrimitiveType::Bool,
1801 hir::PrimTy::Char => PrimitiveType::Char,
1802 }
1803 }
1804
1805 pub(crate) fn from_symbol(s: Symbol) -> Option<PrimitiveType> {
1806 match s {
1807 sym::isize => Some(PrimitiveType::Isize),
1808 sym::i8 => Some(PrimitiveType::I8),
1809 sym::i16 => Some(PrimitiveType::I16),
1810 sym::i32 => Some(PrimitiveType::I32),
1811 sym::i64 => Some(PrimitiveType::I64),
1812 sym::i128 => Some(PrimitiveType::I128),
1813 sym::usize => Some(PrimitiveType::Usize),
1814 sym::u8 => Some(PrimitiveType::U8),
1815 sym::u16 => Some(PrimitiveType::U16),
1816 sym::u32 => Some(PrimitiveType::U32),
1817 sym::u64 => Some(PrimitiveType::U64),
1818 sym::u128 => Some(PrimitiveType::U128),
1819 sym::bool => Some(PrimitiveType::Bool),
1820 sym::char => Some(PrimitiveType::Char),
1821 sym::str => Some(PrimitiveType::Str),
1822 sym::f16 => Some(PrimitiveType::F16),
1823 sym::f32 => Some(PrimitiveType::F32),
1824 sym::f64 => Some(PrimitiveType::F64),
1825 sym::f128 => Some(PrimitiveType::F128),
1826 sym::array => Some(PrimitiveType::Array),
1827 sym::slice => Some(PrimitiveType::Slice),
1828 sym::tuple => Some(PrimitiveType::Tuple),
1829 sym::unit => Some(PrimitiveType::Unit),
1830 sym::pointer => Some(PrimitiveType::RawPointer),
1831 sym::reference => Some(PrimitiveType::Reference),
1832 kw::Fn => Some(PrimitiveType::Fn),
1833 sym::never => Some(PrimitiveType::Never),
1834 _ => None,
1835 }
1836 }
1837
1838 pub(crate) fn simplified_types() -> &'static SimplifiedTypes {
1839 use PrimitiveType::*;
1840 use ty::{FloatTy, IntTy, UintTy};
1841 static CELL: OnceCell<SimplifiedTypes> = OnceCell::new();
1842
1843 let single = |x| iter::once(x).collect();
1844 CELL.get_or_init(move || {
1845 map! {
1846 Isize => single(SimplifiedType::Int(IntTy::Isize)),
1847 I8 => single(SimplifiedType::Int(IntTy::I8)),
1848 I16 => single(SimplifiedType::Int(IntTy::I16)),
1849 I32 => single(SimplifiedType::Int(IntTy::I32)),
1850 I64 => single(SimplifiedType::Int(IntTy::I64)),
1851 I128 => single(SimplifiedType::Int(IntTy::I128)),
1852 Usize => single(SimplifiedType::Uint(UintTy::Usize)),
1853 U8 => single(SimplifiedType::Uint(UintTy::U8)),
1854 U16 => single(SimplifiedType::Uint(UintTy::U16)),
1855 U32 => single(SimplifiedType::Uint(UintTy::U32)),
1856 U64 => single(SimplifiedType::Uint(UintTy::U64)),
1857 U128 => single(SimplifiedType::Uint(UintTy::U128)),
1858 F16 => single(SimplifiedType::Float(FloatTy::F16)),
1859 F32 => single(SimplifiedType::Float(FloatTy::F32)),
1860 F64 => single(SimplifiedType::Float(FloatTy::F64)),
1861 F128 => single(SimplifiedType::Float(FloatTy::F128)),
1862 Str => single(SimplifiedType::Str),
1863 Bool => single(SimplifiedType::Bool),
1864 Char => single(SimplifiedType::Char),
1865 Array => single(SimplifiedType::Array),
1866 Slice => single(SimplifiedType::Slice),
1867 Tuple => [SimplifiedType::Tuple(1), SimplifiedType::Tuple(2), SimplifiedType::Tuple(3)].into(),
1873 Unit => single(SimplifiedType::Tuple(0)),
1874 RawPointer => [SimplifiedType::Ptr(Mutability::Not), SimplifiedType::Ptr(Mutability::Mut)].into_iter().collect(),
1875 Reference => [SimplifiedType::Ref(Mutability::Not), SimplifiedType::Ref(Mutability::Mut)].into_iter().collect(),
1876 Fn => single(SimplifiedType::Function(1)),
1879 Never => single(SimplifiedType::Never),
1880 }
1881 })
1882 }
1883
1884 pub(crate) fn impls<'tcx>(&self, tcx: TyCtxt<'tcx>) -> impl Iterator<Item = DefId> + 'tcx {
1885 Self::simplified_types()
1886 .get(self)
1887 .into_iter()
1888 .flatten()
1889 .flat_map(move |&simp| tcx.incoherent_impls(simp).iter())
1890 .copied()
1891 }
1892
1893 pub(crate) fn all_impls(tcx: TyCtxt<'_>) -> impl Iterator<Item = DefId> {
1894 Self::simplified_types()
1895 .values()
1896 .flatten()
1897 .flat_map(move |&simp| tcx.incoherent_impls(simp).iter())
1898 .copied()
1899 }
1900
1901 pub(crate) fn as_sym(&self) -> Symbol {
1902 use PrimitiveType::*;
1903 match self {
1904 Isize => sym::isize,
1905 I8 => sym::i8,
1906 I16 => sym::i16,
1907 I32 => sym::i32,
1908 I64 => sym::i64,
1909 I128 => sym::i128,
1910 Usize => sym::usize,
1911 U8 => sym::u8,
1912 U16 => sym::u16,
1913 U32 => sym::u32,
1914 U64 => sym::u64,
1915 U128 => sym::u128,
1916 F16 => sym::f16,
1917 F32 => sym::f32,
1918 F64 => sym::f64,
1919 F128 => sym::f128,
1920 Str => sym::str,
1921 Bool => sym::bool,
1922 Char => sym::char,
1923 Array => sym::array,
1924 Pat => sym::pat,
1925 Slice => sym::slice,
1926 Tuple => sym::tuple,
1927 Unit => sym::unit,
1928 RawPointer => sym::pointer,
1929 Reference => sym::reference,
1930 Fn => kw::Fn,
1931 Never => sym::never,
1932 }
1933 }
1934
1935 pub(crate) fn primitive_locations(tcx: TyCtxt<'_>) -> &FxIndexMap<PrimitiveType, DefId> {
1947 static PRIMITIVE_LOCATIONS: OnceCell<FxIndexMap<PrimitiveType, DefId>> = OnceCell::new();
1948 PRIMITIVE_LOCATIONS.get_or_init(|| {
1949 let mut primitive_locations = FxIndexMap::default();
1950 for &crate_num in tcx.crates(()) {
1953 let e = ExternalCrate { crate_num };
1954 let crate_name = e.name(tcx);
1955 debug!(?crate_num, ?crate_name);
1956 for (def_id, prim) in e.primitives(tcx) {
1957 if crate_name == sym::core && primitive_locations.contains_key(&prim) {
1959 continue;
1960 }
1961 primitive_locations.insert(prim, def_id);
1962 }
1963 }
1964 let local_primitives = ExternalCrate { crate_num: LOCAL_CRATE }.primitives(tcx);
1965 for (def_id, prim) in local_primitives {
1966 primitive_locations.insert(prim, def_id);
1967 }
1968 primitive_locations
1969 })
1970 }
1971}
1972
1973impl From<ast::IntTy> for PrimitiveType {
1974 fn from(int_ty: ast::IntTy) -> PrimitiveType {
1975 match int_ty {
1976 ast::IntTy::Isize => PrimitiveType::Isize,
1977 ast::IntTy::I8 => PrimitiveType::I8,
1978 ast::IntTy::I16 => PrimitiveType::I16,
1979 ast::IntTy::I32 => PrimitiveType::I32,
1980 ast::IntTy::I64 => PrimitiveType::I64,
1981 ast::IntTy::I128 => PrimitiveType::I128,
1982 }
1983 }
1984}
1985
1986impl From<ast::UintTy> for PrimitiveType {
1987 fn from(uint_ty: ast::UintTy) -> PrimitiveType {
1988 match uint_ty {
1989 ast::UintTy::Usize => PrimitiveType::Usize,
1990 ast::UintTy::U8 => PrimitiveType::U8,
1991 ast::UintTy::U16 => PrimitiveType::U16,
1992 ast::UintTy::U32 => PrimitiveType::U32,
1993 ast::UintTy::U64 => PrimitiveType::U64,
1994 ast::UintTy::U128 => PrimitiveType::U128,
1995 }
1996 }
1997}
1998
1999impl From<ast::FloatTy> for PrimitiveType {
2000 fn from(float_ty: ast::FloatTy) -> PrimitiveType {
2001 match float_ty {
2002 ast::FloatTy::F16 => PrimitiveType::F16,
2003 ast::FloatTy::F32 => PrimitiveType::F32,
2004 ast::FloatTy::F64 => PrimitiveType::F64,
2005 ast::FloatTy::F128 => PrimitiveType::F128,
2006 }
2007 }
2008}
2009
2010impl From<ty::IntTy> for PrimitiveType {
2011 fn from(int_ty: ty::IntTy) -> PrimitiveType {
2012 match int_ty {
2013 ty::IntTy::Isize => PrimitiveType::Isize,
2014 ty::IntTy::I8 => PrimitiveType::I8,
2015 ty::IntTy::I16 => PrimitiveType::I16,
2016 ty::IntTy::I32 => PrimitiveType::I32,
2017 ty::IntTy::I64 => PrimitiveType::I64,
2018 ty::IntTy::I128 => PrimitiveType::I128,
2019 }
2020 }
2021}
2022
2023impl From<ty::UintTy> for PrimitiveType {
2024 fn from(uint_ty: ty::UintTy) -> PrimitiveType {
2025 match uint_ty {
2026 ty::UintTy::Usize => PrimitiveType::Usize,
2027 ty::UintTy::U8 => PrimitiveType::U8,
2028 ty::UintTy::U16 => PrimitiveType::U16,
2029 ty::UintTy::U32 => PrimitiveType::U32,
2030 ty::UintTy::U64 => PrimitiveType::U64,
2031 ty::UintTy::U128 => PrimitiveType::U128,
2032 }
2033 }
2034}
2035
2036impl From<ty::FloatTy> for PrimitiveType {
2037 fn from(float_ty: ty::FloatTy) -> PrimitiveType {
2038 match float_ty {
2039 ty::FloatTy::F16 => PrimitiveType::F16,
2040 ty::FloatTy::F32 => PrimitiveType::F32,
2041 ty::FloatTy::F64 => PrimitiveType::F64,
2042 ty::FloatTy::F128 => PrimitiveType::F128,
2043 }
2044 }
2045}
2046
2047impl From<hir::PrimTy> for PrimitiveType {
2048 fn from(prim_ty: hir::PrimTy) -> PrimitiveType {
2049 match prim_ty {
2050 hir::PrimTy::Int(int_ty) => int_ty.into(),
2051 hir::PrimTy::Uint(uint_ty) => uint_ty.into(),
2052 hir::PrimTy::Float(float_ty) => float_ty.into(),
2053 hir::PrimTy::Str => PrimitiveType::Str,
2054 hir::PrimTy::Bool => PrimitiveType::Bool,
2055 hir::PrimTy::Char => PrimitiveType::Char,
2056 }
2057 }
2058}
2059
2060#[derive(Clone, Debug)]
2061pub(crate) struct Struct {
2062 pub(crate) ctor_kind: Option<CtorKind>,
2063 pub(crate) generics: Generics,
2064 pub(crate) fields: ThinVec<Item>,
2065}
2066
2067impl Struct {
2068 pub(crate) fn has_stripped_entries(&self) -> bool {
2069 self.fields.iter().any(|f| f.is_stripped())
2070 }
2071}
2072
2073#[derive(Clone, Debug)]
2074pub(crate) struct Union {
2075 pub(crate) generics: Generics,
2076 pub(crate) fields: Vec<Item>,
2077}
2078
2079impl Union {
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)]
2089pub(crate) struct VariantStruct {
2090 pub(crate) fields: ThinVec<Item>,
2091}
2092
2093impl VariantStruct {
2094 pub(crate) fn has_stripped_entries(&self) -> bool {
2095 self.fields.iter().any(|f| f.is_stripped())
2096 }
2097}
2098
2099#[derive(Clone, Debug)]
2100pub(crate) struct Enum {
2101 pub(crate) variants: IndexVec<VariantIdx, Item>,
2102 pub(crate) generics: Generics,
2103}
2104
2105impl Enum {
2106 pub(crate) fn has_stripped_entries(&self) -> bool {
2107 self.variants.iter().any(|f| f.is_stripped())
2108 }
2109
2110 pub(crate) fn non_stripped_variants(&self) -> impl Iterator<Item = &Item> {
2111 self.variants.iter().filter(|v| !v.is_stripped())
2112 }
2113}
2114
2115#[derive(Clone, Debug)]
2116pub(crate) struct Variant {
2117 pub kind: VariantKind,
2118 pub discriminant: Option<Discriminant>,
2119}
2120
2121#[derive(Clone, Debug)]
2122pub(crate) enum VariantKind {
2123 CLike,
2124 Tuple(ThinVec<Item>),
2125 Struct(VariantStruct),
2126}
2127
2128impl Variant {
2129 pub(crate) fn has_stripped_entries(&self) -> Option<bool> {
2130 match &self.kind {
2131 VariantKind::Struct(struct_) => Some(struct_.has_stripped_entries()),
2132 VariantKind::CLike | VariantKind::Tuple(_) => None,
2133 }
2134 }
2135}
2136
2137#[derive(Clone, Debug)]
2138pub(crate) struct Discriminant {
2139 pub(super) expr: Option<BodyId>,
2142 pub(super) value: DefId,
2143}
2144
2145impl Discriminant {
2146 pub(crate) fn expr(&self, tcx: TyCtxt<'_>) -> Option<String> {
2149 self.expr
2150 .map(|body| rendered_const(tcx, tcx.hir_body(body), tcx.hir_body_owner_def_id(body)))
2151 }
2152 pub(crate) fn value(&self, tcx: TyCtxt<'_>, with_underscores: bool) -> String {
2153 print_evaluated_const(tcx, self.value, with_underscores, false).unwrap()
2154 }
2155}
2156
2157#[derive(Copy, Clone, Debug)]
2160pub(crate) struct Span(rustc_span::Span);
2161
2162impl Span {
2163 pub(crate) fn new(sp: rustc_span::Span) -> Self {
2168 Self(sp.source_callsite())
2169 }
2170
2171 pub(crate) fn inner(&self) -> rustc_span::Span {
2172 self.0
2173 }
2174
2175 pub(crate) fn filename(&self, sess: &Session) -> FileName {
2176 sess.source_map().span_to_filename(self.0)
2177 }
2178
2179 pub(crate) fn lo(&self, sess: &Session) -> Loc {
2180 sess.source_map().lookup_char_pos(self.0.lo())
2181 }
2182
2183 pub(crate) fn hi(&self, sess: &Session) -> Loc {
2184 sess.source_map().lookup_char_pos(self.0.hi())
2185 }
2186
2187 pub(crate) fn cnum(&self, sess: &Session) -> CrateNum {
2188 self.lo(sess).file.cnum
2190 }
2191}
2192
2193#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2194pub(crate) struct Path {
2195 pub(crate) res: Res,
2196 pub(crate) segments: ThinVec<PathSegment>,
2197}
2198
2199impl Path {
2200 pub(crate) fn def_id(&self) -> DefId {
2201 self.res.def_id()
2202 }
2203
2204 pub(crate) fn last_opt(&self) -> Option<Symbol> {
2205 self.segments.last().map(|s| s.name)
2206 }
2207
2208 pub(crate) fn last(&self) -> Symbol {
2209 self.last_opt().expect("segments were empty")
2210 }
2211
2212 pub(crate) fn whole_name(&self) -> String {
2213 self.segments
2214 .iter()
2215 .map(|s| if s.name == kw::PathRoot { "" } else { s.name.as_str() })
2216 .intersperse("::")
2217 .collect()
2218 }
2219
2220 pub(crate) fn is_assoc_ty(&self) -> bool {
2222 match self.res {
2223 Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } | Res::Def(DefKind::TyParam, _)
2224 if self.segments.len() != 1 =>
2225 {
2226 true
2227 }
2228 Res::Def(DefKind::AssocTy, _) => true,
2229 _ => false,
2230 }
2231 }
2232
2233 pub(crate) fn generic_args(&self) -> Option<&GenericArgs> {
2234 self.segments.last().map(|seg| &seg.args)
2235 }
2236
2237 pub(crate) fn generics<'a>(&'a self) -> Option<impl Iterator<Item = &'a Type>> {
2238 self.segments.last().and_then(|seg| {
2239 if let GenericArgs::AngleBracketed { ref args, .. } = seg.args {
2240 Some(args.iter().filter_map(|arg| match arg {
2241 GenericArg::Type(ty) => Some(ty),
2242 _ => None,
2243 }))
2244 } else {
2245 None
2246 }
2247 })
2248 }
2249}
2250
2251#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2252pub(crate) enum GenericArg {
2253 Lifetime(Lifetime),
2254 Type(Type),
2255 Const(Box<ConstantKind>),
2256 Infer,
2257}
2258
2259impl GenericArg {
2260 pub(crate) fn as_lt(&self) -> Option<&Lifetime> {
2261 if let Self::Lifetime(lt) = self { Some(lt) } else { None }
2262 }
2263
2264 pub(crate) fn as_ty(&self) -> Option<&Type> {
2265 if let Self::Type(ty) = self { Some(ty) } else { None }
2266 }
2267}
2268
2269#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2270pub(crate) enum GenericArgs {
2271 AngleBracketed { args: ThinVec<GenericArg>, constraints: ThinVec<AssocItemConstraint> },
2273 Parenthesized { inputs: ThinVec<Type>, output: Option<Box<Type>> },
2275 ReturnTypeNotation,
2277}
2278
2279impl GenericArgs {
2280 pub(crate) fn is_empty(&self) -> bool {
2281 match self {
2282 GenericArgs::AngleBracketed { args, constraints } => {
2283 args.is_empty() && constraints.is_empty()
2284 }
2285 GenericArgs::Parenthesized { inputs, output } => inputs.is_empty() && output.is_none(),
2286 GenericArgs::ReturnTypeNotation => false,
2287 }
2288 }
2289 pub(crate) fn constraints(&self) -> Box<dyn Iterator<Item = AssocItemConstraint> + '_> {
2290 match self {
2291 GenericArgs::AngleBracketed { constraints, .. } => {
2292 Box::new(constraints.iter().cloned())
2293 }
2294 GenericArgs::Parenthesized { output, .. } => Box::new(
2295 output
2296 .as_ref()
2297 .map(|ty| AssocItemConstraint {
2298 assoc: PathSegment {
2299 name: sym::Output,
2300 args: GenericArgs::AngleBracketed {
2301 args: ThinVec::new(),
2302 constraints: ThinVec::new(),
2303 },
2304 },
2305 kind: AssocItemConstraintKind::Equality {
2306 term: Term::Type((**ty).clone()),
2307 },
2308 })
2309 .into_iter(),
2310 ),
2311 GenericArgs::ReturnTypeNotation => Box::new([].into_iter()),
2312 }
2313 }
2314}
2315
2316impl<'a> IntoIterator for &'a GenericArgs {
2317 type IntoIter = Box<dyn Iterator<Item = GenericArg> + 'a>;
2318 type Item = GenericArg;
2319 fn into_iter(self) -> Self::IntoIter {
2320 match self {
2321 GenericArgs::AngleBracketed { args, .. } => Box::new(args.iter().cloned()),
2322 GenericArgs::Parenthesized { inputs, .. } => {
2323 Box::new(inputs.iter().cloned().map(GenericArg::Type))
2325 }
2326 GenericArgs::ReturnTypeNotation => Box::new([].into_iter()),
2327 }
2328 }
2329}
2330
2331#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2332pub(crate) struct PathSegment {
2333 pub(crate) name: Symbol,
2334 pub(crate) args: GenericArgs,
2335}
2336
2337#[derive(Clone, Debug)]
2338pub(crate) enum TypeAliasInnerType {
2339 Enum { variants: IndexVec<VariantIdx, Item>, is_non_exhaustive: bool },
2340 Union { fields: Vec<Item> },
2341 Struct { ctor_kind: Option<CtorKind>, fields: Vec<Item> },
2342}
2343
2344impl TypeAliasInnerType {
2345 fn has_stripped_entries(&self) -> Option<bool> {
2346 Some(match self {
2347 Self::Enum { variants, .. } => variants.iter().any(|v| v.is_stripped()),
2348 Self::Union { fields } | Self::Struct { fields, .. } => {
2349 fields.iter().any(|f| f.is_stripped())
2350 }
2351 })
2352 }
2353}
2354
2355#[derive(Clone, Debug)]
2356pub(crate) struct TypeAlias {
2357 pub(crate) type_: Type,
2358 pub(crate) generics: Generics,
2359 pub(crate) inner_type: Option<TypeAliasInnerType>,
2362 pub(crate) item_type: Option<Type>,
2369}
2370
2371#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2372pub(crate) struct BareFunctionDecl {
2373 pub(crate) safety: hir::Safety,
2374 pub(crate) generic_params: Vec<GenericParamDef>,
2375 pub(crate) decl: FnDecl,
2376 pub(crate) abi: ExternAbi,
2377}
2378
2379#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2380pub(crate) struct UnsafeBinderTy {
2381 pub(crate) generic_params: Vec<GenericParamDef>,
2382 pub(crate) ty: Type,
2383}
2384
2385#[derive(Clone, Debug)]
2386pub(crate) struct Static {
2387 pub(crate) type_: Box<Type>,
2388 pub(crate) mutability: Mutability,
2389 pub(crate) expr: Option<BodyId>,
2390}
2391
2392#[derive(Clone, PartialEq, Eq, Hash, Debug)]
2393pub(crate) struct Constant {
2394 pub(crate) generics: Generics,
2395 pub(crate) kind: ConstantKind,
2396 pub(crate) type_: Type,
2397}
2398
2399#[derive(Clone, PartialEq, Eq, Hash, Debug)]
2400pub(crate) enum Term {
2401 Type(Type),
2402 Constant(ConstantKind),
2403}
2404
2405impl Term {
2406 pub(crate) fn ty(&self) -> Option<&Type> {
2407 if let Term::Type(ty) = self { Some(ty) } else { None }
2408 }
2409}
2410
2411impl From<Type> for Term {
2412 fn from(ty: Type) -> Self {
2413 Term::Type(ty)
2414 }
2415}
2416
2417#[derive(Clone, PartialEq, Eq, Hash, Debug)]
2418pub(crate) enum ConstantKind {
2419 TyConst { expr: Box<str> },
2425 Path { path: Box<str> },
2428 Anonymous { body: BodyId },
2432 Extern { def_id: DefId },
2434 Local { def_id: DefId, body: BodyId },
2436 Infer,
2438}
2439
2440impl ConstantKind {
2441 pub(crate) fn expr(&self, tcx: TyCtxt<'_>) -> String {
2442 match *self {
2443 ConstantKind::TyConst { ref expr } => expr.to_string(),
2444 ConstantKind::Path { ref path } => path.to_string(),
2445 ConstantKind::Extern { def_id } => print_inlined_const(tcx, def_id),
2446 ConstantKind::Local { body, .. } | ConstantKind::Anonymous { body } => {
2447 rendered_const(tcx, tcx.hir_body(body), tcx.hir_body_owner_def_id(body))
2448 }
2449 ConstantKind::Infer => "_".to_string(),
2450 }
2451 }
2452
2453 pub(crate) fn value(&self, tcx: TyCtxt<'_>) -> Option<String> {
2454 match *self {
2455 ConstantKind::TyConst { .. }
2456 | ConstantKind::Path { .. }
2457 | ConstantKind::Anonymous { .. }
2458 | ConstantKind::Infer => None,
2459 ConstantKind::Extern { def_id } | ConstantKind::Local { def_id, .. } => {
2460 print_evaluated_const(tcx, def_id, true, true)
2461 }
2462 }
2463 }
2464
2465 pub(crate) fn is_literal(&self, tcx: TyCtxt<'_>) -> bool {
2466 match *self {
2467 ConstantKind::TyConst { .. }
2468 | ConstantKind::Extern { .. }
2469 | ConstantKind::Path { .. }
2470 | ConstantKind::Infer => false,
2471 ConstantKind::Local { body, .. } | ConstantKind::Anonymous { body } => {
2472 is_literal_expr(tcx, body.hir_id)
2473 }
2474 }
2475 }
2476}
2477
2478#[derive(Clone, Debug)]
2479pub(crate) struct Impl {
2480 pub(crate) safety: hir::Safety,
2481 pub(crate) generics: Generics,
2482 pub(crate) trait_: Option<Path>,
2483 pub(crate) for_: Type,
2484 pub(crate) items: Vec<Item>,
2485 pub(crate) polarity: ty::ImplPolarity,
2486 pub(crate) kind: ImplKind,
2487}
2488
2489impl Impl {
2490 pub(crate) fn provided_trait_methods(&self, tcx: TyCtxt<'_>) -> FxIndexSet<Symbol> {
2491 self.trait_
2492 .as_ref()
2493 .map(|t| t.def_id())
2494 .map(|did| tcx.provided_trait_methods(did).map(|meth| meth.name()).collect())
2495 .unwrap_or_default()
2496 }
2497
2498 pub(crate) fn is_negative_trait_impl(&self) -> bool {
2499 matches!(self.polarity, ty::ImplPolarity::Negative)
2500 }
2501}
2502
2503#[derive(Clone, Debug)]
2504pub(crate) enum ImplKind {
2505 Normal,
2506 Auto,
2507 FakeVariadic,
2508 Blanket(Box<Type>),
2509}
2510
2511impl ImplKind {
2512 pub(crate) fn is_auto(&self) -> bool {
2513 matches!(self, ImplKind::Auto)
2514 }
2515
2516 pub(crate) fn is_blanket(&self) -> bool {
2517 matches!(self, ImplKind::Blanket(_))
2518 }
2519
2520 pub(crate) fn is_fake_variadic(&self) -> bool {
2521 matches!(self, ImplKind::FakeVariadic)
2522 }
2523
2524 pub(crate) fn as_blanket_ty(&self) -> Option<&Type> {
2525 match self {
2526 ImplKind::Blanket(ty) => Some(ty),
2527 _ => None,
2528 }
2529 }
2530}
2531
2532#[derive(Clone, Debug)]
2533pub(crate) struct Import {
2534 pub(crate) kind: ImportKind,
2535 pub(crate) source: ImportSource,
2537 pub(crate) should_be_displayed: bool,
2538}
2539
2540impl Import {
2541 pub(crate) fn new_simple(
2542 name: Symbol,
2543 source: ImportSource,
2544 should_be_displayed: bool,
2545 ) -> Self {
2546 Self { kind: ImportKind::Simple(name), source, should_be_displayed }
2547 }
2548
2549 pub(crate) fn new_glob(source: ImportSource, should_be_displayed: bool) -> Self {
2550 Self { kind: ImportKind::Glob, source, should_be_displayed }
2551 }
2552
2553 pub(crate) fn imported_item_is_doc_hidden(&self, tcx: TyCtxt<'_>) -> bool {
2554 self.source.did.is_some_and(|did| tcx.is_doc_hidden(did))
2555 }
2556}
2557
2558#[derive(Clone, Debug)]
2559pub(crate) enum ImportKind {
2560 Simple(Symbol),
2562 Glob,
2564}
2565
2566#[derive(Clone, Debug)]
2567pub(crate) struct ImportSource {
2568 pub(crate) path: Path,
2569 pub(crate) did: Option<DefId>,
2570}
2571
2572#[derive(Clone, Debug)]
2573pub(crate) struct Macro {
2574 pub(crate) source: String,
2575 pub(crate) macro_rules: bool,
2577}
2578
2579#[derive(Clone, Debug)]
2580pub(crate) struct ProcMacro {
2581 pub(crate) kind: MacroKind,
2582 pub(crate) helpers: Vec<Symbol>,
2583}
2584
2585#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2596pub(crate) struct AssocItemConstraint {
2597 pub(crate) assoc: PathSegment,
2598 pub(crate) kind: AssocItemConstraintKind,
2599}
2600
2601#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2603pub(crate) enum AssocItemConstraintKind {
2604 Equality { term: Term },
2605 Bound { bounds: Vec<GenericBound> },
2606}
2607
2608#[cfg(target_pointer_width = "64")]
2610mod size_asserts {
2611 use rustc_data_structures::static_assert_size;
2612
2613 use super::*;
2614 static_assert_size!(Crate, 16); static_assert_size!(DocFragment, 32);
2617 static_assert_size!(GenericArg, 32);
2618 static_assert_size!(GenericArgs, 24);
2619 static_assert_size!(GenericParamDef, 40);
2620 static_assert_size!(Generics, 16);
2621 static_assert_size!(Item, 8);
2622 static_assert_size!(ItemInner, 144);
2623 static_assert_size!(ItemKind, 48);
2624 static_assert_size!(PathSegment, 32);
2625 static_assert_size!(Type, 32);
2626 }