[go: up one dir, main page]

rustdoc/clean/
types.rs

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