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, ModId};
29use rustc_span::hygiene::MacroKind;
30use rustc_span::symbol::{Symbol, kw, sym};
31use rustc_span::{DUMMY_SP, FileName, Ident, Loc, RemapPathScopeComponents};
32use tracing::{debug, trace};
33
34pub(crate) use self::ItemKind::*;
35pub(crate) use self::Type::{
36    Array, BareFunction, BorrowedRef, DynTrait, Generic, ImplTrait, Infer, Primitive, QPath,
37    RawPointer, SelfTy, Slice, Tuple, UnsafeBinder,
38};
39use crate::clean::cfg::Cfg;
40use crate::clean::clean_middle_path;
41use crate::clean::inline::{self, print_inlined_const};
42use crate::clean::utils::{is_literal_expr, print_evaluated_const};
43use crate::core::DocContext;
44use crate::formats::cache::Cache;
45use crate::formats::item_type::ItemType;
46use crate::html::format::HrefInfo;
47use crate::html::render::Context;
48use crate::passes::collect_intra_doc_links::UrlFragment;
49
50#[cfg(test)]
51mod tests;
52
53pub(crate) type ItemIdSet = FxHashSet<ItemId>;
54
55#[derive(Debug, Clone, PartialEq, Eq, Hash, Copy)]
56pub(crate) enum ItemId {
57    /// A "normal" item that uses a [`DefId`] for identification.
58    DefId(DefId),
59    /// Identifier that is used for auto traits.
60    Auto { trait_: DefId, for_: DefId },
61    /// Identifier that is used for blanket implementations.
62    Blanket { impl_id: DefId, for_: DefId },
63}
64
65#[derive(Debug, Copy, Clone, PartialEq, Eq)]
66pub(crate) enum Defaultness {
67    Implicit,
68    Default,
69    Final,
70}
71
72impl Defaultness {
73    pub(crate) fn from_trait_item(defaultness: hir::Defaultness) -> Self {
74        match defaultness {
75            hir::Defaultness::Default { .. } => Self::Implicit,
76            hir::Defaultness::Final => Self::Final,
77        }
78    }
79
80    pub(crate) fn from_impl_item(defaultness: hir::Defaultness) -> Self {
81        match defaultness {
82            hir::Defaultness::Default { .. } => Self::Default,
83            hir::Defaultness::Final => Self::Implicit,
84        }
85    }
86}
87
88impl ItemId {
89    #[inline]
90    pub(crate) fn is_local(self) -> bool {
91        match self {
92            ItemId::Auto { for_: id, .. }
93            | ItemId::Blanket { for_: id, .. }
94            | ItemId::DefId(id) => id.is_local(),
95        }
96    }
97
98    #[inline]
99    #[track_caller]
100    pub(crate) fn expect_def_id(self) -> DefId {
101        self.as_def_id()
102            .unwrap_or_else(|| panic!("ItemId::expect_def_id: `{self:?}` isn't a DefId"))
103    }
104
105    #[inline]
106    pub(crate) fn as_def_id(self) -> Option<DefId> {
107        match self {
108            ItemId::DefId(id) => Some(id),
109            _ => None,
110        }
111    }
112
113    #[inline]
114    pub(crate) fn as_local_def_id(self) -> Option<LocalDefId> {
115        self.as_def_id().and_then(|id| id.as_local())
116    }
117
118    #[inline]
119    pub(crate) fn krate(self) -> CrateNum {
120        match self {
121            ItemId::Auto { for_: id, .. }
122            | ItemId::Blanket { for_: id, .. }
123            | ItemId::DefId(id) => id.krate,
124        }
125    }
126}
127
128impl From<DefId> for ItemId {
129    fn from(id: DefId) -> Self {
130        Self::DefId(id)
131    }
132}
133
134/// The crate currently being documented.
135#[derive(Debug)]
136pub(crate) struct Crate {
137    pub(crate) module: Item,
138    /// Only here so that they can be filtered through the rustdoc passes.
139    pub(crate) external_traits: Box<FxIndexMap<DefId, Trait>>,
140}
141
142impl Crate {
143    pub(crate) fn name(&self, tcx: TyCtxt<'_>) -> Symbol {
144        ExternalCrate::LOCAL.name(tcx)
145    }
146
147    pub(crate) fn src(&self, tcx: TyCtxt<'_>) -> FileName {
148        ExternalCrate::LOCAL.src(tcx)
149    }
150}
151
152#[derive(Copy, Clone, Debug)]
153pub(crate) struct ExternalCrate {
154    pub(crate) crate_num: CrateNum,
155}
156
157impl ExternalCrate {
158    const LOCAL: Self = Self { crate_num: LOCAL_CRATE };
159
160    #[inline]
161    pub(crate) fn def_id(&self) -> DefId {
162        self.crate_num.as_def_id()
163    }
164
165    pub(crate) fn src(&self, tcx: TyCtxt<'_>) -> FileName {
166        let krate_span = tcx.def_span(self.def_id());
167        tcx.sess.source_map().span_to_filename(krate_span)
168    }
169
170    pub(crate) fn name(&self, tcx: TyCtxt<'_>) -> Symbol {
171        tcx.crate_name(self.crate_num)
172    }
173
174    pub(crate) fn src_root(&self, tcx: TyCtxt<'_>) -> PathBuf {
175        match self.src(tcx) {
176            FileName::Real(ref p) => {
177                match p
178                    .local_path()
179                    .or(Some(p.path(RemapPathScopeComponents::DOCUMENTATION)))
180                    .unwrap()
181                    .parent()
182                {
183                    Some(p) => p.to_path_buf(),
184                    None => PathBuf::new(),
185                }
186            }
187            _ => PathBuf::new(),
188        }
189    }
190
191    /// Attempts to find where an external crate is located, given that we're
192    /// rendering into the specified source destination.
193    pub(crate) fn location(
194        &self,
195        extern_url: Option<&str>,
196        extern_url_takes_precedence: bool,
197        dst: &std::path::Path,
198        tcx: TyCtxt<'_>,
199    ) -> ExternalLocation {
200        use ExternalLocation::*;
201
202        fn to_remote(url: impl ToString) -> ExternalLocation {
203            let mut url = url.to_string();
204            if !url.ends_with('/') {
205                url.push('/');
206            }
207            let is_absolute = url.starts_with('/')
208                || url.split_once(':').is_some_and(|(scheme, _)| {
209                    scheme.bytes().next().is_some_and(|b| b.is_ascii_alphabetic())
210                        && scheme
211                            .bytes()
212                            .all(|b| b.is_ascii_alphanumeric() || matches!(b, b'+' | b'-' | b'.'))
213                });
214            Remote { url, is_absolute }
215        }
216
217        // See if there's documentation generated into the local directory
218        // WARNING: since rustdoc creates these directories as it generates documentation, this check is only accurate before rendering starts.
219        // Make sure to call `location()` by that time.
220        let local_location = dst.join(self.name(tcx).as_str());
221        if local_location.is_dir() {
222            return Local;
223        }
224
225        if extern_url_takes_precedence && let Some(url) = extern_url {
226            return to_remote(url);
227        }
228
229        // Failing that, see if there's an attribute specifying where to find this
230        // external crate
231        let did = self.crate_num.as_def_id();
232        find_attr!(tcx, did, Doc(d) =>d.html_root_url.map(|(url, _)| url))
233            .flatten()
234            .map(to_remote)
235            .or_else(|| extern_url.map(to_remote)) // NOTE: only matters if `extern_url_takes_precedence` is false
236            .unwrap_or(Unknown) // Well, at least we tried.
237    }
238
239    fn mapped_root_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 { always: false }
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                    // Foreign functions can never be const or comptime
857                    constness: hir::Constness::NotConst,
858                    asyncness: hir::IsAsync::NotAsync,
859                }
860            }
861            ItemKind::FunctionItem(_)
862            | ItemKind::MethodItem(..)
863            | ItemKind::RequiredMethodItem(..) => {
864                let def_id = self.def_id().unwrap();
865                build_fn_header(def_id, tcx, tcx.asyncness(def_id))
866            }
867            _ => return None,
868        };
869        Some(header)
870    }
871
872    /// Returns the visibility of the current item. If the visibility is "inherited", then `None`
873    /// is returned.
874    pub(crate) fn visibility(&self, tcx: TyCtxt<'_>) -> Option<Visibility<ModId>> {
875        let def_id = match self.item_id {
876            // Anything but DefId *shouldn't* matter, but return a reasonable value anyway.
877            ItemId::Auto { .. } | ItemId::Blanket { .. } => return None,
878            ItemId::DefId(def_id) => def_id,
879        };
880
881        match self.kind {
882            // Primitives and Keywords are written in the source code as private modules.
883            // The modules need to be private so that nobody actually uses them, but the
884            // keywords and primitives that they are documenting are public.
885            ItemKind::KeywordItem | ItemKind::PrimitiveItem(_) | ItemKind::AttributeItem => {
886                return Some(Visibility::Public);
887            }
888            // Variant fields inherit their enum's visibility.
889            StructFieldItem(..) if is_field_vis_inherited(tcx, def_id) => {
890                return None;
891            }
892            // Variants always inherit visibility
893            VariantItem(..) | ImplItem(..) => return None,
894            // Trait items inherit the trait's visibility
895            RequiredAssocConstItem(..)
896            | ProvidedAssocConstItem(..)
897            | ImplAssocConstItem(..)
898            | AssocTypeItem(..)
899            | RequiredAssocTypeItem(..)
900            | RequiredMethodItem(..)
901            | MethodItem(..) => {
902                match tcx.associated_item(def_id).container {
903                    // Trait impl items always inherit the impl's visibility --
904                    // we don't want to show `pub`.
905                    ty::AssocContainer::Trait | ty::AssocContainer::TraitImpl(_) => {
906                        return None;
907                    }
908                    ty::AssocContainer::InherentImpl => {}
909                }
910            }
911            _ => {}
912        }
913        let def_id = match self.inline_stmt_id {
914            Some(inlined) => inlined.to_def_id(),
915            None => def_id,
916        };
917        Some(tcx.visibility(def_id))
918    }
919
920    pub fn is_doc_hidden(&self) -> bool {
921        self.attrs.is_doc_hidden()
922    }
923
924    pub fn def_id(&self) -> Option<DefId> {
925        self.item_id.as_def_id()
926    }
927}
928
929#[derive(Clone, Debug)]
930pub(crate) enum ItemKind {
931    ExternCrateItem {
932        /// The crate's name, *not* the name it's imported as.
933        src: Option<Symbol>,
934    },
935    ImportItem(Import),
936    StructItem(Struct),
937    UnionItem(Union),
938    EnumItem(Enum),
939    FunctionItem(Box<Function>),
940    ModuleItem(Module),
941    TypeAliasItem(Box<TypeAlias>),
942    StaticItem(Static),
943    TraitItem(Box<Trait>),
944    TraitAliasItem(TraitAlias),
945    ImplItem(Box<Impl>),
946    /// This variant is used only as a placeholder for trait impls in order to correctly compute
947    /// `doc_cfg` as trait impls are added to `clean::Crate` after we went through the whole tree.
948    PlaceholderImplItem,
949    /// A required method in a trait declaration meaning it's only a function signature.
950    RequiredMethodItem(Box<Function>, Defaultness),
951    /// A method in a trait impl or a provided method in a trait declaration.
952    ///
953    /// Compared to [RequiredMethodItem], it also contains a method body.
954    MethodItem(Box<Function>, Defaultness),
955    StructFieldItem(Type),
956    VariantItem(Variant),
957    /// `fn`s from an extern block
958    ForeignFunctionItem(Box<Function>, hir::Safety),
959    /// `static`s from an extern block
960    ForeignStaticItem(Static, hir::Safety),
961    /// `type`s from an extern block
962    ForeignTypeItem,
963    /// A macro defined with `macro_rules` or the `macro` keyword. It can be multiple things (macro,
964    /// derive and attribute, potentially multiple at once). Don't forget to look into the
965    ///`MacroKinds` values.
966    ///
967    /// If a `macro_rules!` only contains a `attr`/`derive` branch, then it's not stored in this
968    /// variant but in the `ProcMacroItem` variant.
969    MacroItem(Macro, MacroKinds),
970    ProcMacroItem(ProcMacro),
971    PrimitiveItem(PrimitiveType),
972    /// A required associated constant in a trait declaration.
973    RequiredAssocConstItem(Generics, Box<Type>),
974    ConstantItem(Box<Constant>),
975    /// An associated constant in a trait declaration with provided default value.
976    ProvidedAssocConstItem(Box<Constant>),
977    /// An associated constant in an inherent impl or trait impl.
978    ImplAssocConstItem(Box<Constant>),
979    /// A required associated type in a trait declaration.
980    ///
981    /// The bounds may be non-empty if there is a `where` clause.
982    RequiredAssocTypeItem(Generics, Vec<GenericBound>),
983    /// An associated type in a trait impl or a provided one in a trait declaration.
984    AssocTypeItem(Box<TypeAlias>, Vec<GenericBound>),
985    /// An item that has been stripped by a rustdoc pass
986    StrippedItem(Box<ItemKind>),
987    /// This item represents a module with a `#[doc(keyword = "...")]` attribute which is used
988    /// to generate documentation for Rust keywords.
989    KeywordItem,
990    /// This item represents a module with a `#[doc(attribute = "...")]` attribute which is used
991    /// to generate documentation for Rust builtin attributes.
992    AttributeItem,
993}
994
995impl ItemKind {
996    /// Some items contain others such as structs (for their fields) and Enums
997    /// (for their variants). This method returns those contained items.
998    pub(crate) fn inner_items(&self) -> impl Iterator<Item = &Item> {
999        match self {
1000            StructItem(s) => s.fields.iter(),
1001            UnionItem(u) => u.fields.iter(),
1002            VariantItem(v) => match &v.kind {
1003                VariantKind::CLike => [].iter(),
1004                VariantKind::Tuple(t) => t.iter(),
1005                VariantKind::Struct(s) => s.fields.iter(),
1006            },
1007            EnumItem(e) => e.variants.iter(),
1008            TraitItem(t) => t.items.iter(),
1009            ImplItem(i) => i.items.iter(),
1010            ModuleItem(m) => m.items.iter(),
1011            ExternCrateItem { .. }
1012            | ImportItem(_)
1013            | FunctionItem(_)
1014            | TypeAliasItem(_)
1015            | StaticItem(_)
1016            | ConstantItem(_)
1017            | TraitAliasItem(_)
1018            | RequiredMethodItem(..)
1019            | MethodItem(..)
1020            | StructFieldItem(_)
1021            | ForeignFunctionItem(_, _)
1022            | ForeignStaticItem(_, _)
1023            | ForeignTypeItem
1024            | MacroItem(..)
1025            | ProcMacroItem(_)
1026            | PrimitiveItem(_)
1027            | RequiredAssocConstItem(..)
1028            | ProvidedAssocConstItem(..)
1029            | ImplAssocConstItem(..)
1030            | RequiredAssocTypeItem(..)
1031            | AssocTypeItem(..)
1032            | StrippedItem(_)
1033            | KeywordItem
1034            | AttributeItem
1035            | PlaceholderImplItem => [].iter(),
1036        }
1037    }
1038}
1039
1040#[derive(Clone, Debug)]
1041pub(crate) struct Module {
1042    pub(crate) items: Vec<Item>,
1043    pub(crate) span: Span,
1044}
1045
1046/// A link that has not yet been rendered.
1047///
1048/// This link will be turned into a rendered link by [`Item::links`].
1049#[derive(Clone, Debug, PartialEq, Eq, Hash)]
1050pub(crate) struct ItemLink {
1051    /// The original link written in the markdown
1052    pub(crate) link: Box<str>,
1053    /// The link text displayed in the HTML.
1054    ///
1055    /// This may not be the same as `link` if there was a disambiguator
1056    /// in an intra-doc link (e.g. \[`fn@f`\])
1057    pub(crate) link_text: Box<str>,
1058    /// The `DefId` of the Item whose **HTML Page** contains the item being
1059    /// linked to. This will be different to `item_id` on item's that don't
1060    /// have their own page, such as struct fields and enum variants.
1061    pub(crate) page_id: DefId,
1062    /// The url fragment to append to the link
1063    pub(crate) fragment: Option<UrlFragment>,
1064}
1065
1066pub struct RenderedLink {
1067    /// The text the link was original written as.
1068    ///
1069    /// This could potentially include disambiguators and backticks.
1070    pub(crate) original_text: Box<str>,
1071    /// The text to display in the HTML
1072    pub(crate) new_text: Box<str>,
1073    /// The URL to put in the `href`
1074    pub(crate) href: String,
1075    /// The tooltip.
1076    pub(crate) tooltip: String,
1077}
1078
1079/// The attributes on an [`Item`], including attributes like `#[derive(...)]` and `#[inline]`,
1080/// as well as doc comments.
1081#[derive(Clone, Debug, Default)]
1082pub(crate) struct Attributes {
1083    pub(crate) doc_strings: Vec<DocFragment>,
1084    pub(crate) other_attrs: ThinVec<hir::Attribute>,
1085}
1086
1087impl Attributes {
1088    pub(crate) fn has_doc_flag<F: Fn(&DocAttribute) -> bool>(&self, callback: F) -> bool {
1089        find_attr!(&self.other_attrs, Doc(d) if callback(d))
1090    }
1091
1092    pub(crate) fn is_doc_hidden(&self) -> bool {
1093        find_attr!(&self.other_attrs, Doc(d) if d.hidden.is_some())
1094    }
1095
1096    pub(crate) fn from_hir(attrs: &[hir::Attribute]) -> Attributes {
1097        Attributes::from_hir_iter(attrs.iter().map(|attr| (attr, None)), false)
1098    }
1099
1100    pub(crate) fn from_hir_with_additional(
1101        attrs: &[hir::Attribute],
1102        (additional_attrs, def_id): (&[hir::Attribute], DefId),
1103    ) -> Attributes {
1104        // Additional documentation should be shown before the original documentation.
1105        let attrs1 = additional_attrs.iter().map(|attr| (attr, Some(def_id)));
1106        let attrs2 = attrs.iter().map(|attr| (attr, None));
1107        Attributes::from_hir_iter(attrs1.chain(attrs2), false)
1108    }
1109
1110    pub(crate) fn from_hir_iter<'a>(
1111        attrs: impl Iterator<Item = (&'a hir::Attribute, Option<DefId>)>,
1112        doc_only: bool,
1113    ) -> Attributes {
1114        let (doc_strings, other_attrs) = attrs_to_doc_fragments(attrs, doc_only);
1115        Attributes { doc_strings, other_attrs }
1116    }
1117
1118    /// Combine all doc strings into a single value handling indentation and newlines as needed.
1119    pub(crate) fn doc_value(&self) -> String {
1120        self.opt_doc_value().unwrap_or_default()
1121    }
1122
1123    /// Combine all doc strings into a single value handling indentation and newlines as needed.
1124    /// Returns `None` is there's no documentation at all, and `Some("")` if there is some
1125    /// documentation but it is empty (e.g. `#[doc = ""]`).
1126    pub(crate) fn opt_doc_value(&self) -> Option<String> {
1127        (!self.doc_strings.is_empty()).then(|| {
1128            let mut res = String::new();
1129            for frag in &self.doc_strings {
1130                add_doc_fragment(&mut res, frag);
1131            }
1132            res.pop();
1133            res
1134        })
1135    }
1136
1137    pub(crate) fn get_doc_aliases(&self) -> Box<[Symbol]> {
1138        let mut aliases = FxIndexSet::default();
1139
1140        for attr in &self.other_attrs {
1141            if let Attribute::Parsed(AttributeKind::Doc(d)) = attr {
1142                for (alias, _) in &d.aliases {
1143                    aliases.insert(*alias);
1144                }
1145            }
1146        }
1147        aliases.into_iter().collect::<Vec<_>>().into()
1148    }
1149
1150    pub(crate) fn merge_with(&mut self, other: Self) {
1151        let Self { doc_strings, other_attrs } = other;
1152        self.doc_strings.extend(doc_strings);
1153        self.other_attrs.extend(other_attrs);
1154    }
1155}
1156
1157#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1158pub(crate) enum GenericBound {
1159    TraitBound(PolyTrait, hir::TraitBoundModifiers),
1160    Outlives(Lifetime),
1161    /// `use<'a, T>` precise-capturing bound syntax
1162    Use(Vec<PreciseCapturingArg>),
1163}
1164
1165impl GenericBound {
1166    pub(crate) fn sized(cx: &mut DocContext<'_>) -> GenericBound {
1167        Self::sized_with(cx, hir::TraitBoundModifiers::NONE)
1168    }
1169
1170    pub(crate) fn maybe_sized(cx: &mut DocContext<'_>) -> GenericBound {
1171        Self::sized_with(
1172            cx,
1173            hir::TraitBoundModifiers {
1174                polarity: hir::BoundPolarity::Maybe(DUMMY_SP),
1175                constness: hir::BoundConstness::Never,
1176            },
1177        )
1178    }
1179
1180    fn sized_with(cx: &mut DocContext<'_>, modifiers: hir::TraitBoundModifiers) -> GenericBound {
1181        let did = cx.tcx.require_lang_item(LangItem::Sized, DUMMY_SP);
1182        let empty = ty::Binder::dummy(ty::GenericArgs::empty());
1183        let path = clean_middle_path(cx, did, false, ThinVec::new(), empty);
1184        inline::record_extern_fqn(cx, did, ItemType::Trait);
1185        GenericBound::TraitBound(PolyTrait { trait_: path, generic_params: Vec::new() }, modifiers)
1186    }
1187
1188    pub(crate) fn is_trait_bound(&self) -> bool {
1189        matches!(self, Self::TraitBound(..))
1190    }
1191
1192    pub(crate) fn is_sized_bound(&self, tcx: TyCtxt<'_>) -> bool {
1193        self.is_bounded_by_lang_item(tcx, LangItem::Sized)
1194    }
1195
1196    pub(crate) fn is_meta_sized_bound(&self, tcx: TyCtxt<'_>) -> bool {
1197        self.is_bounded_by_lang_item(tcx, LangItem::MetaSized)
1198    }
1199
1200    fn is_bounded_by_lang_item(&self, tcx: TyCtxt<'_>, lang_item: LangItem) -> bool {
1201        if let GenericBound::TraitBound(poly_trait_ref, rustc_hir::TraitBoundModifiers::NONE) = self
1202            && tcx.is_lang_item(poly_trait_ref.trait_.def_id(), lang_item)
1203        {
1204            return true;
1205        }
1206        false
1207    }
1208
1209    pub(crate) fn get_trait_path(&self) -> Option<Path> {
1210        if let GenericBound::TraitBound(poly_trait_ref, _) = self {
1211            Some(poly_trait_ref.trait_.clone())
1212        } else {
1213            None
1214        }
1215    }
1216}
1217
1218#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
1219pub(crate) struct Lifetime(pub Symbol);
1220
1221impl Lifetime {
1222    pub(crate) fn statik() -> Lifetime {
1223        Lifetime(kw::StaticLifetime)
1224    }
1225
1226    pub(crate) fn elided() -> Lifetime {
1227        Lifetime(kw::UnderscoreLifetime)
1228    }
1229}
1230
1231#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
1232pub(crate) enum PreciseCapturingArg {
1233    Lifetime(Lifetime),
1234    Param(Symbol),
1235}
1236
1237impl PreciseCapturingArg {
1238    pub(crate) fn name(self) -> Symbol {
1239        match self {
1240            PreciseCapturingArg::Lifetime(lt) => lt.0,
1241            PreciseCapturingArg::Param(param) => param,
1242        }
1243    }
1244}
1245
1246#[derive(Clone, PartialEq, Eq, Hash, Debug)]
1247pub(crate) enum WherePredicate {
1248    BoundPredicate { ty: Type, bounds: Vec<GenericBound>, bound_params: Vec<GenericParamDef> },
1249    RegionPredicate { lifetime: Lifetime, bounds: Vec<GenericBound> },
1250    ProjectionPredicate { lhs: QPathData, rhs: Term },
1251}
1252
1253impl WherePredicate {
1254    pub(crate) fn get_bounds(&self) -> Option<&[GenericBound]> {
1255        match self {
1256            WherePredicate::BoundPredicate { bounds, .. } => Some(bounds),
1257            WherePredicate::RegionPredicate { bounds, .. } => Some(bounds),
1258            _ => None,
1259        }
1260    }
1261}
1262
1263#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1264pub(crate) enum GenericParamDefKind {
1265    Lifetime { outlives: ThinVec<Lifetime> },
1266    Type { bounds: ThinVec<GenericBound>, default: Option<Box<Type>>, synthetic: bool },
1267    // Option<Box<String>> makes this type smaller than `Option<String>` would.
1268    Const { ty: Box<Type>, default: Option<Box<String>> },
1269}
1270
1271impl GenericParamDefKind {
1272    pub(crate) fn is_type(&self) -> bool {
1273        matches!(self, GenericParamDefKind::Type { .. })
1274    }
1275}
1276
1277#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1278pub(crate) struct GenericParamDef {
1279    pub(crate) name: Symbol,
1280    pub(crate) def_id: DefId,
1281    pub(crate) kind: GenericParamDefKind,
1282}
1283
1284impl GenericParamDef {
1285    pub(crate) fn lifetime(def_id: DefId, name: Symbol) -> Self {
1286        Self { name, def_id, kind: GenericParamDefKind::Lifetime { outlives: ThinVec::new() } }
1287    }
1288
1289    pub(crate) fn is_synthetic_param(&self) -> bool {
1290        match self.kind {
1291            GenericParamDefKind::Lifetime { .. } | GenericParamDefKind::Const { .. } => false,
1292            GenericParamDefKind::Type { synthetic, .. } => synthetic,
1293        }
1294    }
1295
1296    pub(crate) fn is_type(&self) -> bool {
1297        self.kind.is_type()
1298    }
1299
1300    pub(crate) fn get_bounds(&self) -> Option<&[GenericBound]> {
1301        match self.kind {
1302            GenericParamDefKind::Type { ref bounds, .. } => Some(bounds),
1303            _ => None,
1304        }
1305    }
1306}
1307
1308// maybe use a Generic enum and use Vec<Generic>?
1309#[derive(Clone, PartialEq, Eq, Hash, Debug, Default)]
1310pub(crate) struct Generics {
1311    pub(crate) params: ThinVec<GenericParamDef>,
1312    pub(crate) where_predicates: ThinVec<WherePredicate>,
1313}
1314
1315impl Generics {
1316    pub(crate) fn is_empty(&self) -> bool {
1317        self.params.is_empty() && self.where_predicates.is_empty()
1318    }
1319}
1320
1321#[derive(Clone, Debug)]
1322pub(crate) struct Function {
1323    pub(crate) decl: FnDecl,
1324    pub(crate) generics: Generics,
1325}
1326
1327#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1328pub(crate) struct FnDecl {
1329    pub(crate) inputs: Vec<Parameter>,
1330    pub(crate) output: Type,
1331    pub(crate) c_variadic: bool,
1332}
1333
1334impl FnDecl {
1335    pub(crate) fn receiver_type(&self) -> Option<&Type> {
1336        self.inputs.first().and_then(|v| v.to_receiver())
1337    }
1338}
1339
1340/// A function parameter.
1341#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1342pub(crate) struct Parameter {
1343    pub(crate) name: Option<Symbol>,
1344    pub(crate) type_: Type,
1345    /// This field is used to represent "const" arguments from the `rustc_legacy_const_generics`
1346    /// feature. More information in <https://github.com/rust-lang/rust/issues/83167>.
1347    pub(crate) is_const: bool,
1348}
1349
1350impl Parameter {
1351    pub(crate) fn to_receiver(&self) -> Option<&Type> {
1352        if self.name == Some(kw::SelfLower) { Some(&self.type_) } else { None }
1353    }
1354}
1355
1356#[derive(Clone, Debug)]
1357pub(crate) struct Trait {
1358    pub(crate) def_id: DefId,
1359    pub(crate) items: Vec<Item>,
1360    pub(crate) generics: Generics,
1361    pub(crate) bounds: Vec<GenericBound>,
1362}
1363
1364impl Trait {
1365    pub(crate) fn is_auto(&self, tcx: TyCtxt<'_>) -> bool {
1366        tcx.trait_is_auto(self.def_id)
1367    }
1368    pub(crate) fn is_notable_trait(&self, tcx: TyCtxt<'_>) -> bool {
1369        tcx.is_doc_notable_trait(self.def_id)
1370    }
1371    pub(crate) fn safety(&self, tcx: TyCtxt<'_>) -> hir::Safety {
1372        tcx.trait_def(self.def_id).safety
1373    }
1374    pub(crate) fn is_dyn_compatible(&self, tcx: TyCtxt<'_>) -> bool {
1375        tcx.is_dyn_compatible(self.def_id)
1376    }
1377    pub(crate) fn is_deprecated(&self, tcx: TyCtxt<'_>) -> bool {
1378        tcx.lookup_deprecation(self.def_id).is_some_and(|deprecation| deprecation.is_in_effect())
1379    }
1380}
1381
1382#[derive(Clone, Debug)]
1383pub(crate) struct TraitAlias {
1384    pub(crate) generics: Generics,
1385    pub(crate) bounds: Vec<GenericBound>,
1386}
1387
1388/// A trait reference, which may have higher ranked lifetimes.
1389#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1390pub(crate) struct PolyTrait {
1391    pub(crate) trait_: Path,
1392    pub(crate) generic_params: Vec<GenericParamDef>,
1393}
1394
1395/// Rustdoc's representation of types, mostly based on the [`hir::Ty`].
1396#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1397pub(crate) enum Type {
1398    /// A named type, which could be a trait.
1399    ///
1400    /// This is mostly Rustdoc's version of [`hir::Path`].
1401    /// It has to be different because Rustdoc's [`PathSegment`] can contain cleaned generics.
1402    Path {
1403        path: Path,
1404    },
1405    /// A `dyn Trait` object: `dyn for<'a> Trait<'a> + Send + 'static`
1406    DynTrait(Vec<PolyTrait>, Option<Lifetime>),
1407    /// A type parameter.
1408    Generic(Symbol),
1409    /// The `Self` type.
1410    SelfTy,
1411    /// A primitive (aka, builtin) type.
1412    Primitive(PrimitiveType),
1413    /// A function pointer: `extern "ABI" fn(...) -> ...`
1414    BareFunction(Box<BareFunctionDecl>),
1415    /// A tuple type: `(i32, &str)`.
1416    Tuple(Vec<Type>),
1417    /// A slice type (does *not* include the `&`): `[i32]`
1418    Slice(Box<Type>),
1419    /// An array type.
1420    ///
1421    /// The `String` field is a stringified version of the array's length parameter.
1422    Array(Box<Type>, Box<str>),
1423    Pat(Box<Type>, Box<str>),
1424    FieldOf(Box<Type>, Box<str>),
1425    /// A raw pointer type: `*const i32`, `*mut i32`
1426    RawPointer(Mutability, Box<Type>),
1427    /// A reference type: `&i32`, `&'a mut Foo`
1428    BorrowedRef {
1429        lifetime: Option<Lifetime>,
1430        mutability: Mutability,
1431        type_: Box<Type>,
1432    },
1433
1434    /// A qualified path to an associated item: `<Type as Trait>::Name`
1435    QPath(Box<QPathData>),
1436
1437    /// A type that is inferred: `_`
1438    Infer,
1439
1440    /// An `impl Trait`: `impl TraitA + TraitB + ...`
1441    ImplTrait(Vec<GenericBound>),
1442
1443    UnsafeBinder(Box<UnsafeBinderTy>),
1444}
1445
1446impl Type {
1447    /// When comparing types for equality, it can help to ignore `&` wrapping.
1448    pub(crate) fn without_borrowed_ref(&self) -> &Type {
1449        let mut result = self;
1450        while let Type::BorrowedRef { type_, .. } = result {
1451            result = type_;
1452        }
1453        result
1454    }
1455
1456    pub(crate) fn is_borrowed_ref(&self) -> bool {
1457        matches!(self, Type::BorrowedRef { .. })
1458    }
1459
1460    fn is_type_alias(&self) -> bool {
1461        matches!(self, Type::Path { path: Path { res: Res::Def(DefKind::TyAlias, _), .. } })
1462    }
1463
1464    /// Check if this type is a subtype of another type for documentation purposes.
1465    ///
1466    /// This is different from `Eq`, because it knows that things like
1467    /// `Infer` and generics have special subtyping rules.
1468    ///
1469    /// This relation is not commutative when generics are involved:
1470    ///
1471    /// ```ignore(private)
1472    /// # // see types/tests.rs:is_same_generic for the real test
1473    /// use rustdoc::format::cache::Cache;
1474    /// use rustdoc::clean::types::{Type, PrimitiveType};
1475    /// let cache = Cache::new(false);
1476    /// let generic = Type::Generic(Symbol::intern("T"));
1477    /// let unit = Type::Primitive(PrimitiveType::Unit);
1478    /// assert!(!generic.is_doc_subtype_of(&unit, &cache));
1479    /// assert!(unit.is_doc_subtype_of(&generic, &cache));
1480    /// ```
1481    ///
1482    /// An owned type is also the same as its borrowed variants (this is commutative),
1483    /// but `&T` is not the same as `&mut T`.
1484    pub(crate) fn is_doc_subtype_of(&self, other: &Self, cache: &Cache) -> bool {
1485        // Strip the references so that it can compare the actual types, unless both are references.
1486        // If both are references, leave them alone and compare the mutabilities later.
1487        let (self_cleared, other_cleared) = if !self.is_borrowed_ref() || !other.is_borrowed_ref() {
1488            (self.without_borrowed_ref(), other.without_borrowed_ref())
1489        } else {
1490            (self, other)
1491        };
1492
1493        // FIXME: `Cache` does not have the data required to unwrap type aliases,
1494        // so we just assume they are equal.
1495        // This is only remotely acceptable because we were previously
1496        // assuming all types were equal when used
1497        // as a generic parameter of a type in `Deref::Target`.
1498        if self_cleared.is_type_alias() || other_cleared.is_type_alias() {
1499            return true;
1500        }
1501
1502        match (self_cleared, other_cleared) {
1503            // Recursive cases.
1504            (Type::Tuple(a), Type::Tuple(b)) => {
1505                a.iter().eq_by(b, |a, b| a.is_doc_subtype_of(b, cache))
1506            }
1507            (Type::Slice(a), Type::Slice(b)) => a.is_doc_subtype_of(b, cache),
1508            (Type::Array(a, al), Type::Array(b, bl)) => al == bl && a.is_doc_subtype_of(b, cache),
1509            (Type::RawPointer(mutability, type_), Type::RawPointer(b_mutability, b_type_)) => {
1510                mutability == b_mutability && type_.is_doc_subtype_of(b_type_, cache)
1511            }
1512            (
1513                Type::BorrowedRef { mutability, type_, .. },
1514                Type::BorrowedRef { mutability: b_mutability, type_: b_type_, .. },
1515            ) => mutability == b_mutability && type_.is_doc_subtype_of(b_type_, cache),
1516            // Placeholders are equal to all other types.
1517            (Type::Infer, _) | (_, Type::Infer) => true,
1518            // Generics match everything on the right, but not on the left.
1519            // If both sides are generic, this returns true.
1520            (_, Type::Generic(_)) => true,
1521            (Type::Generic(_), _) => false,
1522            // `Self` only matches itself.
1523            (Type::SelfTy, Type::SelfTy) => true,
1524            // Paths account for both the path itself and its generics.
1525            (Type::Path { path: a }, Type::Path { path: b }) => {
1526                a.def_id() == b.def_id()
1527                    && a.generics()
1528                        .zip(b.generics())
1529                        .map(|(ag, bg)| ag.zip(bg).all(|(at, bt)| at.is_doc_subtype_of(bt, cache)))
1530                        .unwrap_or(true)
1531            }
1532            // Other cases, such as primitives, just use recursion.
1533            (a, b) => a
1534                .def_id(cache)
1535                .and_then(|a| Some((a, b.def_id(cache)?)))
1536                .map(|(a, b)| a == b)
1537                .unwrap_or(false),
1538        }
1539    }
1540
1541    pub(crate) fn primitive_type(&self) -> Option<PrimitiveType> {
1542        match *self {
1543            Primitive(p) | BorrowedRef { type_: Primitive(p), .. } => Some(p),
1544            Slice(..) | BorrowedRef { type_: Slice(..), .. } => Some(PrimitiveType::Slice),
1545            Array(..) | BorrowedRef { type_: Array(..), .. } => Some(PrimitiveType::Array),
1546            Tuple(ref tys) => {
1547                if tys.is_empty() {
1548                    Some(PrimitiveType::Unit)
1549                } else {
1550                    Some(PrimitiveType::Tuple)
1551                }
1552            }
1553            RawPointer(..) => Some(PrimitiveType::RawPointer),
1554            BareFunction(..) => Some(PrimitiveType::Fn),
1555            _ => None,
1556        }
1557    }
1558
1559    /// Returns the sugared return type for an async function.
1560    ///
1561    /// For example, if the return type is `impl std::future::Future<Output = i32>`, this function
1562    /// will return `i32`.
1563    ///
1564    /// # Panics
1565    ///
1566    /// This function will panic if the return type does not match the expected sugaring for async
1567    /// functions.
1568    pub(crate) fn sugared_async_return_type(self) -> Type {
1569        if let Type::ImplTrait(mut v) = self
1570            && let Some(GenericBound::TraitBound(PolyTrait { mut trait_, .. }, _)) = v.pop()
1571            && let Some(segment) = trait_.segments.pop()
1572            && let GenericArgs::AngleBracketed { mut constraints, .. } = segment.args
1573            && let Some(constraint) = constraints.pop()
1574            && let AssocItemConstraintKind::Equality { term } = constraint.kind
1575            && let Term::Type(ty) = term
1576        {
1577            ty
1578        } else {
1579            panic!("unexpected async fn return type")
1580        }
1581    }
1582
1583    /// Checks if this is a `T::Name` path for an associated type.
1584    pub(crate) fn is_assoc_ty(&self) -> bool {
1585        match self {
1586            Type::Path { path, .. } => path.is_assoc_ty(),
1587            _ => false,
1588        }
1589    }
1590
1591    pub(crate) fn is_self_type(&self) -> bool {
1592        matches!(*self, Type::SelfTy)
1593    }
1594
1595    pub(crate) fn generic_args(&self) -> Option<&GenericArgs> {
1596        match self {
1597            Type::Path { path, .. } => path.generic_args(),
1598            _ => None,
1599        }
1600    }
1601
1602    pub(crate) fn generics(&self) -> Option<impl Iterator<Item = &Type>> {
1603        match self {
1604            Type::Path { path, .. } => path.generics(),
1605            _ => None,
1606        }
1607    }
1608
1609    pub(crate) fn is_full_generic(&self) -> bool {
1610        matches!(self, Type::Generic(_))
1611    }
1612
1613    pub(crate) fn is_unit(&self) -> bool {
1614        matches!(self, Type::Tuple(v) if v.is_empty())
1615    }
1616
1617    /// Use this method to get the [DefId] of a [clean] AST node, including [PrimitiveType]s.
1618    ///
1619    /// [clean]: crate::clean
1620    pub(crate) fn def_id(&self, cache: &Cache) -> Option<DefId> {
1621        let t: PrimitiveType = match self {
1622            Type::Path { path } => return Some(path.def_id()),
1623            DynTrait(bounds, _) => return bounds.first().map(|b| b.trait_.def_id()),
1624            Primitive(p) => return cache.primitive_locations.get(p).cloned(),
1625            BorrowedRef { type_: Generic(..), .. } => PrimitiveType::Reference,
1626            BorrowedRef { type_, .. } => return type_.def_id(cache),
1627            Tuple(tys) => {
1628                if tys.is_empty() {
1629                    PrimitiveType::Unit
1630                } else {
1631                    PrimitiveType::Tuple
1632                }
1633            }
1634            BareFunction(..) => PrimitiveType::Fn,
1635            Slice(..) => PrimitiveType::Slice,
1636            Array(..) => PrimitiveType::Array,
1637            Type::Pat(..) => PrimitiveType::Pat,
1638            Type::FieldOf(..) => PrimitiveType::FieldOf,
1639            RawPointer(..) => PrimitiveType::RawPointer,
1640            QPath(QPathData { self_type, .. }) => return self_type.def_id(cache),
1641            Generic(_) | SelfTy | Infer | ImplTrait(_) | UnsafeBinder(_) => return None,
1642        };
1643        Primitive(t).def_id(cache)
1644    }
1645}
1646
1647#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1648pub(crate) struct QPathData {
1649    pub assoc: PathSegment,
1650    pub self_type: Type,
1651    /// FIXME: compute this field on demand.
1652    pub should_fully_qualify: bool,
1653    pub trait_: Option<Path>,
1654}
1655
1656/// A primitive (aka, builtin) type.
1657///
1658/// This represents things like `i32`, `str`, etc.
1659///
1660/// N.B. This has to be different from [`hir::PrimTy`] because it also includes types that aren't
1661/// paths, like [`Self::Unit`].
1662#[derive(Clone, PartialEq, Eq, Hash, Copy, Debug)]
1663pub(crate) enum PrimitiveType {
1664    Isize,
1665    I8,
1666    I16,
1667    I32,
1668    I64,
1669    I128,
1670    Usize,
1671    U8,
1672    U16,
1673    U32,
1674    U64,
1675    U128,
1676    F16,
1677    F32,
1678    F64,
1679    F128,
1680    Char,
1681    Bool,
1682    Str,
1683    Slice,
1684    Array,
1685    Pat,
1686    FieldOf,
1687    Tuple,
1688    Unit,
1689    RawPointer,
1690    Reference,
1691    Fn,
1692    Never,
1693}
1694
1695type SimplifiedTypes = FxIndexMap<PrimitiveType, ArrayVec<SimplifiedType, 3>>;
1696impl PrimitiveType {
1697    pub(crate) fn from_hir(prim: hir::PrimTy) -> PrimitiveType {
1698        use ast::{FloatTy, IntTy, UintTy};
1699        match prim {
1700            hir::PrimTy::Int(IntTy::Isize) => PrimitiveType::Isize,
1701            hir::PrimTy::Int(IntTy::I8) => PrimitiveType::I8,
1702            hir::PrimTy::Int(IntTy::I16) => PrimitiveType::I16,
1703            hir::PrimTy::Int(IntTy::I32) => PrimitiveType::I32,
1704            hir::PrimTy::Int(IntTy::I64) => PrimitiveType::I64,
1705            hir::PrimTy::Int(IntTy::I128) => PrimitiveType::I128,
1706            hir::PrimTy::Uint(UintTy::Usize) => PrimitiveType::Usize,
1707            hir::PrimTy::Uint(UintTy::U8) => PrimitiveType::U8,
1708            hir::PrimTy::Uint(UintTy::U16) => PrimitiveType::U16,
1709            hir::PrimTy::Uint(UintTy::U32) => PrimitiveType::U32,
1710            hir::PrimTy::Uint(UintTy::U64) => PrimitiveType::U64,
1711            hir::PrimTy::Uint(UintTy::U128) => PrimitiveType::U128,
1712            hir::PrimTy::Float(FloatTy::F16) => PrimitiveType::F16,
1713            hir::PrimTy::Float(FloatTy::F32) => PrimitiveType::F32,
1714            hir::PrimTy::Float(FloatTy::F64) => PrimitiveType::F64,
1715            hir::PrimTy::Float(FloatTy::F128) => PrimitiveType::F128,
1716            hir::PrimTy::Str => PrimitiveType::Str,
1717            hir::PrimTy::Bool => PrimitiveType::Bool,
1718            hir::PrimTy::Char => PrimitiveType::Char,
1719        }
1720    }
1721
1722    pub(crate) fn from_symbol(s: Symbol) -> Option<PrimitiveType> {
1723        match s {
1724            sym::isize => Some(PrimitiveType::Isize),
1725            sym::i8 => Some(PrimitiveType::I8),
1726            sym::i16 => Some(PrimitiveType::I16),
1727            sym::i32 => Some(PrimitiveType::I32),
1728            sym::i64 => Some(PrimitiveType::I64),
1729            sym::i128 => Some(PrimitiveType::I128),
1730            sym::usize => Some(PrimitiveType::Usize),
1731            sym::u8 => Some(PrimitiveType::U8),
1732            sym::u16 => Some(PrimitiveType::U16),
1733            sym::u32 => Some(PrimitiveType::U32),
1734            sym::u64 => Some(PrimitiveType::U64),
1735            sym::u128 => Some(PrimitiveType::U128),
1736            sym::bool => Some(PrimitiveType::Bool),
1737            sym::char => Some(PrimitiveType::Char),
1738            sym::str => Some(PrimitiveType::Str),
1739            sym::f16 => Some(PrimitiveType::F16),
1740            sym::f32 => Some(PrimitiveType::F32),
1741            sym::f64 => Some(PrimitiveType::F64),
1742            sym::f128 => Some(PrimitiveType::F128),
1743            sym::array => Some(PrimitiveType::Array),
1744            sym::slice => Some(PrimitiveType::Slice),
1745            sym::tuple => Some(PrimitiveType::Tuple),
1746            sym::unit => Some(PrimitiveType::Unit),
1747            sym::pointer => Some(PrimitiveType::RawPointer),
1748            sym::reference => Some(PrimitiveType::Reference),
1749            kw::Fn => Some(PrimitiveType::Fn),
1750            sym::never => Some(PrimitiveType::Never),
1751            _ => None,
1752        }
1753    }
1754
1755    pub(crate) fn from_ty(ty: Ty<'_>) -> Option<Self> {
1756        match ty.kind() {
1757            ty::Array(..) => Some(Self::Array),
1758            ty::Bool => Some(Self::Bool),
1759            ty::Char => Some(Self::Char),
1760            ty::FnDef(..) | ty::FnPtr(..) => Some(Self::Fn),
1761            ty::Int(int) => Some(Self::from(*int)),
1762            ty::Uint(uint) => Some(Self::from(*uint)),
1763            ty::Float(float) => Some(Self::from(*float)),
1764            ty::Never => Some(Self::Never),
1765            ty::Pat(..) => Some(Self::Pat),
1766            ty::RawPtr(..) => Some(Self::RawPointer),
1767            ty::Ref(..) => Some(Self::Reference),
1768            ty::Slice(..) => Some(Self::Slice),
1769            ty::Str => Some(Self::Str),
1770            ty::Tuple(elems) if elems.is_empty() => Some(Self::Unit),
1771            ty::Tuple(_) => Some(Self::Tuple),
1772            ty::Adt(..)
1773            | ty::Alias(_, ..)
1774            | ty::Bound(..)
1775            | ty::Closure(..)
1776            | ty::Coroutine(..)
1777            | ty::CoroutineClosure(..)
1778            | ty::CoroutineWitness(..)
1779            | ty::Dynamic(..)
1780            | ty::Error(..)
1781            | ty::Foreign(..)
1782            | ty::Infer(..)
1783            | ty::Param(..)
1784            | ty::Placeholder(..)
1785            | ty::UnsafeBinder(..) => None,
1786        }
1787    }
1788
1789    pub(crate) fn simplified_types() -> &'static SimplifiedTypes {
1790        use PrimitiveType::*;
1791        use ty::{FloatTy, IntTy, UintTy};
1792        static CELL: OnceCell<SimplifiedTypes> = OnceCell::new();
1793
1794        let single = |x| iter::once(x).collect();
1795        CELL.get_or_init(move || {
1796            map! {
1797                Isize => single(SimplifiedType::Int(IntTy::Isize)),
1798                I8 => single(SimplifiedType::Int(IntTy::I8)),
1799                I16 => single(SimplifiedType::Int(IntTy::I16)),
1800                I32 => single(SimplifiedType::Int(IntTy::I32)),
1801                I64 => single(SimplifiedType::Int(IntTy::I64)),
1802                I128 => single(SimplifiedType::Int(IntTy::I128)),
1803                Usize => single(SimplifiedType::Uint(UintTy::Usize)),
1804                U8 => single(SimplifiedType::Uint(UintTy::U8)),
1805                U16 => single(SimplifiedType::Uint(UintTy::U16)),
1806                U32 => single(SimplifiedType::Uint(UintTy::U32)),
1807                U64 => single(SimplifiedType::Uint(UintTy::U64)),
1808                U128 => single(SimplifiedType::Uint(UintTy::U128)),
1809                F16 => single(SimplifiedType::Float(FloatTy::F16)),
1810                F32 => single(SimplifiedType::Float(FloatTy::F32)),
1811                F64 => single(SimplifiedType::Float(FloatTy::F64)),
1812                F128 => single(SimplifiedType::Float(FloatTy::F128)),
1813                Str => single(SimplifiedType::Str),
1814                Bool => single(SimplifiedType::Bool),
1815                Char => single(SimplifiedType::Char),
1816                Array => single(SimplifiedType::Array),
1817                Slice => single(SimplifiedType::Slice),
1818                // FIXME: If we ever add an inherent impl for tuples
1819                // with different lengths, they won't show in rustdoc.
1820                //
1821                // Either manually update this arrayvec at this point
1822                // or start with a more complex refactoring.
1823                Tuple => [SimplifiedType::Tuple(1), SimplifiedType::Tuple(2), SimplifiedType::Tuple(3)].into(),
1824                Unit => single(SimplifiedType::Tuple(0)),
1825                RawPointer => [SimplifiedType::Ptr(Mutability::Not), SimplifiedType::Ptr(Mutability::Mut)].into_iter().collect(),
1826                Reference => [SimplifiedType::Ref(Mutability::Not), SimplifiedType::Ref(Mutability::Mut)].into_iter().collect(),
1827                // FIXME: This will be wrong if we ever add inherent impls
1828                // for function pointers.
1829                Fn => single(SimplifiedType::Function(1)),
1830                Never => single(SimplifiedType::Never),
1831            }
1832        })
1833    }
1834
1835    pub(crate) fn impls<'tcx>(&self, tcx: TyCtxt<'tcx>) -> impl Iterator<Item = DefId> + 'tcx {
1836        Self::simplified_types()
1837            .get(self)
1838            .into_iter()
1839            .flatten()
1840            .flat_map(move |&simp| tcx.incoherent_impls(simp).iter())
1841            .copied()
1842    }
1843
1844    pub(crate) fn as_sym(&self) -> Symbol {
1845        use PrimitiveType::*;
1846        match self {
1847            Isize => sym::isize,
1848            I8 => sym::i8,
1849            I16 => sym::i16,
1850            I32 => sym::i32,
1851            I64 => sym::i64,
1852            I128 => sym::i128,
1853            Usize => sym::usize,
1854            U8 => sym::u8,
1855            U16 => sym::u16,
1856            U32 => sym::u32,
1857            U64 => sym::u64,
1858            U128 => sym::u128,
1859            F16 => sym::f16,
1860            F32 => sym::f32,
1861            F64 => sym::f64,
1862            F128 => sym::f128,
1863            Str => sym::str,
1864            Bool => sym::bool,
1865            Char => sym::char,
1866            Array => sym::array,
1867            Pat => sym::pat,
1868            FieldOf => sym::field_of,
1869            Slice => sym::slice,
1870            Tuple => sym::tuple,
1871            Unit => sym::unit,
1872            RawPointer => sym::pointer,
1873            Reference => sym::reference,
1874            Fn => kw::Fn,
1875            Never => sym::never,
1876        }
1877    }
1878
1879    /// Returns the DefId of the module with `rustc_doc_primitive` for this primitive type.
1880    /// Panics if there is no such module.
1881    ///
1882    /// This gives precedence to primitives defined in the current crate, and deprioritizes
1883    /// primitives defined in `core`,
1884    /// but otherwise, if multiple crates define the same primitive, there is no guarantee of which
1885    /// will be picked.
1886    ///
1887    /// In particular, if a crate depends on both `std` and another crate that also defines
1888    /// `rustc_doc_primitive`, then it's entirely random whether `std` or the other crate is picked.
1889    /// (no_std crates are usually fine unless multiple dependencies define a primitive.)
1890    pub(crate) fn primitive_locations(tcx: TyCtxt<'_>) -> &FxIndexMap<PrimitiveType, DefId> {
1891        static PRIMITIVE_LOCATIONS: OnceCell<FxIndexMap<PrimitiveType, DefId>> = OnceCell::new();
1892        PRIMITIVE_LOCATIONS.get_or_init(|| {
1893            let mut primitive_locations = FxIndexMap::default();
1894            // NOTE: technically this misses crates that are only passed with `--extern` and not loaded when checking the crate.
1895            // This is a degenerate case that I don't plan to support.
1896            for &crate_num in tcx.crates(()) {
1897                let e = ExternalCrate { crate_num };
1898                let crate_name = e.name(tcx);
1899                debug!(?crate_num, ?crate_name);
1900                for (def_id, prim) in e.primitives(tcx) {
1901                    // HACK: try to link to std instead where possible
1902                    if crate_name == sym::core && primitive_locations.contains_key(&prim) {
1903                        continue;
1904                    }
1905                    primitive_locations.insert(prim, def_id);
1906                }
1907            }
1908            let local_primitives = ExternalCrate { crate_num: LOCAL_CRATE }.primitives(tcx);
1909            for (def_id, prim) in local_primitives {
1910                primitive_locations.insert(prim, def_id);
1911            }
1912            primitive_locations
1913        })
1914    }
1915}
1916
1917impl From<ty::IntTy> for PrimitiveType {
1918    fn from(int_ty: ty::IntTy) -> PrimitiveType {
1919        match int_ty {
1920            ty::IntTy::Isize => PrimitiveType::Isize,
1921            ty::IntTy::I8 => PrimitiveType::I8,
1922            ty::IntTy::I16 => PrimitiveType::I16,
1923            ty::IntTy::I32 => PrimitiveType::I32,
1924            ty::IntTy::I64 => PrimitiveType::I64,
1925            ty::IntTy::I128 => PrimitiveType::I128,
1926        }
1927    }
1928}
1929
1930impl From<ty::UintTy> for PrimitiveType {
1931    fn from(uint_ty: ty::UintTy) -> PrimitiveType {
1932        match uint_ty {
1933            ty::UintTy::Usize => PrimitiveType::Usize,
1934            ty::UintTy::U8 => PrimitiveType::U8,
1935            ty::UintTy::U16 => PrimitiveType::U16,
1936            ty::UintTy::U32 => PrimitiveType::U32,
1937            ty::UintTy::U64 => PrimitiveType::U64,
1938            ty::UintTy::U128 => PrimitiveType::U128,
1939        }
1940    }
1941}
1942
1943impl From<ty::FloatTy> for PrimitiveType {
1944    fn from(float_ty: ty::FloatTy) -> PrimitiveType {
1945        match float_ty {
1946            ty::FloatTy::F16 => PrimitiveType::F16,
1947            ty::FloatTy::F32 => PrimitiveType::F32,
1948            ty::FloatTy::F64 => PrimitiveType::F64,
1949            ty::FloatTy::F128 => PrimitiveType::F128,
1950        }
1951    }
1952}
1953
1954impl From<hir::PrimTy> for PrimitiveType {
1955    fn from(prim_ty: hir::PrimTy) -> PrimitiveType {
1956        match prim_ty {
1957            hir::PrimTy::Int(int_ty) => int_ty.into(),
1958            hir::PrimTy::Uint(uint_ty) => uint_ty.into(),
1959            hir::PrimTy::Float(float_ty) => float_ty.into(),
1960            hir::PrimTy::Str => PrimitiveType::Str,
1961            hir::PrimTy::Bool => PrimitiveType::Bool,
1962            hir::PrimTy::Char => PrimitiveType::Char,
1963        }
1964    }
1965}
1966
1967#[derive(Clone, Debug)]
1968pub(crate) struct Struct {
1969    pub(crate) ctor_kind: Option<CtorKind>,
1970    pub(crate) generics: Generics,
1971    pub(crate) fields: ThinVec<Item>,
1972}
1973
1974impl Struct {
1975    pub(crate) fn has_stripped_entries(&self) -> bool {
1976        self.fields.iter().any(|f| f.is_stripped())
1977    }
1978}
1979
1980#[derive(Clone, Debug)]
1981pub(crate) struct Union {
1982    pub(crate) generics: Generics,
1983    pub(crate) fields: Vec<Item>,
1984}
1985
1986impl Union {
1987    pub(crate) fn has_stripped_entries(&self) -> bool {
1988        self.fields.iter().any(|f| f.is_stripped())
1989    }
1990}
1991
1992/// This is a more limited form of the standard Struct, different in that
1993/// it lacks the things most items have (name, id, parameterization). Found
1994/// only as a variant in an enum.
1995#[derive(Clone, Debug)]
1996pub(crate) struct VariantStruct {
1997    pub(crate) fields: ThinVec<Item>,
1998}
1999
2000impl VariantStruct {
2001    pub(crate) fn has_stripped_entries(&self) -> bool {
2002        self.fields.iter().any(|f| f.is_stripped())
2003    }
2004}
2005
2006#[derive(Clone, Debug)]
2007pub(crate) struct Enum {
2008    pub(crate) variants: IndexVec<VariantIdx, Item>,
2009    pub(crate) generics: Generics,
2010}
2011
2012impl Enum {
2013    pub(crate) fn has_stripped_entries(&self) -> bool {
2014        self.variants.iter().any(|f| f.is_stripped())
2015    }
2016
2017    pub(crate) fn non_stripped_variants(&self) -> impl Iterator<Item = &Item> {
2018        self.variants.iter().filter(|v| !v.is_stripped())
2019    }
2020}
2021
2022#[derive(Clone, Debug)]
2023pub(crate) struct Variant {
2024    pub kind: VariantKind,
2025    pub discriminant: Option<Discriminant>,
2026}
2027
2028#[derive(Clone, Debug)]
2029pub(crate) enum VariantKind {
2030    CLike,
2031    Tuple(ThinVec<Item>),
2032    Struct(VariantStruct),
2033}
2034
2035impl Variant {
2036    pub(crate) fn has_stripped_entries(&self) -> Option<bool> {
2037        match &self.kind {
2038            VariantKind::Struct(struct_) => Some(struct_.has_stripped_entries()),
2039            VariantKind::CLike | VariantKind::Tuple(_) => None,
2040        }
2041    }
2042}
2043
2044#[derive(Clone, Debug)]
2045pub(crate) struct Discriminant {
2046    // In the case of cross crate re-exports, we don't have the necessary information
2047    // to reconstruct the expression of the discriminant, only the value.
2048    pub(super) expr: Option<BodyId>,
2049    pub(super) value: DefId,
2050}
2051
2052impl Discriminant {
2053    /// Will be `None` in the case of cross-crate reexports, and may be
2054    /// simplified
2055    pub(crate) fn expr(&self, tcx: TyCtxt<'_>) -> Option<String> {
2056        self.expr
2057            .map(|body| rendered_const(tcx, tcx.hir_body(body), tcx.hir_body_owner_def_id(body)))
2058    }
2059    pub(crate) fn value(&self, tcx: TyCtxt<'_>, with_underscores: bool) -> String {
2060        print_evaluated_const(tcx, self.value, with_underscores, false).unwrap()
2061    }
2062}
2063
2064/// Small wrapper around [`rustc_span::Span`] that adds helper methods
2065/// and enforces calling [`rustc_span::Span::source_callsite()`].
2066#[derive(Copy, Clone, Debug)]
2067pub(crate) struct Span(rustc_span::Span);
2068
2069impl Span {
2070    /// Wraps a [`rustc_span::Span`]. In case this span is the result of a macro expansion, the
2071    /// span will be updated to point to the macro invocation instead of the macro definition.
2072    ///
2073    /// (See rust-lang/rust#39726)
2074    pub(crate) fn new(sp: rustc_span::Span) -> Self {
2075        Self(sp.source_callsite())
2076    }
2077
2078    pub(crate) fn inner(&self) -> rustc_span::Span {
2079        self.0
2080    }
2081
2082    pub(crate) fn filename(&self, sess: &Session) -> FileName {
2083        sess.source_map().span_to_filename(self.0)
2084    }
2085
2086    pub(crate) fn lo(&self, sess: &Session) -> Loc {
2087        sess.source_map().lookup_char_pos(self.0.lo())
2088    }
2089
2090    pub(crate) fn hi(&self, sess: &Session) -> Loc {
2091        sess.source_map().lookup_char_pos(self.0.hi())
2092    }
2093
2094    pub(crate) fn cnum(&self, sess: &Session) -> CrateNum {
2095        // FIXME: is there a time when the lo and hi crate would be different?
2096        self.lo(sess).file.cnum
2097    }
2098}
2099
2100#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2101pub(crate) struct Path {
2102    pub(crate) res: Res,
2103    pub(crate) segments: ThinVec<PathSegment>,
2104}
2105
2106impl Path {
2107    pub(crate) fn def_id(&self) -> DefId {
2108        self.res.def_id()
2109    }
2110
2111    pub(crate) fn last_opt(&self) -> Option<Symbol> {
2112        self.segments.last().map(|s| s.name)
2113    }
2114
2115    pub(crate) fn last(&self) -> Symbol {
2116        self.last_opt().expect("segments were empty")
2117    }
2118
2119    pub(crate) fn whole_name(&self) -> String {
2120        self.segments
2121            .iter()
2122            .map(|s| if s.name == kw::PathRoot { "" } else { s.name.as_str() })
2123            .intersperse("::")
2124            .collect()
2125    }
2126
2127    /// Checks if this is a `T::Name` path for an associated type.
2128    pub(crate) fn is_assoc_ty(&self) -> bool {
2129        match self.res {
2130            Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } | Res::Def(DefKind::TyParam, _)
2131                if self.segments.len() != 1 =>
2132            {
2133                true
2134            }
2135            Res::Def(DefKind::AssocTy, _) => true,
2136            _ => false,
2137        }
2138    }
2139
2140    pub(crate) fn generic_args(&self) -> Option<&GenericArgs> {
2141        self.segments.last().map(|seg| &seg.args)
2142    }
2143
2144    pub(crate) fn generics(&self) -> Option<impl Iterator<Item = &Type>> {
2145        self.segments.last().and_then(|seg| {
2146            if let GenericArgs::AngleBracketed { ref args, .. } = seg.args {
2147                Some(args.iter().filter_map(|arg| match arg {
2148                    GenericArg::Type(ty) => Some(ty),
2149                    _ => None,
2150                }))
2151            } else {
2152                None
2153            }
2154        })
2155    }
2156}
2157
2158#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2159pub(crate) enum GenericArg {
2160    Lifetime(Lifetime),
2161    Type(Type),
2162    Const(Box<ConstantKind>),
2163    Infer,
2164}
2165
2166impl GenericArg {
2167    pub(crate) fn as_lt(&self) -> Option<&Lifetime> {
2168        if let Self::Lifetime(lt) = self { Some(lt) } else { None }
2169    }
2170
2171    pub(crate) fn as_ty(&self) -> Option<&Type> {
2172        if let Self::Type(ty) = self { Some(ty) } else { None }
2173    }
2174}
2175
2176#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2177pub(crate) enum GenericArgs {
2178    /// `<args, constraints = ..>`
2179    AngleBracketed { args: ThinVec<GenericArg>, constraints: ThinVec<AssocItemConstraint> },
2180    /// `(inputs) -> output`
2181    Parenthesized { inputs: ThinVec<Type>, output: Option<Box<Type>> },
2182    /// `(..)`
2183    ReturnTypeNotation,
2184}
2185
2186impl GenericArgs {
2187    pub(crate) fn is_empty(&self) -> bool {
2188        match self {
2189            GenericArgs::AngleBracketed { args, constraints } => {
2190                args.is_empty() && constraints.is_empty()
2191            }
2192            GenericArgs::Parenthesized { inputs, output } => inputs.is_empty() && output.is_none(),
2193            GenericArgs::ReturnTypeNotation => false,
2194        }
2195    }
2196    pub(crate) fn constraints(&self) -> Box<dyn Iterator<Item = AssocItemConstraint> + '_> {
2197        match self {
2198            GenericArgs::AngleBracketed { constraints, .. } => {
2199                Box::new(constraints.iter().cloned())
2200            }
2201            GenericArgs::Parenthesized { output, .. } => Box::new(
2202                output
2203                    .as_ref()
2204                    .map(|ty| AssocItemConstraint {
2205                        assoc: PathSegment {
2206                            name: sym::Output,
2207                            args: GenericArgs::AngleBracketed {
2208                                args: ThinVec::new(),
2209                                constraints: ThinVec::new(),
2210                            },
2211                        },
2212                        kind: AssocItemConstraintKind::Equality {
2213                            term: Term::Type((**ty).clone()),
2214                        },
2215                    })
2216                    .into_iter(),
2217            ),
2218            GenericArgs::ReturnTypeNotation => Box::new([].into_iter()),
2219        }
2220    }
2221}
2222
2223impl<'a> IntoIterator for &'a GenericArgs {
2224    type IntoIter = Box<dyn Iterator<Item = GenericArg> + 'a>;
2225    type Item = GenericArg;
2226    fn into_iter(self) -> Self::IntoIter {
2227        match self {
2228            GenericArgs::AngleBracketed { args, .. } => Box::new(args.iter().cloned()),
2229            GenericArgs::Parenthesized { inputs, .. } => {
2230                // FIXME: This isn't really right, since `Fn(A, B)` is `Fn<(A, B)>`
2231                Box::new(inputs.iter().cloned().map(GenericArg::Type))
2232            }
2233            GenericArgs::ReturnTypeNotation => Box::new([].into_iter()),
2234        }
2235    }
2236}
2237
2238#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2239pub(crate) struct PathSegment {
2240    pub(crate) name: Symbol,
2241    pub(crate) args: GenericArgs,
2242}
2243
2244#[derive(Clone, Debug)]
2245pub(crate) enum TypeAliasInnerType {
2246    Enum { variants: IndexVec<VariantIdx, Item>, is_non_exhaustive: bool },
2247    Union { fields: Vec<Item> },
2248    Struct { ctor_kind: Option<CtorKind>, fields: Vec<Item> },
2249}
2250
2251impl TypeAliasInnerType {
2252    fn has_stripped_entries(&self) -> Option<bool> {
2253        Some(match self {
2254            Self::Enum { variants, .. } => variants.iter().any(|v| v.is_stripped()),
2255            Self::Union { fields } | Self::Struct { fields, .. } => {
2256                fields.iter().any(|f| f.is_stripped())
2257            }
2258        })
2259    }
2260}
2261
2262#[derive(Clone, Debug)]
2263pub(crate) struct TypeAlias {
2264    pub(crate) type_: Type,
2265    pub(crate) generics: Generics,
2266    /// Inner `AdtDef` type, ie `type TyKind = IrTyKind<Adt, Ty>`,
2267    /// to be shown directly on the typedef page.
2268    pub(crate) inner_type: Option<TypeAliasInnerType>,
2269    /// `type_` can come from either the HIR or from metadata. If it comes from HIR, it may be a type
2270    /// alias instead of the final type. This will always have the final type, regardless of whether
2271    /// `type_` came from HIR or from metadata.
2272    ///
2273    /// If `item_type.is_none()`, `type_` is guaranteed to come from metadata (and therefore hold the
2274    /// final type).
2275    pub(crate) item_type: Option<Type>,
2276}
2277
2278#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2279pub(crate) struct BareFunctionDecl {
2280    pub(crate) safety: hir::Safety,
2281    pub(crate) generic_params: Vec<GenericParamDef>,
2282    pub(crate) decl: FnDecl,
2283    pub(crate) abi: ExternAbi,
2284}
2285
2286#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2287pub(crate) struct UnsafeBinderTy {
2288    pub(crate) generic_params: Vec<GenericParamDef>,
2289    pub(crate) ty: Type,
2290}
2291
2292#[derive(Clone, Debug)]
2293pub(crate) struct Static {
2294    pub(crate) type_: Box<Type>,
2295    pub(crate) mutability: Mutability,
2296    pub(crate) expr: Option<BodyId>,
2297}
2298
2299#[derive(Clone, PartialEq, Eq, Hash, Debug)]
2300pub(crate) struct Constant {
2301    pub(crate) generics: Generics,
2302    pub(crate) kind: ConstantKind,
2303    pub(crate) type_: Type,
2304}
2305
2306#[derive(Clone, PartialEq, Eq, Hash, Debug)]
2307pub(crate) enum Term {
2308    Type(Type),
2309    Constant(ConstantKind),
2310}
2311
2312impl Term {
2313    pub(crate) fn ty(&self) -> Option<&Type> {
2314        if let Term::Type(ty) = self { Some(ty) } else { None }
2315    }
2316}
2317
2318impl From<Type> for Term {
2319    fn from(ty: Type) -> Self {
2320        Term::Type(ty)
2321    }
2322}
2323
2324#[derive(Clone, PartialEq, Eq, Hash, Debug)]
2325pub(crate) enum ConstantKind {
2326    /// This is the wrapper around `ty::Const` for a non-local constant. Because it doesn't have a
2327    /// `BodyId`, we need to handle it on its own.
2328    ///
2329    /// Note that `ty::Const` includes generic parameters, and may not always be uniquely identified
2330    /// by a DefId. So this field must be different from `Extern`.
2331    TyConst { expr: Box<str> },
2332    /// A constant that is just a path (i.e., referring to a const param, free const, etc.).
2333    // FIXME: this is an unfortunate representation. rustdoc's logic around consts needs to be improved.
2334    Path { path: Box<str> },
2335    /// A constant (expression) that's not an item or associated item. These are usually found
2336    /// nested inside types (e.g., array lengths) or expressions (e.g., repeat counts), and also
2337    /// used to define explicit discriminant values for enum variants.
2338    Anonymous { body: BodyId },
2339    /// A constant from a different crate.
2340    Extern { def_id: DefId },
2341    /// `const FOO: u32 = ...;`
2342    Local { def_id: DefId, body: BodyId },
2343    /// An inferred constant as in `[10u8; _]`.
2344    Infer,
2345}
2346
2347impl ConstantKind {
2348    pub(crate) fn expr(&self, tcx: TyCtxt<'_>) -> String {
2349        match *self {
2350            ConstantKind::TyConst { ref expr } => expr.to_string(),
2351            ConstantKind::Path { ref path } => path.to_string(),
2352            ConstantKind::Extern { def_id } => print_inlined_const(tcx, def_id),
2353            ConstantKind::Local { body, .. } | ConstantKind::Anonymous { body } => {
2354                rendered_const(tcx, tcx.hir_body(body), tcx.hir_body_owner_def_id(body))
2355            }
2356            ConstantKind::Infer => "_".to_string(),
2357        }
2358    }
2359
2360    pub(crate) fn value(&self, tcx: TyCtxt<'_>) -> Option<String> {
2361        match *self {
2362            ConstantKind::TyConst { .. }
2363            | ConstantKind::Path { .. }
2364            | ConstantKind::Anonymous { .. }
2365            | ConstantKind::Infer => None,
2366            ConstantKind::Extern { def_id } | ConstantKind::Local { def_id, .. } => {
2367                print_evaluated_const(tcx, def_id, true, true)
2368            }
2369        }
2370    }
2371
2372    pub(crate) fn is_literal(&self, tcx: TyCtxt<'_>) -> bool {
2373        match *self {
2374            ConstantKind::TyConst { .. }
2375            | ConstantKind::Extern { .. }
2376            | ConstantKind::Path { .. }
2377            | ConstantKind::Infer => false,
2378            ConstantKind::Local { body, .. } | ConstantKind::Anonymous { body } => {
2379                is_literal_expr(tcx, body.hir_id)
2380            }
2381        }
2382    }
2383}
2384
2385#[derive(Clone, Debug)]
2386pub(crate) struct Impl {
2387    pub(crate) safety: hir::Safety,
2388    pub(crate) generics: Generics,
2389    pub(crate) trait_: Option<Path>,
2390    pub(crate) for_: Type,
2391    pub(crate) items: Vec<Item>,
2392    pub(crate) polarity: ty::ImplPolarity,
2393    pub(crate) kind: ImplKind,
2394    pub(crate) is_deprecated: bool,
2395}
2396
2397impl Impl {
2398    pub(crate) fn provided_trait_methods(&self, tcx: TyCtxt<'_>) -> FxIndexSet<Symbol> {
2399        self.trait_
2400            .as_ref()
2401            .map(|t| t.def_id())
2402            .map(|did| tcx.provided_trait_methods(did).map(|meth| meth.name()).collect())
2403            .unwrap_or_default()
2404    }
2405
2406    pub(crate) fn is_negative_trait_impl(&self) -> bool {
2407        matches!(self.polarity, ty::ImplPolarity::Negative)
2408    }
2409}
2410
2411#[derive(Clone, Debug)]
2412pub(crate) enum ImplKind {
2413    Normal,
2414    Auto,
2415    FakeVariadic,
2416    Blanket(Box<Type>),
2417}
2418
2419impl ImplKind {
2420    pub(crate) fn is_auto(&self) -> bool {
2421        matches!(self, ImplKind::Auto)
2422    }
2423
2424    pub(crate) fn is_blanket(&self) -> bool {
2425        matches!(self, ImplKind::Blanket(_))
2426    }
2427
2428    pub(crate) fn is_fake_variadic(&self) -> bool {
2429        matches!(self, ImplKind::FakeVariadic)
2430    }
2431
2432    pub(crate) fn as_blanket_ty(&self) -> Option<&Type> {
2433        match self {
2434            ImplKind::Blanket(ty) => Some(ty),
2435            _ => None,
2436        }
2437    }
2438}
2439
2440#[derive(Clone, Debug)]
2441pub(crate) struct Import {
2442    pub(crate) kind: ImportKind,
2443    /// The item being re-exported.
2444    pub(crate) source: ImportSource,
2445    pub(crate) should_be_displayed: bool,
2446}
2447
2448impl Import {
2449    pub(crate) fn new_simple(
2450        name: Symbol,
2451        source: ImportSource,
2452        should_be_displayed: bool,
2453    ) -> Self {
2454        Self { kind: ImportKind::Simple(name), source, should_be_displayed }
2455    }
2456
2457    pub(crate) fn new_glob(source: ImportSource, should_be_displayed: bool) -> Self {
2458        Self { kind: ImportKind::Glob, source, should_be_displayed }
2459    }
2460
2461    pub(crate) fn imported_item_is_doc_hidden(&self, tcx: TyCtxt<'_>) -> bool {
2462        self.source.did.is_some_and(|did| tcx.is_doc_hidden(did))
2463    }
2464}
2465
2466#[derive(Clone, Debug)]
2467pub(crate) enum ImportKind {
2468    // use source as str;
2469    Simple(Symbol),
2470    // use source::*;
2471    Glob,
2472}
2473
2474#[derive(Clone, Debug)]
2475pub(crate) struct ImportSource {
2476    pub(crate) path: Path,
2477    pub(crate) did: Option<DefId>,
2478}
2479
2480#[derive(Clone, Debug)]
2481pub(crate) struct Macro {
2482    pub(crate) source: String,
2483    /// Whether the macro was defined via `macro_rules!` as opposed to `macro`.
2484    pub(crate) macro_rules: bool,
2485}
2486
2487#[derive(Clone, Debug)]
2488pub(crate) struct ProcMacro {
2489    pub(crate) kind: MacroKind,
2490    pub(crate) helpers: Vec<Symbol>,
2491}
2492
2493/// A constraint on an associated item.
2494///
2495/// ### Examples
2496///
2497/// * the `A = Ty` and `B = Ty` in `Trait<A = Ty, B = Ty>`
2498/// * the `G<Ty> = Ty` in `Trait<G<Ty> = Ty>`
2499/// * the `A: Bound` in `Trait<A: Bound>`
2500/// * the `RetTy` in `Trait(ArgTy, ArgTy) -> RetTy`
2501/// * the `C = { Ct }` in `Trait<C = { Ct }>` (feature `associated_const_equality`)
2502/// * the `f(..): Bound` in `Trait<f(..): Bound>` (feature `return_type_notation`)
2503#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2504pub(crate) struct AssocItemConstraint {
2505    pub(crate) assoc: PathSegment,
2506    pub(crate) kind: AssocItemConstraintKind,
2507}
2508
2509/// The kind of [associated item constraint][AssocItemConstraint].
2510#[derive(Clone, PartialEq, Eq, Debug, Hash)]
2511pub(crate) enum AssocItemConstraintKind {
2512    Equality { term: Term },
2513    Bound { bounds: Vec<GenericBound> },
2514}
2515
2516// Some nodes are used a lot. Make sure they don't unintentionally get bigger.
2517#[cfg(target_pointer_width = "64")]
2518mod size_asserts {
2519    use rustc_data_structures::static_assert_size;
2520
2521    use super::*;
2522    // tidy-alphabetical-start
2523    static_assert_size!(Crate, 16); // frequently moved by-value
2524    static_assert_size!(DocFragment, 48);
2525    static_assert_size!(GenericArg, 32);
2526    static_assert_size!(GenericArgs, 24);
2527    static_assert_size!(GenericParamDef, 40);
2528    static_assert_size!(Generics, 16);
2529    static_assert_size!(Item, 8);
2530    static_assert_size!(ItemInner, 136);
2531    static_assert_size!(ItemKind, 48);
2532    static_assert_size!(PathSegment, 32);
2533    static_assert_size!(Type, 32);
2534    // tidy-alphabetical-end
2535}