rustdoc/clean/
types.rs

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