Skip to main content

rustdoc/clean/
types.rs

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