rustdoc/clean/
types.rs

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