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    /// A required method in a trait declaration meaning it's only a function signature.
889    RequiredMethodItem(Box<Function>, Defaultness),
890    /// A method in a trait impl or a provided method in a trait declaration.
891    ///
892    /// Compared to [RequiredMethodItem], it also contains a method body.
893    MethodItem(Box<Function>, Defaultness),
894    StructFieldItem(Type),
895    VariantItem(Variant),
896    /// `fn`s from an extern block
897    ForeignFunctionItem(Box<Function>, hir::Safety),
898    /// `static`s from an extern block
899    ForeignStaticItem(Static, hir::Safety),
900    /// `type`s from an extern block
901    ForeignTypeItem,
902    MacroItem(Macro),
903    ProcMacroItem(ProcMacro),
904    PrimitiveItem(PrimitiveType),
905    /// A required associated constant in a trait declaration.
906    RequiredAssocConstItem(Generics, Box<Type>),
907    ConstantItem(Box<Constant>),
908    /// An associated constant in a trait declaration with provided default value.
909    ProvidedAssocConstItem(Box<Constant>),
910    /// An associated constant in an inherent impl or trait impl.
911    ImplAssocConstItem(Box<Constant>),
912    /// A required associated type in a trait declaration.
913    ///
914    /// The bounds may be non-empty if there is a `where` clause.
915    RequiredAssocTypeItem(Generics, Vec<GenericBound>),
916    /// An associated type in a trait impl or a provided one in a trait declaration.
917    AssocTypeItem(Box<TypeAlias>, Vec<GenericBound>),
918    /// An item that has been stripped by a rustdoc pass
919    StrippedItem(Box<ItemKind>),
920    /// This item represents a module with a `#[doc(keyword = "...")]` attribute which is used
921    /// to generate documentation for Rust keywords.
922    KeywordItem,
923    /// This item represents a module with a `#[doc(attribute = "...")]` attribute which is used
924    /// to generate documentation for Rust builtin attributes.
925    AttributeItem,
926}
927
928impl ItemKind {
929    /// Some items contain others such as structs (for their fields) and Enums
930    /// (for their variants). This method returns those contained items.
931    pub(crate) fn inner_items(&self) -> impl Iterator<Item = &Item> {
932        match self {
933            StructItem(s) => s.fields.iter(),
934            UnionItem(u) => u.fields.iter(),
935            VariantItem(v) => match &v.kind {
936                VariantKind::CLike => [].iter(),
937                VariantKind::Tuple(t) => t.iter(),
938                VariantKind::Struct(s) => s.fields.iter(),
939            },
940            EnumItem(e) => e.variants.iter(),
941            TraitItem(t) => t.items.iter(),
942            ImplItem(i) => i.items.iter(),
943            ModuleItem(m) => m.items.iter(),
944            ExternCrateItem { .. }
945            | ImportItem(_)
946            | FunctionItem(_)
947            | TypeAliasItem(_)
948            | StaticItem(_)
949            | ConstantItem(_)
950            | TraitAliasItem(_)
951            | RequiredMethodItem(..)
952            | MethodItem(..)
953            | StructFieldItem(_)
954            | ForeignFunctionItem(_, _)
955            | ForeignStaticItem(_, _)
956            | ForeignTypeItem
957            | MacroItem(_)
958            | ProcMacroItem(_)
959            | PrimitiveItem(_)
960            | RequiredAssocConstItem(..)
961            | ProvidedAssocConstItem(..)
962            | ImplAssocConstItem(..)
963            | RequiredAssocTypeItem(..)
964            | AssocTypeItem(..)
965            | StrippedItem(_)
966            | KeywordItem
967            | AttributeItem => [].iter(),
968        }
969    }
970}
971
972#[derive(Clone, Debug)]
973pub(crate) struct Module {
974    pub(crate) items: Vec<Item>,
975    pub(crate) span: Span,
976}
977
978/// A link that has not yet been rendered.
979///
980/// This link will be turned into a rendered link by [`Item::links`].
981#[derive(Clone, Debug, PartialEq, Eq, Hash)]
982pub(crate) struct ItemLink {
983    /// The original link written in the markdown
984    pub(crate) link: Box<str>,
985    /// The link text displayed in the HTML.
986    ///
987    /// This may not be the same as `link` if there was a disambiguator
988    /// in an intra-doc link (e.g. \[`fn@f`\])
989    pub(crate) link_text: Box<str>,
990    /// The `DefId` of the Item whose **HTML Page** contains the item being
991    /// linked to. This will be different to `item_id` on item's that don't
992    /// have their own page, such as struct fields and enum variants.
993    pub(crate) page_id: DefId,
994    /// The url fragment to append to the link
995    pub(crate) fragment: Option<UrlFragment>,
996}
997
998pub struct RenderedLink {
999    /// The text the link was original written as.
1000    ///
1001    /// This could potentially include disambiguators and backticks.
1002    pub(crate) original_text: Box<str>,
1003    /// The text to display in the HTML
1004    pub(crate) new_text: Box<str>,
1005    /// The URL to put in the `href`
1006    pub(crate) href: String,
1007    /// The tooltip.
1008    pub(crate) tooltip: String,
1009}
1010
1011/// The attributes on an [`Item`], including attributes like `#[derive(...)]` and `#[inline]`,
1012/// as well as doc comments.
1013#[derive(Clone, Debug, Default)]
1014pub(crate) struct Attributes {
1015    pub(crate) doc_strings: Vec<DocFragment>,
1016    pub(crate) other_attrs: ThinVec<hir::Attribute>,
1017}
1018
1019impl Attributes {
1020    pub(crate) fn has_doc_flag<F: Fn(&DocAttribute) -> bool>(&self, callback: F) -> bool {
1021        find_attr!(&self.other_attrs, Doc(d) if callback(d))
1022    }
1023
1024    pub(crate) fn is_doc_hidden(&self) -> bool {
1025        find_attr!(&self.other_attrs, Doc(d) if d.hidden.is_some())
1026    }
1027
1028    pub(crate) fn from_hir(attrs: &[hir::Attribute]) -> Attributes {
1029        Attributes::from_hir_iter(attrs.iter().map(|attr| (attr, None)), false)
1030    }
1031
1032    pub(crate) fn from_hir_with_additional(
1033        attrs: &[hir::Attribute],
1034        (additional_attrs, def_id): (&[hir::Attribute], DefId),
1035    ) -> Attributes {
1036        // Additional documentation should be shown before the original documentation.
1037        let attrs1 = additional_attrs.iter().map(|attr| (attr, Some(def_id)));
1038        let attrs2 = attrs.iter().map(|attr| (attr, None));
1039        Attributes::from_hir_iter(attrs1.chain(attrs2), false)
1040    }
1041
1042    pub(crate) fn from_hir_iter<'a>(
1043        attrs: impl Iterator<Item = (&'a hir::Attribute, Option<DefId>)>,
1044        doc_only: bool,
1045    ) -> Attributes {
1046        let (doc_strings, other_attrs) = attrs_to_doc_fragments(attrs, doc_only);
1047        Attributes { doc_strings, other_attrs }
1048    }
1049
1050    /// Combine all doc strings into a single value handling indentation and newlines as needed.
1051    pub(crate) fn doc_value(&self) -> String {
1052        self.opt_doc_value().unwrap_or_default()
1053    }
1054
1055    /// Combine all doc strings into a single value handling indentation and newlines as needed.
1056    /// Returns `None` is there's no documentation at all, and `Some("")` if there is some
1057    /// documentation but it is empty (e.g. `#[doc = ""]`).
1058    pub(crate) fn opt_doc_value(&self) -> Option<String> {
1059        (!self.doc_strings.is_empty()).then(|| {
1060            let mut res = String::new();
1061            for frag in &self.doc_strings {
1062                add_doc_fragment(&mut res, frag);
1063            }
1064            res.pop();
1065            res
1066        })
1067    }
1068
1069    pub(crate) fn get_doc_aliases(&self) -> Box<[Symbol]> {
1070        let mut aliases = FxIndexSet::default();
1071
1072        for attr in &self.other_attrs {
1073            if let Attribute::Parsed(AttributeKind::Doc(d)) = attr {
1074                for (alias, _) in &d.aliases {
1075                    aliases.insert(*alias);
1076                }
1077            }
1078        }
1079        aliases.into_iter().collect::<Vec<_>>().into()
1080    }
1081}
1082
1083#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1084pub(crate) enum GenericBound {
1085    TraitBound(PolyTrait, hir::TraitBoundModifiers),
1086    Outlives(Lifetime),
1087    /// `use<'a, T>` precise-capturing bound syntax
1088    Use(Vec<PreciseCapturingArg>),
1089}
1090
1091impl GenericBound {
1092    pub(crate) fn sized(cx: &mut DocContext<'_>) -> GenericBound {
1093        Self::sized_with(cx, hir::TraitBoundModifiers::NONE)
1094    }
1095
1096    pub(crate) fn maybe_sized(cx: &mut DocContext<'_>) -> GenericBound {
1097        Self::sized_with(
1098            cx,
1099            hir::TraitBoundModifiers {
1100                polarity: hir::BoundPolarity::Maybe(DUMMY_SP),
1101                constness: hir::BoundConstness::Never,
1102            },
1103        )
1104    }
1105
1106    fn sized_with(cx: &mut DocContext<'_>, modifiers: hir::TraitBoundModifiers) -> GenericBound {
1107        let did = cx.tcx.require_lang_item(LangItem::Sized, DUMMY_SP);
1108        let empty = ty::Binder::dummy(ty::GenericArgs::empty());
1109        let path = clean_middle_path(cx, did, false, ThinVec::new(), empty);
1110        inline::record_extern_fqn(cx, did, ItemType::Trait);
1111        GenericBound::TraitBound(PolyTrait { trait_: path, generic_params: Vec::new() }, modifiers)
1112    }
1113
1114    pub(crate) fn is_trait_bound(&self) -> bool {
1115        matches!(self, Self::TraitBound(..))
1116    }
1117
1118    pub(crate) fn is_sized_bound(&self, cx: &DocContext<'_>) -> bool {
1119        self.is_bounded_by_lang_item(cx, LangItem::Sized)
1120    }
1121
1122    pub(crate) fn is_meta_sized_bound(&self, cx: &DocContext<'_>) -> bool {
1123        self.is_bounded_by_lang_item(cx, LangItem::MetaSized)
1124    }
1125
1126    fn is_bounded_by_lang_item(&self, cx: &DocContext<'_>, lang_item: LangItem) -> bool {
1127        if let GenericBound::TraitBound(
1128            PolyTrait { ref trait_, .. },
1129            rustc_hir::TraitBoundModifiers::NONE,
1130        ) = *self
1131            && cx.tcx.is_lang_item(trait_.def_id(), lang_item)
1132        {
1133            return true;
1134        }
1135        false
1136    }
1137
1138    pub(crate) fn get_trait_path(&self) -> Option<Path> {
1139        if let GenericBound::TraitBound(PolyTrait { ref trait_, .. }, _) = *self {
1140            Some(trait_.clone())
1141        } else {
1142            None
1143        }
1144    }
1145}
1146
1147#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
1148pub(crate) struct Lifetime(pub Symbol);
1149
1150impl Lifetime {
1151    pub(crate) fn statik() -> Lifetime {
1152        Lifetime(kw::StaticLifetime)
1153    }
1154
1155    pub(crate) fn elided() -> Lifetime {
1156        Lifetime(kw::UnderscoreLifetime)
1157    }
1158}
1159
1160#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
1161pub(crate) enum PreciseCapturingArg {
1162    Lifetime(Lifetime),
1163    Param(Symbol),
1164}
1165
1166impl PreciseCapturingArg {
1167    pub(crate) fn name(self) -> Symbol {
1168        match self {
1169            PreciseCapturingArg::Lifetime(lt) => lt.0,
1170            PreciseCapturingArg::Param(param) => param,
1171        }
1172    }
1173}
1174
1175#[derive(Clone, PartialEq, Eq, Hash, Debug)]
1176pub(crate) enum WherePredicate {
1177    BoundPredicate { ty: Type, bounds: Vec<GenericBound>, bound_params: Vec<GenericParamDef> },
1178    RegionPredicate { lifetime: Lifetime, bounds: Vec<GenericBound> },
1179    EqPredicate { lhs: QPathData, rhs: Term },
1180}
1181
1182impl WherePredicate {
1183    pub(crate) fn get_bounds(&self) -> Option<&[GenericBound]> {
1184        match self {
1185            WherePredicate::BoundPredicate { bounds, .. } => Some(bounds),
1186            WherePredicate::RegionPredicate { bounds, .. } => Some(bounds),
1187            _ => None,
1188        }
1189    }
1190}
1191
1192#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1193pub(crate) enum GenericParamDefKind {
1194    Lifetime { outlives: ThinVec<Lifetime> },
1195    Type { bounds: ThinVec<GenericBound>, default: Option<Box<Type>>, synthetic: bool },
1196    // Option<Box<String>> makes this type smaller than `Option<String>` would.
1197    Const { ty: Box<Type>, default: Option<Box<String>> },
1198}
1199
1200impl GenericParamDefKind {
1201    pub(crate) fn is_type(&self) -> bool {
1202        matches!(self, GenericParamDefKind::Type { .. })
1203    }
1204}
1205
1206#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1207pub(crate) struct GenericParamDef {
1208    pub(crate) name: Symbol,
1209    pub(crate) def_id: DefId,
1210    pub(crate) kind: GenericParamDefKind,
1211}
1212
1213impl GenericParamDef {
1214    pub(crate) fn lifetime(def_id: DefId, name: Symbol) -> Self {
1215        Self { name, def_id, kind: GenericParamDefKind::Lifetime { outlives: ThinVec::new() } }
1216    }
1217
1218    pub(crate) fn is_synthetic_param(&self) -> bool {
1219        match self.kind {
1220            GenericParamDefKind::Lifetime { .. } | GenericParamDefKind::Const { .. } => false,
1221            GenericParamDefKind::Type { synthetic, .. } => synthetic,
1222        }
1223    }
1224
1225    pub(crate) fn is_type(&self) -> bool {
1226        self.kind.is_type()
1227    }
1228
1229    pub(crate) fn get_bounds(&self) -> Option<&[GenericBound]> {
1230        match self.kind {
1231            GenericParamDefKind::Type { ref bounds, .. } => Some(bounds),
1232            _ => None,
1233        }
1234    }
1235}
1236
1237// maybe use a Generic enum and use Vec<Generic>?
1238#[derive(Clone, PartialEq, Eq, Hash, Debug, Default)]
1239pub(crate) struct Generics {
1240    pub(crate) params: ThinVec<GenericParamDef>,
1241    pub(crate) where_predicates: ThinVec<WherePredicate>,
1242}
1243
1244impl Generics {
1245    pub(crate) fn is_empty(&self) -> bool {
1246        self.params.is_empty() && self.where_predicates.is_empty()
1247    }
1248}
1249
1250#[derive(Clone, Debug)]
1251pub(crate) struct Function {
1252    pub(crate) decl: FnDecl,
1253    pub(crate) generics: Generics,
1254}
1255
1256#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1257pub(crate) struct FnDecl {
1258    pub(crate) inputs: Vec<Parameter>,
1259    pub(crate) output: Type,
1260    pub(crate) c_variadic: bool,
1261}
1262
1263impl FnDecl {
1264    pub(crate) fn receiver_type(&self) -> Option<&Type> {
1265        self.inputs.first().and_then(|v| v.to_receiver())
1266    }
1267}
1268
1269/// A function parameter.
1270#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1271pub(crate) struct Parameter {
1272    pub(crate) name: Option<Symbol>,
1273    pub(crate) type_: Type,
1274    /// This field is used to represent "const" arguments from the `rustc_legacy_const_generics`
1275    /// feature. More information in <https://github.com/rust-lang/rust/issues/83167>.
1276    pub(crate) is_const: bool,
1277}
1278
1279impl Parameter {
1280    pub(crate) fn to_receiver(&self) -> Option<&Type> {
1281        if self.name == Some(kw::SelfLower) { Some(&self.type_) } else { None }
1282    }
1283}
1284
1285#[derive(Clone, Debug)]
1286pub(crate) struct Trait {
1287    pub(crate) def_id: DefId,
1288    pub(crate) items: Vec<Item>,
1289    pub(crate) generics: Generics,
1290    pub(crate) bounds: Vec<GenericBound>,
1291}
1292
1293impl Trait {
1294    pub(crate) fn is_auto(&self, tcx: TyCtxt<'_>) -> bool {
1295        tcx.trait_is_auto(self.def_id)
1296    }
1297    pub(crate) fn is_notable_trait(&self, tcx: TyCtxt<'_>) -> bool {
1298        tcx.is_doc_notable_trait(self.def_id)
1299    }
1300    pub(crate) fn safety(&self, tcx: TyCtxt<'_>) -> hir::Safety {
1301        tcx.trait_def(self.def_id).safety
1302    }
1303    pub(crate) fn is_dyn_compatible(&self, tcx: TyCtxt<'_>) -> bool {
1304        tcx.is_dyn_compatible(self.def_id)
1305    }
1306    pub(crate) fn is_deprecated(&self, tcx: TyCtxt<'_>) -> bool {
1307        tcx.lookup_deprecation(self.def_id).is_some_and(|deprecation| deprecation.is_in_effect())
1308    }
1309}
1310
1311#[derive(Clone, Debug)]
1312pub(crate) struct TraitAlias {
1313    pub(crate) generics: Generics,
1314    pub(crate) bounds: Vec<GenericBound>,
1315}
1316
1317/// A trait reference, which may have higher ranked lifetimes.
1318#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1319pub(crate) struct PolyTrait {
1320    pub(crate) trait_: Path,
1321    pub(crate) generic_params: Vec<GenericParamDef>,
1322}
1323
1324/// Rustdoc's representation of types, mostly based on the [`hir::Ty`].
1325#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1326pub(crate) enum Type {
1327    /// A named type, which could be a trait.
1328    ///
1329    /// This is mostly Rustdoc's version of [`hir::Path`].
1330    /// It has to be different because Rustdoc's [`PathSegment`] can contain cleaned generics.
1331    Path {
1332        path: Path,
1333    },
1334    /// A `dyn Trait` object: `dyn for<'a> Trait<'a> + Send + 'static`
1335    DynTrait(Vec<PolyTrait>, Option<Lifetime>),
1336    /// A type parameter.
1337    Generic(Symbol),
1338    /// The `Self` type.
1339    SelfTy,
1340    /// A primitive (aka, builtin) type.
1341    Primitive(PrimitiveType),
1342    /// A function pointer: `extern "ABI" fn(...) -> ...`
1343    BareFunction(Box<BareFunctionDecl>),
1344    /// A tuple type: `(i32, &str)`.
1345    Tuple(Vec<Type>),
1346    /// A slice type (does *not* include the `&`): `[i32]`
1347    Slice(Box<Type>),
1348    /// An array type.
1349    ///
1350    /// The `String` field is a stringified version of the array's length parameter.
1351    Array(Box<Type>, Box<str>),
1352    Pat(Box<Type>, Box<str>),
1353    FieldOf(Box<Type>, Box<str>),
1354    /// A raw pointer type: `*const i32`, `*mut i32`
1355    RawPointer(Mutability, Box<Type>),
1356    /// A reference type: `&i32`, `&'a mut Foo`
1357    BorrowedRef {
1358        lifetime: Option<Lifetime>,
1359        mutability: Mutability,
1360        type_: Box<Type>,
1361    },
1362
1363    /// A qualified path to an associated item: `<Type as Trait>::Name`
1364    QPath(Box<QPathData>),
1365
1366    /// A type that is inferred: `_`
1367    Infer,
1368
1369    /// An `impl Trait`: `impl TraitA + TraitB + ...`
1370    ImplTrait(Vec<GenericBound>),
1371
1372    UnsafeBinder(Box<UnsafeBinderTy>),
1373}
1374
1375impl Type {
1376    /// When comparing types for equality, it can help to ignore `&` wrapping.
1377    pub(crate) fn without_borrowed_ref(&self) -> &Type {
1378        let mut result = self;
1379        while let Type::BorrowedRef { type_, .. } = result {
1380            result = type_;
1381        }
1382        result
1383    }
1384
1385    pub(crate) fn is_borrowed_ref(&self) -> bool {
1386        matches!(self, Type::BorrowedRef { .. })
1387    }
1388
1389    fn is_type_alias(&self) -> bool {
1390        matches!(self, Type::Path { path: Path { res: Res::Def(DefKind::TyAlias, _), .. } })
1391    }
1392
1393    /// Check if this type is a subtype of another type for documentation purposes.
1394    ///
1395    /// This is different from `Eq`, because it knows that things like
1396    /// `Infer` and generics have special subtyping rules.
1397    ///
1398    /// This relation is not commutative when generics are involved:
1399    ///
1400    /// ```ignore(private)
1401    /// # // see types/tests.rs:is_same_generic for the real test
1402    /// use rustdoc::format::cache::Cache;
1403    /// use rustdoc::clean::types::{Type, PrimitiveType};
1404    /// let cache = Cache::new(false);
1405    /// let generic = Type::Generic(Symbol::intern("T"));
1406    /// let unit = Type::Primitive(PrimitiveType::Unit);
1407    /// assert!(!generic.is_doc_subtype_of(&unit, &cache));
1408    /// assert!(unit.is_doc_subtype_of(&generic, &cache));
1409    /// ```
1410    ///
1411    /// An owned type is also the same as its borrowed variants (this is commutative),
1412    /// but `&T` is not the same as `&mut T`.
1413    pub(crate) fn is_doc_subtype_of(&self, other: &Self, cache: &Cache) -> bool {
1414        // Strip the references so that it can compare the actual types, unless both are references.
1415        // If both are references, leave them alone and compare the mutabilities later.
1416        let (self_cleared, other_cleared) = if !self.is_borrowed_ref() || !other.is_borrowed_ref() {
1417            (self.without_borrowed_ref(), other.without_borrowed_ref())
1418        } else {
1419            (self, other)
1420        };
1421
1422        // FIXME: `Cache` does not have the data required to unwrap type aliases,
1423        // so we just assume they are equal.
1424        // This is only remotely acceptable because we were previously
1425        // assuming all types were equal when used
1426        // as a generic parameter of a type in `Deref::Target`.
1427        if self_cleared.is_type_alias() || other_cleared.is_type_alias() {
1428            return true;
1429        }
1430
1431        match (self_cleared, other_cleared) {
1432            // Recursive cases.
1433            (Type::Tuple(a), Type::Tuple(b)) => {
1434                a.iter().eq_by(b, |a, b| a.is_doc_subtype_of(b, cache))
1435            }
1436            (Type::Slice(a), Type::Slice(b)) => a.is_doc_subtype_of(b, cache),
1437            (Type::Array(a, al), Type::Array(b, bl)) => al == bl && a.is_doc_subtype_of(b, cache),
1438            (Type::RawPointer(mutability, type_), Type::RawPointer(b_mutability, b_type_)) => {
1439                mutability == b_mutability && type_.is_doc_subtype_of(b_type_, cache)
1440            }
1441            (
1442                Type::BorrowedRef { mutability, type_, .. },
1443                Type::BorrowedRef { mutability: b_mutability, type_: b_type_, .. },
1444            ) => mutability == b_mutability && type_.is_doc_subtype_of(b_type_, cache),
1445            // Placeholders are equal to all other types.
1446            (Type::Infer, _) | (_, Type::Infer) => true,
1447            // Generics match everything on the right, but not on the left.
1448            // If both sides are generic, this returns true.
1449            (_, Type::Generic(_)) => true,
1450            (Type::Generic(_), _) => false,
1451            // `Self` only matches itself.
1452            (Type::SelfTy, Type::SelfTy) => true,
1453            // Paths account for both the path itself and its generics.
1454            (Type::Path { path: a }, Type::Path { path: b }) => {
1455                a.def_id() == b.def_id()
1456                    && a.generics()
1457                        .zip(b.generics())
1458                        .map(|(ag, bg)| ag.zip(bg).all(|(at, bt)| at.is_doc_subtype_of(bt, cache)))
1459                        .unwrap_or(true)
1460            }
1461            // Other cases, such as primitives, just use recursion.
1462            (a, b) => a
1463                .def_id(cache)
1464                .and_then(|a| Some((a, b.def_id(cache)?)))
1465                .map(|(a, b)| a == b)
1466                .unwrap_or(false),
1467        }
1468    }
1469
1470    pub(crate) fn primitive_type(&self) -> Option<PrimitiveType> {
1471        match *self {
1472            Primitive(p) | BorrowedRef { type_: box Primitive(p), .. } => Some(p),
1473            Slice(..) | BorrowedRef { type_: box Slice(..), .. } => Some(PrimitiveType::Slice),
1474            Array(..) | BorrowedRef { type_: box Array(..), .. } => Some(PrimitiveType::Array),
1475            Tuple(ref tys) => {
1476                if tys.is_empty() {
1477                    Some(PrimitiveType::Unit)
1478                } else {
1479                    Some(PrimitiveType::Tuple)
1480                }
1481            }
1482            RawPointer(..) => Some(PrimitiveType::RawPointer),
1483            BareFunction(..) => Some(PrimitiveType::Fn),
1484            _ => None,
1485        }
1486    }
1487
1488    /// Returns the sugared return type for an async function.
1489    ///
1490    /// For example, if the return type is `impl std::future::Future<Output = i32>`, this function
1491    /// will return `i32`.
1492    ///
1493    /// # Panics
1494    ///
1495    /// This function will panic if the return type does not match the expected sugaring for async
1496    /// functions.
1497    pub(crate) fn sugared_async_return_type(self) -> Type {
1498        if let Type::ImplTrait(mut v) = self
1499            && let Some(GenericBound::TraitBound(PolyTrait { mut trait_, .. }, _)) = v.pop()
1500            && let Some(segment) = trait_.segments.pop()
1501            && let GenericArgs::AngleBracketed { mut constraints, .. } = segment.args
1502            && let Some(constraint) = constraints.pop()
1503            && let AssocItemConstraintKind::Equality { term } = constraint.kind
1504            && let Term::Type(ty) = term
1505        {
1506            ty
1507        } else {
1508            panic!("unexpected async fn return type")
1509        }
1510    }
1511
1512    /// Checks if this is a `T::Name` path for an associated type.
1513    pub(crate) fn is_assoc_ty(&self) -> bool {
1514        match self {
1515            Type::Path { path, .. } => path.is_assoc_ty(),
1516            _ => false,
1517        }
1518    }
1519
1520    pub(crate) fn is_self_type(&self) -> bool {
1521        matches!(*self, Type::SelfTy)
1522    }
1523
1524    pub(crate) fn generic_args(&self) -> Option<&GenericArgs> {
1525        match self {
1526            Type::Path { path, .. } => path.generic_args(),
1527            _ => None,
1528        }
1529    }
1530
1531    pub(crate) fn generics(&self) -> Option<impl Iterator<Item = &Type>> {
1532        match self {
1533            Type::Path { path, .. } => path.generics(),
1534            _ => None,
1535        }
1536    }
1537
1538    pub(crate) fn is_full_generic(&self) -> bool {
1539        matches!(self, Type::Generic(_))
1540    }
1541
1542    pub(crate) fn is_unit(&self) -> bool {
1543        matches!(self, Type::Tuple(v) if v.is_empty())
1544    }
1545
1546    /// Use this method to get the [DefId] of a [clean] AST node, including [PrimitiveType]s.
1547    ///
1548    /// [clean]: crate::clean
1549    pub(crate) fn def_id(&self, cache: &Cache) -> Option<DefId> {
1550        let t: PrimitiveType = match self {
1551            Type::Path { path } => return Some(path.def_id()),
1552            DynTrait(bounds, _) => return bounds.first().map(|b| b.trait_.def_id()),
1553            Primitive(p) => return cache.primitive_locations.get(p).cloned(),
1554            BorrowedRef { type_: box Generic(..), .. } => PrimitiveType::Reference,
1555            BorrowedRef { type_, .. } => return type_.def_id(cache),
1556            Tuple(tys) => {
1557                if tys.is_empty() {
1558                    PrimitiveType::Unit
1559                } else {
1560                    PrimitiveType::Tuple
1561                }
1562            }
1563            BareFunction(..) => PrimitiveType::Fn,
1564            Slice(..) => PrimitiveType::Slice,
1565            Array(..) => PrimitiveType::Array,
1566            Type::Pat(..) => PrimitiveType::Pat,
1567            Type::FieldOf(..) => PrimitiveType::FieldOf,
1568            RawPointer(..) => PrimitiveType::RawPointer,
1569            QPath(box QPathData { self_type, .. }) => return self_type.def_id(cache),
1570            Generic(_) | SelfTy | Infer | ImplTrait(_) | UnsafeBinder(_) => return None,
1571        };
1572        Primitive(t).def_id(cache)
1573    }
1574}
1575
1576#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1577pub(crate) struct QPathData {
1578    pub assoc: PathSegment,
1579    pub self_type: Type,
1580    /// FIXME: compute this field on demand.
1581    pub should_fully_qualify: bool,
1582    pub trait_: Option<Path>,
1583}
1584
1585/// A primitive (aka, builtin) type.
1586///
1587/// This represents things like `i32`, `str`, etc.
1588///
1589/// N.B. This has to be different from [`hir::PrimTy`] because it also includes types that aren't
1590/// paths, like [`Self::Unit`].
1591#[derive(Clone, PartialEq, Eq, Hash, Copy, Debug)]
1592pub(crate) enum PrimitiveType {
1593    Isize,
1594    I8,
1595    I16,
1596    I32,
1597    I64,
1598    I128,
1599    Usize,
1600    U8,
1601    U16,
1602    U32,
1603    U64,
1604    U128,
1605    F16,
1606    F32,
1607    F64,
1608    F128,
1609    Char,
1610    Bool,
1611    Str,
1612    Slice,
1613    Array,
1614    Pat,
1615    FieldOf,
1616    Tuple,
1617    Unit,
1618    RawPointer,
1619    Reference,
1620    Fn,
1621    Never,
1622}
1623
1624type SimplifiedTypes = FxIndexMap<PrimitiveType, ArrayVec<SimplifiedType, 3>>;
1625impl PrimitiveType {
1626    pub(crate) fn from_hir(prim: hir::PrimTy) -> PrimitiveType {
1627        use ast::{FloatTy, IntTy, UintTy};
1628        match prim {
1629            hir::PrimTy::Int(IntTy::Isize) => PrimitiveType::Isize,
1630            hir::PrimTy::Int(IntTy::I8) => PrimitiveType::I8,
1631            hir::PrimTy::Int(IntTy::I16) => PrimitiveType::I16,
1632            hir::PrimTy::Int(IntTy::I32) => PrimitiveType::I32,
1633            hir::PrimTy::Int(IntTy::I64) => PrimitiveType::I64,
1634            hir::PrimTy::Int(IntTy::I128) => PrimitiveType::I128,
1635            hir::PrimTy::Uint(UintTy::Usize) => PrimitiveType::Usize,
1636            hir::PrimTy::Uint(UintTy::U8) => PrimitiveType::U8,
1637            hir::PrimTy::Uint(UintTy::U16) => PrimitiveType::U16,
1638            hir::PrimTy::Uint(UintTy::U32) => PrimitiveType::U32,
1639            hir::PrimTy::Uint(UintTy::U64) => PrimitiveType::U64,
1640            hir::PrimTy::Uint(UintTy::U128) => PrimitiveType::U128,
1641            hir::PrimTy::Float(FloatTy::F16) => PrimitiveType::F16,
1642            hir::PrimTy::Float(FloatTy::F32) => PrimitiveType::F32,
1643            hir::PrimTy::Float(FloatTy::F64) => PrimitiveType::F64,
1644            hir::PrimTy::Float(FloatTy::F128) => PrimitiveType::F128,
1645            hir::PrimTy::Str => PrimitiveType::Str,
1646            hir::PrimTy::Bool => PrimitiveType::Bool,
1647            hir::PrimTy::Char => PrimitiveType::Char,
1648        }
1649    }
1650
1651    pub(crate) fn from_symbol(s: Symbol) -> Option<PrimitiveType> {
1652        match s {
1653            sym::isize => Some(PrimitiveType::Isize),
1654            sym::i8 => Some(PrimitiveType::I8),
1655            sym::i16 => Some(PrimitiveType::I16),
1656            sym::i32 => Some(PrimitiveType::I32),
1657            sym::i64 => Some(PrimitiveType::I64),
1658            sym::i128 => Some(PrimitiveType::I128),
1659            sym::usize => Some(PrimitiveType::Usize),
1660            sym::u8 => Some(PrimitiveType::U8),
1661            sym::u16 => Some(PrimitiveType::U16),
1662            sym::u32 => Some(PrimitiveType::U32),
1663            sym::u64 => Some(PrimitiveType::U64),
1664            sym::u128 => Some(PrimitiveType::U128),
1665            sym::bool => Some(PrimitiveType::Bool),
1666            sym::char => Some(PrimitiveType::Char),
1667            sym::str => Some(PrimitiveType::Str),
1668            sym::f16 => Some(PrimitiveType::F16),
1669            sym::f32 => Some(PrimitiveType::F32),
1670            sym::f64 => Some(PrimitiveType::F64),
1671            sym::f128 => Some(PrimitiveType::F128),
1672            sym::array => Some(PrimitiveType::Array),
1673            sym::slice => Some(PrimitiveType::Slice),
1674            sym::tuple => Some(PrimitiveType::Tuple),
1675            sym::unit => Some(PrimitiveType::Unit),
1676            sym::pointer => Some(PrimitiveType::RawPointer),
1677            sym::reference => Some(PrimitiveType::Reference),
1678            kw::Fn => Some(PrimitiveType::Fn),
1679            sym::never => Some(PrimitiveType::Never),
1680            _ => None,
1681        }
1682    }
1683
1684    pub(crate) fn simplified_types() -> &'static SimplifiedTypes {
1685        use PrimitiveType::*;
1686        use ty::{FloatTy, IntTy, UintTy};
1687        static CELL: OnceCell<SimplifiedTypes> = OnceCell::new();
1688
1689        let single = |x| iter::once(x).collect();
1690        CELL.get_or_init(move || {
1691            map! {
1692                Isize => single(SimplifiedType::Int(IntTy::Isize)),
1693                I8 => single(SimplifiedType::Int(IntTy::I8)),
1694                I16 => single(SimplifiedType::Int(IntTy::I16)),
1695                I32 => single(SimplifiedType::Int(IntTy::I32)),
1696                I64 => single(SimplifiedType::Int(IntTy::I64)),
1697                I128 => single(SimplifiedType::Int(IntTy::I128)),
1698                Usize => single(SimplifiedType::Uint(UintTy::Usize)),
1699                U8 => single(SimplifiedType::Uint(UintTy::U8)),
1700                U16 => single(SimplifiedType::Uint(UintTy::U16)),
1701                U32 => single(SimplifiedType::Uint(UintTy::U32)),
1702                U64 => single(SimplifiedType::Uint(UintTy::U64)),
1703                U128 => single(SimplifiedType::Uint(UintTy::U128)),
1704                F16 => single(SimplifiedType::Float(FloatTy::F16)),
1705                F32 => single(SimplifiedType::Float(FloatTy::F32)),
1706                F64 => single(SimplifiedType::Float(FloatTy::F64)),
1707                F128 => single(SimplifiedType::Float(FloatTy::F128)),
1708                Str => single(SimplifiedType::Str),
1709                Bool => single(SimplifiedType::Bool),
1710                Char => single(SimplifiedType::Char),
1711                Array => single(SimplifiedType::Array),
1712                Slice => single(SimplifiedType::Slice),
1713                // FIXME: If we ever add an inherent impl for tuples
1714                // with different lengths, they won't show in rustdoc.
1715                //
1716                // Either manually update this arrayvec at this point
1717                // or start with a more complex refactoring.
1718                Tuple => [SimplifiedType::Tuple(1), SimplifiedType::Tuple(2), SimplifiedType::Tuple(3)].into(),
1719                Unit => single(SimplifiedType::Tuple(0)),
1720                RawPointer => [SimplifiedType::Ptr(Mutability::Not), SimplifiedType::Ptr(Mutability::Mut)].into_iter().collect(),
1721                Reference => [SimplifiedType::Ref(Mutability::Not), SimplifiedType::Ref(Mutability::Mut)].into_iter().collect(),
1722                // FIXME: This will be wrong if we ever add inherent impls
1723                // for function pointers.
1724                Fn => single(SimplifiedType::Function(1)),
1725                Never => single(SimplifiedType::Never),
1726            }
1727        })
1728    }
1729
1730    pub(crate) fn impls<'tcx>(&self, tcx: TyCtxt<'tcx>) -> impl Iterator<Item = DefId> + 'tcx {
1731        Self::simplified_types()
1732            .get(self)
1733            .into_iter()
1734            .flatten()
1735            .flat_map(move |&simp| tcx.incoherent_impls(simp).iter())
1736            .copied()
1737    }
1738
1739    pub(crate) fn all_impls(tcx: TyCtxt<'_>) -> impl Iterator<Item = DefId> {
1740        Self::simplified_types()
1741            .values()
1742            .flatten()
1743            .flat_map(move |&simp| tcx.incoherent_impls(simp).iter())
1744            .copied()
1745    }
1746
1747    pub(crate) fn as_sym(&self) -> Symbol {
1748        use PrimitiveType::*;
1749        match self {
1750            Isize => sym::isize,
1751            I8 => sym::i8,
1752            I16 => sym::i16,
1753            I32 => sym::i32,
1754            I64 => sym::i64,
1755            I128 => sym::i128,
1756            Usize => sym::usize,
1757            U8 => sym::u8,
1758            U16 => sym::u16,
1759            U32 => sym::u32,
1760            U64 => sym::u64,
1761            U128 => sym::u128,
1762            F16 => sym::f16,
1763            F32 => sym::f32,
1764            F64 => sym::f64,
1765            F128 => sym::f128,
1766            Str => sym::str,
1767            Bool => sym::bool,
1768            Char => sym::char,
1769            Array => sym::array,
1770            Pat => sym::pat,
1771            FieldOf => sym::field_of,
1772            Slice => sym::slice,
1773            Tuple => sym::tuple,
1774            Unit => sym::unit,
1775            RawPointer => sym::pointer,
1776            Reference => sym::reference,
1777            Fn => kw::Fn,
1778            Never => sym::never,
1779        }
1780    }
1781
1782    /// Returns the DefId of the module with `rustc_doc_primitive` for this primitive type.
1783    /// Panics if there is no such module.
1784    ///
1785    /// This gives precedence to primitives defined in the current crate, and deprioritizes
1786    /// primitives defined in `core`,
1787    /// but otherwise, if multiple crates define the same primitive, there is no guarantee of which
1788    /// will be picked.
1789    ///
1790    /// In particular, if a crate depends on both `std` and another crate that also defines
1791    /// `rustc_doc_primitive`, then it's entirely random whether `std` or the other crate is picked.
1792    /// (no_std crates are usually fine unless multiple dependencies define a primitive.)
1793    pub(crate) fn primitive_locations(tcx: TyCtxt<'_>) -> &FxIndexMap<PrimitiveType, DefId> {
1794        static PRIMITIVE_LOCATIONS: OnceCell<FxIndexMap<PrimitiveType, DefId>> = OnceCell::new();
1795        PRIMITIVE_LOCATIONS.get_or_init(|| {
1796            let mut primitive_locations = FxIndexMap::default();
1797            // NOTE: technically this misses crates that are only passed with `--extern` and not loaded when checking the crate.
1798            // This is a degenerate case that I don't plan to support.
1799            for &crate_num in tcx.crates(()) {
1800                let e = ExternalCrate { crate_num };
1801                let crate_name = e.name(tcx);
1802                debug!(?crate_num, ?crate_name);
1803                for (def_id, prim) in e.primitives(tcx) {
1804                    // HACK: try to link to std instead where possible
1805                    if crate_name == sym::core && primitive_locations.contains_key(&prim) {
1806                        continue;
1807                    }
1808                    primitive_locations.insert(prim, def_id);
1809                }
1810            }
1811            let local_primitives = ExternalCrate { crate_num: LOCAL_CRATE }.primitives(tcx);
1812            for (def_id, prim) in local_primitives {
1813                primitive_locations.insert(prim, def_id);
1814            }
1815            primitive_locations
1816        })
1817    }
1818}
1819
1820impl From<ty::IntTy> for PrimitiveType {
1821    fn from(int_ty: ty::IntTy) -> PrimitiveType {
1822        match int_ty {
1823            ty::IntTy::Isize => PrimitiveType::Isize,
1824            ty::IntTy::I8 => PrimitiveType::I8,
1825            ty::IntTy::I16 => PrimitiveType::I16,
1826            ty::IntTy::I32 => PrimitiveType::I32,
1827            ty::IntTy::I64 => PrimitiveType::I64,
1828            ty::IntTy::I128 => PrimitiveType::I128,
1829        }
1830    }
1831}
1832
1833impl From<ty::UintTy> for PrimitiveType {
1834    fn from(uint_ty: ty::UintTy) -> PrimitiveType {
1835        match uint_ty {
1836            ty::UintTy::Usize => PrimitiveType::Usize,
1837            ty::UintTy::U8 => PrimitiveType::U8,
1838            ty::UintTy::U16 => PrimitiveType::U16,
1839            ty::UintTy::U32 => PrimitiveType::U32,
1840            ty::UintTy::U64 => PrimitiveType::U64,
1841            ty::UintTy::U128 => PrimitiveType::U128,
1842        }
1843    }
1844}
1845
1846impl From<ty::FloatTy> for PrimitiveType {
1847    fn from(float_ty: ty::FloatTy) -> PrimitiveType {
1848        match float_ty {
1849            ty::FloatTy::F16 => PrimitiveType::F16,
1850            ty::FloatTy::F32 => PrimitiveType::F32,
1851            ty::FloatTy::F64 => PrimitiveType::F64,
1852            ty::FloatTy::F128 => PrimitiveType::F128,
1853        }
1854    }
1855}
1856
1857impl From<hir::PrimTy> for PrimitiveType {
1858    fn from(prim_ty: hir::PrimTy) -> PrimitiveType {
1859        match prim_ty {
1860            hir::PrimTy::Int(int_ty) => int_ty.into(),
1861            hir::PrimTy::Uint(uint_ty) => uint_ty.into(),
1862            hir::PrimTy::Float(float_ty) => float_ty.into(),
1863            hir::PrimTy::Str => PrimitiveType::Str,
1864            hir::PrimTy::Bool => PrimitiveType::Bool,
1865            hir::PrimTy::Char => PrimitiveType::Char,
1866        }
1867    }
1868}
1869
1870#[derive(Clone, Debug)]
1871pub(crate) struct Struct {
1872    pub(crate) ctor_kind: Option<CtorKind>,
1873    pub(crate) generics: Generics,
1874    pub(crate) fields: ThinVec<Item>,
1875}
1876
1877impl Struct {
1878    pub(crate) fn has_stripped_entries(&self) -> bool {
1879        self.fields.iter().any(|f| f.is_stripped())
1880    }
1881}
1882
1883#[derive(Clone, Debug)]
1884pub(crate) struct Union {
1885    pub(crate) generics: Generics,
1886    pub(crate) fields: Vec<Item>,
1887}
1888
1889impl Union {
1890    pub(crate) fn has_stripped_entries(&self) -> bool {
1891        self.fields.iter().any(|f| f.is_stripped())
1892    }
1893}
1894
1895/// This is a more limited form of the standard Struct, different in that
1896/// it lacks the things most items have (name, id, parameterization). Found
1897/// only as a variant in an enum.
1898#[derive(Clone, Debug)]
1899pub(crate) struct VariantStruct {
1900    pub(crate) fields: ThinVec<Item>,
1901}
1902
1903impl VariantStruct {
1904    pub(crate) fn has_stripped_entries(&self) -> bool {
1905        self.fields.iter().any(|f| f.is_stripped())
1906    }
1907}
1908
1909#[derive(Clone, Debug)]
1910pub(crate) struct Enum {
1911    pub(crate) variants: IndexVec<VariantIdx, Item>,
1912    pub(crate) generics: Generics,
1913}
1914
1915impl Enum {
1916    pub(crate) fn has_stripped_entries(&self) -> bool {
1917        self.variants.iter().any(|f| f.is_stripped())
1918    }
1919
1920    pub(crate) fn non_stripped_variants(&self) -> impl Iterator<Item = &Item> {
1921        self.variants.iter().filter(|v| !v.is_stripped())
1922    }
1923}
1924
1925#[derive(Clone, Debug)]
1926pub(crate) struct Variant {
1927    pub kind: VariantKind,
1928    pub discriminant: Option<Discriminant>,
1929}
1930
1931#[derive(Clone, Debug)]
1932pub(crate) enum VariantKind {
1933    CLike,
1934    Tuple(ThinVec<Item>),
1935    Struct(VariantStruct),
1936}
1937
1938impl Variant {
1939    pub(crate) fn has_stripped_entries(&self) -> Option<bool> {
1940        match &self.kind {
1941            VariantKind::Struct(struct_) => Some(struct_.has_stripped_entries()),
1942            VariantKind::CLike | VariantKind::Tuple(_) => None,
1943        }
1944    }
1945}
1946
1947#[derive(Clone, Debug)]
1948pub(crate) struct Discriminant {
1949    // In the case of cross crate re-exports, we don't have the necessary information
1950    // to reconstruct the expression of the discriminant, only the value.
1951    pub(super) expr: Option<BodyId>,
1952    pub(super) value: DefId,
1953}
1954
1955impl Discriminant {
1956    /// Will be `None` in the case of cross-crate reexports, and may be
1957    /// simplified
1958    pub(crate) fn expr(&self, tcx: TyCtxt<'_>) -> Option<String> {
1959        self.expr
1960            .map(|body| rendered_const(tcx, tcx.hir_body(body), tcx.hir_body_owner_def_id(body)))
1961    }
1962    pub(crate) fn value(&self, tcx: TyCtxt<'_>, with_underscores: bool) -> String {
1963        print_evaluated_const(tcx, self.value, with_underscores, false).unwrap()
1964    }
1965}
1966
1967/// Small wrapper around [`rustc_span::Span`] that adds helper methods
1968/// and enforces calling [`rustc_span::Span::source_callsite()`].
1969#[derive(Copy, Clone, Debug)]
1970pub(crate) struct Span(rustc_span::Span);
1971
1972impl Span {
1973    /// Wraps a [`rustc_span::Span`]. In case this span is the result of a macro expansion, the
1974    /// span will be updated to point to the macro invocation instead of the macro definition.
1975    ///
1976    /// (See rust-lang/rust#39726)
1977    pub(crate) fn new(sp: rustc_span::Span) -> Self {
1978        Self(sp.source_callsite())
1979    }
1980
1981    pub(crate) fn inner(&self) -> rustc_span::Span {
1982        self.0
1983    }
1984
1985    pub(crate) fn filename(&self, sess: &Session) -> FileName {
1986        sess.source_map().span_to_filename(self.0)
1987    }
1988
1989    pub(crate) fn lo(&self, sess: &Session) -> Loc {
1990        sess.source_map().lookup_char_pos(self.0.lo())
1991    }
1992
1993    pub(crate) fn hi(&self, sess: &Session) -> Loc {
1994        sess.source_map().lookup_char_pos(self.0.hi())
1995    }
1996
1997    pub(crate) fn cnum(&self, sess: &Session) -> CrateNum {
1998        // FIXME: is there a time when the lo and hi crate would be different?
1999        self.lo(sess).file.cnum
2000    }
2001}
2002
2003#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2004pub(crate) struct Path {
2005    pub(crate) res: Res,
2006    pub(crate) segments: ThinVec<PathSegment>,
2007}
2008
2009impl Path {
2010    pub(crate) fn def_id(&self) -> DefId {
2011        self.res.def_id()
2012    }
2013
2014    pub(crate) fn last_opt(&self) -> Option<Symbol> {
2015        self.segments.last().map(|s| s.name)
2016    }
2017
2018    pub(crate) fn last(&self) -> Symbol {
2019        self.last_opt().expect("segments were empty")
2020    }
2021
2022    pub(crate) fn whole_name(&self) -> String {
2023        self.segments
2024            .iter()
2025            .map(|s| if s.name == kw::PathRoot { "" } else { s.name.as_str() })
2026            .intersperse("::")
2027            .collect()
2028    }
2029
2030    /// Checks if this is a `T::Name` path for an associated type.
2031    pub(crate) fn is_assoc_ty(&self) -> bool {
2032        match self.res {
2033            Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } | Res::Def(DefKind::TyParam, _)
2034                if self.segments.len() != 1 =>
2035            {
2036                true
2037            }
2038            Res::Def(DefKind::AssocTy, _) => true,
2039            _ => false,
2040        }
2041    }
2042
2043    pub(crate) fn generic_args(&self) -> Option<&GenericArgs> {
2044        self.segments.last().map(|seg| &seg.args)
2045    }
2046
2047    pub(crate) fn generics(&self) -> Option<impl Iterator<Item = &Type>> {
2048        self.segments.last().and_then(|seg| {
2049            if let GenericArgs::AngleBracketed { ref args, .. } = seg.args {
2050                Some(args.iter().filter_map(|arg| match arg {
2051                    GenericArg::Type(ty) => Some(ty),
2052                    _ => None,
2053                }))
2054            } else {
2055                None
2056            }
2057        })
2058    }
2059}
2060
2061#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2062pub(crate) enum GenericArg {
2063    Lifetime(Lifetime),
2064    Type(Type),
2065    Const(Box<ConstantKind>),
2066    Infer,
2067}
2068
2069impl GenericArg {
2070    pub(crate) fn as_lt(&self) -> Option<&Lifetime> {
2071        if let Self::Lifetime(lt) = self { Some(lt) } else { None }
2072    }
2073
2074    pub(crate) fn as_ty(&self) -> Option<&Type> {
2075        if let Self::Type(ty) = self { Some(ty) } else { None }
2076    }
2077}
2078
2079#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2080pub(crate) enum GenericArgs {
2081    /// `<args, constraints = ..>`
2082    AngleBracketed { args: ThinVec<GenericArg>, constraints: ThinVec<AssocItemConstraint> },
2083    /// `(inputs) -> output`
2084    Parenthesized { inputs: ThinVec<Type>, output: Option<Box<Type>> },
2085    /// `(..)`
2086    ReturnTypeNotation,
2087}
2088
2089impl GenericArgs {
2090    pub(crate) fn is_empty(&self) -> bool {
2091        match self {
2092            GenericArgs::AngleBracketed { args, constraints } => {
2093                args.is_empty() && constraints.is_empty()
2094            }
2095            GenericArgs::Parenthesized { inputs, output } => inputs.is_empty() && output.is_none(),
2096            GenericArgs::ReturnTypeNotation => false,
2097        }
2098    }
2099    pub(crate) fn constraints(&self) -> Box<dyn Iterator<Item = AssocItemConstraint> + '_> {
2100        match self {
2101            GenericArgs::AngleBracketed { constraints, .. } => {
2102                Box::new(constraints.iter().cloned())
2103            }
2104            GenericArgs::Parenthesized { output, .. } => Box::new(
2105                output
2106                    .as_ref()
2107                    .map(|ty| AssocItemConstraint {
2108                        assoc: PathSegment {
2109                            name: sym::Output,
2110                            args: GenericArgs::AngleBracketed {
2111                                args: ThinVec::new(),
2112                                constraints: ThinVec::new(),
2113                            },
2114                        },
2115                        kind: AssocItemConstraintKind::Equality {
2116                            term: Term::Type((**ty).clone()),
2117                        },
2118                    })
2119                    .into_iter(),
2120            ),
2121            GenericArgs::ReturnTypeNotation => Box::new([].into_iter()),
2122        }
2123    }
2124}
2125
2126impl<'a> IntoIterator for &'a GenericArgs {
2127    type IntoIter = Box<dyn Iterator<Item = GenericArg> + 'a>;
2128    type Item = GenericArg;
2129    fn into_iter(self) -> Self::IntoIter {
2130        match self {
2131            GenericArgs::AngleBracketed { args, .. } => Box::new(args.iter().cloned()),
2132            GenericArgs::Parenthesized { inputs, .. } => {
2133                // FIXME: This isn't really right, since `Fn(A, B)` is `Fn<(A, B)>`
2134                Box::new(inputs.iter().cloned().map(GenericArg::Type))
2135            }
2136            GenericArgs::ReturnTypeNotation => Box::new([].into_iter()),
2137        }
2138    }
2139}
2140
2141#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2142pub(crate) struct PathSegment {
2143    pub(crate) name: Symbol,
2144    pub(crate) args: GenericArgs,
2145}
2146
2147#[derive(Clone, Debug)]
2148pub(crate) enum TypeAliasInnerType {
2149    Enum { variants: IndexVec<VariantIdx, Item>, is_non_exhaustive: bool },
2150    Union { fields: Vec<Item> },
2151    Struct { ctor_kind: Option<CtorKind>, fields: Vec<Item> },
2152}
2153
2154impl TypeAliasInnerType {
2155    fn has_stripped_entries(&self) -> Option<bool> {
2156        Some(match self {
2157            Self::Enum { variants, .. } => variants.iter().any(|v| v.is_stripped()),
2158            Self::Union { fields } | Self::Struct { fields, .. } => {
2159                fields.iter().any(|f| f.is_stripped())
2160            }
2161        })
2162    }
2163}
2164
2165#[derive(Clone, Debug)]
2166pub(crate) struct TypeAlias {
2167    pub(crate) type_: Type,
2168    pub(crate) generics: Generics,
2169    /// Inner `AdtDef` type, ie `type TyKind = IrTyKind<Adt, Ty>`,
2170    /// to be shown directly on the typedef page.
2171    pub(crate) inner_type: Option<TypeAliasInnerType>,
2172    /// `type_` can come from either the HIR or from metadata. If it comes from HIR, it may be a type
2173    /// alias instead of the final type. This will always have the final type, regardless of whether
2174    /// `type_` came from HIR or from metadata.
2175    ///
2176    /// If `item_type.is_none()`, `type_` is guaranteed to come from metadata (and therefore hold the
2177    /// final type).
2178    pub(crate) item_type: Option<Type>,
2179}
2180
2181#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2182pub(crate) struct BareFunctionDecl {
2183    pub(crate) safety: hir::Safety,
2184    pub(crate) generic_params: Vec<GenericParamDef>,
2185    pub(crate) decl: FnDecl,
2186    pub(crate) abi: ExternAbi,
2187}
2188
2189#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2190pub(crate) struct UnsafeBinderTy {
2191    pub(crate) generic_params: Vec<GenericParamDef>,
2192    pub(crate) ty: Type,
2193}
2194
2195#[derive(Clone, Debug)]
2196pub(crate) struct Static {
2197    pub(crate) type_: Box<Type>,
2198    pub(crate) mutability: Mutability,
2199    pub(crate) expr: Option<BodyId>,
2200}
2201
2202#[derive(Clone, PartialEq, Eq, Hash, Debug)]
2203pub(crate) struct Constant {
2204    pub(crate) generics: Generics,
2205    pub(crate) kind: ConstantKind,
2206    pub(crate) type_: Type,
2207}
2208
2209#[derive(Clone, PartialEq, Eq, Hash, Debug)]
2210pub(crate) enum Term {
2211    Type(Type),
2212    Constant(ConstantKind),
2213}
2214
2215impl Term {
2216    pub(crate) fn ty(&self) -> Option<&Type> {
2217        if let Term::Type(ty) = self { Some(ty) } else { None }
2218    }
2219}
2220
2221impl From<Type> for Term {
2222    fn from(ty: Type) -> Self {
2223        Term::Type(ty)
2224    }
2225}
2226
2227#[derive(Clone, PartialEq, Eq, Hash, Debug)]
2228pub(crate) enum ConstantKind {
2229    /// This is the wrapper around `ty::Const` for a non-local constant. Because it doesn't have a
2230    /// `BodyId`, we need to handle it on its own.
2231    ///
2232    /// Note that `ty::Const` includes generic parameters, and may not always be uniquely identified
2233    /// by a DefId. So this field must be different from `Extern`.
2234    TyConst { expr: Box<str> },
2235    /// A constant that is just a path (i.e., referring to a const param, free const, etc.).
2236    // FIXME: this is an unfortunate representation. rustdoc's logic around consts needs to be improved.
2237    Path { path: Box<str> },
2238    /// A constant (expression) that's not an item or associated item. These are usually found
2239    /// nested inside types (e.g., array lengths) or expressions (e.g., repeat counts), and also
2240    /// used to define explicit discriminant values for enum variants.
2241    Anonymous { body: BodyId },
2242    /// A constant from a different crate.
2243    Extern { def_id: DefId },
2244    /// `const FOO: u32 = ...;`
2245    Local { def_id: DefId, body: BodyId },
2246    /// An inferred constant as in `[10u8; _]`.
2247    Infer,
2248}
2249
2250impl ConstantKind {
2251    pub(crate) fn expr(&self, tcx: TyCtxt<'_>) -> String {
2252        match *self {
2253            ConstantKind::TyConst { ref expr } => expr.to_string(),
2254            ConstantKind::Path { ref path } => path.to_string(),
2255            ConstantKind::Extern { def_id } => print_inlined_const(tcx, def_id),
2256            ConstantKind::Local { body, .. } | ConstantKind::Anonymous { body } => {
2257                rendered_const(tcx, tcx.hir_body(body), tcx.hir_body_owner_def_id(body))
2258            }
2259            ConstantKind::Infer => "_".to_string(),
2260        }
2261    }
2262
2263    pub(crate) fn value(&self, tcx: TyCtxt<'_>) -> Option<String> {
2264        match *self {
2265            ConstantKind::TyConst { .. }
2266            | ConstantKind::Path { .. }
2267            | ConstantKind::Anonymous { .. }
2268            | ConstantKind::Infer => None,
2269            ConstantKind::Extern { def_id } | ConstantKind::Local { def_id, .. } => {
2270                print_evaluated_const(tcx, def_id, true, true)
2271            }
2272        }
2273    }
2274
2275    pub(crate) fn is_literal(&self, tcx: TyCtxt<'_>) -> bool {
2276        match *self {
2277            ConstantKind::TyConst { .. }
2278            | ConstantKind::Extern { .. }
2279            | ConstantKind::Path { .. }
2280            | ConstantKind::Infer => false,
2281            ConstantKind::Local { body, .. } | ConstantKind::Anonymous { body } => {
2282                is_literal_expr(tcx, body.hir_id)
2283            }
2284        }
2285    }
2286}
2287
2288#[derive(Clone, Debug)]
2289pub(crate) struct Impl {
2290    pub(crate) safety: hir::Safety,
2291    pub(crate) generics: Generics,
2292    pub(crate) trait_: Option<Path>,
2293    pub(crate) for_: Type,
2294    pub(crate) items: Vec<Item>,
2295    pub(crate) polarity: ty::ImplPolarity,
2296    pub(crate) kind: ImplKind,
2297    pub(crate) is_deprecated: bool,
2298}
2299
2300impl Impl {
2301    pub(crate) fn provided_trait_methods(&self, tcx: TyCtxt<'_>) -> FxIndexSet<Symbol> {
2302        self.trait_
2303            .as_ref()
2304            .map(|t| t.def_id())
2305            .map(|did| tcx.provided_trait_methods(did).map(|meth| meth.name()).collect())
2306            .unwrap_or_default()
2307    }
2308
2309    pub(crate) fn is_negative_trait_impl(&self) -> bool {
2310        matches!(self.polarity, ty::ImplPolarity::Negative)
2311    }
2312}
2313
2314#[derive(Clone, Debug)]
2315pub(crate) enum ImplKind {
2316    Normal,
2317    Auto,
2318    FakeVariadic,
2319    Blanket(Box<Type>),
2320}
2321
2322impl ImplKind {
2323    pub(crate) fn is_auto(&self) -> bool {
2324        matches!(self, ImplKind::Auto)
2325    }
2326
2327    pub(crate) fn is_blanket(&self) -> bool {
2328        matches!(self, ImplKind::Blanket(_))
2329    }
2330
2331    pub(crate) fn is_fake_variadic(&self) -> bool {
2332        matches!(self, ImplKind::FakeVariadic)
2333    }
2334
2335    pub(crate) fn as_blanket_ty(&self) -> Option<&Type> {
2336        match self {
2337            ImplKind::Blanket(ty) => Some(ty),
2338            _ => None,
2339        }
2340    }
2341}
2342
2343#[derive(Clone, Debug)]
2344pub(crate) struct Import {
2345    pub(crate) kind: ImportKind,
2346    /// The item being re-exported.
2347    pub(crate) source: ImportSource,
2348    pub(crate) should_be_displayed: bool,
2349}
2350
2351impl Import {
2352    pub(crate) fn new_simple(
2353        name: Symbol,
2354        source: ImportSource,
2355        should_be_displayed: bool,
2356    ) -> Self {
2357        Self { kind: ImportKind::Simple(name), source, should_be_displayed }
2358    }
2359
2360    pub(crate) fn new_glob(source: ImportSource, should_be_displayed: bool) -> Self {
2361        Self { kind: ImportKind::Glob, source, should_be_displayed }
2362    }
2363
2364    pub(crate) fn imported_item_is_doc_hidden(&self, tcx: TyCtxt<'_>) -> bool {
2365        self.source.did.is_some_and(|did| tcx.is_doc_hidden(did))
2366    }
2367}
2368
2369#[derive(Clone, Debug)]
2370pub(crate) enum ImportKind {
2371    // use source as str;
2372    Simple(Symbol),
2373    // use source::*;
2374    Glob,
2375}
2376
2377#[derive(Clone, Debug)]
2378pub(crate) struct ImportSource {
2379    pub(crate) path: Path,
2380    pub(crate) did: Option<DefId>,
2381}
2382
2383#[derive(Clone, Debug)]
2384pub(crate) struct Macro {
2385    pub(crate) source: String,
2386    /// Whether the macro was defined via `macro_rules!` as opposed to `macro`.
2387    pub(crate) macro_rules: bool,
2388}
2389
2390#[derive(Clone, Debug)]
2391pub(crate) struct ProcMacro {
2392    pub(crate) kind: MacroKind,
2393    pub(crate) helpers: Vec<Symbol>,
2394}
2395
2396/// A constraint on an associated item.
2397///
2398/// ### Examples
2399///
2400/// * the `A = Ty` and `B = Ty` in `Trait<A = Ty, B = Ty>`
2401/// * the `G<Ty> = Ty` in `Trait<G<Ty> = Ty>`
2402/// * the `A: Bound` in `Trait<A: Bound>`
2403/// * the `RetTy` in `Trait(ArgTy, ArgTy) -> RetTy`
2404/// * the `C = { Ct }` in `Trait<C = { Ct }>` (feature `associated_const_equality`)
2405/// * the `f(..): Bound` in `Trait<f(..): Bound>` (feature `return_type_notation`)
2406#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2407pub(crate) struct AssocItemConstraint {
2408    pub(crate) assoc: PathSegment,
2409    pub(crate) kind: AssocItemConstraintKind,
2410}
2411
2412/// The kind of [associated item constraint][AssocItemConstraint].
2413#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2414pub(crate) enum AssocItemConstraintKind {
2415    Equality { term: Term },
2416    Bound { bounds: Vec<GenericBound> },
2417}
2418
2419// Some nodes are used a lot. Make sure they don't unintentionally get bigger.
2420#[cfg(target_pointer_width = "64")]
2421mod size_asserts {
2422    use rustc_data_structures::static_assert_size;
2423
2424    use super::*;
2425    // tidy-alphabetical-start
2426    static_assert_size!(Crate, 16); // frequently moved by-value
2427    static_assert_size!(DocFragment, 48);
2428    static_assert_size!(GenericArg, 32);
2429    static_assert_size!(GenericArgs, 24);
2430    static_assert_size!(GenericParamDef, 40);
2431    static_assert_size!(Generics, 16);
2432    static_assert_size!(Item, 8);
2433    static_assert_size!(ItemInner, 144);
2434    static_assert_size!(ItemKind, 48);
2435    static_assert_size!(PathSegment, 32);
2436    static_assert_size!(Type, 32);
2437    // tidy-alphabetical-end
2438}