[go: up one dir, main page]

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