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                if let Some(assoc) = tcx.opt_associated_item(def_id)
694                    && let ty::AssocContainer::Trait | ty::AssocContainer::TraitImpl(_) =
695                        assoc.container
696                {
697                    hir::Constness::NotConst
698                } else {
699                    hir::Constness::Const
700                }
701            } else {
702                hir::Constness::NotConst
703            };
704            let asyncness = match asyncness {
705                ty::Asyncness::Yes => hir::IsAsync::Async(DUMMY_SP),
706                ty::Asyncness::No => hir::IsAsync::NotAsync,
707            };
708            hir::FnHeader {
709                safety: if tcx.codegen_fn_attrs(def_id).safe_target_features {
710                    hir::HeaderSafety::SafeTargetFeatures
711                } else {
712                    sig.safety().into()
713                },
714                abi: sig.abi(),
715                constness,
716                asyncness,
717            }
718        }
719        let header = match self.kind {
720            ItemKind::ForeignFunctionItem(_, safety) => {
721                let def_id = self.def_id().unwrap();
722                let abi = tcx.fn_sig(def_id).skip_binder().abi();
723                hir::FnHeader {
724                    safety: if tcx.codegen_fn_attrs(def_id).safe_target_features {
725                        hir::HeaderSafety::SafeTargetFeatures
726                    } else {
727                        safety.into()
728                    },
729                    abi,
730                    constness: if tcx.is_const_fn(def_id) {
731                        hir::Constness::Const
732                    } else {
733                        hir::Constness::NotConst
734                    },
735                    asyncness: hir::IsAsync::NotAsync,
736                }
737            }
738            ItemKind::FunctionItem(_)
739            | ItemKind::MethodItem(_, _)
740            | ItemKind::RequiredMethodItem(_) => {
741                let def_id = self.def_id().unwrap();
742                build_fn_header(def_id, tcx, tcx.asyncness(def_id))
743            }
744            _ => return None,
745        };
746        Some(header)
747    }
748
749    /// Returns the visibility of the current item. If the visibility is "inherited", then `None`
750    /// is returned.
751    pub(crate) fn visibility(&self, tcx: TyCtxt<'_>) -> Option<Visibility<DefId>> {
752        let def_id = match self.item_id {
753            // Anything but DefId *shouldn't* matter, but return a reasonable value anyway.
754            ItemId::Auto { .. } | ItemId::Blanket { .. } => return None,
755            ItemId::DefId(def_id) => def_id,
756        };
757
758        match self.kind {
759            // Primitives and Keywords are written in the source code as private modules.
760            // The modules need to be private so that nobody actually uses them, but the
761            // keywords and primitives that they are documenting are public.
762            ItemKind::KeywordItem | ItemKind::PrimitiveItem(_) | ItemKind::AttributeItem => {
763                return Some(Visibility::Public);
764            }
765            // Variant fields inherit their enum's visibility.
766            StructFieldItem(..) if is_field_vis_inherited(tcx, def_id) => {
767                return None;
768            }
769            // Variants always inherit visibility
770            VariantItem(..) | ImplItem(..) => return None,
771            // Trait items inherit the trait's visibility
772            RequiredAssocConstItem(..)
773            | ProvidedAssocConstItem(..)
774            | ImplAssocConstItem(..)
775            | AssocTypeItem(..)
776            | RequiredAssocTypeItem(..)
777            | RequiredMethodItem(..)
778            | MethodItem(..) => {
779                match tcx.associated_item(def_id).container {
780                    // Trait impl items always inherit the impl's visibility --
781                    // we don't want to show `pub`.
782                    ty::AssocContainer::Trait | ty::AssocContainer::TraitImpl(_) => {
783                        return None;
784                    }
785                    ty::AssocContainer::InherentImpl => {}
786                }
787            }
788            _ => {}
789        }
790        let def_id = match self.inline_stmt_id {
791            Some(inlined) => inlined.to_def_id(),
792            None => def_id,
793        };
794        Some(tcx.visibility(def_id))
795    }
796
797    /// Get a list of attributes excluding `#[repr]` to display.
798    ///
799    /// Only used by the HTML output-format.
800    fn attributes_without_repr(&self) -> Vec<String> {
801        self.attrs
802            .other_attrs
803            .iter()
804            .filter_map(|attr| match attr {
805                hir::Attribute::Parsed(AttributeKind::LinkSection { name, .. }) => {
806                    Some(format!("#[unsafe(link_section = \"{name}\")]"))
807                }
808                hir::Attribute::Parsed(AttributeKind::NoMangle(..)) => {
809                    Some("#[unsafe(no_mangle)]".to_string())
810                }
811                hir::Attribute::Parsed(AttributeKind::ExportName { name, .. }) => {
812                    Some(format!("#[unsafe(export_name = \"{name}\")]"))
813                }
814                hir::Attribute::Parsed(AttributeKind::NonExhaustive(..)) => {
815                    Some("#[non_exhaustive]".to_string())
816                }
817                _ => None,
818            })
819            .collect()
820    }
821
822    /// Get a list of attributes to display on this item.
823    ///
824    /// Only used by the HTML output-format.
825    pub(crate) fn attributes(&self, tcx: TyCtxt<'_>, cache: &Cache) -> Vec<String> {
826        let mut attrs = self.attributes_without_repr();
827
828        if let Some(repr_attr) = self.repr(tcx, cache) {
829            attrs.push(repr_attr);
830        }
831        attrs
832    }
833
834    /// Returns a stringified `#[repr(...)]` attribute.
835    ///
836    /// Only used by the HTML output-format.
837    pub(crate) fn repr(&self, tcx: TyCtxt<'_>, cache: &Cache) -> Option<String> {
838        repr_attributes(tcx, cache, self.def_id()?, self.type_())
839    }
840
841    pub fn is_doc_hidden(&self) -> bool {
842        self.attrs.is_doc_hidden()
843    }
844
845    pub fn def_id(&self) -> Option<DefId> {
846        self.item_id.as_def_id()
847    }
848}
849
850/// Return a string representing the `#[repr]` attribute if present.
851///
852/// Only used by the HTML output-format.
853pub(crate) fn repr_attributes(
854    tcx: TyCtxt<'_>,
855    cache: &Cache,
856    def_id: DefId,
857    item_type: ItemType,
858) -> Option<String> {
859    use rustc_abi::IntegerType;
860
861    if !matches!(item_type, ItemType::Struct | ItemType::Enum | ItemType::Union) {
862        return None;
863    }
864    let adt = tcx.adt_def(def_id);
865    let repr = adt.repr();
866    let mut out = Vec::new();
867    if repr.c() {
868        out.push("C");
869    }
870    if repr.transparent() {
871        // Render `repr(transparent)` iff the non-1-ZST field is public or at least one
872        // field is public in case all fields are 1-ZST fields.
873        let render_transparent = cache.document_private
874            || adt
875                .all_fields()
876                .find(|field| {
877                    let ty = field.ty(tcx, ty::GenericArgs::identity_for_item(tcx, field.did));
878                    tcx.layout_of(ty::TypingEnv::post_analysis(tcx, field.did).as_query_input(ty))
879                        .is_ok_and(|layout| !layout.is_1zst())
880                })
881                .map_or_else(
882                    || adt.all_fields().any(|field| field.vis.is_public()),
883                    |field| field.vis.is_public(),
884                );
885
886        if render_transparent {
887            out.push("transparent");
888        }
889    }
890    if repr.simd() {
891        out.push("simd");
892    }
893    let pack_s;
894    if let Some(pack) = repr.pack {
895        pack_s = format!("packed({})", pack.bytes());
896        out.push(&pack_s);
897    }
898    let align_s;
899    if let Some(align) = repr.align {
900        align_s = format!("align({})", align.bytes());
901        out.push(&align_s);
902    }
903    let int_s;
904    if let Some(int) = repr.int {
905        int_s = match int {
906            IntegerType::Pointer(is_signed) => {
907                format!("{}size", if is_signed { 'i' } else { 'u' })
908            }
909            IntegerType::Fixed(size, is_signed) => {
910                format!("{}{}", if is_signed { 'i' } else { 'u' }, size.size().bytes() * 8)
911            }
912        };
913        out.push(&int_s);
914    }
915    if !out.is_empty() { Some(format!("#[repr({})]", out.join(", "))) } else { None }
916}
917
918#[derive(Clone, Debug)]
919pub(crate) enum ItemKind {
920    ExternCrateItem {
921        /// The crate's name, *not* the name it's imported as.
922        src: Option<Symbol>,
923    },
924    ImportItem(Import),
925    StructItem(Struct),
926    UnionItem(Union),
927    EnumItem(Enum),
928    FunctionItem(Box<Function>),
929    ModuleItem(Module),
930    TypeAliasItem(Box<TypeAlias>),
931    StaticItem(Static),
932    TraitItem(Box<Trait>),
933    TraitAliasItem(TraitAlias),
934    ImplItem(Box<Impl>),
935    /// A required method in a trait declaration meaning it's only a function signature.
936    RequiredMethodItem(Box<Function>),
937    /// A method in a trait impl or a provided method in a trait declaration.
938    ///
939    /// Compared to [RequiredMethodItem], it also contains a method body.
940    MethodItem(Box<Function>, Option<hir::Defaultness>),
941    StructFieldItem(Type),
942    VariantItem(Variant),
943    /// `fn`s from an extern block
944    ForeignFunctionItem(Box<Function>, hir::Safety),
945    /// `static`s from an extern block
946    ForeignStaticItem(Static, hir::Safety),
947    /// `type`s from an extern block
948    ForeignTypeItem,
949    MacroItem(Macro),
950    ProcMacroItem(ProcMacro),
951    PrimitiveItem(PrimitiveType),
952    /// A required associated constant in a trait declaration.
953    RequiredAssocConstItem(Generics, Box<Type>),
954    ConstantItem(Box<Constant>),
955    /// An associated constant in a trait declaration with provided default value.
956    ProvidedAssocConstItem(Box<Constant>),
957    /// An associated constant in an inherent impl or trait impl.
958    ImplAssocConstItem(Box<Constant>),
959    /// A required associated type in a trait declaration.
960    ///
961    /// The bounds may be non-empty if there is a `where` clause.
962    RequiredAssocTypeItem(Generics, Vec<GenericBound>),
963    /// An associated type in a trait impl or a provided one in a trait declaration.
964    AssocTypeItem(Box<TypeAlias>, Vec<GenericBound>),
965    /// An item that has been stripped by a rustdoc pass
966    StrippedItem(Box<ItemKind>),
967    /// This item represents a module with a `#[doc(keyword = "...")]` attribute which is used
968    /// to generate documentation for Rust keywords.
969    KeywordItem,
970    /// This item represents a module with a `#[doc(attribute = "...")]` attribute which is used
971    /// to generate documentation for Rust builtin attributes.
972    AttributeItem,
973}
974
975impl ItemKind {
976    /// Some items contain others such as structs (for their fields) and Enums
977    /// (for their variants). This method returns those contained items.
978    pub(crate) fn inner_items(&self) -> impl Iterator<Item = &Item> {
979        match self {
980            StructItem(s) => s.fields.iter(),
981            UnionItem(u) => u.fields.iter(),
982            VariantItem(v) => match &v.kind {
983                VariantKind::CLike => [].iter(),
984                VariantKind::Tuple(t) => t.iter(),
985                VariantKind::Struct(s) => s.fields.iter(),
986            },
987            EnumItem(e) => e.variants.iter(),
988            TraitItem(t) => t.items.iter(),
989            ImplItem(i) => i.items.iter(),
990            ModuleItem(m) => m.items.iter(),
991            ExternCrateItem { .. }
992            | ImportItem(_)
993            | FunctionItem(_)
994            | TypeAliasItem(_)
995            | StaticItem(_)
996            | ConstantItem(_)
997            | TraitAliasItem(_)
998            | RequiredMethodItem(_)
999            | MethodItem(_, _)
1000            | StructFieldItem(_)
1001            | ForeignFunctionItem(_, _)
1002            | ForeignStaticItem(_, _)
1003            | ForeignTypeItem
1004            | MacroItem(_)
1005            | ProcMacroItem(_)
1006            | PrimitiveItem(_)
1007            | RequiredAssocConstItem(..)
1008            | ProvidedAssocConstItem(..)
1009            | ImplAssocConstItem(..)
1010            | RequiredAssocTypeItem(..)
1011            | AssocTypeItem(..)
1012            | StrippedItem(_)
1013            | KeywordItem
1014            | AttributeItem => [].iter(),
1015        }
1016    }
1017
1018    /// Returns `true` if this item does not appear inside an impl block.
1019    pub(crate) fn is_non_assoc(&self) -> bool {
1020        matches!(
1021            self,
1022            StructItem(_)
1023                | UnionItem(_)
1024                | EnumItem(_)
1025                | TraitItem(_)
1026                | ModuleItem(_)
1027                | ExternCrateItem { .. }
1028                | FunctionItem(_)
1029                | TypeAliasItem(_)
1030                | StaticItem(_)
1031                | ConstantItem(_)
1032                | TraitAliasItem(_)
1033                | ForeignFunctionItem(_, _)
1034                | ForeignStaticItem(_, _)
1035                | ForeignTypeItem
1036                | MacroItem(_)
1037                | ProcMacroItem(_)
1038                | PrimitiveItem(_)
1039        )
1040    }
1041}
1042
1043#[derive(Clone, Debug)]
1044pub(crate) struct Module {
1045    pub(crate) items: Vec<Item>,
1046    pub(crate) span: Span,
1047}
1048
1049pub(crate) fn hir_attr_lists<'a, I: IntoIterator<Item = &'a hir::Attribute>>(
1050    attrs: I,
1051    name: Symbol,
1052) -> impl Iterator<Item = ast::MetaItemInner> + use<'a, I> {
1053    attrs
1054        .into_iter()
1055        .filter(move |attr| attr.has_name(name))
1056        .filter_map(ast::attr::AttributeExt::meta_item_list)
1057        .flatten()
1058}
1059
1060pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator<Item = &'a hir::Attribute> + Clone>(
1061    attrs: I,
1062    tcx: TyCtxt<'_>,
1063    hidden_cfg: &FxHashSet<Cfg>,
1064) -> Option<Arc<Cfg>> {
1065    let doc_cfg_active = tcx.features().doc_cfg();
1066    let doc_auto_cfg_active = tcx.features().doc_auto_cfg();
1067
1068    fn single<T: IntoIterator>(it: T) -> Option<T::Item> {
1069        let mut iter = it.into_iter();
1070        let item = iter.next()?;
1071        if iter.next().is_some() {
1072            return None;
1073        }
1074        Some(item)
1075    }
1076
1077    let mut cfg = if doc_cfg_active || doc_auto_cfg_active {
1078        let mut doc_cfg = attrs
1079            .clone()
1080            .filter(|attr| attr.has_name(sym::doc))
1081            .flat_map(|attr| attr.meta_item_list().unwrap_or_default())
1082            .filter(|attr| attr.has_name(sym::cfg))
1083            .peekable();
1084        if doc_cfg.peek().is_some() && doc_cfg_active {
1085            let sess = tcx.sess;
1086
1087            doc_cfg.fold(Cfg::True, |mut cfg, item| {
1088                if let Some(cfg_mi) =
1089                    item.meta_item().and_then(|item| rustc_expand::config::parse_cfg(item, sess))
1090                {
1091                    match Cfg::parse(cfg_mi) {
1092                        Ok(new_cfg) => cfg &= new_cfg,
1093                        Err(e) => {
1094                            sess.dcx().span_err(e.span, e.msg);
1095                        }
1096                    }
1097                }
1098                cfg
1099            })
1100        } else if doc_auto_cfg_active {
1101            // If there is no `doc(cfg())`, then we retrieve the `cfg()` attributes (because
1102            // `doc(cfg())` overrides `cfg()`).
1103            attrs
1104                .clone()
1105                .filter(|attr| attr.has_name(sym::cfg_trace))
1106                .filter_map(|attr| single(attr.meta_item_list()?))
1107                .filter_map(|attr| Cfg::parse_without(attr.meta_item()?, hidden_cfg).ok().flatten())
1108                .fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg)
1109        } else {
1110            Cfg::True
1111        }
1112    } else {
1113        Cfg::True
1114    };
1115
1116    // treat #[target_feature(enable = "feat")] attributes as if they were
1117    // #[doc(cfg(target_feature = "feat"))] attributes as well
1118    if let Some(features) =
1119        find_attr!(attrs, AttributeKind::TargetFeature { features, .. } => features)
1120    {
1121        for (feature, _) in features {
1122            cfg &= Cfg::Cfg(sym::target_feature, Some(*feature));
1123        }
1124    }
1125
1126    if cfg == Cfg::True { None } else { Some(Arc::new(cfg)) }
1127}
1128
1129pub(crate) trait NestedAttributesExt {
1130    /// Returns `true` if the attribute list contains a specific `word`
1131    fn has_word(self, word: Symbol) -> bool
1132    where
1133        Self: Sized,
1134    {
1135        <Self as NestedAttributesExt>::get_word_attr(self, word).is_some()
1136    }
1137
1138    /// Returns `Some(attr)` if the attribute list contains 'attr'
1139    /// corresponding to a specific `word`
1140    fn get_word_attr(self, word: Symbol) -> Option<ast::MetaItemInner>;
1141}
1142
1143impl<I: Iterator<Item = ast::MetaItemInner>> NestedAttributesExt for I {
1144    fn get_word_attr(mut self, word: Symbol) -> Option<ast::MetaItemInner> {
1145        self.find(|attr| attr.is_word() && attr.has_name(word))
1146    }
1147}
1148
1149/// A link that has not yet been rendered.
1150///
1151/// This link will be turned into a rendered link by [`Item::links`].
1152#[derive(Clone, Debug, PartialEq, Eq, Hash)]
1153pub(crate) struct ItemLink {
1154    /// The original link written in the markdown
1155    pub(crate) link: Box<str>,
1156    /// The link text displayed in the HTML.
1157    ///
1158    /// This may not be the same as `link` if there was a disambiguator
1159    /// in an intra-doc link (e.g. \[`fn@f`\])
1160    pub(crate) link_text: Box<str>,
1161    /// The `DefId` of the Item whose **HTML Page** contains the item being
1162    /// linked to. This will be different to `item_id` on item's that don't
1163    /// have their own page, such as struct fields and enum variants.
1164    pub(crate) page_id: DefId,
1165    /// The url fragment to append to the link
1166    pub(crate) fragment: Option<UrlFragment>,
1167}
1168
1169pub struct RenderedLink {
1170    /// The text the link was original written as.
1171    ///
1172    /// This could potentially include disambiguators and backticks.
1173    pub(crate) original_text: Box<str>,
1174    /// The text to display in the HTML
1175    pub(crate) new_text: Box<str>,
1176    /// The URL to put in the `href`
1177    pub(crate) href: String,
1178    /// The tooltip.
1179    pub(crate) tooltip: String,
1180}
1181
1182/// The attributes on an [`Item`], including attributes like `#[derive(...)]` and `#[inline]`,
1183/// as well as doc comments.
1184#[derive(Clone, Debug, Default)]
1185pub(crate) struct Attributes {
1186    pub(crate) doc_strings: Vec<DocFragment>,
1187    pub(crate) other_attrs: ThinVec<hir::Attribute>,
1188}
1189
1190impl Attributes {
1191    pub(crate) fn lists(&self, name: Symbol) -> impl Iterator<Item = ast::MetaItemInner> {
1192        hir_attr_lists(&self.other_attrs[..], name)
1193    }
1194
1195    pub(crate) fn has_doc_flag(&self, flag: Symbol) -> bool {
1196        for attr in &self.other_attrs {
1197            if !attr.has_name(sym::doc) {
1198                continue;
1199            }
1200
1201            if let Some(items) = attr.meta_item_list()
1202                && items.iter().filter_map(|i| i.meta_item()).any(|it| it.has_name(flag))
1203            {
1204                return true;
1205            }
1206        }
1207
1208        false
1209    }
1210
1211    pub(crate) fn is_doc_hidden(&self) -> bool {
1212        self.has_doc_flag(sym::hidden)
1213    }
1214
1215    pub(crate) fn from_hir(attrs: &[hir::Attribute]) -> Attributes {
1216        Attributes::from_hir_iter(attrs.iter().map(|attr| (attr, None)), false)
1217    }
1218
1219    pub(crate) fn from_hir_with_additional(
1220        attrs: &[hir::Attribute],
1221        (additional_attrs, def_id): (&[hir::Attribute], DefId),
1222    ) -> Attributes {
1223        // Additional documentation should be shown before the original documentation.
1224        let attrs1 = additional_attrs.iter().map(|attr| (attr, Some(def_id)));
1225        let attrs2 = attrs.iter().map(|attr| (attr, None));
1226        Attributes::from_hir_iter(attrs1.chain(attrs2), false)
1227    }
1228
1229    pub(crate) fn from_hir_iter<'a>(
1230        attrs: impl Iterator<Item = (&'a hir::Attribute, Option<DefId>)>,
1231        doc_only: bool,
1232    ) -> Attributes {
1233        let (doc_strings, other_attrs) = attrs_to_doc_fragments(attrs, doc_only);
1234        Attributes { doc_strings, other_attrs }
1235    }
1236
1237    /// Combine all doc strings into a single value handling indentation and newlines as needed.
1238    pub(crate) fn doc_value(&self) -> String {
1239        self.opt_doc_value().unwrap_or_default()
1240    }
1241
1242    /// Combine all doc strings into a single value handling indentation and newlines as needed.
1243    /// Returns `None` is there's no documentation at all, and `Some("")` if there is some
1244    /// documentation but it is empty (e.g. `#[doc = ""]`).
1245    pub(crate) fn opt_doc_value(&self) -> Option<String> {
1246        (!self.doc_strings.is_empty()).then(|| {
1247            let mut res = String::new();
1248            for frag in &self.doc_strings {
1249                add_doc_fragment(&mut res, frag);
1250            }
1251            res.pop();
1252            res
1253        })
1254    }
1255
1256    pub(crate) fn get_doc_aliases(&self) -> Box<[Symbol]> {
1257        let mut aliases = FxIndexSet::default();
1258
1259        for attr in
1260            hir_attr_lists(&self.other_attrs[..], sym::doc).filter(|a| a.has_name(sym::alias))
1261        {
1262            if let Some(values) = attr.meta_item_list() {
1263                for l in values {
1264                    if let Some(lit) = l.lit()
1265                        && let ast::LitKind::Str(s, _) = lit.kind
1266                    {
1267                        aliases.insert(s);
1268                    }
1269                }
1270            } else if let Some(value) = attr.value_str() {
1271                aliases.insert(value);
1272            }
1273        }
1274        aliases.into_iter().collect::<Vec<_>>().into()
1275    }
1276}
1277
1278#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1279pub(crate) enum GenericBound {
1280    TraitBound(PolyTrait, hir::TraitBoundModifiers),
1281    Outlives(Lifetime),
1282    /// `use<'a, T>` precise-capturing bound syntax
1283    Use(Vec<PreciseCapturingArg>),
1284}
1285
1286impl GenericBound {
1287    pub(crate) fn sized(cx: &mut DocContext<'_>) -> GenericBound {
1288        Self::sized_with(cx, hir::TraitBoundModifiers::NONE)
1289    }
1290
1291    pub(crate) fn maybe_sized(cx: &mut DocContext<'_>) -> GenericBound {
1292        Self::sized_with(
1293            cx,
1294            hir::TraitBoundModifiers {
1295                polarity: hir::BoundPolarity::Maybe(DUMMY_SP),
1296                constness: hir::BoundConstness::Never,
1297            },
1298        )
1299    }
1300
1301    fn sized_with(cx: &mut DocContext<'_>, modifiers: hir::TraitBoundModifiers) -> GenericBound {
1302        let did = cx.tcx.require_lang_item(LangItem::Sized, DUMMY_SP);
1303        let empty = ty::Binder::dummy(ty::GenericArgs::empty());
1304        let path = clean_middle_path(cx, did, false, ThinVec::new(), empty);
1305        inline::record_extern_fqn(cx, did, ItemType::Trait);
1306        GenericBound::TraitBound(PolyTrait { trait_: path, generic_params: Vec::new() }, modifiers)
1307    }
1308
1309    pub(crate) fn is_trait_bound(&self) -> bool {
1310        matches!(self, Self::TraitBound(..))
1311    }
1312
1313    pub(crate) fn is_sized_bound(&self, cx: &DocContext<'_>) -> bool {
1314        self.is_bounded_by_lang_item(cx, LangItem::Sized)
1315    }
1316
1317    pub(crate) fn is_meta_sized_bound(&self, cx: &DocContext<'_>) -> bool {
1318        self.is_bounded_by_lang_item(cx, LangItem::MetaSized)
1319    }
1320
1321    fn is_bounded_by_lang_item(&self, cx: &DocContext<'_>, lang_item: LangItem) -> bool {
1322        if let GenericBound::TraitBound(
1323            PolyTrait { ref trait_, .. },
1324            rustc_hir::TraitBoundModifiers::NONE,
1325        ) = *self
1326            && cx.tcx.is_lang_item(trait_.def_id(), lang_item)
1327        {
1328            return true;
1329        }
1330        false
1331    }
1332
1333    pub(crate) fn get_trait_path(&self) -> Option<Path> {
1334        if let GenericBound::TraitBound(PolyTrait { ref trait_, .. }, _) = *self {
1335            Some(trait_.clone())
1336        } else {
1337            None
1338        }
1339    }
1340}
1341
1342#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
1343pub(crate) struct Lifetime(pub Symbol);
1344
1345impl Lifetime {
1346    pub(crate) fn statik() -> Lifetime {
1347        Lifetime(kw::StaticLifetime)
1348    }
1349
1350    pub(crate) fn elided() -> Lifetime {
1351        Lifetime(kw::UnderscoreLifetime)
1352    }
1353}
1354
1355#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
1356pub(crate) enum PreciseCapturingArg {
1357    Lifetime(Lifetime),
1358    Param(Symbol),
1359}
1360
1361impl PreciseCapturingArg {
1362    pub(crate) fn name(self) -> Symbol {
1363        match self {
1364            PreciseCapturingArg::Lifetime(lt) => lt.0,
1365            PreciseCapturingArg::Param(param) => param,
1366        }
1367    }
1368}
1369
1370#[derive(Clone, PartialEq, Eq, Hash, Debug)]
1371pub(crate) enum WherePredicate {
1372    BoundPredicate { ty: Type, bounds: Vec<GenericBound>, bound_params: Vec<GenericParamDef> },
1373    RegionPredicate { lifetime: Lifetime, bounds: Vec<GenericBound> },
1374    EqPredicate { lhs: QPathData, rhs: Term },
1375}
1376
1377impl WherePredicate {
1378    pub(crate) fn get_bounds(&self) -> Option<&[GenericBound]> {
1379        match self {
1380            WherePredicate::BoundPredicate { bounds, .. } => Some(bounds),
1381            WherePredicate::RegionPredicate { bounds, .. } => Some(bounds),
1382            _ => None,
1383        }
1384    }
1385}
1386
1387#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1388pub(crate) enum GenericParamDefKind {
1389    Lifetime { outlives: ThinVec<Lifetime> },
1390    Type { bounds: ThinVec<GenericBound>, default: Option<Box<Type>>, synthetic: bool },
1391    // Option<Box<String>> makes this type smaller than `Option<String>` would.
1392    Const { ty: Box<Type>, default: Option<Box<String>> },
1393}
1394
1395impl GenericParamDefKind {
1396    pub(crate) fn is_type(&self) -> bool {
1397        matches!(self, GenericParamDefKind::Type { .. })
1398    }
1399}
1400
1401#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1402pub(crate) struct GenericParamDef {
1403    pub(crate) name: Symbol,
1404    pub(crate) def_id: DefId,
1405    pub(crate) kind: GenericParamDefKind,
1406}
1407
1408impl GenericParamDef {
1409    pub(crate) fn lifetime(def_id: DefId, name: Symbol) -> Self {
1410        Self { name, def_id, kind: GenericParamDefKind::Lifetime { outlives: ThinVec::new() } }
1411    }
1412
1413    pub(crate) fn is_synthetic_param(&self) -> bool {
1414        match self.kind {
1415            GenericParamDefKind::Lifetime { .. } | GenericParamDefKind::Const { .. } => false,
1416            GenericParamDefKind::Type { synthetic, .. } => synthetic,
1417        }
1418    }
1419
1420    pub(crate) fn is_type(&self) -> bool {
1421        self.kind.is_type()
1422    }
1423
1424    pub(crate) fn get_bounds(&self) -> Option<&[GenericBound]> {
1425        match self.kind {
1426            GenericParamDefKind::Type { ref bounds, .. } => Some(bounds),
1427            _ => None,
1428        }
1429    }
1430}
1431
1432// maybe use a Generic enum and use Vec<Generic>?
1433#[derive(Clone, PartialEq, Eq, Hash, Debug, Default)]
1434pub(crate) struct Generics {
1435    pub(crate) params: ThinVec<GenericParamDef>,
1436    pub(crate) where_predicates: ThinVec<WherePredicate>,
1437}
1438
1439impl Generics {
1440    pub(crate) fn is_empty(&self) -> bool {
1441        self.params.is_empty() && self.where_predicates.is_empty()
1442    }
1443}
1444
1445#[derive(Clone, Debug)]
1446pub(crate) struct Function {
1447    pub(crate) decl: FnDecl,
1448    pub(crate) generics: Generics,
1449}
1450
1451#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1452pub(crate) struct FnDecl {
1453    pub(crate) inputs: Vec<Parameter>,
1454    pub(crate) output: Type,
1455    pub(crate) c_variadic: bool,
1456}
1457
1458impl FnDecl {
1459    pub(crate) fn receiver_type(&self) -> Option<&Type> {
1460        self.inputs.first().and_then(|v| v.to_receiver())
1461    }
1462}
1463
1464/// A function parameter.
1465#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1466pub(crate) struct Parameter {
1467    pub(crate) name: Option<Symbol>,
1468    pub(crate) type_: Type,
1469    /// This field is used to represent "const" arguments from the `rustc_legacy_const_generics`
1470    /// feature. More information in <https://github.com/rust-lang/rust/issues/83167>.
1471    pub(crate) is_const: bool,
1472}
1473
1474impl Parameter {
1475    pub(crate) fn to_receiver(&self) -> Option<&Type> {
1476        if self.name == Some(kw::SelfLower) { Some(&self.type_) } else { None }
1477    }
1478}
1479
1480#[derive(Clone, Debug)]
1481pub(crate) struct Trait {
1482    pub(crate) def_id: DefId,
1483    pub(crate) items: Vec<Item>,
1484    pub(crate) generics: Generics,
1485    pub(crate) bounds: Vec<GenericBound>,
1486}
1487
1488impl Trait {
1489    pub(crate) fn is_auto(&self, tcx: TyCtxt<'_>) -> bool {
1490        tcx.trait_is_auto(self.def_id)
1491    }
1492    pub(crate) fn is_notable_trait(&self, tcx: TyCtxt<'_>) -> bool {
1493        tcx.is_doc_notable_trait(self.def_id)
1494    }
1495    pub(crate) fn safety(&self, tcx: TyCtxt<'_>) -> hir::Safety {
1496        tcx.trait_def(self.def_id).safety
1497    }
1498    pub(crate) fn is_dyn_compatible(&self, tcx: TyCtxt<'_>) -> bool {
1499        tcx.is_dyn_compatible(self.def_id)
1500    }
1501}
1502
1503#[derive(Clone, Debug)]
1504pub(crate) struct TraitAlias {
1505    pub(crate) generics: Generics,
1506    pub(crate) bounds: Vec<GenericBound>,
1507}
1508
1509/// A trait reference, which may have higher ranked lifetimes.
1510#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1511pub(crate) struct PolyTrait {
1512    pub(crate) trait_: Path,
1513    pub(crate) generic_params: Vec<GenericParamDef>,
1514}
1515
1516/// Rustdoc's representation of types, mostly based on the [`hir::Ty`].
1517#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1518pub(crate) enum Type {
1519    /// A named type, which could be a trait.
1520    ///
1521    /// This is mostly Rustdoc's version of [`hir::Path`].
1522    /// It has to be different because Rustdoc's [`PathSegment`] can contain cleaned generics.
1523    Path {
1524        path: Path,
1525    },
1526    /// A `dyn Trait` object: `dyn for<'a> Trait<'a> + Send + 'static`
1527    DynTrait(Vec<PolyTrait>, Option<Lifetime>),
1528    /// A type parameter.
1529    Generic(Symbol),
1530    /// The `Self` type.
1531    SelfTy,
1532    /// A primitive (aka, builtin) type.
1533    Primitive(PrimitiveType),
1534    /// A function pointer: `extern "ABI" fn(...) -> ...`
1535    BareFunction(Box<BareFunctionDecl>),
1536    /// A tuple type: `(i32, &str)`.
1537    Tuple(Vec<Type>),
1538    /// A slice type (does *not* include the `&`): `[i32]`
1539    Slice(Box<Type>),
1540    /// An array type.
1541    ///
1542    /// The `String` field is a stringified version of the array's length parameter.
1543    Array(Box<Type>, Box<str>),
1544    Pat(Box<Type>, Box<str>),
1545    /// A raw pointer type: `*const i32`, `*mut i32`
1546    RawPointer(Mutability, Box<Type>),
1547    /// A reference type: `&i32`, `&'a mut Foo`
1548    BorrowedRef {
1549        lifetime: Option<Lifetime>,
1550        mutability: Mutability,
1551        type_: Box<Type>,
1552    },
1553
1554    /// A qualified path to an associated item: `<Type as Trait>::Name`
1555    QPath(Box<QPathData>),
1556
1557    /// A type that is inferred: `_`
1558    Infer,
1559
1560    /// An `impl Trait`: `impl TraitA + TraitB + ...`
1561    ImplTrait(Vec<GenericBound>),
1562
1563    UnsafeBinder(Box<UnsafeBinderTy>),
1564}
1565
1566impl Type {
1567    /// When comparing types for equality, it can help to ignore `&` wrapping.
1568    pub(crate) fn without_borrowed_ref(&self) -> &Type {
1569        let mut result = self;
1570        while let Type::BorrowedRef { type_, .. } = result {
1571            result = type_;
1572        }
1573        result
1574    }
1575
1576    pub(crate) fn is_borrowed_ref(&self) -> bool {
1577        matches!(self, Type::BorrowedRef { .. })
1578    }
1579
1580    fn is_type_alias(&self) -> bool {
1581        matches!(self, Type::Path { path: Path { res: Res::Def(DefKind::TyAlias, _), .. } })
1582    }
1583
1584    /// Check if this type is a subtype of another type for documentation purposes.
1585    ///
1586    /// This is different from `Eq`, because it knows that things like
1587    /// `Infer` and generics have special subtyping rules.
1588    ///
1589    /// This relation is not commutative when generics are involved:
1590    ///
1591    /// ```ignore(private)
1592    /// # // see types/tests.rs:is_same_generic for the real test
1593    /// use rustdoc::format::cache::Cache;
1594    /// use rustdoc::clean::types::{Type, PrimitiveType};
1595    /// let cache = Cache::new(false);
1596    /// let generic = Type::Generic(rustc_span::symbol::sym::Any);
1597    /// let unit = Type::Primitive(PrimitiveType::Unit);
1598    /// assert!(!generic.is_doc_subtype_of(&unit, &cache));
1599    /// assert!(unit.is_doc_subtype_of(&generic, &cache));
1600    /// ```
1601    ///
1602    /// An owned type is also the same as its borrowed variants (this is commutative),
1603    /// but `&T` is not the same as `&mut T`.
1604    pub(crate) fn is_doc_subtype_of(&self, other: &Self, cache: &Cache) -> bool {
1605        // Strip the references so that it can compare the actual types, unless both are references.
1606        // If both are references, leave them alone and compare the mutabilities later.
1607        let (self_cleared, other_cleared) = if !self.is_borrowed_ref() || !other.is_borrowed_ref() {
1608            (self.without_borrowed_ref(), other.without_borrowed_ref())
1609        } else {
1610            (self, other)
1611        };
1612
1613        // FIXME: `Cache` does not have the data required to unwrap type aliases,
1614        // so we just assume they are equal.
1615        // This is only remotely acceptable because we were previously
1616        // assuming all types were equal when used
1617        // as a generic parameter of a type in `Deref::Target`.
1618        if self_cleared.is_type_alias() || other_cleared.is_type_alias() {
1619            return true;
1620        }
1621
1622        match (self_cleared, other_cleared) {
1623            // Recursive cases.
1624            (Type::Tuple(a), Type::Tuple(b)) => {
1625                a.len() == b.len() && a.iter().zip(b).all(|(a, b)| a.is_doc_subtype_of(b, cache))
1626            }
1627            (Type::Slice(a), Type::Slice(b)) => a.is_doc_subtype_of(b, cache),
1628            (Type::Array(a, al), Type::Array(b, bl)) => al == bl && a.is_doc_subtype_of(b, cache),
1629            (Type::RawPointer(mutability, type_), Type::RawPointer(b_mutability, b_type_)) => {
1630                mutability == b_mutability && type_.is_doc_subtype_of(b_type_, cache)
1631            }
1632            (
1633                Type::BorrowedRef { mutability, type_, .. },
1634                Type::BorrowedRef { mutability: b_mutability, type_: b_type_, .. },
1635            ) => mutability == b_mutability && type_.is_doc_subtype_of(b_type_, cache),
1636            // Placeholders are equal to all other types.
1637            (Type::Infer, _) | (_, Type::Infer) => true,
1638            // Generics match everything on the right, but not on the left.
1639            // If both sides are generic, this returns true.
1640            (_, Type::Generic(_)) => true,
1641            (Type::Generic(_), _) => false,
1642            // `Self` only matches itself.
1643            (Type::SelfTy, Type::SelfTy) => true,
1644            // Paths account for both the path itself and its generics.
1645            (Type::Path { path: a }, Type::Path { path: b }) => {
1646                a.def_id() == b.def_id()
1647                    && a.generics()
1648                        .zip(b.generics())
1649                        .map(|(ag, bg)| ag.zip(bg).all(|(at, bt)| at.is_doc_subtype_of(bt, cache)))
1650                        .unwrap_or(true)
1651            }
1652            // Other cases, such as primitives, just use recursion.
1653            (a, b) => a
1654                .def_id(cache)
1655                .and_then(|a| Some((a, b.def_id(cache)?)))
1656                .map(|(a, b)| a == b)
1657                .unwrap_or(false),
1658        }
1659    }
1660
1661    pub(crate) fn primitive_type(&self) -> Option<PrimitiveType> {
1662        match *self {
1663            Primitive(p) | BorrowedRef { type_: box Primitive(p), .. } => Some(p),
1664            Slice(..) | BorrowedRef { type_: box Slice(..), .. } => Some(PrimitiveType::Slice),
1665            Array(..) | BorrowedRef { type_: box Array(..), .. } => Some(PrimitiveType::Array),
1666            Tuple(ref tys) => {
1667                if tys.is_empty() {
1668                    Some(PrimitiveType::Unit)
1669                } else {
1670                    Some(PrimitiveType::Tuple)
1671                }
1672            }
1673            RawPointer(..) => Some(PrimitiveType::RawPointer),
1674            BareFunction(..) => Some(PrimitiveType::Fn),
1675            _ => None,
1676        }
1677    }
1678
1679    /// Returns the sugared return type for an async function.
1680    ///
1681    /// For example, if the return type is `impl std::future::Future<Output = i32>`, this function
1682    /// will return `i32`.
1683    ///
1684    /// # Panics
1685    ///
1686    /// This function will panic if the return type does not match the expected sugaring for async
1687    /// functions.
1688    pub(crate) fn sugared_async_return_type(self) -> Type {
1689        if let Type::ImplTrait(mut v) = self
1690            && let Some(GenericBound::TraitBound(PolyTrait { mut trait_, .. }, _)) = v.pop()
1691            && let Some(segment) = trait_.segments.pop()
1692            && let GenericArgs::AngleBracketed { mut constraints, .. } = segment.args
1693            && let Some(constraint) = constraints.pop()
1694            && let AssocItemConstraintKind::Equality { term } = constraint.kind
1695            && let Term::Type(ty) = term
1696        {
1697            ty
1698        } else {
1699            panic!("unexpected async fn return type")
1700        }
1701    }
1702
1703    /// Checks if this is a `T::Name` path for an associated type.
1704    pub(crate) fn is_assoc_ty(&self) -> bool {
1705        match self {
1706            Type::Path { path, .. } => path.is_assoc_ty(),
1707            _ => false,
1708        }
1709    }
1710
1711    pub(crate) fn is_self_type(&self) -> bool {
1712        matches!(*self, Type::SelfTy)
1713    }
1714
1715    pub(crate) fn generic_args(&self) -> Option<&GenericArgs> {
1716        match self {
1717            Type::Path { path, .. } => path.generic_args(),
1718            _ => None,
1719        }
1720    }
1721
1722    pub(crate) fn generics(&self) -> Option<impl Iterator<Item = &Type>> {
1723        match self {
1724            Type::Path { path, .. } => path.generics(),
1725            _ => None,
1726        }
1727    }
1728
1729    pub(crate) fn is_full_generic(&self) -> bool {
1730        matches!(self, Type::Generic(_))
1731    }
1732
1733    pub(crate) fn is_unit(&self) -> bool {
1734        matches!(self, Type::Tuple(v) if v.is_empty())
1735    }
1736
1737    /// Use this method to get the [DefId] of a [clean] AST node, including [PrimitiveType]s.
1738    ///
1739    /// [clean]: crate::clean
1740    pub(crate) fn def_id(&self, cache: &Cache) -> Option<DefId> {
1741        let t: PrimitiveType = match self {
1742            Type::Path { path } => return Some(path.def_id()),
1743            DynTrait(bounds, _) => return bounds.first().map(|b| b.trait_.def_id()),
1744            Primitive(p) => return cache.primitive_locations.get(p).cloned(),
1745            BorrowedRef { type_: box Generic(..), .. } => PrimitiveType::Reference,
1746            BorrowedRef { type_, .. } => return type_.def_id(cache),
1747            Tuple(tys) => {
1748                if tys.is_empty() {
1749                    PrimitiveType::Unit
1750                } else {
1751                    PrimitiveType::Tuple
1752                }
1753            }
1754            BareFunction(..) => PrimitiveType::Fn,
1755            Slice(..) => PrimitiveType::Slice,
1756            Array(..) => PrimitiveType::Array,
1757            Type::Pat(..) => PrimitiveType::Pat,
1758            RawPointer(..) => PrimitiveType::RawPointer,
1759            QPath(box QPathData { self_type, .. }) => return self_type.def_id(cache),
1760            Generic(_) | SelfTy | Infer | ImplTrait(_) | UnsafeBinder(_) => return None,
1761        };
1762        Primitive(t).def_id(cache)
1763    }
1764}
1765
1766#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1767pub(crate) struct QPathData {
1768    pub assoc: PathSegment,
1769    pub self_type: Type,
1770    /// FIXME: compute this field on demand.
1771    pub should_fully_qualify: bool,
1772    pub trait_: Option<Path>,
1773}
1774
1775/// A primitive (aka, builtin) type.
1776///
1777/// This represents things like `i32`, `str`, etc.
1778///
1779/// N.B. This has to be different from [`hir::PrimTy`] because it also includes types that aren't
1780/// paths, like [`Self::Unit`].
1781#[derive(Clone, PartialEq, Eq, Hash, Copy, Debug)]
1782pub(crate) enum PrimitiveType {
1783    Isize,
1784    I8,
1785    I16,
1786    I32,
1787    I64,
1788    I128,
1789    Usize,
1790    U8,
1791    U16,
1792    U32,
1793    U64,
1794    U128,
1795    F16,
1796    F32,
1797    F64,
1798    F128,
1799    Char,
1800    Bool,
1801    Str,
1802    Slice,
1803    Array,
1804    Pat,
1805    Tuple,
1806    Unit,
1807    RawPointer,
1808    Reference,
1809    Fn,
1810    Never,
1811}
1812
1813type SimplifiedTypes = FxIndexMap<PrimitiveType, ArrayVec<SimplifiedType, 3>>;
1814impl PrimitiveType {
1815    pub(crate) fn from_hir(prim: hir::PrimTy) -> PrimitiveType {
1816        use ast::{FloatTy, IntTy, UintTy};
1817        match prim {
1818            hir::PrimTy::Int(IntTy::Isize) => PrimitiveType::Isize,
1819            hir::PrimTy::Int(IntTy::I8) => PrimitiveType::I8,
1820            hir::PrimTy::Int(IntTy::I16) => PrimitiveType::I16,
1821            hir::PrimTy::Int(IntTy::I32) => PrimitiveType::I32,
1822            hir::PrimTy::Int(IntTy::I64) => PrimitiveType::I64,
1823            hir::PrimTy::Int(IntTy::I128) => PrimitiveType::I128,
1824            hir::PrimTy::Uint(UintTy::Usize) => PrimitiveType::Usize,
1825            hir::PrimTy::Uint(UintTy::U8) => PrimitiveType::U8,
1826            hir::PrimTy::Uint(UintTy::U16) => PrimitiveType::U16,
1827            hir::PrimTy::Uint(UintTy::U32) => PrimitiveType::U32,
1828            hir::PrimTy::Uint(UintTy::U64) => PrimitiveType::U64,
1829            hir::PrimTy::Uint(UintTy::U128) => PrimitiveType::U128,
1830            hir::PrimTy::Float(FloatTy::F16) => PrimitiveType::F16,
1831            hir::PrimTy::Float(FloatTy::F32) => PrimitiveType::F32,
1832            hir::PrimTy::Float(FloatTy::F64) => PrimitiveType::F64,
1833            hir::PrimTy::Float(FloatTy::F128) => PrimitiveType::F128,
1834            hir::PrimTy::Str => PrimitiveType::Str,
1835            hir::PrimTy::Bool => PrimitiveType::Bool,
1836            hir::PrimTy::Char => PrimitiveType::Char,
1837        }
1838    }
1839
1840    pub(crate) fn from_symbol(s: Symbol) -> Option<PrimitiveType> {
1841        match s {
1842            sym::isize => Some(PrimitiveType::Isize),
1843            sym::i8 => Some(PrimitiveType::I8),
1844            sym::i16 => Some(PrimitiveType::I16),
1845            sym::i32 => Some(PrimitiveType::I32),
1846            sym::i64 => Some(PrimitiveType::I64),
1847            sym::i128 => Some(PrimitiveType::I128),
1848            sym::usize => Some(PrimitiveType::Usize),
1849            sym::u8 => Some(PrimitiveType::U8),
1850            sym::u16 => Some(PrimitiveType::U16),
1851            sym::u32 => Some(PrimitiveType::U32),
1852            sym::u64 => Some(PrimitiveType::U64),
1853            sym::u128 => Some(PrimitiveType::U128),
1854            sym::bool => Some(PrimitiveType::Bool),
1855            sym::char => Some(PrimitiveType::Char),
1856            sym::str => Some(PrimitiveType::Str),
1857            sym::f16 => Some(PrimitiveType::F16),
1858            sym::f32 => Some(PrimitiveType::F32),
1859            sym::f64 => Some(PrimitiveType::F64),
1860            sym::f128 => Some(PrimitiveType::F128),
1861            sym::array => Some(PrimitiveType::Array),
1862            sym::slice => Some(PrimitiveType::Slice),
1863            sym::tuple => Some(PrimitiveType::Tuple),
1864            sym::unit => Some(PrimitiveType::Unit),
1865            sym::pointer => Some(PrimitiveType::RawPointer),
1866            sym::reference => Some(PrimitiveType::Reference),
1867            kw::Fn => Some(PrimitiveType::Fn),
1868            sym::never => Some(PrimitiveType::Never),
1869            _ => None,
1870        }
1871    }
1872
1873    pub(crate) fn simplified_types() -> &'static SimplifiedTypes {
1874        use PrimitiveType::*;
1875        use ty::{FloatTy, IntTy, UintTy};
1876        static CELL: OnceCell<SimplifiedTypes> = OnceCell::new();
1877
1878        let single = |x| iter::once(x).collect();
1879        CELL.get_or_init(move || {
1880            map! {
1881                Isize => single(SimplifiedType::Int(IntTy::Isize)),
1882                I8 => single(SimplifiedType::Int(IntTy::I8)),
1883                I16 => single(SimplifiedType::Int(IntTy::I16)),
1884                I32 => single(SimplifiedType::Int(IntTy::I32)),
1885                I64 => single(SimplifiedType::Int(IntTy::I64)),
1886                I128 => single(SimplifiedType::Int(IntTy::I128)),
1887                Usize => single(SimplifiedType::Uint(UintTy::Usize)),
1888                U8 => single(SimplifiedType::Uint(UintTy::U8)),
1889                U16 => single(SimplifiedType::Uint(UintTy::U16)),
1890                U32 => single(SimplifiedType::Uint(UintTy::U32)),
1891                U64 => single(SimplifiedType::Uint(UintTy::U64)),
1892                U128 => single(SimplifiedType::Uint(UintTy::U128)),
1893                F16 => single(SimplifiedType::Float(FloatTy::F16)),
1894                F32 => single(SimplifiedType::Float(FloatTy::F32)),
1895                F64 => single(SimplifiedType::Float(FloatTy::F64)),
1896                F128 => single(SimplifiedType::Float(FloatTy::F128)),
1897                Str => single(SimplifiedType::Str),
1898                Bool => single(SimplifiedType::Bool),
1899                Char => single(SimplifiedType::Char),
1900                Array => single(SimplifiedType::Array),
1901                Slice => single(SimplifiedType::Slice),
1902                // FIXME: If we ever add an inherent impl for tuples
1903                // with different lengths, they won't show in rustdoc.
1904                //
1905                // Either manually update this arrayvec at this point
1906                // or start with a more complex refactoring.
1907                Tuple => [SimplifiedType::Tuple(1), SimplifiedType::Tuple(2), SimplifiedType::Tuple(3)].into(),
1908                Unit => single(SimplifiedType::Tuple(0)),
1909                RawPointer => [SimplifiedType::Ptr(Mutability::Not), SimplifiedType::Ptr(Mutability::Mut)].into_iter().collect(),
1910                Reference => [SimplifiedType::Ref(Mutability::Not), SimplifiedType::Ref(Mutability::Mut)].into_iter().collect(),
1911                // FIXME: This will be wrong if we ever add inherent impls
1912                // for function pointers.
1913                Fn => single(SimplifiedType::Function(1)),
1914                Never => single(SimplifiedType::Never),
1915            }
1916        })
1917    }
1918
1919    pub(crate) fn impls<'tcx>(&self, tcx: TyCtxt<'tcx>) -> impl Iterator<Item = DefId> + 'tcx {
1920        Self::simplified_types()
1921            .get(self)
1922            .into_iter()
1923            .flatten()
1924            .flat_map(move |&simp| tcx.incoherent_impls(simp).iter())
1925            .copied()
1926    }
1927
1928    pub(crate) fn all_impls(tcx: TyCtxt<'_>) -> impl Iterator<Item = DefId> {
1929        Self::simplified_types()
1930            .values()
1931            .flatten()
1932            .flat_map(move |&simp| tcx.incoherent_impls(simp).iter())
1933            .copied()
1934    }
1935
1936    pub(crate) fn as_sym(&self) -> Symbol {
1937        use PrimitiveType::*;
1938        match self {
1939            Isize => sym::isize,
1940            I8 => sym::i8,
1941            I16 => sym::i16,
1942            I32 => sym::i32,
1943            I64 => sym::i64,
1944            I128 => sym::i128,
1945            Usize => sym::usize,
1946            U8 => sym::u8,
1947            U16 => sym::u16,
1948            U32 => sym::u32,
1949            U64 => sym::u64,
1950            U128 => sym::u128,
1951            F16 => sym::f16,
1952            F32 => sym::f32,
1953            F64 => sym::f64,
1954            F128 => sym::f128,
1955            Str => sym::str,
1956            Bool => sym::bool,
1957            Char => sym::char,
1958            Array => sym::array,
1959            Pat => sym::pat,
1960            Slice => sym::slice,
1961            Tuple => sym::tuple,
1962            Unit => sym::unit,
1963            RawPointer => sym::pointer,
1964            Reference => sym::reference,
1965            Fn => kw::Fn,
1966            Never => sym::never,
1967        }
1968    }
1969
1970    /// Returns the DefId of the module with `rustc_doc_primitive` for this primitive type.
1971    /// Panics if there is no such module.
1972    ///
1973    /// This gives precedence to primitives defined in the current crate, and deprioritizes
1974    /// primitives defined in `core`,
1975    /// but otherwise, if multiple crates define the same primitive, there is no guarantee of which
1976    /// will be picked.
1977    ///
1978    /// In particular, if a crate depends on both `std` and another crate that also defines
1979    /// `rustc_doc_primitive`, then it's entirely random whether `std` or the other crate is picked.
1980    /// (no_std crates are usually fine unless multiple dependencies define a primitive.)
1981    pub(crate) fn primitive_locations(tcx: TyCtxt<'_>) -> &FxIndexMap<PrimitiveType, DefId> {
1982        static PRIMITIVE_LOCATIONS: OnceCell<FxIndexMap<PrimitiveType, DefId>> = OnceCell::new();
1983        PRIMITIVE_LOCATIONS.get_or_init(|| {
1984            let mut primitive_locations = FxIndexMap::default();
1985            // NOTE: technically this misses crates that are only passed with `--extern` and not loaded when checking the crate.
1986            // This is a degenerate case that I don't plan to support.
1987            for &crate_num in tcx.crates(()) {
1988                let e = ExternalCrate { crate_num };
1989                let crate_name = e.name(tcx);
1990                debug!(?crate_num, ?crate_name);
1991                for (def_id, prim) in e.primitives(tcx) {
1992                    // HACK: try to link to std instead where possible
1993                    if crate_name == sym::core && primitive_locations.contains_key(&prim) {
1994                        continue;
1995                    }
1996                    primitive_locations.insert(prim, def_id);
1997                }
1998            }
1999            let local_primitives = ExternalCrate { crate_num: LOCAL_CRATE }.primitives(tcx);
2000            for (def_id, prim) in local_primitives {
2001                primitive_locations.insert(prim, def_id);
2002            }
2003            primitive_locations
2004        })
2005    }
2006}
2007
2008impl From<ty::IntTy> for PrimitiveType {
2009    fn from(int_ty: ty::IntTy) -> PrimitiveType {
2010        match int_ty {
2011            ty::IntTy::Isize => PrimitiveType::Isize,
2012            ty::IntTy::I8 => PrimitiveType::I8,
2013            ty::IntTy::I16 => PrimitiveType::I16,
2014            ty::IntTy::I32 => PrimitiveType::I32,
2015            ty::IntTy::I64 => PrimitiveType::I64,
2016            ty::IntTy::I128 => PrimitiveType::I128,
2017        }
2018    }
2019}
2020
2021impl From<ty::UintTy> for PrimitiveType {
2022    fn from(uint_ty: ty::UintTy) -> PrimitiveType {
2023        match uint_ty {
2024            ty::UintTy::Usize => PrimitiveType::Usize,
2025            ty::UintTy::U8 => PrimitiveType::U8,
2026            ty::UintTy::U16 => PrimitiveType::U16,
2027            ty::UintTy::U32 => PrimitiveType::U32,
2028            ty::UintTy::U64 => PrimitiveType::U64,
2029            ty::UintTy::U128 => PrimitiveType::U128,
2030        }
2031    }
2032}
2033
2034impl From<ty::FloatTy> for PrimitiveType {
2035    fn from(float_ty: ty::FloatTy) -> PrimitiveType {
2036        match float_ty {
2037            ty::FloatTy::F16 => PrimitiveType::F16,
2038            ty::FloatTy::F32 => PrimitiveType::F32,
2039            ty::FloatTy::F64 => PrimitiveType::F64,
2040            ty::FloatTy::F128 => PrimitiveType::F128,
2041        }
2042    }
2043}
2044
2045impl From<hir::PrimTy> for PrimitiveType {
2046    fn from(prim_ty: hir::PrimTy) -> PrimitiveType {
2047        match prim_ty {
2048            hir::PrimTy::Int(int_ty) => int_ty.into(),
2049            hir::PrimTy::Uint(uint_ty) => uint_ty.into(),
2050            hir::PrimTy::Float(float_ty) => float_ty.into(),
2051            hir::PrimTy::Str => PrimitiveType::Str,
2052            hir::PrimTy::Bool => PrimitiveType::Bool,
2053            hir::PrimTy::Char => PrimitiveType::Char,
2054        }
2055    }
2056}
2057
2058#[derive(Clone, Debug)]
2059pub(crate) struct Struct {
2060    pub(crate) ctor_kind: Option<CtorKind>,
2061    pub(crate) generics: Generics,
2062    pub(crate) fields: ThinVec<Item>,
2063}
2064
2065impl Struct {
2066    pub(crate) fn has_stripped_entries(&self) -> bool {
2067        self.fields.iter().any(|f| f.is_stripped())
2068    }
2069}
2070
2071#[derive(Clone, Debug)]
2072pub(crate) struct Union {
2073    pub(crate) generics: Generics,
2074    pub(crate) fields: Vec<Item>,
2075}
2076
2077impl Union {
2078    pub(crate) fn has_stripped_entries(&self) -> bool {
2079        self.fields.iter().any(|f| f.is_stripped())
2080    }
2081}
2082
2083/// This is a more limited form of the standard Struct, different in that
2084/// it lacks the things most items have (name, id, parameterization). Found
2085/// only as a variant in an enum.
2086#[derive(Clone, Debug)]
2087pub(crate) struct VariantStruct {
2088    pub(crate) fields: ThinVec<Item>,
2089}
2090
2091impl VariantStruct {
2092    pub(crate) fn has_stripped_entries(&self) -> bool {
2093        self.fields.iter().any(|f| f.is_stripped())
2094    }
2095}
2096
2097#[derive(Clone, Debug)]
2098pub(crate) struct Enum {
2099    pub(crate) variants: IndexVec<VariantIdx, Item>,
2100    pub(crate) generics: Generics,
2101}
2102
2103impl Enum {
2104    pub(crate) fn has_stripped_entries(&self) -> bool {
2105        self.variants.iter().any(|f| f.is_stripped())
2106    }
2107
2108    pub(crate) fn non_stripped_variants(&self) -> impl Iterator<Item = &Item> {
2109        self.variants.iter().filter(|v| !v.is_stripped())
2110    }
2111}
2112
2113#[derive(Clone, Debug)]
2114pub(crate) struct Variant {
2115    pub kind: VariantKind,
2116    pub discriminant: Option<Discriminant>,
2117}
2118
2119#[derive(Clone, Debug)]
2120pub(crate) enum VariantKind {
2121    CLike,
2122    Tuple(ThinVec<Item>),
2123    Struct(VariantStruct),
2124}
2125
2126impl Variant {
2127    pub(crate) fn has_stripped_entries(&self) -> Option<bool> {
2128        match &self.kind {
2129            VariantKind::Struct(struct_) => Some(struct_.has_stripped_entries()),
2130            VariantKind::CLike | VariantKind::Tuple(_) => None,
2131        }
2132    }
2133}
2134
2135#[derive(Clone, Debug)]
2136pub(crate) struct Discriminant {
2137    // In the case of cross crate re-exports, we don't have the necessary information
2138    // to reconstruct the expression of the discriminant, only the value.
2139    pub(super) expr: Option<BodyId>,
2140    pub(super) value: DefId,
2141}
2142
2143impl Discriminant {
2144    /// Will be `None` in the case of cross-crate reexports, and may be
2145    /// simplified
2146    pub(crate) fn expr(&self, tcx: TyCtxt<'_>) -> Option<String> {
2147        self.expr
2148            .map(|body| rendered_const(tcx, tcx.hir_body(body), tcx.hir_body_owner_def_id(body)))
2149    }
2150    pub(crate) fn value(&self, tcx: TyCtxt<'_>, with_underscores: bool) -> String {
2151        print_evaluated_const(tcx, self.value, with_underscores, false).unwrap()
2152    }
2153}
2154
2155/// Small wrapper around [`rustc_span::Span`] that adds helper methods
2156/// and enforces calling [`rustc_span::Span::source_callsite()`].
2157#[derive(Copy, Clone, Debug)]
2158pub(crate) struct Span(rustc_span::Span);
2159
2160impl Span {
2161    /// Wraps a [`rustc_span::Span`]. In case this span is the result of a macro expansion, the
2162    /// span will be updated to point to the macro invocation instead of the macro definition.
2163    ///
2164    /// (See rust-lang/rust#39726)
2165    pub(crate) fn new(sp: rustc_span::Span) -> Self {
2166        Self(sp.source_callsite())
2167    }
2168
2169    pub(crate) fn inner(&self) -> rustc_span::Span {
2170        self.0
2171    }
2172
2173    pub(crate) fn filename(&self, sess: &Session) -> FileName {
2174        sess.source_map().span_to_filename(self.0)
2175    }
2176
2177    pub(crate) fn lo(&self, sess: &Session) -> Loc {
2178        sess.source_map().lookup_char_pos(self.0.lo())
2179    }
2180
2181    pub(crate) fn hi(&self, sess: &Session) -> Loc {
2182        sess.source_map().lookup_char_pos(self.0.hi())
2183    }
2184
2185    pub(crate) fn cnum(&self, sess: &Session) -> CrateNum {
2186        // FIXME: is there a time when the lo and hi crate would be different?
2187        self.lo(sess).file.cnum
2188    }
2189}
2190
2191#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2192pub(crate) struct Path {
2193    pub(crate) res: Res,
2194    pub(crate) segments: ThinVec<PathSegment>,
2195}
2196
2197impl Path {
2198    pub(crate) fn def_id(&self) -> DefId {
2199        self.res.def_id()
2200    }
2201
2202    pub(crate) fn last_opt(&self) -> Option<Symbol> {
2203        self.segments.last().map(|s| s.name)
2204    }
2205
2206    pub(crate) fn last(&self) -> Symbol {
2207        self.last_opt().expect("segments were empty")
2208    }
2209
2210    pub(crate) fn whole_name(&self) -> String {
2211        self.segments
2212            .iter()
2213            .map(|s| if s.name == kw::PathRoot { "" } else { s.name.as_str() })
2214            .intersperse("::")
2215            .collect()
2216    }
2217
2218    /// Checks if this is a `T::Name` path for an associated type.
2219    pub(crate) fn is_assoc_ty(&self) -> bool {
2220        match self.res {
2221            Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } | Res::Def(DefKind::TyParam, _)
2222                if self.segments.len() != 1 =>
2223            {
2224                true
2225            }
2226            Res::Def(DefKind::AssocTy, _) => true,
2227            _ => false,
2228        }
2229    }
2230
2231    pub(crate) fn generic_args(&self) -> Option<&GenericArgs> {
2232        self.segments.last().map(|seg| &seg.args)
2233    }
2234
2235    pub(crate) fn generics(&self) -> Option<impl Iterator<Item = &Type>> {
2236        self.segments.last().and_then(|seg| {
2237            if let GenericArgs::AngleBracketed { ref args, .. } = seg.args {
2238                Some(args.iter().filter_map(|arg| match arg {
2239                    GenericArg::Type(ty) => Some(ty),
2240                    _ => None,
2241                }))
2242            } else {
2243                None
2244            }
2245        })
2246    }
2247}
2248
2249#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2250pub(crate) enum GenericArg {
2251    Lifetime(Lifetime),
2252    Type(Type),
2253    Const(Box<ConstantKind>),
2254    Infer,
2255}
2256
2257impl GenericArg {
2258    pub(crate) fn as_lt(&self) -> Option<&Lifetime> {
2259        if let Self::Lifetime(lt) = self { Some(lt) } else { None }
2260    }
2261
2262    pub(crate) fn as_ty(&self) -> Option<&Type> {
2263        if let Self::Type(ty) = self { Some(ty) } else { None }
2264    }
2265}
2266
2267#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2268pub(crate) enum GenericArgs {
2269    /// `<args, constraints = ..>`
2270    AngleBracketed { args: ThinVec<GenericArg>, constraints: ThinVec<AssocItemConstraint> },
2271    /// `(inputs) -> output`
2272    Parenthesized { inputs: ThinVec<Type>, output: Option<Box<Type>> },
2273    /// `(..)`
2274    ReturnTypeNotation,
2275}
2276
2277impl GenericArgs {
2278    pub(crate) fn is_empty(&self) -> bool {
2279        match self {
2280            GenericArgs::AngleBracketed { args, constraints } => {
2281                args.is_empty() && constraints.is_empty()
2282            }
2283            GenericArgs::Parenthesized { inputs, output } => inputs.is_empty() && output.is_none(),
2284            GenericArgs::ReturnTypeNotation => false,
2285        }
2286    }
2287    pub(crate) fn constraints(&self) -> Box<dyn Iterator<Item = AssocItemConstraint> + '_> {
2288        match self {
2289            GenericArgs::AngleBracketed { constraints, .. } => {
2290                Box::new(constraints.iter().cloned())
2291            }
2292            GenericArgs::Parenthesized { output, .. } => Box::new(
2293                output
2294                    .as_ref()
2295                    .map(|ty| AssocItemConstraint {
2296                        assoc: PathSegment {
2297                            name: sym::Output,
2298                            args: GenericArgs::AngleBracketed {
2299                                args: ThinVec::new(),
2300                                constraints: ThinVec::new(),
2301                            },
2302                        },
2303                        kind: AssocItemConstraintKind::Equality {
2304                            term: Term::Type((**ty).clone()),
2305                        },
2306                    })
2307                    .into_iter(),
2308            ),
2309            GenericArgs::ReturnTypeNotation => Box::new([].into_iter()),
2310        }
2311    }
2312}
2313
2314impl<'a> IntoIterator for &'a GenericArgs {
2315    type IntoIter = Box<dyn Iterator<Item = GenericArg> + 'a>;
2316    type Item = GenericArg;
2317    fn into_iter(self) -> Self::IntoIter {
2318        match self {
2319            GenericArgs::AngleBracketed { args, .. } => Box::new(args.iter().cloned()),
2320            GenericArgs::Parenthesized { inputs, .. } => {
2321                // FIXME: This isn't really right, since `Fn(A, B)` is `Fn<(A, B)>`
2322                Box::new(inputs.iter().cloned().map(GenericArg::Type))
2323            }
2324            GenericArgs::ReturnTypeNotation => Box::new([].into_iter()),
2325        }
2326    }
2327}
2328
2329#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2330pub(crate) struct PathSegment {
2331    pub(crate) name: Symbol,
2332    pub(crate) args: GenericArgs,
2333}
2334
2335#[derive(Clone, Debug)]
2336pub(crate) enum TypeAliasInnerType {
2337    Enum { variants: IndexVec<VariantIdx, Item>, is_non_exhaustive: bool },
2338    Union { fields: Vec<Item> },
2339    Struct { ctor_kind: Option<CtorKind>, fields: Vec<Item> },
2340}
2341
2342impl TypeAliasInnerType {
2343    fn has_stripped_entries(&self) -> Option<bool> {
2344        Some(match self {
2345            Self::Enum { variants, .. } => variants.iter().any(|v| v.is_stripped()),
2346            Self::Union { fields } | Self::Struct { fields, .. } => {
2347                fields.iter().any(|f| f.is_stripped())
2348            }
2349        })
2350    }
2351}
2352
2353#[derive(Clone, Debug)]
2354pub(crate) struct TypeAlias {
2355    pub(crate) type_: Type,
2356    pub(crate) generics: Generics,
2357    /// Inner `AdtDef` type, ie `type TyKind = IrTyKind<Adt, Ty>`,
2358    /// to be shown directly on the typedef page.
2359    pub(crate) inner_type: Option<TypeAliasInnerType>,
2360    /// `type_` can come from either the HIR or from metadata. If it comes from HIR, it may be a type
2361    /// alias instead of the final type. This will always have the final type, regardless of whether
2362    /// `type_` came from HIR or from metadata.
2363    ///
2364    /// If `item_type.is_none()`, `type_` is guaranteed to come from metadata (and therefore hold the
2365    /// final type).
2366    pub(crate) item_type: Option<Type>,
2367}
2368
2369#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2370pub(crate) struct BareFunctionDecl {
2371    pub(crate) safety: hir::Safety,
2372    pub(crate) generic_params: Vec<GenericParamDef>,
2373    pub(crate) decl: FnDecl,
2374    pub(crate) abi: ExternAbi,
2375}
2376
2377#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2378pub(crate) struct UnsafeBinderTy {
2379    pub(crate) generic_params: Vec<GenericParamDef>,
2380    pub(crate) ty: Type,
2381}
2382
2383#[derive(Clone, Debug)]
2384pub(crate) struct Static {
2385    pub(crate) type_: Box<Type>,
2386    pub(crate) mutability: Mutability,
2387    pub(crate) expr: Option<BodyId>,
2388}
2389
2390#[derive(Clone, PartialEq, Eq, Hash, Debug)]
2391pub(crate) struct Constant {
2392    pub(crate) generics: Generics,
2393    pub(crate) kind: ConstantKind,
2394    pub(crate) type_: Type,
2395}
2396
2397#[derive(Clone, PartialEq, Eq, Hash, Debug)]
2398pub(crate) enum Term {
2399    Type(Type),
2400    Constant(ConstantKind),
2401}
2402
2403impl Term {
2404    pub(crate) fn ty(&self) -> Option<&Type> {
2405        if let Term::Type(ty) = self { Some(ty) } else { None }
2406    }
2407}
2408
2409impl From<Type> for Term {
2410    fn from(ty: Type) -> Self {
2411        Term::Type(ty)
2412    }
2413}
2414
2415#[derive(Clone, PartialEq, Eq, Hash, Debug)]
2416pub(crate) enum ConstantKind {
2417    /// This is the wrapper around `ty::Const` for a non-local constant. Because it doesn't have a
2418    /// `BodyId`, we need to handle it on its own.
2419    ///
2420    /// Note that `ty::Const` includes generic parameters, and may not always be uniquely identified
2421    /// by a DefId. So this field must be different from `Extern`.
2422    TyConst { expr: Box<str> },
2423    /// A constant that is just a path (i.e., referring to a const param, free const, etc.).
2424    // FIXME: this is an unfortunate representation. rustdoc's logic around consts needs to be improved.
2425    Path { path: Box<str> },
2426    /// A constant (expression) that's not an item or associated item. These are usually found
2427    /// nested inside types (e.g., array lengths) or expressions (e.g., repeat counts), and also
2428    /// used to define explicit discriminant values for enum variants.
2429    Anonymous { body: BodyId },
2430    /// A constant from a different crate.
2431    Extern { def_id: DefId },
2432    /// `const FOO: u32 = ...;`
2433    Local { def_id: DefId, body: BodyId },
2434    /// An inferred constant as in `[10u8; _]`.
2435    Infer,
2436}
2437
2438impl ConstantKind {
2439    pub(crate) fn expr(&self, tcx: TyCtxt<'_>) -> String {
2440        match *self {
2441            ConstantKind::TyConst { ref expr } => expr.to_string(),
2442            ConstantKind::Path { ref path } => path.to_string(),
2443            ConstantKind::Extern { def_id } => print_inlined_const(tcx, def_id),
2444            ConstantKind::Local { body, .. } | ConstantKind::Anonymous { body } => {
2445                rendered_const(tcx, tcx.hir_body(body), tcx.hir_body_owner_def_id(body))
2446            }
2447            ConstantKind::Infer => "_".to_string(),
2448        }
2449    }
2450
2451    pub(crate) fn value(&self, tcx: TyCtxt<'_>) -> Option<String> {
2452        match *self {
2453            ConstantKind::TyConst { .. }
2454            | ConstantKind::Path { .. }
2455            | ConstantKind::Anonymous { .. }
2456            | ConstantKind::Infer => None,
2457            ConstantKind::Extern { def_id } | ConstantKind::Local { def_id, .. } => {
2458                print_evaluated_const(tcx, def_id, true, true)
2459            }
2460        }
2461    }
2462
2463    pub(crate) fn is_literal(&self, tcx: TyCtxt<'_>) -> bool {
2464        match *self {
2465            ConstantKind::TyConst { .. }
2466            | ConstantKind::Extern { .. }
2467            | ConstantKind::Path { .. }
2468            | ConstantKind::Infer => false,
2469            ConstantKind::Local { body, .. } | ConstantKind::Anonymous { body } => {
2470                is_literal_expr(tcx, body.hir_id)
2471            }
2472        }
2473    }
2474}
2475
2476#[derive(Clone, Debug)]
2477pub(crate) struct Impl {
2478    pub(crate) safety: hir::Safety,
2479    pub(crate) generics: Generics,
2480    pub(crate) trait_: Option<Path>,
2481    pub(crate) for_: Type,
2482    pub(crate) items: Vec<Item>,
2483    pub(crate) polarity: ty::ImplPolarity,
2484    pub(crate) kind: ImplKind,
2485}
2486
2487impl Impl {
2488    pub(crate) fn provided_trait_methods(&self, tcx: TyCtxt<'_>) -> FxIndexSet<Symbol> {
2489        self.trait_
2490            .as_ref()
2491            .map(|t| t.def_id())
2492            .map(|did| tcx.provided_trait_methods(did).map(|meth| meth.name()).collect())
2493            .unwrap_or_default()
2494    }
2495
2496    pub(crate) fn is_negative_trait_impl(&self) -> bool {
2497        matches!(self.polarity, ty::ImplPolarity::Negative)
2498    }
2499}
2500
2501#[derive(Clone, Debug)]
2502pub(crate) enum ImplKind {
2503    Normal,
2504    Auto,
2505    FakeVariadic,
2506    Blanket(Box<Type>),
2507}
2508
2509impl ImplKind {
2510    pub(crate) fn is_auto(&self) -> bool {
2511        matches!(self, ImplKind::Auto)
2512    }
2513
2514    pub(crate) fn is_blanket(&self) -> bool {
2515        matches!(self, ImplKind::Blanket(_))
2516    }
2517
2518    pub(crate) fn is_fake_variadic(&self) -> bool {
2519        matches!(self, ImplKind::FakeVariadic)
2520    }
2521
2522    pub(crate) fn as_blanket_ty(&self) -> Option<&Type> {
2523        match self {
2524            ImplKind::Blanket(ty) => Some(ty),
2525            _ => None,
2526        }
2527    }
2528}
2529
2530#[derive(Clone, Debug)]
2531pub(crate) struct Import {
2532    pub(crate) kind: ImportKind,
2533    /// The item being re-exported.
2534    pub(crate) source: ImportSource,
2535    pub(crate) should_be_displayed: bool,
2536}
2537
2538impl Import {
2539    pub(crate) fn new_simple(
2540        name: Symbol,
2541        source: ImportSource,
2542        should_be_displayed: bool,
2543    ) -> Self {
2544        Self { kind: ImportKind::Simple(name), source, should_be_displayed }
2545    }
2546
2547    pub(crate) fn new_glob(source: ImportSource, should_be_displayed: bool) -> Self {
2548        Self { kind: ImportKind::Glob, source, should_be_displayed }
2549    }
2550
2551    pub(crate) fn imported_item_is_doc_hidden(&self, tcx: TyCtxt<'_>) -> bool {
2552        self.source.did.is_some_and(|did| tcx.is_doc_hidden(did))
2553    }
2554}
2555
2556#[derive(Clone, Debug)]
2557pub(crate) enum ImportKind {
2558    // use source as str;
2559    Simple(Symbol),
2560    // use source::*;
2561    Glob,
2562}
2563
2564#[derive(Clone, Debug)]
2565pub(crate) struct ImportSource {
2566    pub(crate) path: Path,
2567    pub(crate) did: Option<DefId>,
2568}
2569
2570#[derive(Clone, Debug)]
2571pub(crate) struct Macro {
2572    pub(crate) source: String,
2573    /// Whether the macro was defined via `macro_rules!` as opposed to `macro`.
2574    pub(crate) macro_rules: bool,
2575}
2576
2577#[derive(Clone, Debug)]
2578pub(crate) struct ProcMacro {
2579    pub(crate) kind: MacroKind,
2580    pub(crate) helpers: Vec<Symbol>,
2581}
2582
2583/// A constraint on an associated item.
2584///
2585/// ### Examples
2586///
2587/// * the `A = Ty` and `B = Ty` in `Trait<A = Ty, B = Ty>`
2588/// * the `G<Ty> = Ty` in `Trait<G<Ty> = Ty>`
2589/// * the `A: Bound` in `Trait<A: Bound>`
2590/// * the `RetTy` in `Trait(ArgTy, ArgTy) -> RetTy`
2591/// * the `C = { Ct }` in `Trait<C = { Ct }>` (feature `associated_const_equality`)
2592/// * the `f(..): Bound` in `Trait<f(..): Bound>` (feature `return_type_notation`)
2593#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2594pub(crate) struct AssocItemConstraint {
2595    pub(crate) assoc: PathSegment,
2596    pub(crate) kind: AssocItemConstraintKind,
2597}
2598
2599/// The kind of [associated item constraint][AssocItemConstraint].
2600#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2601pub(crate) enum AssocItemConstraintKind {
2602    Equality { term: Term },
2603    Bound { bounds: Vec<GenericBound> },
2604}
2605
2606// Some nodes are used a lot. Make sure they don't unintentionally get bigger.
2607#[cfg(target_pointer_width = "64")]
2608mod size_asserts {
2609    use rustc_data_structures::static_assert_size;
2610
2611    use super::*;
2612    // tidy-alphabetical-start
2613    static_assert_size!(Crate, 16); // frequently moved by-value
2614    static_assert_size!(DocFragment, 32);
2615    static_assert_size!(GenericArg, 32);
2616    static_assert_size!(GenericArgs, 24);
2617    static_assert_size!(GenericParamDef, 40);
2618    static_assert_size!(Generics, 16);
2619    static_assert_size!(Item, 8);
2620    static_assert_size!(ItemInner, 144);
2621    static_assert_size!(ItemKind, 48);
2622    static_assert_size!(PathSegment, 32);
2623    static_assert_size!(Type, 32);
2624    // tidy-alphabetical-end
2625}