1use std::hash::Hash;
2use std::path::PathBuf;
3use std::sync::{Arc, OnceLock as OnceCell};
4use std::{fmt, iter};
5
6use arrayvec::ArrayVec;
7use rustc_abi::{ExternAbi, VariantIdx};
8use rustc_attr_parsing::{AttributeKind, ConstStability, Deprecation, Stability, StableSince};
9use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
10use rustc_hir::def::{CtorKind, DefKind, Res};
11use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId};
12use rustc_hir::lang_items::LangItem;
13use rustc_hir::{BodyId, Mutability};
14use rustc_index::IndexVec;
15use rustc_metadata::rendered_const;
16use rustc_middle::span_bug;
17use rustc_middle::ty::fast_reject::SimplifiedType;
18use rustc_middle::ty::{self, TyCtxt, Visibility};
19use rustc_resolve::rustdoc::{
20 DocFragment, add_doc_fragment, attrs_to_doc_fragments, inner_docs, span_of_fragments,
21};
22use rustc_session::Session;
23use rustc_span::hygiene::MacroKind;
24use rustc_span::symbol::{Ident, Symbol, kw, sym};
25use rustc_span::{DUMMY_SP, FileName, Loc};
26use thin_vec::ThinVec;
27use tracing::{debug, trace};
28use {rustc_ast as ast, rustc_hir as hir};
29
30pub(crate) use self::ItemKind::*;
31pub(crate) use self::Type::{
32 Array, BareFunction, BorrowedRef, DynTrait, Generic, ImplTrait, Infer, Primitive, QPath,
33 RawPointer, SelfTy, Slice, Tuple, UnsafeBinder,
34};
35use crate::clean::cfg::Cfg;
36use crate::clean::clean_middle_path;
37use crate::clean::inline::{self, print_inlined_const};
38use crate::clean::utils::{is_literal_expr, print_evaluated_const};
39use crate::core::DocContext;
40use crate::formats::cache::Cache;
41use crate::formats::item_type::ItemType;
42use crate::html::render::Context;
43use crate::passes::collect_intra_doc_links::UrlFragment;
44
45#[cfg(test)]
46mod tests;
47
48pub(crate) type ItemIdSet = FxHashSet<ItemId>;
49
50#[derive(Debug, Clone, PartialEq, Eq, Hash, Copy)]
51pub(crate) enum ItemId {
52 DefId(DefId),
54 Auto { trait_: DefId, for_: DefId },
56 Blanket { impl_id: DefId, for_: DefId },
58}
59
60impl ItemId {
61 #[inline]
62 pub(crate) fn is_local(self) -> bool {
63 match self {
64 ItemId::Auto { for_: id, .. }
65 | ItemId::Blanket { for_: id, .. }
66 | ItemId::DefId(id) => id.is_local(),
67 }
68 }
69
70 #[inline]
71 #[track_caller]
72 pub(crate) fn expect_def_id(self) -> DefId {
73 self.as_def_id()
74 .unwrap_or_else(|| panic!("ItemId::expect_def_id: `{self:?}` isn't a DefId"))
75 }
76
77 #[inline]
78 pub(crate) fn as_def_id(self) -> Option<DefId> {
79 match self {
80 ItemId::DefId(id) => Some(id),
81 _ => None,
82 }
83 }
84
85 #[inline]
86 pub(crate) fn as_local_def_id(self) -> Option<LocalDefId> {
87 self.as_def_id().and_then(|id| id.as_local())
88 }
89
90 #[inline]
91 pub(crate) fn krate(self) -> CrateNum {
92 match self {
93 ItemId::Auto { for_: id, .. }
94 | ItemId::Blanket { for_: id, .. }
95 | ItemId::DefId(id) => id.krate,
96 }
97 }
98}
99
100impl From<DefId> for ItemId {
101 fn from(id: DefId) -> Self {
102 Self::DefId(id)
103 }
104}
105
106#[derive(Clone, Debug)]
108pub(crate) struct Crate {
109 pub(crate) module: Item,
110 pub(crate) external_traits: Box<FxIndexMap<DefId, Trait>>,
112}
113
114impl Crate {
115 pub(crate) fn name(&self, tcx: TyCtxt<'_>) -> Symbol {
116 ExternalCrate::LOCAL.name(tcx)
117 }
118
119 pub(crate) fn src(&self, tcx: TyCtxt<'_>) -> FileName {
120 ExternalCrate::LOCAL.src(tcx)
121 }
122}
123
124#[derive(Copy, Clone, Debug)]
125pub(crate) struct ExternalCrate {
126 pub(crate) crate_num: CrateNum,
127}
128
129impl ExternalCrate {
130 const LOCAL: Self = Self { crate_num: LOCAL_CRATE };
131
132 #[inline]
133 pub(crate) fn def_id(&self) -> DefId {
134 self.crate_num.as_def_id()
135 }
136
137 pub(crate) fn src(&self, tcx: TyCtxt<'_>) -> FileName {
138 let krate_span = tcx.def_span(self.def_id());
139 tcx.sess.source_map().span_to_filename(krate_span)
140 }
141
142 pub(crate) fn name(&self, tcx: TyCtxt<'_>) -> Symbol {
143 tcx.crate_name(self.crate_num)
144 }
145
146 pub(crate) fn src_root(&self, tcx: TyCtxt<'_>) -> PathBuf {
147 match self.src(tcx) {
148 FileName::Real(ref p) => match p.local_path_if_available().parent() {
149 Some(p) => p.to_path_buf(),
150 None => PathBuf::new(),
151 },
152 _ => PathBuf::new(),
153 }
154 }
155
156 pub(crate) fn location(
159 &self,
160 extern_url: Option<&str>,
161 extern_url_takes_precedence: bool,
162 dst: &std::path::Path,
163 tcx: TyCtxt<'_>,
164 ) -> ExternalLocation {
165 use ExternalLocation::*;
166
167 fn to_remote(url: impl ToString) -> ExternalLocation {
168 let mut url = url.to_string();
169 if !url.ends_with('/') {
170 url.push('/');
171 }
172 Remote(url)
173 }
174
175 let local_location = dst.join(self.name(tcx).as_str());
179 if local_location.is_dir() {
180 return Local;
181 }
182
183 if extern_url_takes_precedence && let Some(url) = extern_url {
184 return to_remote(url);
185 }
186
187 let did = self.crate_num.as_def_id();
190 tcx.get_attrs(did, sym::doc)
191 .flat_map(|attr| attr.meta_item_list().unwrap_or_default())
192 .filter(|a| a.has_name(sym::html_root_url))
193 .filter_map(|a| a.value_str())
194 .map(to_remote)
195 .next()
196 .or_else(|| extern_url.map(to_remote)) .unwrap_or(Unknown) }
199
200 pub(crate) fn keywords(&self, tcx: TyCtxt<'_>) -> ThinVec<(DefId, Symbol)> {
201 let root = self.def_id();
202
203 let as_keyword = |res: Res<!>| {
204 if let Res::Def(DefKind::Mod, def_id) = res {
205 let mut keyword = None;
206 let meta_items = tcx
207 .get_attrs(def_id, sym::doc)
208 .flat_map(|attr| attr.meta_item_list().unwrap_or_default());
209 for meta in meta_items {
210 if meta.has_name(sym::keyword)
211 && let Some(v) = meta.value_str()
212 {
213 keyword = Some(v);
214 break;
215 }
216 }
217 return keyword.map(|p| (def_id, p));
218 }
219 None
220 };
221 if root.is_local() {
222 tcx.hir_root_module()
223 .item_ids
224 .iter()
225 .filter_map(|&id| {
226 let item = tcx.hir_item(id);
227 match item.kind {
228 hir::ItemKind::Mod(..) => {
229 as_keyword(Res::Def(DefKind::Mod, id.owner_id.to_def_id()))
230 }
231 _ => None,
232 }
233 })
234 .collect()
235 } else {
236 tcx.module_children(root).iter().map(|item| item.res).filter_map(as_keyword).collect()
237 }
238 }
239
240 pub(crate) fn primitives(&self, tcx: TyCtxt<'_>) -> ThinVec<(DefId, PrimitiveType)> {
241 let root = self.def_id();
242
243 let as_primitive = |res: Res<!>| {
261 let Res::Def(DefKind::Mod, def_id) = res else { return None };
262 tcx.get_attrs(def_id, sym::rustc_doc_primitive)
263 .map(|attr| {
264 let attr_value = attr.value_str().expect("syntax should already be validated");
265 let Some(prim) = PrimitiveType::from_symbol(attr_value) else {
266 span_bug!(
267 attr.span(),
268 "primitive `{attr_value}` is not a member of `PrimitiveType`"
269 );
270 };
271
272 (def_id, prim)
273 })
274 .next()
275 };
276
277 if root.is_local() {
278 tcx.hir_root_module()
279 .item_ids
280 .iter()
281 .filter_map(|&id| {
282 let item = tcx.hir_item(id);
283 match item.kind {
284 hir::ItemKind::Mod(..) => {
285 as_primitive(Res::Def(DefKind::Mod, id.owner_id.to_def_id()))
286 }
287 _ => None,
288 }
289 })
290 .collect()
291 } else {
292 tcx.module_children(root).iter().map(|item| item.res).filter_map(as_primitive).collect()
293 }
294 }
295}
296
297#[derive(Debug)]
299pub(crate) enum ExternalLocation {
300 Remote(String),
302 Local,
304 Unknown,
306}
307
308#[derive(Clone)]
312pub(crate) struct Item {
313 pub(crate) inner: Box<ItemInner>,
314}
315
316#[derive(Clone)]
322pub(crate) struct ItemInner {
323 pub(crate) name: Option<Symbol>,
326 pub(crate) kind: ItemKind,
329 pub(crate) attrs: Attributes,
330 pub(crate) stability: Option<Stability>,
332 pub(crate) item_id: ItemId,
333 pub(crate) inline_stmt_id: Option<LocalDefId>,
337 pub(crate) cfg: Option<Arc<Cfg>>,
338}
339
340impl std::ops::Deref for Item {
341 type Target = ItemInner;
342 fn deref(&self) -> &ItemInner {
343 &self.inner
344 }
345}
346
347impl fmt::Debug for Item {
350 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
351 let alternate = f.alternate();
352 let mut fmt = f.debug_struct("Item");
354 fmt.field("name", &self.name).field("item_id", &self.item_id);
355 if alternate {
357 fmt.field("attrs", &self.attrs).field("kind", &self.kind).field("cfg", &self.cfg);
358 } else {
359 fmt.field("kind", &self.type_());
360 fmt.field("docs", &self.doc_value());
361 }
362 fmt.finish()
363 }
364}
365
366pub(crate) fn rustc_span(def_id: DefId, tcx: TyCtxt<'_>) -> Span {
367 Span::new(def_id.as_local().map_or_else(
368 || tcx.def_span(def_id),
369 |local| tcx.hir_span_with_body(tcx.local_def_id_to_hir_id(local)),
370 ))
371}
372
373fn is_field_vis_inherited(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
374 let parent = tcx.parent(def_id);
375 match tcx.def_kind(parent) {
376 DefKind::Struct | DefKind::Union => false,
377 DefKind::Variant => true,
378 parent_kind => panic!("unexpected parent kind: {parent_kind:?}"),
379 }
380}
381
382impl Item {
383 pub(crate) fn stability(&self, tcx: TyCtxt<'_>) -> Option<Stability> {
387 let stability = self.inner.stability;
388 debug_assert!(
389 stability.is_some()
390 || self.def_id().is_none_or(|did| tcx.lookup_stability(did).is_none()),
391 "missing stability for cleaned item: {self:?}",
392 );
393 stability
394 }
395
396 pub(crate) fn const_stability(&self, tcx: TyCtxt<'_>) -> Option<ConstStability> {
397 self.def_id().and_then(|did| tcx.lookup_const_stability(did))
398 }
399
400 pub(crate) fn deprecation(&self, tcx: TyCtxt<'_>) -> Option<Deprecation> {
401 self.def_id().and_then(|did| tcx.lookup_deprecation(did)).or_else(|| {
402 let stab = self.stability(tcx)?;
406 if let rustc_attr_parsing::StabilityLevel::Stable {
407 allowed_through_unstable_modules: Some(note),
408 ..
409 } = stab.level
410 {
411 Some(Deprecation {
412 since: rustc_attr_parsing::DeprecatedSince::Unspecified,
413 note: Some(note),
414 suggestion: None,
415 })
416 } else {
417 None
418 }
419 })
420 }
421
422 pub(crate) fn inner_docs(&self, tcx: TyCtxt<'_>) -> bool {
423 self.item_id
424 .as_def_id()
425 .map(|did| inner_docs(tcx.get_attrs_unchecked(did)))
426 .unwrap_or(false)
427 }
428
429 pub(crate) fn span(&self, tcx: TyCtxt<'_>) -> Option<Span> {
430 let kind = match &self.kind {
431 ItemKind::StrippedItem(k) => k,
432 _ => &self.kind,
433 };
434 match kind {
435 ItemKind::ModuleItem(Module { span, .. }) => Some(*span),
436 ItemKind::ImplItem(box Impl { kind: ImplKind::Auto, .. }) => None,
437 ItemKind::ImplItem(box Impl { kind: ImplKind::Blanket(_), .. }) => {
438 if let ItemId::Blanket { impl_id, .. } = self.item_id {
439 Some(rustc_span(impl_id, tcx))
440 } else {
441 panic!("blanket impl item has non-blanket ID")
442 }
443 }
444 _ => self.def_id().map(|did| rustc_span(did, tcx)),
445 }
446 }
447
448 pub(crate) fn attr_span(&self, tcx: TyCtxt<'_>) -> rustc_span::Span {
449 span_of_fragments(&self.attrs.doc_strings)
450 .unwrap_or_else(|| self.span(tcx).map_or(DUMMY_SP, |span| span.inner()))
451 }
452
453 pub(crate) fn doc_value(&self) -> String {
455 self.attrs.doc_value()
456 }
457
458 pub(crate) fn opt_doc_value(&self) -> Option<String> {
462 self.attrs.opt_doc_value()
463 }
464
465 pub(crate) fn from_def_id_and_parts(
466 def_id: DefId,
467 name: Option<Symbol>,
468 kind: ItemKind,
469 cx: &mut DocContext<'_>,
470 ) -> Item {
471 let hir_attrs = cx.tcx.get_attrs_unchecked(def_id);
472
473 Self::from_def_id_and_attrs_and_parts(
474 def_id,
475 name,
476 kind,
477 Attributes::from_hir(hir_attrs),
478 extract_cfg_from_attrs(hir_attrs.iter(), cx.tcx, &cx.cache.hidden_cfg),
479 )
480 }
481
482 pub(crate) fn from_def_id_and_attrs_and_parts(
483 def_id: DefId,
484 name: Option<Symbol>,
485 kind: ItemKind,
486 attrs: Attributes,
487 cfg: Option<Arc<Cfg>>,
488 ) -> Item {
489 trace!("name={name:?}, def_id={def_id:?} cfg={cfg:?}");
490
491 Item {
492 inner: Box::new(ItemInner {
493 item_id: def_id.into(),
494 kind,
495 attrs,
496 stability: None,
497 name,
498 cfg,
499 inline_stmt_id: None,
500 }),
501 }
502 }
503
504 pub(crate) fn links(&self, cx: &Context<'_>) -> Vec<RenderedLink> {
505 use crate::html::format::{href, link_tooltip};
506
507 let Some(links) = cx.cache().intra_doc_links.get(&self.item_id) else { return vec![] };
508 links
509 .iter()
510 .filter_map(|ItemLink { link: s, link_text, page_id: id, fragment }| {
511 debug!(?id);
512 if let Ok((mut href, ..)) = href(*id, cx) {
513 debug!(?href);
514 if let Some(ref fragment) = *fragment {
515 fragment.render(&mut href, cx.tcx())
516 }
517 Some(RenderedLink {
518 original_text: s.clone(),
519 new_text: link_text.clone(),
520 tooltip: link_tooltip(*id, fragment, cx).to_string(),
521 href,
522 })
523 } else {
524 None
525 }
526 })
527 .collect()
528 }
529
530 pub(crate) fn link_names(&self, cache: &Cache) -> Vec<RenderedLink> {
536 let Some(links) = cache.intra_doc_links.get(&self.item_id) else {
537 return vec![];
538 };
539 links
540 .iter()
541 .map(|ItemLink { link: s, link_text, .. }| RenderedLink {
542 original_text: s.clone(),
543 new_text: link_text.clone(),
544 href: String::new(),
545 tooltip: String::new(),
546 })
547 .collect()
548 }
549
550 pub(crate) fn is_crate(&self) -> bool {
551 self.is_mod() && self.def_id().is_some_and(|did| did.is_crate_root())
552 }
553 pub(crate) fn is_mod(&self) -> bool {
554 self.type_() == ItemType::Module
555 }
556 pub(crate) fn is_struct(&self) -> bool {
557 self.type_() == ItemType::Struct
558 }
559 pub(crate) fn is_enum(&self) -> bool {
560 self.type_() == ItemType::Enum
561 }
562 pub(crate) fn is_variant(&self) -> bool {
563 self.type_() == ItemType::Variant
564 }
565 pub(crate) fn is_associated_type(&self) -> bool {
566 matches!(self.kind, AssocTypeItem(..) | StrippedItem(box AssocTypeItem(..)))
567 }
568 pub(crate) fn is_required_associated_type(&self) -> bool {
569 matches!(self.kind, RequiredAssocTypeItem(..) | StrippedItem(box RequiredAssocTypeItem(..)))
570 }
571 pub(crate) fn is_associated_const(&self) -> bool {
572 matches!(self.kind, ProvidedAssocConstItem(..) | ImplAssocConstItem(..) | StrippedItem(box (ProvidedAssocConstItem(..) | ImplAssocConstItem(..))))
573 }
574 pub(crate) fn is_required_associated_const(&self) -> bool {
575 matches!(self.kind, RequiredAssocConstItem(..) | StrippedItem(box RequiredAssocConstItem(..)))
576 }
577 pub(crate) fn is_method(&self) -> bool {
578 self.type_() == ItemType::Method
579 }
580 pub(crate) fn is_ty_method(&self) -> bool {
581 self.type_() == ItemType::TyMethod
582 }
583 pub(crate) fn is_primitive(&self) -> bool {
584 self.type_() == ItemType::Primitive
585 }
586 pub(crate) fn is_union(&self) -> bool {
587 self.type_() == ItemType::Union
588 }
589 pub(crate) fn is_import(&self) -> bool {
590 self.type_() == ItemType::Import
591 }
592 pub(crate) fn is_extern_crate(&self) -> bool {
593 self.type_() == ItemType::ExternCrate
594 }
595 pub(crate) fn is_keyword(&self) -> bool {
596 self.type_() == ItemType::Keyword
597 }
598 pub(crate) fn is_stripped(&self) -> bool {
599 match self.kind {
600 StrippedItem(..) => true,
601 ImportItem(ref i) => !i.should_be_displayed,
602 _ => false,
603 }
604 }
605 pub(crate) fn has_stripped_entries(&self) -> Option<bool> {
606 match self.kind {
607 StructItem(ref struct_) => Some(struct_.has_stripped_entries()),
608 UnionItem(ref union_) => Some(union_.has_stripped_entries()),
609 EnumItem(ref enum_) => Some(enum_.has_stripped_entries()),
610 VariantItem(ref v) => v.has_stripped_entries(),
611 _ => None,
612 }
613 }
614
615 pub(crate) fn stability_class(&self, tcx: TyCtxt<'_>) -> Option<String> {
616 self.stability(tcx).as_ref().and_then(|s| {
617 let mut classes = Vec::with_capacity(2);
618
619 if s.is_unstable() {
620 classes.push("unstable");
621 }
622
623 if self.deprecation(tcx).is_some() {
625 classes.push("deprecated");
626 }
627
628 if !classes.is_empty() { Some(classes.join(" ")) } else { None }
629 })
630 }
631
632 pub(crate) fn stable_since(&self, tcx: TyCtxt<'_>) -> Option<StableSince> {
633 self.stability(tcx).and_then(|stability| stability.stable_since())
634 }
635
636 pub(crate) fn is_non_exhaustive(&self) -> bool {
637 self.attrs.other_attrs.iter().any(|a| a.has_name(sym::non_exhaustive))
638 }
639
640 pub(crate) fn type_(&self) -> ItemType {
642 ItemType::from(self)
643 }
644
645 pub(crate) fn is_default(&self) -> bool {
646 match self.kind {
647 ItemKind::MethodItem(_, Some(defaultness)) => {
648 defaultness.has_value() && !defaultness.is_final()
649 }
650 _ => false,
651 }
652 }
653
654 pub(crate) fn fn_header(&self, tcx: TyCtxt<'_>) -> Option<hir::FnHeader> {
656 fn build_fn_header(
657 def_id: DefId,
658 tcx: TyCtxt<'_>,
659 asyncness: ty::Asyncness,
660 ) -> hir::FnHeader {
661 let sig = tcx.fn_sig(def_id).skip_binder();
662 let constness = if tcx.is_const_fn(def_id) {
663 hir::Constness::Const
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 pub(crate) fn attributes(&self, tcx: TyCtxt<'_>, cache: &Cache, is_json: bool) -> Vec<String> {
763 const ALLOWED_ATTRIBUTES: &[Symbol] =
764 &[sym::export_name, sym::link_section, sym::no_mangle, sym::non_exhaustive];
765
766 use rustc_abi::IntegerType;
767
768 let mut attrs: Vec<String> = self
769 .attrs
770 .other_attrs
771 .iter()
772 .filter_map(|attr| {
773 if is_json {
774 match attr {
775 hir::Attribute::Parsed(AttributeKind::Deprecation { .. }) => {
776 None
779 }
780 rustc_hir::Attribute::Parsed(rustc_attr_parsing::AttributeKind::Repr(
781 ..,
782 )) => {
783 None
788 }
789 _ => Some({
790 let mut s = rustc_hir_pretty::attribute_to_string(&tcx, attr);
791 assert_eq!(s.pop(), Some('\n'));
792 s
793 }),
794 }
795 } else if attr.has_any_name(ALLOWED_ATTRIBUTES) {
796 Some(
797 rustc_hir_pretty::attribute_to_string(&tcx, attr)
798 .replace("\\\n", "")
799 .replace('\n', "")
800 .replace(" ", " "),
801 )
802 } else {
803 None
804 }
805 })
806 .collect();
807
808 if let Some(def_id) = self.def_id()
810 && let ItemType::Struct | ItemType::Enum | ItemType::Union = self.type_()
811 {
812 let adt = tcx.adt_def(def_id);
813 let repr = adt.repr();
814 let mut out = Vec::new();
815 if repr.c() {
816 out.push("C");
817 }
818 if repr.transparent() {
819 let render_transparent = cache.document_private
822 || adt
823 .all_fields()
824 .find(|field| {
825 let ty =
826 field.ty(tcx, ty::GenericArgs::identity_for_item(tcx, field.did));
827 tcx.layout_of(
828 ty::TypingEnv::post_analysis(tcx, field.did).as_query_input(ty),
829 )
830 .is_ok_and(|layout| !layout.is_1zst())
831 })
832 .map_or_else(
833 || adt.all_fields().any(|field| field.vis.is_public()),
834 |field| field.vis.is_public(),
835 );
836
837 if render_transparent {
838 out.push("transparent");
839 }
840 }
841 if repr.simd() {
842 out.push("simd");
843 }
844 let pack_s;
845 if let Some(pack) = repr.pack {
846 pack_s = format!("packed({})", pack.bytes());
847 out.push(&pack_s);
848 }
849 let align_s;
850 if let Some(align) = repr.align {
851 align_s = format!("align({})", align.bytes());
852 out.push(&align_s);
853 }
854 let int_s;
855 if let Some(int) = repr.int {
856 int_s = match int {
857 IntegerType::Pointer(is_signed) => {
858 format!("{}size", if is_signed { 'i' } else { 'u' })
859 }
860 IntegerType::Fixed(size, is_signed) => {
861 format!("{}{}", if is_signed { 'i' } else { 'u' }, size.size().bytes() * 8)
862 }
863 };
864 out.push(&int_s);
865 }
866 if !out.is_empty() {
867 attrs.push(format!("#[repr({})]", out.join(", ")));
868 }
869 }
870 attrs
871 }
872
873 pub fn is_doc_hidden(&self) -> bool {
874 self.attrs.is_doc_hidden()
875 }
876
877 pub fn def_id(&self) -> Option<DefId> {
878 self.item_id.as_def_id()
879 }
880}
881
882#[derive(Clone, Debug)]
883pub(crate) enum ItemKind {
884 ExternCrateItem {
885 src: Option<Symbol>,
887 },
888 ImportItem(Import),
889 StructItem(Struct),
890 UnionItem(Union),
891 EnumItem(Enum),
892 FunctionItem(Box<Function>),
893 ModuleItem(Module),
894 TypeAliasItem(Box<TypeAlias>),
895 StaticItem(Static),
896 TraitItem(Box<Trait>),
897 TraitAliasItem(TraitAlias),
898 ImplItem(Box<Impl>),
899 RequiredMethodItem(Box<Function>),
901 MethodItem(Box<Function>, Option<hir::Defaultness>),
905 StructFieldItem(Type),
906 VariantItem(Variant),
907 ForeignFunctionItem(Box<Function>, hir::Safety),
909 ForeignStaticItem(Static, hir::Safety),
911 ForeignTypeItem,
913 MacroItem(Macro),
914 ProcMacroItem(ProcMacro),
915 PrimitiveItem(PrimitiveType),
916 RequiredAssocConstItem(Generics, Box<Type>),
918 ConstantItem(Box<Constant>),
919 ProvidedAssocConstItem(Box<Constant>),
921 ImplAssocConstItem(Box<Constant>),
923 RequiredAssocTypeItem(Generics, Vec<GenericBound>),
927 AssocTypeItem(Box<TypeAlias>, Vec<GenericBound>),
929 StrippedItem(Box<ItemKind>),
931 KeywordItem,
932}
933
934impl ItemKind {
935 pub(crate) fn inner_items(&self) -> impl Iterator<Item = &Item> {
938 match self {
939 StructItem(s) => s.fields.iter(),
940 UnionItem(u) => u.fields.iter(),
941 VariantItem(v) => match &v.kind {
942 VariantKind::CLike => [].iter(),
943 VariantKind::Tuple(t) => t.iter(),
944 VariantKind::Struct(s) => s.fields.iter(),
945 },
946 EnumItem(e) => e.variants.iter(),
947 TraitItem(t) => t.items.iter(),
948 ImplItem(i) => i.items.iter(),
949 ModuleItem(m) => m.items.iter(),
950 ExternCrateItem { .. }
951 | ImportItem(_)
952 | FunctionItem(_)
953 | TypeAliasItem(_)
954 | StaticItem(_)
955 | ConstantItem(_)
956 | TraitAliasItem(_)
957 | RequiredMethodItem(_)
958 | MethodItem(_, _)
959 | StructFieldItem(_)
960 | ForeignFunctionItem(_, _)
961 | ForeignStaticItem(_, _)
962 | ForeignTypeItem
963 | MacroItem(_)
964 | ProcMacroItem(_)
965 | PrimitiveItem(_)
966 | RequiredAssocConstItem(..)
967 | ProvidedAssocConstItem(..)
968 | ImplAssocConstItem(..)
969 | RequiredAssocTypeItem(..)
970 | AssocTypeItem(..)
971 | StrippedItem(_)
972 | KeywordItem => [].iter(),
973 }
974 }
975
976 pub(crate) fn is_non_assoc(&self) -> bool {
978 matches!(
979 self,
980 StructItem(_)
981 | UnionItem(_)
982 | EnumItem(_)
983 | TraitItem(_)
984 | ModuleItem(_)
985 | ExternCrateItem { .. }
986 | FunctionItem(_)
987 | TypeAliasItem(_)
988 | StaticItem(_)
989 | ConstantItem(_)
990 | TraitAliasItem(_)
991 | ForeignFunctionItem(_, _)
992 | ForeignStaticItem(_, _)
993 | ForeignTypeItem
994 | MacroItem(_)
995 | ProcMacroItem(_)
996 | PrimitiveItem(_)
997 )
998 }
999}
1000
1001#[derive(Clone, Debug)]
1002pub(crate) struct Module {
1003 pub(crate) items: Vec<Item>,
1004 pub(crate) span: Span,
1005}
1006
1007pub(crate) fn hir_attr_lists<'a, I: IntoIterator<Item = &'a hir::Attribute>>(
1008 attrs: I,
1009 name: Symbol,
1010) -> impl Iterator<Item = ast::MetaItemInner> + use<'a, I> {
1011 attrs
1012 .into_iter()
1013 .filter(move |attr| attr.has_name(name))
1014 .filter_map(ast::attr::AttributeExt::meta_item_list)
1015 .flatten()
1016}
1017
1018pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator<Item = &'a hir::Attribute> + Clone>(
1019 attrs: I,
1020 tcx: TyCtxt<'_>,
1021 hidden_cfg: &FxHashSet<Cfg>,
1022) -> Option<Arc<Cfg>> {
1023 let doc_cfg_active = tcx.features().doc_cfg();
1024 let doc_auto_cfg_active = tcx.features().doc_auto_cfg();
1025
1026 fn single<T: IntoIterator>(it: T) -> Option<T::Item> {
1027 let mut iter = it.into_iter();
1028 let item = iter.next()?;
1029 if iter.next().is_some() {
1030 return None;
1031 }
1032 Some(item)
1033 }
1034
1035 let mut cfg = if doc_cfg_active || doc_auto_cfg_active {
1036 let mut doc_cfg = attrs
1037 .clone()
1038 .filter(|attr| attr.has_name(sym::doc))
1039 .flat_map(|attr| attr.meta_item_list().unwrap_or_default())
1040 .filter(|attr| attr.has_name(sym::cfg))
1041 .peekable();
1042 if doc_cfg.peek().is_some() && doc_cfg_active {
1043 let sess = tcx.sess;
1044 doc_cfg.fold(Cfg::True, |mut cfg, item| {
1045 if let Some(cfg_mi) =
1046 item.meta_item().and_then(|item| rustc_expand::config::parse_cfg(item, sess))
1047 {
1048 rustc_attr_parsing::cfg_matches(
1050 cfg_mi,
1051 tcx.sess,
1052 rustc_ast::CRATE_NODE_ID,
1053 Some(tcx.features()),
1054 );
1055 match Cfg::parse(cfg_mi) {
1056 Ok(new_cfg) => cfg &= new_cfg,
1057 Err(e) => {
1058 sess.dcx().span_err(e.span, e.msg);
1059 }
1060 }
1061 }
1062 cfg
1063 })
1064 } else if doc_auto_cfg_active {
1065 attrs
1068 .clone()
1069 .filter(|attr| attr.has_name(sym::cfg_trace))
1070 .filter_map(|attr| single(attr.meta_item_list()?))
1071 .filter_map(|attr| Cfg::parse_without(attr.meta_item()?, hidden_cfg).ok().flatten())
1072 .fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg)
1073 } else {
1074 Cfg::True
1075 }
1076 } else {
1077 Cfg::True
1078 };
1079
1080 for attr in hir_attr_lists(attrs, sym::target_feature) {
1083 if attr.has_name(sym::enable) && attr.value_str().is_some() {
1084 let mut meta = attr.meta_item().unwrap().clone();
1087 meta.path = ast::Path::from_ident(Ident::with_dummy_span(sym::target_feature));
1088
1089 if let Ok(feat_cfg) = Cfg::parse(&ast::MetaItemInner::MetaItem(meta)) {
1090 cfg &= feat_cfg;
1091 }
1092 }
1093 }
1094
1095 if cfg == Cfg::True { None } else { Some(Arc::new(cfg)) }
1096}
1097
1098pub(crate) trait NestedAttributesExt {
1099 fn has_word(self, word: Symbol) -> bool
1101 where
1102 Self: Sized,
1103 {
1104 <Self as NestedAttributesExt>::get_word_attr(self, word).is_some()
1105 }
1106
1107 fn get_word_attr(self, word: Symbol) -> Option<ast::MetaItemInner>;
1110}
1111
1112impl<I: Iterator<Item = ast::MetaItemInner>> NestedAttributesExt for I {
1113 fn get_word_attr(mut self, word: Symbol) -> Option<ast::MetaItemInner> {
1114 self.find(|attr| attr.is_word() && attr.has_name(word))
1115 }
1116}
1117
1118#[derive(Clone, Debug, PartialEq, Eq, Hash)]
1122pub(crate) struct ItemLink {
1123 pub(crate) link: Box<str>,
1125 pub(crate) link_text: Box<str>,
1130 pub(crate) page_id: DefId,
1134 pub(crate) fragment: Option<UrlFragment>,
1136}
1137
1138pub struct RenderedLink {
1139 pub(crate) original_text: Box<str>,
1143 pub(crate) new_text: Box<str>,
1145 pub(crate) href: String,
1147 pub(crate) tooltip: String,
1149}
1150
1151#[derive(Clone, Debug, Default)]
1154pub(crate) struct Attributes {
1155 pub(crate) doc_strings: Vec<DocFragment>,
1156 pub(crate) other_attrs: ThinVec<hir::Attribute>,
1157}
1158
1159impl Attributes {
1160 pub(crate) fn lists(&self, name: Symbol) -> impl Iterator<Item = ast::MetaItemInner> {
1161 hir_attr_lists(&self.other_attrs[..], name)
1162 }
1163
1164 pub(crate) fn has_doc_flag(&self, flag: Symbol) -> bool {
1165 for attr in &self.other_attrs {
1166 if !attr.has_name(sym::doc) {
1167 continue;
1168 }
1169
1170 if let Some(items) = attr.meta_item_list()
1171 && items.iter().filter_map(|i| i.meta_item()).any(|it| it.has_name(flag))
1172 {
1173 return true;
1174 }
1175 }
1176
1177 false
1178 }
1179
1180 pub(crate) fn is_doc_hidden(&self) -> bool {
1181 self.has_doc_flag(sym::hidden)
1182 }
1183
1184 pub(crate) fn from_hir(attrs: &[hir::Attribute]) -> Attributes {
1185 Attributes::from_hir_iter(attrs.iter().map(|attr| (attr, None)), false)
1186 }
1187
1188 pub(crate) fn from_hir_with_additional(
1189 attrs: &[hir::Attribute],
1190 (additional_attrs, def_id): (&[hir::Attribute], DefId),
1191 ) -> Attributes {
1192 let attrs1 = additional_attrs.iter().map(|attr| (attr, Some(def_id)));
1194 let attrs2 = attrs.iter().map(|attr| (attr, None));
1195 Attributes::from_hir_iter(attrs1.chain(attrs2), false)
1196 }
1197
1198 pub(crate) fn from_hir_iter<'a>(
1199 attrs: impl Iterator<Item = (&'a hir::Attribute, Option<DefId>)>,
1200 doc_only: bool,
1201 ) -> Attributes {
1202 let (doc_strings, other_attrs) = attrs_to_doc_fragments(attrs, doc_only);
1203 Attributes { doc_strings, other_attrs }
1204 }
1205
1206 pub(crate) fn doc_value(&self) -> String {
1208 self.opt_doc_value().unwrap_or_default()
1209 }
1210
1211 pub(crate) fn opt_doc_value(&self) -> Option<String> {
1215 (!self.doc_strings.is_empty()).then(|| {
1216 let mut res = String::new();
1217 for frag in &self.doc_strings {
1218 add_doc_fragment(&mut res, frag);
1219 }
1220 res.pop();
1221 res
1222 })
1223 }
1224
1225 pub(crate) fn get_doc_aliases(&self) -> Box<[Symbol]> {
1226 let mut aliases = FxIndexSet::default();
1227
1228 for attr in
1229 hir_attr_lists(&self.other_attrs[..], sym::doc).filter(|a| a.has_name(sym::alias))
1230 {
1231 if let Some(values) = attr.meta_item_list() {
1232 for l in values {
1233 if let Some(lit) = l.lit()
1234 && let ast::LitKind::Str(s, _) = lit.kind
1235 {
1236 aliases.insert(s);
1237 }
1238 }
1239 } else if let Some(value) = attr.value_str() {
1240 aliases.insert(value);
1241 }
1242 }
1243 aliases.into_iter().collect::<Vec<_>>().into()
1244 }
1245}
1246
1247#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1248pub(crate) enum GenericBound {
1249 TraitBound(PolyTrait, hir::TraitBoundModifiers),
1250 Outlives(Lifetime),
1251 Use(Vec<PreciseCapturingArg>),
1253}
1254
1255impl GenericBound {
1256 pub(crate) fn sized(cx: &mut DocContext<'_>) -> GenericBound {
1257 Self::sized_with(cx, hir::TraitBoundModifiers::NONE)
1258 }
1259
1260 pub(crate) fn maybe_sized(cx: &mut DocContext<'_>) -> GenericBound {
1261 Self::sized_with(
1262 cx,
1263 hir::TraitBoundModifiers {
1264 polarity: hir::BoundPolarity::Maybe(DUMMY_SP),
1265 constness: hir::BoundConstness::Never,
1266 },
1267 )
1268 }
1269
1270 fn sized_with(cx: &mut DocContext<'_>, modifiers: hir::TraitBoundModifiers) -> GenericBound {
1271 let did = cx.tcx.require_lang_item(LangItem::Sized, None);
1272 let empty = ty::Binder::dummy(ty::GenericArgs::empty());
1273 let path = clean_middle_path(cx, did, false, ThinVec::new(), empty);
1274 inline::record_extern_fqn(cx, did, ItemType::Trait);
1275 GenericBound::TraitBound(PolyTrait { trait_: path, generic_params: Vec::new() }, modifiers)
1276 }
1277
1278 pub(crate) fn is_trait_bound(&self) -> bool {
1279 matches!(self, Self::TraitBound(..))
1280 }
1281
1282 pub(crate) fn is_sized_bound(&self, cx: &DocContext<'_>) -> bool {
1283 if let GenericBound::TraitBound(
1284 PolyTrait { ref trait_, .. },
1285 rustc_hir::TraitBoundModifiers::NONE,
1286 ) = *self
1287 && Some(trait_.def_id()) == cx.tcx.lang_items().sized_trait()
1288 {
1289 return true;
1290 }
1291 false
1292 }
1293
1294 pub(crate) fn get_trait_path(&self) -> Option<Path> {
1295 if let GenericBound::TraitBound(PolyTrait { ref trait_, .. }, _) = *self {
1296 Some(trait_.clone())
1297 } else {
1298 None
1299 }
1300 }
1301}
1302
1303#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
1304pub(crate) struct Lifetime(pub Symbol);
1305
1306impl Lifetime {
1307 pub(crate) fn statik() -> Lifetime {
1308 Lifetime(kw::StaticLifetime)
1309 }
1310
1311 pub(crate) fn elided() -> Lifetime {
1312 Lifetime(kw::UnderscoreLifetime)
1313 }
1314}
1315
1316#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
1317pub(crate) enum PreciseCapturingArg {
1318 Lifetime(Lifetime),
1319 Param(Symbol),
1320}
1321
1322impl PreciseCapturingArg {
1323 pub(crate) fn name(self) -> Symbol {
1324 match self {
1325 PreciseCapturingArg::Lifetime(lt) => lt.0,
1326 PreciseCapturingArg::Param(param) => param,
1327 }
1328 }
1329}
1330
1331#[derive(Clone, PartialEq, Eq, Hash, Debug)]
1332pub(crate) enum WherePredicate {
1333 BoundPredicate { ty: Type, bounds: Vec<GenericBound>, bound_params: Vec<GenericParamDef> },
1334 RegionPredicate { lifetime: Lifetime, bounds: Vec<GenericBound> },
1335 EqPredicate { lhs: Type, rhs: Term },
1336}
1337
1338impl WherePredicate {
1339 pub(crate) fn get_bounds(&self) -> Option<&[GenericBound]> {
1340 match *self {
1341 WherePredicate::BoundPredicate { ref bounds, .. } => Some(bounds),
1342 WherePredicate::RegionPredicate { ref bounds, .. } => Some(bounds),
1343 _ => None,
1344 }
1345 }
1346}
1347
1348#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1349pub(crate) enum GenericParamDefKind {
1350 Lifetime { outlives: ThinVec<Lifetime> },
1351 Type { bounds: ThinVec<GenericBound>, default: Option<Box<Type>>, synthetic: bool },
1352 Const { ty: Box<Type>, default: Option<Box<String>>, synthetic: bool },
1354}
1355
1356impl GenericParamDefKind {
1357 pub(crate) fn is_type(&self) -> bool {
1358 matches!(self, GenericParamDefKind::Type { .. })
1359 }
1360}
1361
1362#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1363pub(crate) struct GenericParamDef {
1364 pub(crate) name: Symbol,
1365 pub(crate) def_id: DefId,
1366 pub(crate) kind: GenericParamDefKind,
1367}
1368
1369impl GenericParamDef {
1370 pub(crate) fn lifetime(def_id: DefId, name: Symbol) -> Self {
1371 Self { name, def_id, kind: GenericParamDefKind::Lifetime { outlives: ThinVec::new() } }
1372 }
1373
1374 pub(crate) fn is_synthetic_param(&self) -> bool {
1375 match self.kind {
1376 GenericParamDefKind::Lifetime { .. } | GenericParamDefKind::Const { .. } => false,
1377 GenericParamDefKind::Type { synthetic, .. } => synthetic,
1378 }
1379 }
1380
1381 pub(crate) fn is_type(&self) -> bool {
1382 self.kind.is_type()
1383 }
1384
1385 pub(crate) fn get_bounds(&self) -> Option<&[GenericBound]> {
1386 match self.kind {
1387 GenericParamDefKind::Type { ref bounds, .. } => Some(bounds),
1388 _ => None,
1389 }
1390 }
1391}
1392
1393#[derive(Clone, PartialEq, Eq, Hash, Debug, Default)]
1395pub(crate) struct Generics {
1396 pub(crate) params: ThinVec<GenericParamDef>,
1397 pub(crate) where_predicates: ThinVec<WherePredicate>,
1398}
1399
1400impl Generics {
1401 pub(crate) fn is_empty(&self) -> bool {
1402 self.params.is_empty() && self.where_predicates.is_empty()
1403 }
1404}
1405
1406#[derive(Clone, Debug)]
1407pub(crate) struct Function {
1408 pub(crate) decl: FnDecl,
1409 pub(crate) generics: Generics,
1410}
1411
1412#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1413pub(crate) struct FnDecl {
1414 pub(crate) inputs: Vec<Parameter>,
1415 pub(crate) output: Type,
1416 pub(crate) c_variadic: bool,
1417}
1418
1419impl FnDecl {
1420 pub(crate) fn receiver_type(&self) -> Option<&Type> {
1421 self.inputs.first().and_then(|v| v.to_receiver())
1422 }
1423}
1424
1425#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1427pub(crate) struct Parameter {
1428 pub(crate) name: Option<Symbol>,
1429 pub(crate) type_: Type,
1430 pub(crate) is_const: bool,
1433}
1434
1435impl Parameter {
1436 pub(crate) fn to_receiver(&self) -> Option<&Type> {
1437 if self.name == Some(kw::SelfLower) { Some(&self.type_) } else { None }
1438 }
1439}
1440
1441#[derive(Clone, Debug)]
1442pub(crate) struct Trait {
1443 pub(crate) def_id: DefId,
1444 pub(crate) items: Vec<Item>,
1445 pub(crate) generics: Generics,
1446 pub(crate) bounds: Vec<GenericBound>,
1447}
1448
1449impl Trait {
1450 pub(crate) fn is_auto(&self, tcx: TyCtxt<'_>) -> bool {
1451 tcx.trait_is_auto(self.def_id)
1452 }
1453 pub(crate) fn is_notable_trait(&self, tcx: TyCtxt<'_>) -> bool {
1454 tcx.is_doc_notable_trait(self.def_id)
1455 }
1456 pub(crate) fn safety(&self, tcx: TyCtxt<'_>) -> hir::Safety {
1457 tcx.trait_def(self.def_id).safety
1458 }
1459 pub(crate) fn is_dyn_compatible(&self, tcx: TyCtxt<'_>) -> bool {
1460 tcx.is_dyn_compatible(self.def_id)
1461 }
1462}
1463
1464#[derive(Clone, Debug)]
1465pub(crate) struct TraitAlias {
1466 pub(crate) generics: Generics,
1467 pub(crate) bounds: Vec<GenericBound>,
1468}
1469
1470#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1472pub(crate) struct PolyTrait {
1473 pub(crate) trait_: Path,
1474 pub(crate) generic_params: Vec<GenericParamDef>,
1475}
1476
1477#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1479pub(crate) enum Type {
1480 Path {
1485 path: Path,
1486 },
1487 DynTrait(Vec<PolyTrait>, Option<Lifetime>),
1489 Generic(Symbol),
1491 SelfTy,
1493 Primitive(PrimitiveType),
1495 BareFunction(Box<BareFunctionDecl>),
1497 Tuple(Vec<Type>),
1499 Slice(Box<Type>),
1501 Array(Box<Type>, Box<str>),
1505 Pat(Box<Type>, Box<str>),
1506 RawPointer(Mutability, Box<Type>),
1508 BorrowedRef {
1510 lifetime: Option<Lifetime>,
1511 mutability: Mutability,
1512 type_: Box<Type>,
1513 },
1514
1515 QPath(Box<QPathData>),
1517
1518 Infer,
1520
1521 ImplTrait(Vec<GenericBound>),
1523
1524 UnsafeBinder(Box<UnsafeBinderTy>),
1525}
1526
1527impl Type {
1528 pub(crate) fn without_borrowed_ref(&self) -> &Type {
1530 let mut result = self;
1531 while let Type::BorrowedRef { type_, .. } = result {
1532 result = type_;
1533 }
1534 result
1535 }
1536
1537 pub(crate) fn is_borrowed_ref(&self) -> bool {
1538 matches!(self, Type::BorrowedRef { .. })
1539 }
1540
1541 fn is_type_alias(&self) -> bool {
1542 matches!(self, Type::Path { path: Path { res: Res::Def(DefKind::TyAlias, _), .. } })
1543 }
1544
1545 pub(crate) fn is_doc_subtype_of(&self, other: &Self, cache: &Cache) -> bool {
1566 let (self_cleared, other_cleared) = if !self.is_borrowed_ref() || !other.is_borrowed_ref() {
1569 (self.without_borrowed_ref(), other.without_borrowed_ref())
1570 } else {
1571 (self, other)
1572 };
1573
1574 if self_cleared.is_type_alias() || other_cleared.is_type_alias() {
1580 return true;
1581 }
1582
1583 match (self_cleared, other_cleared) {
1584 (Type::Tuple(a), Type::Tuple(b)) => {
1586 a.len() == b.len() && a.iter().zip(b).all(|(a, b)| a.is_doc_subtype_of(b, cache))
1587 }
1588 (Type::Slice(a), Type::Slice(b)) => a.is_doc_subtype_of(b, cache),
1589 (Type::Array(a, al), Type::Array(b, bl)) => al == bl && a.is_doc_subtype_of(b, cache),
1590 (Type::RawPointer(mutability, type_), Type::RawPointer(b_mutability, b_type_)) => {
1591 mutability == b_mutability && type_.is_doc_subtype_of(b_type_, cache)
1592 }
1593 (
1594 Type::BorrowedRef { mutability, type_, .. },
1595 Type::BorrowedRef { mutability: b_mutability, type_: b_type_, .. },
1596 ) => mutability == b_mutability && type_.is_doc_subtype_of(b_type_, cache),
1597 (Type::Infer, _) | (_, Type::Infer) => true,
1599 (_, Type::Generic(_)) => true,
1602 (Type::Generic(_), _) => false,
1603 (Type::SelfTy, Type::SelfTy) => true,
1605 (Type::Path { path: a }, Type::Path { path: b }) => {
1607 a.def_id() == b.def_id()
1608 && a.generics()
1609 .zip(b.generics())
1610 .map(|(ag, bg)| {
1611 ag.iter().zip(bg.iter()).all(|(at, bt)| at.is_doc_subtype_of(bt, cache))
1612 })
1613 .unwrap_or(true)
1614 }
1615 (a, b) => a
1617 .def_id(cache)
1618 .and_then(|a| Some((a, b.def_id(cache)?)))
1619 .map(|(a, b)| a == b)
1620 .unwrap_or(false),
1621 }
1622 }
1623
1624 pub(crate) fn primitive_type(&self) -> Option<PrimitiveType> {
1625 match *self {
1626 Primitive(p) | BorrowedRef { type_: box Primitive(p), .. } => Some(p),
1627 Slice(..) | BorrowedRef { type_: box Slice(..), .. } => Some(PrimitiveType::Slice),
1628 Array(..) | BorrowedRef { type_: box Array(..), .. } => Some(PrimitiveType::Array),
1629 Tuple(ref tys) => {
1630 if tys.is_empty() {
1631 Some(PrimitiveType::Unit)
1632 } else {
1633 Some(PrimitiveType::Tuple)
1634 }
1635 }
1636 RawPointer(..) => Some(PrimitiveType::RawPointer),
1637 BareFunction(..) => Some(PrimitiveType::Fn),
1638 _ => None,
1639 }
1640 }
1641
1642 pub(crate) fn sugared_async_return_type(self) -> Type {
1652 if let Type::ImplTrait(mut v) = self
1653 && let Some(GenericBound::TraitBound(PolyTrait { mut trait_, .. }, _)) = v.pop()
1654 && let Some(segment) = trait_.segments.pop()
1655 && let GenericArgs::AngleBracketed { mut constraints, .. } = segment.args
1656 && let Some(constraint) = constraints.pop()
1657 && let AssocItemConstraintKind::Equality { term } = constraint.kind
1658 && let Term::Type(ty) = term
1659 {
1660 ty
1661 } else {
1662 panic!("unexpected async fn return type")
1663 }
1664 }
1665
1666 pub(crate) fn is_assoc_ty(&self) -> bool {
1668 match self {
1669 Type::Path { path, .. } => path.is_assoc_ty(),
1670 _ => false,
1671 }
1672 }
1673
1674 pub(crate) fn is_self_type(&self) -> bool {
1675 matches!(*self, Type::SelfTy)
1676 }
1677
1678 pub(crate) fn generic_args(&self) -> Option<&GenericArgs> {
1679 match self {
1680 Type::Path { path, .. } => path.generic_args(),
1681 _ => None,
1682 }
1683 }
1684
1685 pub(crate) fn generics(&self) -> Option<Vec<&Type>> {
1686 match self {
1687 Type::Path { path, .. } => path.generics(),
1688 _ => None,
1689 }
1690 }
1691
1692 pub(crate) fn is_full_generic(&self) -> bool {
1693 matches!(self, Type::Generic(_))
1694 }
1695
1696 pub(crate) fn is_unit(&self) -> bool {
1697 matches!(self, Type::Tuple(v) if v.is_empty())
1698 }
1699
1700 pub(crate) fn projection(&self) -> Option<(&Type, DefId, PathSegment)> {
1701 if let QPath(box QPathData { self_type, trait_, assoc, .. }) = self {
1702 Some((self_type, trait_.as_ref()?.def_id(), assoc.clone()))
1703 } else {
1704 None
1705 }
1706 }
1707
1708 pub(crate) fn def_id(&self, cache: &Cache) -> Option<DefId> {
1712 let t: PrimitiveType = match *self {
1713 Type::Path { ref path } => return Some(path.def_id()),
1714 DynTrait(ref 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 { ref type_, .. } => return type_.def_id(cache),
1718 Tuple(ref 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 { ref 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_show_cast: 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 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(&self) -> Option<Vec<&Type>> {
2244 self.segments.last().and_then(|seg| {
2245 if let GenericArgs::AngleBracketed { ref args, .. } = seg.args {
2246 Some(
2247 args.iter()
2248 .filter_map(|arg| match arg {
2249 GenericArg::Type(ty) => Some(ty),
2250 _ => None,
2251 })
2252 .collect(),
2253 )
2254 } else {
2255 None
2256 }
2257 })
2258 }
2259}
2260
2261#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2262pub(crate) enum GenericArg {
2263 Lifetime(Lifetime),
2264 Type(Type),
2265 Const(Box<ConstantKind>),
2266 Infer,
2267}
2268
2269impl GenericArg {
2270 pub(crate) fn as_lt(&self) -> Option<&Lifetime> {
2271 if let Self::Lifetime(lt) = self { Some(lt) } else { None }
2272 }
2273
2274 pub(crate) fn as_ty(&self) -> Option<&Type> {
2275 if let Self::Type(ty) = self { Some(ty) } else { None }
2276 }
2277}
2278
2279#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2280pub(crate) enum GenericArgs {
2281 AngleBracketed { args: ThinVec<GenericArg>, constraints: ThinVec<AssocItemConstraint> },
2283 Parenthesized { inputs: ThinVec<Type>, output: Option<Box<Type>> },
2285 ReturnTypeNotation,
2287}
2288
2289impl GenericArgs {
2290 pub(crate) fn is_empty(&self) -> bool {
2291 match self {
2292 GenericArgs::AngleBracketed { args, constraints } => {
2293 args.is_empty() && constraints.is_empty()
2294 }
2295 GenericArgs::Parenthesized { inputs, output } => inputs.is_empty() && output.is_none(),
2296 GenericArgs::ReturnTypeNotation => false,
2297 }
2298 }
2299 pub(crate) fn constraints(&self) -> Box<dyn Iterator<Item = AssocItemConstraint> + '_> {
2300 match self {
2301 GenericArgs::AngleBracketed { constraints, .. } => {
2302 Box::new(constraints.iter().cloned())
2303 }
2304 GenericArgs::Parenthesized { output, .. } => Box::new(
2305 output
2306 .as_ref()
2307 .map(|ty| AssocItemConstraint {
2308 assoc: PathSegment {
2309 name: sym::Output,
2310 args: GenericArgs::AngleBracketed {
2311 args: ThinVec::new(),
2312 constraints: ThinVec::new(),
2313 },
2314 },
2315 kind: AssocItemConstraintKind::Equality {
2316 term: Term::Type((**ty).clone()),
2317 },
2318 })
2319 .into_iter(),
2320 ),
2321 GenericArgs::ReturnTypeNotation => Box::new([].into_iter()),
2322 }
2323 }
2324}
2325
2326impl<'a> IntoIterator for &'a GenericArgs {
2327 type IntoIter = Box<dyn Iterator<Item = GenericArg> + 'a>;
2328 type Item = GenericArg;
2329 fn into_iter(self) -> Self::IntoIter {
2330 match self {
2331 GenericArgs::AngleBracketed { args, .. } => Box::new(args.iter().cloned()),
2332 GenericArgs::Parenthesized { inputs, .. } => {
2333 Box::new(inputs.iter().cloned().map(GenericArg::Type))
2335 }
2336 GenericArgs::ReturnTypeNotation => Box::new([].into_iter()),
2337 }
2338 }
2339}
2340
2341#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2342pub(crate) struct PathSegment {
2343 pub(crate) name: Symbol,
2344 pub(crate) args: GenericArgs,
2345}
2346
2347#[derive(Clone, Debug)]
2348pub(crate) enum TypeAliasInnerType {
2349 Enum { variants: IndexVec<VariantIdx, Item>, is_non_exhaustive: bool },
2350 Union { fields: Vec<Item> },
2351 Struct { ctor_kind: Option<CtorKind>, fields: Vec<Item> },
2352}
2353
2354#[derive(Clone, Debug)]
2355pub(crate) struct TypeAlias {
2356 pub(crate) type_: Type,
2357 pub(crate) generics: Generics,
2358 pub(crate) inner_type: Option<TypeAliasInnerType>,
2361 pub(crate) item_type: Option<Type>,
2368}
2369
2370#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2371pub(crate) struct BareFunctionDecl {
2372 pub(crate) safety: hir::Safety,
2373 pub(crate) generic_params: Vec<GenericParamDef>,
2374 pub(crate) decl: FnDecl,
2375 pub(crate) abi: ExternAbi,
2376}
2377
2378#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2379pub(crate) struct UnsafeBinderTy {
2380 pub(crate) generic_params: Vec<GenericParamDef>,
2381 pub(crate) ty: Type,
2382}
2383
2384#[derive(Clone, Debug)]
2385pub(crate) struct Static {
2386 pub(crate) type_: Box<Type>,
2387 pub(crate) mutability: Mutability,
2388 pub(crate) expr: Option<BodyId>,
2389}
2390
2391#[derive(Clone, PartialEq, Eq, Hash, Debug)]
2392pub(crate) struct Constant {
2393 pub(crate) generics: Generics,
2394 pub(crate) kind: ConstantKind,
2395 pub(crate) type_: Type,
2396}
2397
2398#[derive(Clone, PartialEq, Eq, Hash, Debug)]
2399pub(crate) enum Term {
2400 Type(Type),
2401 Constant(ConstantKind),
2402}
2403
2404impl Term {
2405 pub(crate) fn ty(&self) -> Option<&Type> {
2406 if let Term::Type(ty) = self { Some(ty) } else { None }
2407 }
2408}
2409
2410impl From<Type> for Term {
2411 fn from(ty: Type) -> Self {
2412 Term::Type(ty)
2413 }
2414}
2415
2416#[derive(Clone, PartialEq, Eq, Hash, Debug)]
2417pub(crate) enum ConstantKind {
2418 TyConst { expr: Box<str> },
2424 Path { path: Box<str> },
2427 Anonymous { body: BodyId },
2431 Extern { def_id: DefId },
2433 Local { def_id: DefId, body: BodyId },
2435 Infer,
2437}
2438
2439impl Constant {
2440 pub(crate) fn expr(&self, tcx: TyCtxt<'_>) -> String {
2441 self.kind.expr(tcx)
2442 }
2443
2444 pub(crate) fn value(&self, tcx: TyCtxt<'_>) -> Option<String> {
2445 self.kind.value(tcx)
2446 }
2447
2448 pub(crate) fn is_literal(&self, tcx: TyCtxt<'_>) -> bool {
2449 self.kind.is_literal(tcx)
2450 }
2451}
2452
2453impl ConstantKind {
2454 pub(crate) fn expr(&self, tcx: TyCtxt<'_>) -> String {
2455 match *self {
2456 ConstantKind::TyConst { ref expr } => expr.to_string(),
2457 ConstantKind::Path { ref path } => path.to_string(),
2458 ConstantKind::Extern { def_id } => print_inlined_const(tcx, def_id),
2459 ConstantKind::Local { body, .. } | ConstantKind::Anonymous { body } => {
2460 rendered_const(tcx, tcx.hir_body(body), tcx.hir_body_owner_def_id(body))
2461 }
2462 ConstantKind::Infer => "_".to_string(),
2463 }
2464 }
2465
2466 pub(crate) fn value(&self, tcx: TyCtxt<'_>) -> Option<String> {
2467 match *self {
2468 ConstantKind::TyConst { .. }
2469 | ConstantKind::Path { .. }
2470 | ConstantKind::Anonymous { .. }
2471 | ConstantKind::Infer => None,
2472 ConstantKind::Extern { def_id } | ConstantKind::Local { def_id, .. } => {
2473 print_evaluated_const(tcx, def_id, true, true)
2474 }
2475 }
2476 }
2477
2478 pub(crate) fn is_literal(&self, tcx: TyCtxt<'_>) -> bool {
2479 match *self {
2480 ConstantKind::TyConst { .. }
2481 | ConstantKind::Extern { .. }
2482 | ConstantKind::Path { .. }
2483 | ConstantKind::Infer => false,
2484 ConstantKind::Local { body, .. } | ConstantKind::Anonymous { body } => {
2485 is_literal_expr(tcx, body.hir_id)
2486 }
2487 }
2488 }
2489}
2490
2491#[derive(Clone, Debug)]
2492pub(crate) struct Impl {
2493 pub(crate) safety: hir::Safety,
2494 pub(crate) generics: Generics,
2495 pub(crate) trait_: Option<Path>,
2496 pub(crate) for_: Type,
2497 pub(crate) items: Vec<Item>,
2498 pub(crate) polarity: ty::ImplPolarity,
2499 pub(crate) kind: ImplKind,
2500}
2501
2502impl Impl {
2503 pub(crate) fn provided_trait_methods(&self, tcx: TyCtxt<'_>) -> FxIndexSet<Symbol> {
2504 self.trait_
2505 .as_ref()
2506 .map(|t| t.def_id())
2507 .map(|did| tcx.provided_trait_methods(did).map(|meth| meth.name()).collect())
2508 .unwrap_or_default()
2509 }
2510
2511 pub(crate) fn is_negative_trait_impl(&self) -> bool {
2512 matches!(self.polarity, ty::ImplPolarity::Negative)
2513 }
2514}
2515
2516#[derive(Clone, Debug)]
2517pub(crate) enum ImplKind {
2518 Normal,
2519 Auto,
2520 FakeVariadic,
2521 Blanket(Box<Type>),
2522}
2523
2524impl ImplKind {
2525 pub(crate) fn is_auto(&self) -> bool {
2526 matches!(self, ImplKind::Auto)
2527 }
2528
2529 pub(crate) fn is_blanket(&self) -> bool {
2530 matches!(self, ImplKind::Blanket(_))
2531 }
2532
2533 pub(crate) fn is_fake_variadic(&self) -> bool {
2534 matches!(self, ImplKind::FakeVariadic)
2535 }
2536
2537 pub(crate) fn as_blanket_ty(&self) -> Option<&Type> {
2538 match self {
2539 ImplKind::Blanket(ty) => Some(ty),
2540 _ => None,
2541 }
2542 }
2543}
2544
2545#[derive(Clone, Debug)]
2546pub(crate) struct Import {
2547 pub(crate) kind: ImportKind,
2548 pub(crate) source: ImportSource,
2550 pub(crate) should_be_displayed: bool,
2551}
2552
2553impl Import {
2554 pub(crate) fn new_simple(
2555 name: Symbol,
2556 source: ImportSource,
2557 should_be_displayed: bool,
2558 ) -> Self {
2559 Self { kind: ImportKind::Simple(name), source, should_be_displayed }
2560 }
2561
2562 pub(crate) fn new_glob(source: ImportSource, should_be_displayed: bool) -> Self {
2563 Self { kind: ImportKind::Glob, source, should_be_displayed }
2564 }
2565
2566 pub(crate) fn imported_item_is_doc_hidden(&self, tcx: TyCtxt<'_>) -> bool {
2567 self.source.did.is_some_and(|did| tcx.is_doc_hidden(did))
2568 }
2569}
2570
2571#[derive(Clone, Debug)]
2572pub(crate) enum ImportKind {
2573 Simple(Symbol),
2575 Glob,
2577}
2578
2579#[derive(Clone, Debug)]
2580pub(crate) struct ImportSource {
2581 pub(crate) path: Path,
2582 pub(crate) did: Option<DefId>,
2583}
2584
2585#[derive(Clone, Debug)]
2586pub(crate) struct Macro {
2587 pub(crate) source: String,
2588 pub(crate) macro_rules: bool,
2590}
2591
2592#[derive(Clone, Debug)]
2593pub(crate) struct ProcMacro {
2594 pub(crate) kind: MacroKind,
2595 pub(crate) helpers: Vec<Symbol>,
2596}
2597
2598#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2609pub(crate) struct AssocItemConstraint {
2610 pub(crate) assoc: PathSegment,
2611 pub(crate) kind: AssocItemConstraintKind,
2612}
2613
2614#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2616pub(crate) enum AssocItemConstraintKind {
2617 Equality { term: Term },
2618 Bound { bounds: Vec<GenericBound> },
2619}
2620
2621#[cfg(target_pointer_width = "64")]
2623mod size_asserts {
2624 use rustc_data_structures::static_assert_size;
2625
2626 use super::*;
2627 static_assert_size!(Crate, 16); static_assert_size!(DocFragment, 32);
2630 static_assert_size!(GenericArg, 32);
2631 static_assert_size!(GenericArgs, 24);
2632 static_assert_size!(GenericParamDef, 40);
2633 static_assert_size!(Generics, 16);
2634 static_assert_size!(Item, 8);
2635 static_assert_size!(ItemInner, 136);
2636 static_assert_size!(ItemKind, 48);
2637 static_assert_size!(PathSegment, 32);
2638 static_assert_size!(Type, 32);
2639 }