[go: up one dir, main page]

rustdoc/clean/
types.rs

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