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, DUMMY_SP);
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: QPathData, 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 def_id(&self, cache: &Cache) -> Option<DefId> {
1711 let t: PrimitiveType = match self {
1712 Type::Path { path } => return Some(path.def_id()),
1713 DynTrait(bounds, _) => return bounds.first().map(|b| b.trait_.def_id()),
1714 Primitive(p) => return cache.primitive_locations.get(p).cloned(),
1715 BorrowedRef { type_: box Generic(..), .. } => PrimitiveType::Reference,
1716 BorrowedRef { type_, .. } => return type_.def_id(cache),
1717 Tuple(tys) => {
1718 if tys.is_empty() {
1719 PrimitiveType::Unit
1720 } else {
1721 PrimitiveType::Tuple
1722 }
1723 }
1724 BareFunction(..) => PrimitiveType::Fn,
1725 Slice(..) => PrimitiveType::Slice,
1726 Array(..) => PrimitiveType::Array,
1727 Type::Pat(..) => PrimitiveType::Pat,
1728 RawPointer(..) => PrimitiveType::RawPointer,
1729 QPath(box QPathData { self_type, .. }) => return self_type.def_id(cache),
1730 Generic(_) | SelfTy | Infer | ImplTrait(_) | UnsafeBinder(_) => return None,
1731 };
1732 Primitive(t).def_id(cache)
1733 }
1734}
1735
1736#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1737pub(crate) struct QPathData {
1738 pub assoc: PathSegment,
1739 pub self_type: Type,
1740 pub should_fully_qualify: bool,
1742 pub trait_: Option<Path>,
1743}
1744
1745#[derive(Clone, PartialEq, Eq, Hash, Copy, Debug)]
1752pub(crate) enum PrimitiveType {
1753 Isize,
1754 I8,
1755 I16,
1756 I32,
1757 I64,
1758 I128,
1759 Usize,
1760 U8,
1761 U16,
1762 U32,
1763 U64,
1764 U128,
1765 F16,
1766 F32,
1767 F64,
1768 F128,
1769 Char,
1770 Bool,
1771 Str,
1772 Slice,
1773 Array,
1774 Pat,
1775 Tuple,
1776 Unit,
1777 RawPointer,
1778 Reference,
1779 Fn,
1780 Never,
1781}
1782
1783type SimplifiedTypes = FxIndexMap<PrimitiveType, ArrayVec<SimplifiedType, 3>>;
1784impl PrimitiveType {
1785 pub(crate) fn from_hir(prim: hir::PrimTy) -> PrimitiveType {
1786 use ast::{FloatTy, IntTy, UintTy};
1787 match prim {
1788 hir::PrimTy::Int(IntTy::Isize) => PrimitiveType::Isize,
1789 hir::PrimTy::Int(IntTy::I8) => PrimitiveType::I8,
1790 hir::PrimTy::Int(IntTy::I16) => PrimitiveType::I16,
1791 hir::PrimTy::Int(IntTy::I32) => PrimitiveType::I32,
1792 hir::PrimTy::Int(IntTy::I64) => PrimitiveType::I64,
1793 hir::PrimTy::Int(IntTy::I128) => PrimitiveType::I128,
1794 hir::PrimTy::Uint(UintTy::Usize) => PrimitiveType::Usize,
1795 hir::PrimTy::Uint(UintTy::U8) => PrimitiveType::U8,
1796 hir::PrimTy::Uint(UintTy::U16) => PrimitiveType::U16,
1797 hir::PrimTy::Uint(UintTy::U32) => PrimitiveType::U32,
1798 hir::PrimTy::Uint(UintTy::U64) => PrimitiveType::U64,
1799 hir::PrimTy::Uint(UintTy::U128) => PrimitiveType::U128,
1800 hir::PrimTy::Float(FloatTy::F16) => PrimitiveType::F16,
1801 hir::PrimTy::Float(FloatTy::F32) => PrimitiveType::F32,
1802 hir::PrimTy::Float(FloatTy::F64) => PrimitiveType::F64,
1803 hir::PrimTy::Float(FloatTy::F128) => PrimitiveType::F128,
1804 hir::PrimTy::Str => PrimitiveType::Str,
1805 hir::PrimTy::Bool => PrimitiveType::Bool,
1806 hir::PrimTy::Char => PrimitiveType::Char,
1807 }
1808 }
1809
1810 pub(crate) fn from_symbol(s: Symbol) -> Option<PrimitiveType> {
1811 match s {
1812 sym::isize => Some(PrimitiveType::Isize),
1813 sym::i8 => Some(PrimitiveType::I8),
1814 sym::i16 => Some(PrimitiveType::I16),
1815 sym::i32 => Some(PrimitiveType::I32),
1816 sym::i64 => Some(PrimitiveType::I64),
1817 sym::i128 => Some(PrimitiveType::I128),
1818 sym::usize => Some(PrimitiveType::Usize),
1819 sym::u8 => Some(PrimitiveType::U8),
1820 sym::u16 => Some(PrimitiveType::U16),
1821 sym::u32 => Some(PrimitiveType::U32),
1822 sym::u64 => Some(PrimitiveType::U64),
1823 sym::u128 => Some(PrimitiveType::U128),
1824 sym::bool => Some(PrimitiveType::Bool),
1825 sym::char => Some(PrimitiveType::Char),
1826 sym::str => Some(PrimitiveType::Str),
1827 sym::f16 => Some(PrimitiveType::F16),
1828 sym::f32 => Some(PrimitiveType::F32),
1829 sym::f64 => Some(PrimitiveType::F64),
1830 sym::f128 => Some(PrimitiveType::F128),
1831 sym::array => Some(PrimitiveType::Array),
1832 sym::slice => Some(PrimitiveType::Slice),
1833 sym::tuple => Some(PrimitiveType::Tuple),
1834 sym::unit => Some(PrimitiveType::Unit),
1835 sym::pointer => Some(PrimitiveType::RawPointer),
1836 sym::reference => Some(PrimitiveType::Reference),
1837 kw::Fn => Some(PrimitiveType::Fn),
1838 sym::never => Some(PrimitiveType::Never),
1839 _ => None,
1840 }
1841 }
1842
1843 pub(crate) fn simplified_types() -> &'static SimplifiedTypes {
1844 use PrimitiveType::*;
1845 use ty::{FloatTy, IntTy, UintTy};
1846 static CELL: OnceCell<SimplifiedTypes> = OnceCell::new();
1847
1848 let single = |x| iter::once(x).collect();
1849 CELL.get_or_init(move || {
1850 map! {
1851 Isize => single(SimplifiedType::Int(IntTy::Isize)),
1852 I8 => single(SimplifiedType::Int(IntTy::I8)),
1853 I16 => single(SimplifiedType::Int(IntTy::I16)),
1854 I32 => single(SimplifiedType::Int(IntTy::I32)),
1855 I64 => single(SimplifiedType::Int(IntTy::I64)),
1856 I128 => single(SimplifiedType::Int(IntTy::I128)),
1857 Usize => single(SimplifiedType::Uint(UintTy::Usize)),
1858 U8 => single(SimplifiedType::Uint(UintTy::U8)),
1859 U16 => single(SimplifiedType::Uint(UintTy::U16)),
1860 U32 => single(SimplifiedType::Uint(UintTy::U32)),
1861 U64 => single(SimplifiedType::Uint(UintTy::U64)),
1862 U128 => single(SimplifiedType::Uint(UintTy::U128)),
1863 F16 => single(SimplifiedType::Float(FloatTy::F16)),
1864 F32 => single(SimplifiedType::Float(FloatTy::F32)),
1865 F64 => single(SimplifiedType::Float(FloatTy::F64)),
1866 F128 => single(SimplifiedType::Float(FloatTy::F128)),
1867 Str => single(SimplifiedType::Str),
1868 Bool => single(SimplifiedType::Bool),
1869 Char => single(SimplifiedType::Char),
1870 Array => single(SimplifiedType::Array),
1871 Slice => single(SimplifiedType::Slice),
1872 Tuple => [SimplifiedType::Tuple(1), SimplifiedType::Tuple(2), SimplifiedType::Tuple(3)].into(),
1878 Unit => single(SimplifiedType::Tuple(0)),
1879 RawPointer => [SimplifiedType::Ptr(Mutability::Not), SimplifiedType::Ptr(Mutability::Mut)].into_iter().collect(),
1880 Reference => [SimplifiedType::Ref(Mutability::Not), SimplifiedType::Ref(Mutability::Mut)].into_iter().collect(),
1881 Fn => single(SimplifiedType::Function(1)),
1884 Never => single(SimplifiedType::Never),
1885 }
1886 })
1887 }
1888
1889 pub(crate) fn impls<'tcx>(&self, tcx: TyCtxt<'tcx>) -> impl Iterator<Item = DefId> + 'tcx {
1890 Self::simplified_types()
1891 .get(self)
1892 .into_iter()
1893 .flatten()
1894 .flat_map(move |&simp| tcx.incoherent_impls(simp).iter())
1895 .copied()
1896 }
1897
1898 pub(crate) fn all_impls(tcx: TyCtxt<'_>) -> impl Iterator<Item = DefId> {
1899 Self::simplified_types()
1900 .values()
1901 .flatten()
1902 .flat_map(move |&simp| tcx.incoherent_impls(simp).iter())
1903 .copied()
1904 }
1905
1906 pub(crate) fn as_sym(&self) -> Symbol {
1907 use PrimitiveType::*;
1908 match self {
1909 Isize => sym::isize,
1910 I8 => sym::i8,
1911 I16 => sym::i16,
1912 I32 => sym::i32,
1913 I64 => sym::i64,
1914 I128 => sym::i128,
1915 Usize => sym::usize,
1916 U8 => sym::u8,
1917 U16 => sym::u16,
1918 U32 => sym::u32,
1919 U64 => sym::u64,
1920 U128 => sym::u128,
1921 F16 => sym::f16,
1922 F32 => sym::f32,
1923 F64 => sym::f64,
1924 F128 => sym::f128,
1925 Str => sym::str,
1926 Bool => sym::bool,
1927 Char => sym::char,
1928 Array => sym::array,
1929 Pat => sym::pat,
1930 Slice => sym::slice,
1931 Tuple => sym::tuple,
1932 Unit => sym::unit,
1933 RawPointer => sym::pointer,
1934 Reference => sym::reference,
1935 Fn => kw::Fn,
1936 Never => sym::never,
1937 }
1938 }
1939
1940 pub(crate) fn primitive_locations(tcx: TyCtxt<'_>) -> &FxIndexMap<PrimitiveType, DefId> {
1952 static PRIMITIVE_LOCATIONS: OnceCell<FxIndexMap<PrimitiveType, DefId>> = OnceCell::new();
1953 PRIMITIVE_LOCATIONS.get_or_init(|| {
1954 let mut primitive_locations = FxIndexMap::default();
1955 for &crate_num in tcx.crates(()) {
1958 let e = ExternalCrate { crate_num };
1959 let crate_name = e.name(tcx);
1960 debug!(?crate_num, ?crate_name);
1961 for &(def_id, prim) in &e.primitives(tcx) {
1962 if crate_name == sym::core && primitive_locations.contains_key(&prim) {
1964 continue;
1965 }
1966 primitive_locations.insert(prim, def_id);
1967 }
1968 }
1969 let local_primitives = ExternalCrate { crate_num: LOCAL_CRATE }.primitives(tcx);
1970 for (def_id, prim) in local_primitives {
1971 primitive_locations.insert(prim, def_id);
1972 }
1973 primitive_locations
1974 })
1975 }
1976}
1977
1978impl From<ast::IntTy> for PrimitiveType {
1979 fn from(int_ty: ast::IntTy) -> PrimitiveType {
1980 match int_ty {
1981 ast::IntTy::Isize => PrimitiveType::Isize,
1982 ast::IntTy::I8 => PrimitiveType::I8,
1983 ast::IntTy::I16 => PrimitiveType::I16,
1984 ast::IntTy::I32 => PrimitiveType::I32,
1985 ast::IntTy::I64 => PrimitiveType::I64,
1986 ast::IntTy::I128 => PrimitiveType::I128,
1987 }
1988 }
1989}
1990
1991impl From<ast::UintTy> for PrimitiveType {
1992 fn from(uint_ty: ast::UintTy) -> PrimitiveType {
1993 match uint_ty {
1994 ast::UintTy::Usize => PrimitiveType::Usize,
1995 ast::UintTy::U8 => PrimitiveType::U8,
1996 ast::UintTy::U16 => PrimitiveType::U16,
1997 ast::UintTy::U32 => PrimitiveType::U32,
1998 ast::UintTy::U64 => PrimitiveType::U64,
1999 ast::UintTy::U128 => PrimitiveType::U128,
2000 }
2001 }
2002}
2003
2004impl From<ast::FloatTy> for PrimitiveType {
2005 fn from(float_ty: ast::FloatTy) -> PrimitiveType {
2006 match float_ty {
2007 ast::FloatTy::F16 => PrimitiveType::F16,
2008 ast::FloatTy::F32 => PrimitiveType::F32,
2009 ast::FloatTy::F64 => PrimitiveType::F64,
2010 ast::FloatTy::F128 => PrimitiveType::F128,
2011 }
2012 }
2013}
2014
2015impl From<ty::IntTy> for PrimitiveType {
2016 fn from(int_ty: ty::IntTy) -> PrimitiveType {
2017 match int_ty {
2018 ty::IntTy::Isize => PrimitiveType::Isize,
2019 ty::IntTy::I8 => PrimitiveType::I8,
2020 ty::IntTy::I16 => PrimitiveType::I16,
2021 ty::IntTy::I32 => PrimitiveType::I32,
2022 ty::IntTy::I64 => PrimitiveType::I64,
2023 ty::IntTy::I128 => PrimitiveType::I128,
2024 }
2025 }
2026}
2027
2028impl From<ty::UintTy> for PrimitiveType {
2029 fn from(uint_ty: ty::UintTy) -> PrimitiveType {
2030 match uint_ty {
2031 ty::UintTy::Usize => PrimitiveType::Usize,
2032 ty::UintTy::U8 => PrimitiveType::U8,
2033 ty::UintTy::U16 => PrimitiveType::U16,
2034 ty::UintTy::U32 => PrimitiveType::U32,
2035 ty::UintTy::U64 => PrimitiveType::U64,
2036 ty::UintTy::U128 => PrimitiveType::U128,
2037 }
2038 }
2039}
2040
2041impl From<ty::FloatTy> for PrimitiveType {
2042 fn from(float_ty: ty::FloatTy) -> PrimitiveType {
2043 match float_ty {
2044 ty::FloatTy::F16 => PrimitiveType::F16,
2045 ty::FloatTy::F32 => PrimitiveType::F32,
2046 ty::FloatTy::F64 => PrimitiveType::F64,
2047 ty::FloatTy::F128 => PrimitiveType::F128,
2048 }
2049 }
2050}
2051
2052impl From<hir::PrimTy> for PrimitiveType {
2053 fn from(prim_ty: hir::PrimTy) -> PrimitiveType {
2054 match prim_ty {
2055 hir::PrimTy::Int(int_ty) => int_ty.into(),
2056 hir::PrimTy::Uint(uint_ty) => uint_ty.into(),
2057 hir::PrimTy::Float(float_ty) => float_ty.into(),
2058 hir::PrimTy::Str => PrimitiveType::Str,
2059 hir::PrimTy::Bool => PrimitiveType::Bool,
2060 hir::PrimTy::Char => PrimitiveType::Char,
2061 }
2062 }
2063}
2064
2065#[derive(Clone, Debug)]
2066pub(crate) struct Struct {
2067 pub(crate) ctor_kind: Option<CtorKind>,
2068 pub(crate) generics: Generics,
2069 pub(crate) fields: ThinVec<Item>,
2070}
2071
2072impl Struct {
2073 pub(crate) fn has_stripped_entries(&self) -> bool {
2074 self.fields.iter().any(|f| f.is_stripped())
2075 }
2076}
2077
2078#[derive(Clone, Debug)]
2079pub(crate) struct Union {
2080 pub(crate) generics: Generics,
2081 pub(crate) fields: Vec<Item>,
2082}
2083
2084impl Union {
2085 pub(crate) fn has_stripped_entries(&self) -> bool {
2086 self.fields.iter().any(|f| f.is_stripped())
2087 }
2088}
2089
2090#[derive(Clone, Debug)]
2094pub(crate) struct VariantStruct {
2095 pub(crate) fields: ThinVec<Item>,
2096}
2097
2098impl VariantStruct {
2099 pub(crate) fn has_stripped_entries(&self) -> bool {
2100 self.fields.iter().any(|f| f.is_stripped())
2101 }
2102}
2103
2104#[derive(Clone, Debug)]
2105pub(crate) struct Enum {
2106 pub(crate) variants: IndexVec<VariantIdx, Item>,
2107 pub(crate) generics: Generics,
2108}
2109
2110impl Enum {
2111 pub(crate) fn has_stripped_entries(&self) -> bool {
2112 self.variants.iter().any(|f| f.is_stripped())
2113 }
2114
2115 pub(crate) fn non_stripped_variants(&self) -> impl Iterator<Item = &Item> {
2116 self.variants.iter().filter(|v| !v.is_stripped())
2117 }
2118}
2119
2120#[derive(Clone, Debug)]
2121pub(crate) struct Variant {
2122 pub kind: VariantKind,
2123 pub discriminant: Option<Discriminant>,
2124}
2125
2126#[derive(Clone, Debug)]
2127pub(crate) enum VariantKind {
2128 CLike,
2129 Tuple(ThinVec<Item>),
2130 Struct(VariantStruct),
2131}
2132
2133impl Variant {
2134 pub(crate) fn has_stripped_entries(&self) -> Option<bool> {
2135 match &self.kind {
2136 VariantKind::Struct(struct_) => Some(struct_.has_stripped_entries()),
2137 VariantKind::CLike | VariantKind::Tuple(_) => None,
2138 }
2139 }
2140}
2141
2142#[derive(Clone, Debug)]
2143pub(crate) struct Discriminant {
2144 pub(super) expr: Option<BodyId>,
2147 pub(super) value: DefId,
2148}
2149
2150impl Discriminant {
2151 pub(crate) fn expr(&self, tcx: TyCtxt<'_>) -> Option<String> {
2154 self.expr
2155 .map(|body| rendered_const(tcx, tcx.hir_body(body), tcx.hir_body_owner_def_id(body)))
2156 }
2157 pub(crate) fn value(&self, tcx: TyCtxt<'_>, with_underscores: bool) -> String {
2158 print_evaluated_const(tcx, self.value, with_underscores, false).unwrap()
2159 }
2160}
2161
2162#[derive(Copy, Clone, Debug)]
2165pub(crate) struct Span(rustc_span::Span);
2166
2167impl Span {
2168 pub(crate) fn new(sp: rustc_span::Span) -> Self {
2173 Self(sp.source_callsite())
2174 }
2175
2176 pub(crate) fn inner(&self) -> rustc_span::Span {
2177 self.0
2178 }
2179
2180 pub(crate) fn filename(&self, sess: &Session) -> FileName {
2181 sess.source_map().span_to_filename(self.0)
2182 }
2183
2184 pub(crate) fn lo(&self, sess: &Session) -> Loc {
2185 sess.source_map().lookup_char_pos(self.0.lo())
2186 }
2187
2188 pub(crate) fn hi(&self, sess: &Session) -> Loc {
2189 sess.source_map().lookup_char_pos(self.0.hi())
2190 }
2191
2192 pub(crate) fn cnum(&self, sess: &Session) -> CrateNum {
2193 self.lo(sess).file.cnum
2195 }
2196}
2197
2198#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2199pub(crate) struct Path {
2200 pub(crate) res: Res,
2201 pub(crate) segments: ThinVec<PathSegment>,
2202}
2203
2204impl Path {
2205 pub(crate) fn def_id(&self) -> DefId {
2206 self.res.def_id()
2207 }
2208
2209 pub(crate) fn last_opt(&self) -> Option<Symbol> {
2210 self.segments.last().map(|s| s.name)
2211 }
2212
2213 pub(crate) fn last(&self) -> Symbol {
2214 self.last_opt().expect("segments were empty")
2215 }
2216
2217 pub(crate) fn whole_name(&self) -> String {
2218 self.segments
2219 .iter()
2220 .map(|s| if s.name == kw::PathRoot { "" } else { s.name.as_str() })
2221 .intersperse("::")
2222 .collect()
2223 }
2224
2225 pub(crate) fn is_assoc_ty(&self) -> bool {
2227 match self.res {
2228 Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } | Res::Def(DefKind::TyParam, _)
2229 if self.segments.len() != 1 =>
2230 {
2231 true
2232 }
2233 Res::Def(DefKind::AssocTy, _) => true,
2234 _ => false,
2235 }
2236 }
2237
2238 pub(crate) fn generic_args(&self) -> Option<&GenericArgs> {
2239 self.segments.last().map(|seg| &seg.args)
2240 }
2241
2242 pub(crate) fn generics<'a>(&'a self) -> Option<impl Iterator<Item = &'a Type>> {
2243 self.segments.last().and_then(|seg| {
2244 if let GenericArgs::AngleBracketed { ref args, .. } = seg.args {
2245 Some(args.iter().filter_map(|arg| match arg {
2246 GenericArg::Type(ty) => Some(ty),
2247 _ => None,
2248 }))
2249 } else {
2250 None
2251 }
2252 })
2253 }
2254}
2255
2256#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2257pub(crate) enum GenericArg {
2258 Lifetime(Lifetime),
2259 Type(Type),
2260 Const(Box<ConstantKind>),
2261 Infer,
2262}
2263
2264impl GenericArg {
2265 pub(crate) fn as_lt(&self) -> Option<&Lifetime> {
2266 if let Self::Lifetime(lt) = self { Some(lt) } else { None }
2267 }
2268
2269 pub(crate) fn as_ty(&self) -> Option<&Type> {
2270 if let Self::Type(ty) = self { Some(ty) } else { None }
2271 }
2272}
2273
2274#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2275pub(crate) enum GenericArgs {
2276 AngleBracketed { args: ThinVec<GenericArg>, constraints: ThinVec<AssocItemConstraint> },
2278 Parenthesized { inputs: ThinVec<Type>, output: Option<Box<Type>> },
2280 ReturnTypeNotation,
2282}
2283
2284impl GenericArgs {
2285 pub(crate) fn is_empty(&self) -> bool {
2286 match self {
2287 GenericArgs::AngleBracketed { args, constraints } => {
2288 args.is_empty() && constraints.is_empty()
2289 }
2290 GenericArgs::Parenthesized { inputs, output } => inputs.is_empty() && output.is_none(),
2291 GenericArgs::ReturnTypeNotation => false,
2292 }
2293 }
2294 pub(crate) fn constraints(&self) -> Box<dyn Iterator<Item = AssocItemConstraint> + '_> {
2295 match self {
2296 GenericArgs::AngleBracketed { constraints, .. } => {
2297 Box::new(constraints.iter().cloned())
2298 }
2299 GenericArgs::Parenthesized { output, .. } => Box::new(
2300 output
2301 .as_ref()
2302 .map(|ty| AssocItemConstraint {
2303 assoc: PathSegment {
2304 name: sym::Output,
2305 args: GenericArgs::AngleBracketed {
2306 args: ThinVec::new(),
2307 constraints: ThinVec::new(),
2308 },
2309 },
2310 kind: AssocItemConstraintKind::Equality {
2311 term: Term::Type((**ty).clone()),
2312 },
2313 })
2314 .into_iter(),
2315 ),
2316 GenericArgs::ReturnTypeNotation => Box::new([].into_iter()),
2317 }
2318 }
2319}
2320
2321impl<'a> IntoIterator for &'a GenericArgs {
2322 type IntoIter = Box<dyn Iterator<Item = GenericArg> + 'a>;
2323 type Item = GenericArg;
2324 fn into_iter(self) -> Self::IntoIter {
2325 match self {
2326 GenericArgs::AngleBracketed { args, .. } => Box::new(args.iter().cloned()),
2327 GenericArgs::Parenthesized { inputs, .. } => {
2328 Box::new(inputs.iter().cloned().map(GenericArg::Type))
2330 }
2331 GenericArgs::ReturnTypeNotation => Box::new([].into_iter()),
2332 }
2333 }
2334}
2335
2336#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2337pub(crate) struct PathSegment {
2338 pub(crate) name: Symbol,
2339 pub(crate) args: GenericArgs,
2340}
2341
2342#[derive(Clone, Debug)]
2343pub(crate) enum TypeAliasInnerType {
2344 Enum { variants: IndexVec<VariantIdx, Item>, is_non_exhaustive: bool },
2345 Union { fields: Vec<Item> },
2346 Struct { ctor_kind: Option<CtorKind>, fields: Vec<Item> },
2347}
2348
2349impl TypeAliasInnerType {
2350 fn has_stripped_entries(&self) -> Option<bool> {
2351 Some(match self {
2352 Self::Enum { variants, .. } => variants.iter().any(|v| v.is_stripped()),
2353 Self::Union { fields } | Self::Struct { fields, .. } => {
2354 fields.iter().any(|f| f.is_stripped())
2355 }
2356 })
2357 }
2358}
2359
2360#[derive(Clone, Debug)]
2361pub(crate) struct TypeAlias {
2362 pub(crate) type_: Type,
2363 pub(crate) generics: Generics,
2364 pub(crate) inner_type: Option<TypeAliasInnerType>,
2367 pub(crate) item_type: Option<Type>,
2374}
2375
2376#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2377pub(crate) struct BareFunctionDecl {
2378 pub(crate) safety: hir::Safety,
2379 pub(crate) generic_params: Vec<GenericParamDef>,
2380 pub(crate) decl: FnDecl,
2381 pub(crate) abi: ExternAbi,
2382}
2383
2384#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2385pub(crate) struct UnsafeBinderTy {
2386 pub(crate) generic_params: Vec<GenericParamDef>,
2387 pub(crate) ty: Type,
2388}
2389
2390#[derive(Clone, Debug)]
2391pub(crate) struct Static {
2392 pub(crate) type_: Box<Type>,
2393 pub(crate) mutability: Mutability,
2394 pub(crate) expr: Option<BodyId>,
2395}
2396
2397#[derive(Clone, PartialEq, Eq, Hash, Debug)]
2398pub(crate) struct Constant {
2399 pub(crate) generics: Generics,
2400 pub(crate) kind: ConstantKind,
2401 pub(crate) type_: Type,
2402}
2403
2404#[derive(Clone, PartialEq, Eq, Hash, Debug)]
2405pub(crate) enum Term {
2406 Type(Type),
2407 Constant(ConstantKind),
2408}
2409
2410impl Term {
2411 pub(crate) fn ty(&self) -> Option<&Type> {
2412 if let Term::Type(ty) = self { Some(ty) } else { None }
2413 }
2414}
2415
2416impl From<Type> for Term {
2417 fn from(ty: Type) -> Self {
2418 Term::Type(ty)
2419 }
2420}
2421
2422#[derive(Clone, PartialEq, Eq, Hash, Debug)]
2423pub(crate) enum ConstantKind {
2424 TyConst { expr: Box<str> },
2430 Path { path: Box<str> },
2433 Anonymous { body: BodyId },
2437 Extern { def_id: DefId },
2439 Local { def_id: DefId, body: BodyId },
2441 Infer,
2443}
2444
2445impl Constant {
2446 pub(crate) fn expr(&self, tcx: TyCtxt<'_>) -> String {
2447 self.kind.expr(tcx)
2448 }
2449
2450 pub(crate) fn value(&self, tcx: TyCtxt<'_>) -> Option<String> {
2451 self.kind.value(tcx)
2452 }
2453
2454 pub(crate) fn is_literal(&self, tcx: TyCtxt<'_>) -> bool {
2455 self.kind.is_literal(tcx)
2456 }
2457}
2458
2459impl ConstantKind {
2460 pub(crate) fn expr(&self, tcx: TyCtxt<'_>) -> String {
2461 match *self {
2462 ConstantKind::TyConst { ref expr } => expr.to_string(),
2463 ConstantKind::Path { ref path } => path.to_string(),
2464 ConstantKind::Extern { def_id } => print_inlined_const(tcx, def_id),
2465 ConstantKind::Local { body, .. } | ConstantKind::Anonymous { body } => {
2466 rendered_const(tcx, tcx.hir_body(body), tcx.hir_body_owner_def_id(body))
2467 }
2468 ConstantKind::Infer => "_".to_string(),
2469 }
2470 }
2471
2472 pub(crate) fn value(&self, tcx: TyCtxt<'_>) -> Option<String> {
2473 match *self {
2474 ConstantKind::TyConst { .. }
2475 | ConstantKind::Path { .. }
2476 | ConstantKind::Anonymous { .. }
2477 | ConstantKind::Infer => None,
2478 ConstantKind::Extern { def_id } | ConstantKind::Local { def_id, .. } => {
2479 print_evaluated_const(tcx, def_id, true, true)
2480 }
2481 }
2482 }
2483
2484 pub(crate) fn is_literal(&self, tcx: TyCtxt<'_>) -> bool {
2485 match *self {
2486 ConstantKind::TyConst { .. }
2487 | ConstantKind::Extern { .. }
2488 | ConstantKind::Path { .. }
2489 | ConstantKind::Infer => false,
2490 ConstantKind::Local { body, .. } | ConstantKind::Anonymous { body } => {
2491 is_literal_expr(tcx, body.hir_id)
2492 }
2493 }
2494 }
2495}
2496
2497#[derive(Clone, Debug)]
2498pub(crate) struct Impl {
2499 pub(crate) safety: hir::Safety,
2500 pub(crate) generics: Generics,
2501 pub(crate) trait_: Option<Path>,
2502 pub(crate) for_: Type,
2503 pub(crate) items: Vec<Item>,
2504 pub(crate) polarity: ty::ImplPolarity,
2505 pub(crate) kind: ImplKind,
2506}
2507
2508impl Impl {
2509 pub(crate) fn provided_trait_methods(&self, tcx: TyCtxt<'_>) -> FxIndexSet<Symbol> {
2510 self.trait_
2511 .as_ref()
2512 .map(|t| t.def_id())
2513 .map(|did| tcx.provided_trait_methods(did).map(|meth| meth.name()).collect())
2514 .unwrap_or_default()
2515 }
2516
2517 pub(crate) fn is_negative_trait_impl(&self) -> bool {
2518 matches!(self.polarity, ty::ImplPolarity::Negative)
2519 }
2520}
2521
2522#[derive(Clone, Debug)]
2523pub(crate) enum ImplKind {
2524 Normal,
2525 Auto,
2526 FakeVariadic,
2527 Blanket(Box<Type>),
2528}
2529
2530impl ImplKind {
2531 pub(crate) fn is_auto(&self) -> bool {
2532 matches!(self, ImplKind::Auto)
2533 }
2534
2535 pub(crate) fn is_blanket(&self) -> bool {
2536 matches!(self, ImplKind::Blanket(_))
2537 }
2538
2539 pub(crate) fn is_fake_variadic(&self) -> bool {
2540 matches!(self, ImplKind::FakeVariadic)
2541 }
2542
2543 pub(crate) fn as_blanket_ty(&self) -> Option<&Type> {
2544 match self {
2545 ImplKind::Blanket(ty) => Some(ty),
2546 _ => None,
2547 }
2548 }
2549}
2550
2551#[derive(Clone, Debug)]
2552pub(crate) struct Import {
2553 pub(crate) kind: ImportKind,
2554 pub(crate) source: ImportSource,
2556 pub(crate) should_be_displayed: bool,
2557}
2558
2559impl Import {
2560 pub(crate) fn new_simple(
2561 name: Symbol,
2562 source: ImportSource,
2563 should_be_displayed: bool,
2564 ) -> Self {
2565 Self { kind: ImportKind::Simple(name), source, should_be_displayed }
2566 }
2567
2568 pub(crate) fn new_glob(source: ImportSource, should_be_displayed: bool) -> Self {
2569 Self { kind: ImportKind::Glob, source, should_be_displayed }
2570 }
2571
2572 pub(crate) fn imported_item_is_doc_hidden(&self, tcx: TyCtxt<'_>) -> bool {
2573 self.source.did.is_some_and(|did| tcx.is_doc_hidden(did))
2574 }
2575}
2576
2577#[derive(Clone, Debug)]
2578pub(crate) enum ImportKind {
2579 Simple(Symbol),
2581 Glob,
2583}
2584
2585#[derive(Clone, Debug)]
2586pub(crate) struct ImportSource {
2587 pub(crate) path: Path,
2588 pub(crate) did: Option<DefId>,
2589}
2590
2591#[derive(Clone, Debug)]
2592pub(crate) struct Macro {
2593 pub(crate) source: String,
2594 pub(crate) macro_rules: bool,
2596}
2597
2598#[derive(Clone, Debug)]
2599pub(crate) struct ProcMacro {
2600 pub(crate) kind: MacroKind,
2601 pub(crate) helpers: Vec<Symbol>,
2602}
2603
2604#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2615pub(crate) struct AssocItemConstraint {
2616 pub(crate) assoc: PathSegment,
2617 pub(crate) kind: AssocItemConstraintKind,
2618}
2619
2620#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2622pub(crate) enum AssocItemConstraintKind {
2623 Equality { term: Term },
2624 Bound { bounds: Vec<GenericBound> },
2625}
2626
2627#[cfg(target_pointer_width = "64")]
2629mod size_asserts {
2630 use rustc_data_structures::static_assert_size;
2631
2632 use super::*;
2633 static_assert_size!(Crate, 16); static_assert_size!(DocFragment, 32);
2636 static_assert_size!(GenericArg, 32);
2637 static_assert_size!(GenericArgs, 24);
2638 static_assert_size!(GenericParamDef, 40);
2639 static_assert_size!(Generics, 16);
2640 static_assert_size!(Item, 8);
2641 static_assert_size!(ItemInner, 136);
2642 static_assert_size!(ItemKind, 48);
2643 static_assert_size!(PathSegment, 32);
2644 static_assert_size!(Type, 32);
2645 }