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