rustdoc/clean/
types.rs

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