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