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