1 use std::cell::RefCell;
2 use std::default::Default;
4 use std::path::PathBuf;
7 use std::sync::OnceLock as OnceCell;
8 use std::{cmp, fmt, iter};
10 use arrayvec::ArrayVec;
11 use thin_vec::ThinVec;
13 use rustc_ast::util::comments::beautify_doc_string;
14 use rustc_ast::{self as ast, AttrStyle};
15 use rustc_attr::{ConstStability, Deprecation, Stability, StabilityLevel};
16 use rustc_const_eval::const_eval::is_unstable_const_fn;
17 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
19 use rustc_hir::def::{CtorKind, DefKind, Res};
20 use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
21 use rustc_hir::lang_items::LangItem;
22 use rustc_hir::{BodyId, Mutability};
23 use rustc_hir_analysis::check::intrinsic::intrinsic_operation_unsafety;
24 use rustc_index::vec::IndexVec;
25 use rustc_middle::ty::fast_reject::SimplifiedType;
26 use rustc_middle::ty::{self, DefIdTree, TyCtxt, Visibility};
27 use rustc_session::Session;
28 use rustc_span::hygiene::MacroKind;
29 use rustc_span::symbol::{kw, sym, Ident, Symbol};
30 use rustc_span::{self, FileName, Loc};
31 use rustc_target::abi::VariantIdx;
32 use rustc_target::spec::abi::Abi;
34 use crate::clean::cfg::Cfg;
35 use crate::clean::external_path;
36 use crate::clean::inline::{self, print_inlined_const};
37 use crate::clean::utils::{is_literal_expr, print_const_expr, print_evaluated_const};
38 use crate::core::DocContext;
39 use crate::formats::cache::Cache;
40 use crate::formats::item_type::ItemType;
41 use crate::html::render::Context;
42 use crate::passes::collect_intra_doc_links::UrlFragment;
44 pub(crate) use self::FnRetTy::*;
45 pub(crate) use self::ItemKind::*;
46 pub(crate) use self::SelfTy::*;
47 pub(crate) use self::Type::{
48 Array, BareFunction, BorrowedRef, DynTrait, Generic, ImplTrait, Infer, Primitive, QPath,
49 RawPointer, Slice, Tuple,
55 pub(crate) type ItemIdSet = FxHashSet<ItemId>;
57 #[derive(Debug, Clone, PartialEq, Eq, Hash, Copy)]
58 pub(crate) enum ItemId {
59 /// A "normal" item that uses a [`DefId`] for identification.
61 /// Identifier that is used for auto traits.
62 Auto { trait_: DefId, for_: DefId },
63 /// Identifier that is used for blanket implementations.
64 Blanket { impl_id: DefId, for_: DefId },
65 /// Identifier for primitive types.
66 Primitive(PrimitiveType, CrateNum),
71 pub(crate) fn is_local(self) -> bool {
73 ItemId::Auto { for_: id, .. }
74 | ItemId::Blanket { for_: id, .. }
75 | ItemId::DefId(id) => id.is_local(),
76 ItemId::Primitive(_, krate) => krate == LOCAL_CRATE,
82 pub(crate) fn expect_def_id(self) -> DefId {
84 .unwrap_or_else(|| panic!("ItemId::expect_def_id: `{:?}` isn't a DefId", self))
88 pub(crate) fn as_def_id(self) -> Option<DefId> {
90 ItemId::DefId(id) => Some(id),
96 pub(crate) fn krate(self) -> CrateNum {
98 ItemId::Auto { for_: id, .. }
99 | ItemId::Blanket { for_: id, .. }
100 | ItemId::DefId(id) => id.krate,
101 ItemId::Primitive(_, krate) => krate,
106 impl From<DefId> for ItemId {
107 fn from(id: DefId) -> Self {
112 /// The crate currently being documented.
113 #[derive(Clone, Debug)]
114 pub(crate) struct Crate {
115 pub(crate) module: Item,
116 /// Only here so that they can be filtered through the rustdoc passes.
117 pub(crate) external_traits: Rc<RefCell<FxHashMap<DefId, Trait>>>,
121 pub(crate) fn name(&self, tcx: TyCtxt<'_>) -> Symbol {
122 ExternalCrate::LOCAL.name(tcx)
125 pub(crate) fn src(&self, tcx: TyCtxt<'_>) -> FileName {
126 ExternalCrate::LOCAL.src(tcx)
130 #[derive(Copy, Clone, Debug)]
131 pub(crate) struct ExternalCrate {
132 pub(crate) crate_num: CrateNum,
136 const LOCAL: Self = Self { crate_num: LOCAL_CRATE };
139 pub(crate) fn def_id(&self) -> DefId {
140 self.crate_num.as_def_id()
143 pub(crate) fn src(&self, tcx: TyCtxt<'_>) -> FileName {
144 let krate_span = tcx.def_span(self.def_id());
145 tcx.sess.source_map().span_to_filename(krate_span)
148 pub(crate) fn name(&self, tcx: TyCtxt<'_>) -> Symbol {
149 tcx.crate_name(self.crate_num)
152 pub(crate) fn src_root(&self, tcx: TyCtxt<'_>) -> PathBuf {
153 match self.src(tcx) {
154 FileName::Real(ref p) => match p.local_path_if_available().parent() {
155 Some(p) => p.to_path_buf(),
156 None => PathBuf::new(),
162 /// Attempts to find where an external crate is located, given that we're
163 /// rendering in to the specified source destination.
164 pub(crate) fn location(
166 extern_url: Option<&str>,
167 extern_url_takes_precedence: bool,
168 dst: &std::path::Path,
170 ) -> ExternalLocation {
171 use ExternalLocation::*;
173 fn to_remote(url: impl ToString) -> ExternalLocation {
174 let mut url = url.to_string();
175 if !url.ends_with('/') {
181 // See if there's documentation generated into the local directory
182 // WARNING: since rustdoc creates these directories as it generates documentation, this check is only accurate before rendering starts.
183 // Make sure to call `location()` by that time.
184 let local_location = dst.join(self.name(tcx).as_str());
185 if local_location.is_dir() {
189 if extern_url_takes_precedence {
190 if let Some(url) = extern_url {
191 return to_remote(url);
195 // Failing that, see if there's an attribute specifying where to find this
197 let did = self.crate_num.as_def_id();
198 tcx.get_attrs(did, sym::doc)
199 .flat_map(|attr| attr.meta_item_list().unwrap_or_default())
200 .filter(|a| a.has_name(sym::html_root_url))
201 .filter_map(|a| a.value_str())
204 .or_else(|| extern_url.map(to_remote)) // NOTE: only matters if `extern_url_takes_precedence` is false
205 .unwrap_or(Unknown) // Well, at least we tried.
208 pub(crate) fn keywords(&self, tcx: TyCtxt<'_>) -> ThinVec<(DefId, Symbol)> {
209 let root = self.def_id();
211 let as_keyword = |res: Res<!>| {
212 if let Res::Def(DefKind::Mod, def_id) = res {
213 let mut keyword = None;
215 .get_attrs(def_id, sym::doc)
216 .flat_map(|attr| attr.meta_item_list().unwrap_or_default());
217 for meta in meta_items {
218 if meta.has_name(sym::keyword) {
219 if let Some(v) = meta.value_str() {
225 return keyword.map(|p| (def_id, p));
235 let item = tcx.hir().item(id);
237 hir::ItemKind::Mod(_) => {
238 as_keyword(Res::Def(DefKind::Mod, id.owner_id.to_def_id()))
240 hir::ItemKind::Use(path, hir::UseKind::Single)
241 if tcx.visibility(id.owner_id).is_public() =>
245 .find_map(|res| as_keyword(res.expect_non_local()))
246 .map(|(_, prim)| (id.owner_id.to_def_id(), prim))
253 tcx.module_children(root).iter().map(|item| item.res).filter_map(as_keyword).collect()
257 pub(crate) fn primitives(&self, tcx: TyCtxt<'_>) -> ThinVec<(DefId, PrimitiveType)> {
258 let root = self.def_id();
260 // Collect all inner modules which are tagged as implementations of
263 // Note that this loop only searches the top-level items of the crate,
264 // and this is intentional. If we were to search the entire crate for an
265 // item tagged with `#[doc(primitive)]` then we would also have to
266 // search the entirety of external modules for items tagged
267 // `#[doc(primitive)]`, which is a pretty inefficient process (decoding
268 // all that metadata unconditionally).
270 // In order to keep the metadata load under control, the
271 // `#[doc(primitive)]` feature is explicitly designed to only allow the
272 // primitive tags to show up as the top level items in a crate.
274 // Also note that this does not attempt to deal with modules tagged
275 // duplicately for the same primitive. This is handled later on when
276 // rendering by delegating everything to a hash map.
277 let as_primitive = |res: Res<!>| {
278 if let Res::Def(DefKind::Mod, def_id) = res {
281 .get_attrs(def_id, sym::doc)
282 .flat_map(|attr| attr.meta_item_list().unwrap_or_default());
283 for meta in meta_items {
284 if let Some(v) = meta.value_str() {
285 if meta.has_name(sym::primitive) {
286 prim = PrimitiveType::from_symbol(v);
290 // FIXME: should warn on unknown primitives?
294 return prim.map(|p| (def_id, p));
305 let item = tcx.hir().item(id);
307 hir::ItemKind::Mod(_) => {
308 as_primitive(Res::Def(DefKind::Mod, id.owner_id.to_def_id()))
310 hir::ItemKind::Use(path, hir::UseKind::Single)
311 if tcx.visibility(id.owner_id).is_public() =>
315 .find_map(|res| as_primitive(res.expect_non_local()))
316 // Pretend the primitive is local.
317 .map(|(_, prim)| (id.owner_id.to_def_id(), prim))
324 tcx.module_children(root).iter().map(|item| item.res).filter_map(as_primitive).collect()
329 /// Indicates where an external crate can be found.
331 pub(crate) enum ExternalLocation {
332 /// Remote URL root of the external crate
334 /// This external crate can be found in the local doc/ folder
336 /// The external crate could not be found.
340 /// Anything with a source location and set of attributes and, optionally, a
341 /// name. That is, anything that can be documented. This doesn't correspond
342 /// directly to the AST's concept of an item; it's a strict superset.
344 pub(crate) struct Item {
345 /// The name of this item.
346 /// Optional because not every item has a name, e.g. impls.
347 pub(crate) name: Option<Symbol>,
348 pub(crate) attrs: Box<Attributes>,
349 /// Information about this item that is specific to what kind of item it is.
350 /// E.g., struct vs enum vs function.
351 pub(crate) kind: Box<ItemKind>,
352 pub(crate) item_id: ItemId,
353 /// This is the `DefId` of the `use` statement if the item was inlined.
354 pub(crate) inline_stmt_id: Option<DefId>,
355 pub(crate) cfg: Option<Arc<Cfg>>,
358 /// NOTE: this does NOT unconditionally print every item, to avoid thousands of lines of logs.
359 /// If you want to see the debug output for attributes and the `kind` as well, use `{:#?}` instead of `{:?}`.
360 impl fmt::Debug for Item {
361 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
362 let alternate = f.alternate();
363 // hand-picked fields that don't bloat the logs too much
364 let mut fmt = f.debug_struct("Item");
365 fmt.field("name", &self.name).field("item_id", &self.item_id);
366 // allow printing the full item if someone really wants to
368 fmt.field("attrs", &self.attrs).field("kind", &self.kind).field("cfg", &self.cfg);
370 fmt.field("kind", &self.type_());
371 fmt.field("docs", &self.doc_value());
377 pub(crate) fn rustc_span(def_id: DefId, tcx: TyCtxt<'_>) -> Span {
378 Span::new(def_id.as_local().map_or_else(
379 || tcx.def_span(def_id),
382 hir.span_with_body(hir.local_def_id_to_hir_id(local))
387 fn is_field_vis_inherited(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
388 let parent = tcx.parent(def_id);
389 match tcx.def_kind(parent) {
390 DefKind::Struct | DefKind::Union => false,
391 DefKind::Variant => true,
392 parent_kind => panic!("unexpected parent kind: {:?}", parent_kind),
397 pub(crate) fn stability<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Option<Stability> {
398 self.item_id.as_def_id().and_then(|did| tcx.lookup_stability(did))
401 pub(crate) fn const_stability<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Option<ConstStability> {
402 self.item_id.as_def_id().and_then(|did| tcx.lookup_const_stability(did))
405 pub(crate) fn deprecation(&self, tcx: TyCtxt<'_>) -> Option<Deprecation> {
406 self.item_id.as_def_id().and_then(|did| tcx.lookup_deprecation(did))
409 pub(crate) fn inner_docs(&self, tcx: TyCtxt<'_>) -> bool {
412 .map(|did| tcx.get_attrs_unchecked(did).inner_docs())
416 pub(crate) fn span(&self, tcx: TyCtxt<'_>) -> Option<Span> {
417 let kind = match &*self.kind {
418 ItemKind::StrippedItem(k) => k,
422 ItemKind::ModuleItem(Module { span, .. }) => Some(*span),
423 ItemKind::ImplItem(box Impl { kind: ImplKind::Auto, .. }) => None,
424 ItemKind::ImplItem(box Impl { kind: ImplKind::Blanket(_), .. }) => {
425 if let ItemId::Blanket { impl_id, .. } = self.item_id {
426 Some(rustc_span(impl_id, tcx))
428 panic!("blanket impl item has non-blanket ID")
431 _ => self.item_id.as_def_id().map(|did| rustc_span(did, tcx)),
435 pub(crate) fn attr_span(&self, tcx: TyCtxt<'_>) -> rustc_span::Span {
436 crate::passes::span_of_attrs(&self.attrs)
437 .unwrap_or_else(|| self.span(tcx).map_or(rustc_span::DUMMY_SP, |span| span.inner()))
440 /// Finds the `doc` attribute as a NameValue and returns the corresponding
442 pub(crate) fn doc_value(&self) -> Option<String> {
443 self.attrs.doc_value()
446 /// Convenience wrapper around [`Self::from_def_id_and_parts`] which converts
447 /// `hir_id` to a [`DefId`]
448 pub(crate) fn from_hir_id_and_parts(
450 name: Option<Symbol>,
452 cx: &mut DocContext<'_>,
454 Item::from_def_id_and_parts(cx.tcx.hir().local_def_id(hir_id).to_def_id(), name, kind, cx)
457 pub(crate) fn from_def_id_and_parts(
459 name: Option<Symbol>,
461 cx: &mut DocContext<'_>,
463 let ast_attrs = cx.tcx.get_attrs_unchecked(def_id);
465 Self::from_def_id_and_attrs_and_parts(
469 Box::new(Attributes::from_ast(ast_attrs)),
470 ast_attrs.cfg(cx.tcx, &cx.cache.hidden_cfg),
474 pub(crate) fn from_def_id_and_attrs_and_parts(
476 name: Option<Symbol>,
478 attrs: Box<Attributes>,
479 cfg: Option<Arc<Cfg>>,
481 trace!("name={:?}, def_id={:?} cfg={:?}", name, def_id, cfg);
484 item_id: def_id.into(),
485 kind: Box::new(kind),
489 inline_stmt_id: None,
493 /// Finds all `doc` attributes as NameValues and returns their corresponding values, joined
495 pub(crate) fn collapsed_doc_value(&self) -> Option<String> {
496 self.attrs.collapsed_doc_value()
499 pub(crate) fn links(&self, cx: &Context<'_>) -> Vec<RenderedLink> {
500 use crate::html::format::href;
505 .map_or(&[][..], |v| v.as_slice())
507 .filter_map(|ItemLink { link: s, link_text, page_id: did, ref fragment }| {
509 if let Ok((mut href, ..)) = href(*did, cx) {
511 if let Some(ref fragment) = *fragment {
512 fragment.render(&mut href, cx.tcx())
515 original_text: s.clone(),
516 new_text: link_text.clone(),
526 /// Find a list of all link names, without finding their href.
528 /// This is used for generating summary text, which does not include
529 /// the link text, but does need to know which `[]`-bracketed names
530 /// are actually links.
531 pub(crate) fn link_names(&self, cache: &Cache) -> Vec<RenderedLink> {
535 .map_or(&[][..], |v| v.as_slice())
537 .map(|ItemLink { link: s, link_text, .. }| RenderedLink {
538 original_text: s.clone(),
539 new_text: link_text.clone(),
545 pub(crate) fn is_crate(&self) -> bool {
546 self.is_mod() && self.item_id.as_def_id().map_or(false, |did| did.is_crate_root())
548 pub(crate) fn is_mod(&self) -> bool {
549 self.type_() == ItemType::Module
551 pub(crate) fn is_trait(&self) -> bool {
552 self.type_() == ItemType::Trait
554 pub(crate) fn is_struct(&self) -> bool {
555 self.type_() == ItemType::Struct
557 pub(crate) fn is_enum(&self) -> bool {
558 self.type_() == ItemType::Enum
560 pub(crate) fn is_variant(&self) -> bool {
561 self.type_() == ItemType::Variant
563 pub(crate) fn is_associated_type(&self) -> bool {
564 matches!(&*self.kind, AssocTypeItem(..) | StrippedItem(box AssocTypeItem(..)))
566 pub(crate) fn is_ty_associated_type(&self) -> bool {
567 matches!(&*self.kind, TyAssocTypeItem(..) | StrippedItem(box TyAssocTypeItem(..)))
569 pub(crate) fn is_associated_const(&self) -> bool {
570 matches!(&*self.kind, AssocConstItem(..) | StrippedItem(box AssocConstItem(..)))
572 pub(crate) fn is_ty_associated_const(&self) -> bool {
573 matches!(&*self.kind, TyAssocConstItem(..) | StrippedItem(box TyAssocConstItem(..)))
575 pub(crate) fn is_method(&self) -> bool {
576 self.type_() == ItemType::Method
578 pub(crate) fn is_ty_method(&self) -> bool {
579 self.type_() == ItemType::TyMethod
581 pub(crate) fn is_typedef(&self) -> bool {
582 self.type_() == ItemType::Typedef
584 pub(crate) fn is_primitive(&self) -> bool {
585 self.type_() == ItemType::Primitive
587 pub(crate) fn is_union(&self) -> bool {
588 self.type_() == ItemType::Union
590 pub(crate) fn is_import(&self) -> bool {
591 self.type_() == ItemType::Import
593 pub(crate) fn is_extern_crate(&self) -> bool {
594 self.type_() == ItemType::ExternCrate
596 pub(crate) fn is_keyword(&self) -> bool {
597 self.type_() == ItemType::Keyword
599 pub(crate) fn is_stripped(&self) -> bool {
601 StrippedItem(..) => true,
602 ImportItem(ref i) => !i.should_be_displayed,
606 pub(crate) fn has_stripped_entries(&self) -> Option<bool> {
608 StructItem(ref struct_) => Some(struct_.has_stripped_entries()),
609 UnionItem(ref union_) => Some(union_.has_stripped_entries()),
610 EnumItem(ref enum_) => Some(enum_.has_stripped_entries()),
611 VariantItem(ref v) => v.has_stripped_entries(),
616 pub(crate) fn stability_class(&self, tcx: TyCtxt<'_>) -> Option<String> {
617 self.stability(tcx).as_ref().and_then(|s| {
618 let mut classes = Vec::with_capacity(2);
621 classes.push("unstable");
624 // FIXME: what about non-staged API items that are deprecated?
625 if self.deprecation(tcx).is_some() {
626 classes.push("deprecated");
629 if !classes.is_empty() { Some(classes.join(" ")) } else { None }
633 pub(crate) fn stable_since(&self, tcx: TyCtxt<'_>) -> Option<Symbol> {
634 match self.stability(tcx)?.level {
635 StabilityLevel::Stable { since, .. } => Some(since),
636 StabilityLevel::Unstable { .. } => None,
640 pub(crate) fn const_stable_since(&self, tcx: TyCtxt<'_>) -> Option<Symbol> {
641 match self.const_stability(tcx)?.level {
642 StabilityLevel::Stable { since, .. } => Some(since),
643 StabilityLevel::Unstable { .. } => None,
647 pub(crate) fn is_non_exhaustive(&self) -> bool {
648 self.attrs.other_attrs.iter().any(|a| a.has_name(sym::non_exhaustive))
651 /// Returns a documentation-level item type from the item.
652 pub(crate) fn type_(&self) -> ItemType {
656 pub(crate) fn is_default(&self) -> bool {
658 ItemKind::MethodItem(_, Some(defaultness)) => {
659 defaultness.has_value() && !defaultness.is_final()
665 /// Returns a `FnHeader` if `self` is a function item, otherwise returns `None`.
666 pub(crate) fn fn_header(&self, tcx: TyCtxt<'_>) -> Option<hir::FnHeader> {
670 asyncness: hir::IsAsync,
672 let sig = tcx.fn_sig(def_id);
674 if tcx.is_const_fn(def_id) && is_unstable_const_fn(tcx, def_id).is_none() {
675 hir::Constness::Const
677 hir::Constness::NotConst
679 hir::FnHeader { unsafety: sig.unsafety(), abi: sig.abi(), constness, asyncness }
681 let header = match *self.kind {
682 ItemKind::ForeignFunctionItem(_) => {
683 let abi = tcx.fn_sig(self.item_id.as_def_id().unwrap()).abi();
685 unsafety: if abi == Abi::RustIntrinsic {
686 intrinsic_operation_unsafety(tcx, self.item_id.as_def_id().unwrap())
688 hir::Unsafety::Unsafe
691 constness: hir::Constness::NotConst,
692 asyncness: hir::IsAsync::NotAsync,
695 ItemKind::FunctionItem(_) | ItemKind::MethodItem(_, _) | ItemKind::TyMethodItem(_) => {
696 let def_id = self.item_id.as_def_id().unwrap();
697 build_fn_header(def_id, tcx, tcx.asyncness(def_id))
704 /// Returns the visibility of the current item. If the visibility is "inherited", then `None`
706 pub(crate) fn visibility(&self, tcx: TyCtxt<'_>) -> Option<Visibility<DefId>> {
707 let def_id = match self.item_id {
708 // Anything but DefId *shouldn't* matter, but return a reasonable value anyway.
709 ItemId::Auto { .. } | ItemId::Blanket { .. } => return None,
710 // Primitives and Keywords are written in the source code as private modules.
711 // The modules need to be private so that nobody actually uses them, but the
712 // keywords and primitives that they are documenting are public.
713 ItemId::Primitive(..) => return Some(Visibility::Public),
714 ItemId::DefId(def_id) => def_id,
718 // Explication on `ItemId::Primitive` just above.
719 ItemKind::KeywordItem | ItemKind::PrimitiveItem(_) => return Some(Visibility::Public),
720 // Variant fields inherit their enum's visibility.
721 StructFieldItem(..) if is_field_vis_inherited(tcx, def_id) => {
724 // Variants always inherit visibility
725 VariantItem(..) => return None,
726 // Trait items inherit the trait's visibility
727 AssocConstItem(..) | TyAssocConstItem(..) | AssocTypeItem(..) | TyAssocTypeItem(..)
728 | TyMethodItem(..) | MethodItem(..) => {
729 let assoc_item = tcx.associated_item(def_id);
730 let is_trait_item = match assoc_item.container {
731 ty::TraitContainer => true,
732 ty::ImplContainer => {
733 // Trait impl items always inherit the impl's visibility --
734 // we don't want to show `pub`.
735 tcx.impl_trait_ref(tcx.parent(assoc_item.def_id)).is_some()
744 let def_id = match self.inline_stmt_id {
745 Some(inlined) => inlined,
748 Some(tcx.visibility(def_id))
752 #[derive(Clone, Debug)]
753 pub(crate) enum ItemKind {
755 /// The crate's name, *not* the name it's imported as.
762 FunctionItem(Box<Function>),
764 TypedefItem(Box<Typedef>),
765 OpaqueTyItem(OpaqueTy),
767 ConstantItem(Constant),
768 TraitItem(Box<Trait>),
769 TraitAliasItem(TraitAlias),
771 /// A required method in a trait declaration meaning it's only a function signature.
772 TyMethodItem(Box<Function>),
773 /// A method in a trait impl or a provided method in a trait declaration.
775 /// Compared to [TyMethodItem], it also contains a method body.
776 MethodItem(Box<Function>, Option<hir::Defaultness>),
777 StructFieldItem(Type),
778 VariantItem(Variant),
779 /// `fn`s from an extern block
780 ForeignFunctionItem(Box<Function>),
781 /// `static`s from an extern block
782 ForeignStaticItem(Static),
783 /// `type`s from an extern block
786 ProcMacroItem(ProcMacro),
787 PrimitiveItem(PrimitiveType),
788 /// A required associated constant in a trait declaration.
789 TyAssocConstItem(Type),
790 /// An associated associated constant in a trait impl or a provided one in a trait declaration.
791 AssocConstItem(Type, ConstantKind),
792 /// A required associated type in a trait declaration.
794 /// The bounds may be non-empty if there is a `where` clause.
795 TyAssocTypeItem(Generics, Vec<GenericBound>),
796 /// An associated type in a trait impl or a provided one in a trait declaration.
797 AssocTypeItem(Box<Typedef>, Vec<GenericBound>),
798 /// An item that has been stripped by a rustdoc pass
799 StrippedItem(Box<ItemKind>),
804 /// Some items contain others such as structs (for their fields) and Enums
805 /// (for their variants). This method returns those contained items.
806 pub(crate) fn inner_items(&self) -> impl Iterator<Item = &Item> {
808 StructItem(s) => s.fields.iter(),
809 UnionItem(u) => u.fields.iter(),
810 VariantItem(v) => match &v.kind {
811 VariantKind::CLike => [].iter(),
812 VariantKind::Tuple(t) => t.iter(),
813 VariantKind::Struct(s) => s.fields.iter(),
815 EnumItem(e) => e.variants.iter(),
816 TraitItem(t) => t.items.iter(),
817 ImplItem(i) => i.items.iter(),
818 ModuleItem(m) => m.items.iter(),
819 ExternCrateItem { .. }
830 | ForeignFunctionItem(_)
831 | ForeignStaticItem(_)
836 | TyAssocConstItem(_)
837 | AssocConstItem(_, _)
838 | TyAssocTypeItem(..)
841 | KeywordItem => [].iter(),
845 /// Returns `true` if this item does not appear inside an impl block.
846 pub(crate) fn is_non_assoc(&self) -> bool {
854 | ExternCrateItem { .. }
861 | ForeignFunctionItem(_)
862 | ForeignStaticItem(_)
871 #[derive(Clone, Debug)]
872 pub(crate) struct Module {
873 pub(crate) items: Vec<Item>,
874 pub(crate) span: Span,
877 pub(crate) trait AttributesExt {
878 type AttributeIterator<'a>: Iterator<Item = ast::NestedMetaItem>
882 fn lists<'a>(&'a self, name: Symbol) -> Self::AttributeIterator<'a>;
884 fn span(&self) -> Option<rustc_span::Span>;
886 fn inner_docs(&self) -> bool;
888 fn cfg(&self, tcx: TyCtxt<'_>, hidden_cfg: &FxHashSet<Cfg>) -> Option<Arc<Cfg>>;
891 impl AttributesExt for [ast::Attribute] {
892 type AttributeIterator<'a> = impl Iterator<Item = ast::NestedMetaItem> + 'a;
894 fn lists<'a>(&'a self, name: Symbol) -> Self::AttributeIterator<'a> {
896 .filter(move |attr| attr.has_name(name))
897 .filter_map(ast::Attribute::meta_item_list)
901 /// Return the span of the first doc-comment, if it exists.
902 fn span(&self) -> Option<rustc_span::Span> {
903 self.iter().find(|attr| attr.doc_str().is_some()).map(|attr| attr.span)
906 /// Returns whether the first doc-comment is an inner attribute.
908 //// If there are no doc-comments, return true.
909 /// FIXME(#78591): Support both inner and outer attributes on the same item.
910 fn inner_docs(&self) -> bool {
911 self.iter().find(|a| a.doc_str().is_some()).map_or(true, |a| a.style == AttrStyle::Inner)
914 fn cfg(&self, tcx: TyCtxt<'_>, hidden_cfg: &FxHashSet<Cfg>) -> Option<Arc<Cfg>> {
916 let doc_cfg_active = tcx.features().doc_cfg;
917 let doc_auto_cfg_active = tcx.features().doc_auto_cfg;
919 fn single<T: IntoIterator>(it: T) -> Option<T::Item> {
920 let mut iter = it.into_iter();
921 let item = iter.next()?;
922 if iter.next().is_some() {
928 let mut cfg = if doc_cfg_active || doc_auto_cfg_active {
929 let mut doc_cfg = self
931 .filter(|attr| attr.has_name(sym::doc))
932 .flat_map(|attr| attr.meta_item_list().unwrap_or_default())
933 .filter(|attr| attr.has_name(sym::cfg))
935 if doc_cfg.peek().is_some() && doc_cfg_active {
937 .filter_map(|attr| Cfg::parse(attr.meta_item()?).ok())
938 .fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg)
939 } else if doc_auto_cfg_active {
941 .filter(|attr| attr.has_name(sym::cfg))
942 .filter_map(|attr| single(attr.meta_item_list()?))
944 Cfg::parse_without(attr.meta_item()?, hidden_cfg).ok().flatten()
946 .fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg)
954 for attr in self.iter() {
956 if attr.doc_str().is_none() && attr.has_name(sym::doc) {
958 if let Some(list) = attr.meta().as_ref().and_then(|mi| mi.meta_item_list()) {
961 if !item.has_name(sym::cfg) {
965 if let Some(cfg_mi) = item
967 .and_then(|item| rustc_expand::config::parse_cfg(item, sess))
969 match Cfg::parse(cfg_mi) {
970 Ok(new_cfg) => cfg &= new_cfg,
972 sess.span_err(e.span, e.msg);
981 // treat #[target_feature(enable = "feat")] attributes as if they were
982 // #[doc(cfg(target_feature = "feat"))] attributes as well
983 for attr in self.lists(sym::target_feature) {
984 if attr.has_name(sym::enable) {
985 if attr.value_str().is_some() {
986 // Clone `enable = "feat"`, change to `target_feature = "feat"`.
987 // Unwrap is safe because `value_str` succeeded above.
988 let mut meta = attr.meta_item().unwrap().clone();
989 meta.path = ast::Path::from_ident(Ident::with_dummy_span(sym::target_feature));
991 if let Ok(feat_cfg) = Cfg::parse(&meta) {
998 if cfg == Cfg::True { None } else { Some(Arc::new(cfg)) }
1002 pub(crate) trait NestedAttributesExt {
1003 /// Returns `true` if the attribute list contains a specific `word`
1004 fn has_word(self, word: Symbol) -> bool
1006 Self: std::marker::Sized,
1008 <Self as NestedAttributesExt>::get_word_attr(self, word).is_some()
1011 /// Returns `Some(attr)` if the attribute list contains 'attr'
1012 /// corresponding to a specific `word`
1013 fn get_word_attr(self, word: Symbol) -> Option<ast::NestedMetaItem>;
1016 impl<I: Iterator<Item = ast::NestedMetaItem>> NestedAttributesExt for I {
1017 fn get_word_attr(mut self, word: Symbol) -> Option<ast::NestedMetaItem> {
1018 self.find(|attr| attr.is_word() && attr.has_name(word))
1022 /// A portion of documentation, extracted from a `#[doc]` attribute.
1024 /// Each variant contains the line number within the complete doc-comment where the fragment
1025 /// starts, as well as the Span where the corresponding doc comment or attribute is located.
1027 /// Included files are kept separate from inline doc comments so that proper line-number
1028 /// information can be given when a doctest fails. Sugared doc comments and "raw" doc comments are
1029 /// kept separate because of issue #42760.
1030 #[derive(Clone, PartialEq, Eq, Debug)]
1031 pub(crate) struct DocFragment {
1032 pub(crate) span: rustc_span::Span,
1033 /// The module this doc-comment came from.
1035 /// This allows distinguishing between the original documentation and a pub re-export.
1036 /// If it is `None`, the item was not re-exported.
1037 pub(crate) parent_module: Option<DefId>,
1038 pub(crate) doc: Symbol,
1039 pub(crate) kind: DocFragmentKind,
1040 pub(crate) indent: usize,
1043 #[derive(Clone, Copy, PartialEq, Eq, Debug)]
1044 pub(crate) enum DocFragmentKind {
1045 /// A doc fragment created from a `///` or `//!` doc comment.
1047 /// A doc fragment created from a "raw" `#[doc=""]` attribute.
1051 /// The goal of this function is to apply the `DocFragment` transformation that is required when
1052 /// transforming into the final Markdown, which is applying the computed indent to each line in
1053 /// each doc fragment (a `DocFragment` can contain multiple lines in case of `#[doc = ""]`).
1055 /// Note: remove the trailing newline where appropriate
1056 fn add_doc_fragment(out: &mut String, frag: &DocFragment) {
1057 let s = frag.doc.as_str();
1058 let mut iter = s.lines();
1063 while let Some(line) = iter.next() {
1064 if line.chars().any(|c| !c.is_whitespace()) {
1065 assert!(line.len() >= frag.indent);
1066 out.push_str(&line[frag.indent..]);
1074 /// Collapse a collection of [`DocFragment`]s into one string,
1075 /// handling indentation and newlines as needed.
1076 pub(crate) fn collapse_doc_fragments(doc_strings: &[DocFragment]) -> String {
1077 let mut acc = String::new();
1078 for frag in doc_strings {
1079 add_doc_fragment(&mut acc, frag);
1085 /// Removes excess indentation on comments in order for the Markdown
1086 /// to be parsed correctly. This is necessary because the convention for
1087 /// writing documentation is to provide a space between the /// or //! marker
1088 /// and the doc text, but Markdown is whitespace-sensitive. For example,
1089 /// a block of text with four-space indentation is parsed as a code block,
1090 /// so if we didn't unindent comments, these list items
1097 /// would be parsed as if they were in a code block, which is likely not what the user intended.
1098 fn unindent_doc_fragments(docs: &mut Vec<DocFragment>) {
1099 // `add` is used in case the most common sugared doc syntax is used ("/// "). The other
1100 // fragments kind's lines are never starting with a whitespace unless they are using some
1101 // markdown formatting requiring it. Therefore, if the doc block have a mix between the two,
1102 // we need to take into account the fact that the minimum indent minus one (to take this
1103 // whitespace into account).
1108 // #[doc = "another"]
1110 // In this case, you want "hello! another" and not "hello! another".
1111 let add = if docs.windows(2).any(|arr| arr[0].kind != arr[1].kind)
1112 && docs.iter().any(|d| d.kind == DocFragmentKind::SugaredDoc)
1114 // In case we have a mix of sugared doc comments and "raw" ones, we want the sugared one to
1115 // "decide" how much the minimum indent will be.
1121 // `min_indent` is used to know how much whitespaces from the start of each lines must be
1122 // removed. Example:
1125 // #[doc = "another"]
1127 // In here, the `min_indent` is 1 (because non-sugared fragment are always counted with minimum
1128 // 1 whitespace), meaning that "hello!" will be considered a codeblock because it starts with 4
1129 // (5 - 1) whitespaces.
1130 let Some(min_indent) = docs
1133 fragment.doc.as_str().lines().fold(usize::MAX, |min_indent, line| {
1134 if line.chars().all(|c| c.is_whitespace()) {
1137 // Compare against either space or tab, ignoring whether they are
1139 let whitespace = line.chars().take_while(|c| *c == ' ' || *c == '\t').count();
1140 cmp::min(min_indent, whitespace)
1141 + if fragment.kind == DocFragmentKind::SugaredDoc { 0 } else { add }
1150 for fragment in docs {
1151 if fragment.doc == kw::Empty {
1155 let min_indent = if fragment.kind != DocFragmentKind::SugaredDoc && min_indent > 0 {
1161 fragment.indent = min_indent;
1165 /// A link that has not yet been rendered.
1167 /// This link will be turned into a rendered link by [`Item::links`].
1168 #[derive(Clone, Debug, PartialEq, Eq)]
1169 pub(crate) struct ItemLink {
1170 /// The original link written in the markdown
1171 pub(crate) link: String,
1172 /// The link text displayed in the HTML.
1174 /// This may not be the same as `link` if there was a disambiguator
1175 /// in an intra-doc link (e.g. \[`fn@f`\])
1176 pub(crate) link_text: String,
1177 /// The `DefId` of the Item whose **HTML Page** contains the item being
1178 /// linked to. This will be different to `item_id` on item's that don't
1179 /// have their own page, such as struct fields and enum variants.
1180 pub(crate) page_id: DefId,
1181 /// The url fragment to append to the link
1182 pub(crate) fragment: Option<UrlFragment>,
1185 pub struct RenderedLink {
1186 /// The text the link was original written as.
1188 /// This could potentially include disambiguators and backticks.
1189 pub(crate) original_text: String,
1190 /// The text to display in the HTML
1191 pub(crate) new_text: String,
1192 /// The URL to put in the `href`
1193 pub(crate) href: String,
1196 /// The attributes on an [`Item`], including attributes like `#[derive(...)]` and `#[inline]`,
1197 /// as well as doc comments.
1198 #[derive(Clone, Debug, Default)]
1199 pub(crate) struct Attributes {
1200 pub(crate) doc_strings: Vec<DocFragment>,
1201 pub(crate) other_attrs: ast::AttrVec,
1205 pub(crate) fn lists(&self, name: Symbol) -> impl Iterator<Item = ast::NestedMetaItem> + '_ {
1206 self.other_attrs.lists(name)
1209 pub(crate) fn has_doc_flag(&self, flag: Symbol) -> bool {
1210 for attr in &self.other_attrs {
1211 if !attr.has_name(sym::doc) {
1215 if let Some(items) = attr.meta_item_list() {
1216 if items.iter().filter_map(|i| i.meta_item()).any(|it| it.has_name(flag)) {
1225 pub(crate) fn from_ast(attrs: &[ast::Attribute]) -> Attributes {
1226 Attributes::from_ast_iter(attrs.iter().map(|attr| (attr, None)), false)
1229 pub(crate) fn from_ast_with_additional(
1230 attrs: &[ast::Attribute],
1231 (additional_attrs, def_id): (&[ast::Attribute], DefId),
1233 // Additional documentation should be shown before the original documentation.
1234 let attrs1 = additional_attrs.iter().map(|attr| (attr, Some(def_id)));
1235 let attrs2 = attrs.iter().map(|attr| (attr, None));
1236 Attributes::from_ast_iter(attrs1.chain(attrs2), false)
1239 pub(crate) fn from_ast_iter<'a>(
1240 attrs: impl Iterator<Item = (&'a ast::Attribute, Option<DefId>)>,
1243 let mut doc_strings = Vec::new();
1244 let mut other_attrs = ast::AttrVec::new();
1245 for (attr, parent_module) in attrs {
1246 if let Some((doc_str, comment_kind)) = attr.doc_str_and_comment_kind() {
1247 trace!("got doc_str={doc_str:?}");
1248 let doc = beautify_doc_string(doc_str, comment_kind);
1249 let kind = if attr.is_doc_comment() {
1250 DocFragmentKind::SugaredDoc
1252 DocFragmentKind::RawDoc
1254 let fragment = DocFragment { span: attr.span, doc, kind, parent_module, indent: 0 };
1255 doc_strings.push(fragment);
1256 } else if !doc_only {
1257 other_attrs.push(attr.clone());
1261 unindent_doc_fragments(&mut doc_strings);
1263 Attributes { doc_strings, other_attrs }
1266 /// Finds the `doc` attribute as a NameValue and returns the corresponding
1268 pub(crate) fn doc_value(&self) -> Option<String> {
1269 let mut iter = self.doc_strings.iter();
1271 let ori = iter.next()?;
1272 let mut out = String::new();
1273 add_doc_fragment(&mut out, ori);
1274 for new_frag in iter {
1275 add_doc_fragment(&mut out, new_frag);
1278 if out.is_empty() { None } else { Some(out) }
1281 /// Return the doc-comments on this item, grouped by the module they came from.
1282 /// The module can be different if this is a re-export with added documentation.
1284 /// The last newline is not trimmed so the produced strings are reusable between
1285 /// early and late doc link resolution regardless of their position.
1286 pub(crate) fn prepare_to_doc_link_resolution(&self) -> FxHashMap<Option<DefId>, String> {
1287 let mut res = FxHashMap::default();
1288 for fragment in &self.doc_strings {
1289 let out_str = res.entry(fragment.parent_module).or_default();
1290 add_doc_fragment(out_str, fragment);
1295 /// Finds all `doc` attributes as NameValues and returns their corresponding values, joined
1297 pub(crate) fn collapsed_doc_value(&self) -> Option<String> {
1298 if self.doc_strings.is_empty() {
1301 Some(collapse_doc_fragments(&self.doc_strings))
1305 pub(crate) fn get_doc_aliases(&self) -> Box<[Symbol]> {
1306 let mut aliases = FxHashSet::default();
1308 for attr in self.other_attrs.lists(sym::doc).filter(|a| a.has_name(sym::alias)) {
1309 if let Some(values) = attr.meta_item_list() {
1311 match l.lit().unwrap().kind {
1312 ast::LitKind::Str(s, _) => {
1315 _ => unreachable!(),
1319 aliases.insert(attr.value_str().unwrap());
1322 aliases.into_iter().collect::<Vec<_>>().into()
1326 impl PartialEq for Attributes {
1327 fn eq(&self, rhs: &Self) -> bool {
1328 self.doc_strings == rhs.doc_strings
1332 .map(|attr| attr.id)
1333 .eq(rhs.other_attrs.iter().map(|attr| attr.id))
1337 impl Eq for Attributes {}
1339 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
1340 pub(crate) enum GenericBound {
1341 TraitBound(PolyTrait, hir::TraitBoundModifier),
1346 pub(crate) fn maybe_sized(cx: &mut DocContext<'_>) -> GenericBound {
1347 let did = cx.tcx.require_lang_item(LangItem::Sized, None);
1348 let empty = ty::Binder::dummy(ty::InternalSubsts::empty());
1349 let path = external_path(cx, did, false, ThinVec::new(), empty);
1350 inline::record_extern_fqn(cx, did, ItemType::Trait);
1351 GenericBound::TraitBound(
1352 PolyTrait { trait_: path, generic_params: Vec::new() },
1353 hir::TraitBoundModifier::Maybe,
1357 pub(crate) fn is_sized_bound(&self, cx: &DocContext<'_>) -> bool {
1358 use rustc_hir::TraitBoundModifier as TBM;
1359 if let GenericBound::TraitBound(PolyTrait { ref trait_, .. }, TBM::None) = *self {
1360 if Some(trait_.def_id()) == cx.tcx.lang_items().sized_trait() {
1367 pub(crate) fn get_poly_trait(&self) -> Option<PolyTrait> {
1368 if let GenericBound::TraitBound(ref p, _) = *self {
1369 return Some(p.clone());
1374 pub(crate) fn get_trait_path(&self) -> Option<Path> {
1375 if let GenericBound::TraitBound(PolyTrait { ref trait_, .. }, _) = *self {
1376 Some(trait_.clone())
1383 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
1384 pub(crate) struct Lifetime(pub Symbol);
1387 pub(crate) fn statik() -> Lifetime {
1388 Lifetime(kw::StaticLifetime)
1391 pub(crate) fn elided() -> Lifetime {
1392 Lifetime(kw::UnderscoreLifetime)
1396 #[derive(Clone, Debug)]
1397 pub(crate) enum WherePredicate {
1398 BoundPredicate { ty: Type, bounds: Vec<GenericBound>, bound_params: Vec<Lifetime> },
1399 RegionPredicate { lifetime: Lifetime, bounds: Vec<GenericBound> },
1400 EqPredicate { lhs: Box<Type>, rhs: Box<Term>, bound_params: Vec<Lifetime> },
1403 impl WherePredicate {
1404 pub(crate) fn get_bounds(&self) -> Option<&[GenericBound]> {
1406 WherePredicate::BoundPredicate { ref bounds, .. } => Some(bounds),
1407 WherePredicate::RegionPredicate { ref bounds, .. } => Some(bounds),
1412 pub(crate) fn get_bound_params(&self) -> Option<&[Lifetime]> {
1414 Self::BoundPredicate { bound_params, .. } | Self::EqPredicate { bound_params, .. } => {
1422 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
1423 pub(crate) enum GenericParamDefKind {
1424 Lifetime { outlives: Vec<Lifetime> },
1425 Type { did: DefId, bounds: Vec<GenericBound>, default: Option<Box<Type>>, synthetic: bool },
1426 Const { did: DefId, ty: Box<Type>, default: Option<Box<String>> },
1429 impl GenericParamDefKind {
1430 pub(crate) fn is_type(&self) -> bool {
1431 matches!(self, GenericParamDefKind::Type { .. })
1435 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
1436 pub(crate) struct GenericParamDef {
1437 pub(crate) name: Symbol,
1438 pub(crate) kind: GenericParamDefKind,
1441 impl GenericParamDef {
1442 pub(crate) fn lifetime(name: Symbol) -> Self {
1443 Self { name, kind: GenericParamDefKind::Lifetime { outlives: Vec::new() } }
1446 pub(crate) fn is_synthetic_type_param(&self) -> bool {
1448 GenericParamDefKind::Lifetime { .. } | GenericParamDefKind::Const { .. } => false,
1449 GenericParamDefKind::Type { synthetic, .. } => synthetic,
1453 pub(crate) fn is_type(&self) -> bool {
1457 pub(crate) fn get_bounds(&self) -> Option<&[GenericBound]> {
1459 GenericParamDefKind::Type { ref bounds, .. } => Some(bounds),
1465 // maybe use a Generic enum and use Vec<Generic>?
1466 #[derive(Clone, Debug, Default)]
1467 pub(crate) struct Generics {
1468 pub(crate) params: ThinVec<GenericParamDef>,
1469 pub(crate) where_predicates: ThinVec<WherePredicate>,
1473 pub(crate) fn is_empty(&self) -> bool {
1474 self.params.is_empty() && self.where_predicates.is_empty()
1478 #[derive(Clone, Debug)]
1479 pub(crate) struct Function {
1480 pub(crate) decl: FnDecl,
1481 pub(crate) generics: Generics,
1484 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
1485 pub(crate) struct FnDecl {
1486 pub(crate) inputs: Arguments,
1487 pub(crate) output: FnRetTy,
1488 pub(crate) c_variadic: bool,
1492 pub(crate) fn self_type(&self) -> Option<SelfTy> {
1493 self.inputs.values.get(0).and_then(|v| v.to_self())
1496 /// Returns the sugared return type for an async function.
1498 /// For example, if the return type is `impl std::future::Future<Output = i32>`, this function
1499 /// will return `i32`.
1503 /// This function will panic if the return type does not match the expected sugaring for async
1505 pub(crate) fn sugared_async_return_type(&self) -> FnRetTy {
1506 match &self.output {
1507 FnRetTy::Return(Type::ImplTrait(bounds)) => match &bounds[0] {
1508 GenericBound::TraitBound(PolyTrait { trait_, .. }, ..) => {
1509 let bindings = trait_.bindings().unwrap();
1510 let ret_ty = bindings[0].term();
1511 let ty = ret_ty.ty().expect("Unexpected constant return term");
1512 FnRetTy::Return(ty.clone())
1514 _ => panic!("unexpected desugaring of async function"),
1516 _ => panic!("unexpected desugaring of async function"),
1521 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
1522 pub(crate) struct Arguments {
1523 pub(crate) values: Vec<Argument>,
1526 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
1527 pub(crate) struct Argument {
1528 pub(crate) type_: Type,
1529 pub(crate) name: Symbol,
1530 /// This field is used to represent "const" arguments from the `rustc_legacy_const_generics`
1531 /// feature. More information in <https://github.com/rust-lang/rust/issues/83167>.
1532 pub(crate) is_const: bool,
1535 #[derive(Clone, PartialEq, Debug)]
1536 pub(crate) enum SelfTy {
1538 SelfBorrowed(Option<Lifetime>, Mutability),
1543 pub(crate) fn to_self(&self) -> Option<SelfTy> {
1544 if self.name != kw::SelfLower {
1547 if self.type_.is_self_type() {
1548 return Some(SelfValue);
1551 BorrowedRef { ref lifetime, mutability, ref type_ } if type_.is_self_type() => {
1552 Some(SelfBorrowed(lifetime.clone(), mutability))
1554 _ => Some(SelfExplicit(self.type_.clone())),
1559 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
1560 pub(crate) enum FnRetTy {
1566 pub(crate) fn as_return(&self) -> Option<&Type> {
1568 Return(ret) => Some(ret),
1569 DefaultReturn => None,
1574 #[derive(Clone, Debug)]
1575 pub(crate) struct Trait {
1576 pub(crate) def_id: DefId,
1577 pub(crate) items: Vec<Item>,
1578 pub(crate) generics: Generics,
1579 pub(crate) bounds: Vec<GenericBound>,
1583 pub(crate) fn is_auto(&self, tcx: TyCtxt<'_>) -> bool {
1584 tcx.trait_is_auto(self.def_id)
1586 pub(crate) fn is_notable_trait(&self, tcx: TyCtxt<'_>) -> bool {
1587 tcx.is_doc_notable_trait(self.def_id)
1589 pub(crate) fn unsafety(&self, tcx: TyCtxt<'_>) -> hir::Unsafety {
1590 tcx.trait_def(self.def_id).unsafety
1594 #[derive(Clone, Debug)]
1595 pub(crate) struct TraitAlias {
1596 pub(crate) generics: Generics,
1597 pub(crate) bounds: Vec<GenericBound>,
1600 /// A trait reference, which may have higher ranked lifetimes.
1601 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
1602 pub(crate) struct PolyTrait {
1603 pub(crate) trait_: Path,
1604 pub(crate) generic_params: Vec<GenericParamDef>,
1607 /// Rustdoc's representation of types, mostly based on the [`hir::Ty`].
1608 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
1609 pub(crate) enum Type {
1610 /// A named type, which could be a trait.
1612 /// This is mostly Rustdoc's version of [`hir::Path`].
1613 /// It has to be different because Rustdoc's [`PathSegment`] can contain cleaned generics.
1614 Path { path: Path },
1615 /// A `dyn Trait` object: `dyn for<'a> Trait<'a> + Send + 'static`
1616 DynTrait(Vec<PolyTrait>, Option<Lifetime>),
1617 /// A type parameter.
1619 /// A primitive (aka, builtin) type.
1620 Primitive(PrimitiveType),
1621 /// A function pointer: `extern "ABI" fn(...) -> ...`
1622 BareFunction(Box<BareFunctionDecl>),
1623 /// A tuple type: `(i32, &str)`.
1625 /// A slice type (does *not* include the `&`): `[i32]`
1629 /// The `String` field is a stringified version of the array's length parameter.
1630 Array(Box<Type>, Box<str>),
1631 /// A raw pointer type: `*const i32`, `*mut i32`
1632 RawPointer(Mutability, Box<Type>),
1633 /// A reference type: `&i32`, `&'a mut Foo`
1634 BorrowedRef { lifetime: Option<Lifetime>, mutability: Mutability, type_: Box<Type> },
1636 /// A qualified path to an associated item: `<Type as Trait>::Name`
1637 QPath(Box<QPathData>),
1639 /// A type that is inferred: `_`
1642 /// An `impl Trait`: `impl TraitA + TraitB + ...`
1643 ImplTrait(Vec<GenericBound>),
1647 /// When comparing types for equality, it can help to ignore `&` wrapping.
1648 pub(crate) fn without_borrowed_ref(&self) -> &Type {
1649 let mut result = self;
1650 while let Type::BorrowedRef { type_, .. } = result {
1656 /// Check if two types are "potentially the same".
1657 /// This is different from `Eq`, because it knows that things like
1658 /// `Placeholder` are possible matches for everything.
1659 pub(crate) fn is_same(&self, other: &Self, cache: &Cache) -> bool {
1660 match (self, other) {
1662 (Type::Tuple(a), Type::Tuple(b)) => {
1663 a.len() == b.len() && a.iter().zip(b).all(|(a, b)| a.is_same(b, cache))
1665 (Type::Slice(a), Type::Slice(b)) => a.is_same(b, cache),
1666 (Type::Array(a, al), Type::Array(b, bl)) => al == bl && a.is_same(b, cache),
1667 (Type::RawPointer(mutability, type_), Type::RawPointer(b_mutability, b_type_)) => {
1668 mutability == b_mutability && type_.is_same(b_type_, cache)
1671 Type::BorrowedRef { mutability, type_, .. },
1672 Type::BorrowedRef { mutability: b_mutability, type_: b_type_, .. },
1673 ) => mutability == b_mutability && type_.is_same(b_type_, cache),
1674 // Placeholders and generics are equal to all other types.
1675 (Type::Infer, _) | (_, Type::Infer) => true,
1676 (Type::Generic(_), _) | (_, Type::Generic(_)) => true,
1677 // Other cases, such as primitives, just use recursion.
1680 .and_then(|a| Some((a, b.def_id(cache)?)))
1681 .map(|(a, b)| a == b)
1686 pub(crate) fn primitive_type(&self) -> Option<PrimitiveType> {
1688 Primitive(p) | BorrowedRef { type_: box Primitive(p), .. } => Some(p),
1689 Slice(..) | BorrowedRef { type_: box Slice(..), .. } => Some(PrimitiveType::Slice),
1690 Array(..) | BorrowedRef { type_: box Array(..), .. } => Some(PrimitiveType::Array),
1693 Some(PrimitiveType::Unit)
1695 Some(PrimitiveType::Tuple)
1698 RawPointer(..) => Some(PrimitiveType::RawPointer),
1699 BareFunction(..) => Some(PrimitiveType::Fn),
1704 /// Checks if this is a `T::Name` path for an associated type.
1705 pub(crate) fn is_assoc_ty(&self) -> bool {
1707 Type::Path { path, .. } => path.is_assoc_ty(),
1712 pub(crate) fn is_self_type(&self) -> bool {
1714 Generic(name) => name == kw::SelfUpper,
1719 pub(crate) fn generics(&self) -> Option<Vec<&Type>> {
1721 Type::Path { path, .. } => path.generics(),
1726 pub(crate) fn is_full_generic(&self) -> bool {
1727 matches!(self, Type::Generic(_))
1730 pub(crate) fn is_impl_trait(&self) -> bool {
1731 matches!(self, Type::ImplTrait(_))
1734 pub(crate) fn projection(&self) -> Option<(&Type, DefId, PathSegment)> {
1735 if let QPath(box QPathData { self_type, trait_, assoc, .. }) = self {
1736 Some((self_type, trait_.def_id(), assoc.clone()))
1742 fn inner_def_id(&self, cache: Option<&Cache>) -> Option<DefId> {
1743 let t: PrimitiveType = match *self {
1744 Type::Path { ref path } => return Some(path.def_id()),
1745 DynTrait(ref bounds, _) => return bounds.get(0).map(|b| b.trait_.def_id()),
1746 Primitive(p) => return cache.and_then(|c| c.primitive_locations.get(&p).cloned()),
1747 BorrowedRef { type_: box Generic(..), .. } => PrimitiveType::Reference,
1748 BorrowedRef { ref type_, .. } => return type_.inner_def_id(cache),
1753 PrimitiveType::Tuple
1756 BareFunction(..) => PrimitiveType::Fn,
1757 Slice(..) => PrimitiveType::Slice,
1758 Array(..) => PrimitiveType::Array,
1759 RawPointer(..) => PrimitiveType::RawPointer,
1760 QPath(box QPathData { ref self_type, .. }) => return self_type.inner_def_id(cache),
1761 Generic(_) | Infer | ImplTrait(_) => return None,
1763 cache.and_then(|c| Primitive(t).def_id(c))
1766 /// Use this method to get the [DefId] of a [clean] AST node, including [PrimitiveType]s.
1768 /// [clean]: crate::clean
1769 pub(crate) fn def_id(&self, cache: &Cache) -> Option<DefId> {
1770 self.inner_def_id(Some(cache))
1774 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
1775 pub(crate) struct QPathData {
1776 pub assoc: PathSegment,
1777 pub self_type: Type,
1778 /// FIXME: compute this field on demand.
1779 pub should_show_cast: bool,
1783 /// A primitive (aka, builtin) type.
1785 /// This represents things like `i32`, `str`, etc.
1787 /// N.B. This has to be different from [`hir::PrimTy`] because it also includes types that aren't
1788 /// paths, like [`Self::Unit`].
1789 #[derive(Clone, PartialEq, Eq, Hash, Copy, Debug)]
1790 pub(crate) enum PrimitiveType {
1818 type SimplifiedTypes = FxHashMap<PrimitiveType, ArrayVec<SimplifiedType, 3>>;
1819 impl PrimitiveType {
1820 pub(crate) fn from_hir(prim: hir::PrimTy) -> PrimitiveType {
1821 use ast::{FloatTy, IntTy, UintTy};
1823 hir::PrimTy::Int(IntTy::Isize) => PrimitiveType::Isize,
1824 hir::PrimTy::Int(IntTy::I8) => PrimitiveType::I8,
1825 hir::PrimTy::Int(IntTy::I16) => PrimitiveType::I16,
1826 hir::PrimTy::Int(IntTy::I32) => PrimitiveType::I32,
1827 hir::PrimTy::Int(IntTy::I64) => PrimitiveType::I64,
1828 hir::PrimTy::Int(IntTy::I128) => PrimitiveType::I128,
1829 hir::PrimTy::Uint(UintTy::Usize) => PrimitiveType::Usize,
1830 hir::PrimTy::Uint(UintTy::U8) => PrimitiveType::U8,
1831 hir::PrimTy::Uint(UintTy::U16) => PrimitiveType::U16,
1832 hir::PrimTy::Uint(UintTy::U32) => PrimitiveType::U32,
1833 hir::PrimTy::Uint(UintTy::U64) => PrimitiveType::U64,
1834 hir::PrimTy::Uint(UintTy::U128) => PrimitiveType::U128,
1835 hir::PrimTy::Float(FloatTy::F32) => PrimitiveType::F32,
1836 hir::PrimTy::Float(FloatTy::F64) => PrimitiveType::F64,
1837 hir::PrimTy::Str => PrimitiveType::Str,
1838 hir::PrimTy::Bool => PrimitiveType::Bool,
1839 hir::PrimTy::Char => PrimitiveType::Char,
1843 pub(crate) fn from_symbol(s: Symbol) -> Option<PrimitiveType> {
1845 sym::isize => Some(PrimitiveType::Isize),
1846 sym::i8 => Some(PrimitiveType::I8),
1847 sym::i16 => Some(PrimitiveType::I16),
1848 sym::i32 => Some(PrimitiveType::I32),
1849 sym::i64 => Some(PrimitiveType::I64),
1850 sym::i128 => Some(PrimitiveType::I128),
1851 sym::usize => Some(PrimitiveType::Usize),
1852 sym::u8 => Some(PrimitiveType::U8),
1853 sym::u16 => Some(PrimitiveType::U16),
1854 sym::u32 => Some(PrimitiveType::U32),
1855 sym::u64 => Some(PrimitiveType::U64),
1856 sym::u128 => Some(PrimitiveType::U128),
1857 sym::bool => Some(PrimitiveType::Bool),
1858 sym::char => Some(PrimitiveType::Char),
1859 sym::str => Some(PrimitiveType::Str),
1860 sym::f32 => Some(PrimitiveType::F32),
1861 sym::f64 => Some(PrimitiveType::F64),
1862 sym::array => Some(PrimitiveType::Array),
1863 sym::slice => Some(PrimitiveType::Slice),
1864 sym::tuple => Some(PrimitiveType::Tuple),
1865 sym::unit => Some(PrimitiveType::Unit),
1866 sym::pointer => Some(PrimitiveType::RawPointer),
1867 sym::reference => Some(PrimitiveType::Reference),
1868 kw::Fn => Some(PrimitiveType::Fn),
1869 sym::never => Some(PrimitiveType::Never),
1874 pub(crate) fn simplified_types() -> &'static SimplifiedTypes {
1875 use ty::fast_reject::SimplifiedType::*;
1876 use ty::{FloatTy, IntTy, UintTy};
1877 use PrimitiveType::*;
1878 static CELL: OnceCell<SimplifiedTypes> = OnceCell::new();
1880 let single = |x| iter::once(x).collect();
1881 CELL.get_or_init(move || {
1883 Isize => single(IntSimplifiedType(IntTy::Isize)),
1884 I8 => single(IntSimplifiedType(IntTy::I8)),
1885 I16 => single(IntSimplifiedType(IntTy::I16)),
1886 I32 => single(IntSimplifiedType(IntTy::I32)),
1887 I64 => single(IntSimplifiedType(IntTy::I64)),
1888 I128 => single(IntSimplifiedType(IntTy::I128)),
1889 Usize => single(UintSimplifiedType(UintTy::Usize)),
1890 U8 => single(UintSimplifiedType(UintTy::U8)),
1891 U16 => single(UintSimplifiedType(UintTy::U16)),
1892 U32 => single(UintSimplifiedType(UintTy::U32)),
1893 U64 => single(UintSimplifiedType(UintTy::U64)),
1894 U128 => single(UintSimplifiedType(UintTy::U128)),
1895 F32 => single(FloatSimplifiedType(FloatTy::F32)),
1896 F64 => single(FloatSimplifiedType(FloatTy::F64)),
1897 Str => single(StrSimplifiedType),
1898 Bool => single(BoolSimplifiedType),
1899 Char => single(CharSimplifiedType),
1900 Array => single(ArraySimplifiedType),
1901 Slice => single(SliceSimplifiedType),
1902 // FIXME: If we ever add an inherent impl for tuples
1903 // with different lengths, they won't show in rustdoc.
1905 // Either manually update this arrayvec at this point
1906 // or start with a more complex refactoring.
1907 Tuple => [TupleSimplifiedType(1), TupleSimplifiedType(2), TupleSimplifiedType(3)].into(),
1908 Unit => single(TupleSimplifiedType(0)),
1909 RawPointer => [PtrSimplifiedType(Mutability::Not), PtrSimplifiedType(Mutability::Mut)].into_iter().collect(),
1910 Reference => [RefSimplifiedType(Mutability::Not), RefSimplifiedType(Mutability::Mut)].into_iter().collect(),
1911 // FIXME: This will be wrong if we ever add inherent impls
1912 // for function pointers.
1913 Fn => single(FunctionSimplifiedType(1)),
1914 Never => single(NeverSimplifiedType),
1919 pub(crate) fn impls<'tcx>(&self, tcx: TyCtxt<'tcx>) -> impl Iterator<Item = DefId> + 'tcx {
1920 Self::simplified_types()
1924 .flat_map(move |&simp| tcx.incoherent_impls(simp))
1928 pub(crate) fn all_impls(tcx: TyCtxt<'_>) -> impl Iterator<Item = DefId> + '_ {
1929 Self::simplified_types()
1932 .flat_map(move |&simp| tcx.incoherent_impls(simp))
1936 pub(crate) fn as_sym(&self) -> Symbol {
1937 use PrimitiveType::*;
1939 Isize => sym::isize,
1945 Usize => sym::usize,
1956 Array => sym::array,
1957 Slice => sym::slice,
1958 Tuple => sym::tuple,
1960 RawPointer => sym::pointer,
1961 Reference => sym::reference,
1963 Never => sym::never,
1967 /// Returns the DefId of the module with `doc(primitive)` for this primitive type.
1968 /// Panics if there is no such module.
1970 /// This gives precedence to primitives defined in the current crate, and deprioritizes primitives defined in `core`,
1971 /// but otherwise, if multiple crates define the same primitive, there is no guarantee of which will be picked.
1972 /// In particular, if a crate depends on both `std` and another crate that also defines `doc(primitive)`, then
1973 /// it's entirely random whether `std` or the other crate is picked. (no_std crates are usually fine unless multiple dependencies define a primitive.)
1974 pub(crate) fn primitive_locations(tcx: TyCtxt<'_>) -> &FxHashMap<PrimitiveType, DefId> {
1975 static PRIMITIVE_LOCATIONS: OnceCell<FxHashMap<PrimitiveType, DefId>> = OnceCell::new();
1976 PRIMITIVE_LOCATIONS.get_or_init(|| {
1977 let mut primitive_locations = FxHashMap::default();
1978 // NOTE: technically this misses crates that are only passed with `--extern` and not loaded when checking the crate.
1979 // This is a degenerate case that I don't plan to support.
1980 for &crate_num in tcx.crates(()) {
1981 let e = ExternalCrate { crate_num };
1982 let crate_name = e.name(tcx);
1983 debug!(?crate_num, ?crate_name);
1984 for &(def_id, prim) in &e.primitives(tcx) {
1985 // HACK: try to link to std instead where possible
1986 if crate_name == sym::core && primitive_locations.contains_key(&prim) {
1989 primitive_locations.insert(prim, def_id);
1992 let local_primitives = ExternalCrate { crate_num: LOCAL_CRATE }.primitives(tcx);
1993 for (def_id, prim) in local_primitives {
1994 primitive_locations.insert(prim, def_id);
2001 impl From<ast::IntTy> for PrimitiveType {
2002 fn from(int_ty: ast::IntTy) -> PrimitiveType {
2004 ast::IntTy::Isize => PrimitiveType::Isize,
2005 ast::IntTy::I8 => PrimitiveType::I8,
2006 ast::IntTy::I16 => PrimitiveType::I16,
2007 ast::IntTy::I32 => PrimitiveType::I32,
2008 ast::IntTy::I64 => PrimitiveType::I64,
2009 ast::IntTy::I128 => PrimitiveType::I128,
2014 impl From<ast::UintTy> for PrimitiveType {
2015 fn from(uint_ty: ast::UintTy) -> PrimitiveType {
2017 ast::UintTy::Usize => PrimitiveType::Usize,
2018 ast::UintTy::U8 => PrimitiveType::U8,
2019 ast::UintTy::U16 => PrimitiveType::U16,
2020 ast::UintTy::U32 => PrimitiveType::U32,
2021 ast::UintTy::U64 => PrimitiveType::U64,
2022 ast::UintTy::U128 => PrimitiveType::U128,
2027 impl From<ast::FloatTy> for PrimitiveType {
2028 fn from(float_ty: ast::FloatTy) -> PrimitiveType {
2030 ast::FloatTy::F32 => PrimitiveType::F32,
2031 ast::FloatTy::F64 => PrimitiveType::F64,
2036 impl From<ty::IntTy> for PrimitiveType {
2037 fn from(int_ty: ty::IntTy) -> PrimitiveType {
2039 ty::IntTy::Isize => PrimitiveType::Isize,
2040 ty::IntTy::I8 => PrimitiveType::I8,
2041 ty::IntTy::I16 => PrimitiveType::I16,
2042 ty::IntTy::I32 => PrimitiveType::I32,
2043 ty::IntTy::I64 => PrimitiveType::I64,
2044 ty::IntTy::I128 => PrimitiveType::I128,
2049 impl From<ty::UintTy> for PrimitiveType {
2050 fn from(uint_ty: ty::UintTy) -> PrimitiveType {
2052 ty::UintTy::Usize => PrimitiveType::Usize,
2053 ty::UintTy::U8 => PrimitiveType::U8,
2054 ty::UintTy::U16 => PrimitiveType::U16,
2055 ty::UintTy::U32 => PrimitiveType::U32,
2056 ty::UintTy::U64 => PrimitiveType::U64,
2057 ty::UintTy::U128 => PrimitiveType::U128,
2062 impl From<ty::FloatTy> for PrimitiveType {
2063 fn from(float_ty: ty::FloatTy) -> PrimitiveType {
2065 ty::FloatTy::F32 => PrimitiveType::F32,
2066 ty::FloatTy::F64 => PrimitiveType::F64,
2071 impl From<hir::PrimTy> for PrimitiveType {
2072 fn from(prim_ty: hir::PrimTy) -> PrimitiveType {
2074 hir::PrimTy::Int(int_ty) => int_ty.into(),
2075 hir::PrimTy::Uint(uint_ty) => uint_ty.into(),
2076 hir::PrimTy::Float(float_ty) => float_ty.into(),
2077 hir::PrimTy::Str => PrimitiveType::Str,
2078 hir::PrimTy::Bool => PrimitiveType::Bool,
2079 hir::PrimTy::Char => PrimitiveType::Char,
2084 #[derive(Clone, Debug)]
2085 pub(crate) struct Struct {
2086 pub(crate) ctor_kind: Option<CtorKind>,
2087 pub(crate) generics: Generics,
2088 pub(crate) fields: Vec<Item>,
2092 pub(crate) fn has_stripped_entries(&self) -> bool {
2093 self.fields.iter().any(|f| f.is_stripped())
2097 #[derive(Clone, Debug)]
2098 pub(crate) struct Union {
2099 pub(crate) generics: Generics,
2100 pub(crate) fields: Vec<Item>,
2104 pub(crate) fn has_stripped_entries(&self) -> bool {
2105 self.fields.iter().any(|f| f.is_stripped())
2109 /// This is a more limited form of the standard Struct, different in that
2110 /// it lacks the things most items have (name, id, parameterization). Found
2111 /// only as a variant in an enum.
2112 #[derive(Clone, Debug)]
2113 pub(crate) struct VariantStruct {
2114 pub(crate) fields: Vec<Item>,
2117 impl VariantStruct {
2118 pub(crate) fn has_stripped_entries(&self) -> bool {
2119 self.fields.iter().any(|f| f.is_stripped())
2123 #[derive(Clone, Debug)]
2124 pub(crate) struct Enum {
2125 pub(crate) variants: IndexVec<VariantIdx, Item>,
2126 pub(crate) generics: Generics,
2130 pub(crate) fn has_stripped_entries(&self) -> bool {
2131 self.variants.iter().any(|f| f.is_stripped())
2134 pub(crate) fn variants(&self) -> impl Iterator<Item = &Item> {
2135 self.variants.iter().filter(|v| !v.is_stripped())
2139 #[derive(Clone, Debug)]
2140 pub(crate) struct Variant {
2141 pub kind: VariantKind,
2142 pub discriminant: Option<Discriminant>,
2145 #[derive(Clone, Debug)]
2146 pub(crate) enum VariantKind {
2149 Struct(VariantStruct),
2153 pub(crate) fn has_stripped_entries(&self) -> Option<bool> {
2155 VariantKind::Struct(struct_) => Some(struct_.has_stripped_entries()),
2156 VariantKind::CLike | VariantKind::Tuple(_) => None,
2161 #[derive(Clone, Debug)]
2162 pub(crate) struct Discriminant {
2163 // In the case of cross crate re-exports, we don't have the nessesary information
2164 // to reconstruct the expression of the discriminant, only the value.
2165 pub(super) expr: Option<BodyId>,
2166 pub(super) value: DefId,
2170 /// Will be `None` in the case of cross-crate reexports, and may be
2172 pub(crate) fn expr(&self, tcx: TyCtxt<'_>) -> Option<String> {
2173 self.expr.map(|body| print_const_expr(tcx, body))
2175 /// Will always be a machine readable number, without underscores or suffixes.
2176 pub(crate) fn value(&self, tcx: TyCtxt<'_>) -> String {
2177 print_evaluated_const(tcx, self.value, false).unwrap()
2181 /// Small wrapper around [`rustc_span::Span`] that adds helper methods
2182 /// and enforces calling [`rustc_span::Span::source_callsite()`].
2183 #[derive(Copy, Clone, Debug)]
2184 pub(crate) struct Span(rustc_span::Span);
2187 /// Wraps a [`rustc_span::Span`]. In case this span is the result of a macro expansion, the
2188 /// span will be updated to point to the macro invocation instead of the macro definition.
2190 /// (See rust-lang/rust#39726)
2191 pub(crate) fn new(sp: rustc_span::Span) -> Self {
2192 Self(sp.source_callsite())
2195 pub(crate) fn inner(&self) -> rustc_span::Span {
2199 pub(crate) fn filename(&self, sess: &Session) -> FileName {
2200 sess.source_map().span_to_filename(self.0)
2203 pub(crate) fn lo(&self, sess: &Session) -> Loc {
2204 sess.source_map().lookup_char_pos(self.0.lo())
2207 pub(crate) fn hi(&self, sess: &Session) -> Loc {
2208 sess.source_map().lookup_char_pos(self.0.hi())
2211 pub(crate) fn cnum(&self, sess: &Session) -> CrateNum {
2212 // FIXME: is there a time when the lo and hi crate would be different?
2213 self.lo(sess).file.cnum
2217 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
2218 pub(crate) struct Path {
2219 pub(crate) res: Res,
2220 pub(crate) segments: ThinVec<PathSegment>,
2224 pub(crate) fn def_id(&self) -> DefId {
2228 pub(crate) fn last_opt(&self) -> Option<Symbol> {
2229 self.segments.last().map(|s| s.name)
2232 pub(crate) fn last(&self) -> Symbol {
2233 self.last_opt().expect("segments were empty")
2236 pub(crate) fn whole_name(&self) -> String {
2239 .map(|s| if s.name == kw::PathRoot { "" } else { s.name.as_str() })
2244 /// Checks if this is a `T::Name` path for an associated type.
2245 pub(crate) fn is_assoc_ty(&self) -> bool {
2247 Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } | Res::Def(DefKind::TyParam, _)
2248 if self.segments.len() != 1 =>
2252 Res::Def(DefKind::AssocTy, _) => true,
2257 pub(crate) fn generics(&self) -> Option<Vec<&Type>> {
2258 self.segments.last().and_then(|seg| {
2259 if let GenericArgs::AngleBracketed { ref args, .. } = seg.args {
2262 .filter_map(|arg| match arg {
2263 GenericArg::Type(ty) => Some(ty),
2274 pub(crate) fn bindings(&self) -> Option<&[TypeBinding]> {
2275 self.segments.last().and_then(|seg| {
2276 if let GenericArgs::AngleBracketed { ref bindings, .. } = seg.args {
2285 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
2286 pub(crate) enum GenericArg {
2289 Const(Box<Constant>),
2293 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
2294 pub(crate) enum GenericArgs {
2295 AngleBracketed { args: Box<[GenericArg]>, bindings: ThinVec<TypeBinding> },
2296 Parenthesized { inputs: Box<[Type]>, output: Option<Box<Type>> },
2299 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
2300 pub(crate) struct PathSegment {
2301 pub(crate) name: Symbol,
2302 pub(crate) args: GenericArgs,
2305 #[derive(Clone, Debug)]
2306 pub(crate) struct Typedef {
2307 pub(crate) type_: Type,
2308 pub(crate) generics: Generics,
2309 /// `type_` can come from either the HIR or from metadata. If it comes from HIR, it may be a type
2310 /// alias instead of the final type. This will always have the final type, regardless of whether
2311 /// `type_` came from HIR or from metadata.
2313 /// If `item_type.is_none()`, `type_` is guaranteed to come from metadata (and therefore hold the
2315 pub(crate) item_type: Option<Type>,
2318 #[derive(Clone, Debug)]
2319 pub(crate) struct OpaqueTy {
2320 pub(crate) bounds: Vec<GenericBound>,
2321 pub(crate) generics: Generics,
2324 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
2325 pub(crate) struct BareFunctionDecl {
2326 pub(crate) unsafety: hir::Unsafety,
2327 pub(crate) generic_params: Vec<GenericParamDef>,
2328 pub(crate) decl: FnDecl,
2329 pub(crate) abi: Abi,
2332 #[derive(Clone, Debug)]
2333 pub(crate) struct Static {
2334 pub(crate) type_: Type,
2335 pub(crate) mutability: Mutability,
2336 pub(crate) expr: Option<BodyId>,
2339 #[derive(Clone, PartialEq, Eq, Hash, Debug)]
2340 pub(crate) struct Constant {
2341 pub(crate) type_: Type,
2342 pub(crate) kind: ConstantKind,
2345 #[derive(Clone, PartialEq, Eq, Hash, Debug)]
2346 pub(crate) enum Term {
2352 pub(crate) fn ty(&self) -> Option<&Type> {
2353 if let Term::Type(ty) = self { Some(ty) } else { None }
2357 impl From<Type> for Term {
2358 fn from(ty: Type) -> Self {
2363 #[derive(Clone, PartialEq, Eq, Hash, Debug)]
2364 pub(crate) enum ConstantKind {
2365 /// This is the wrapper around `ty::Const` for a non-local constant. Because it doesn't have a
2366 /// `BodyId`, we need to handle it on its own.
2368 /// Note that `ty::Const` includes generic parameters, and may not always be uniquely identified
2369 /// by a DefId. So this field must be different from `Extern`.
2370 TyConst { expr: Box<str> },
2371 /// A constant (expression) that's not an item or associated item. These are usually found
2372 /// nested inside types (e.g., array lengths) or expressions (e.g., repeat counts), and also
2373 /// used to define explicit discriminant values for enum variants.
2374 Anonymous { body: BodyId },
2375 /// A constant from a different crate.
2376 Extern { def_id: DefId },
2377 /// `const FOO: u32 = ...;`
2378 Local { def_id: DefId, body: BodyId },
2382 pub(crate) fn expr(&self, tcx: TyCtxt<'_>) -> String {
2386 pub(crate) fn value(&self, tcx: TyCtxt<'_>) -> Option<String> {
2387 self.kind.value(tcx)
2390 pub(crate) fn is_literal(&self, tcx: TyCtxt<'_>) -> bool {
2391 self.kind.is_literal(tcx)
2396 pub(crate) fn expr(&self, tcx: TyCtxt<'_>) -> String {
2398 ConstantKind::TyConst { ref expr } => expr.to_string(),
2399 ConstantKind::Extern { def_id } => print_inlined_const(tcx, def_id),
2400 ConstantKind::Local { body, .. } | ConstantKind::Anonymous { body } => {
2401 print_const_expr(tcx, body)
2406 pub(crate) fn value(&self, tcx: TyCtxt<'_>) -> Option<String> {
2408 ConstantKind::TyConst { .. } | ConstantKind::Anonymous { .. } => None,
2409 ConstantKind::Extern { def_id } | ConstantKind::Local { def_id, .. } => {
2410 print_evaluated_const(tcx, def_id, true)
2415 pub(crate) fn is_literal(&self, tcx: TyCtxt<'_>) -> bool {
2417 ConstantKind::TyConst { .. } => false,
2418 ConstantKind::Extern { def_id } => def_id.as_local().map_or(false, |def_id| {
2419 is_literal_expr(tcx, tcx.hir().local_def_id_to_hir_id(def_id))
2421 ConstantKind::Local { body, .. } | ConstantKind::Anonymous { body } => {
2422 is_literal_expr(tcx, body.hir_id)
2428 #[derive(Clone, Debug)]
2429 pub(crate) struct Impl {
2430 pub(crate) unsafety: hir::Unsafety,
2431 pub(crate) generics: Generics,
2432 pub(crate) trait_: Option<Path>,
2433 pub(crate) for_: Type,
2434 pub(crate) items: Vec<Item>,
2435 pub(crate) polarity: ty::ImplPolarity,
2436 pub(crate) kind: ImplKind,
2440 pub(crate) fn provided_trait_methods(&self, tcx: TyCtxt<'_>) -> FxHashSet<Symbol> {
2443 .map(|t| t.def_id())
2444 .map(|did| tcx.provided_trait_methods(did).map(|meth| meth.name).collect())
2445 .unwrap_or_default()
2449 #[derive(Clone, Debug)]
2450 pub(crate) enum ImplKind {
2458 pub(crate) fn is_auto(&self) -> bool {
2459 matches!(self, ImplKind::Auto)
2462 pub(crate) fn is_blanket(&self) -> bool {
2463 matches!(self, ImplKind::Blanket(_))
2466 pub(crate) fn is_fake_variadic(&self) -> bool {
2467 matches!(self, ImplKind::FakeVaradic)
2470 pub(crate) fn as_blanket_ty(&self) -> Option<&Type> {
2472 ImplKind::Blanket(ty) => Some(ty),
2478 #[derive(Clone, Debug)]
2479 pub(crate) struct Import {
2480 pub(crate) kind: ImportKind,
2481 pub(crate) source: ImportSource,
2482 pub(crate) should_be_displayed: bool,
2486 pub(crate) fn new_simple(
2488 source: ImportSource,
2489 should_be_displayed: bool,
2491 Self { kind: ImportKind::Simple(name), source, should_be_displayed }
2494 pub(crate) fn new_glob(source: ImportSource, should_be_displayed: bool) -> Self {
2495 Self { kind: ImportKind::Glob, source, should_be_displayed }
2498 pub(crate) fn imported_item_is_doc_hidden(&self, tcx: TyCtxt<'_>) -> bool {
2499 match self.source.did {
2501 .get_attrs(did, sym::doc)
2502 .filter_map(ast::Attribute::meta_item_list)
2504 .has_word(sym::hidden),
2510 #[derive(Clone, Debug)]
2511 pub(crate) enum ImportKind {
2512 // use source as str;
2518 #[derive(Clone, Debug)]
2519 pub(crate) struct ImportSource {
2520 pub(crate) path: Path,
2521 pub(crate) did: Option<DefId>,
2524 #[derive(Clone, Debug)]
2525 pub(crate) struct Macro {
2526 pub(crate) source: String,
2529 #[derive(Clone, Debug)]
2530 pub(crate) struct ProcMacro {
2531 pub(crate) kind: MacroKind,
2532 pub(crate) helpers: Vec<Symbol>,
2535 /// An type binding on an associated type (e.g., `A = Bar` in `Foo<A = Bar>` or
2536 /// `A: Send + Sync` in `Foo<A: Send + Sync>`).
2537 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
2538 pub(crate) struct TypeBinding {
2539 pub(crate) assoc: PathSegment,
2540 pub(crate) kind: TypeBindingKind,
2543 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
2544 pub(crate) enum TypeBindingKind {
2545 Equality { term: Term },
2546 Constraint { bounds: Vec<GenericBound> },
2550 pub(crate) fn term(&self) -> &Term {
2552 TypeBindingKind::Equality { ref term } => term,
2553 _ => panic!("expected equality type binding for parenthesized generic args"),
2558 /// The type, lifetime, or constant that a private type alias's parameter should be
2559 /// replaced with when expanding a use of that type alias.
2564 /// type PrivAlias<T> = Vec<T>;
2566 /// pub fn public_fn() -> PrivAlias<i32> { vec![] }
2569 /// `public_fn`'s docs will show it as returning `Vec<i32>`, since `PrivAlias` is private.
2570 /// [`SubstParam`] is used to record that `T` should be mapped to `i32`.
2571 pub(crate) enum SubstParam {
2578 pub(crate) fn as_ty(&self) -> Option<&Type> {
2579 if let Self::Type(ty) = self { Some(ty) } else { None }
2582 pub(crate) fn as_lt(&self) -> Option<&Lifetime> {
2583 if let Self::Lifetime(lt) = self { Some(lt) } else { None }
2587 // Some nodes are used a lot. Make sure they don't unintentionally get bigger.
2588 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
2591 use rustc_data_structures::static_assert_size;
2592 // tidy-alphabetical-start
2593 static_assert_size!(Crate, 64); // frequently moved by-value
2594 static_assert_size!(DocFragment, 32);
2595 static_assert_size!(GenericArg, 32);
2596 static_assert_size!(GenericArgs, 32);
2597 static_assert_size!(GenericParamDef, 56);
2598 static_assert_size!(Generics, 16);
2599 static_assert_size!(Item, 56);
2600 static_assert_size!(ItemKind, 64);
2601 static_assert_size!(PathSegment, 40);
2602 static_assert_size!(Type, 32);
2603 // tidy-alphabetical-end