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