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