rustdoc/clean/
types.rs

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