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) = find_attr!(attrs, AttributeKind::TargetFeature(features, _) => features)
1091    {
1092        for (feature, _) in features {
1093            cfg &= Cfg::Cfg(sym::target_feature, Some(*feature));
1094        }
1095    }
1096
1097    if cfg == Cfg::True { None } else { Some(Arc::new(cfg)) }
1098}
1099
1100pub(crate) trait NestedAttributesExt {
1101    /// Returns `true` if the attribute list contains a specific `word`
1102    fn has_word(self, word: Symbol) -> bool
1103    where
1104        Self: Sized,
1105    {
1106        <Self as NestedAttributesExt>::get_word_attr(self, word).is_some()
1107    }
1108
1109    /// Returns `Some(attr)` if the attribute list contains 'attr'
1110    /// corresponding to a specific `word`
1111    fn get_word_attr(self, word: Symbol) -> Option<ast::MetaItemInner>;
1112}
1113
1114impl<I: Iterator<Item = ast::MetaItemInner>> NestedAttributesExt for I {
1115    fn get_word_attr(mut self, word: Symbol) -> Option<ast::MetaItemInner> {
1116        self.find(|attr| attr.is_word() && attr.has_name(word))
1117    }
1118}
1119
1120/// A link that has not yet been rendered.
1121///
1122/// This link will be turned into a rendered link by [`Item::links`].
1123#[derive(Clone, Debug, PartialEq, Eq, Hash)]
1124pub(crate) struct ItemLink {
1125    /// The original link written in the markdown
1126    pub(crate) link: Box<str>,
1127    /// The link text displayed in the HTML.
1128    ///
1129    /// This may not be the same as `link` if there was a disambiguator
1130    /// in an intra-doc link (e.g. \[`fn@f`\])
1131    pub(crate) link_text: Box<str>,
1132    /// The `DefId` of the Item whose **HTML Page** contains the item being
1133    /// linked to. This will be different to `item_id` on item's that don't
1134    /// have their own page, such as struct fields and enum variants.
1135    pub(crate) page_id: DefId,
1136    /// The url fragment to append to the link
1137    pub(crate) fragment: Option<UrlFragment>,
1138}
1139
1140pub struct RenderedLink {
1141    /// The text the link was original written as.
1142    ///
1143    /// This could potentially include disambiguators and backticks.
1144    pub(crate) original_text: Box<str>,
1145    /// The text to display in the HTML
1146    pub(crate) new_text: Box<str>,
1147    /// The URL to put in the `href`
1148    pub(crate) href: String,
1149    /// The tooltip.
1150    pub(crate) tooltip: String,
1151}
1152
1153/// The attributes on an [`Item`], including attributes like `#[derive(...)]` and `#[inline]`,
1154/// as well as doc comments.
1155#[derive(Clone, Debug, Default)]
1156pub(crate) struct Attributes {
1157    pub(crate) doc_strings: Vec<DocFragment>,
1158    pub(crate) other_attrs: ThinVec<hir::Attribute>,
1159}
1160
1161impl Attributes {
1162    pub(crate) fn lists(&self, name: Symbol) -> impl Iterator<Item = ast::MetaItemInner> {
1163        hir_attr_lists(&self.other_attrs[..], name)
1164    }
1165
1166    pub(crate) fn has_doc_flag(&self, flag: Symbol) -> bool {
1167        for attr in &self.other_attrs {
1168            if !attr.has_name(sym::doc) {
1169                continue;
1170            }
1171
1172            if let Some(items) = attr.meta_item_list()
1173                && items.iter().filter_map(|i| i.meta_item()).any(|it| it.has_name(flag))
1174            {
1175                return true;
1176            }
1177        }
1178
1179        false
1180    }
1181
1182    pub(crate) fn is_doc_hidden(&self) -> bool {
1183        self.has_doc_flag(sym::hidden)
1184    }
1185
1186    pub(crate) fn from_hir(attrs: &[hir::Attribute]) -> Attributes {
1187        Attributes::from_hir_iter(attrs.iter().map(|attr| (attr, None)), false)
1188    }
1189
1190    pub(crate) fn from_hir_with_additional(
1191        attrs: &[hir::Attribute],
1192        (additional_attrs, def_id): (&[hir::Attribute], DefId),
1193    ) -> Attributes {
1194        // Additional documentation should be shown before the original documentation.
1195        let attrs1 = additional_attrs.iter().map(|attr| (attr, Some(def_id)));
1196        let attrs2 = attrs.iter().map(|attr| (attr, None));
1197        Attributes::from_hir_iter(attrs1.chain(attrs2), false)
1198    }
1199
1200    pub(crate) fn from_hir_iter<'a>(
1201        attrs: impl Iterator<Item = (&'a hir::Attribute, Option<DefId>)>,
1202        doc_only: bool,
1203    ) -> Attributes {
1204        let (doc_strings, other_attrs) = attrs_to_doc_fragments(attrs, doc_only);
1205        Attributes { doc_strings, other_attrs }
1206    }
1207
1208    /// Combine all doc strings into a single value handling indentation and newlines as needed.
1209    pub(crate) fn doc_value(&self) -> String {
1210        self.opt_doc_value().unwrap_or_default()
1211    }
1212
1213    /// Combine all doc strings into a single value handling indentation and newlines as needed.
1214    /// Returns `None` is there's no documentation at all, and `Some("")` if there is some
1215    /// documentation but it is empty (e.g. `#[doc = ""]`).
1216    pub(crate) fn opt_doc_value(&self) -> Option<String> {
1217        (!self.doc_strings.is_empty()).then(|| {
1218            let mut res = String::new();
1219            for frag in &self.doc_strings {
1220                add_doc_fragment(&mut res, frag);
1221            }
1222            res.pop();
1223            res
1224        })
1225    }
1226
1227    pub(crate) fn get_doc_aliases(&self) -> Box<[Symbol]> {
1228        let mut aliases = FxIndexSet::default();
1229
1230        for attr in
1231            hir_attr_lists(&self.other_attrs[..], sym::doc).filter(|a| a.has_name(sym::alias))
1232        {
1233            if let Some(values) = attr.meta_item_list() {
1234                for l in values {
1235                    if let Some(lit) = l.lit()
1236                        && let ast::LitKind::Str(s, _) = lit.kind
1237                    {
1238                        aliases.insert(s);
1239                    }
1240                }
1241            } else if let Some(value) = attr.value_str() {
1242                aliases.insert(value);
1243            }
1244        }
1245        aliases.into_iter().collect::<Vec<_>>().into()
1246    }
1247}
1248
1249#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1250pub(crate) enum GenericBound {
1251    TraitBound(PolyTrait, hir::TraitBoundModifiers),
1252    Outlives(Lifetime),
1253    /// `use<'a, T>` precise-capturing bound syntax
1254    Use(Vec<PreciseCapturingArg>),
1255}
1256
1257impl GenericBound {
1258    pub(crate) fn sized(cx: &mut DocContext<'_>) -> GenericBound {
1259        Self::sized_with(cx, hir::TraitBoundModifiers::NONE)
1260    }
1261
1262    pub(crate) fn maybe_sized(cx: &mut DocContext<'_>) -> GenericBound {
1263        Self::sized_with(
1264            cx,
1265            hir::TraitBoundModifiers {
1266                polarity: hir::BoundPolarity::Maybe(DUMMY_SP),
1267                constness: hir::BoundConstness::Never,
1268            },
1269        )
1270    }
1271
1272    fn sized_with(cx: &mut DocContext<'_>, modifiers: hir::TraitBoundModifiers) -> GenericBound {
1273        let did = cx.tcx.require_lang_item(LangItem::Sized, DUMMY_SP);
1274        let empty = ty::Binder::dummy(ty::GenericArgs::empty());
1275        let path = clean_middle_path(cx, did, false, ThinVec::new(), empty);
1276        inline::record_extern_fqn(cx, did, ItemType::Trait);
1277        GenericBound::TraitBound(PolyTrait { trait_: path, generic_params: Vec::new() }, modifiers)
1278    }
1279
1280    pub(crate) fn is_trait_bound(&self) -> bool {
1281        matches!(self, Self::TraitBound(..))
1282    }
1283
1284    pub(crate) fn is_sized_bound(&self, cx: &DocContext<'_>) -> bool {
1285        self.is_bounded_by_lang_item(cx, LangItem::Sized)
1286    }
1287
1288    pub(crate) fn is_meta_sized_bound(&self, cx: &DocContext<'_>) -> bool {
1289        self.is_bounded_by_lang_item(cx, LangItem::MetaSized)
1290    }
1291
1292    fn is_bounded_by_lang_item(&self, cx: &DocContext<'_>, lang_item: LangItem) -> bool {
1293        if let GenericBound::TraitBound(
1294            PolyTrait { ref trait_, .. },
1295            rustc_hir::TraitBoundModifiers::NONE,
1296        ) = *self
1297            && cx.tcx.is_lang_item(trait_.def_id(), lang_item)
1298        {
1299            return true;
1300        }
1301        false
1302    }
1303
1304    pub(crate) fn get_trait_path(&self) -> Option<Path> {
1305        if let GenericBound::TraitBound(PolyTrait { ref trait_, .. }, _) = *self {
1306            Some(trait_.clone())
1307        } else {
1308            None
1309        }
1310    }
1311}
1312
1313#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
1314pub(crate) struct Lifetime(pub Symbol);
1315
1316impl Lifetime {
1317    pub(crate) fn statik() -> Lifetime {
1318        Lifetime(kw::StaticLifetime)
1319    }
1320
1321    pub(crate) fn elided() -> Lifetime {
1322        Lifetime(kw::UnderscoreLifetime)
1323    }
1324}
1325
1326#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
1327pub(crate) enum PreciseCapturingArg {
1328    Lifetime(Lifetime),
1329    Param(Symbol),
1330}
1331
1332impl PreciseCapturingArg {
1333    pub(crate) fn name(self) -> Symbol {
1334        match self {
1335            PreciseCapturingArg::Lifetime(lt) => lt.0,
1336            PreciseCapturingArg::Param(param) => param,
1337        }
1338    }
1339}
1340
1341#[derive(Clone, PartialEq, Eq, Hash, Debug)]
1342pub(crate) enum WherePredicate {
1343    BoundPredicate { ty: Type, bounds: Vec<GenericBound>, bound_params: Vec<GenericParamDef> },
1344    RegionPredicate { lifetime: Lifetime, bounds: Vec<GenericBound> },
1345    EqPredicate { lhs: QPathData, rhs: Term },
1346}
1347
1348impl WherePredicate {
1349    pub(crate) fn get_bounds(&self) -> Option<&[GenericBound]> {
1350        match self {
1351            WherePredicate::BoundPredicate { bounds, .. } => Some(bounds),
1352            WherePredicate::RegionPredicate { bounds, .. } => Some(bounds),
1353            _ => None,
1354        }
1355    }
1356}
1357
1358#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1359pub(crate) enum GenericParamDefKind {
1360    Lifetime { outlives: ThinVec<Lifetime> },
1361    Type { bounds: ThinVec<GenericBound>, default: Option<Box<Type>>, synthetic: bool },
1362    // Option<Box<String>> makes this type smaller than `Option<String>` would.
1363    Const { ty: Box<Type>, default: Option<Box<String>>, synthetic: bool },
1364}
1365
1366impl GenericParamDefKind {
1367    pub(crate) fn is_type(&self) -> bool {
1368        matches!(self, GenericParamDefKind::Type { .. })
1369    }
1370}
1371
1372#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1373pub(crate) struct GenericParamDef {
1374    pub(crate) name: Symbol,
1375    pub(crate) def_id: DefId,
1376    pub(crate) kind: GenericParamDefKind,
1377}
1378
1379impl GenericParamDef {
1380    pub(crate) fn lifetime(def_id: DefId, name: Symbol) -> Self {
1381        Self { name, def_id, kind: GenericParamDefKind::Lifetime { outlives: ThinVec::new() } }
1382    }
1383
1384    pub(crate) fn is_synthetic_param(&self) -> bool {
1385        match self.kind {
1386            GenericParamDefKind::Lifetime { .. } | GenericParamDefKind::Const { .. } => false,
1387            GenericParamDefKind::Type { synthetic, .. } => synthetic,
1388        }
1389    }
1390
1391    pub(crate) fn is_type(&self) -> bool {
1392        self.kind.is_type()
1393    }
1394
1395    pub(crate) fn get_bounds(&self) -> Option<&[GenericBound]> {
1396        match self.kind {
1397            GenericParamDefKind::Type { ref bounds, .. } => Some(bounds),
1398            _ => None,
1399        }
1400    }
1401}
1402
1403// maybe use a Generic enum and use Vec<Generic>?
1404#[derive(Clone, PartialEq, Eq, Hash, Debug, Default)]
1405pub(crate) struct Generics {
1406    pub(crate) params: ThinVec<GenericParamDef>,
1407    pub(crate) where_predicates: ThinVec<WherePredicate>,
1408}
1409
1410impl Generics {
1411    pub(crate) fn is_empty(&self) -> bool {
1412        self.params.is_empty() && self.where_predicates.is_empty()
1413    }
1414}
1415
1416#[derive(Clone, Debug)]
1417pub(crate) struct Function {
1418    pub(crate) decl: FnDecl,
1419    pub(crate) generics: Generics,
1420}
1421
1422#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1423pub(crate) struct FnDecl {
1424    pub(crate) inputs: Vec<Parameter>,
1425    pub(crate) output: Type,
1426    pub(crate) c_variadic: bool,
1427}
1428
1429impl FnDecl {
1430    pub(crate) fn receiver_type(&self) -> Option<&Type> {
1431        self.inputs.first().and_then(|v| v.to_receiver())
1432    }
1433}
1434
1435/// A function parameter.
1436#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1437pub(crate) struct Parameter {
1438    pub(crate) name: Option<Symbol>,
1439    pub(crate) type_: Type,
1440    /// This field is used to represent "const" arguments from the `rustc_legacy_const_generics`
1441    /// feature. More information in <https://github.com/rust-lang/rust/issues/83167>.
1442    pub(crate) is_const: bool,
1443}
1444
1445impl Parameter {
1446    pub(crate) fn to_receiver(&self) -> Option<&Type> {
1447        if self.name == Some(kw::SelfLower) { Some(&self.type_) } else { None }
1448    }
1449}
1450
1451#[derive(Clone, Debug)]
1452pub(crate) struct Trait {
1453    pub(crate) def_id: DefId,
1454    pub(crate) items: Vec<Item>,
1455    pub(crate) generics: Generics,
1456    pub(crate) bounds: Vec<GenericBound>,
1457}
1458
1459impl Trait {
1460    pub(crate) fn is_auto(&self, tcx: TyCtxt<'_>) -> bool {
1461        tcx.trait_is_auto(self.def_id)
1462    }
1463    pub(crate) fn is_notable_trait(&self, tcx: TyCtxt<'_>) -> bool {
1464        tcx.is_doc_notable_trait(self.def_id)
1465    }
1466    pub(crate) fn safety(&self, tcx: TyCtxt<'_>) -> hir::Safety {
1467        tcx.trait_def(self.def_id).safety
1468    }
1469    pub(crate) fn is_dyn_compatible(&self, tcx: TyCtxt<'_>) -> bool {
1470        tcx.is_dyn_compatible(self.def_id)
1471    }
1472}
1473
1474#[derive(Clone, Debug)]
1475pub(crate) struct TraitAlias {
1476    pub(crate) generics: Generics,
1477    pub(crate) bounds: Vec<GenericBound>,
1478}
1479
1480/// A trait reference, which may have higher ranked lifetimes.
1481#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1482pub(crate) struct PolyTrait {
1483    pub(crate) trait_: Path,
1484    pub(crate) generic_params: Vec<GenericParamDef>,
1485}
1486
1487/// Rustdoc's representation of types, mostly based on the [`hir::Ty`].
1488#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1489pub(crate) enum Type {
1490    /// A named type, which could be a trait.
1491    ///
1492    /// This is mostly Rustdoc's version of [`hir::Path`].
1493    /// It has to be different because Rustdoc's [`PathSegment`] can contain cleaned generics.
1494    Path {
1495        path: Path,
1496    },
1497    /// A `dyn Trait` object: `dyn for<'a> Trait<'a> + Send + 'static`
1498    DynTrait(Vec<PolyTrait>, Option<Lifetime>),
1499    /// A type parameter.
1500    Generic(Symbol),
1501    /// The `Self` type.
1502    SelfTy,
1503    /// A primitive (aka, builtin) type.
1504    Primitive(PrimitiveType),
1505    /// A function pointer: `extern "ABI" fn(...) -> ...`
1506    BareFunction(Box<BareFunctionDecl>),
1507    /// A tuple type: `(i32, &str)`.
1508    Tuple(Vec<Type>),
1509    /// A slice type (does *not* include the `&`): `[i32]`
1510    Slice(Box<Type>),
1511    /// An array type.
1512    ///
1513    /// The `String` field is a stringified version of the array's length parameter.
1514    Array(Box<Type>, Box<str>),
1515    Pat(Box<Type>, Box<str>),
1516    /// A raw pointer type: `*const i32`, `*mut i32`
1517    RawPointer(Mutability, Box<Type>),
1518    /// A reference type: `&i32`, `&'a mut Foo`
1519    BorrowedRef {
1520        lifetime: Option<Lifetime>,
1521        mutability: Mutability,
1522        type_: Box<Type>,
1523    },
1524
1525    /// A qualified path to an associated item: `<Type as Trait>::Name`
1526    QPath(Box<QPathData>),
1527
1528    /// A type that is inferred: `_`
1529    Infer,
1530
1531    /// An `impl Trait`: `impl TraitA + TraitB + ...`
1532    ImplTrait(Vec<GenericBound>),
1533
1534    UnsafeBinder(Box<UnsafeBinderTy>),
1535}
1536
1537impl Type {
1538    /// When comparing types for equality, it can help to ignore `&` wrapping.
1539    pub(crate) fn without_borrowed_ref(&self) -> &Type {
1540        let mut result = self;
1541        while let Type::BorrowedRef { type_, .. } = result {
1542            result = type_;
1543        }
1544        result
1545    }
1546
1547    pub(crate) fn is_borrowed_ref(&self) -> bool {
1548        matches!(self, Type::BorrowedRef { .. })
1549    }
1550
1551    fn is_type_alias(&self) -> bool {
1552        matches!(self, Type::Path { path: Path { res: Res::Def(DefKind::TyAlias, _), .. } })
1553    }
1554
1555    /// Check if two types are "the same" for documentation purposes.
1556    ///
1557    /// This is different from `Eq`, because it knows that things like
1558    /// `Placeholder` are possible matches for everything.
1559    ///
1560    /// This relation is not commutative when generics are involved:
1561    ///
1562    /// ```ignore(private)
1563    /// # // see types/tests.rs:is_same_generic for the real test
1564    /// use rustdoc::format::cache::Cache;
1565    /// use rustdoc::clean::types::{Type, PrimitiveType};
1566    /// let cache = Cache::new(false);
1567    /// let generic = Type::Generic(rustc_span::symbol::sym::Any);
1568    /// let unit = Type::Primitive(PrimitiveType::Unit);
1569    /// assert!(!generic.is_same(&unit, &cache));
1570    /// assert!(unit.is_same(&generic, &cache));
1571    /// ```
1572    ///
1573    /// An owned type is also the same as its borrowed variants (this is commutative),
1574    /// but `&T` is not the same as `&mut T`.
1575    pub(crate) fn is_doc_subtype_of(&self, other: &Self, cache: &Cache) -> bool {
1576        // Strip the references so that it can compare the actual types, unless both are references.
1577        // If both are references, leave them alone and compare the mutabilities later.
1578        let (self_cleared, other_cleared) = if !self.is_borrowed_ref() || !other.is_borrowed_ref() {
1579            (self.without_borrowed_ref(), other.without_borrowed_ref())
1580        } else {
1581            (self, other)
1582        };
1583
1584        // FIXME: `Cache` does not have the data required to unwrap type aliases,
1585        // so we just assume they are equal.
1586        // This is only remotely acceptable because we were previously
1587        // assuming all types were equal when used
1588        // as a generic parameter of a type in `Deref::Target`.
1589        if self_cleared.is_type_alias() || other_cleared.is_type_alias() {
1590            return true;
1591        }
1592
1593        match (self_cleared, other_cleared) {
1594            // Recursive cases.
1595            (Type::Tuple(a), Type::Tuple(b)) => {
1596                a.len() == b.len() && a.iter().zip(b).all(|(a, b)| a.is_doc_subtype_of(b, cache))
1597            }
1598            (Type::Slice(a), Type::Slice(b)) => a.is_doc_subtype_of(b, cache),
1599            (Type::Array(a, al), Type::Array(b, bl)) => al == bl && a.is_doc_subtype_of(b, cache),
1600            (Type::RawPointer(mutability, type_), Type::RawPointer(b_mutability, b_type_)) => {
1601                mutability == b_mutability && type_.is_doc_subtype_of(b_type_, cache)
1602            }
1603            (
1604                Type::BorrowedRef { mutability, type_, .. },
1605                Type::BorrowedRef { mutability: b_mutability, type_: b_type_, .. },
1606            ) => mutability == b_mutability && type_.is_doc_subtype_of(b_type_, cache),
1607            // Placeholders are equal to all other types.
1608            (Type::Infer, _) | (_, Type::Infer) => true,
1609            // Generics match everything on the right, but not on the left.
1610            // If both sides are generic, this returns true.
1611            (_, Type::Generic(_)) => true,
1612            (Type::Generic(_), _) => false,
1613            // `Self` only matches itself.
1614            (Type::SelfTy, Type::SelfTy) => true,
1615            // Paths account for both the path itself and its generics.
1616            (Type::Path { path: a }, Type::Path { path: b }) => {
1617                a.def_id() == b.def_id()
1618                    && a.generics()
1619                        .zip(b.generics())
1620                        .map(|(ag, bg)| ag.zip(bg).all(|(at, bt)| at.is_doc_subtype_of(bt, cache)))
1621                        .unwrap_or(true)
1622            }
1623            // Other cases, such as primitives, just use recursion.
1624            (a, b) => a
1625                .def_id(cache)
1626                .and_then(|a| Some((a, b.def_id(cache)?)))
1627                .map(|(a, b)| a == b)
1628                .unwrap_or(false),
1629        }
1630    }
1631
1632    pub(crate) fn primitive_type(&self) -> Option<PrimitiveType> {
1633        match *self {
1634            Primitive(p) | BorrowedRef { type_: box Primitive(p), .. } => Some(p),
1635            Slice(..) | BorrowedRef { type_: box Slice(..), .. } => Some(PrimitiveType::Slice),
1636            Array(..) | BorrowedRef { type_: box Array(..), .. } => Some(PrimitiveType::Array),
1637            Tuple(ref tys) => {
1638                if tys.is_empty() {
1639                    Some(PrimitiveType::Unit)
1640                } else {
1641                    Some(PrimitiveType::Tuple)
1642                }
1643            }
1644            RawPointer(..) => Some(PrimitiveType::RawPointer),
1645            BareFunction(..) => Some(PrimitiveType::Fn),
1646            _ => None,
1647        }
1648    }
1649
1650    /// Returns the sugared return type for an async function.
1651    ///
1652    /// For example, if the return type is `impl std::future::Future<Output = i32>`, this function
1653    /// will return `i32`.
1654    ///
1655    /// # Panics
1656    ///
1657    /// This function will panic if the return type does not match the expected sugaring for async
1658    /// functions.
1659    pub(crate) fn sugared_async_return_type(self) -> Type {
1660        if let Type::ImplTrait(mut v) = self
1661            && let Some(GenericBound::TraitBound(PolyTrait { mut trait_, .. }, _)) = v.pop()
1662            && let Some(segment) = trait_.segments.pop()
1663            && let GenericArgs::AngleBracketed { mut constraints, .. } = segment.args
1664            && let Some(constraint) = constraints.pop()
1665            && let AssocItemConstraintKind::Equality { term } = constraint.kind
1666            && let Term::Type(ty) = term
1667        {
1668            ty
1669        } else {
1670            panic!("unexpected async fn return type")
1671        }
1672    }
1673
1674    /// Checks if this is a `T::Name` path for an associated type.
1675    pub(crate) fn is_assoc_ty(&self) -> bool {
1676        match self {
1677            Type::Path { path, .. } => path.is_assoc_ty(),
1678            _ => false,
1679        }
1680    }
1681
1682    pub(crate) fn is_self_type(&self) -> bool {
1683        matches!(*self, Type::SelfTy)
1684    }
1685
1686    pub(crate) fn generic_args(&self) -> Option<&GenericArgs> {
1687        match self {
1688            Type::Path { path, .. } => path.generic_args(),
1689            _ => None,
1690        }
1691    }
1692
1693    pub(crate) fn generics(&self) -> Option<impl Iterator<Item = &Type>> {
1694        match self {
1695            Type::Path { path, .. } => path.generics(),
1696            _ => None,
1697        }
1698    }
1699
1700    pub(crate) fn is_full_generic(&self) -> bool {
1701        matches!(self, Type::Generic(_))
1702    }
1703
1704    pub(crate) fn is_unit(&self) -> bool {
1705        matches!(self, Type::Tuple(v) if v.is_empty())
1706    }
1707
1708    /// Use this method to get the [DefId] of a [clean] AST node, including [PrimitiveType]s.
1709    ///
1710    /// [clean]: crate::clean
1711    pub(crate) fn def_id(&self, cache: &Cache) -> Option<DefId> {
1712        let t: PrimitiveType = match self {
1713            Type::Path { path } => return Some(path.def_id()),
1714            DynTrait(bounds, _) => return bounds.first().map(|b| b.trait_.def_id()),
1715            Primitive(p) => return cache.primitive_locations.get(p).cloned(),
1716            BorrowedRef { type_: box Generic(..), .. } => PrimitiveType::Reference,
1717            BorrowedRef { type_, .. } => return type_.def_id(cache),
1718            Tuple(tys) => {
1719                if tys.is_empty() {
1720                    PrimitiveType::Unit
1721                } else {
1722                    PrimitiveType::Tuple
1723                }
1724            }
1725            BareFunction(..) => PrimitiveType::Fn,
1726            Slice(..) => PrimitiveType::Slice,
1727            Array(..) => PrimitiveType::Array,
1728            Type::Pat(..) => PrimitiveType::Pat,
1729            RawPointer(..) => PrimitiveType::RawPointer,
1730            QPath(box QPathData { self_type, .. }) => return self_type.def_id(cache),
1731            Generic(_) | SelfTy | Infer | ImplTrait(_) | UnsafeBinder(_) => return None,
1732        };
1733        Primitive(t).def_id(cache)
1734    }
1735}
1736
1737#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1738pub(crate) struct QPathData {
1739    pub assoc: PathSegment,
1740    pub self_type: Type,
1741    /// FIXME: compute this field on demand.
1742    pub should_fully_qualify: bool,
1743    pub trait_: Option<Path>,
1744}
1745
1746/// A primitive (aka, builtin) type.
1747///
1748/// This represents things like `i32`, `str`, etc.
1749///
1750/// N.B. This has to be different from [`hir::PrimTy`] because it also includes types that aren't
1751/// paths, like [`Self::Unit`].
1752#[derive(Clone, PartialEq, Eq, Hash, Copy, Debug)]
1753pub(crate) enum PrimitiveType {
1754    Isize,
1755    I8,
1756    I16,
1757    I32,
1758    I64,
1759    I128,
1760    Usize,
1761    U8,
1762    U16,
1763    U32,
1764    U64,
1765    U128,
1766    F16,
1767    F32,
1768    F64,
1769    F128,
1770    Char,
1771    Bool,
1772    Str,
1773    Slice,
1774    Array,
1775    Pat,
1776    Tuple,
1777    Unit,
1778    RawPointer,
1779    Reference,
1780    Fn,
1781    Never,
1782}
1783
1784type SimplifiedTypes = FxIndexMap<PrimitiveType, ArrayVec<SimplifiedType, 3>>;
1785impl PrimitiveType {
1786    pub(crate) fn from_hir(prim: hir::PrimTy) -> PrimitiveType {
1787        use ast::{FloatTy, IntTy, UintTy};
1788        match prim {
1789            hir::PrimTy::Int(IntTy::Isize) => PrimitiveType::Isize,
1790            hir::PrimTy::Int(IntTy::I8) => PrimitiveType::I8,
1791            hir::PrimTy::Int(IntTy::I16) => PrimitiveType::I16,
1792            hir::PrimTy::Int(IntTy::I32) => PrimitiveType::I32,
1793            hir::PrimTy::Int(IntTy::I64) => PrimitiveType::I64,
1794            hir::PrimTy::Int(IntTy::I128) => PrimitiveType::I128,
1795            hir::PrimTy::Uint(UintTy::Usize) => PrimitiveType::Usize,
1796            hir::PrimTy::Uint(UintTy::U8) => PrimitiveType::U8,
1797            hir::PrimTy::Uint(UintTy::U16) => PrimitiveType::U16,
1798            hir::PrimTy::Uint(UintTy::U32) => PrimitiveType::U32,
1799            hir::PrimTy::Uint(UintTy::U64) => PrimitiveType::U64,
1800            hir::PrimTy::Uint(UintTy::U128) => PrimitiveType::U128,
1801            hir::PrimTy::Float(FloatTy::F16) => PrimitiveType::F16,
1802            hir::PrimTy::Float(FloatTy::F32) => PrimitiveType::F32,
1803            hir::PrimTy::Float(FloatTy::F64) => PrimitiveType::F64,
1804            hir::PrimTy::Float(FloatTy::F128) => PrimitiveType::F128,
1805            hir::PrimTy::Str => PrimitiveType::Str,
1806            hir::PrimTy::Bool => PrimitiveType::Bool,
1807            hir::PrimTy::Char => PrimitiveType::Char,
1808        }
1809    }
1810
1811    pub(crate) fn from_symbol(s: Symbol) -> Option<PrimitiveType> {
1812        match s {
1813            sym::isize => Some(PrimitiveType::Isize),
1814            sym::i8 => Some(PrimitiveType::I8),
1815            sym::i16 => Some(PrimitiveType::I16),
1816            sym::i32 => Some(PrimitiveType::I32),
1817            sym::i64 => Some(PrimitiveType::I64),
1818            sym::i128 => Some(PrimitiveType::I128),
1819            sym::usize => Some(PrimitiveType::Usize),
1820            sym::u8 => Some(PrimitiveType::U8),
1821            sym::u16 => Some(PrimitiveType::U16),
1822            sym::u32 => Some(PrimitiveType::U32),
1823            sym::u64 => Some(PrimitiveType::U64),
1824            sym::u128 => Some(PrimitiveType::U128),
1825            sym::bool => Some(PrimitiveType::Bool),
1826            sym::char => Some(PrimitiveType::Char),
1827            sym::str => Some(PrimitiveType::Str),
1828            sym::f16 => Some(PrimitiveType::F16),
1829            sym::f32 => Some(PrimitiveType::F32),
1830            sym::f64 => Some(PrimitiveType::F64),
1831            sym::f128 => Some(PrimitiveType::F128),
1832            sym::array => Some(PrimitiveType::Array),
1833            sym::slice => Some(PrimitiveType::Slice),
1834            sym::tuple => Some(PrimitiveType::Tuple),
1835            sym::unit => Some(PrimitiveType::Unit),
1836            sym::pointer => Some(PrimitiveType::RawPointer),
1837            sym::reference => Some(PrimitiveType::Reference),
1838            kw::Fn => Some(PrimitiveType::Fn),
1839            sym::never => Some(PrimitiveType::Never),
1840            _ => None,
1841        }
1842    }
1843
1844    pub(crate) fn simplified_types() -> &'static SimplifiedTypes {
1845        use PrimitiveType::*;
1846        use ty::{FloatTy, IntTy, UintTy};
1847        static CELL: OnceCell<SimplifiedTypes> = OnceCell::new();
1848
1849        let single = |x| iter::once(x).collect();
1850        CELL.get_or_init(move || {
1851            map! {
1852                Isize => single(SimplifiedType::Int(IntTy::Isize)),
1853                I8 => single(SimplifiedType::Int(IntTy::I8)),
1854                I16 => single(SimplifiedType::Int(IntTy::I16)),
1855                I32 => single(SimplifiedType::Int(IntTy::I32)),
1856                I64 => single(SimplifiedType::Int(IntTy::I64)),
1857                I128 => single(SimplifiedType::Int(IntTy::I128)),
1858                Usize => single(SimplifiedType::Uint(UintTy::Usize)),
1859                U8 => single(SimplifiedType::Uint(UintTy::U8)),
1860                U16 => single(SimplifiedType::Uint(UintTy::U16)),
1861                U32 => single(SimplifiedType::Uint(UintTy::U32)),
1862                U64 => single(SimplifiedType::Uint(UintTy::U64)),
1863                U128 => single(SimplifiedType::Uint(UintTy::U128)),
1864                F16 => single(SimplifiedType::Float(FloatTy::F16)),
1865                F32 => single(SimplifiedType::Float(FloatTy::F32)),
1866                F64 => single(SimplifiedType::Float(FloatTy::F64)),
1867                F128 => single(SimplifiedType::Float(FloatTy::F128)),
1868                Str => single(SimplifiedType::Str),
1869                Bool => single(SimplifiedType::Bool),
1870                Char => single(SimplifiedType::Char),
1871                Array => single(SimplifiedType::Array),
1872                Slice => single(SimplifiedType::Slice),
1873                // FIXME: If we ever add an inherent impl for tuples
1874                // with different lengths, they won't show in rustdoc.
1875                //
1876                // Either manually update this arrayvec at this point
1877                // or start with a more complex refactoring.
1878                Tuple => [SimplifiedType::Tuple(1), SimplifiedType::Tuple(2), SimplifiedType::Tuple(3)].into(),
1879                Unit => single(SimplifiedType::Tuple(0)),
1880                RawPointer => [SimplifiedType::Ptr(Mutability::Not), SimplifiedType::Ptr(Mutability::Mut)].into_iter().collect(),
1881                Reference => [SimplifiedType::Ref(Mutability::Not), SimplifiedType::Ref(Mutability::Mut)].into_iter().collect(),
1882                // FIXME: This will be wrong if we ever add inherent impls
1883                // for function pointers.
1884                Fn => single(SimplifiedType::Function(1)),
1885                Never => single(SimplifiedType::Never),
1886            }
1887        })
1888    }
1889
1890    pub(crate) fn impls<'tcx>(&self, tcx: TyCtxt<'tcx>) -> impl Iterator<Item = DefId> + 'tcx {
1891        Self::simplified_types()
1892            .get(self)
1893            .into_iter()
1894            .flatten()
1895            .flat_map(move |&simp| tcx.incoherent_impls(simp).iter())
1896            .copied()
1897    }
1898
1899    pub(crate) fn all_impls(tcx: TyCtxt<'_>) -> impl Iterator<Item = DefId> {
1900        Self::simplified_types()
1901            .values()
1902            .flatten()
1903            .flat_map(move |&simp| tcx.incoherent_impls(simp).iter())
1904            .copied()
1905    }
1906
1907    pub(crate) fn as_sym(&self) -> Symbol {
1908        use PrimitiveType::*;
1909        match self {
1910            Isize => sym::isize,
1911            I8 => sym::i8,
1912            I16 => sym::i16,
1913            I32 => sym::i32,
1914            I64 => sym::i64,
1915            I128 => sym::i128,
1916            Usize => sym::usize,
1917            U8 => sym::u8,
1918            U16 => sym::u16,
1919            U32 => sym::u32,
1920            U64 => sym::u64,
1921            U128 => sym::u128,
1922            F16 => sym::f16,
1923            F32 => sym::f32,
1924            F64 => sym::f64,
1925            F128 => sym::f128,
1926            Str => sym::str,
1927            Bool => sym::bool,
1928            Char => sym::char,
1929            Array => sym::array,
1930            Pat => sym::pat,
1931            Slice => sym::slice,
1932            Tuple => sym::tuple,
1933            Unit => sym::unit,
1934            RawPointer => sym::pointer,
1935            Reference => sym::reference,
1936            Fn => kw::Fn,
1937            Never => sym::never,
1938        }
1939    }
1940
1941    /// Returns the DefId of the module with `rustc_doc_primitive` for this primitive type.
1942    /// Panics if there is no such module.
1943    ///
1944    /// This gives precedence to primitives defined in the current crate, and deprioritizes
1945    /// primitives defined in `core`,
1946    /// but otherwise, if multiple crates define the same primitive, there is no guarantee of which
1947    /// will be picked.
1948    ///
1949    /// In particular, if a crate depends on both `std` and another crate that also defines
1950    /// `rustc_doc_primitive`, then it's entirely random whether `std` or the other crate is picked.
1951    /// (no_std crates are usually fine unless multiple dependencies define a primitive.)
1952    pub(crate) fn primitive_locations(tcx: TyCtxt<'_>) -> &FxIndexMap<PrimitiveType, DefId> {
1953        static PRIMITIVE_LOCATIONS: OnceCell<FxIndexMap<PrimitiveType, DefId>> = OnceCell::new();
1954        PRIMITIVE_LOCATIONS.get_or_init(|| {
1955            let mut primitive_locations = FxIndexMap::default();
1956            // NOTE: technically this misses crates that are only passed with `--extern` and not loaded when checking the crate.
1957            // This is a degenerate case that I don't plan to support.
1958            for &crate_num in tcx.crates(()) {
1959                let e = ExternalCrate { crate_num };
1960                let crate_name = e.name(tcx);
1961                debug!(?crate_num, ?crate_name);
1962                for (def_id, prim) in e.primitives(tcx) {
1963                    // HACK: try to link to std instead where possible
1964                    if crate_name == sym::core && primitive_locations.contains_key(&prim) {
1965                        continue;
1966                    }
1967                    primitive_locations.insert(prim, def_id);
1968                }
1969            }
1970            let local_primitives = ExternalCrate { crate_num: LOCAL_CRATE }.primitives(tcx);
1971            for (def_id, prim) in local_primitives {
1972                primitive_locations.insert(prim, def_id);
1973            }
1974            primitive_locations
1975        })
1976    }
1977}
1978
1979impl From<ty::IntTy> for PrimitiveType {
1980    fn from(int_ty: ty::IntTy) -> PrimitiveType {
1981        match int_ty {
1982            ty::IntTy::Isize => PrimitiveType::Isize,
1983            ty::IntTy::I8 => PrimitiveType::I8,
1984            ty::IntTy::I16 => PrimitiveType::I16,
1985            ty::IntTy::I32 => PrimitiveType::I32,
1986            ty::IntTy::I64 => PrimitiveType::I64,
1987            ty::IntTy::I128 => PrimitiveType::I128,
1988        }
1989    }
1990}
1991
1992impl From<ty::UintTy> for PrimitiveType {
1993    fn from(uint_ty: ty::UintTy) -> PrimitiveType {
1994        match uint_ty {
1995            ty::UintTy::Usize => PrimitiveType::Usize,
1996            ty::UintTy::U8 => PrimitiveType::U8,
1997            ty::UintTy::U16 => PrimitiveType::U16,
1998            ty::UintTy::U32 => PrimitiveType::U32,
1999            ty::UintTy::U64 => PrimitiveType::U64,
2000            ty::UintTy::U128 => PrimitiveType::U128,
2001        }
2002    }
2003}
2004
2005impl From<ty::FloatTy> for PrimitiveType {
2006    fn from(float_ty: ty::FloatTy) -> PrimitiveType {
2007        match float_ty {
2008            ty::FloatTy::F16 => PrimitiveType::F16,
2009            ty::FloatTy::F32 => PrimitiveType::F32,
2010            ty::FloatTy::F64 => PrimitiveType::F64,
2011            ty::FloatTy::F128 => PrimitiveType::F128,
2012        }
2013    }
2014}
2015
2016impl From<hir::PrimTy> for PrimitiveType {
2017    fn from(prim_ty: hir::PrimTy) -> PrimitiveType {
2018        match prim_ty {
2019            hir::PrimTy::Int(int_ty) => int_ty.into(),
2020            hir::PrimTy::Uint(uint_ty) => uint_ty.into(),
2021            hir::PrimTy::Float(float_ty) => float_ty.into(),
2022            hir::PrimTy::Str => PrimitiveType::Str,
2023            hir::PrimTy::Bool => PrimitiveType::Bool,
2024            hir::PrimTy::Char => PrimitiveType::Char,
2025        }
2026    }
2027}
2028
2029#[derive(Clone, Debug)]
2030pub(crate) struct Struct {
2031    pub(crate) ctor_kind: Option<CtorKind>,
2032    pub(crate) generics: Generics,
2033    pub(crate) fields: ThinVec<Item>,
2034}
2035
2036impl Struct {
2037    pub(crate) fn has_stripped_entries(&self) -> bool {
2038        self.fields.iter().any(|f| f.is_stripped())
2039    }
2040}
2041
2042#[derive(Clone, Debug)]
2043pub(crate) struct Union {
2044    pub(crate) generics: Generics,
2045    pub(crate) fields: Vec<Item>,
2046}
2047
2048impl Union {
2049    pub(crate) fn has_stripped_entries(&self) -> bool {
2050        self.fields.iter().any(|f| f.is_stripped())
2051    }
2052}
2053
2054/// This is a more limited form of the standard Struct, different in that
2055/// it lacks the things most items have (name, id, parameterization). Found
2056/// only as a variant in an enum.
2057#[derive(Clone, Debug)]
2058pub(crate) struct VariantStruct {
2059    pub(crate) fields: ThinVec<Item>,
2060}
2061
2062impl VariantStruct {
2063    pub(crate) fn has_stripped_entries(&self) -> bool {
2064        self.fields.iter().any(|f| f.is_stripped())
2065    }
2066}
2067
2068#[derive(Clone, Debug)]
2069pub(crate) struct Enum {
2070    pub(crate) variants: IndexVec<VariantIdx, Item>,
2071    pub(crate) generics: Generics,
2072}
2073
2074impl Enum {
2075    pub(crate) fn has_stripped_entries(&self) -> bool {
2076        self.variants.iter().any(|f| f.is_stripped())
2077    }
2078
2079    pub(crate) fn non_stripped_variants(&self) -> impl Iterator<Item = &Item> {
2080        self.variants.iter().filter(|v| !v.is_stripped())
2081    }
2082}
2083
2084#[derive(Clone, Debug)]
2085pub(crate) struct Variant {
2086    pub kind: VariantKind,
2087    pub discriminant: Option<Discriminant>,
2088}
2089
2090#[derive(Clone, Debug)]
2091pub(crate) enum VariantKind {
2092    CLike,
2093    Tuple(ThinVec<Item>),
2094    Struct(VariantStruct),
2095}
2096
2097impl Variant {
2098    pub(crate) fn has_stripped_entries(&self) -> Option<bool> {
2099        match &self.kind {
2100            VariantKind::Struct(struct_) => Some(struct_.has_stripped_entries()),
2101            VariantKind::CLike | VariantKind::Tuple(_) => None,
2102        }
2103    }
2104}
2105
2106#[derive(Clone, Debug)]
2107pub(crate) struct Discriminant {
2108    // In the case of cross crate re-exports, we don't have the necessary information
2109    // to reconstruct the expression of the discriminant, only the value.
2110    pub(super) expr: Option<BodyId>,
2111    pub(super) value: DefId,
2112}
2113
2114impl Discriminant {
2115    /// Will be `None` in the case of cross-crate reexports, and may be
2116    /// simplified
2117    pub(crate) fn expr(&self, tcx: TyCtxt<'_>) -> Option<String> {
2118        self.expr
2119            .map(|body| rendered_const(tcx, tcx.hir_body(body), tcx.hir_body_owner_def_id(body)))
2120    }
2121    pub(crate) fn value(&self, tcx: TyCtxt<'_>, with_underscores: bool) -> String {
2122        print_evaluated_const(tcx, self.value, with_underscores, false).unwrap()
2123    }
2124}
2125
2126/// Small wrapper around [`rustc_span::Span`] that adds helper methods
2127/// and enforces calling [`rustc_span::Span::source_callsite()`].
2128#[derive(Copy, Clone, Debug)]
2129pub(crate) struct Span(rustc_span::Span);
2130
2131impl Span {
2132    /// Wraps a [`rustc_span::Span`]. In case this span is the result of a macro expansion, the
2133    /// span will be updated to point to the macro invocation instead of the macro definition.
2134    ///
2135    /// (See rust-lang/rust#39726)
2136    pub(crate) fn new(sp: rustc_span::Span) -> Self {
2137        Self(sp.source_callsite())
2138    }
2139
2140    pub(crate) fn inner(&self) -> rustc_span::Span {
2141        self.0
2142    }
2143
2144    pub(crate) fn filename(&self, sess: &Session) -> FileName {
2145        sess.source_map().span_to_filename(self.0)
2146    }
2147
2148    pub(crate) fn lo(&self, sess: &Session) -> Loc {
2149        sess.source_map().lookup_char_pos(self.0.lo())
2150    }
2151
2152    pub(crate) fn hi(&self, sess: &Session) -> Loc {
2153        sess.source_map().lookup_char_pos(self.0.hi())
2154    }
2155
2156    pub(crate) fn cnum(&self, sess: &Session) -> CrateNum {
2157        // FIXME: is there a time when the lo and hi crate would be different?
2158        self.lo(sess).file.cnum
2159    }
2160}
2161
2162#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2163pub(crate) struct Path {
2164    pub(crate) res: Res,
2165    pub(crate) segments: ThinVec<PathSegment>,
2166}
2167
2168impl Path {
2169    pub(crate) fn def_id(&self) -> DefId {
2170        self.res.def_id()
2171    }
2172
2173    pub(crate) fn last_opt(&self) -> Option<Symbol> {
2174        self.segments.last().map(|s| s.name)
2175    }
2176
2177    pub(crate) fn last(&self) -> Symbol {
2178        self.last_opt().expect("segments were empty")
2179    }
2180
2181    pub(crate) fn whole_name(&self) -> String {
2182        self.segments
2183            .iter()
2184            .map(|s| if s.name == kw::PathRoot { "" } else { s.name.as_str() })
2185            .intersperse("::")
2186            .collect()
2187    }
2188
2189    /// Checks if this is a `T::Name` path for an associated type.
2190    pub(crate) fn is_assoc_ty(&self) -> bool {
2191        match self.res {
2192            Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } | Res::Def(DefKind::TyParam, _)
2193                if self.segments.len() != 1 =>
2194            {
2195                true
2196            }
2197            Res::Def(DefKind::AssocTy, _) => true,
2198            _ => false,
2199        }
2200    }
2201
2202    pub(crate) fn generic_args(&self) -> Option<&GenericArgs> {
2203        self.segments.last().map(|seg| &seg.args)
2204    }
2205
2206    pub(crate) fn generics(&self) -> Option<impl Iterator<Item = &Type>> {
2207        self.segments.last().and_then(|seg| {
2208            if let GenericArgs::AngleBracketed { ref args, .. } = seg.args {
2209                Some(args.iter().filter_map(|arg| match arg {
2210                    GenericArg::Type(ty) => Some(ty),
2211                    _ => None,
2212                }))
2213            } else {
2214                None
2215            }
2216        })
2217    }
2218}
2219
2220#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2221pub(crate) enum GenericArg {
2222    Lifetime(Lifetime),
2223    Type(Type),
2224    Const(Box<ConstantKind>),
2225    Infer,
2226}
2227
2228impl GenericArg {
2229    pub(crate) fn as_lt(&self) -> Option<&Lifetime> {
2230        if let Self::Lifetime(lt) = self { Some(lt) } else { None }
2231    }
2232
2233    pub(crate) fn as_ty(&self) -> Option<&Type> {
2234        if let Self::Type(ty) = self { Some(ty) } else { None }
2235    }
2236}
2237
2238#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2239pub(crate) enum GenericArgs {
2240    /// `<args, constraints = ..>`
2241    AngleBracketed { args: ThinVec<GenericArg>, constraints: ThinVec<AssocItemConstraint> },
2242    /// `(inputs) -> output`
2243    Parenthesized { inputs: ThinVec<Type>, output: Option<Box<Type>> },
2244    /// `(..)`
2245    ReturnTypeNotation,
2246}
2247
2248impl GenericArgs {
2249    pub(crate) fn is_empty(&self) -> bool {
2250        match self {
2251            GenericArgs::AngleBracketed { args, constraints } => {
2252                args.is_empty() && constraints.is_empty()
2253            }
2254            GenericArgs::Parenthesized { inputs, output } => inputs.is_empty() && output.is_none(),
2255            GenericArgs::ReturnTypeNotation => false,
2256        }
2257    }
2258    pub(crate) fn constraints(&self) -> Box<dyn Iterator<Item = AssocItemConstraint> + '_> {
2259        match self {
2260            GenericArgs::AngleBracketed { constraints, .. } => {
2261                Box::new(constraints.iter().cloned())
2262            }
2263            GenericArgs::Parenthesized { output, .. } => Box::new(
2264                output
2265                    .as_ref()
2266                    .map(|ty| AssocItemConstraint {
2267                        assoc: PathSegment {
2268                            name: sym::Output,
2269                            args: GenericArgs::AngleBracketed {
2270                                args: ThinVec::new(),
2271                                constraints: ThinVec::new(),
2272                            },
2273                        },
2274                        kind: AssocItemConstraintKind::Equality {
2275                            term: Term::Type((**ty).clone()),
2276                        },
2277                    })
2278                    .into_iter(),
2279            ),
2280            GenericArgs::ReturnTypeNotation => Box::new([].into_iter()),
2281        }
2282    }
2283}
2284
2285impl<'a> IntoIterator for &'a GenericArgs {
2286    type IntoIter = Box<dyn Iterator<Item = GenericArg> + 'a>;
2287    type Item = GenericArg;
2288    fn into_iter(self) -> Self::IntoIter {
2289        match self {
2290            GenericArgs::AngleBracketed { args, .. } => Box::new(args.iter().cloned()),
2291            GenericArgs::Parenthesized { inputs, .. } => {
2292                // FIXME: This isn't really right, since `Fn(A, B)` is `Fn<(A, B)>`
2293                Box::new(inputs.iter().cloned().map(GenericArg::Type))
2294            }
2295            GenericArgs::ReturnTypeNotation => Box::new([].into_iter()),
2296        }
2297    }
2298}
2299
2300#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2301pub(crate) struct PathSegment {
2302    pub(crate) name: Symbol,
2303    pub(crate) args: GenericArgs,
2304}
2305
2306#[derive(Clone, Debug)]
2307pub(crate) enum TypeAliasInnerType {
2308    Enum { variants: IndexVec<VariantIdx, Item>, is_non_exhaustive: bool },
2309    Union { fields: Vec<Item> },
2310    Struct { ctor_kind: Option<CtorKind>, fields: Vec<Item> },
2311}
2312
2313impl TypeAliasInnerType {
2314    fn has_stripped_entries(&self) -> Option<bool> {
2315        Some(match self {
2316            Self::Enum { variants, .. } => variants.iter().any(|v| v.is_stripped()),
2317            Self::Union { fields } | Self::Struct { fields, .. } => {
2318                fields.iter().any(|f| f.is_stripped())
2319            }
2320        })
2321    }
2322}
2323
2324#[derive(Clone, Debug)]
2325pub(crate) struct TypeAlias {
2326    pub(crate) type_: Type,
2327    pub(crate) generics: Generics,
2328    /// Inner `AdtDef` type, ie `type TyKind = IrTyKind<Adt, Ty>`,
2329    /// to be shown directly on the typedef page.
2330    pub(crate) inner_type: Option<TypeAliasInnerType>,
2331    /// `type_` can come from either the HIR or from metadata. If it comes from HIR, it may be a type
2332    /// alias instead of the final type. This will always have the final type, regardless of whether
2333    /// `type_` came from HIR or from metadata.
2334    ///
2335    /// If `item_type.is_none()`, `type_` is guaranteed to come from metadata (and therefore hold the
2336    /// final type).
2337    pub(crate) item_type: Option<Type>,
2338}
2339
2340#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2341pub(crate) struct BareFunctionDecl {
2342    pub(crate) safety: hir::Safety,
2343    pub(crate) generic_params: Vec<GenericParamDef>,
2344    pub(crate) decl: FnDecl,
2345    pub(crate) abi: ExternAbi,
2346}
2347
2348#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2349pub(crate) struct UnsafeBinderTy {
2350    pub(crate) generic_params: Vec<GenericParamDef>,
2351    pub(crate) ty: Type,
2352}
2353
2354#[derive(Clone, Debug)]
2355pub(crate) struct Static {
2356    pub(crate) type_: Box<Type>,
2357    pub(crate) mutability: Mutability,
2358    pub(crate) expr: Option<BodyId>,
2359}
2360
2361#[derive(Clone, PartialEq, Eq, Hash, Debug)]
2362pub(crate) struct Constant {
2363    pub(crate) generics: Generics,
2364    pub(crate) kind: ConstantKind,
2365    pub(crate) type_: Type,
2366}
2367
2368#[derive(Clone, PartialEq, Eq, Hash, Debug)]
2369pub(crate) enum Term {
2370    Type(Type),
2371    Constant(ConstantKind),
2372}
2373
2374impl Term {
2375    pub(crate) fn ty(&self) -> Option<&Type> {
2376        if let Term::Type(ty) = self { Some(ty) } else { None }
2377    }
2378}
2379
2380impl From<Type> for Term {
2381    fn from(ty: Type) -> Self {
2382        Term::Type(ty)
2383    }
2384}
2385
2386#[derive(Clone, PartialEq, Eq, Hash, Debug)]
2387pub(crate) enum ConstantKind {
2388    /// This is the wrapper around `ty::Const` for a non-local constant. Because it doesn't have a
2389    /// `BodyId`, we need to handle it on its own.
2390    ///
2391    /// Note that `ty::Const` includes generic parameters, and may not always be uniquely identified
2392    /// by a DefId. So this field must be different from `Extern`.
2393    TyConst { expr: Box<str> },
2394    /// A constant that is just a path (i.e., referring to a const param, free const, etc.).
2395    // FIXME: this is an unfortunate representation. rustdoc's logic around consts needs to be improved.
2396    Path { path: Box<str> },
2397    /// A constant (expression) that's not an item or associated item. These are usually found
2398    /// nested inside types (e.g., array lengths) or expressions (e.g., repeat counts), and also
2399    /// used to define explicit discriminant values for enum variants.
2400    Anonymous { body: BodyId },
2401    /// A constant from a different crate.
2402    Extern { def_id: DefId },
2403    /// `const FOO: u32 = ...;`
2404    Local { def_id: DefId, body: BodyId },
2405    /// An inferred constant as in `[10u8; _]`.
2406    Infer,
2407}
2408
2409impl ConstantKind {
2410    pub(crate) fn expr(&self, tcx: TyCtxt<'_>) -> String {
2411        match *self {
2412            ConstantKind::TyConst { ref expr } => expr.to_string(),
2413            ConstantKind::Path { ref path } => path.to_string(),
2414            ConstantKind::Extern { def_id } => print_inlined_const(tcx, def_id),
2415            ConstantKind::Local { body, .. } | ConstantKind::Anonymous { body } => {
2416                rendered_const(tcx, tcx.hir_body(body), tcx.hir_body_owner_def_id(body))
2417            }
2418            ConstantKind::Infer => "_".to_string(),
2419        }
2420    }
2421
2422    pub(crate) fn value(&self, tcx: TyCtxt<'_>) -> Option<String> {
2423        match *self {
2424            ConstantKind::TyConst { .. }
2425            | ConstantKind::Path { .. }
2426            | ConstantKind::Anonymous { .. }
2427            | ConstantKind::Infer => None,
2428            ConstantKind::Extern { def_id } | ConstantKind::Local { def_id, .. } => {
2429                print_evaluated_const(tcx, def_id, true, true)
2430            }
2431        }
2432    }
2433
2434    pub(crate) fn is_literal(&self, tcx: TyCtxt<'_>) -> bool {
2435        match *self {
2436            ConstantKind::TyConst { .. }
2437            | ConstantKind::Extern { .. }
2438            | ConstantKind::Path { .. }
2439            | ConstantKind::Infer => false,
2440            ConstantKind::Local { body, .. } | ConstantKind::Anonymous { body } => {
2441                is_literal_expr(tcx, body.hir_id)
2442            }
2443        }
2444    }
2445}
2446
2447#[derive(Clone, Debug)]
2448pub(crate) struct Impl {
2449    pub(crate) safety: hir::Safety,
2450    pub(crate) generics: Generics,
2451    pub(crate) trait_: Option<Path>,
2452    pub(crate) for_: Type,
2453    pub(crate) items: Vec<Item>,
2454    pub(crate) polarity: ty::ImplPolarity,
2455    pub(crate) kind: ImplKind,
2456}
2457
2458impl Impl {
2459    pub(crate) fn provided_trait_methods(&self, tcx: TyCtxt<'_>) -> FxIndexSet<Symbol> {
2460        self.trait_
2461            .as_ref()
2462            .map(|t| t.def_id())
2463            .map(|did| tcx.provided_trait_methods(did).map(|meth| meth.name()).collect())
2464            .unwrap_or_default()
2465    }
2466
2467    pub(crate) fn is_negative_trait_impl(&self) -> bool {
2468        matches!(self.polarity, ty::ImplPolarity::Negative)
2469    }
2470}
2471
2472#[derive(Clone, Debug)]
2473pub(crate) enum ImplKind {
2474    Normal,
2475    Auto,
2476    FakeVariadic,
2477    Blanket(Box<Type>),
2478}
2479
2480impl ImplKind {
2481    pub(crate) fn is_auto(&self) -> bool {
2482        matches!(self, ImplKind::Auto)
2483    }
2484
2485    pub(crate) fn is_blanket(&self) -> bool {
2486        matches!(self, ImplKind::Blanket(_))
2487    }
2488
2489    pub(crate) fn is_fake_variadic(&self) -> bool {
2490        matches!(self, ImplKind::FakeVariadic)
2491    }
2492
2493    pub(crate) fn as_blanket_ty(&self) -> Option<&Type> {
2494        match self {
2495            ImplKind::Blanket(ty) => Some(ty),
2496            _ => None,
2497        }
2498    }
2499}
2500
2501#[derive(Clone, Debug)]
2502pub(crate) struct Import {
2503    pub(crate) kind: ImportKind,
2504    /// The item being re-exported.
2505    pub(crate) source: ImportSource,
2506    pub(crate) should_be_displayed: bool,
2507}
2508
2509impl Import {
2510    pub(crate) fn new_simple(
2511        name: Symbol,
2512        source: ImportSource,
2513        should_be_displayed: bool,
2514    ) -> Self {
2515        Self { kind: ImportKind::Simple(name), source, should_be_displayed }
2516    }
2517
2518    pub(crate) fn new_glob(source: ImportSource, should_be_displayed: bool) -> Self {
2519        Self { kind: ImportKind::Glob, source, should_be_displayed }
2520    }
2521
2522    pub(crate) fn imported_item_is_doc_hidden(&self, tcx: TyCtxt<'_>) -> bool {
2523        self.source.did.is_some_and(|did| tcx.is_doc_hidden(did))
2524    }
2525}
2526
2527#[derive(Clone, Debug)]
2528pub(crate) enum ImportKind {
2529    // use source as str;
2530    Simple(Symbol),
2531    // use source::*;
2532    Glob,
2533}
2534
2535#[derive(Clone, Debug)]
2536pub(crate) struct ImportSource {
2537    pub(crate) path: Path,
2538    pub(crate) did: Option<DefId>,
2539}
2540
2541#[derive(Clone, Debug)]
2542pub(crate) struct Macro {
2543    pub(crate) source: String,
2544    /// Whether the macro was defined via `macro_rules!` as opposed to `macro`.
2545    pub(crate) macro_rules: bool,
2546}
2547
2548#[derive(Clone, Debug)]
2549pub(crate) struct ProcMacro {
2550    pub(crate) kind: MacroKind,
2551    pub(crate) helpers: Vec<Symbol>,
2552}
2553
2554/// A constraint on an associated item.
2555///
2556/// ### Examples
2557///
2558/// * the `A = Ty` and `B = Ty` in `Trait<A = Ty, B = Ty>`
2559/// * the `G<Ty> = Ty` in `Trait<G<Ty> = Ty>`
2560/// * the `A: Bound` in `Trait<A: Bound>`
2561/// * the `RetTy` in `Trait(ArgTy, ArgTy) -> RetTy`
2562/// * the `C = { Ct }` in `Trait<C = { Ct }>` (feature `associated_const_equality`)
2563/// * the `f(..): Bound` in `Trait<f(..): Bound>` (feature `return_type_notation`)
2564#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2565pub(crate) struct AssocItemConstraint {
2566    pub(crate) assoc: PathSegment,
2567    pub(crate) kind: AssocItemConstraintKind,
2568}
2569
2570/// The kind of [associated item constraint][AssocItemConstraint].
2571#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2572pub(crate) enum AssocItemConstraintKind {
2573    Equality { term: Term },
2574    Bound { bounds: Vec<GenericBound> },
2575}
2576
2577// Some nodes are used a lot. Make sure they don't unintentionally get bigger.
2578#[cfg(target_pointer_width = "64")]
2579mod size_asserts {
2580    use rustc_data_structures::static_assert_size;
2581
2582    use super::*;
2583    // tidy-alphabetical-start
2584    static_assert_size!(Crate, 16); // frequently moved by-value
2585    static_assert_size!(DocFragment, 32);
2586    static_assert_size!(GenericArg, 32);
2587    static_assert_size!(GenericArgs, 24);
2588    static_assert_size!(GenericParamDef, 40);
2589    static_assert_size!(Generics, 16);
2590    static_assert_size!(Item, 8);
2591    static_assert_size!(ItemInner, 144);
2592    static_assert_size!(ItemKind, 48);
2593    static_assert_size!(PathSegment, 32);
2594    static_assert_size!(Type, 32);
2595    // tidy-alphabetical-end
2596}