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