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