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