rustdoc/clean/
types.rs

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