Skip to main content

rustdoc/clean/
types.rs

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