[go: up one dir, main page]

rustdoc/clean/
types.rs

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