[go: up one dir, main page]

rustdoc/clean/
types.rs

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