1 use std::cell::RefCell;
2 use std::default::Default;
4 use std::lazy::SyncOnceCell as OnceCell;
5 use std::path::PathBuf;
10 use arrayvec::ArrayVec;
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_data_structures::fx::{FxHashMap, FxHashSet};
17 use rustc_data_structures::thin_vec::ThinVec;
19 use rustc_hir::def::{CtorKind, DefKind, Res};
20 use rustc_hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE};
21 use rustc_hir::lang_items::LangItem;
22 use rustc_hir::{BodyId, Mutability};
23 use rustc_index::vec::IndexVec;
24 use rustc_middle::ty::{self, TyCtxt};
25 use rustc_session::Session;
26 use rustc_span::hygiene::MacroKind;
27 use rustc_span::source_map::DUMMY_SP;
28 use rustc_span::symbol::{kw, sym, Ident, Symbol};
29 use rustc_span::{self, FileName, Loc};
30 use rustc_target::abi::VariantIdx;
31 use rustc_target::spec::abi::Abi;
33 use crate::clean::cfg::Cfg;
34 use crate::clean::external_path;
35 use crate::clean::inline::{self, print_inlined_const};
36 use crate::clean::utils::{is_literal_expr, print_const_expr, print_evaluated_const};
37 use crate::clean::Clean;
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 crate use self::FnRetTy::*;
45 crate use self::ItemKind::*;
46 crate use self::SelfTy::*;
47 crate use self::Type::{
48 Array, BareFunction, BorrowedRef, DynTrait, Generic, ImplTrait, Infer, Primitive, QPath,
49 RawPointer, Slice, Tuple,
51 crate use self::Visibility::{Inherited, Public};
53 crate type ItemIdSet = FxHashSet<ItemId>;
55 #[derive(Debug, Clone, PartialEq, Eq, Hash, Copy)]
57 /// A "normal" item that uses a [`DefId`] for identification.
59 /// Identifier that is used for auto traits.
60 Auto { trait_: DefId, for_: DefId },
61 /// Identifier that is used for blanket implementations.
62 Blanket { impl_id: DefId, for_: DefId },
63 /// Identifier for primitive types.
64 Primitive(PrimitiveType, CrateNum),
69 crate fn is_local(self) -> bool {
71 ItemId::Auto { for_: id, .. }
72 | ItemId::Blanket { for_: id, .. }
73 | ItemId::DefId(id) => id.is_local(),
74 ItemId::Primitive(_, krate) => krate == LOCAL_CRATE,
80 crate fn expect_def_id(self) -> DefId {
82 .unwrap_or_else(|| panic!("ItemId::expect_def_id: `{:?}` isn't a DefId", self))
86 crate fn as_def_id(self) -> Option<DefId> {
88 ItemId::DefId(id) => Some(id),
94 crate fn krate(self) -> CrateNum {
96 ItemId::Auto { for_: id, .. }
97 | ItemId::Blanket { for_: id, .. }
98 | ItemId::DefId(id) => id.krate,
99 ItemId::Primitive(_, krate) => krate,
104 crate fn index(self) -> Option<DefIndex> {
106 ItemId::DefId(id) => Some(id.index),
112 impl From<DefId> for ItemId {
113 fn from(id: DefId) -> Self {
118 /// The crate currently being documented.
119 #[derive(Clone, Debug)]
122 crate primitives: ThinVec<(DefId, PrimitiveType)>,
123 /// Only here so that they can be filtered through the rustdoc passes.
124 crate external_traits: Rc<RefCell<FxHashMap<DefId, TraitWithExtraInfo>>>,
127 // `Crate` is frequently moved by-value. Make sure it doesn't unintentionally get bigger.
128 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
129 rustc_data_structures::static_assert_size!(Crate, 72);
132 crate fn name(&self, tcx: TyCtxt<'_>) -> Symbol {
133 ExternalCrate::LOCAL.name(tcx)
136 crate fn src(&self, tcx: TyCtxt<'_>) -> FileName {
137 ExternalCrate::LOCAL.src(tcx)
141 /// This struct is used to wrap additional information added by rustdoc on a `trait` item.
142 #[derive(Clone, Debug)]
143 crate struct TraitWithExtraInfo {
145 crate is_notable: bool,
148 #[derive(Copy, Clone, Debug)]
149 crate struct ExternalCrate {
150 crate crate_num: CrateNum,
154 const LOCAL: Self = Self { crate_num: LOCAL_CRATE };
157 crate fn def_id(&self) -> DefId {
158 DefId { krate: self.crate_num, index: CRATE_DEF_INDEX }
161 crate fn src(&self, tcx: TyCtxt<'_>) -> FileName {
162 let krate_span = tcx.def_span(self.def_id());
163 tcx.sess.source_map().span_to_filename(krate_span)
166 crate fn name(&self, tcx: TyCtxt<'_>) -> Symbol {
167 tcx.crate_name(self.crate_num)
170 crate fn src_root(&self, tcx: TyCtxt<'_>) -> PathBuf {
171 match self.src(tcx) {
172 FileName::Real(ref p) => match p.local_path_if_available().parent() {
173 Some(p) => p.to_path_buf(),
174 None => PathBuf::new(),
180 /// Attempts to find where an external crate is located, given that we're
181 /// rendering in to the specified source destination.
184 extern_url: Option<&str>,
185 extern_url_takes_precedence: bool,
186 dst: &std::path::Path,
188 ) -> ExternalLocation {
189 use ExternalLocation::*;
191 fn to_remote(url: impl ToString) -> ExternalLocation {
192 let mut url = url.to_string();
193 if !url.ends_with('/') {
199 // See if there's documentation generated into the local directory
200 // WARNING: since rustdoc creates these directories as it generates documentation, this check is only accurate before rendering starts.
201 // Make sure to call `location()` by that time.
202 let local_location = dst.join(self.name(tcx).as_str());
203 if local_location.is_dir() {
207 if extern_url_takes_precedence {
208 if let Some(url) = extern_url {
209 return to_remote(url);
213 // Failing that, see if there's an attribute specifying where to find this
215 let did = DefId { krate: self.crate_num, index: CRATE_DEF_INDEX };
218 .filter(|a| a.has_name(sym::html_root_url))
219 .filter_map(|a| a.value_str())
222 .or_else(|| extern_url.map(to_remote)) // NOTE: only matters if `extern_url_takes_precedence` is false
223 .unwrap_or(Unknown) // Well, at least we tried.
226 crate fn keywords(&self, tcx: TyCtxt<'_>) -> ThinVec<(DefId, Symbol)> {
227 let root = self.def_id();
229 let as_keyword = |res: Res<!>| {
230 if let Res::Def(DefKind::Mod, def_id) = res {
231 let attrs = tcx.get_attrs(def_id);
232 let mut keyword = None;
233 for attr in attrs.lists(sym::doc) {
234 if attr.has_name(sym::keyword) {
235 if let Some(v) = attr.value_str() {
241 return keyword.map(|p| (def_id, p));
251 let item = tcx.hir().item(id);
253 hir::ItemKind::Mod(_) => {
254 as_keyword(Res::Def(DefKind::Mod, id.def_id.to_def_id()))
256 hir::ItemKind::Use(path, hir::UseKind::Single)
257 if tcx.visibility(id.def_id).is_public() =>
259 as_keyword(path.res.expect_non_local())
260 .map(|(_, prim)| (id.def_id.to_def_id(), prim))
267 tcx.module_children(root).iter().map(|item| item.res).filter_map(as_keyword).collect()
271 crate fn primitives(&self, tcx: TyCtxt<'_>) -> ThinVec<(DefId, PrimitiveType)> {
272 let root = self.def_id();
274 // Collect all inner modules which are tagged as implementations of
277 // Note that this loop only searches the top-level items of the crate,
278 // and this is intentional. If we were to search the entire crate for an
279 // item tagged with `#[doc(primitive)]` then we would also have to
280 // search the entirety of external modules for items tagged
281 // `#[doc(primitive)]`, which is a pretty inefficient process (decoding
282 // all that metadata unconditionally).
284 // In order to keep the metadata load under control, the
285 // `#[doc(primitive)]` feature is explicitly designed to only allow the
286 // primitive tags to show up as the top level items in a crate.
288 // Also note that this does not attempt to deal with modules tagged
289 // duplicately for the same primitive. This is handled later on when
290 // rendering by delegating everything to a hash map.
291 let as_primitive = |res: Res<!>| {
292 if let Res::Def(DefKind::Mod, def_id) = res {
293 let attrs = tcx.get_attrs(def_id);
295 for attr in attrs.lists(sym::doc) {
296 if let Some(v) = attr.value_str() {
297 if attr.has_name(sym::primitive) {
298 prim = PrimitiveType::from_symbol(v);
302 // FIXME: should warn on unknown primitives?
306 return prim.map(|p| (def_id, p));
317 let item = tcx.hir().item(id);
319 hir::ItemKind::Mod(_) => {
320 as_primitive(Res::Def(DefKind::Mod, id.def_id.to_def_id()))
322 hir::ItemKind::Use(path, hir::UseKind::Single)
323 if tcx.visibility(id.def_id).is_public() =>
325 as_primitive(path.res.expect_non_local()).map(|(_, prim)| {
326 // Pretend the primitive is local.
327 (id.def_id.to_def_id(), prim)
335 tcx.module_children(root).iter().map(|item| item.res).filter_map(as_primitive).collect()
340 /// Indicates where an external crate can be found.
341 crate enum ExternalLocation {
342 /// Remote URL root of the external crate
344 /// This external crate can be found in the local doc/ folder
346 /// The external crate could not be found.
350 /// Anything with a source location and set of attributes and, optionally, a
351 /// name. That is, anything that can be documented. This doesn't correspond
352 /// directly to the AST's concept of an item; it's a strict superset.
353 #[derive(Clone, Debug)]
355 /// The name of this item.
356 /// Optional because not every item has a name, e.g. impls.
357 crate name: Option<Symbol>,
358 crate attrs: Box<Attributes>,
359 crate visibility: Visibility,
360 /// Information about this item that is specific to what kind of item it is.
361 /// E.g., struct vs enum vs function.
362 crate kind: Box<ItemKind>,
363 crate def_id: ItemId,
365 crate cfg: Option<Arc<Cfg>>,
368 // `Item` is used a lot. Make sure it doesn't unintentionally get bigger.
369 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
370 rustc_data_structures::static_assert_size!(Item, 56);
372 crate fn rustc_span(def_id: DefId, tcx: TyCtxt<'_>) -> Span {
373 Span::new(def_id.as_local().map_or_else(
374 || tcx.def_span(def_id),
377 hir.span_with_body(hir.local_def_id_to_hir_id(local))
383 crate fn stability<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Option<&'tcx Stability> {
384 self.def_id.as_def_id().and_then(|did| tcx.lookup_stability(did))
387 crate fn const_stability<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Option<ConstStability> {
388 self.def_id.as_def_id().and_then(|did| tcx.lookup_const_stability(did)).map(|cs| *cs)
391 crate fn deprecation(&self, tcx: TyCtxt<'_>) -> Option<Deprecation> {
392 self.def_id.as_def_id().and_then(|did| tcx.lookup_deprecation(did))
395 crate fn inner_docs(&self, tcx: TyCtxt<'_>) -> bool {
396 self.def_id.as_def_id().map(|did| tcx.get_attrs(did).inner_docs()).unwrap_or(false)
399 crate fn span(&self, tcx: TyCtxt<'_>) -> Span {
400 let kind = match &*self.kind {
401 ItemKind::StrippedItem(k) => k,
405 ItemKind::ModuleItem(Module { span, .. }) => *span,
406 ItemKind::ImplItem(Impl { kind: ImplKind::Auto, .. }) => Span::dummy(),
407 ItemKind::ImplItem(Impl { kind: ImplKind::Blanket(_), .. }) => {
408 if let ItemId::Blanket { impl_id, .. } = self.def_id {
409 rustc_span(impl_id, tcx)
411 panic!("blanket impl item has non-blanket ID")
415 self.def_id.as_def_id().map(|did| rustc_span(did, tcx)).unwrap_or_else(Span::dummy)
420 crate fn attr_span(&self, tcx: TyCtxt<'_>) -> rustc_span::Span {
421 crate::passes::span_of_attrs(&self.attrs).unwrap_or_else(|| self.span(tcx).inner())
424 /// Finds the `doc` attribute as a NameValue and returns the corresponding
426 crate fn doc_value(&self) -> Option<String> {
427 self.attrs.doc_value()
430 /// Convenience wrapper around [`Self::from_def_id_and_parts`] which converts
431 /// `hir_id` to a [`DefId`]
432 crate fn from_hir_id_and_parts(
434 name: Option<Symbol>,
436 cx: &mut DocContext<'_>,
438 Item::from_def_id_and_parts(cx.tcx.hir().local_def_id(hir_id).to_def_id(), name, kind, cx)
441 crate fn from_def_id_and_parts(
443 name: Option<Symbol>,
445 cx: &mut DocContext<'_>,
447 let ast_attrs = cx.tcx.get_attrs(def_id);
449 Self::from_def_id_and_attrs_and_parts(
453 box ast_attrs.clean(cx),
455 ast_attrs.cfg(cx.tcx, &cx.cache.hidden_cfg),
459 crate fn from_def_id_and_attrs_and_parts(
461 name: Option<Symbol>,
463 attrs: Box<Attributes>,
464 cx: &mut DocContext<'_>,
465 cfg: Option<Arc<Cfg>>,
467 trace!("name={:?}, def_id={:?}", name, def_id);
470 def_id: def_id.into(),
474 visibility: cx.tcx.visibility(def_id).clean(cx),
479 /// Finds all `doc` attributes as NameValues and returns their corresponding values, joined
481 crate fn collapsed_doc_value(&self) -> Option<String> {
482 self.attrs.collapsed_doc_value()
485 crate fn links(&self, cx: &Context<'_>) -> Vec<RenderedLink> {
486 use crate::html::format::href;
491 .map_or(&[][..], |v| v.as_slice())
493 .filter_map(|ItemLink { link: s, link_text, did, ref fragment }| {
495 if let Ok((mut href, ..)) = href(*did, cx) {
497 if let Some(ref fragment) = *fragment {
498 fragment.render(&mut href, cx.tcx()).unwrap()
501 original_text: s.clone(),
502 new_text: link_text.clone(),
512 /// Find a list of all link names, without finding their href.
514 /// This is used for generating summary text, which does not include
515 /// the link text, but does need to know which `[]`-bracketed names
516 /// are actually links.
517 crate fn link_names(&self, cache: &Cache) -> Vec<RenderedLink> {
521 .map_or(&[][..], |v| v.as_slice())
523 .map(|ItemLink { link: s, link_text, .. }| RenderedLink {
524 original_text: s.clone(),
525 new_text: link_text.clone(),
531 crate fn is_crate(&self) -> bool {
532 self.is_mod() && self.def_id.as_def_id().map_or(false, |did| did.index == CRATE_DEF_INDEX)
534 crate fn is_mod(&self) -> bool {
535 self.type_() == ItemType::Module
537 crate fn is_trait(&self) -> bool {
538 self.type_() == ItemType::Trait
540 crate fn is_struct(&self) -> bool {
541 self.type_() == ItemType::Struct
543 crate fn is_enum(&self) -> bool {
544 self.type_() == ItemType::Enum
546 crate fn is_variant(&self) -> bool {
547 self.type_() == ItemType::Variant
549 crate fn is_associated_type(&self) -> bool {
550 self.type_() == ItemType::AssocType
552 crate fn is_associated_const(&self) -> bool {
553 self.type_() == ItemType::AssocConst
555 crate fn is_method(&self) -> bool {
556 self.type_() == ItemType::Method
558 crate fn is_ty_method(&self) -> bool {
559 self.type_() == ItemType::TyMethod
561 crate fn is_typedef(&self) -> bool {
562 self.type_() == ItemType::Typedef
564 crate fn is_primitive(&self) -> bool {
565 self.type_() == ItemType::Primitive
567 crate fn is_union(&self) -> bool {
568 self.type_() == ItemType::Union
570 crate fn is_import(&self) -> bool {
571 self.type_() == ItemType::Import
573 crate fn is_extern_crate(&self) -> bool {
574 self.type_() == ItemType::ExternCrate
576 crate fn is_keyword(&self) -> bool {
577 self.type_() == ItemType::Keyword
579 crate fn is_stripped(&self) -> bool {
581 StrippedItem(..) => true,
582 ImportItem(ref i) => !i.should_be_displayed,
586 crate fn has_stripped_fields(&self) -> Option<bool> {
588 StructItem(ref _struct) => Some(_struct.fields_stripped),
589 UnionItem(ref union) => Some(union.fields_stripped),
590 VariantItem(Variant::Struct(ref vstruct)) => Some(vstruct.fields_stripped),
595 crate fn stability_class(&self, tcx: TyCtxt<'_>) -> Option<String> {
596 self.stability(tcx).as_ref().and_then(|s| {
597 let mut classes = Vec::with_capacity(2);
599 if s.level.is_unstable() {
600 classes.push("unstable");
603 // FIXME: what about non-staged API items that are deprecated?
604 if self.deprecation(tcx).is_some() {
605 classes.push("deprecated");
608 if !classes.is_empty() { Some(classes.join(" ")) } else { None }
612 crate fn stable_since(&self, tcx: TyCtxt<'_>) -> Option<Symbol> {
613 match self.stability(tcx)?.level {
614 StabilityLevel::Stable { since, .. } => Some(since),
615 StabilityLevel::Unstable { .. } => None,
619 crate fn const_stable_since(&self, tcx: TyCtxt<'_>) -> Option<Symbol> {
620 match self.const_stability(tcx)?.level {
621 StabilityLevel::Stable { since, .. } => Some(since),
622 StabilityLevel::Unstable { .. } => None,
626 crate fn is_non_exhaustive(&self) -> bool {
627 self.attrs.other_attrs.iter().any(|a| a.has_name(sym::non_exhaustive))
630 /// Returns a documentation-level item type from the item.
631 crate fn type_(&self) -> ItemType {
635 crate fn is_default(&self) -> bool {
637 ItemKind::MethodItem(_, Some(defaultness)) => {
638 defaultness.has_value() && !defaultness.is_final()
645 #[derive(Clone, Debug)]
646 crate enum ItemKind {
648 /// The crate's name, *not* the name it's imported as.
655 FunctionItem(Function),
657 TypedefItem(Typedef, bool /* is associated type */),
658 OpaqueTyItem(OpaqueTy),
660 ConstantItem(Constant),
662 TraitAliasItem(TraitAlias),
664 /// A method signature only. Used for required methods in traits (ie,
665 /// non-default-methods).
666 TyMethodItem(Function),
667 /// A method with a body.
668 MethodItem(Function, Option<hir::Defaultness>),
669 StructFieldItem(Type),
670 VariantItem(Variant),
671 /// `fn`s from an extern block
672 ForeignFunctionItem(Function),
673 /// `static`s from an extern block
674 ForeignStaticItem(Static),
675 /// `type`s from an extern block
678 ProcMacroItem(ProcMacro),
679 PrimitiveItem(PrimitiveType),
680 AssocConstItem(Type, Option<ConstantKind>),
681 /// An associated item in a trait or trait impl.
683 /// The bounds may be non-empty if there is a `where` clause.
684 /// The `Option<Type>` is the default concrete type (e.g. `trait Trait { type Target = usize; }`)
685 AssocTypeItem(Vec<GenericBound>, Option<Type>),
686 /// An item that has been stripped by a rustdoc pass
687 StrippedItem(Box<ItemKind>),
692 /// Some items contain others such as structs (for their fields) and Enums
693 /// (for their variants). This method returns those contained items.
694 crate fn inner_items(&self) -> impl Iterator<Item = &Item> {
696 StructItem(s) => s.fields.iter(),
697 UnionItem(u) => u.fields.iter(),
698 VariantItem(Variant::Struct(v)) => v.fields.iter(),
699 VariantItem(Variant::Tuple(v)) => v.iter(),
700 EnumItem(e) => e.variants.iter(),
701 TraitItem(t) => t.items.iter(),
702 ImplItem(i) => i.items.iter(),
703 ModuleItem(m) => m.items.iter(),
704 ExternCrateItem { .. }
716 | ForeignFunctionItem(_)
717 | ForeignStaticItem(_)
722 | AssocConstItem(_, _)
723 | AssocTypeItem(_, _)
725 | KeywordItem(_) => [].iter(),
730 #[derive(Clone, Debug)]
731 crate struct Module {
732 crate items: Vec<Item>,
736 crate trait AttributesExt {
737 type AttributeIterator<'a>: Iterator<Item = ast::NestedMetaItem>
741 fn lists<'a>(&'a self, name: Symbol) -> Self::AttributeIterator<'a>;
743 fn span(&self) -> Option<rustc_span::Span>;
745 fn inner_docs(&self) -> bool;
747 fn other_attrs(&self) -> Vec<ast::Attribute>;
749 fn cfg(&self, tcx: TyCtxt<'_>, hidden_cfg: &FxHashSet<Cfg>) -> Option<Arc<Cfg>>;
752 impl AttributesExt for [ast::Attribute] {
753 type AttributeIterator<'a> = impl Iterator<Item = ast::NestedMetaItem> + 'a;
755 fn lists<'a>(&'a self, name: Symbol) -> Self::AttributeIterator<'a> {
757 .filter(move |attr| attr.has_name(name))
758 .filter_map(ast::Attribute::meta_item_list)
762 /// Return the span of the first doc-comment, if it exists.
763 fn span(&self) -> Option<rustc_span::Span> {
764 self.iter().find(|attr| attr.doc_str().is_some()).map(|attr| attr.span)
767 /// Returns whether the first doc-comment is an inner attribute.
769 //// If there are no doc-comments, return true.
770 /// FIXME(#78591): Support both inner and outer attributes on the same item.
771 fn inner_docs(&self) -> bool {
772 self.iter().find(|a| a.doc_str().is_some()).map_or(true, |a| a.style == AttrStyle::Inner)
775 fn other_attrs(&self) -> Vec<ast::Attribute> {
776 self.iter().filter(|attr| attr.doc_str().is_none()).cloned().collect()
779 fn cfg(&self, tcx: TyCtxt<'_>, hidden_cfg: &FxHashSet<Cfg>) -> Option<Arc<Cfg>> {
781 let doc_cfg_active = tcx.features().doc_cfg;
782 let doc_auto_cfg_active = tcx.features().doc_auto_cfg;
784 fn single<T: IntoIterator>(it: T) -> Option<T::Item> {
785 let mut iter = it.into_iter();
786 let item = iter.next()?;
787 if iter.next().is_some() {
793 let mut cfg = if doc_cfg_active || doc_auto_cfg_active {
794 let mut doc_cfg = self
796 .filter(|attr| attr.has_name(sym::doc))
797 .flat_map(|attr| attr.meta_item_list().unwrap_or_else(Vec::new))
798 .filter(|attr| attr.has_name(sym::cfg))
800 if doc_cfg.peek().is_some() && doc_cfg_active {
802 .filter_map(|attr| Cfg::parse(attr.meta_item()?).ok())
803 .fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg)
804 } else if doc_auto_cfg_active {
806 .filter(|attr| attr.has_name(sym::cfg))
807 .filter_map(|attr| single(attr.meta_item_list()?))
809 Cfg::parse_without(attr.meta_item()?, hidden_cfg).ok().flatten()
811 .fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg)
819 for attr in self.iter() {
821 if attr.doc_str().is_none() && attr.has_name(sym::doc) {
823 if let Some(list) = attr.meta().as_ref().and_then(|mi| mi.meta_item_list()) {
826 if !item.has_name(sym::cfg) {
830 if let Some(cfg_mi) = item
832 .and_then(|item| rustc_expand::config::parse_cfg(item, sess))
834 match Cfg::parse(cfg_mi) {
835 Ok(new_cfg) => cfg &= new_cfg,
836 Err(e) => sess.span_err(e.span, e.msg),
844 // treat #[target_feature(enable = "feat")] attributes as if they were
845 // #[doc(cfg(target_feature = "feat"))] attributes as well
846 for attr in self.lists(sym::target_feature) {
847 if attr.has_name(sym::enable) {
848 if let Some(feat) = attr.value_str() {
849 let meta = attr::mk_name_value_item_str(
850 Ident::with_dummy_span(sym::target_feature),
854 if let Ok(feat_cfg) = Cfg::parse(&meta) {
861 if cfg == Cfg::True { None } else { Some(Arc::new(cfg)) }
865 crate trait NestedAttributesExt {
866 /// Returns `true` if the attribute list contains a specific `word`
867 fn has_word(self, word: Symbol) -> bool
869 Self: std::marker::Sized,
871 <Self as NestedAttributesExt>::get_word_attr(self, word).is_some()
874 /// Returns `Some(attr)` if the attribute list contains 'attr'
875 /// corresponding to a specific `word`
876 fn get_word_attr(self, word: Symbol) -> Option<ast::NestedMetaItem>;
879 impl<I: Iterator<Item = ast::NestedMetaItem>> NestedAttributesExt for I {
880 fn get_word_attr(mut self, word: Symbol) -> Option<ast::NestedMetaItem> {
881 self.find(|attr| attr.is_word() && attr.has_name(word))
885 /// A portion of documentation, extracted from a `#[doc]` attribute.
887 /// Each variant contains the line number within the complete doc-comment where the fragment
888 /// starts, as well as the Span where the corresponding doc comment or attribute is located.
890 /// Included files are kept separate from inline doc comments so that proper line-number
891 /// information can be given when a doctest fails. Sugared doc comments and "raw" doc comments are
892 /// kept separate because of issue #42760.
893 #[derive(Clone, PartialEq, Eq, Debug)]
894 crate struct DocFragment {
895 crate span: rustc_span::Span,
896 /// The module this doc-comment came from.
898 /// This allows distinguishing between the original documentation and a pub re-export.
899 /// If it is `None`, the item was not re-exported.
900 crate parent_module: Option<DefId>,
902 crate kind: DocFragmentKind,
906 // `DocFragment` is used a lot. Make sure it doesn't unintentionally get bigger.
907 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
908 rustc_data_structures::static_assert_size!(DocFragment, 32);
910 #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
911 crate enum DocFragmentKind {
912 /// A doc fragment created from a `///` or `//!` doc comment.
914 /// A doc fragment created from a "raw" `#[doc=""]` attribute.
918 /// The goal of this function is to apply the `DocFragment` transformation that is required when
919 /// transforming into the final Markdown, which is applying the computed indent to each line in
920 /// each doc fragment (a `DocFragment` can contain multiple lines in case of `#[doc = ""]`).
922 /// Note: remove the trailing newline where appropriate
923 fn add_doc_fragment(out: &mut String, frag: &DocFragment) {
924 let s = frag.doc.as_str();
925 let mut iter = s.lines();
930 while let Some(line) = iter.next() {
931 if line.chars().any(|c| !c.is_whitespace()) {
932 assert!(line.len() >= frag.indent);
933 out.push_str(&line[frag.indent..]);
941 /// Collapse a collection of [`DocFragment`]s into one string,
942 /// handling indentation and newlines as needed.
943 crate fn collapse_doc_fragments(doc_strings: &[DocFragment]) -> String {
944 let mut acc = String::new();
945 for frag in doc_strings {
946 add_doc_fragment(&mut acc, frag);
952 /// A link that has not yet been rendered.
954 /// This link will be turned into a rendered link by [`Item::links`].
955 #[derive(Clone, Debug, PartialEq, Eq, Hash)]
956 crate struct ItemLink {
957 /// The original link written in the markdown
959 /// The link text displayed in the HTML.
961 /// This may not be the same as `link` if there was a disambiguator
962 /// in an intra-doc link (e.g. \[`fn@f`\])
963 crate link_text: String,
965 /// The url fragment to append to the link
966 crate fragment: Option<UrlFragment>,
969 pub struct RenderedLink {
970 /// The text the link was original written as.
972 /// This could potentially include disambiguators and backticks.
973 crate original_text: String,
974 /// The text to display in the HTML
975 crate new_text: String,
976 /// The URL to put in the `href`
980 /// The attributes on an [`Item`], including attributes like `#[derive(...)]` and `#[inline]`,
981 /// as well as doc comments.
982 #[derive(Clone, Debug, Default)]
983 crate struct Attributes {
984 crate doc_strings: Vec<DocFragment>,
985 crate other_attrs: Vec<ast::Attribute>,
989 crate fn lists(&self, name: Symbol) -> impl Iterator<Item = ast::NestedMetaItem> + '_ {
990 self.other_attrs.lists(name)
993 crate fn has_doc_flag(&self, flag: Symbol) -> bool {
994 for attr in &self.other_attrs {
995 if !attr.has_name(sym::doc) {
999 if let Some(items) = attr.meta_item_list() {
1000 if items.iter().filter_map(|i| i.meta_item()).any(|it| it.has_name(flag)) {
1010 attrs: &[ast::Attribute],
1011 additional_attrs: Option<(&[ast::Attribute], DefId)>,
1013 let mut doc_strings: Vec<DocFragment> = vec![];
1014 let clean_attr = |(attr, parent_module): (&ast::Attribute, Option<DefId>)| {
1015 if let Some((value, kind)) = attr.doc_str_and_comment_kind() {
1016 trace!("got doc_str={:?}", value);
1017 let value = beautify_doc_string(value, kind);
1018 let kind = if attr.is_doc_comment() {
1019 DocFragmentKind::SugaredDoc
1021 DocFragmentKind::RawDoc
1025 DocFragment { span: attr.span, doc: value, kind, parent_module, indent: 0 };
1027 doc_strings.push(frag);
1035 // Additional documentation should be shown before the original documentation
1036 let other_attrs = additional_attrs
1038 .map(|(attrs, id)| attrs.iter().map(move |attr| (attr, Some(id))))
1040 .chain(attrs.iter().map(|attr| (attr, None)))
1041 .filter_map(clean_attr)
1044 Attributes { doc_strings, other_attrs }
1047 /// Finds the `doc` attribute as a NameValue and returns the corresponding
1049 crate fn doc_value(&self) -> Option<String> {
1050 let mut iter = self.doc_strings.iter();
1052 let ori = iter.next()?;
1053 let mut out = String::new();
1054 add_doc_fragment(&mut out, ori);
1055 for new_frag in iter {
1056 add_doc_fragment(&mut out, new_frag);
1059 if out.is_empty() { None } else { Some(out) }
1062 /// Return the doc-comments on this item, grouped by the module they came from.
1064 /// The module can be different if this is a re-export with added documentation.
1065 crate fn collapsed_doc_value_by_module_level(&self) -> FxHashMap<Option<DefId>, String> {
1066 let mut ret = FxHashMap::default();
1067 if self.doc_strings.len() == 0 {
1070 let last_index = self.doc_strings.len() - 1;
1072 for (i, new_frag) in self.doc_strings.iter().enumerate() {
1073 let out = ret.entry(new_frag.parent_module).or_default();
1074 add_doc_fragment(out, new_frag);
1075 if i == last_index {
1082 /// Finds all `doc` attributes as NameValues and returns their corresponding values, joined
1084 crate fn collapsed_doc_value(&self) -> Option<String> {
1085 if self.doc_strings.is_empty() {
1088 Some(collapse_doc_fragments(&self.doc_strings))
1092 crate fn get_doc_aliases(&self) -> Box<[Symbol]> {
1093 let mut aliases = FxHashSet::default();
1095 for attr in self.other_attrs.lists(sym::doc).filter(|a| a.has_name(sym::alias)) {
1096 if let Some(values) = attr.meta_item_list() {
1098 match l.literal().unwrap().kind {
1099 ast::LitKind::Str(s, _) => {
1102 _ => unreachable!(),
1106 aliases.insert(attr.value_str().unwrap());
1109 aliases.into_iter().collect::<Vec<_>>().into()
1113 impl PartialEq for Attributes {
1114 fn eq(&self, rhs: &Self) -> bool {
1115 self.doc_strings == rhs.doc_strings
1119 .map(|attr| attr.id)
1120 .eq(rhs.other_attrs.iter().map(|attr| attr.id))
1124 impl Eq for Attributes {}
1126 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
1127 crate enum GenericBound {
1128 TraitBound(PolyTrait, hir::TraitBoundModifier),
1133 crate fn maybe_sized(cx: &mut DocContext<'_>) -> GenericBound {
1134 let did = cx.tcx.require_lang_item(LangItem::Sized, None);
1135 let empty = cx.tcx.intern_substs(&[]);
1136 let path = external_path(cx, did, false, vec![], empty);
1137 inline::record_extern_fqn(cx, did, ItemType::Trait);
1138 GenericBound::TraitBound(
1139 PolyTrait { trait_: path, generic_params: Vec::new() },
1140 hir::TraitBoundModifier::Maybe,
1144 crate fn is_sized_bound(&self, cx: &DocContext<'_>) -> bool {
1145 use rustc_hir::TraitBoundModifier as TBM;
1146 if let GenericBound::TraitBound(PolyTrait { ref trait_, .. }, TBM::None) = *self {
1147 if Some(trait_.def_id()) == cx.tcx.lang_items().sized_trait() {
1154 crate fn get_poly_trait(&self) -> Option<PolyTrait> {
1155 if let GenericBound::TraitBound(ref p, _) = *self {
1156 return Some(p.clone());
1161 crate fn get_trait_path(&self) -> Option<Path> {
1162 if let GenericBound::TraitBound(PolyTrait { ref trait_, .. }, _) = *self {
1163 Some(trait_.clone())
1170 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
1171 crate struct Lifetime(pub Symbol);
1174 crate fn statik() -> Lifetime {
1175 Lifetime(kw::StaticLifetime)
1178 crate fn elided() -> Lifetime {
1179 Lifetime(kw::UnderscoreLifetime)
1183 #[derive(Clone, Debug)]
1184 crate enum WherePredicate {
1185 BoundPredicate { ty: Type, bounds: Vec<GenericBound>, bound_params: Vec<Lifetime> },
1186 RegionPredicate { lifetime: Lifetime, bounds: Vec<GenericBound> },
1187 EqPredicate { lhs: Type, rhs: Term },
1190 impl WherePredicate {
1191 crate fn get_bounds(&self) -> Option<&[GenericBound]> {
1193 WherePredicate::BoundPredicate { ref bounds, .. } => Some(bounds),
1194 WherePredicate::RegionPredicate { ref bounds, .. } => Some(bounds),
1200 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
1201 crate enum GenericParamDefKind {
1202 Lifetime { outlives: Vec<Lifetime> },
1203 Type { did: DefId, bounds: Vec<GenericBound>, default: Option<Box<Type>>, synthetic: bool },
1204 Const { did: DefId, ty: Box<Type>, default: Option<Box<String>> },
1207 impl GenericParamDefKind {
1208 crate fn is_type(&self) -> bool {
1209 matches!(self, GenericParamDefKind::Type { .. })
1213 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
1214 crate struct GenericParamDef {
1216 crate kind: GenericParamDefKind,
1219 // `GenericParamDef` is used in many places. Make sure it doesn't unintentionally get bigger.
1220 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
1221 rustc_data_structures::static_assert_size!(GenericParamDef, 56);
1223 impl GenericParamDef {
1224 crate fn is_synthetic_type_param(&self) -> bool {
1226 GenericParamDefKind::Lifetime { .. } | GenericParamDefKind::Const { .. } => false,
1227 GenericParamDefKind::Type { synthetic, .. } => synthetic,
1231 crate fn is_type(&self) -> bool {
1235 crate fn get_bounds(&self) -> Option<&[GenericBound]> {
1237 GenericParamDefKind::Type { ref bounds, .. } => Some(bounds),
1243 // maybe use a Generic enum and use Vec<Generic>?
1244 #[derive(Clone, Debug, Default)]
1245 crate struct Generics {
1246 crate params: Vec<GenericParamDef>,
1247 crate where_predicates: Vec<WherePredicate>,
1250 #[derive(Clone, Debug)]
1251 crate struct Function {
1253 crate generics: Generics,
1254 crate header: hir::FnHeader,
1257 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
1258 crate struct FnDecl {
1259 crate inputs: Arguments,
1260 crate output: FnRetTy,
1261 crate c_variadic: bool,
1265 crate fn self_type(&self) -> Option<SelfTy> {
1266 self.inputs.values.get(0).and_then(|v| v.to_self())
1269 /// Returns the sugared return type for an async function.
1271 /// For example, if the return type is `impl std::future::Future<Output = i32>`, this function
1272 /// will return `i32`.
1276 /// This function will panic if the return type does not match the expected sugaring for async
1278 crate fn sugared_async_return_type(&self) -> FnRetTy {
1279 match &self.output {
1280 FnRetTy::Return(Type::ImplTrait(bounds)) => match &bounds[0] {
1281 GenericBound::TraitBound(PolyTrait { trait_, .. }, ..) => {
1282 let bindings = trait_.bindings().unwrap();
1283 let ret_ty = bindings[0].term();
1284 let ty = ret_ty.ty().expect("Unexpected constant return term");
1285 FnRetTy::Return(ty.clone())
1287 _ => panic!("unexpected desugaring of async function"),
1289 _ => panic!("unexpected desugaring of async function"),
1294 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
1295 crate struct Arguments {
1296 crate values: Vec<Argument>,
1299 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
1300 crate struct Argument {
1303 /// This field is used to represent "const" arguments from the `rustc_legacy_const_generics`
1304 /// feature. More information in <https://github.com/rust-lang/rust/issues/83167>.
1305 crate is_const: bool,
1308 #[derive(Clone, PartialEq, Debug)]
1311 SelfBorrowed(Option<Lifetime>, Mutability),
1316 crate fn to_self(&self) -> Option<SelfTy> {
1317 if self.name != kw::SelfLower {
1320 if self.type_.is_self_type() {
1321 return Some(SelfValue);
1324 BorrowedRef { ref lifetime, mutability, ref type_ } if type_.is_self_type() => {
1325 Some(SelfBorrowed(lifetime.clone(), mutability))
1327 _ => Some(SelfExplicit(self.type_.clone())),
1332 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
1333 crate enum FnRetTy {
1339 crate fn as_return(&self) -> Option<&Type> {
1341 Return(ret) => Some(ret),
1342 DefaultReturn => None,
1347 #[derive(Clone, Debug)]
1348 crate struct Trait {
1349 crate unsafety: hir::Unsafety,
1350 crate items: Vec<Item>,
1351 crate generics: Generics,
1352 crate bounds: Vec<GenericBound>,
1353 crate is_auto: bool,
1356 #[derive(Clone, Debug)]
1357 crate struct TraitAlias {
1358 crate generics: Generics,
1359 crate bounds: Vec<GenericBound>,
1362 /// A trait reference, which may have higher ranked lifetimes.
1363 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
1364 crate struct PolyTrait {
1366 crate generic_params: Vec<GenericParamDef>,
1369 /// Rustdoc's representation of types, mostly based on the [`hir::Ty`].
1370 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
1372 /// A named type, which could be a trait.
1374 /// This is mostly Rustdoc's version of [`hir::Path`].
1375 /// It has to be different because Rustdoc's [`PathSegment`] can contain cleaned generics.
1376 Path { path: Path },
1377 /// A `dyn Trait` object: `dyn for<'a> Trait<'a> + Send + 'static`
1378 DynTrait(Vec<PolyTrait>, Option<Lifetime>),
1379 /// A type parameter.
1381 /// A primitive (aka, builtin) type.
1382 Primitive(PrimitiveType),
1383 /// A function pointer: `extern "ABI" fn(...) -> ...`
1384 BareFunction(Box<BareFunctionDecl>),
1385 /// A tuple type: `(i32, &str)`.
1387 /// A slice type (does *not* include the `&`): `[i32]`
1391 /// The `String` field is a stringified version of the array's length parameter.
1392 Array(Box<Type>, String),
1393 /// A raw pointer type: `*const i32`, `*mut i32`
1394 RawPointer(Mutability, Box<Type>),
1395 /// A reference type: `&i32`, `&'a mut Foo`
1396 BorrowedRef { lifetime: Option<Lifetime>, mutability: Mutability, type_: Box<Type> },
1398 /// A qualified path to an associated item: `<Type as Trait>::Name`
1401 self_type: Box<Type>,
1402 /// FIXME: This is a hack that should be removed; see [this discussion][1].
1404 /// [1]: https://github.com/rust-lang/rust/pull/85479#discussion_r635729093
1405 self_def_id: Option<DefId>,
1409 /// A type that is inferred: `_`
1412 /// An `impl Trait`: `impl TraitA + TraitB + ...`
1413 ImplTrait(Vec<GenericBound>),
1416 // `Type` is used a lot. Make sure it doesn't unintentionally get bigger.
1417 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
1418 rustc_data_structures::static_assert_size!(Type, 72);
1421 /// When comparing types for equality, it can help to ignore `&` wrapping.
1422 crate fn without_borrowed_ref(&self) -> &Type {
1423 let mut result = self;
1424 while let Type::BorrowedRef { type_, .. } = result {
1430 /// Check if two types are "potentially the same".
1431 /// This is different from `Eq`, because it knows that things like
1432 /// `Placeholder` are possible matches for everything.
1433 crate fn is_same(&self, other: &Self, cache: &Cache) -> bool {
1434 match (self, other) {
1436 (Type::Tuple(a), Type::Tuple(b)) => {
1437 a.len() == b.len() && a.iter().zip(b).all(|(a, b)| a.is_same(&b, cache))
1439 (Type::Slice(a), Type::Slice(b)) => a.is_same(&b, cache),
1440 (Type::Array(a, al), Type::Array(b, bl)) => al == bl && a.is_same(&b, cache),
1441 (Type::RawPointer(mutability, type_), Type::RawPointer(b_mutability, b_type_)) => {
1442 mutability == b_mutability && type_.is_same(&b_type_, cache)
1445 Type::BorrowedRef { mutability, type_, .. },
1446 Type::BorrowedRef { mutability: b_mutability, type_: b_type_, .. },
1447 ) => mutability == b_mutability && type_.is_same(&b_type_, cache),
1448 // Placeholders and generics are equal to all other types.
1449 (Type::Infer, _) | (_, Type::Infer) => true,
1450 (Type::Generic(_), _) | (_, Type::Generic(_)) => true,
1451 // Other cases, such as primitives, just use recursion.
1454 .and_then(|a| Some((a, b.def_id(cache)?)))
1455 .map(|(a, b)| a == b)
1460 crate fn primitive_type(&self) -> Option<PrimitiveType> {
1462 Primitive(p) | BorrowedRef { type_: box Primitive(p), .. } => Some(p),
1463 Slice(..) | BorrowedRef { type_: box Slice(..), .. } => Some(PrimitiveType::Slice),
1464 Array(..) | BorrowedRef { type_: box Array(..), .. } => Some(PrimitiveType::Array),
1467 Some(PrimitiveType::Unit)
1469 Some(PrimitiveType::Tuple)
1472 RawPointer(..) => Some(PrimitiveType::RawPointer),
1473 BareFunction(..) => Some(PrimitiveType::Fn),
1478 /// Checks if this is a `T::Name` path for an associated type.
1479 crate fn is_assoc_ty(&self) -> bool {
1481 Type::Path { path, .. } => path.is_assoc_ty(),
1486 crate fn is_self_type(&self) -> bool {
1488 Generic(name) => name == kw::SelfUpper,
1493 crate fn generics(&self) -> Option<Vec<&Type>> {
1495 Type::Path { path, .. } => path.generics(),
1500 crate fn is_full_generic(&self) -> bool {
1501 matches!(self, Type::Generic(_))
1504 crate fn is_primitive(&self) -> bool {
1505 self.primitive_type().is_some()
1508 crate fn projection(&self) -> Option<(&Type, DefId, Symbol)> {
1509 let (self_, trait_, name) = match self {
1510 QPath { self_type, trait_, name, .. } => (self_type, trait_, name),
1513 Some((&self_, trait_.def_id(), *name))
1516 fn inner_def_id(&self, cache: Option<&Cache>) -> Option<DefId> {
1517 let t: PrimitiveType = match *self {
1518 Type::Path { ref path } => return Some(path.def_id()),
1519 DynTrait(ref bounds, _) => return Some(bounds[0].trait_.def_id()),
1520 Primitive(p) => return cache.and_then(|c| c.primitive_locations.get(&p).cloned()),
1521 BorrowedRef { type_: box Generic(..), .. } => PrimitiveType::Reference,
1522 BorrowedRef { ref type_, .. } => return type_.inner_def_id(cache),
1527 PrimitiveType::Tuple
1530 BareFunction(..) => PrimitiveType::Fn,
1531 Slice(..) => PrimitiveType::Slice,
1532 Array(..) => PrimitiveType::Array,
1533 RawPointer(..) => PrimitiveType::RawPointer,
1534 QPath { ref self_type, .. } => return self_type.inner_def_id(cache),
1535 Generic(_) | Infer | ImplTrait(_) => return None,
1537 cache.and_then(|c| Primitive(t).def_id(c))
1540 /// Use this method to get the [DefId] of a [clean] AST node, including [PrimitiveType]s.
1542 /// See [`Self::def_id_no_primitives`] for more.
1544 /// [clean]: crate::clean
1545 crate fn def_id(&self, cache: &Cache) -> Option<DefId> {
1546 self.inner_def_id(Some(cache))
1549 /// Use this method to get the [`DefId`] of a [`clean`] AST node.
1550 /// This will return [`None`] when called on a primitive [`clean::Type`].
1551 /// Use [`Self::def_id`] if you want to include primitives.
1553 /// [`clean`]: crate::clean
1554 /// [`clean::Type`]: crate::clean::Type
1555 // FIXME: get rid of this function and always use `def_id`
1556 crate fn def_id_no_primitives(&self) -> Option<DefId> {
1557 self.inner_def_id(None)
1561 /// A primitive (aka, builtin) type.
1563 /// This represents things like `i32`, `str`, etc.
1565 /// N.B. This has to be different from [`hir::PrimTy`] because it also includes types that aren't
1566 /// paths, like [`Self::Unit`].
1567 #[derive(Clone, PartialEq, Eq, Hash, Copy, Debug)]
1568 crate enum PrimitiveType {
1596 impl PrimitiveType {
1597 crate fn from_hir(prim: hir::PrimTy) -> PrimitiveType {
1598 use ast::{FloatTy, IntTy, UintTy};
1600 hir::PrimTy::Int(IntTy::Isize) => PrimitiveType::Isize,
1601 hir::PrimTy::Int(IntTy::I8) => PrimitiveType::I8,
1602 hir::PrimTy::Int(IntTy::I16) => PrimitiveType::I16,
1603 hir::PrimTy::Int(IntTy::I32) => PrimitiveType::I32,
1604 hir::PrimTy::Int(IntTy::I64) => PrimitiveType::I64,
1605 hir::PrimTy::Int(IntTy::I128) => PrimitiveType::I128,
1606 hir::PrimTy::Uint(UintTy::Usize) => PrimitiveType::Usize,
1607 hir::PrimTy::Uint(UintTy::U8) => PrimitiveType::U8,
1608 hir::PrimTy::Uint(UintTy::U16) => PrimitiveType::U16,
1609 hir::PrimTy::Uint(UintTy::U32) => PrimitiveType::U32,
1610 hir::PrimTy::Uint(UintTy::U64) => PrimitiveType::U64,
1611 hir::PrimTy::Uint(UintTy::U128) => PrimitiveType::U128,
1612 hir::PrimTy::Float(FloatTy::F32) => PrimitiveType::F32,
1613 hir::PrimTy::Float(FloatTy::F64) => PrimitiveType::F64,
1614 hir::PrimTy::Str => PrimitiveType::Str,
1615 hir::PrimTy::Bool => PrimitiveType::Bool,
1616 hir::PrimTy::Char => PrimitiveType::Char,
1620 crate fn from_symbol(s: Symbol) -> Option<PrimitiveType> {
1622 sym::isize => Some(PrimitiveType::Isize),
1623 sym::i8 => Some(PrimitiveType::I8),
1624 sym::i16 => Some(PrimitiveType::I16),
1625 sym::i32 => Some(PrimitiveType::I32),
1626 sym::i64 => Some(PrimitiveType::I64),
1627 sym::i128 => Some(PrimitiveType::I128),
1628 sym::usize => Some(PrimitiveType::Usize),
1629 sym::u8 => Some(PrimitiveType::U8),
1630 sym::u16 => Some(PrimitiveType::U16),
1631 sym::u32 => Some(PrimitiveType::U32),
1632 sym::u64 => Some(PrimitiveType::U64),
1633 sym::u128 => Some(PrimitiveType::U128),
1634 sym::bool => Some(PrimitiveType::Bool),
1635 sym::char => Some(PrimitiveType::Char),
1636 sym::str => Some(PrimitiveType::Str),
1637 sym::f32 => Some(PrimitiveType::F32),
1638 sym::f64 => Some(PrimitiveType::F64),
1639 sym::array => Some(PrimitiveType::Array),
1640 sym::slice => Some(PrimitiveType::Slice),
1641 sym::tuple => Some(PrimitiveType::Tuple),
1642 sym::unit => Some(PrimitiveType::Unit),
1643 sym::pointer => Some(PrimitiveType::RawPointer),
1644 sym::reference => Some(PrimitiveType::Reference),
1645 kw::Fn => Some(PrimitiveType::Fn),
1646 sym::never => Some(PrimitiveType::Never),
1651 crate fn impls(&self, tcx: TyCtxt<'_>) -> &'static ArrayVec<DefId, 4> {
1652 Self::all_impls(tcx).get(self).expect("missing impl for primitive type")
1655 crate fn all_impls(tcx: TyCtxt<'_>) -> &'static FxHashMap<PrimitiveType, ArrayVec<DefId, 4>> {
1656 static CELL: OnceCell<FxHashMap<PrimitiveType, ArrayVec<DefId, 4>>> = OnceCell::new();
1658 CELL.get_or_init(move || {
1659 use self::PrimitiveType::*;
1661 let single = |a: Option<DefId>| a.into_iter().collect();
1662 let both = |a: Option<DefId>, b: Option<DefId>| -> ArrayVec<_, 4> {
1663 a.into_iter().chain(b).collect()
1666 let lang_items = tcx.lang_items();
1668 Isize => single(lang_items.isize_impl()),
1669 I8 => single(lang_items.i8_impl()),
1670 I16 => single(lang_items.i16_impl()),
1671 I32 => single(lang_items.i32_impl()),
1672 I64 => single(lang_items.i64_impl()),
1673 I128 => single(lang_items.i128_impl()),
1674 Usize => single(lang_items.usize_impl()),
1675 U8 => single(lang_items.u8_impl()),
1676 U16 => single(lang_items.u16_impl()),
1677 U32 => single(lang_items.u32_impl()),
1678 U64 => single(lang_items.u64_impl()),
1679 U128 => single(lang_items.u128_impl()),
1680 F32 => both(lang_items.f32_impl(), lang_items.f32_runtime_impl()),
1681 F64 => both(lang_items.f64_impl(), lang_items.f64_runtime_impl()),
1682 Char => single(lang_items.char_impl()),
1683 Bool => single(lang_items.bool_impl()),
1684 Str => both(lang_items.str_impl(), lang_items.str_alloc_impl()),
1689 .chain(lang_items.slice_u8_impl())
1690 .chain(lang_items.slice_alloc_impl())
1691 .chain(lang_items.slice_u8_alloc_impl())
1694 Array => single(lang_items.array_impl()),
1695 Tuple => ArrayVec::new(),
1696 Unit => ArrayVec::new(),
1701 .chain(lang_items.mut_ptr_impl())
1702 .chain(lang_items.const_slice_ptr_impl())
1703 .chain(lang_items.mut_slice_ptr_impl())
1706 Reference => ArrayVec::new(),
1707 Fn => ArrayVec::new(),
1708 Never => ArrayVec::new(),
1713 crate fn as_sym(&self) -> Symbol {
1714 use PrimitiveType::*;
1716 Isize => sym::isize,
1722 Usize => sym::usize,
1733 Array => sym::array,
1734 Slice => sym::slice,
1735 Tuple => sym::tuple,
1737 RawPointer => sym::pointer,
1738 Reference => sym::reference,
1740 Never => sym::never,
1744 /// Returns the DefId of the module with `doc(primitive)` for this primitive type.
1745 /// Panics if there is no such module.
1747 /// This gives precedence to primitives defined in the current crate, and deprioritizes primitives defined in `core`,
1748 /// but otherwise, if multiple crates define the same primitive, there is no guarantee of which will be picked.
1749 /// In particular, if a crate depends on both `std` and another crate that also defines `doc(primitive)`, then
1750 /// it's entirely random whether `std` or the other crate is picked. (no_std crates are usually fine unless multiple dependencies define a primitive.)
1751 crate fn primitive_locations(tcx: TyCtxt<'_>) -> &FxHashMap<PrimitiveType, DefId> {
1752 static PRIMITIVE_LOCATIONS: OnceCell<FxHashMap<PrimitiveType, DefId>> = OnceCell::new();
1753 PRIMITIVE_LOCATIONS.get_or_init(|| {
1754 let mut primitive_locations = FxHashMap::default();
1755 // NOTE: technically this misses crates that are only passed with `--extern` and not loaded when checking the crate.
1756 // This is a degenerate case that I don't plan to support.
1757 for &crate_num in tcx.crates(()) {
1758 let e = ExternalCrate { crate_num };
1759 let crate_name = e.name(tcx);
1760 debug!(?crate_num, ?crate_name);
1761 for &(def_id, prim) in &e.primitives(tcx) {
1762 // HACK: try to link to std instead where possible
1763 if crate_name == sym::core && primitive_locations.contains_key(&prim) {
1766 primitive_locations.insert(prim, def_id);
1769 let local_primitives = ExternalCrate { crate_num: LOCAL_CRATE }.primitives(tcx);
1770 for (def_id, prim) in local_primitives {
1771 primitive_locations.insert(prim, def_id);
1778 impl From<ast::IntTy> for PrimitiveType {
1779 fn from(int_ty: ast::IntTy) -> PrimitiveType {
1781 ast::IntTy::Isize => PrimitiveType::Isize,
1782 ast::IntTy::I8 => PrimitiveType::I8,
1783 ast::IntTy::I16 => PrimitiveType::I16,
1784 ast::IntTy::I32 => PrimitiveType::I32,
1785 ast::IntTy::I64 => PrimitiveType::I64,
1786 ast::IntTy::I128 => PrimitiveType::I128,
1791 impl From<ast::UintTy> for PrimitiveType {
1792 fn from(uint_ty: ast::UintTy) -> PrimitiveType {
1794 ast::UintTy::Usize => PrimitiveType::Usize,
1795 ast::UintTy::U8 => PrimitiveType::U8,
1796 ast::UintTy::U16 => PrimitiveType::U16,
1797 ast::UintTy::U32 => PrimitiveType::U32,
1798 ast::UintTy::U64 => PrimitiveType::U64,
1799 ast::UintTy::U128 => PrimitiveType::U128,
1804 impl From<ast::FloatTy> for PrimitiveType {
1805 fn from(float_ty: ast::FloatTy) -> PrimitiveType {
1807 ast::FloatTy::F32 => PrimitiveType::F32,
1808 ast::FloatTy::F64 => PrimitiveType::F64,
1813 impl From<ty::IntTy> for PrimitiveType {
1814 fn from(int_ty: ty::IntTy) -> PrimitiveType {
1816 ty::IntTy::Isize => PrimitiveType::Isize,
1817 ty::IntTy::I8 => PrimitiveType::I8,
1818 ty::IntTy::I16 => PrimitiveType::I16,
1819 ty::IntTy::I32 => PrimitiveType::I32,
1820 ty::IntTy::I64 => PrimitiveType::I64,
1821 ty::IntTy::I128 => PrimitiveType::I128,
1826 impl From<ty::UintTy> for PrimitiveType {
1827 fn from(uint_ty: ty::UintTy) -> PrimitiveType {
1829 ty::UintTy::Usize => PrimitiveType::Usize,
1830 ty::UintTy::U8 => PrimitiveType::U8,
1831 ty::UintTy::U16 => PrimitiveType::U16,
1832 ty::UintTy::U32 => PrimitiveType::U32,
1833 ty::UintTy::U64 => PrimitiveType::U64,
1834 ty::UintTy::U128 => PrimitiveType::U128,
1839 impl From<ty::FloatTy> for PrimitiveType {
1840 fn from(float_ty: ty::FloatTy) -> PrimitiveType {
1842 ty::FloatTy::F32 => PrimitiveType::F32,
1843 ty::FloatTy::F64 => PrimitiveType::F64,
1848 impl From<hir::PrimTy> for PrimitiveType {
1849 fn from(prim_ty: hir::PrimTy) -> PrimitiveType {
1851 hir::PrimTy::Int(int_ty) => int_ty.into(),
1852 hir::PrimTy::Uint(uint_ty) => uint_ty.into(),
1853 hir::PrimTy::Float(float_ty) => float_ty.into(),
1854 hir::PrimTy::Str => PrimitiveType::Str,
1855 hir::PrimTy::Bool => PrimitiveType::Bool,
1856 hir::PrimTy::Char => PrimitiveType::Char,
1861 #[derive(Copy, Clone, Debug)]
1862 crate enum Visibility {
1865 /// Visibility inherited from parent.
1867 /// For example, this is the visibility of private items and of enum variants.
1869 /// `pub(crate)`, `pub(super)`, or `pub(in path::to::somewhere)`
1874 crate fn is_public(&self) -> bool {
1875 matches!(self, Visibility::Public)
1879 #[derive(Clone, Debug)]
1880 crate struct Struct {
1881 crate struct_type: CtorKind,
1882 crate generics: Generics,
1883 crate fields: Vec<Item>,
1884 crate fields_stripped: bool,
1887 #[derive(Clone, Debug)]
1888 crate struct Union {
1889 crate generics: Generics,
1890 crate fields: Vec<Item>,
1891 crate fields_stripped: bool,
1894 /// This is a more limited form of the standard Struct, different in that
1895 /// it lacks the things most items have (name, id, parameterization). Found
1896 /// only as a variant in an enum.
1897 #[derive(Clone, Debug)]
1898 crate struct VariantStruct {
1899 crate struct_type: CtorKind,
1900 crate fields: Vec<Item>,
1901 crate fields_stripped: bool,
1904 #[derive(Clone, Debug)]
1906 crate variants: IndexVec<VariantIdx, Item>,
1907 crate generics: Generics,
1908 crate variants_stripped: bool,
1911 #[derive(Clone, Debug)]
1912 crate enum Variant {
1915 Struct(VariantStruct),
1918 /// Small wrapper around [`rustc_span::Span`] that adds helper methods
1919 /// and enforces calling [`rustc_span::Span::source_callsite()`].
1920 #[derive(Copy, Clone, Debug)]
1921 crate struct Span(rustc_span::Span);
1924 /// Wraps a [`rustc_span::Span`]. In case this span is the result of a macro expansion, the
1925 /// span will be updated to point to the macro invocation instead of the macro definition.
1927 /// (See rust-lang/rust#39726)
1928 crate fn new(sp: rustc_span::Span) -> Self {
1929 Self(sp.source_callsite())
1932 crate fn inner(&self) -> rustc_span::Span {
1936 crate fn dummy() -> Self {
1937 Self(rustc_span::DUMMY_SP)
1940 crate fn is_dummy(&self) -> bool {
1944 crate fn filename(&self, sess: &Session) -> FileName {
1945 sess.source_map().span_to_filename(self.0)
1948 crate fn lo(&self, sess: &Session) -> Loc {
1949 sess.source_map().lookup_char_pos(self.0.lo())
1952 crate fn hi(&self, sess: &Session) -> Loc {
1953 sess.source_map().lookup_char_pos(self.0.hi())
1956 crate fn cnum(&self, sess: &Session) -> CrateNum {
1957 // FIXME: is there a time when the lo and hi crate would be different?
1958 self.lo(sess).file.cnum
1962 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
1965 crate segments: Vec<PathSegment>,
1969 crate fn def_id(&self) -> DefId {
1973 crate fn last(&self) -> Symbol {
1974 self.segments.last().expect("segments were empty").name
1977 crate fn whole_name(&self) -> String {
1980 .map(|s| if s.name == kw::PathRoot { String::new() } else { s.name.to_string() })
1981 .intersperse("::".into())
1985 /// Checks if this is a `T::Name` path for an associated type.
1986 crate fn is_assoc_ty(&self) -> bool {
1988 Res::SelfTy(..) if self.segments.len() != 1 => true,
1989 Res::Def(DefKind::TyParam, _) if self.segments.len() != 1 => true,
1990 Res::Def(DefKind::AssocTy, _) => true,
1995 crate fn generics(&self) -> Option<Vec<&Type>> {
1996 self.segments.last().and_then(|seg| {
1997 if let GenericArgs::AngleBracketed { ref args, .. } = seg.args {
2000 .filter_map(|arg| match arg {
2001 GenericArg::Type(ty) => Some(ty),
2012 crate fn bindings(&self) -> Option<&[TypeBinding]> {
2013 self.segments.last().and_then(|seg| {
2014 if let GenericArgs::AngleBracketed { ref bindings, .. } = seg.args {
2023 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
2024 crate enum GenericArg {
2027 Const(Box<Constant>),
2031 // `GenericArg` can occur many times in a single `Path`, so make sure it
2032 // doesn't increase in size unexpectedly.
2033 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
2034 rustc_data_structures::static_assert_size!(GenericArg, 80);
2036 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
2037 crate enum GenericArgs {
2038 AngleBracketed { args: Vec<GenericArg>, bindings: ThinVec<TypeBinding> },
2039 Parenthesized { inputs: Vec<Type>, output: Option<Box<Type>> },
2042 // `GenericArgs` is in every `PathSegment`, so its size can significantly
2043 // affect rustdoc's memory usage.
2044 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
2045 rustc_data_structures::static_assert_size!(GenericArgs, 40);
2047 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
2048 crate struct PathSegment {
2050 crate args: GenericArgs,
2053 // `PathSegment` usually occurs multiple times in every `Path`, so its size can
2054 // significantly affect rustdoc's memory usage.
2055 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
2056 rustc_data_structures::static_assert_size!(PathSegment, 48);
2058 #[derive(Clone, Debug)]
2059 crate struct Typedef {
2061 crate generics: Generics,
2062 /// `type_` can come from either the HIR or from metadata. If it comes from HIR, it may be a type
2063 /// alias instead of the final type. This will always have the final type, regardless of whether
2064 /// `type_` came from HIR or from metadata.
2066 /// If `item_type.is_none()`, `type_` is guarenteed to come from metadata (and therefore hold the
2068 crate item_type: Option<Type>,
2071 #[derive(Clone, Debug)]
2072 crate struct OpaqueTy {
2073 crate bounds: Vec<GenericBound>,
2074 crate generics: Generics,
2077 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
2078 crate struct BareFunctionDecl {
2079 crate unsafety: hir::Unsafety,
2080 crate generic_params: Vec<GenericParamDef>,
2085 #[derive(Clone, Debug)]
2086 crate struct Static {
2088 crate mutability: Mutability,
2089 crate expr: Option<BodyId>,
2092 #[derive(Clone, PartialEq, Eq, Hash, Debug)]
2093 crate struct Constant {
2095 crate kind: ConstantKind,
2098 #[derive(Clone, PartialEq, Eq, Hash, Debug)]
2105 crate fn ty(&self) -> Option<&Type> {
2106 if let Term::Type(ty) = self { Some(ty) } else { None }
2110 impl From<Type> for Term {
2111 fn from(ty: Type) -> Self {
2116 #[derive(Clone, PartialEq, Eq, Hash, Debug)]
2117 crate enum ConstantKind {
2118 /// This is the wrapper around `ty::Const` for a non-local constant. Because it doesn't have a
2119 /// `BodyId`, we need to handle it on its own.
2121 /// Note that `ty::Const` includes generic parameters, and may not always be uniquely identified
2122 /// by a DefId. So this field must be different from `Extern`.
2123 TyConst { expr: String },
2124 /// A constant (expression) that's not an item or associated item. These are usually found
2125 /// nested inside types (e.g., array lengths) or expressions (e.g., repeat counts), and also
2126 /// used to define explicit discriminant values for enum variants.
2127 Anonymous { body: BodyId },
2128 /// A constant from a different crate.
2129 Extern { def_id: DefId },
2130 /// `const FOO: u32 = ...;`
2131 Local { def_id: DefId, body: BodyId },
2135 crate fn expr(&self, tcx: TyCtxt<'_>) -> String {
2139 crate fn value(&self, tcx: TyCtxt<'_>) -> Option<String> {
2140 self.kind.value(tcx)
2143 crate fn is_literal(&self, tcx: TyCtxt<'_>) -> bool {
2144 self.kind.is_literal(tcx)
2149 crate fn expr(&self, tcx: TyCtxt<'_>) -> String {
2151 ConstantKind::TyConst { ref expr } => expr.clone(),
2152 ConstantKind::Extern { def_id } => print_inlined_const(tcx, def_id),
2153 ConstantKind::Local { body, .. } | ConstantKind::Anonymous { body } => {
2154 print_const_expr(tcx, body)
2159 crate fn value(&self, tcx: TyCtxt<'_>) -> Option<String> {
2161 ConstantKind::TyConst { .. } | ConstantKind::Anonymous { .. } => None,
2162 ConstantKind::Extern { def_id } | ConstantKind::Local { def_id, .. } => {
2163 print_evaluated_const(tcx, def_id)
2168 crate fn is_literal(&self, tcx: TyCtxt<'_>) -> bool {
2170 ConstantKind::TyConst { .. } => false,
2171 ConstantKind::Extern { def_id } => def_id.as_local().map_or(false, |def_id| {
2172 is_literal_expr(tcx, tcx.hir().local_def_id_to_hir_id(def_id))
2174 ConstantKind::Local { body, .. } | ConstantKind::Anonymous { body } => {
2175 is_literal_expr(tcx, body.hir_id)
2181 #[derive(Clone, Debug)]
2183 crate unsafety: hir::Unsafety,
2184 crate generics: Generics,
2185 crate trait_: Option<Path>,
2187 crate items: Vec<Item>,
2188 crate polarity: ty::ImplPolarity,
2189 crate kind: ImplKind,
2193 crate fn provided_trait_methods(&self, tcx: TyCtxt<'_>) -> FxHashSet<Symbol> {
2196 .map(|t| t.def_id())
2197 .map(|did| tcx.provided_trait_methods(did).map(|meth| meth.name).collect())
2198 .unwrap_or_default()
2202 #[derive(Clone, Debug)]
2203 crate enum ImplKind {
2210 crate fn is_auto(&self) -> bool {
2211 matches!(self, ImplKind::Auto)
2214 crate fn is_blanket(&self) -> bool {
2215 matches!(self, ImplKind::Blanket(_))
2218 crate fn as_blanket_ty(&self) -> Option<&Type> {
2220 ImplKind::Blanket(ty) => Some(ty),
2226 #[derive(Clone, Debug)]
2227 crate struct Import {
2228 crate kind: ImportKind,
2229 crate source: ImportSource,
2230 crate should_be_displayed: bool,
2234 crate fn new_simple(name: Symbol, source: ImportSource, should_be_displayed: bool) -> Self {
2235 Self { kind: ImportKind::Simple(name), source, should_be_displayed }
2238 crate fn new_glob(source: ImportSource, should_be_displayed: bool) -> Self {
2239 Self { kind: ImportKind::Glob, source, should_be_displayed }
2243 #[derive(Clone, Debug)]
2244 crate enum ImportKind {
2245 // use source as str;
2251 #[derive(Clone, Debug)]
2252 crate struct ImportSource {
2254 crate did: Option<DefId>,
2257 #[derive(Clone, Debug)]
2258 crate struct Macro {
2259 crate source: String,
2262 #[derive(Clone, Debug)]
2263 crate struct ProcMacro {
2264 crate kind: MacroKind,
2265 crate helpers: Vec<Symbol>,
2268 /// An type binding on an associated type (e.g., `A = Bar` in `Foo<A = Bar>` or
2269 /// `A: Send + Sync` in `Foo<A: Send + Sync>`).
2270 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
2271 crate struct TypeBinding {
2273 crate kind: TypeBindingKind,
2276 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
2277 crate enum TypeBindingKind {
2278 Equality { term: Term },
2279 Constraint { bounds: Vec<GenericBound> },
2283 crate fn term(&self) -> &Term {
2285 TypeBindingKind::Equality { ref term } => term,
2286 _ => panic!("expected equality type binding for parenthesized generic args"),
2291 /// The type, lifetime, or constant that a private type alias's parameter should be
2292 /// replaced with when expanding a use of that type alias.
2297 /// type PrivAlias<T> = Vec<T>;
2299 /// pub fn public_fn() -> PrivAlias<i32> { vec![] }
2302 /// `public_fn`'s docs will show it as returning `Vec<i32>`, since `PrivAlias` is private.
2303 /// [`SubstParam`] is used to record that `T` should be mapped to `i32`.
2304 crate enum SubstParam {
2311 crate fn as_ty(&self) -> Option<&Type> {
2312 if let Self::Type(ty) = self { Some(ty) } else { None }
2315 crate fn as_lt(&self) -> Option<&Lifetime> {
2316 if let Self::Lifetime(lt) = self { Some(lt) } else { None }