Skip to main content

rustdoc/clean/
types.rs

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