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