rustdoc/clean/
types.rs

1use std::hash::Hash;
2use std::path::PathBuf;
3use std::sync::{Arc, OnceLock as OnceCell};
4use std::{fmt, iter};
5
6use arrayvec::ArrayVec;
7use rustc_abi::{ExternAbi, VariantIdx};
8use rustc_attr_parsing::{AttributeKind, ConstStability, Deprecation, Stability, StableSince};
9use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
10use rustc_hir::def::{CtorKind, DefKind, Res};
11use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId};
12use rustc_hir::lang_items::LangItem;
13use rustc_hir::{BodyId, Mutability};
14use rustc_index::IndexVec;
15use rustc_metadata::rendered_const;
16use rustc_middle::span_bug;
17use rustc_middle::ty::fast_reject::SimplifiedType;
18use rustc_middle::ty::{self, TyCtxt, Visibility};
19use rustc_resolve::rustdoc::{
20    DocFragment, add_doc_fragment, attrs_to_doc_fragments, inner_docs, span_of_fragments,
21};
22use rustc_session::Session;
23use rustc_span::hygiene::MacroKind;
24use rustc_span::symbol::{Ident, Symbol, kw, sym};
25use rustc_span::{DUMMY_SP, FileName, Loc};
26use thin_vec::ThinVec;
27use tracing::{debug, trace};
28use {rustc_ast as ast, rustc_hir as hir};
29
30pub(crate) use self::ItemKind::*;
31pub(crate) use self::Type::{
32    Array, BareFunction, BorrowedRef, DynTrait, Generic, ImplTrait, Infer, Primitive, QPath,
33    RawPointer, SelfTy, Slice, Tuple, UnsafeBinder,
34};
35use crate::clean::cfg::Cfg;
36use crate::clean::clean_middle_path;
37use crate::clean::inline::{self, print_inlined_const};
38use crate::clean::utils::{is_literal_expr, print_evaluated_const};
39use crate::core::DocContext;
40use crate::formats::cache::Cache;
41use crate::formats::item_type::ItemType;
42use crate::html::render::Context;
43use crate::passes::collect_intra_doc_links::UrlFragment;
44
45#[cfg(test)]
46mod tests;
47
48pub(crate) type ItemIdSet = FxHashSet<ItemId>;
49
50#[derive(Debug, Clone, PartialEq, Eq, Hash, Copy)]
51pub(crate) enum ItemId {
52    /// A "normal" item that uses a [`DefId`] for identification.
53    DefId(DefId),
54    /// Identifier that is used for auto traits.
55    Auto { trait_: DefId, for_: DefId },
56    /// Identifier that is used for blanket implementations.
57    Blanket { impl_id: DefId, for_: DefId },
58}
59
60impl ItemId {
61    #[inline]
62    pub(crate) fn is_local(self) -> bool {
63        match self {
64            ItemId::Auto { for_: id, .. }
65            | ItemId::Blanket { for_: id, .. }
66            | ItemId::DefId(id) => id.is_local(),
67        }
68    }
69
70    #[inline]
71    #[track_caller]
72    pub(crate) fn expect_def_id(self) -> DefId {
73        self.as_def_id()
74            .unwrap_or_else(|| panic!("ItemId::expect_def_id: `{self:?}` isn't a DefId"))
75    }
76
77    #[inline]
78    pub(crate) fn as_def_id(self) -> Option<DefId> {
79        match self {
80            ItemId::DefId(id) => Some(id),
81            _ => None,
82        }
83    }
84
85    #[inline]
86    pub(crate) fn as_local_def_id(self) -> Option<LocalDefId> {
87        self.as_def_id().and_then(|id| id.as_local())
88    }
89
90    #[inline]
91    pub(crate) fn krate(self) -> CrateNum {
92        match self {
93            ItemId::Auto { for_: id, .. }
94            | ItemId::Blanket { for_: id, .. }
95            | ItemId::DefId(id) => id.krate,
96        }
97    }
98}
99
100impl From<DefId> for ItemId {
101    fn from(id: DefId) -> Self {
102        Self::DefId(id)
103    }
104}
105
106/// The crate currently being documented.
107#[derive(Clone, Debug)]
108pub(crate) struct Crate {
109    pub(crate) module: Item,
110    /// Only here so that they can be filtered through the rustdoc passes.
111    pub(crate) external_traits: Box<FxIndexMap<DefId, Trait>>,
112}
113
114impl Crate {
115    pub(crate) fn name(&self, tcx: TyCtxt<'_>) -> Symbol {
116        ExternalCrate::LOCAL.name(tcx)
117    }
118
119    pub(crate) fn src(&self, tcx: TyCtxt<'_>) -> FileName {
120        ExternalCrate::LOCAL.src(tcx)
121    }
122}
123
124#[derive(Copy, Clone, Debug)]
125pub(crate) struct ExternalCrate {
126    pub(crate) crate_num: CrateNum,
127}
128
129impl ExternalCrate {
130    const LOCAL: Self = Self { crate_num: LOCAL_CRATE };
131
132    #[inline]
133    pub(crate) fn def_id(&self) -> DefId {
134        self.crate_num.as_def_id()
135    }
136
137    pub(crate) fn src(&self, tcx: TyCtxt<'_>) -> FileName {
138        let krate_span = tcx.def_span(self.def_id());
139        tcx.sess.source_map().span_to_filename(krate_span)
140    }
141
142    pub(crate) fn name(&self, tcx: TyCtxt<'_>) -> Symbol {
143        tcx.crate_name(self.crate_num)
144    }
145
146    pub(crate) fn src_root(&self, tcx: TyCtxt<'_>) -> PathBuf {
147        match self.src(tcx) {
148            FileName::Real(ref p) => match p.local_path_if_available().parent() {
149                Some(p) => p.to_path_buf(),
150                None => PathBuf::new(),
151            },
152            _ => PathBuf::new(),
153        }
154    }
155
156    /// Attempts to find where an external crate is located, given that we're
157    /// rendering into the specified source destination.
158    pub(crate) fn location(
159        &self,
160        extern_url: Option<&str>,
161        extern_url_takes_precedence: bool,
162        dst: &std::path::Path,
163        tcx: TyCtxt<'_>,
164    ) -> ExternalLocation {
165        use ExternalLocation::*;
166
167        fn to_remote(url: impl ToString) -> ExternalLocation {
168            let mut url = url.to_string();
169            if !url.ends_with('/') {
170                url.push('/');
171            }
172            Remote(url)
173        }
174
175        // See if there's documentation generated into the local directory
176        // WARNING: since rustdoc creates these directories as it generates documentation, this check is only accurate before rendering starts.
177        // Make sure to call `location()` by that time.
178        let local_location = dst.join(self.name(tcx).as_str());
179        if local_location.is_dir() {
180            return Local;
181        }
182
183        if extern_url_takes_precedence && let Some(url) = extern_url {
184            return to_remote(url);
185        }
186
187        // Failing that, see if there's an attribute specifying where to find this
188        // external crate
189        let did = self.crate_num.as_def_id();
190        tcx.get_attrs(did, sym::doc)
191            .flat_map(|attr| attr.meta_item_list().unwrap_or_default())
192            .filter(|a| a.has_name(sym::html_root_url))
193            .filter_map(|a| a.value_str())
194            .map(to_remote)
195            .next()
196            .or_else(|| extern_url.map(to_remote)) // NOTE: only matters if `extern_url_takes_precedence` is false
197            .unwrap_or(Unknown) // Well, at least we tried.
198    }
199
200    pub(crate) fn keywords(&self, tcx: TyCtxt<'_>) -> ThinVec<(DefId, Symbol)> {
201        let root = self.def_id();
202
203        let as_keyword = |res: Res<!>| {
204            if let Res::Def(DefKind::Mod, def_id) = res {
205                let mut keyword = None;
206                let meta_items = tcx
207                    .get_attrs(def_id, sym::doc)
208                    .flat_map(|attr| attr.meta_item_list().unwrap_or_default());
209                for meta in meta_items {
210                    if meta.has_name(sym::keyword)
211                        && let Some(v) = meta.value_str()
212                    {
213                        keyword = Some(v);
214                        break;
215                    }
216                }
217                return keyword.map(|p| (def_id, p));
218            }
219            None
220        };
221        if root.is_local() {
222            tcx.hir_root_module()
223                .item_ids
224                .iter()
225                .filter_map(|&id| {
226                    let item = tcx.hir_item(id);
227                    match item.kind {
228                        hir::ItemKind::Mod(..) => {
229                            as_keyword(Res::Def(DefKind::Mod, id.owner_id.to_def_id()))
230                        }
231                        _ => None,
232                    }
233                })
234                .collect()
235        } else {
236            tcx.module_children(root).iter().map(|item| item.res).filter_map(as_keyword).collect()
237        }
238    }
239
240    pub(crate) fn primitives(&self, tcx: TyCtxt<'_>) -> ThinVec<(DefId, PrimitiveType)> {
241        let root = self.def_id();
242
243        // Collect all inner modules which are tagged as implementations of
244        // primitives.
245        //
246        // Note that this loop only searches the top-level items of the crate,
247        // and this is intentional. If we were to search the entire crate for an
248        // item tagged with `#[rustc_doc_primitive]` then we would also have to
249        // search the entirety of external modules for items tagged
250        // `#[rustc_doc_primitive]`, which is a pretty inefficient process (decoding
251        // all that metadata unconditionally).
252        //
253        // In order to keep the metadata load under control, the
254        // `#[rustc_doc_primitive]` feature is explicitly designed to only allow the
255        // primitive tags to show up as the top level items in a crate.
256        //
257        // Also note that this does not attempt to deal with modules tagged
258        // duplicately for the same primitive. This is handled later on when
259        // rendering by delegating everything to a hash map.
260        let as_primitive = |res: Res<!>| {
261            let Res::Def(DefKind::Mod, def_id) = res else { return None };
262            tcx.get_attrs(def_id, sym::rustc_doc_primitive)
263                .map(|attr| {
264                    let attr_value = attr.value_str().expect("syntax should already be validated");
265                    let Some(prim) = PrimitiveType::from_symbol(attr_value) else {
266                        span_bug!(
267                            attr.span(),
268                            "primitive `{attr_value}` is not a member of `PrimitiveType`"
269                        );
270                    };
271
272                    (def_id, prim)
273                })
274                .next()
275        };
276
277        if root.is_local() {
278            tcx.hir_root_module()
279                .item_ids
280                .iter()
281                .filter_map(|&id| {
282                    let item = tcx.hir_item(id);
283                    match item.kind {
284                        hir::ItemKind::Mod(..) => {
285                            as_primitive(Res::Def(DefKind::Mod, id.owner_id.to_def_id()))
286                        }
287                        _ => None,
288                    }
289                })
290                .collect()
291        } else {
292            tcx.module_children(root).iter().map(|item| item.res).filter_map(as_primitive).collect()
293        }
294    }
295}
296
297/// Indicates where an external crate can be found.
298#[derive(Debug)]
299pub(crate) enum ExternalLocation {
300    /// Remote URL root of the external crate
301    Remote(String),
302    /// This external crate can be found in the local doc/ folder
303    Local,
304    /// The external crate could not be found.
305    Unknown,
306}
307
308/// Anything with a source location and set of attributes and, optionally, a
309/// name. That is, anything that can be documented. This doesn't correspond
310/// directly to the AST's concept of an item; it's a strict superset.
311#[derive(Clone)]
312pub(crate) struct Item {
313    pub(crate) inner: Box<ItemInner>,
314}
315
316// Why does the `Item`/`ItemInner` split exist? `Vec<Item>`s are common, and
317// without the split `Item` would be a large type (100+ bytes) which results in
318// lots of wasted space in the unused parts of a `Vec<Item>`. With the split,
319// `Item` is just 8 bytes, and the wasted space is avoided, at the cost of an
320// extra allocation per item. This is a performance win.
321#[derive(Clone)]
322pub(crate) struct ItemInner {
323    /// The name of this item.
324    /// Optional because not every item has a name, e.g. impls.
325    pub(crate) name: Option<Symbol>,
326    /// Information about this item that is specific to what kind of item it is.
327    /// E.g., struct vs enum vs function.
328    pub(crate) kind: ItemKind,
329    pub(crate) attrs: Attributes,
330    /// The effective stability, filled out by the `propagate-stability` pass.
331    pub(crate) stability: Option<Stability>,
332    pub(crate) item_id: ItemId,
333    /// This is the `LocalDefId` of the `use` statement if the item was inlined.
334    /// The crate metadata doesn't hold this information, so the `use` statement
335    /// always belongs to the current crate.
336    pub(crate) inline_stmt_id: Option<LocalDefId>,
337    pub(crate) cfg: Option<Arc<Cfg>>,
338}
339
340impl std::ops::Deref for Item {
341    type Target = ItemInner;
342    fn deref(&self) -> &ItemInner {
343        &self.inner
344    }
345}
346
347/// NOTE: this does NOT unconditionally print every item, to avoid thousands of lines of logs.
348/// If you want to see the debug output for attributes and the `kind` as well, use `{:#?}` instead of `{:?}`.
349impl fmt::Debug for Item {
350    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
351        let alternate = f.alternate();
352        // hand-picked fields that don't bloat the logs too much
353        let mut fmt = f.debug_struct("Item");
354        fmt.field("name", &self.name).field("item_id", &self.item_id);
355        // allow printing the full item if someone really wants to
356        if alternate {
357            fmt.field("attrs", &self.attrs).field("kind", &self.kind).field("cfg", &self.cfg);
358        } else {
359            fmt.field("kind", &self.type_());
360            fmt.field("docs", &self.doc_value());
361        }
362        fmt.finish()
363    }
364}
365
366pub(crate) fn rustc_span(def_id: DefId, tcx: TyCtxt<'_>) -> Span {
367    Span::new(def_id.as_local().map_or_else(
368        || tcx.def_span(def_id),
369        |local| tcx.hir_span_with_body(tcx.local_def_id_to_hir_id(local)),
370    ))
371}
372
373fn is_field_vis_inherited(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
374    let parent = tcx.parent(def_id);
375    match tcx.def_kind(parent) {
376        DefKind::Struct | DefKind::Union => false,
377        DefKind::Variant => true,
378        parent_kind => panic!("unexpected parent kind: {parent_kind:?}"),
379    }
380}
381
382impl Item {
383    /// Returns the effective stability of the item.
384    ///
385    /// This method should only be called after the `propagate-stability` pass has been run.
386    pub(crate) fn stability(&self, tcx: TyCtxt<'_>) -> Option<Stability> {
387        let stability = self.inner.stability;
388        debug_assert!(
389            stability.is_some()
390                || self.def_id().is_none_or(|did| tcx.lookup_stability(did).is_none()),
391            "missing stability for cleaned item: {self:?}",
392        );
393        stability
394    }
395
396    pub(crate) fn const_stability(&self, tcx: TyCtxt<'_>) -> Option<ConstStability> {
397        self.def_id().and_then(|did| tcx.lookup_const_stability(did))
398    }
399
400    pub(crate) fn deprecation(&self, tcx: TyCtxt<'_>) -> Option<Deprecation> {
401        self.def_id().and_then(|did| tcx.lookup_deprecation(did)).or_else(|| {
402            // `allowed_through_unstable_modules` is a bug-compatibility hack for old rustc
403            // versions; the paths that are exposed through it are "deprecated" because they
404            // were never supposed to work at all.
405            let stab = self.stability(tcx)?;
406            if let rustc_attr_parsing::StabilityLevel::Stable {
407                allowed_through_unstable_modules: Some(note),
408                ..
409            } = stab.level
410            {
411                Some(Deprecation {
412                    since: rustc_attr_parsing::DeprecatedSince::Unspecified,
413                    note: Some(note),
414                    suggestion: None,
415                })
416            } else {
417                None
418            }
419        })
420    }
421
422    pub(crate) fn inner_docs(&self, tcx: TyCtxt<'_>) -> bool {
423        self.item_id
424            .as_def_id()
425            .map(|did| inner_docs(tcx.get_attrs_unchecked(did)))
426            .unwrap_or(false)
427    }
428
429    pub(crate) fn span(&self, tcx: TyCtxt<'_>) -> Option<Span> {
430        let kind = match &self.kind {
431            ItemKind::StrippedItem(k) => k,
432            _ => &self.kind,
433        };
434        match kind {
435            ItemKind::ModuleItem(Module { span, .. }) => Some(*span),
436            ItemKind::ImplItem(box Impl { kind: ImplKind::Auto, .. }) => None,
437            ItemKind::ImplItem(box Impl { kind: ImplKind::Blanket(_), .. }) => {
438                if let ItemId::Blanket { impl_id, .. } = self.item_id {
439                    Some(rustc_span(impl_id, tcx))
440                } else {
441                    panic!("blanket impl item has non-blanket ID")
442                }
443            }
444            _ => self.def_id().map(|did| rustc_span(did, tcx)),
445        }
446    }
447
448    pub(crate) fn attr_span(&self, tcx: TyCtxt<'_>) -> rustc_span::Span {
449        span_of_fragments(&self.attrs.doc_strings)
450            .unwrap_or_else(|| self.span(tcx).map_or(DUMMY_SP, |span| span.inner()))
451    }
452
453    /// Combine all doc strings into a single value handling indentation and newlines as needed.
454    pub(crate) fn doc_value(&self) -> String {
455        self.attrs.doc_value()
456    }
457
458    /// Combine all doc strings into a single value handling indentation and newlines as needed.
459    /// Returns `None` is there's no documentation at all, and `Some("")` if there is some
460    /// documentation but it is empty (e.g. `#[doc = ""]`).
461    pub(crate) fn opt_doc_value(&self) -> Option<String> {
462        self.attrs.opt_doc_value()
463    }
464
465    pub(crate) fn from_def_id_and_parts(
466        def_id: DefId,
467        name: Option<Symbol>,
468        kind: ItemKind,
469        cx: &mut DocContext<'_>,
470    ) -> Item {
471        let hir_attrs = cx.tcx.get_attrs_unchecked(def_id);
472
473        Self::from_def_id_and_attrs_and_parts(
474            def_id,
475            name,
476            kind,
477            Attributes::from_hir(hir_attrs),
478            extract_cfg_from_attrs(hir_attrs.iter(), cx.tcx, &cx.cache.hidden_cfg),
479        )
480    }
481
482    pub(crate) fn from_def_id_and_attrs_and_parts(
483        def_id: DefId,
484        name: Option<Symbol>,
485        kind: ItemKind,
486        attrs: Attributes,
487        cfg: Option<Arc<Cfg>>,
488    ) -> Item {
489        trace!("name={name:?}, def_id={def_id:?} cfg={cfg:?}");
490
491        Item {
492            inner: Box::new(ItemInner {
493                item_id: def_id.into(),
494                kind,
495                attrs,
496                stability: None,
497                name,
498                cfg,
499                inline_stmt_id: None,
500            }),
501        }
502    }
503
504    pub(crate) fn links(&self, cx: &Context<'_>) -> Vec<RenderedLink> {
505        use crate::html::format::{href, link_tooltip};
506
507        let Some(links) = cx.cache().intra_doc_links.get(&self.item_id) else { return vec![] };
508        links
509            .iter()
510            .filter_map(|ItemLink { link: s, link_text, page_id: id, fragment }| {
511                debug!(?id);
512                if let Ok((mut href, ..)) = href(*id, cx) {
513                    debug!(?href);
514                    if let Some(ref fragment) = *fragment {
515                        fragment.render(&mut href, cx.tcx())
516                    }
517                    Some(RenderedLink {
518                        original_text: s.clone(),
519                        new_text: link_text.clone(),
520                        tooltip: link_tooltip(*id, fragment, cx),
521                        href,
522                    })
523                } else {
524                    None
525                }
526            })
527            .collect()
528    }
529
530    /// Find a list of all link names, without finding their href.
531    ///
532    /// This is used for generating summary text, which does not include
533    /// the link text, but does need to know which `[]`-bracketed names
534    /// are actually links.
535    pub(crate) fn link_names(&self, cache: &Cache) -> Vec<RenderedLink> {
536        let Some(links) = cache.intra_doc_links.get(&self.item_id) else {
537            return vec![];
538        };
539        links
540            .iter()
541            .map(|ItemLink { link: s, link_text, .. }| RenderedLink {
542                original_text: s.clone(),
543                new_text: link_text.clone(),
544                href: String::new(),
545                tooltip: String::new(),
546            })
547            .collect()
548    }
549
550    pub(crate) fn is_crate(&self) -> bool {
551        self.is_mod() && self.def_id().is_some_and(|did| did.is_crate_root())
552    }
553    pub(crate) fn is_mod(&self) -> bool {
554        self.type_() == ItemType::Module
555    }
556    pub(crate) fn is_struct(&self) -> bool {
557        self.type_() == ItemType::Struct
558    }
559    pub(crate) fn is_enum(&self) -> bool {
560        self.type_() == ItemType::Enum
561    }
562    pub(crate) fn is_variant(&self) -> bool {
563        self.type_() == ItemType::Variant
564    }
565    pub(crate) fn is_associated_type(&self) -> bool {
566        matches!(self.kind, AssocTypeItem(..) | StrippedItem(box AssocTypeItem(..)))
567    }
568    pub(crate) fn is_required_associated_type(&self) -> bool {
569        matches!(self.kind, RequiredAssocTypeItem(..) | StrippedItem(box RequiredAssocTypeItem(..)))
570    }
571    pub(crate) fn is_associated_const(&self) -> bool {
572        matches!(self.kind, ProvidedAssocConstItem(..) | ImplAssocConstItem(..) | StrippedItem(box (ProvidedAssocConstItem(..) | ImplAssocConstItem(..))))
573    }
574    pub(crate) fn is_required_associated_const(&self) -> bool {
575        matches!(self.kind, RequiredAssocConstItem(..) | StrippedItem(box RequiredAssocConstItem(..)))
576    }
577    pub(crate) fn is_method(&self) -> bool {
578        self.type_() == ItemType::Method
579    }
580    pub(crate) fn is_ty_method(&self) -> bool {
581        self.type_() == ItemType::TyMethod
582    }
583    pub(crate) fn is_primitive(&self) -> bool {
584        self.type_() == ItemType::Primitive
585    }
586    pub(crate) fn is_union(&self) -> bool {
587        self.type_() == ItemType::Union
588    }
589    pub(crate) fn is_import(&self) -> bool {
590        self.type_() == ItemType::Import
591    }
592    pub(crate) fn is_extern_crate(&self) -> bool {
593        self.type_() == ItemType::ExternCrate
594    }
595    pub(crate) fn is_keyword(&self) -> bool {
596        self.type_() == ItemType::Keyword
597    }
598    pub(crate) fn is_stripped(&self) -> bool {
599        match self.kind {
600            StrippedItem(..) => true,
601            ImportItem(ref i) => !i.should_be_displayed,
602            _ => false,
603        }
604    }
605    pub(crate) fn has_stripped_entries(&self) -> Option<bool> {
606        match self.kind {
607            StructItem(ref struct_) => Some(struct_.has_stripped_entries()),
608            UnionItem(ref union_) => Some(union_.has_stripped_entries()),
609            EnumItem(ref enum_) => Some(enum_.has_stripped_entries()),
610            VariantItem(ref v) => v.has_stripped_entries(),
611            _ => None,
612        }
613    }
614
615    pub(crate) fn stability_class(&self, tcx: TyCtxt<'_>) -> Option<String> {
616        self.stability(tcx).as_ref().and_then(|s| {
617            let mut classes = Vec::with_capacity(2);
618
619            if s.is_unstable() {
620                classes.push("unstable");
621            }
622
623            // FIXME: what about non-staged API items that are deprecated?
624            if self.deprecation(tcx).is_some() {
625                classes.push("deprecated");
626            }
627
628            if !classes.is_empty() { Some(classes.join(" ")) } else { None }
629        })
630    }
631
632    pub(crate) fn stable_since(&self, tcx: TyCtxt<'_>) -> Option<StableSince> {
633        self.stability(tcx).and_then(|stability| stability.stable_since())
634    }
635
636    pub(crate) fn is_non_exhaustive(&self) -> bool {
637        self.attrs.other_attrs.iter().any(|a| a.has_name(sym::non_exhaustive))
638    }
639
640    /// Returns a documentation-level item type from the item.
641    pub(crate) fn type_(&self) -> ItemType {
642        ItemType::from(self)
643    }
644
645    pub(crate) fn is_default(&self) -> bool {
646        match self.kind {
647            ItemKind::MethodItem(_, Some(defaultness)) => {
648                defaultness.has_value() && !defaultness.is_final()
649            }
650            _ => false,
651        }
652    }
653
654    /// Returns a `FnHeader` if `self` is a function item, otherwise returns `None`.
655    pub(crate) fn fn_header(&self, tcx: TyCtxt<'_>) -> Option<hir::FnHeader> {
656        fn build_fn_header(
657            def_id: DefId,
658            tcx: TyCtxt<'_>,
659            asyncness: ty::Asyncness,
660        ) -> hir::FnHeader {
661            let sig = tcx.fn_sig(def_id).skip_binder();
662            let constness = if tcx.is_const_fn(def_id) {
663                hir::Constness::Const
664            } else {
665                hir::Constness::NotConst
666            };
667            let asyncness = match asyncness {
668                ty::Asyncness::Yes => hir::IsAsync::Async(DUMMY_SP),
669                ty::Asyncness::No => hir::IsAsync::NotAsync,
670            };
671            hir::FnHeader {
672                safety: if tcx.codegen_fn_attrs(def_id).safe_target_features {
673                    hir::HeaderSafety::SafeTargetFeatures
674                } else {
675                    sig.safety().into()
676                },
677                abi: sig.abi(),
678                constness,
679                asyncness,
680            }
681        }
682        let header = match self.kind {
683            ItemKind::ForeignFunctionItem(_, safety) => {
684                let def_id = self.def_id().unwrap();
685                let abi = tcx.fn_sig(def_id).skip_binder().abi();
686                hir::FnHeader {
687                    safety: if tcx.codegen_fn_attrs(def_id).safe_target_features {
688                        hir::HeaderSafety::SafeTargetFeatures
689                    } else {
690                        safety.into()
691                    },
692                    abi,
693                    constness: if tcx.is_const_fn(def_id) {
694                        hir::Constness::Const
695                    } else {
696                        hir::Constness::NotConst
697                    },
698                    asyncness: hir::IsAsync::NotAsync,
699                }
700            }
701            ItemKind::FunctionItem(_)
702            | ItemKind::MethodItem(_, _)
703            | ItemKind::RequiredMethodItem(_) => {
704                let def_id = self.def_id().unwrap();
705                build_fn_header(def_id, tcx, tcx.asyncness(def_id))
706            }
707            _ => return None,
708        };
709        Some(header)
710    }
711
712    /// Returns the visibility of the current item. If the visibility is "inherited", then `None`
713    /// is returned.
714    pub(crate) fn visibility(&self, tcx: TyCtxt<'_>) -> Option<Visibility<DefId>> {
715        let def_id = match self.item_id {
716            // Anything but DefId *shouldn't* matter, but return a reasonable value anyway.
717            ItemId::Auto { .. } | ItemId::Blanket { .. } => return None,
718            ItemId::DefId(def_id) => def_id,
719        };
720
721        match self.kind {
722            // Primitives and Keywords are written in the source code as private modules.
723            // The modules need to be private so that nobody actually uses them, but the
724            // keywords and primitives that they are documenting are public.
725            ItemKind::KeywordItem | ItemKind::PrimitiveItem(_) => return Some(Visibility::Public),
726            // Variant fields inherit their enum's visibility.
727            StructFieldItem(..) if is_field_vis_inherited(tcx, def_id) => {
728                return None;
729            }
730            // Variants always inherit visibility
731            VariantItem(..) | ImplItem(..) => return None,
732            // Trait items inherit the trait's visibility
733            RequiredAssocConstItem(..)
734            | ProvidedAssocConstItem(..)
735            | ImplAssocConstItem(..)
736            | AssocTypeItem(..)
737            | RequiredAssocTypeItem(..)
738            | RequiredMethodItem(..)
739            | MethodItem(..) => {
740                let assoc_item = tcx.associated_item(def_id);
741                let is_trait_item = match assoc_item.container {
742                    ty::AssocItemContainer::Trait => true,
743                    ty::AssocItemContainer::Impl => {
744                        // Trait impl items always inherit the impl's visibility --
745                        // we don't want to show `pub`.
746                        tcx.impl_trait_ref(tcx.parent(assoc_item.def_id)).is_some()
747                    }
748                };
749                if is_trait_item {
750                    return None;
751                }
752            }
753            _ => {}
754        }
755        let def_id = match self.inline_stmt_id {
756            Some(inlined) => inlined.to_def_id(),
757            None => def_id,
758        };
759        Some(tcx.visibility(def_id))
760    }
761
762    pub(crate) fn attributes(&self, tcx: TyCtxt<'_>, cache: &Cache, is_json: bool) -> Vec<String> {
763        const ALLOWED_ATTRIBUTES: &[Symbol] =
764            &[sym::export_name, sym::link_section, sym::no_mangle, sym::non_exhaustive];
765
766        use rustc_abi::IntegerType;
767
768        let mut attrs: Vec<String> = self
769            .attrs
770            .other_attrs
771            .iter()
772            .filter_map(|attr| {
773                if is_json {
774                    match attr {
775                        hir::Attribute::Parsed(AttributeKind::Deprecation { .. }) => {
776                            // rustdoc-json stores this in `Item::deprecation`, so we
777                            // don't want it it `Item::attrs`.
778                            None
779                        }
780                        rustc_hir::Attribute::Parsed(rustc_attr_parsing::AttributeKind::Repr(
781                            ..,
782                        )) => {
783                            // We have separate pretty-printing logic for `#[repr(..)]` attributes.
784                            // For example, there are circumstances where `#[repr(transparent)]`
785                            // is applied but should not be publicly shown in rustdoc
786                            // because it isn't public API.
787                            None
788                        }
789                        _ => Some(rustc_hir_pretty::attribute_to_string(&tcx, attr)),
790                    }
791                } else if ALLOWED_ATTRIBUTES.contains(&attr.name_or_empty()) {
792                    Some(
793                        rustc_hir_pretty::attribute_to_string(&tcx, attr)
794                            .replace("\\\n", "")
795                            .replace('\n', "")
796                            .replace("  ", " "),
797                    )
798                } else {
799                    None
800                }
801            })
802            .collect();
803
804        // Add #[repr(...)]
805        if let Some(def_id) = self.def_id()
806            && let ItemType::Struct | ItemType::Enum | ItemType::Union = self.type_()
807        {
808            let adt = tcx.adt_def(def_id);
809            let repr = adt.repr();
810            let mut out = Vec::new();
811            if repr.c() {
812                out.push("C");
813            }
814            if repr.transparent() {
815                // Render `repr(transparent)` iff the non-1-ZST field is public or at least one
816                // field is public in case all fields are 1-ZST fields.
817                let render_transparent = cache.document_private
818                    || adt
819                        .all_fields()
820                        .find(|field| {
821                            let ty =
822                                field.ty(tcx, ty::GenericArgs::identity_for_item(tcx, field.did));
823                            tcx.layout_of(
824                                ty::TypingEnv::post_analysis(tcx, field.did).as_query_input(ty),
825                            )
826                            .is_ok_and(|layout| !layout.is_1zst())
827                        })
828                        .map_or_else(
829                            || adt.all_fields().any(|field| field.vis.is_public()),
830                            |field| field.vis.is_public(),
831                        );
832
833                if render_transparent {
834                    out.push("transparent");
835                }
836            }
837            if repr.simd() {
838                out.push("simd");
839            }
840            let pack_s;
841            if let Some(pack) = repr.pack {
842                pack_s = format!("packed({})", pack.bytes());
843                out.push(&pack_s);
844            }
845            let align_s;
846            if let Some(align) = repr.align {
847                align_s = format!("align({})", align.bytes());
848                out.push(&align_s);
849            }
850            let int_s;
851            if let Some(int) = repr.int {
852                int_s = match int {
853                    IntegerType::Pointer(is_signed) => {
854                        format!("{}size", if is_signed { 'i' } else { 'u' })
855                    }
856                    IntegerType::Fixed(size, is_signed) => {
857                        format!("{}{}", if is_signed { 'i' } else { 'u' }, size.size().bytes() * 8)
858                    }
859                };
860                out.push(&int_s);
861            }
862            if !out.is_empty() {
863                attrs.push(format!("#[repr({})]", out.join(", ")));
864            }
865        }
866        attrs
867    }
868
869    pub fn is_doc_hidden(&self) -> bool {
870        self.attrs.is_doc_hidden()
871    }
872
873    pub fn def_id(&self) -> Option<DefId> {
874        self.item_id.as_def_id()
875    }
876}
877
878#[derive(Clone, Debug)]
879pub(crate) enum ItemKind {
880    ExternCrateItem {
881        /// The crate's name, *not* the name it's imported as.
882        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    /// A required method in a trait declaration meaning it's only a function signature.
896    RequiredMethodItem(Box<Function>),
897    /// A method in a trait impl or a provided method in a trait declaration.
898    ///
899    /// Compared to [RequiredMethodItem], it also contains a method body.
900    MethodItem(Box<Function>, Option<hir::Defaultness>),
901    StructFieldItem(Type),
902    VariantItem(Variant),
903    /// `fn`s from an extern block
904    ForeignFunctionItem(Box<Function>, hir::Safety),
905    /// `static`s from an extern block
906    ForeignStaticItem(Static, hir::Safety),
907    /// `type`s from an extern block
908    ForeignTypeItem,
909    MacroItem(Macro),
910    ProcMacroItem(ProcMacro),
911    PrimitiveItem(PrimitiveType),
912    /// A required associated constant in a trait declaration.
913    RequiredAssocConstItem(Generics, Box<Type>),
914    ConstantItem(Box<Constant>),
915    /// An associated constant in a trait declaration with provided default value.
916    ProvidedAssocConstItem(Box<Constant>),
917    /// An associated constant in an inherent impl or trait impl.
918    ImplAssocConstItem(Box<Constant>),
919    /// A required associated type in a trait declaration.
920    ///
921    /// The bounds may be non-empty if there is a `where` clause.
922    RequiredAssocTypeItem(Generics, Vec<GenericBound>),
923    /// An associated type in a trait impl or a provided one in a trait declaration.
924    AssocTypeItem(Box<TypeAlias>, Vec<GenericBound>),
925    /// An item that has been stripped by a rustdoc pass
926    StrippedItem(Box<ItemKind>),
927    KeywordItem,
928}
929
930impl ItemKind {
931    /// Some items contain others such as structs (for their fields) and Enums
932    /// (for their variants). This method returns those contained items.
933    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    /// Returns `true` if this item does not appear inside an impl block.
973    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            doc_cfg.fold(Cfg::True, |mut cfg, item| {
1041                if let Some(cfg_mi) =
1042                    item.meta_item().and_then(|item| rustc_expand::config::parse_cfg(item, sess))
1043                {
1044                    // The result is unused here but we can gate unstable predicates
1045                    rustc_attr_parsing::cfg_matches(
1046                        cfg_mi,
1047                        tcx.sess,
1048                        rustc_ast::CRATE_NODE_ID,
1049                        Some(tcx.features()),
1050                    );
1051                    match Cfg::parse(cfg_mi) {
1052                        Ok(new_cfg) => cfg &= new_cfg,
1053                        Err(e) => {
1054                            sess.dcx().span_err(e.span, e.msg);
1055                        }
1056                    }
1057                }
1058                cfg
1059            })
1060        } else if doc_auto_cfg_active {
1061            // If there is no `doc(cfg())`, then we retrieve the `cfg()` attributes (because
1062            // `doc(cfg())` overrides `cfg()`).
1063            attrs
1064                .clone()
1065                .filter(|attr| attr.has_name(sym::cfg_trace))
1066                .filter_map(|attr| single(attr.meta_item_list()?))
1067                .filter_map(|attr| Cfg::parse_without(attr.meta_item()?, hidden_cfg).ok().flatten())
1068                .fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg)
1069        } else {
1070            Cfg::True
1071        }
1072    } else {
1073        Cfg::True
1074    };
1075
1076    // treat #[target_feature(enable = "feat")] attributes as if they were
1077    // #[doc(cfg(target_feature = "feat"))] attributes as well
1078    for attr in hir_attr_lists(attrs, sym::target_feature) {
1079        if attr.has_name(sym::enable) && attr.value_str().is_some() {
1080            // Clone `enable = "feat"`, change to `target_feature = "feat"`.
1081            // Unwrap is safe because `value_str` succeeded above.
1082            let mut meta = attr.meta_item().unwrap().clone();
1083            meta.path = ast::Path::from_ident(Ident::with_dummy_span(sym::target_feature));
1084
1085            if let Ok(feat_cfg) = Cfg::parse(&ast::MetaItemInner::MetaItem(meta)) {
1086                cfg &= feat_cfg;
1087            }
1088        }
1089    }
1090
1091    if cfg == Cfg::True { None } else { Some(Arc::new(cfg)) }
1092}
1093
1094pub(crate) trait NestedAttributesExt {
1095    /// Returns `true` if the attribute list contains a specific `word`
1096    fn has_word(self, word: Symbol) -> bool
1097    where
1098        Self: Sized,
1099    {
1100        <Self as NestedAttributesExt>::get_word_attr(self, word).is_some()
1101    }
1102
1103    /// Returns `Some(attr)` if the attribute list contains 'attr'
1104    /// corresponding to a specific `word`
1105    fn get_word_attr(self, word: Symbol) -> Option<ast::MetaItemInner>;
1106}
1107
1108impl<I: Iterator<Item = ast::MetaItemInner>> NestedAttributesExt for I {
1109    fn get_word_attr(mut self, word: Symbol) -> Option<ast::MetaItemInner> {
1110        self.find(|attr| attr.is_word() && attr.has_name(word))
1111    }
1112}
1113
1114/// A link that has not yet been rendered.
1115///
1116/// This link will be turned into a rendered link by [`Item::links`].
1117#[derive(Clone, Debug, PartialEq, Eq, Hash)]
1118pub(crate) struct ItemLink {
1119    /// The original link written in the markdown
1120    pub(crate) link: Box<str>,
1121    /// The link text displayed in the HTML.
1122    ///
1123    /// This may not be the same as `link` if there was a disambiguator
1124    /// in an intra-doc link (e.g. \[`fn@f`\])
1125    pub(crate) link_text: Box<str>,
1126    /// The `DefId` of the Item whose **HTML Page** contains the item being
1127    /// linked to. This will be different to `item_id` on item's that don't
1128    /// have their own page, such as struct fields and enum variants.
1129    pub(crate) page_id: DefId,
1130    /// The url fragment to append to the link
1131    pub(crate) fragment: Option<UrlFragment>,
1132}
1133
1134pub struct RenderedLink {
1135    /// The text the link was original written as.
1136    ///
1137    /// This could potentially include disambiguators and backticks.
1138    pub(crate) original_text: Box<str>,
1139    /// The text to display in the HTML
1140    pub(crate) new_text: Box<str>,
1141    /// The URL to put in the `href`
1142    pub(crate) href: String,
1143    /// The tooltip.
1144    pub(crate) tooltip: String,
1145}
1146
1147/// The attributes on an [`Item`], including attributes like `#[derive(...)]` and `#[inline]`,
1148/// as well as doc comments.
1149#[derive(Clone, Debug, Default)]
1150pub(crate) struct Attributes {
1151    pub(crate) doc_strings: Vec<DocFragment>,
1152    pub(crate) other_attrs: ThinVec<hir::Attribute>,
1153}
1154
1155impl Attributes {
1156    pub(crate) fn lists(&self, name: Symbol) -> impl Iterator<Item = ast::MetaItemInner> {
1157        hir_attr_lists(&self.other_attrs[..], name)
1158    }
1159
1160    pub(crate) fn has_doc_flag(&self, flag: Symbol) -> bool {
1161        for attr in &self.other_attrs {
1162            if !attr.has_name(sym::doc) {
1163                continue;
1164            }
1165
1166            if let Some(items) = attr.meta_item_list()
1167                && items.iter().filter_map(|i| i.meta_item()).any(|it| it.has_name(flag))
1168            {
1169                return true;
1170            }
1171        }
1172
1173        false
1174    }
1175
1176    pub(crate) fn is_doc_hidden(&self) -> bool {
1177        self.has_doc_flag(sym::hidden)
1178    }
1179
1180    pub(crate) fn from_hir(attrs: &[hir::Attribute]) -> Attributes {
1181        Attributes::from_hir_iter(attrs.iter().map(|attr| (attr, None)), false)
1182    }
1183
1184    pub(crate) fn from_hir_with_additional(
1185        attrs: &[hir::Attribute],
1186        (additional_attrs, def_id): (&[hir::Attribute], DefId),
1187    ) -> Attributes {
1188        // Additional documentation should be shown before the original documentation.
1189        let attrs1 = additional_attrs.iter().map(|attr| (attr, Some(def_id)));
1190        let attrs2 = attrs.iter().map(|attr| (attr, None));
1191        Attributes::from_hir_iter(attrs1.chain(attrs2), false)
1192    }
1193
1194    pub(crate) fn from_hir_iter<'a>(
1195        attrs: impl Iterator<Item = (&'a hir::Attribute, Option<DefId>)>,
1196        doc_only: bool,
1197    ) -> Attributes {
1198        let (doc_strings, other_attrs) = attrs_to_doc_fragments(attrs, doc_only);
1199        Attributes { doc_strings, other_attrs }
1200    }
1201
1202    /// Combine all doc strings into a single value handling indentation and newlines as needed.
1203    pub(crate) fn doc_value(&self) -> String {
1204        self.opt_doc_value().unwrap_or_default()
1205    }
1206
1207    /// Combine all doc strings into a single value handling indentation and newlines as needed.
1208    /// Returns `None` is there's no documentation at all, and `Some("")` if there is some
1209    /// documentation but it is empty (e.g. `#[doc = ""]`).
1210    pub(crate) fn opt_doc_value(&self) -> Option<String> {
1211        (!self.doc_strings.is_empty()).then(|| {
1212            let mut res = String::new();
1213            for frag in &self.doc_strings {
1214                add_doc_fragment(&mut res, frag);
1215            }
1216            res.pop();
1217            res
1218        })
1219    }
1220
1221    pub(crate) fn get_doc_aliases(&self) -> Box<[Symbol]> {
1222        let mut aliases = FxIndexSet::default();
1223
1224        for attr in
1225            hir_attr_lists(&self.other_attrs[..], sym::doc).filter(|a| a.has_name(sym::alias))
1226        {
1227            if let Some(values) = attr.meta_item_list() {
1228                for l in values {
1229                    if let Some(lit) = l.lit()
1230                        && let ast::LitKind::Str(s, _) = lit.kind
1231                    {
1232                        aliases.insert(s);
1233                    }
1234                }
1235            } else if let Some(value) = attr.value_str() {
1236                aliases.insert(value);
1237            }
1238        }
1239        aliases.into_iter().collect::<Vec<_>>().into()
1240    }
1241}
1242
1243#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1244pub(crate) enum GenericBound {
1245    TraitBound(PolyTrait, hir::TraitBoundModifiers),
1246    Outlives(Lifetime),
1247    /// `use<'a, T>` precise-capturing bound syntax
1248    Use(Vec<PreciseCapturingArg>),
1249}
1250
1251impl GenericBound {
1252    pub(crate) fn sized(cx: &mut DocContext<'_>) -> GenericBound {
1253        Self::sized_with(cx, hir::TraitBoundModifiers::NONE)
1254    }
1255
1256    pub(crate) fn maybe_sized(cx: &mut DocContext<'_>) -> GenericBound {
1257        Self::sized_with(
1258            cx,
1259            hir::TraitBoundModifiers {
1260                polarity: hir::BoundPolarity::Maybe(DUMMY_SP),
1261                constness: hir::BoundConstness::Never,
1262            },
1263        )
1264    }
1265
1266    fn sized_with(cx: &mut DocContext<'_>, modifiers: hir::TraitBoundModifiers) -> GenericBound {
1267        let did = cx.tcx.require_lang_item(LangItem::Sized, None);
1268        let empty = ty::Binder::dummy(ty::GenericArgs::empty());
1269        let path = clean_middle_path(cx, did, false, ThinVec::new(), empty);
1270        inline::record_extern_fqn(cx, did, ItemType::Trait);
1271        GenericBound::TraitBound(PolyTrait { trait_: path, generic_params: Vec::new() }, modifiers)
1272    }
1273
1274    pub(crate) fn is_trait_bound(&self) -> bool {
1275        matches!(self, Self::TraitBound(..))
1276    }
1277
1278    pub(crate) fn is_sized_bound(&self, cx: &DocContext<'_>) -> bool {
1279        if let GenericBound::TraitBound(
1280            PolyTrait { ref trait_, .. },
1281            rustc_hir::TraitBoundModifiers::NONE,
1282        ) = *self
1283            && Some(trait_.def_id()) == cx.tcx.lang_items().sized_trait()
1284        {
1285            return true;
1286        }
1287        false
1288    }
1289
1290    pub(crate) fn get_trait_path(&self) -> Option<Path> {
1291        if let GenericBound::TraitBound(PolyTrait { ref trait_, .. }, _) = *self {
1292            Some(trait_.clone())
1293        } else {
1294            None
1295        }
1296    }
1297}
1298
1299#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
1300pub(crate) struct Lifetime(pub Symbol);
1301
1302impl Lifetime {
1303    pub(crate) fn statik() -> Lifetime {
1304        Lifetime(kw::StaticLifetime)
1305    }
1306
1307    pub(crate) fn elided() -> Lifetime {
1308        Lifetime(kw::UnderscoreLifetime)
1309    }
1310}
1311
1312#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
1313pub(crate) enum PreciseCapturingArg {
1314    Lifetime(Lifetime),
1315    Param(Symbol),
1316}
1317
1318impl PreciseCapturingArg {
1319    pub(crate) fn name(self) -> Symbol {
1320        match self {
1321            PreciseCapturingArg::Lifetime(lt) => lt.0,
1322            PreciseCapturingArg::Param(param) => param,
1323        }
1324    }
1325}
1326
1327#[derive(Clone, PartialEq, Eq, Hash, Debug)]
1328pub(crate) enum WherePredicate {
1329    BoundPredicate { ty: Type, bounds: Vec<GenericBound>, bound_params: Vec<GenericParamDef> },
1330    RegionPredicate { lifetime: Lifetime, bounds: Vec<GenericBound> },
1331    EqPredicate { lhs: Type, rhs: Term },
1332}
1333
1334impl WherePredicate {
1335    pub(crate) fn get_bounds(&self) -> Option<&[GenericBound]> {
1336        match *self {
1337            WherePredicate::BoundPredicate { ref bounds, .. } => Some(bounds),
1338            WherePredicate::RegionPredicate { ref bounds, .. } => Some(bounds),
1339            _ => None,
1340        }
1341    }
1342}
1343
1344#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1345pub(crate) enum GenericParamDefKind {
1346    Lifetime { outlives: ThinVec<Lifetime> },
1347    Type { bounds: ThinVec<GenericBound>, default: Option<Box<Type>>, synthetic: bool },
1348    // Option<Box<String>> makes this type smaller than `Option<String>` would.
1349    Const { ty: Box<Type>, default: Option<Box<String>>, synthetic: bool },
1350}
1351
1352impl GenericParamDefKind {
1353    pub(crate) fn is_type(&self) -> bool {
1354        matches!(self, GenericParamDefKind::Type { .. })
1355    }
1356}
1357
1358#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1359pub(crate) struct GenericParamDef {
1360    pub(crate) name: Symbol,
1361    pub(crate) def_id: DefId,
1362    pub(crate) kind: GenericParamDefKind,
1363}
1364
1365impl GenericParamDef {
1366    pub(crate) fn lifetime(def_id: DefId, name: Symbol) -> Self {
1367        Self { name, def_id, kind: GenericParamDefKind::Lifetime { outlives: ThinVec::new() } }
1368    }
1369
1370    pub(crate) fn is_synthetic_param(&self) -> bool {
1371        match self.kind {
1372            GenericParamDefKind::Lifetime { .. } | GenericParamDefKind::Const { .. } => false,
1373            GenericParamDefKind::Type { synthetic, .. } => synthetic,
1374        }
1375    }
1376
1377    pub(crate) fn is_type(&self) -> bool {
1378        self.kind.is_type()
1379    }
1380
1381    pub(crate) fn get_bounds(&self) -> Option<&[GenericBound]> {
1382        match self.kind {
1383            GenericParamDefKind::Type { ref bounds, .. } => Some(bounds),
1384            _ => None,
1385        }
1386    }
1387}
1388
1389// maybe use a Generic enum and use Vec<Generic>?
1390#[derive(Clone, PartialEq, Eq, Hash, Debug, Default)]
1391pub(crate) struct Generics {
1392    pub(crate) params: ThinVec<GenericParamDef>,
1393    pub(crate) where_predicates: ThinVec<WherePredicate>,
1394}
1395
1396impl Generics {
1397    pub(crate) fn is_empty(&self) -> bool {
1398        self.params.is_empty() && self.where_predicates.is_empty()
1399    }
1400}
1401
1402#[derive(Clone, Debug)]
1403pub(crate) struct Function {
1404    pub(crate) decl: FnDecl,
1405    pub(crate) generics: Generics,
1406}
1407
1408#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1409pub(crate) struct FnDecl {
1410    pub(crate) inputs: Arguments,
1411    pub(crate) output: Type,
1412    pub(crate) c_variadic: bool,
1413}
1414
1415impl FnDecl {
1416    pub(crate) fn receiver_type(&self) -> Option<&Type> {
1417        self.inputs.values.first().and_then(|v| v.to_receiver())
1418    }
1419}
1420
1421#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1422pub(crate) struct Arguments {
1423    pub(crate) values: Vec<Argument>,
1424}
1425
1426#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1427pub(crate) struct Argument {
1428    pub(crate) type_: Type,
1429    pub(crate) name: Symbol,
1430    /// This field is used to represent "const" arguments from the `rustc_legacy_const_generics`
1431    /// feature. More information in <https://github.com/rust-lang/rust/issues/83167>.
1432    pub(crate) is_const: bool,
1433}
1434
1435impl Argument {
1436    pub(crate) fn to_receiver(&self) -> Option<&Type> {
1437        if self.name == kw::SelfLower { Some(&self.type_) } else { None }
1438    }
1439}
1440
1441#[derive(Clone, Debug)]
1442pub(crate) struct Trait {
1443    pub(crate) def_id: DefId,
1444    pub(crate) items: Vec<Item>,
1445    pub(crate) generics: Generics,
1446    pub(crate) bounds: Vec<GenericBound>,
1447}
1448
1449impl Trait {
1450    pub(crate) fn is_auto(&self, tcx: TyCtxt<'_>) -> bool {
1451        tcx.trait_is_auto(self.def_id)
1452    }
1453    pub(crate) fn is_notable_trait(&self, tcx: TyCtxt<'_>) -> bool {
1454        tcx.is_doc_notable_trait(self.def_id)
1455    }
1456    pub(crate) fn safety(&self, tcx: TyCtxt<'_>) -> hir::Safety {
1457        tcx.trait_def(self.def_id).safety
1458    }
1459    pub(crate) fn is_dyn_compatible(&self, tcx: TyCtxt<'_>) -> bool {
1460        tcx.is_dyn_compatible(self.def_id)
1461    }
1462}
1463
1464#[derive(Clone, Debug)]
1465pub(crate) struct TraitAlias {
1466    pub(crate) generics: Generics,
1467    pub(crate) bounds: Vec<GenericBound>,
1468}
1469
1470/// A trait reference, which may have higher ranked lifetimes.
1471#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1472pub(crate) struct PolyTrait {
1473    pub(crate) trait_: Path,
1474    pub(crate) generic_params: Vec<GenericParamDef>,
1475}
1476
1477/// Rustdoc's representation of types, mostly based on the [`hir::Ty`].
1478#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1479pub(crate) enum Type {
1480    /// A named type, which could be a trait.
1481    ///
1482    /// This is mostly Rustdoc's version of [`hir::Path`].
1483    /// It has to be different because Rustdoc's [`PathSegment`] can contain cleaned generics.
1484    Path {
1485        path: Path,
1486    },
1487    /// A `dyn Trait` object: `dyn for<'a> Trait<'a> + Send + 'static`
1488    DynTrait(Vec<PolyTrait>, Option<Lifetime>),
1489    /// A type parameter.
1490    Generic(Symbol),
1491    /// The `Self` type.
1492    SelfTy,
1493    /// A primitive (aka, builtin) type.
1494    Primitive(PrimitiveType),
1495    /// A function pointer: `extern "ABI" fn(...) -> ...`
1496    BareFunction(Box<BareFunctionDecl>),
1497    /// A tuple type: `(i32, &str)`.
1498    Tuple(Vec<Type>),
1499    /// A slice type (does *not* include the `&`): `[i32]`
1500    Slice(Box<Type>),
1501    /// An array type.
1502    ///
1503    /// The `String` field is a stringified version of the array's length parameter.
1504    Array(Box<Type>, Box<str>),
1505    Pat(Box<Type>, Box<str>),
1506    /// A raw pointer type: `*const i32`, `*mut i32`
1507    RawPointer(Mutability, Box<Type>),
1508    /// A reference type: `&i32`, `&'a mut Foo`
1509    BorrowedRef {
1510        lifetime: Option<Lifetime>,
1511        mutability: Mutability,
1512        type_: Box<Type>,
1513    },
1514
1515    /// A qualified path to an associated item: `<Type as Trait>::Name`
1516    QPath(Box<QPathData>),
1517
1518    /// A type that is inferred: `_`
1519    Infer,
1520
1521    /// An `impl Trait`: `impl TraitA + TraitB + ...`
1522    ImplTrait(Vec<GenericBound>),
1523
1524    UnsafeBinder(Box<UnsafeBinderTy>),
1525}
1526
1527impl Type {
1528    /// When comparing types for equality, it can help to ignore `&` wrapping.
1529    pub(crate) fn without_borrowed_ref(&self) -> &Type {
1530        let mut result = self;
1531        while let Type::BorrowedRef { type_, .. } = result {
1532            result = type_;
1533        }
1534        result
1535    }
1536
1537    pub(crate) fn is_borrowed_ref(&self) -> bool {
1538        matches!(self, Type::BorrowedRef { .. })
1539    }
1540
1541    fn is_type_alias(&self) -> bool {
1542        matches!(self, Type::Path { path: Path { res: Res::Def(DefKind::TyAlias, _), .. } })
1543    }
1544
1545    /// Check if two types are "the same" for documentation purposes.
1546    ///
1547    /// This is different from `Eq`, because it knows that things like
1548    /// `Placeholder` are possible matches for everything.
1549    ///
1550    /// This relation is not commutative when generics are involved:
1551    ///
1552    /// ```ignore(private)
1553    /// # // see types/tests.rs:is_same_generic for the real test
1554    /// use rustdoc::format::cache::Cache;
1555    /// use rustdoc::clean::types::{Type, PrimitiveType};
1556    /// let cache = Cache::new(false);
1557    /// let generic = Type::Generic(rustc_span::symbol::sym::Any);
1558    /// let unit = Type::Primitive(PrimitiveType::Unit);
1559    /// assert!(!generic.is_same(&unit, &cache));
1560    /// assert!(unit.is_same(&generic, &cache));
1561    /// ```
1562    ///
1563    /// An owned type is also the same as its borrowed variants (this is commutative),
1564    /// but `&T` is not the same as `&mut T`.
1565    pub(crate) fn is_doc_subtype_of(&self, other: &Self, cache: &Cache) -> bool {
1566        // Strip the references so that it can compare the actual types, unless both are references.
1567        // If both are references, leave them alone and compare the mutabilities later.
1568        let (self_cleared, other_cleared) = if !self.is_borrowed_ref() || !other.is_borrowed_ref() {
1569            (self.without_borrowed_ref(), other.without_borrowed_ref())
1570        } else {
1571            (self, other)
1572        };
1573
1574        // FIXME: `Cache` does not have the data required to unwrap type aliases,
1575        // so we just assume they are equal.
1576        // This is only remotely acceptable because we were previously
1577        // assuming all types were equal when used
1578        // as a generic parameter of a type in `Deref::Target`.
1579        if self_cleared.is_type_alias() || other_cleared.is_type_alias() {
1580            return true;
1581        }
1582
1583        match (self_cleared, other_cleared) {
1584            // Recursive cases.
1585            (Type::Tuple(a), Type::Tuple(b)) => {
1586                a.len() == b.len() && a.iter().zip(b).all(|(a, b)| a.is_doc_subtype_of(b, cache))
1587            }
1588            (Type::Slice(a), Type::Slice(b)) => a.is_doc_subtype_of(b, cache),
1589            (Type::Array(a, al), Type::Array(b, bl)) => al == bl && a.is_doc_subtype_of(b, cache),
1590            (Type::RawPointer(mutability, type_), Type::RawPointer(b_mutability, b_type_)) => {
1591                mutability == b_mutability && type_.is_doc_subtype_of(b_type_, cache)
1592            }
1593            (
1594                Type::BorrowedRef { mutability, type_, .. },
1595                Type::BorrowedRef { mutability: b_mutability, type_: b_type_, .. },
1596            ) => mutability == b_mutability && type_.is_doc_subtype_of(b_type_, cache),
1597            // Placeholders are equal to all other types.
1598            (Type::Infer, _) | (_, Type::Infer) => true,
1599            // Generics match everything on the right, but not on the left.
1600            // If both sides are generic, this returns true.
1601            (_, Type::Generic(_)) => true,
1602            (Type::Generic(_), _) => false,
1603            // `Self` only matches itself.
1604            (Type::SelfTy, Type::SelfTy) => true,
1605            // Paths account for both the path itself and its generics.
1606            (Type::Path { path: a }, Type::Path { path: b }) => {
1607                a.def_id() == b.def_id()
1608                    && a.generics()
1609                        .zip(b.generics())
1610                        .map(|(ag, bg)| {
1611                            ag.iter().zip(bg.iter()).all(|(at, bt)| at.is_doc_subtype_of(bt, cache))
1612                        })
1613                        .unwrap_or(true)
1614            }
1615            // Other cases, such as primitives, just use recursion.
1616            (a, b) => a
1617                .def_id(cache)
1618                .and_then(|a| Some((a, b.def_id(cache)?)))
1619                .map(|(a, b)| a == b)
1620                .unwrap_or(false),
1621        }
1622    }
1623
1624    pub(crate) fn primitive_type(&self) -> Option<PrimitiveType> {
1625        match *self {
1626            Primitive(p) | BorrowedRef { type_: box Primitive(p), .. } => Some(p),
1627            Slice(..) | BorrowedRef { type_: box Slice(..), .. } => Some(PrimitiveType::Slice),
1628            Array(..) | BorrowedRef { type_: box Array(..), .. } => Some(PrimitiveType::Array),
1629            Tuple(ref tys) => {
1630                if tys.is_empty() {
1631                    Some(PrimitiveType::Unit)
1632                } else {
1633                    Some(PrimitiveType::Tuple)
1634                }
1635            }
1636            RawPointer(..) => Some(PrimitiveType::RawPointer),
1637            BareFunction(..) => Some(PrimitiveType::Fn),
1638            _ => None,
1639        }
1640    }
1641
1642    /// Returns the sugared return type for an async function.
1643    ///
1644    /// For example, if the return type is `impl std::future::Future<Output = i32>`, this function
1645    /// will return `i32`.
1646    ///
1647    /// # Panics
1648    ///
1649    /// This function will panic if the return type does not match the expected sugaring for async
1650    /// functions.
1651    pub(crate) fn sugared_async_return_type(self) -> Type {
1652        if let Type::ImplTrait(mut v) = self
1653            && let Some(GenericBound::TraitBound(PolyTrait { mut trait_, .. }, _)) = v.pop()
1654            && let Some(segment) = trait_.segments.pop()
1655            && let GenericArgs::AngleBracketed { mut constraints, .. } = segment.args
1656            && let Some(constraint) = constraints.pop()
1657            && let AssocItemConstraintKind::Equality { term } = constraint.kind
1658            && let Term::Type(ty) = term
1659        {
1660            ty
1661        } else {
1662            panic!("unexpected async fn return type")
1663        }
1664    }
1665
1666    /// Checks if this is a `T::Name` path for an associated type.
1667    pub(crate) fn is_assoc_ty(&self) -> bool {
1668        match self {
1669            Type::Path { path, .. } => path.is_assoc_ty(),
1670            _ => false,
1671        }
1672    }
1673
1674    pub(crate) fn is_self_type(&self) -> bool {
1675        matches!(*self, Type::SelfTy)
1676    }
1677
1678    pub(crate) fn generic_args(&self) -> Option<&GenericArgs> {
1679        match self {
1680            Type::Path { path, .. } => path.generic_args(),
1681            _ => None,
1682        }
1683    }
1684
1685    pub(crate) fn generics(&self) -> Option<Vec<&Type>> {
1686        match self {
1687            Type::Path { path, .. } => path.generics(),
1688            _ => None,
1689        }
1690    }
1691
1692    pub(crate) fn is_full_generic(&self) -> bool {
1693        matches!(self, Type::Generic(_))
1694    }
1695
1696    pub(crate) fn is_unit(&self) -> bool {
1697        matches!(self, Type::Tuple(v) if v.is_empty())
1698    }
1699
1700    pub(crate) fn projection(&self) -> Option<(&Type, DefId, PathSegment)> {
1701        if let QPath(box QPathData { self_type, trait_, assoc, .. }) = self {
1702            Some((self_type, trait_.as_ref()?.def_id(), assoc.clone()))
1703        } else {
1704            None
1705        }
1706    }
1707
1708    /// Use this method to get the [DefId] of a [clean] AST node, including [PrimitiveType]s.
1709    ///
1710    /// [clean]: crate::clean
1711    pub(crate) fn def_id(&self, cache: &Cache) -> Option<DefId> {
1712        let t: PrimitiveType = match *self {
1713            Type::Path { ref path } => return Some(path.def_id()),
1714            DynTrait(ref bounds, _) => return bounds.first().map(|b| b.trait_.def_id()),
1715            Primitive(p) => return cache.primitive_locations.get(&p).cloned(),
1716            BorrowedRef { type_: box Generic(..), .. } => PrimitiveType::Reference,
1717            BorrowedRef { ref type_, .. } => return type_.def_id(cache),
1718            Tuple(ref tys) => {
1719                if tys.is_empty() {
1720                    PrimitiveType::Unit
1721                } else {
1722                    PrimitiveType::Tuple
1723                }
1724            }
1725            BareFunction(..) => PrimitiveType::Fn,
1726            Slice(..) => PrimitiveType::Slice,
1727            Array(..) => PrimitiveType::Array,
1728            Type::Pat(..) => PrimitiveType::Pat,
1729            RawPointer(..) => PrimitiveType::RawPointer,
1730            QPath(box QPathData { ref self_type, .. }) => return self_type.def_id(cache),
1731            Generic(_) | SelfTy | Infer | ImplTrait(_) | UnsafeBinder(_) => return None,
1732        };
1733        Primitive(t).def_id(cache)
1734    }
1735}
1736
1737#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1738pub(crate) struct QPathData {
1739    pub assoc: PathSegment,
1740    pub self_type: Type,
1741    /// FIXME: compute this field on demand.
1742    pub should_show_cast: bool,
1743    pub trait_: Option<Path>,
1744}
1745
1746/// A primitive (aka, builtin) type.
1747///
1748/// This represents things like `i32`, `str`, etc.
1749///
1750/// N.B. This has to be different from [`hir::PrimTy`] because it also includes types that aren't
1751/// paths, like [`Self::Unit`].
1752#[derive(Clone, PartialEq, Eq, Hash, Copy, Debug)]
1753pub(crate) enum PrimitiveType {
1754    Isize,
1755    I8,
1756    I16,
1757    I32,
1758    I64,
1759    I128,
1760    Usize,
1761    U8,
1762    U16,
1763    U32,
1764    U64,
1765    U128,
1766    F16,
1767    F32,
1768    F64,
1769    F128,
1770    Char,
1771    Bool,
1772    Str,
1773    Slice,
1774    Array,
1775    Pat,
1776    Tuple,
1777    Unit,
1778    RawPointer,
1779    Reference,
1780    Fn,
1781    Never,
1782}
1783
1784type SimplifiedTypes = FxIndexMap<PrimitiveType, ArrayVec<SimplifiedType, 3>>;
1785impl PrimitiveType {
1786    pub(crate) fn from_hir(prim: hir::PrimTy) -> PrimitiveType {
1787        use ast::{FloatTy, IntTy, UintTy};
1788        match prim {
1789            hir::PrimTy::Int(IntTy::Isize) => PrimitiveType::Isize,
1790            hir::PrimTy::Int(IntTy::I8) => PrimitiveType::I8,
1791            hir::PrimTy::Int(IntTy::I16) => PrimitiveType::I16,
1792            hir::PrimTy::Int(IntTy::I32) => PrimitiveType::I32,
1793            hir::PrimTy::Int(IntTy::I64) => PrimitiveType::I64,
1794            hir::PrimTy::Int(IntTy::I128) => PrimitiveType::I128,
1795            hir::PrimTy::Uint(UintTy::Usize) => PrimitiveType::Usize,
1796            hir::PrimTy::Uint(UintTy::U8) => PrimitiveType::U8,
1797            hir::PrimTy::Uint(UintTy::U16) => PrimitiveType::U16,
1798            hir::PrimTy::Uint(UintTy::U32) => PrimitiveType::U32,
1799            hir::PrimTy::Uint(UintTy::U64) => PrimitiveType::U64,
1800            hir::PrimTy::Uint(UintTy::U128) => PrimitiveType::U128,
1801            hir::PrimTy::Float(FloatTy::F16) => PrimitiveType::F16,
1802            hir::PrimTy::Float(FloatTy::F32) => PrimitiveType::F32,
1803            hir::PrimTy::Float(FloatTy::F64) => PrimitiveType::F64,
1804            hir::PrimTy::Float(FloatTy::F128) => PrimitiveType::F128,
1805            hir::PrimTy::Str => PrimitiveType::Str,
1806            hir::PrimTy::Bool => PrimitiveType::Bool,
1807            hir::PrimTy::Char => PrimitiveType::Char,
1808        }
1809    }
1810
1811    pub(crate) fn from_symbol(s: Symbol) -> Option<PrimitiveType> {
1812        match s {
1813            sym::isize => Some(PrimitiveType::Isize),
1814            sym::i8 => Some(PrimitiveType::I8),
1815            sym::i16 => Some(PrimitiveType::I16),
1816            sym::i32 => Some(PrimitiveType::I32),
1817            sym::i64 => Some(PrimitiveType::I64),
1818            sym::i128 => Some(PrimitiveType::I128),
1819            sym::usize => Some(PrimitiveType::Usize),
1820            sym::u8 => Some(PrimitiveType::U8),
1821            sym::u16 => Some(PrimitiveType::U16),
1822            sym::u32 => Some(PrimitiveType::U32),
1823            sym::u64 => Some(PrimitiveType::U64),
1824            sym::u128 => Some(PrimitiveType::U128),
1825            sym::bool => Some(PrimitiveType::Bool),
1826            sym::char => Some(PrimitiveType::Char),
1827            sym::str => Some(PrimitiveType::Str),
1828            sym::f16 => Some(PrimitiveType::F16),
1829            sym::f32 => Some(PrimitiveType::F32),
1830            sym::f64 => Some(PrimitiveType::F64),
1831            sym::f128 => Some(PrimitiveType::F128),
1832            sym::array => Some(PrimitiveType::Array),
1833            sym::slice => Some(PrimitiveType::Slice),
1834            sym::tuple => Some(PrimitiveType::Tuple),
1835            sym::unit => Some(PrimitiveType::Unit),
1836            sym::pointer => Some(PrimitiveType::RawPointer),
1837            sym::reference => Some(PrimitiveType::Reference),
1838            kw::Fn => Some(PrimitiveType::Fn),
1839            sym::never => Some(PrimitiveType::Never),
1840            _ => None,
1841        }
1842    }
1843
1844    pub(crate) fn simplified_types() -> &'static SimplifiedTypes {
1845        use PrimitiveType::*;
1846        use ty::{FloatTy, IntTy, UintTy};
1847        static CELL: OnceCell<SimplifiedTypes> = OnceCell::new();
1848
1849        let single = |x| iter::once(x).collect();
1850        CELL.get_or_init(move || {
1851            map! {
1852                Isize => single(SimplifiedType::Int(IntTy::Isize)),
1853                I8 => single(SimplifiedType::Int(IntTy::I8)),
1854                I16 => single(SimplifiedType::Int(IntTy::I16)),
1855                I32 => single(SimplifiedType::Int(IntTy::I32)),
1856                I64 => single(SimplifiedType::Int(IntTy::I64)),
1857                I128 => single(SimplifiedType::Int(IntTy::I128)),
1858                Usize => single(SimplifiedType::Uint(UintTy::Usize)),
1859                U8 => single(SimplifiedType::Uint(UintTy::U8)),
1860                U16 => single(SimplifiedType::Uint(UintTy::U16)),
1861                U32 => single(SimplifiedType::Uint(UintTy::U32)),
1862                U64 => single(SimplifiedType::Uint(UintTy::U64)),
1863                U128 => single(SimplifiedType::Uint(UintTy::U128)),
1864                F16 => single(SimplifiedType::Float(FloatTy::F16)),
1865                F32 => single(SimplifiedType::Float(FloatTy::F32)),
1866                F64 => single(SimplifiedType::Float(FloatTy::F64)),
1867                F128 => single(SimplifiedType::Float(FloatTy::F128)),
1868                Str => single(SimplifiedType::Str),
1869                Bool => single(SimplifiedType::Bool),
1870                Char => single(SimplifiedType::Char),
1871                Array => single(SimplifiedType::Array),
1872                Slice => single(SimplifiedType::Slice),
1873                // FIXME: If we ever add an inherent impl for tuples
1874                // with different lengths, they won't show in rustdoc.
1875                //
1876                // Either manually update this arrayvec at this point
1877                // or start with a more complex refactoring.
1878                Tuple => [SimplifiedType::Tuple(1), SimplifiedType::Tuple(2), SimplifiedType::Tuple(3)].into(),
1879                Unit => single(SimplifiedType::Tuple(0)),
1880                RawPointer => [SimplifiedType::Ptr(Mutability::Not), SimplifiedType::Ptr(Mutability::Mut)].into_iter().collect(),
1881                Reference => [SimplifiedType::Ref(Mutability::Not), SimplifiedType::Ref(Mutability::Mut)].into_iter().collect(),
1882                // FIXME: This will be wrong if we ever add inherent impls
1883                // for function pointers.
1884                Fn => single(SimplifiedType::Function(1)),
1885                Never => single(SimplifiedType::Never),
1886            }
1887        })
1888    }
1889
1890    pub(crate) fn impls<'tcx>(&self, tcx: TyCtxt<'tcx>) -> impl Iterator<Item = DefId> + 'tcx {
1891        Self::simplified_types()
1892            .get(self)
1893            .into_iter()
1894            .flatten()
1895            .flat_map(move |&simp| tcx.incoherent_impls(simp).iter())
1896            .copied()
1897    }
1898
1899    pub(crate) fn all_impls(tcx: TyCtxt<'_>) -> impl Iterator<Item = DefId> {
1900        Self::simplified_types()
1901            .values()
1902            .flatten()
1903            .flat_map(move |&simp| tcx.incoherent_impls(simp).iter())
1904            .copied()
1905    }
1906
1907    pub(crate) fn as_sym(&self) -> Symbol {
1908        use PrimitiveType::*;
1909        match self {
1910            Isize => sym::isize,
1911            I8 => sym::i8,
1912            I16 => sym::i16,
1913            I32 => sym::i32,
1914            I64 => sym::i64,
1915            I128 => sym::i128,
1916            Usize => sym::usize,
1917            U8 => sym::u8,
1918            U16 => sym::u16,
1919            U32 => sym::u32,
1920            U64 => sym::u64,
1921            U128 => sym::u128,
1922            F16 => sym::f16,
1923            F32 => sym::f32,
1924            F64 => sym::f64,
1925            F128 => sym::f128,
1926            Str => sym::str,
1927            Bool => sym::bool,
1928            Char => sym::char,
1929            Array => sym::array,
1930            Pat => sym::pat,
1931            Slice => sym::slice,
1932            Tuple => sym::tuple,
1933            Unit => sym::unit,
1934            RawPointer => sym::pointer,
1935            Reference => sym::reference,
1936            Fn => kw::Fn,
1937            Never => sym::never,
1938        }
1939    }
1940
1941    /// Returns the DefId of the module with `rustc_doc_primitive` for this primitive type.
1942    /// Panics if there is no such module.
1943    ///
1944    /// This gives precedence to primitives defined in the current crate, and deprioritizes
1945    /// primitives defined in `core`,
1946    /// but otherwise, if multiple crates define the same primitive, there is no guarantee of which
1947    /// will be picked.
1948    ///
1949    /// In particular, if a crate depends on both `std` and another crate that also defines
1950    /// `rustc_doc_primitive`, then it's entirely random whether `std` or the other crate is picked.
1951    /// (no_std crates are usually fine unless multiple dependencies define a primitive.)
1952    pub(crate) fn primitive_locations(tcx: TyCtxt<'_>) -> &FxIndexMap<PrimitiveType, DefId> {
1953        static PRIMITIVE_LOCATIONS: OnceCell<FxIndexMap<PrimitiveType, DefId>> = OnceCell::new();
1954        PRIMITIVE_LOCATIONS.get_or_init(|| {
1955            let mut primitive_locations = FxIndexMap::default();
1956            // NOTE: technically this misses crates that are only passed with `--extern` and not loaded when checking the crate.
1957            // This is a degenerate case that I don't plan to support.
1958            for &crate_num in tcx.crates(()) {
1959                let e = ExternalCrate { crate_num };
1960                let crate_name = e.name(tcx);
1961                debug!(?crate_num, ?crate_name);
1962                for &(def_id, prim) in &e.primitives(tcx) {
1963                    // HACK: try to link to std instead where possible
1964                    if crate_name == sym::core && primitive_locations.contains_key(&prim) {
1965                        continue;
1966                    }
1967                    primitive_locations.insert(prim, def_id);
1968                }
1969            }
1970            let local_primitives = ExternalCrate { crate_num: LOCAL_CRATE }.primitives(tcx);
1971            for (def_id, prim) in local_primitives {
1972                primitive_locations.insert(prim, def_id);
1973            }
1974            primitive_locations
1975        })
1976    }
1977}
1978
1979impl From<ast::IntTy> for PrimitiveType {
1980    fn from(int_ty: ast::IntTy) -> PrimitiveType {
1981        match int_ty {
1982            ast::IntTy::Isize => PrimitiveType::Isize,
1983            ast::IntTy::I8 => PrimitiveType::I8,
1984            ast::IntTy::I16 => PrimitiveType::I16,
1985            ast::IntTy::I32 => PrimitiveType::I32,
1986            ast::IntTy::I64 => PrimitiveType::I64,
1987            ast::IntTy::I128 => PrimitiveType::I128,
1988        }
1989    }
1990}
1991
1992impl From<ast::UintTy> for PrimitiveType {
1993    fn from(uint_ty: ast::UintTy) -> PrimitiveType {
1994        match uint_ty {
1995            ast::UintTy::Usize => PrimitiveType::Usize,
1996            ast::UintTy::U8 => PrimitiveType::U8,
1997            ast::UintTy::U16 => PrimitiveType::U16,
1998            ast::UintTy::U32 => PrimitiveType::U32,
1999            ast::UintTy::U64 => PrimitiveType::U64,
2000            ast::UintTy::U128 => PrimitiveType::U128,
2001        }
2002    }
2003}
2004
2005impl From<ast::FloatTy> for PrimitiveType {
2006    fn from(float_ty: ast::FloatTy) -> PrimitiveType {
2007        match float_ty {
2008            ast::FloatTy::F16 => PrimitiveType::F16,
2009            ast::FloatTy::F32 => PrimitiveType::F32,
2010            ast::FloatTy::F64 => PrimitiveType::F64,
2011            ast::FloatTy::F128 => PrimitiveType::F128,
2012        }
2013    }
2014}
2015
2016impl From<ty::IntTy> for PrimitiveType {
2017    fn from(int_ty: ty::IntTy) -> PrimitiveType {
2018        match int_ty {
2019            ty::IntTy::Isize => PrimitiveType::Isize,
2020            ty::IntTy::I8 => PrimitiveType::I8,
2021            ty::IntTy::I16 => PrimitiveType::I16,
2022            ty::IntTy::I32 => PrimitiveType::I32,
2023            ty::IntTy::I64 => PrimitiveType::I64,
2024            ty::IntTy::I128 => PrimitiveType::I128,
2025        }
2026    }
2027}
2028
2029impl From<ty::UintTy> for PrimitiveType {
2030    fn from(uint_ty: ty::UintTy) -> PrimitiveType {
2031        match uint_ty {
2032            ty::UintTy::Usize => PrimitiveType::Usize,
2033            ty::UintTy::U8 => PrimitiveType::U8,
2034            ty::UintTy::U16 => PrimitiveType::U16,
2035            ty::UintTy::U32 => PrimitiveType::U32,
2036            ty::UintTy::U64 => PrimitiveType::U64,
2037            ty::UintTy::U128 => PrimitiveType::U128,
2038        }
2039    }
2040}
2041
2042impl From<ty::FloatTy> for PrimitiveType {
2043    fn from(float_ty: ty::FloatTy) -> PrimitiveType {
2044        match float_ty {
2045            ty::FloatTy::F16 => PrimitiveType::F16,
2046            ty::FloatTy::F32 => PrimitiveType::F32,
2047            ty::FloatTy::F64 => PrimitiveType::F64,
2048            ty::FloatTy::F128 => PrimitiveType::F128,
2049        }
2050    }
2051}
2052
2053impl From<hir::PrimTy> for PrimitiveType {
2054    fn from(prim_ty: hir::PrimTy) -> PrimitiveType {
2055        match prim_ty {
2056            hir::PrimTy::Int(int_ty) => int_ty.into(),
2057            hir::PrimTy::Uint(uint_ty) => uint_ty.into(),
2058            hir::PrimTy::Float(float_ty) => float_ty.into(),
2059            hir::PrimTy::Str => PrimitiveType::Str,
2060            hir::PrimTy::Bool => PrimitiveType::Bool,
2061            hir::PrimTy::Char => PrimitiveType::Char,
2062        }
2063    }
2064}
2065
2066#[derive(Clone, Debug)]
2067pub(crate) struct Struct {
2068    pub(crate) ctor_kind: Option<CtorKind>,
2069    pub(crate) generics: Generics,
2070    pub(crate) fields: ThinVec<Item>,
2071}
2072
2073impl Struct {
2074    pub(crate) fn has_stripped_entries(&self) -> bool {
2075        self.fields.iter().any(|f| f.is_stripped())
2076    }
2077}
2078
2079#[derive(Clone, Debug)]
2080pub(crate) struct Union {
2081    pub(crate) generics: Generics,
2082    pub(crate) fields: Vec<Item>,
2083}
2084
2085impl Union {
2086    pub(crate) fn has_stripped_entries(&self) -> bool {
2087        self.fields.iter().any(|f| f.is_stripped())
2088    }
2089}
2090
2091/// This is a more limited form of the standard Struct, different in that
2092/// it lacks the things most items have (name, id, parameterization). Found
2093/// only as a variant in an enum.
2094#[derive(Clone, Debug)]
2095pub(crate) struct VariantStruct {
2096    pub(crate) fields: ThinVec<Item>,
2097}
2098
2099impl VariantStruct {
2100    pub(crate) fn has_stripped_entries(&self) -> bool {
2101        self.fields.iter().any(|f| f.is_stripped())
2102    }
2103}
2104
2105#[derive(Clone, Debug)]
2106pub(crate) struct Enum {
2107    pub(crate) variants: IndexVec<VariantIdx, Item>,
2108    pub(crate) generics: Generics,
2109}
2110
2111impl Enum {
2112    pub(crate) fn has_stripped_entries(&self) -> bool {
2113        self.variants.iter().any(|f| f.is_stripped())
2114    }
2115
2116    pub(crate) fn variants(&self) -> impl Iterator<Item = &Item> {
2117        self.variants.iter().filter(|v| !v.is_stripped())
2118    }
2119}
2120
2121#[derive(Clone, Debug)]
2122pub(crate) struct Variant {
2123    pub kind: VariantKind,
2124    pub discriminant: Option<Discriminant>,
2125}
2126
2127#[derive(Clone, Debug)]
2128pub(crate) enum VariantKind {
2129    CLike,
2130    Tuple(ThinVec<Item>),
2131    Struct(VariantStruct),
2132}
2133
2134impl Variant {
2135    pub(crate) fn has_stripped_entries(&self) -> Option<bool> {
2136        match &self.kind {
2137            VariantKind::Struct(struct_) => Some(struct_.has_stripped_entries()),
2138            VariantKind::CLike | VariantKind::Tuple(_) => None,
2139        }
2140    }
2141}
2142
2143#[derive(Clone, Debug)]
2144pub(crate) struct Discriminant {
2145    // In the case of cross crate re-exports, we don't have the necessary information
2146    // to reconstruct the expression of the discriminant, only the value.
2147    pub(super) expr: Option<BodyId>,
2148    pub(super) value: DefId,
2149}
2150
2151impl Discriminant {
2152    /// Will be `None` in the case of cross-crate reexports, and may be
2153    /// simplified
2154    pub(crate) fn expr(&self, tcx: TyCtxt<'_>) -> Option<String> {
2155        self.expr
2156            .map(|body| rendered_const(tcx, tcx.hir_body(body), tcx.hir_body_owner_def_id(body)))
2157    }
2158    pub(crate) fn value(&self, tcx: TyCtxt<'_>, with_underscores: bool) -> String {
2159        print_evaluated_const(tcx, self.value, with_underscores, false).unwrap()
2160    }
2161}
2162
2163/// Small wrapper around [`rustc_span::Span`] that adds helper methods
2164/// and enforces calling [`rustc_span::Span::source_callsite()`].
2165#[derive(Copy, Clone, Debug)]
2166pub(crate) struct Span(rustc_span::Span);
2167
2168impl Span {
2169    /// Wraps a [`rustc_span::Span`]. In case this span is the result of a macro expansion, the
2170    /// span will be updated to point to the macro invocation instead of the macro definition.
2171    ///
2172    /// (See rust-lang/rust#39726)
2173    pub(crate) fn new(sp: rustc_span::Span) -> Self {
2174        Self(sp.source_callsite())
2175    }
2176
2177    pub(crate) fn inner(&self) -> rustc_span::Span {
2178        self.0
2179    }
2180
2181    pub(crate) fn filename(&self, sess: &Session) -> FileName {
2182        sess.source_map().span_to_filename(self.0)
2183    }
2184
2185    pub(crate) fn lo(&self, sess: &Session) -> Loc {
2186        sess.source_map().lookup_char_pos(self.0.lo())
2187    }
2188
2189    pub(crate) fn hi(&self, sess: &Session) -> Loc {
2190        sess.source_map().lookup_char_pos(self.0.hi())
2191    }
2192
2193    pub(crate) fn cnum(&self, sess: &Session) -> CrateNum {
2194        // FIXME: is there a time when the lo and hi crate would be different?
2195        self.lo(sess).file.cnum
2196    }
2197}
2198
2199#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2200pub(crate) struct Path {
2201    pub(crate) res: Res,
2202    pub(crate) segments: ThinVec<PathSegment>,
2203}
2204
2205impl Path {
2206    pub(crate) fn def_id(&self) -> DefId {
2207        self.res.def_id()
2208    }
2209
2210    pub(crate) fn last_opt(&self) -> Option<Symbol> {
2211        self.segments.last().map(|s| s.name)
2212    }
2213
2214    pub(crate) fn last(&self) -> Symbol {
2215        self.last_opt().expect("segments were empty")
2216    }
2217
2218    pub(crate) fn whole_name(&self) -> String {
2219        self.segments
2220            .iter()
2221            .map(|s| if s.name == kw::PathRoot { "" } else { s.name.as_str() })
2222            .intersperse("::")
2223            .collect()
2224    }
2225
2226    /// Checks if this is a `T::Name` path for an associated type.
2227    pub(crate) fn is_assoc_ty(&self) -> bool {
2228        match self.res {
2229            Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } | Res::Def(DefKind::TyParam, _)
2230                if self.segments.len() != 1 =>
2231            {
2232                true
2233            }
2234            Res::Def(DefKind::AssocTy, _) => true,
2235            _ => false,
2236        }
2237    }
2238
2239    pub(crate) fn generic_args(&self) -> Option<&GenericArgs> {
2240        self.segments.last().map(|seg| &seg.args)
2241    }
2242
2243    pub(crate) fn generics(&self) -> Option<Vec<&Type>> {
2244        self.segments.last().and_then(|seg| {
2245            if let GenericArgs::AngleBracketed { ref args, .. } = seg.args {
2246                Some(
2247                    args.iter()
2248                        .filter_map(|arg| match arg {
2249                            GenericArg::Type(ty) => Some(ty),
2250                            _ => None,
2251                        })
2252                        .collect(),
2253                )
2254            } else {
2255                None
2256            }
2257        })
2258    }
2259}
2260
2261#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2262pub(crate) enum GenericArg {
2263    Lifetime(Lifetime),
2264    Type(Type),
2265    Const(Box<ConstantKind>),
2266    Infer,
2267}
2268
2269impl GenericArg {
2270    pub(crate) fn as_lt(&self) -> Option<&Lifetime> {
2271        if let Self::Lifetime(lt) = self { Some(lt) } else { None }
2272    }
2273
2274    pub(crate) fn as_ty(&self) -> Option<&Type> {
2275        if let Self::Type(ty) = self { Some(ty) } else { None }
2276    }
2277}
2278
2279#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2280pub(crate) enum GenericArgs {
2281    /// `<args, constraints = ..>`
2282    AngleBracketed { args: ThinVec<GenericArg>, constraints: ThinVec<AssocItemConstraint> },
2283    /// `(inputs) -> output`
2284    Parenthesized { inputs: ThinVec<Type>, output: Option<Box<Type>> },
2285    /// `(..)`
2286    ReturnTypeNotation,
2287}
2288
2289impl GenericArgs {
2290    pub(crate) fn is_empty(&self) -> bool {
2291        match self {
2292            GenericArgs::AngleBracketed { args, constraints } => {
2293                args.is_empty() && constraints.is_empty()
2294            }
2295            GenericArgs::Parenthesized { inputs, output } => inputs.is_empty() && output.is_none(),
2296            GenericArgs::ReturnTypeNotation => false,
2297        }
2298    }
2299    pub(crate) fn constraints(&self) -> Box<dyn Iterator<Item = AssocItemConstraint> + '_> {
2300        match self {
2301            GenericArgs::AngleBracketed { constraints, .. } => {
2302                Box::new(constraints.iter().cloned())
2303            }
2304            GenericArgs::Parenthesized { output, .. } => Box::new(
2305                output
2306                    .as_ref()
2307                    .map(|ty| AssocItemConstraint {
2308                        assoc: PathSegment {
2309                            name: sym::Output,
2310                            args: GenericArgs::AngleBracketed {
2311                                args: ThinVec::new(),
2312                                constraints: ThinVec::new(),
2313                            },
2314                        },
2315                        kind: AssocItemConstraintKind::Equality {
2316                            term: Term::Type((**ty).clone()),
2317                        },
2318                    })
2319                    .into_iter(),
2320            ),
2321            GenericArgs::ReturnTypeNotation => Box::new([].into_iter()),
2322        }
2323    }
2324}
2325
2326impl<'a> IntoIterator for &'a GenericArgs {
2327    type IntoIter = Box<dyn Iterator<Item = GenericArg> + 'a>;
2328    type Item = GenericArg;
2329    fn into_iter(self) -> Self::IntoIter {
2330        match self {
2331            GenericArgs::AngleBracketed { args, .. } => Box::new(args.iter().cloned()),
2332            GenericArgs::Parenthesized { inputs, .. } => {
2333                // FIXME: This isn't really right, since `Fn(A, B)` is `Fn<(A, B)>`
2334                Box::new(inputs.iter().cloned().map(GenericArg::Type))
2335            }
2336            GenericArgs::ReturnTypeNotation => Box::new([].into_iter()),
2337        }
2338    }
2339}
2340
2341#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2342pub(crate) struct PathSegment {
2343    pub(crate) name: Symbol,
2344    pub(crate) args: GenericArgs,
2345}
2346
2347#[derive(Clone, Debug)]
2348pub(crate) enum TypeAliasInnerType {
2349    Enum { variants: IndexVec<VariantIdx, Item>, is_non_exhaustive: bool },
2350    Union { fields: Vec<Item> },
2351    Struct { ctor_kind: Option<CtorKind>, fields: Vec<Item> },
2352}
2353
2354#[derive(Clone, Debug)]
2355pub(crate) struct TypeAlias {
2356    pub(crate) type_: Type,
2357    pub(crate) generics: Generics,
2358    /// Inner `AdtDef` type, ie `type TyKind = IrTyKind<Adt, Ty>`,
2359    /// to be shown directly on the typedef page.
2360    pub(crate) inner_type: Option<TypeAliasInnerType>,
2361    /// `type_` can come from either the HIR or from metadata. If it comes from HIR, it may be a type
2362    /// alias instead of the final type. This will always have the final type, regardless of whether
2363    /// `type_` came from HIR or from metadata.
2364    ///
2365    /// If `item_type.is_none()`, `type_` is guaranteed to come from metadata (and therefore hold the
2366    /// final type).
2367    pub(crate) item_type: Option<Type>,
2368}
2369
2370#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2371pub(crate) struct BareFunctionDecl {
2372    pub(crate) safety: hir::Safety,
2373    pub(crate) generic_params: Vec<GenericParamDef>,
2374    pub(crate) decl: FnDecl,
2375    pub(crate) abi: ExternAbi,
2376}
2377
2378#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2379pub(crate) struct UnsafeBinderTy {
2380    pub(crate) generic_params: Vec<GenericParamDef>,
2381    pub(crate) ty: Type,
2382}
2383
2384#[derive(Clone, Debug)]
2385pub(crate) struct Static {
2386    pub(crate) type_: Box<Type>,
2387    pub(crate) mutability: Mutability,
2388    pub(crate) expr: Option<BodyId>,
2389}
2390
2391#[derive(Clone, PartialEq, Eq, Hash, Debug)]
2392pub(crate) struct Constant {
2393    pub(crate) generics: Generics,
2394    pub(crate) kind: ConstantKind,
2395    pub(crate) type_: Type,
2396}
2397
2398#[derive(Clone, PartialEq, Eq, Hash, Debug)]
2399pub(crate) enum Term {
2400    Type(Type),
2401    Constant(ConstantKind),
2402}
2403
2404impl Term {
2405    pub(crate) fn ty(&self) -> Option<&Type> {
2406        if let Term::Type(ty) = self { Some(ty) } else { None }
2407    }
2408}
2409
2410impl From<Type> for Term {
2411    fn from(ty: Type) -> Self {
2412        Term::Type(ty)
2413    }
2414}
2415
2416#[derive(Clone, PartialEq, Eq, Hash, Debug)]
2417pub(crate) enum ConstantKind {
2418    /// This is the wrapper around `ty::Const` for a non-local constant. Because it doesn't have a
2419    /// `BodyId`, we need to handle it on its own.
2420    ///
2421    /// Note that `ty::Const` includes generic parameters, and may not always be uniquely identified
2422    /// by a DefId. So this field must be different from `Extern`.
2423    TyConst { expr: Box<str> },
2424    /// A constant that is just a path (i.e., referring to a const param, free const, etc.).
2425    // FIXME: this is an unfortunate representation. rustdoc's logic around consts needs to be improved.
2426    Path { path: Box<str> },
2427    /// A constant (expression) that's not an item or associated item. These are usually found
2428    /// nested inside types (e.g., array lengths) or expressions (e.g., repeat counts), and also
2429    /// used to define explicit discriminant values for enum variants.
2430    Anonymous { body: BodyId },
2431    /// A constant from a different crate.
2432    Extern { def_id: DefId },
2433    /// `const FOO: u32 = ...;`
2434    Local { def_id: DefId, body: BodyId },
2435    /// An inferred constant as in `[10u8; _]`.
2436    Infer,
2437}
2438
2439impl Constant {
2440    pub(crate) fn expr(&self, tcx: TyCtxt<'_>) -> String {
2441        self.kind.expr(tcx)
2442    }
2443
2444    pub(crate) fn value(&self, tcx: TyCtxt<'_>) -> Option<String> {
2445        self.kind.value(tcx)
2446    }
2447
2448    pub(crate) fn is_literal(&self, tcx: TyCtxt<'_>) -> bool {
2449        self.kind.is_literal(tcx)
2450    }
2451}
2452
2453impl ConstantKind {
2454    pub(crate) fn expr(&self, tcx: TyCtxt<'_>) -> String {
2455        match *self {
2456            ConstantKind::TyConst { ref expr } => expr.to_string(),
2457            ConstantKind::Path { ref path } => path.to_string(),
2458            ConstantKind::Extern { def_id } => print_inlined_const(tcx, def_id),
2459            ConstantKind::Local { body, .. } | ConstantKind::Anonymous { body } => {
2460                rendered_const(tcx, tcx.hir_body(body), tcx.hir_body_owner_def_id(body))
2461            }
2462            ConstantKind::Infer => "_".to_string(),
2463        }
2464    }
2465
2466    pub(crate) fn value(&self, tcx: TyCtxt<'_>) -> Option<String> {
2467        match *self {
2468            ConstantKind::TyConst { .. }
2469            | ConstantKind::Path { .. }
2470            | ConstantKind::Anonymous { .. }
2471            | ConstantKind::Infer => None,
2472            ConstantKind::Extern { def_id } | ConstantKind::Local { def_id, .. } => {
2473                print_evaluated_const(tcx, def_id, true, true)
2474            }
2475        }
2476    }
2477
2478    pub(crate) fn is_literal(&self, tcx: TyCtxt<'_>) -> bool {
2479        match *self {
2480            ConstantKind::TyConst { .. }
2481            | ConstantKind::Extern { .. }
2482            | ConstantKind::Path { .. }
2483            | ConstantKind::Infer => false,
2484            ConstantKind::Local { body, .. } | ConstantKind::Anonymous { body } => {
2485                is_literal_expr(tcx, body.hir_id)
2486            }
2487        }
2488    }
2489}
2490
2491#[derive(Clone, Debug)]
2492pub(crate) struct Impl {
2493    pub(crate) safety: hir::Safety,
2494    pub(crate) generics: Generics,
2495    pub(crate) trait_: Option<Path>,
2496    pub(crate) for_: Type,
2497    pub(crate) items: Vec<Item>,
2498    pub(crate) polarity: ty::ImplPolarity,
2499    pub(crate) kind: ImplKind,
2500}
2501
2502impl Impl {
2503    pub(crate) fn provided_trait_methods(&self, tcx: TyCtxt<'_>) -> FxIndexSet<Symbol> {
2504        self.trait_
2505            .as_ref()
2506            .map(|t| t.def_id())
2507            .map(|did| tcx.provided_trait_methods(did).map(|meth| meth.name).collect())
2508            .unwrap_or_default()
2509    }
2510
2511    pub(crate) fn is_negative_trait_impl(&self) -> bool {
2512        matches!(self.polarity, ty::ImplPolarity::Negative)
2513    }
2514}
2515
2516#[derive(Clone, Debug)]
2517pub(crate) enum ImplKind {
2518    Normal,
2519    Auto,
2520    FakeVariadic,
2521    Blanket(Box<Type>),
2522}
2523
2524impl ImplKind {
2525    pub(crate) fn is_auto(&self) -> bool {
2526        matches!(self, ImplKind::Auto)
2527    }
2528
2529    pub(crate) fn is_blanket(&self) -> bool {
2530        matches!(self, ImplKind::Blanket(_))
2531    }
2532
2533    pub(crate) fn is_fake_variadic(&self) -> bool {
2534        matches!(self, ImplKind::FakeVariadic)
2535    }
2536
2537    pub(crate) fn as_blanket_ty(&self) -> Option<&Type> {
2538        match self {
2539            ImplKind::Blanket(ty) => Some(ty),
2540            _ => None,
2541        }
2542    }
2543}
2544
2545#[derive(Clone, Debug)]
2546pub(crate) struct Import {
2547    pub(crate) kind: ImportKind,
2548    /// The item being re-exported.
2549    pub(crate) source: ImportSource,
2550    pub(crate) should_be_displayed: bool,
2551}
2552
2553impl Import {
2554    pub(crate) fn new_simple(
2555        name: Symbol,
2556        source: ImportSource,
2557        should_be_displayed: bool,
2558    ) -> Self {
2559        Self { kind: ImportKind::Simple(name), source, should_be_displayed }
2560    }
2561
2562    pub(crate) fn new_glob(source: ImportSource, should_be_displayed: bool) -> Self {
2563        Self { kind: ImportKind::Glob, source, should_be_displayed }
2564    }
2565
2566    pub(crate) fn imported_item_is_doc_hidden(&self, tcx: TyCtxt<'_>) -> bool {
2567        self.source.did.is_some_and(|did| tcx.is_doc_hidden(did))
2568    }
2569}
2570
2571#[derive(Clone, Debug)]
2572pub(crate) enum ImportKind {
2573    // use source as str;
2574    Simple(Symbol),
2575    // use source::*;
2576    Glob,
2577}
2578
2579#[derive(Clone, Debug)]
2580pub(crate) struct ImportSource {
2581    pub(crate) path: Path,
2582    pub(crate) did: Option<DefId>,
2583}
2584
2585#[derive(Clone, Debug)]
2586pub(crate) struct Macro {
2587    pub(crate) source: String,
2588    /// Whether the macro was defined via `macro_rules!` as opposed to `macro`.
2589    pub(crate) macro_rules: bool,
2590}
2591
2592#[derive(Clone, Debug)]
2593pub(crate) struct ProcMacro {
2594    pub(crate) kind: MacroKind,
2595    pub(crate) helpers: Vec<Symbol>,
2596}
2597
2598/// A constraint on an associated item.
2599///
2600/// ### Examples
2601///
2602/// * the `A = Ty` and `B = Ty` in `Trait<A = Ty, B = Ty>`
2603/// * the `G<Ty> = Ty` in `Trait<G<Ty> = Ty>`
2604/// * the `A: Bound` in `Trait<A: Bound>`
2605/// * the `RetTy` in `Trait(ArgTy, ArgTy) -> RetTy`
2606/// * the `C = { Ct }` in `Trait<C = { Ct }>` (feature `associated_const_equality`)
2607/// * the `f(..): Bound` in `Trait<f(..): Bound>` (feature `return_type_notation`)
2608#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2609pub(crate) struct AssocItemConstraint {
2610    pub(crate) assoc: PathSegment,
2611    pub(crate) kind: AssocItemConstraintKind,
2612}
2613
2614/// The kind of [associated item constraint][AssocItemConstraint].
2615#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2616pub(crate) enum AssocItemConstraintKind {
2617    Equality { term: Term },
2618    Bound { bounds: Vec<GenericBound> },
2619}
2620
2621// Some nodes are used a lot. Make sure they don't unintentionally get bigger.
2622#[cfg(target_pointer_width = "64")]
2623mod size_asserts {
2624    use rustc_data_structures::static_assert_size;
2625
2626    use super::*;
2627    // tidy-alphabetical-start
2628    static_assert_size!(Crate, 16); // frequently moved by-value
2629    static_assert_size!(DocFragment, 32);
2630    static_assert_size!(GenericArg, 32);
2631    static_assert_size!(GenericArgs, 24);
2632    static_assert_size!(GenericParamDef, 40);
2633    static_assert_size!(Generics, 16);
2634    static_assert_size!(Item, 8);
2635    static_assert_size!(ItemInner, 136);
2636    static_assert_size!(ItemKind, 48);
2637    static_assert_size!(PathSegment, 32);
2638    static_assert_size!(Type, 32);
2639    // tidy-alphabetical-end
2640}