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