rustdoc/clean/
types.rs

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