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