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