Skip to main content

rustdoc/clean/
types.rs

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