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