Skip to main content

rustdoc/clean/
types.rs

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