1 use std::cell::RefCell;
2 use std::default::Default;
3 use std::hash::{Hash, Hasher};
4 use std::iter::FromIterator;
5 use std::lazy::SyncOnceCell as OnceCell;
6 use std::path::PathBuf;
7 use std::rc::Rc;
8 use std::sync::Arc;
9 use std::{slice, vec};
10
11 use arrayvec::ArrayVec;
12
13 use rustc_ast::attr;
14 use rustc_ast::util::comments::beautify_doc_string;
15 use rustc_ast::{self as ast, AttrStyle};
16 use rustc_attr::{ConstStability, Deprecation, Stability, StabilityLevel};
17 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
18 use rustc_data_structures::thin_vec::ThinVec;
19 use rustc_hir as hir;
20 use rustc_hir::def::{CtorKind, DefKind, Res};
21 use rustc_hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE};
22 use rustc_hir::lang_items::LangItem;
23 use rustc_hir::{BodyId, Mutability};
24 use rustc_index::vec::IndexVec;
25 use rustc_middle::ty::{self, TyCtxt};
26 use rustc_session::Session;
27 use rustc_span::hygiene::MacroKind;
28 use rustc_span::source_map::DUMMY_SP;
29 use rustc_span::symbol::{kw, sym, Ident, Symbol, SymbolStr};
30 use rustc_span::{self, FileName, Loc};
31 use rustc_target::abi::VariantIdx;
32 use rustc_target::spec::abi::Abi;
33
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::clean::Clean;
39 use crate::core::DocContext;
40 use crate::formats::cache::Cache;
41 use crate::formats::item_type::ItemType;
42 use crate::html::render::cache::ExternalLocation;
43 use crate::html::render::Context;
44
45 crate use self::FnRetTy::*;
46 crate use self::ItemKind::*;
47 crate use self::SelfTy::*;
48 crate use self::Type::{
49 Array, BareFunction, BorrowedRef, DynTrait, Generic, ImplTrait, Infer, Primitive, QPath,
50 RawPointer, Slice, Tuple,
51 };
52 crate use self::Visibility::{Inherited, Public};
53
54 crate type ItemIdSet = FxHashSet<ItemId>;
55
56 #[derive(Debug, Clone, PartialEq, Eq, Hash, Copy)]
57 crate enum ItemId {
58 /// A "normal" item that uses a [`DefId`] for identification.
59 DefId(DefId),
60 /// Identifier that is used for auto traits.
61 Auto { trait_: DefId, for_: DefId },
62 /// Identifier that is used for blanket implementations.
63 Blanket { impl_id: DefId, for_: DefId },
64 /// Identifier for primitive types.
65 Primitive(PrimitiveType, CrateNum),
66 }
67
68 impl ItemId {
69 #[inline]
is_local(self) -> bool70 crate fn is_local(self) -> bool {
71 match self {
72 ItemId::Auto { for_: id, .. }
73 | ItemId::Blanket { for_: id, .. }
74 | ItemId::DefId(id) => id.is_local(),
75 ItemId::Primitive(_, krate) => krate == LOCAL_CRATE,
76 }
77 }
78
79 #[inline]
80 #[track_caller]
expect_def_id(self) -> DefId81 crate fn expect_def_id(self) -> DefId {
82 self.as_def_id()
83 .unwrap_or_else(|| panic!("ItemId::expect_def_id: `{:?}` isn't a DefId", self))
84 }
85
86 #[inline]
as_def_id(self) -> Option<DefId>87 crate fn as_def_id(self) -> Option<DefId> {
88 match self {
89 ItemId::DefId(id) => Some(id),
90 _ => None,
91 }
92 }
93
94 #[inline]
krate(self) -> CrateNum95 crate fn krate(self) -> CrateNum {
96 match self {
97 ItemId::Auto { for_: id, .. }
98 | ItemId::Blanket { for_: id, .. }
99 | ItemId::DefId(id) => id.krate,
100 ItemId::Primitive(_, krate) => krate,
101 }
102 }
103
104 #[inline]
index(self) -> Option<DefIndex>105 crate fn index(self) -> Option<DefIndex> {
106 match self {
107 ItemId::DefId(id) => Some(id.index),
108 _ => None,
109 }
110 }
111 }
112
113 impl From<DefId> for ItemId {
from(id: DefId) -> Self114 fn from(id: DefId) -> Self {
115 Self::DefId(id)
116 }
117 }
118
119 /// The crate currently being documented.
120 #[derive(Clone, Debug)]
121 crate struct Crate {
122 crate module: Item,
123 crate primitives: ThinVec<(DefId, PrimitiveType)>,
124 /// Only here so that they can be filtered through the rustdoc passes.
125 crate external_traits: Rc<RefCell<FxHashMap<DefId, TraitWithExtraInfo>>>,
126 crate collapsed: bool,
127 }
128
129 // `Crate` is frequently moved by-value. Make sure it doesn't unintentionally get bigger.
130 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
131 rustc_data_structures::static_assert_size!(Crate, 80);
132
133 impl Crate {
name(&self, tcx: TyCtxt<'_>) -> Symbol134 crate fn name(&self, tcx: TyCtxt<'_>) -> Symbol {
135 ExternalCrate::LOCAL.name(tcx)
136 }
137
src(&self, tcx: TyCtxt<'_>) -> FileName138 crate fn src(&self, tcx: TyCtxt<'_>) -> FileName {
139 ExternalCrate::LOCAL.src(tcx)
140 }
141 }
142
143 /// This struct is used to wrap additional information added by rustdoc on a `trait` item.
144 #[derive(Clone, Debug)]
145 crate struct TraitWithExtraInfo {
146 crate trait_: Trait,
147 crate is_notable: bool,
148 }
149
150 #[derive(Copy, Clone, Debug)]
151 crate struct ExternalCrate {
152 crate crate_num: CrateNum,
153 }
154
155 impl ExternalCrate {
156 const LOCAL: Self = Self { crate_num: LOCAL_CRATE };
157
158 #[inline]
def_id(&self) -> DefId159 crate fn def_id(&self) -> DefId {
160 DefId { krate: self.crate_num, index: CRATE_DEF_INDEX }
161 }
162
src(&self, tcx: TyCtxt<'_>) -> FileName163 crate fn src(&self, tcx: TyCtxt<'_>) -> FileName {
164 let krate_span = tcx.def_span(self.def_id());
165 tcx.sess.source_map().span_to_filename(krate_span)
166 }
167
name(&self, tcx: TyCtxt<'_>) -> Symbol168 crate fn name(&self, tcx: TyCtxt<'_>) -> Symbol {
169 tcx.crate_name(self.crate_num)
170 }
171
src_root(&self, tcx: TyCtxt<'_>) -> PathBuf172 crate fn src_root(&self, tcx: TyCtxt<'_>) -> PathBuf {
173 match self.src(tcx) {
174 FileName::Real(ref p) => match p.local_path_if_available().parent() {
175 Some(p) => p.to_path_buf(),
176 None => PathBuf::new(),
177 },
178 _ => PathBuf::new(),
179 }
180 }
181
182 /// Attempts to find where an external crate is located, given that we're
183 /// rendering in to the specified source destination.
location( &self, extern_url: Option<&str>, extern_url_takes_precedence: bool, dst: &std::path::Path, tcx: TyCtxt<'_>, ) -> ExternalLocation184 crate fn location(
185 &self,
186 extern_url: Option<&str>,
187 extern_url_takes_precedence: bool,
188 dst: &std::path::Path,
189 tcx: TyCtxt<'_>,
190 ) -> ExternalLocation {
191 use ExternalLocation::*;
192
193 fn to_remote(url: impl ToString) -> ExternalLocation {
194 let mut url = url.to_string();
195 if !url.ends_with('/') {
196 url.push('/');
197 }
198 Remote(url)
199 }
200
201 // See if there's documentation generated into the local directory
202 // WARNING: since rustdoc creates these directories as it generates documentation, this check is only accurate before rendering starts.
203 // Make sure to call `location()` by that time.
204 let local_location = dst.join(&*self.name(tcx).as_str());
205 if local_location.is_dir() {
206 return Local;
207 }
208
209 if extern_url_takes_precedence {
210 if let Some(url) = extern_url {
211 return to_remote(url);
212 }
213 }
214
215 // Failing that, see if there's an attribute specifying where to find this
216 // external crate
217 let did = DefId { krate: self.crate_num, index: CRATE_DEF_INDEX };
218 tcx.get_attrs(did)
219 .lists(sym::doc)
220 .filter(|a| a.has_name(sym::html_root_url))
221 .filter_map(|a| a.value_str())
222 .map(to_remote)
223 .next()
224 .or_else(|| extern_url.map(to_remote)) // NOTE: only matters if `extern_url_takes_precedence` is false
225 .unwrap_or(Unknown) // Well, at least we tried.
226 }
227
keywords(&self, tcx: TyCtxt<'_>) -> ThinVec<(DefId, Symbol)>228 crate fn keywords(&self, tcx: TyCtxt<'_>) -> ThinVec<(DefId, Symbol)> {
229 let root = self.def_id();
230
231 let as_keyword = |res: Res<!>| {
232 if let Res::Def(DefKind::Mod, def_id) = res {
233 let attrs = tcx.get_attrs(def_id);
234 let mut keyword = None;
235 for attr in attrs.lists(sym::doc) {
236 if attr.has_name(sym::keyword) {
237 if let Some(v) = attr.value_str() {
238 keyword = Some(v);
239 break;
240 }
241 }
242 }
243 return keyword.map(|p| (def_id, p));
244 }
245 None
246 };
247 if root.is_local() {
248 tcx.hir()
249 .root_module()
250 .item_ids
251 .iter()
252 .filter_map(|&id| {
253 let item = tcx.hir().item(id);
254 match item.kind {
255 hir::ItemKind::Mod(_) => {
256 as_keyword(Res::Def(DefKind::Mod, id.def_id.to_def_id()))
257 }
258 hir::ItemKind::Use(path, hir::UseKind::Single)
259 if tcx.visibility(id.def_id).is_public() =>
260 {
261 as_keyword(path.res.expect_non_local())
262 .map(|(_, prim)| (id.def_id.to_def_id(), prim))
263 }
264 _ => None,
265 }
266 })
267 .collect()
268 } else {
269 tcx.item_children(root).iter().map(|item| item.res).filter_map(as_keyword).collect()
270 }
271 }
272
primitives(&self, tcx: TyCtxt<'_>) -> ThinVec<(DefId, PrimitiveType)>273 crate fn primitives(&self, tcx: TyCtxt<'_>) -> ThinVec<(DefId, PrimitiveType)> {
274 let root = self.def_id();
275
276 // Collect all inner modules which are tagged as implementations of
277 // primitives.
278 //
279 // Note that this loop only searches the top-level items of the crate,
280 // and this is intentional. If we were to search the entire crate for an
281 // item tagged with `#[doc(primitive)]` then we would also have to
282 // search the entirety of external modules for items tagged
283 // `#[doc(primitive)]`, which is a pretty inefficient process (decoding
284 // all that metadata unconditionally).
285 //
286 // In order to keep the metadata load under control, the
287 // `#[doc(primitive)]` feature is explicitly designed to only allow the
288 // primitive tags to show up as the top level items in a crate.
289 //
290 // Also note that this does not attempt to deal with modules tagged
291 // duplicately for the same primitive. This is handled later on when
292 // rendering by delegating everything to a hash map.
293 let as_primitive = |res: Res<!>| {
294 if let Res::Def(DefKind::Mod, def_id) = res {
295 let attrs = tcx.get_attrs(def_id);
296 let mut prim = None;
297 for attr in attrs.lists(sym::doc) {
298 if let Some(v) = attr.value_str() {
299 if attr.has_name(sym::primitive) {
300 prim = PrimitiveType::from_symbol(v);
301 if prim.is_some() {
302 break;
303 }
304 // FIXME: should warn on unknown primitives?
305 }
306 }
307 }
308 return prim.map(|p| (def_id, p));
309 }
310 None
311 };
312
313 if root.is_local() {
314 tcx.hir()
315 .root_module()
316 .item_ids
317 .iter()
318 .filter_map(|&id| {
319 let item = tcx.hir().item(id);
320 match item.kind {
321 hir::ItemKind::Mod(_) => {
322 as_primitive(Res::Def(DefKind::Mod, id.def_id.to_def_id()))
323 }
324 hir::ItemKind::Use(path, hir::UseKind::Single)
325 if tcx.visibility(id.def_id).is_public() =>
326 {
327 as_primitive(path.res.expect_non_local()).map(|(_, prim)| {
328 // Pretend the primitive is local.
329 (id.def_id.to_def_id(), prim)
330 })
331 }
332 _ => None,
333 }
334 })
335 .collect()
336 } else {
337 tcx.item_children(root).iter().map(|item| item.res).filter_map(as_primitive).collect()
338 }
339 }
340 }
341
342 /// Anything with a source location and set of attributes and, optionally, a
343 /// name. That is, anything that can be documented. This doesn't correspond
344 /// directly to the AST's concept of an item; it's a strict superset.
345 #[derive(Clone, Debug)]
346 crate struct Item {
347 /// The name of this item.
348 /// Optional because not every item has a name, e.g. impls.
349 crate name: Option<Symbol>,
350 crate attrs: Box<Attributes>,
351 crate visibility: Visibility,
352 /// Information about this item that is specific to what kind of item it is.
353 /// E.g., struct vs enum vs function.
354 crate kind: Box<ItemKind>,
355 crate def_id: ItemId,
356
357 crate cfg: Option<Arc<Cfg>>,
358 }
359
360 // `Item` is used a lot. Make sure it doesn't unintentionally get bigger.
361 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
362 rustc_data_structures::static_assert_size!(Item, 56);
363
rustc_span(def_id: DefId, tcx: TyCtxt<'_>) -> Span364 crate fn rustc_span(def_id: DefId, tcx: TyCtxt<'_>) -> Span {
365 Span::new(def_id.as_local().map_or_else(
366 || tcx.def_span(def_id),
367 |local| {
368 let hir = tcx.hir();
369 hir.span_with_body(hir.local_def_id_to_hir_id(local))
370 },
371 ))
372 }
373
374 impl Item {
stability<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Option<&'tcx Stability>375 crate fn stability<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Option<&'tcx Stability> {
376 self.def_id.as_def_id().and_then(|did| tcx.lookup_stability(did))
377 }
378
const_stability<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Option<&'tcx ConstStability>379 crate fn const_stability<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Option<&'tcx ConstStability> {
380 self.def_id.as_def_id().and_then(|did| tcx.lookup_const_stability(did))
381 }
382
deprecation(&self, tcx: TyCtxt<'_>) -> Option<Deprecation>383 crate fn deprecation(&self, tcx: TyCtxt<'_>) -> Option<Deprecation> {
384 self.def_id.as_def_id().and_then(|did| tcx.lookup_deprecation(did))
385 }
386
inner_docs(&self, tcx: TyCtxt<'_>) -> bool387 crate fn inner_docs(&self, tcx: TyCtxt<'_>) -> bool {
388 self.def_id.as_def_id().map(|did| tcx.get_attrs(did).inner_docs()).unwrap_or(false)
389 }
390
span(&self, tcx: TyCtxt<'_>) -> Span391 crate fn span(&self, tcx: TyCtxt<'_>) -> Span {
392 let kind = match &*self.kind {
393 ItemKind::StrippedItem(k) => k,
394 _ => &*self.kind,
395 };
396 match kind {
397 ItemKind::ModuleItem(Module { span, .. }) => *span,
398 ItemKind::ImplItem(Impl { kind: ImplKind::Auto, .. }) => Span::dummy(),
399 ItemKind::ImplItem(Impl { kind: ImplKind::Blanket(_), .. }) => {
400 if let ItemId::Blanket { impl_id, .. } = self.def_id {
401 rustc_span(impl_id, tcx)
402 } else {
403 panic!("blanket impl item has non-blanket ID")
404 }
405 }
406 _ => {
407 self.def_id.as_def_id().map(|did| rustc_span(did, tcx)).unwrap_or_else(Span::dummy)
408 }
409 }
410 }
411
attr_span(&self, tcx: TyCtxt<'_>) -> rustc_span::Span412 crate fn attr_span(&self, tcx: TyCtxt<'_>) -> rustc_span::Span {
413 crate::passes::span_of_attrs(&self.attrs).unwrap_or_else(|| self.span(tcx).inner())
414 }
415
416 /// Finds the `doc` attribute as a NameValue and returns the corresponding
417 /// value found.
doc_value(&self) -> Option<String>418 crate fn doc_value(&self) -> Option<String> {
419 self.attrs.doc_value()
420 }
421
422 /// Convenience wrapper around [`Self::from_def_id_and_parts`] which converts
423 /// `hir_id` to a [`DefId`]
from_hir_id_and_parts( hir_id: hir::HirId, name: Option<Symbol>, kind: ItemKind, cx: &mut DocContext<'_>, ) -> Item424 pub fn from_hir_id_and_parts(
425 hir_id: hir::HirId,
426 name: Option<Symbol>,
427 kind: ItemKind,
428 cx: &mut DocContext<'_>,
429 ) -> Item {
430 Item::from_def_id_and_parts(cx.tcx.hir().local_def_id(hir_id).to_def_id(), name, kind, cx)
431 }
432
from_def_id_and_parts( def_id: DefId, name: Option<Symbol>, kind: ItemKind, cx: &mut DocContext<'_>, ) -> Item433 pub fn from_def_id_and_parts(
434 def_id: DefId,
435 name: Option<Symbol>,
436 kind: ItemKind,
437 cx: &mut DocContext<'_>,
438 ) -> Item {
439 let ast_attrs = cx.tcx.get_attrs(def_id);
440
441 Self::from_def_id_and_attrs_and_parts(
442 def_id,
443 name,
444 kind,
445 box ast_attrs.clean(cx),
446 cx,
447 ast_attrs.cfg(cx.tcx, &cx.cache.hidden_cfg),
448 )
449 }
450
from_def_id_and_attrs_and_parts( def_id: DefId, name: Option<Symbol>, kind: ItemKind, attrs: Box<Attributes>, cx: &mut DocContext<'_>, cfg: Option<Arc<Cfg>>, ) -> Item451 pub fn from_def_id_and_attrs_and_parts(
452 def_id: DefId,
453 name: Option<Symbol>,
454 kind: ItemKind,
455 attrs: Box<Attributes>,
456 cx: &mut DocContext<'_>,
457 cfg: Option<Arc<Cfg>>,
458 ) -> Item {
459 trace!("name={:?}, def_id={:?}", name, def_id);
460
461 Item {
462 def_id: def_id.into(),
463 kind: box kind,
464 name,
465 attrs,
466 visibility: cx.tcx.visibility(def_id).clean(cx),
467 cfg,
468 }
469 }
470
471 /// Finds all `doc` attributes as NameValues and returns their corresponding values, joined
472 /// with newlines.
collapsed_doc_value(&self) -> Option<String>473 crate fn collapsed_doc_value(&self) -> Option<String> {
474 self.attrs.collapsed_doc_value()
475 }
476
links(&self, cx: &Context<'_>) -> Vec<RenderedLink>477 crate fn links(&self, cx: &Context<'_>) -> Vec<RenderedLink> {
478 use crate::html::format::href;
479
480 cx.cache()
481 .intra_doc_links
482 .get(&self.def_id)
483 .map_or(&[][..], |v| v.as_slice())
484 .iter()
485 .filter_map(|ItemLink { link: s, link_text, did, ref fragment }| {
486 debug!(?did);
487 if let Ok((mut href, ..)) = href(*did, cx) {
488 debug!(?href);
489 if let Some(ref fragment) = *fragment {
490 href.push('#');
491 href.push_str(fragment);
492 }
493 Some(RenderedLink {
494 original_text: s.clone(),
495 new_text: link_text.clone(),
496 href,
497 })
498 } else {
499 None
500 }
501 })
502 .collect()
503 }
504
505 /// Find a list of all link names, without finding their href.
506 ///
507 /// This is used for generating summary text, which does not include
508 /// the link text, but does need to know which `[]`-bracketed names
509 /// are actually links.
link_names(&self, cache: &Cache) -> Vec<RenderedLink>510 crate fn link_names(&self, cache: &Cache) -> Vec<RenderedLink> {
511 cache
512 .intra_doc_links
513 .get(&self.def_id)
514 .map_or(&[][..], |v| v.as_slice())
515 .iter()
516 .map(|ItemLink { link: s, link_text, .. }| RenderedLink {
517 original_text: s.clone(),
518 new_text: link_text.clone(),
519 href: String::new(),
520 })
521 .collect()
522 }
523
is_crate(&self) -> bool524 crate fn is_crate(&self) -> bool {
525 self.is_mod() && self.def_id.as_def_id().map_or(false, |did| did.index == CRATE_DEF_INDEX)
526 }
is_mod(&self) -> bool527 crate fn is_mod(&self) -> bool {
528 self.type_() == ItemType::Module
529 }
is_trait(&self) -> bool530 crate fn is_trait(&self) -> bool {
531 self.type_() == ItemType::Trait
532 }
is_struct(&self) -> bool533 crate fn is_struct(&self) -> bool {
534 self.type_() == ItemType::Struct
535 }
is_enum(&self) -> bool536 crate fn is_enum(&self) -> bool {
537 self.type_() == ItemType::Enum
538 }
is_variant(&self) -> bool539 crate fn is_variant(&self) -> bool {
540 self.type_() == ItemType::Variant
541 }
is_associated_type(&self) -> bool542 crate fn is_associated_type(&self) -> bool {
543 self.type_() == ItemType::AssocType
544 }
is_associated_const(&self) -> bool545 crate fn is_associated_const(&self) -> bool {
546 self.type_() == ItemType::AssocConst
547 }
is_method(&self) -> bool548 crate fn is_method(&self) -> bool {
549 self.type_() == ItemType::Method
550 }
is_ty_method(&self) -> bool551 crate fn is_ty_method(&self) -> bool {
552 self.type_() == ItemType::TyMethod
553 }
is_typedef(&self) -> bool554 crate fn is_typedef(&self) -> bool {
555 self.type_() == ItemType::Typedef
556 }
is_primitive(&self) -> bool557 crate fn is_primitive(&self) -> bool {
558 self.type_() == ItemType::Primitive
559 }
is_union(&self) -> bool560 crate fn is_union(&self) -> bool {
561 self.type_() == ItemType::Union
562 }
is_import(&self) -> bool563 crate fn is_import(&self) -> bool {
564 self.type_() == ItemType::Import
565 }
is_extern_crate(&self) -> bool566 crate fn is_extern_crate(&self) -> bool {
567 self.type_() == ItemType::ExternCrate
568 }
is_keyword(&self) -> bool569 crate fn is_keyword(&self) -> bool {
570 self.type_() == ItemType::Keyword
571 }
is_stripped(&self) -> bool572 crate fn is_stripped(&self) -> bool {
573 match *self.kind {
574 StrippedItem(..) => true,
575 ImportItem(ref i) => !i.should_be_displayed,
576 _ => false,
577 }
578 }
has_stripped_fields(&self) -> Option<bool>579 crate fn has_stripped_fields(&self) -> Option<bool> {
580 match *self.kind {
581 StructItem(ref _struct) => Some(_struct.fields_stripped),
582 UnionItem(ref union) => Some(union.fields_stripped),
583 VariantItem(Variant::Struct(ref vstruct)) => Some(vstruct.fields_stripped),
584 _ => None,
585 }
586 }
587
stability_class(&self, tcx: TyCtxt<'_>) -> Option<String>588 crate fn stability_class(&self, tcx: TyCtxt<'_>) -> Option<String> {
589 self.stability(tcx).as_ref().and_then(|s| {
590 let mut classes = Vec::with_capacity(2);
591
592 if s.level.is_unstable() {
593 classes.push("unstable");
594 }
595
596 // FIXME: what about non-staged API items that are deprecated?
597 if self.deprecation(tcx).is_some() {
598 classes.push("deprecated");
599 }
600
601 if !classes.is_empty() { Some(classes.join(" ")) } else { None }
602 })
603 }
604
stable_since(&self, tcx: TyCtxt<'_>) -> Option<SymbolStr>605 crate fn stable_since(&self, tcx: TyCtxt<'_>) -> Option<SymbolStr> {
606 match self.stability(tcx)?.level {
607 StabilityLevel::Stable { since, .. } => Some(since.as_str()),
608 StabilityLevel::Unstable { .. } => None,
609 }
610 }
611
const_stable_since(&self, tcx: TyCtxt<'_>) -> Option<SymbolStr>612 crate fn const_stable_since(&self, tcx: TyCtxt<'_>) -> Option<SymbolStr> {
613 match self.const_stability(tcx)?.level {
614 StabilityLevel::Stable { since, .. } => Some(since.as_str()),
615 StabilityLevel::Unstable { .. } => None,
616 }
617 }
618
is_non_exhaustive(&self) -> bool619 crate fn is_non_exhaustive(&self) -> bool {
620 self.attrs.other_attrs.iter().any(|a| a.has_name(sym::non_exhaustive))
621 }
622
623 /// Returns a documentation-level item type from the item.
type_(&self) -> ItemType624 crate fn type_(&self) -> ItemType {
625 ItemType::from(self)
626 }
627
is_default(&self) -> bool628 crate fn is_default(&self) -> bool {
629 match *self.kind {
630 ItemKind::MethodItem(_, Some(defaultness)) => {
631 defaultness.has_value() && !defaultness.is_final()
632 }
633 _ => false,
634 }
635 }
636 }
637
638 #[derive(Clone, Debug)]
639 crate enum ItemKind {
640 ExternCrateItem {
641 /// The crate's name, *not* the name it's imported as.
642 src: Option<Symbol>,
643 },
644 ImportItem(Import),
645 StructItem(Struct),
646 UnionItem(Union),
647 EnumItem(Enum),
648 FunctionItem(Function),
649 ModuleItem(Module),
650 TypedefItem(Typedef, bool /* is associated type */),
651 OpaqueTyItem(OpaqueTy),
652 StaticItem(Static),
653 ConstantItem(Constant),
654 TraitItem(Trait),
655 TraitAliasItem(TraitAlias),
656 ImplItem(Impl),
657 /// A method signature only. Used for required methods in traits (ie,
658 /// non-default-methods).
659 TyMethodItem(Function),
660 /// A method with a body.
661 MethodItem(Function, Option<hir::Defaultness>),
662 StructFieldItem(Type),
663 VariantItem(Variant),
664 /// `fn`s from an extern block
665 ForeignFunctionItem(Function),
666 /// `static`s from an extern block
667 ForeignStaticItem(Static),
668 /// `type`s from an extern block
669 ForeignTypeItem,
670 MacroItem(Macro),
671 ProcMacroItem(ProcMacro),
672 PrimitiveItem(PrimitiveType),
673 AssocConstItem(Type, Option<String>),
674 /// An associated item in a trait or trait impl.
675 ///
676 /// The bounds may be non-empty if there is a `where` clause.
677 /// The `Option<Type>` is the default concrete type (e.g. `trait Trait { type Target = usize; }`)
678 AssocTypeItem(Vec<GenericBound>, Option<Type>),
679 /// An item that has been stripped by a rustdoc pass
680 StrippedItem(Box<ItemKind>),
681 KeywordItem(Symbol),
682 }
683
684 impl ItemKind {
685 /// Some items contain others such as structs (for their fields) and Enums
686 /// (for their variants). This method returns those contained items.
inner_items(&self) -> impl Iterator<Item = &Item>687 crate fn inner_items(&self) -> impl Iterator<Item = &Item> {
688 match self {
689 StructItem(s) => s.fields.iter(),
690 UnionItem(u) => u.fields.iter(),
691 VariantItem(Variant::Struct(v)) => v.fields.iter(),
692 VariantItem(Variant::Tuple(v)) => v.iter(),
693 EnumItem(e) => e.variants.iter(),
694 TraitItem(t) => t.items.iter(),
695 ImplItem(i) => i.items.iter(),
696 ModuleItem(m) => m.items.iter(),
697 ExternCrateItem { .. }
698 | ImportItem(_)
699 | FunctionItem(_)
700 | TypedefItem(_, _)
701 | OpaqueTyItem(_)
702 | StaticItem(_)
703 | ConstantItem(_)
704 | TraitAliasItem(_)
705 | TyMethodItem(_)
706 | MethodItem(_, _)
707 | StructFieldItem(_)
708 | VariantItem(_)
709 | ForeignFunctionItem(_)
710 | ForeignStaticItem(_)
711 | ForeignTypeItem
712 | MacroItem(_)
713 | ProcMacroItem(_)
714 | PrimitiveItem(_)
715 | AssocConstItem(_, _)
716 | AssocTypeItem(_, _)
717 | StrippedItem(_)
718 | KeywordItem(_) => [].iter(),
719 }
720 }
721 }
722
723 #[derive(Clone, Debug)]
724 crate struct Module {
725 crate items: Vec<Item>,
726 crate span: Span,
727 }
728
729 crate struct ListAttributesIter<'a> {
730 attrs: slice::Iter<'a, ast::Attribute>,
731 current_list: vec::IntoIter<ast::NestedMetaItem>,
732 name: Symbol,
733 }
734
735 impl<'a> Iterator for ListAttributesIter<'a> {
736 type Item = ast::NestedMetaItem;
737
next(&mut self) -> Option<Self::Item>738 fn next(&mut self) -> Option<Self::Item> {
739 if let Some(nested) = self.current_list.next() {
740 return Some(nested);
741 }
742
743 for attr in &mut self.attrs {
744 if let Some(list) = attr.meta_item_list() {
745 if attr.has_name(self.name) {
746 self.current_list = list.into_iter();
747 if let Some(nested) = self.current_list.next() {
748 return Some(nested);
749 }
750 }
751 }
752 }
753
754 None
755 }
756
size_hint(&self) -> (usize, Option<usize>)757 fn size_hint(&self) -> (usize, Option<usize>) {
758 let lower = self.current_list.len();
759 (lower, None)
760 }
761 }
762
763 crate trait AttributesExt {
764 /// Finds an attribute as List and returns the list of attributes nested inside.
lists(&self, name: Symbol) -> ListAttributesIter<'_>765 fn lists(&self, name: Symbol) -> ListAttributesIter<'_>;
766
span(&self) -> Option<rustc_span::Span>767 fn span(&self) -> Option<rustc_span::Span>;
768
inner_docs(&self) -> bool769 fn inner_docs(&self) -> bool;
770
other_attrs(&self) -> Vec<ast::Attribute>771 fn other_attrs(&self) -> Vec<ast::Attribute>;
772
cfg(&self, tcx: TyCtxt<'_>, hidden_cfg: &FxHashSet<Cfg>) -> Option<Arc<Cfg>>773 fn cfg(&self, tcx: TyCtxt<'_>, hidden_cfg: &FxHashSet<Cfg>) -> Option<Arc<Cfg>>;
774 }
775
776 impl AttributesExt for [ast::Attribute] {
lists(&self, name: Symbol) -> ListAttributesIter<'_>777 fn lists(&self, name: Symbol) -> ListAttributesIter<'_> {
778 ListAttributesIter { attrs: self.iter(), current_list: Vec::new().into_iter(), name }
779 }
780
781 /// Return the span of the first doc-comment, if it exists.
span(&self) -> Option<rustc_span::Span>782 fn span(&self) -> Option<rustc_span::Span> {
783 self.iter().find(|attr| attr.doc_str().is_some()).map(|attr| attr.span)
784 }
785
786 /// Returns whether the first doc-comment is an inner attribute.
787 ///
788 //// If there are no doc-comments, return true.
789 /// FIXME(#78591): Support both inner and outer attributes on the same item.
inner_docs(&self) -> bool790 fn inner_docs(&self) -> bool {
791 self.iter().find(|a| a.doc_str().is_some()).map_or(true, |a| a.style == AttrStyle::Inner)
792 }
793
other_attrs(&self) -> Vec<ast::Attribute>794 fn other_attrs(&self) -> Vec<ast::Attribute> {
795 self.iter().filter(|attr| attr.doc_str().is_none()).cloned().collect()
796 }
797
cfg(&self, tcx: TyCtxt<'_>, hidden_cfg: &FxHashSet<Cfg>) -> Option<Arc<Cfg>>798 fn cfg(&self, tcx: TyCtxt<'_>, hidden_cfg: &FxHashSet<Cfg>) -> Option<Arc<Cfg>> {
799 let sess = tcx.sess;
800 let doc_cfg_active = tcx.features().doc_cfg;
801 let doc_auto_cfg_active = tcx.features().doc_auto_cfg;
802
803 fn single<T: IntoIterator>(it: T) -> Option<T::Item> {
804 let mut iter = it.into_iter();
805 let item = iter.next()?;
806 if iter.next().is_some() {
807 return None;
808 }
809 Some(item)
810 }
811
812 let mut cfg = if doc_cfg_active || doc_auto_cfg_active {
813 let mut doc_cfg = self
814 .iter()
815 .filter(|attr| attr.has_name(sym::doc))
816 .flat_map(|attr| attr.meta_item_list().unwrap_or_else(Vec::new))
817 .filter(|attr| attr.has_name(sym::cfg))
818 .peekable();
819 if doc_cfg.peek().is_some() && doc_cfg_active {
820 doc_cfg
821 .filter_map(|attr| Cfg::parse(attr.meta_item()?).ok())
822 .fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg)
823 } else if doc_auto_cfg_active {
824 self.iter()
825 .filter(|attr| attr.has_name(sym::cfg))
826 .filter_map(|attr| single(attr.meta_item_list()?))
827 .filter_map(|attr| Cfg::parse(attr.meta_item()?).ok())
828 .filter(|cfg| !hidden_cfg.contains(cfg))
829 .fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg)
830 } else {
831 Cfg::True
832 }
833 } else {
834 Cfg::True
835 };
836
837 for attr in self.iter() {
838 // #[doc]
839 if attr.doc_str().is_none() && attr.has_name(sym::doc) {
840 // #[doc(...)]
841 if let Some(list) = attr.meta().as_ref().and_then(|mi| mi.meta_item_list()) {
842 for item in list {
843 // #[doc(hidden)]
844 if !item.has_name(sym::cfg) {
845 continue;
846 }
847 // #[doc(cfg(...))]
848 if let Some(cfg_mi) = item
849 .meta_item()
850 .and_then(|item| rustc_expand::config::parse_cfg(item, sess))
851 {
852 match Cfg::parse(cfg_mi) {
853 Ok(new_cfg) => cfg &= new_cfg,
854 Err(e) => sess.span_err(e.span, e.msg),
855 }
856 }
857 }
858 }
859 }
860 }
861
862 // treat #[target_feature(enable = "feat")] attributes as if they were
863 // #[doc(cfg(target_feature = "feat"))] attributes as well
864 for attr in self.lists(sym::target_feature) {
865 if attr.has_name(sym::enable) {
866 if let Some(feat) = attr.value_str() {
867 let meta = attr::mk_name_value_item_str(
868 Ident::with_dummy_span(sym::target_feature),
869 feat,
870 DUMMY_SP,
871 );
872 if let Ok(feat_cfg) = Cfg::parse(&meta) {
873 cfg &= feat_cfg;
874 }
875 }
876 }
877 }
878
879 if cfg == Cfg::True { None } else { Some(Arc::new(cfg)) }
880 }
881 }
882
883 crate trait NestedAttributesExt {
884 /// Returns `true` if the attribute list contains a specific `Word`
has_word(self, word: Symbol) -> bool885 fn has_word(self, word: Symbol) -> bool;
get_word_attr(self, word: Symbol) -> Option<ast::NestedMetaItem>886 fn get_word_attr(self, word: Symbol) -> Option<ast::NestedMetaItem>;
887 }
888
889 impl<I: Iterator<Item = ast::NestedMetaItem> + IntoIterator<Item = ast::NestedMetaItem>>
890 NestedAttributesExt for I
891 {
has_word(self, word: Symbol) -> bool892 fn has_word(self, word: Symbol) -> bool {
893 self.into_iter().any(|attr| attr.is_word() && attr.has_name(word))
894 }
895
get_word_attr(mut self, word: Symbol) -> Option<ast::NestedMetaItem>896 fn get_word_attr(mut self, word: Symbol) -> Option<ast::NestedMetaItem> {
897 self.find(|attr| attr.is_word() && attr.has_name(word))
898 }
899 }
900
901 /// A portion of documentation, extracted from a `#[doc]` attribute.
902 ///
903 /// Each variant contains the line number within the complete doc-comment where the fragment
904 /// starts, as well as the Span where the corresponding doc comment or attribute is located.
905 ///
906 /// Included files are kept separate from inline doc comments so that proper line-number
907 /// information can be given when a doctest fails. Sugared doc comments and "raw" doc comments are
908 /// kept separate because of issue #42760.
909 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
910 crate struct DocFragment {
911 crate span: rustc_span::Span,
912 /// The module this doc-comment came from.
913 ///
914 /// This allows distinguishing between the original documentation and a pub re-export.
915 /// If it is `None`, the item was not re-exported.
916 crate parent_module: Option<DefId>,
917 crate doc: Symbol,
918 crate kind: DocFragmentKind,
919 crate need_backline: bool,
920 crate indent: usize,
921 }
922
923 // `DocFragment` is used a lot. Make sure it doesn't unintentionally get bigger.
924 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
925 rustc_data_structures::static_assert_size!(DocFragment, 32);
926
927 #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
928 crate enum DocFragmentKind {
929 /// A doc fragment created from a `///` or `//!` doc comment.
930 SugaredDoc,
931 /// A doc fragment created from a "raw" `#[doc=""]` attribute.
932 RawDoc,
933 }
934
935 // The goal of this function is to apply the `DocFragment` transformations that are required when
936 // transforming into the final markdown. So the transformations in here are:
937 //
938 // * Applying the computed indent to each lines in each doc fragment (a `DocFragment` can contain
939 // multiple lines in case of `#[doc = ""]`).
940 // * Adding backlines between `DocFragment`s and adding an extra one if required (stored in the
941 // `need_backline` field).
add_doc_fragment(out: &mut String, frag: &DocFragment)942 fn add_doc_fragment(out: &mut String, frag: &DocFragment) {
943 let s = frag.doc.as_str();
944 let mut iter = s.lines().peekable();
945 while let Some(line) = iter.next() {
946 if line.chars().any(|c| !c.is_whitespace()) {
947 assert!(line.len() >= frag.indent);
948 out.push_str(&line[frag.indent..]);
949 } else {
950 out.push_str(line);
951 }
952 if iter.peek().is_some() {
953 out.push('\n');
954 }
955 }
956 if frag.need_backline {
957 out.push('\n');
958 }
959 }
960
961 impl<'a> FromIterator<&'a DocFragment> for String {
from_iter<T>(iter: T) -> Self where T: IntoIterator<Item = &'a DocFragment>,962 fn from_iter<T>(iter: T) -> Self
963 where
964 T: IntoIterator<Item = &'a DocFragment>,
965 {
966 iter.into_iter().fold(String::new(), |mut acc, frag| {
967 add_doc_fragment(&mut acc, frag);
968 acc
969 })
970 }
971 }
972
973 /// A link that has not yet been rendered.
974 ///
975 /// This link will be turned into a rendered link by [`Item::links`].
976 #[derive(Clone, Debug, PartialEq, Eq, Hash)]
977 crate struct ItemLink {
978 /// The original link written in the markdown
979 pub(crate) link: String,
980 /// The link text displayed in the HTML.
981 ///
982 /// This may not be the same as `link` if there was a disambiguator
983 /// in an intra-doc link (e.g. \[`fn@f`\])
984 pub(crate) link_text: String,
985 pub(crate) did: DefId,
986 /// The url fragment to append to the link
987 pub(crate) fragment: Option<String>,
988 }
989
990 pub struct RenderedLink {
991 /// The text the link was original written as.
992 ///
993 /// This could potentially include disambiguators and backticks.
994 pub(crate) original_text: String,
995 /// The text to display in the HTML
996 pub(crate) new_text: String,
997 /// The URL to put in the `href`
998 pub(crate) href: String,
999 }
1000
1001 /// The attributes on an [`Item`], including attributes like `#[derive(...)]` and `#[inline]`,
1002 /// as well as doc comments.
1003 #[derive(Clone, Debug, Default)]
1004 crate struct Attributes {
1005 crate doc_strings: Vec<DocFragment>,
1006 crate other_attrs: Vec<ast::Attribute>,
1007 }
1008
1009 impl Attributes {
lists(&self, name: Symbol) -> ListAttributesIter<'_>1010 crate fn lists(&self, name: Symbol) -> ListAttributesIter<'_> {
1011 self.other_attrs.lists(name)
1012 }
1013
has_doc_flag(&self, flag: Symbol) -> bool1014 crate fn has_doc_flag(&self, flag: Symbol) -> bool {
1015 for attr in &self.other_attrs {
1016 if !attr.has_name(sym::doc) {
1017 continue;
1018 }
1019
1020 if let Some(items) = attr.meta_item_list() {
1021 if items.iter().filter_map(|i| i.meta_item()).any(|it| it.has_name(flag)) {
1022 return true;
1023 }
1024 }
1025 }
1026
1027 false
1028 }
1029
from_ast( attrs: &[ast::Attribute], additional_attrs: Option<(&[ast::Attribute], DefId)>, ) -> Attributes1030 crate fn from_ast(
1031 attrs: &[ast::Attribute],
1032 additional_attrs: Option<(&[ast::Attribute], DefId)>,
1033 ) -> Attributes {
1034 let mut doc_strings: Vec<DocFragment> = vec![];
1035
1036 fn update_need_backline(doc_strings: &mut Vec<DocFragment>) {
1037 if let Some(prev) = doc_strings.last_mut() {
1038 prev.need_backline = true;
1039 }
1040 }
1041
1042 let clean_attr = |(attr, parent_module): (&ast::Attribute, Option<DefId>)| {
1043 if let Some(value) = attr.doc_str() {
1044 trace!("got doc_str={:?}", value);
1045 let value = beautify_doc_string(value);
1046 let kind = if attr.is_doc_comment() {
1047 DocFragmentKind::SugaredDoc
1048 } else {
1049 DocFragmentKind::RawDoc
1050 };
1051
1052 let frag = DocFragment {
1053 span: attr.span,
1054 doc: value,
1055 kind,
1056 parent_module,
1057 need_backline: false,
1058 indent: 0,
1059 };
1060
1061 update_need_backline(&mut doc_strings);
1062
1063 doc_strings.push(frag);
1064
1065 None
1066 } else {
1067 Some(attr.clone())
1068 }
1069 };
1070
1071 // Additional documentation should be shown before the original documentation
1072 let other_attrs = additional_attrs
1073 .into_iter()
1074 .map(|(attrs, id)| attrs.iter().map(move |attr| (attr, Some(id))))
1075 .flatten()
1076 .chain(attrs.iter().map(|attr| (attr, None)))
1077 .filter_map(clean_attr)
1078 .collect();
1079
1080 Attributes { doc_strings, other_attrs }
1081 }
1082
1083 /// Finds the `doc` attribute as a NameValue and returns the corresponding
1084 /// value found.
doc_value(&self) -> Option<String>1085 crate fn doc_value(&self) -> Option<String> {
1086 let mut iter = self.doc_strings.iter();
1087
1088 let ori = iter.next()?;
1089 let mut out = String::new();
1090 add_doc_fragment(&mut out, ori);
1091 for new_frag in iter {
1092 if new_frag.kind != ori.kind || new_frag.parent_module != ori.parent_module {
1093 break;
1094 }
1095 add_doc_fragment(&mut out, new_frag);
1096 }
1097 if out.is_empty() { None } else { Some(out) }
1098 }
1099
1100 /// Return the doc-comments on this item, grouped by the module they came from.
1101 ///
1102 /// The module can be different if this is a re-export with added documentation.
collapsed_doc_value_by_module_level(&self) -> FxHashMap<Option<DefId>, String>1103 crate fn collapsed_doc_value_by_module_level(&self) -> FxHashMap<Option<DefId>, String> {
1104 let mut ret = FxHashMap::default();
1105
1106 for new_frag in self.doc_strings.iter() {
1107 let out = ret.entry(new_frag.parent_module).or_default();
1108 add_doc_fragment(out, new_frag);
1109 }
1110 ret
1111 }
1112
1113 /// Finds all `doc` attributes as NameValues and returns their corresponding values, joined
1114 /// with newlines.
collapsed_doc_value(&self) -> Option<String>1115 crate fn collapsed_doc_value(&self) -> Option<String> {
1116 if self.doc_strings.is_empty() { None } else { Some(self.doc_strings.iter().collect()) }
1117 }
1118
get_doc_aliases(&self) -> Box<[Symbol]>1119 crate fn get_doc_aliases(&self) -> Box<[Symbol]> {
1120 let mut aliases = FxHashSet::default();
1121
1122 for attr in self.other_attrs.lists(sym::doc).filter(|a| a.has_name(sym::alias)) {
1123 if let Some(values) = attr.meta_item_list() {
1124 for l in values {
1125 match l.literal().unwrap().kind {
1126 ast::LitKind::Str(s, _) => {
1127 aliases.insert(s);
1128 }
1129 _ => unreachable!(),
1130 }
1131 }
1132 } else {
1133 aliases.insert(attr.value_str().unwrap());
1134 }
1135 }
1136 aliases.into_iter().collect::<Vec<_>>().into()
1137 }
1138 }
1139
1140 impl PartialEq for Attributes {
eq(&self, rhs: &Self) -> bool1141 fn eq(&self, rhs: &Self) -> bool {
1142 self.doc_strings == rhs.doc_strings
1143 && self
1144 .other_attrs
1145 .iter()
1146 .map(|attr| attr.id)
1147 .eq(rhs.other_attrs.iter().map(|attr| attr.id))
1148 }
1149 }
1150
1151 impl Eq for Attributes {}
1152
1153 impl Hash for Attributes {
hash<H: Hasher>(&self, hasher: &mut H)1154 fn hash<H: Hasher>(&self, hasher: &mut H) {
1155 self.doc_strings.hash(hasher);
1156 for attr in &self.other_attrs {
1157 attr.id.hash(hasher);
1158 }
1159 }
1160 }
1161
1162 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
1163 crate enum GenericBound {
1164 TraitBound(PolyTrait, hir::TraitBoundModifier),
1165 Outlives(Lifetime),
1166 }
1167
1168 impl GenericBound {
maybe_sized(cx: &mut DocContext<'_>) -> GenericBound1169 crate fn maybe_sized(cx: &mut DocContext<'_>) -> GenericBound {
1170 let did = cx.tcx.require_lang_item(LangItem::Sized, None);
1171 let empty = cx.tcx.intern_substs(&[]);
1172 let path = external_path(cx, did, false, vec![], empty);
1173 inline::record_extern_fqn(cx, did, ItemType::Trait);
1174 GenericBound::TraitBound(
1175 PolyTrait { trait_: path, generic_params: Vec::new() },
1176 hir::TraitBoundModifier::Maybe,
1177 )
1178 }
1179
is_sized_bound(&self, cx: &DocContext<'_>) -> bool1180 crate fn is_sized_bound(&self, cx: &DocContext<'_>) -> bool {
1181 use rustc_hir::TraitBoundModifier as TBM;
1182 if let GenericBound::TraitBound(PolyTrait { ref trait_, .. }, TBM::None) = *self {
1183 if Some(trait_.def_id()) == cx.tcx.lang_items().sized_trait() {
1184 return true;
1185 }
1186 }
1187 false
1188 }
1189
get_poly_trait(&self) -> Option<PolyTrait>1190 crate fn get_poly_trait(&self) -> Option<PolyTrait> {
1191 if let GenericBound::TraitBound(ref p, _) = *self {
1192 return Some(p.clone());
1193 }
1194 None
1195 }
1196
get_trait_path(&self) -> Option<Path>1197 crate fn get_trait_path(&self) -> Option<Path> {
1198 if let GenericBound::TraitBound(PolyTrait { ref trait_, .. }, _) = *self {
1199 Some(trait_.clone())
1200 } else {
1201 None
1202 }
1203 }
1204 }
1205
1206 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
1207 crate struct Lifetime(pub Symbol);
1208
1209 impl Lifetime {
get_ref(&self) -> SymbolStr1210 crate fn get_ref(&self) -> SymbolStr {
1211 self.0.as_str()
1212 }
1213
statik() -> Lifetime1214 crate fn statik() -> Lifetime {
1215 Lifetime(kw::StaticLifetime)
1216 }
1217
elided() -> Lifetime1218 crate fn elided() -> Lifetime {
1219 Lifetime(kw::UnderscoreLifetime)
1220 }
1221 }
1222
1223 #[derive(Clone, Debug)]
1224 crate enum WherePredicate {
1225 BoundPredicate { ty: Type, bounds: Vec<GenericBound>, bound_params: Vec<Lifetime> },
1226 RegionPredicate { lifetime: Lifetime, bounds: Vec<GenericBound> },
1227 EqPredicate { lhs: Type, rhs: Type },
1228 }
1229
1230 impl WherePredicate {
get_bounds(&self) -> Option<&[GenericBound]>1231 crate fn get_bounds(&self) -> Option<&[GenericBound]> {
1232 match *self {
1233 WherePredicate::BoundPredicate { ref bounds, .. } => Some(bounds),
1234 WherePredicate::RegionPredicate { ref bounds, .. } => Some(bounds),
1235 _ => None,
1236 }
1237 }
1238 }
1239
1240 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
1241 crate enum GenericParamDefKind {
1242 Lifetime { outlives: Vec<Lifetime> },
1243 Type { did: DefId, bounds: Vec<GenericBound>, default: Option<Box<Type>>, synthetic: bool },
1244 Const { did: DefId, ty: Box<Type>, default: Option<Box<String>> },
1245 }
1246
1247 impl GenericParamDefKind {
is_type(&self) -> bool1248 crate fn is_type(&self) -> bool {
1249 matches!(self, GenericParamDefKind::Type { .. })
1250 }
1251
1252 // FIXME(eddyb) this either returns the default of a type parameter, or the
1253 // type of a `const` parameter. It seems that the intention is to *visit*
1254 // any embedded types, but `get_type` seems to be the wrong name for that.
get_type(&self) -> Option<Type>1255 crate fn get_type(&self) -> Option<Type> {
1256 match self {
1257 GenericParamDefKind::Type { default, .. } => default.as_deref().cloned(),
1258 GenericParamDefKind::Const { ty, .. } => Some((&**ty).clone()),
1259 GenericParamDefKind::Lifetime { .. } => None,
1260 }
1261 }
1262 }
1263
1264 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
1265 crate struct GenericParamDef {
1266 crate name: Symbol,
1267 crate kind: GenericParamDefKind,
1268 }
1269
1270 // `GenericParamDef` is used in many places. Make sure it doesn't unintentionally get bigger.
1271 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
1272 rustc_data_structures::static_assert_size!(GenericParamDef, 56);
1273
1274 impl GenericParamDef {
is_synthetic_type_param(&self) -> bool1275 crate fn is_synthetic_type_param(&self) -> bool {
1276 match self.kind {
1277 GenericParamDefKind::Lifetime { .. } | GenericParamDefKind::Const { .. } => false,
1278 GenericParamDefKind::Type { synthetic, .. } => synthetic,
1279 }
1280 }
1281
is_type(&self) -> bool1282 crate fn is_type(&self) -> bool {
1283 self.kind.is_type()
1284 }
1285
get_type(&self) -> Option<Type>1286 crate fn get_type(&self) -> Option<Type> {
1287 self.kind.get_type()
1288 }
1289
get_bounds(&self) -> Option<&[GenericBound]>1290 crate fn get_bounds(&self) -> Option<&[GenericBound]> {
1291 match self.kind {
1292 GenericParamDefKind::Type { ref bounds, .. } => Some(bounds),
1293 _ => None,
1294 }
1295 }
1296 }
1297
1298 // maybe use a Generic enum and use Vec<Generic>?
1299 #[derive(Clone, Debug, Default)]
1300 crate struct Generics {
1301 crate params: Vec<GenericParamDef>,
1302 crate where_predicates: Vec<WherePredicate>,
1303 }
1304
1305 #[derive(Clone, Debug)]
1306 crate struct Function {
1307 crate decl: FnDecl,
1308 crate generics: Generics,
1309 crate header: hir::FnHeader,
1310 }
1311
1312 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
1313 crate struct FnDecl {
1314 crate inputs: Arguments,
1315 crate output: FnRetTy,
1316 crate c_variadic: bool,
1317 }
1318
1319 impl FnDecl {
self_type(&self) -> Option<SelfTy>1320 crate fn self_type(&self) -> Option<SelfTy> {
1321 self.inputs.values.get(0).and_then(|v| v.to_self())
1322 }
1323
1324 /// Returns the sugared return type for an async function.
1325 ///
1326 /// For example, if the return type is `impl std::future::Future<Output = i32>`, this function
1327 /// will return `i32`.
1328 ///
1329 /// # Panics
1330 ///
1331 /// This function will panic if the return type does not match the expected sugaring for async
1332 /// functions.
sugared_async_return_type(&self) -> FnRetTy1333 crate fn sugared_async_return_type(&self) -> FnRetTy {
1334 match &self.output {
1335 FnRetTy::Return(Type::ImplTrait(bounds)) => match &bounds[0] {
1336 GenericBound::TraitBound(PolyTrait { trait_, .. }, ..) => {
1337 let bindings = trait_.bindings().unwrap();
1338 FnRetTy::Return(bindings[0].ty().clone())
1339 }
1340 _ => panic!("unexpected desugaring of async function"),
1341 },
1342 _ => panic!("unexpected desugaring of async function"),
1343 }
1344 }
1345 }
1346
1347 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
1348 crate struct Arguments {
1349 crate values: Vec<Argument>,
1350 }
1351
1352 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
1353 crate struct Argument {
1354 crate type_: Type,
1355 crate name: Symbol,
1356 }
1357
1358 #[derive(Clone, PartialEq, Debug)]
1359 crate enum SelfTy {
1360 SelfValue,
1361 SelfBorrowed(Option<Lifetime>, Mutability),
1362 SelfExplicit(Type),
1363 }
1364
1365 impl Argument {
to_self(&self) -> Option<SelfTy>1366 crate fn to_self(&self) -> Option<SelfTy> {
1367 if self.name != kw::SelfLower {
1368 return None;
1369 }
1370 if self.type_.is_self_type() {
1371 return Some(SelfValue);
1372 }
1373 match self.type_ {
1374 BorrowedRef { ref lifetime, mutability, ref type_ } if type_.is_self_type() => {
1375 Some(SelfBorrowed(lifetime.clone(), mutability))
1376 }
1377 _ => Some(SelfExplicit(self.type_.clone())),
1378 }
1379 }
1380 }
1381
1382 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
1383 crate enum FnRetTy {
1384 Return(Type),
1385 DefaultReturn,
1386 }
1387
1388 impl FnRetTy {
as_return(&self) -> Option<&Type>1389 crate fn as_return(&self) -> Option<&Type> {
1390 match self {
1391 Return(ret) => Some(ret),
1392 DefaultReturn => None,
1393 }
1394 }
1395 }
1396
1397 #[derive(Clone, Debug)]
1398 crate struct Trait {
1399 crate unsafety: hir::Unsafety,
1400 crate items: Vec<Item>,
1401 crate generics: Generics,
1402 crate bounds: Vec<GenericBound>,
1403 crate is_auto: bool,
1404 }
1405
1406 #[derive(Clone, Debug)]
1407 crate struct TraitAlias {
1408 crate generics: Generics,
1409 crate bounds: Vec<GenericBound>,
1410 }
1411
1412 /// A trait reference, which may have higher ranked lifetimes.
1413 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
1414 crate struct PolyTrait {
1415 crate trait_: Path,
1416 crate generic_params: Vec<GenericParamDef>,
1417 }
1418
1419 /// Rustdoc's representation of types, mostly based on the [`hir::Ty`].
1420 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
1421 crate enum Type {
1422 /// A named type, which could be a trait.
1423 ///
1424 /// This is mostly Rustdoc's version of [`hir::Path`].
1425 /// It has to be different because Rustdoc's [`PathSegment`] can contain cleaned generics.
1426 Path { path: Path },
1427 /// A `dyn Trait` object: `dyn for<'a> Trait<'a> + Send + 'static`
1428 DynTrait(Vec<PolyTrait>, Option<Lifetime>),
1429 /// A type parameter.
1430 Generic(Symbol),
1431 /// A primitive (aka, builtin) type.
1432 Primitive(PrimitiveType),
1433 /// A function pointer: `extern "ABI" fn(...) -> ...`
1434 BareFunction(Box<BareFunctionDecl>),
1435 /// A tuple type: `(i32, &str)`.
1436 Tuple(Vec<Type>),
1437 /// A slice type (does *not* include the `&`): `[i32]`
1438 Slice(Box<Type>),
1439 /// An array type.
1440 ///
1441 /// The `String` field is a stringified version of the array's length parameter.
1442 Array(Box<Type>, String),
1443 /// A raw pointer type: `*const i32`, `*mut i32`
1444 RawPointer(Mutability, Box<Type>),
1445 /// A reference type: `&i32`, `&'a mut Foo`
1446 BorrowedRef { lifetime: Option<Lifetime>, mutability: Mutability, type_: Box<Type> },
1447
1448 /// A qualified path to an associated item: `<Type as Trait>::Name`
1449 QPath {
1450 name: Symbol,
1451 self_type: Box<Type>,
1452 /// FIXME: This is a hack that should be removed; see [this discussion][1].
1453 ///
1454 /// [1]: https://github.com/rust-lang/rust/pull/85479#discussion_r635729093
1455 self_def_id: Option<DefId>,
1456 trait_: Path,
1457 },
1458
1459 /// A type that is inferred: `_`
1460 Infer,
1461
1462 /// An `impl Trait`: `impl TraitA + TraitB + ...`
1463 ImplTrait(Vec<GenericBound>),
1464 }
1465
1466 // `Type` is used a lot. Make sure it doesn't unintentionally get bigger.
1467 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
1468 rustc_data_structures::static_assert_size!(Type, 72);
1469
1470 impl Type {
primitive_type(&self) -> Option<PrimitiveType>1471 crate fn primitive_type(&self) -> Option<PrimitiveType> {
1472 match *self {
1473 Primitive(p) | BorrowedRef { type_: box Primitive(p), .. } => Some(p),
1474 Slice(..) | BorrowedRef { type_: box Slice(..), .. } => Some(PrimitiveType::Slice),
1475 Array(..) | BorrowedRef { type_: box Array(..), .. } => Some(PrimitiveType::Array),
1476 Tuple(ref tys) => {
1477 if tys.is_empty() {
1478 Some(PrimitiveType::Unit)
1479 } else {
1480 Some(PrimitiveType::Tuple)
1481 }
1482 }
1483 RawPointer(..) => Some(PrimitiveType::RawPointer),
1484 BareFunction(..) => Some(PrimitiveType::Fn),
1485 _ => None,
1486 }
1487 }
1488
1489 /// Checks if this is a `T::Name` path for an associated type.
is_assoc_ty(&self) -> bool1490 crate fn is_assoc_ty(&self) -> bool {
1491 match self {
1492 Type::Path { path, .. } => path.is_assoc_ty(),
1493 _ => false,
1494 }
1495 }
1496
is_self_type(&self) -> bool1497 crate fn is_self_type(&self) -> bool {
1498 match *self {
1499 Generic(name) => name == kw::SelfUpper,
1500 _ => false,
1501 }
1502 }
1503
generics(&self) -> Option<Vec<&Type>>1504 crate fn generics(&self) -> Option<Vec<&Type>> {
1505 match self {
1506 Type::Path { path, .. } => path.generics(),
1507 _ => None,
1508 }
1509 }
1510
is_full_generic(&self) -> bool1511 crate fn is_full_generic(&self) -> bool {
1512 matches!(self, Type::Generic(_))
1513 }
1514
is_primitive(&self) -> bool1515 crate fn is_primitive(&self) -> bool {
1516 self.primitive_type().is_some()
1517 }
1518
projection(&self) -> Option<(&Type, DefId, Symbol)>1519 crate fn projection(&self) -> Option<(&Type, DefId, Symbol)> {
1520 let (self_, trait_, name) = match self {
1521 QPath { self_type, trait_, name, .. } => (self_type, trait_, name),
1522 _ => return None,
1523 };
1524 Some((&self_, trait_.def_id(), *name))
1525 }
1526
inner_def_id(&self, cache: Option<&Cache>) -> Option<DefId>1527 fn inner_def_id(&self, cache: Option<&Cache>) -> Option<DefId> {
1528 let t: PrimitiveType = match *self {
1529 Type::Path { ref path } => return Some(path.def_id()),
1530 DynTrait(ref bounds, _) => return Some(bounds[0].trait_.def_id()),
1531 Primitive(p) => return cache.and_then(|c| c.primitive_locations.get(&p).cloned()),
1532 BorrowedRef { type_: box Generic(..), .. } => PrimitiveType::Reference,
1533 BorrowedRef { ref type_, .. } => return type_.inner_def_id(cache),
1534 Tuple(ref tys) => {
1535 if tys.is_empty() {
1536 PrimitiveType::Unit
1537 } else {
1538 PrimitiveType::Tuple
1539 }
1540 }
1541 BareFunction(..) => PrimitiveType::Fn,
1542 Slice(..) => PrimitiveType::Slice,
1543 Array(..) => PrimitiveType::Array,
1544 RawPointer(..) => PrimitiveType::RawPointer,
1545 QPath { ref self_type, .. } => return self_type.inner_def_id(cache),
1546 Generic(_) | Infer | ImplTrait(_) => return None,
1547 };
1548 cache.and_then(|c| Primitive(t).def_id(c))
1549 }
1550
1551 /// Use this method to get the [DefId] of a [clean] AST node, including [PrimitiveType]s.
1552 ///
1553 /// See [`Self::def_id_no_primitives`] for more.
1554 ///
1555 /// [clean]: crate::clean
def_id(&self, cache: &Cache) -> Option<DefId>1556 crate fn def_id(&self, cache: &Cache) -> Option<DefId> {
1557 self.inner_def_id(Some(cache))
1558 }
1559
1560 /// Use this method to get the [`DefId`] of a [`clean`] AST node.
1561 /// This will return [`None`] when called on a primitive [`clean::Type`].
1562 /// Use [`Self::def_id`] if you want to include primitives.
1563 ///
1564 /// [`clean`]: crate::clean
1565 /// [`clean::Type`]: crate::clean::Type
1566 // FIXME: get rid of this function and always use `def_id`
def_id_no_primitives(&self) -> Option<DefId>1567 crate fn def_id_no_primitives(&self) -> Option<DefId> {
1568 self.inner_def_id(None)
1569 }
1570 }
1571
1572 /// A primitive (aka, builtin) type.
1573 ///
1574 /// This represents things like `i32`, `str`, etc.
1575 ///
1576 /// N.B. This has to be different from [`hir::PrimTy`] because it also includes types that aren't
1577 /// paths, like [`Self::Unit`].
1578 #[derive(Clone, PartialEq, Eq, Hash, Copy, Debug)]
1579 crate enum PrimitiveType {
1580 Isize,
1581 I8,
1582 I16,
1583 I32,
1584 I64,
1585 I128,
1586 Usize,
1587 U8,
1588 U16,
1589 U32,
1590 U64,
1591 U128,
1592 F32,
1593 F64,
1594 Char,
1595 Bool,
1596 Str,
1597 Slice,
1598 Array,
1599 Tuple,
1600 Unit,
1601 RawPointer,
1602 Reference,
1603 Fn,
1604 Never,
1605 }
1606
1607 impl PrimitiveType {
from_hir(prim: hir::PrimTy) -> PrimitiveType1608 crate fn from_hir(prim: hir::PrimTy) -> PrimitiveType {
1609 use ast::{FloatTy, IntTy, UintTy};
1610 match prim {
1611 hir::PrimTy::Int(IntTy::Isize) => PrimitiveType::Isize,
1612 hir::PrimTy::Int(IntTy::I8) => PrimitiveType::I8,
1613 hir::PrimTy::Int(IntTy::I16) => PrimitiveType::I16,
1614 hir::PrimTy::Int(IntTy::I32) => PrimitiveType::I32,
1615 hir::PrimTy::Int(IntTy::I64) => PrimitiveType::I64,
1616 hir::PrimTy::Int(IntTy::I128) => PrimitiveType::I128,
1617 hir::PrimTy::Uint(UintTy::Usize) => PrimitiveType::Usize,
1618 hir::PrimTy::Uint(UintTy::U8) => PrimitiveType::U8,
1619 hir::PrimTy::Uint(UintTy::U16) => PrimitiveType::U16,
1620 hir::PrimTy::Uint(UintTy::U32) => PrimitiveType::U32,
1621 hir::PrimTy::Uint(UintTy::U64) => PrimitiveType::U64,
1622 hir::PrimTy::Uint(UintTy::U128) => PrimitiveType::U128,
1623 hir::PrimTy::Float(FloatTy::F32) => PrimitiveType::F32,
1624 hir::PrimTy::Float(FloatTy::F64) => PrimitiveType::F64,
1625 hir::PrimTy::Str => PrimitiveType::Str,
1626 hir::PrimTy::Bool => PrimitiveType::Bool,
1627 hir::PrimTy::Char => PrimitiveType::Char,
1628 }
1629 }
1630
from_symbol(s: Symbol) -> Option<PrimitiveType>1631 crate fn from_symbol(s: Symbol) -> Option<PrimitiveType> {
1632 match s {
1633 sym::isize => Some(PrimitiveType::Isize),
1634 sym::i8 => Some(PrimitiveType::I8),
1635 sym::i16 => Some(PrimitiveType::I16),
1636 sym::i32 => Some(PrimitiveType::I32),
1637 sym::i64 => Some(PrimitiveType::I64),
1638 sym::i128 => Some(PrimitiveType::I128),
1639 sym::usize => Some(PrimitiveType::Usize),
1640 sym::u8 => Some(PrimitiveType::U8),
1641 sym::u16 => Some(PrimitiveType::U16),
1642 sym::u32 => Some(PrimitiveType::U32),
1643 sym::u64 => Some(PrimitiveType::U64),
1644 sym::u128 => Some(PrimitiveType::U128),
1645 sym::bool => Some(PrimitiveType::Bool),
1646 sym::char => Some(PrimitiveType::Char),
1647 sym::str => Some(PrimitiveType::Str),
1648 sym::f32 => Some(PrimitiveType::F32),
1649 sym::f64 => Some(PrimitiveType::F64),
1650 sym::array => Some(PrimitiveType::Array),
1651 sym::slice => Some(PrimitiveType::Slice),
1652 sym::tuple => Some(PrimitiveType::Tuple),
1653 sym::unit => Some(PrimitiveType::Unit),
1654 sym::pointer => Some(PrimitiveType::RawPointer),
1655 sym::reference => Some(PrimitiveType::Reference),
1656 kw::Fn => Some(PrimitiveType::Fn),
1657 sym::never => Some(PrimitiveType::Never),
1658 _ => None,
1659 }
1660 }
1661
impls(&self, tcx: TyCtxt<'_>) -> &'static ArrayVec<DefId, 4>1662 crate fn impls(&self, tcx: TyCtxt<'_>) -> &'static ArrayVec<DefId, 4> {
1663 Self::all_impls(tcx).get(self).expect("missing impl for primitive type")
1664 }
1665
all_impls(tcx: TyCtxt<'_>) -> &'static FxHashMap<PrimitiveType, ArrayVec<DefId, 4>>1666 crate fn all_impls(tcx: TyCtxt<'_>) -> &'static FxHashMap<PrimitiveType, ArrayVec<DefId, 4>> {
1667 static CELL: OnceCell<FxHashMap<PrimitiveType, ArrayVec<DefId, 4>>> = OnceCell::new();
1668
1669 CELL.get_or_init(move || {
1670 use self::PrimitiveType::*;
1671
1672 let single = |a: Option<DefId>| a.into_iter().collect();
1673 let both = |a: Option<DefId>, b: Option<DefId>| -> ArrayVec<_, 4> {
1674 a.into_iter().chain(b).collect()
1675 };
1676
1677 let lang_items = tcx.lang_items();
1678 map! {
1679 Isize => single(lang_items.isize_impl()),
1680 I8 => single(lang_items.i8_impl()),
1681 I16 => single(lang_items.i16_impl()),
1682 I32 => single(lang_items.i32_impl()),
1683 I64 => single(lang_items.i64_impl()),
1684 I128 => single(lang_items.i128_impl()),
1685 Usize => single(lang_items.usize_impl()),
1686 U8 => single(lang_items.u8_impl()),
1687 U16 => single(lang_items.u16_impl()),
1688 U32 => single(lang_items.u32_impl()),
1689 U64 => single(lang_items.u64_impl()),
1690 U128 => single(lang_items.u128_impl()),
1691 F32 => both(lang_items.f32_impl(), lang_items.f32_runtime_impl()),
1692 F64 => both(lang_items.f64_impl(), lang_items.f64_runtime_impl()),
1693 Char => single(lang_items.char_impl()),
1694 Bool => single(lang_items.bool_impl()),
1695 Str => both(lang_items.str_impl(), lang_items.str_alloc_impl()),
1696 Slice => {
1697 lang_items
1698 .slice_impl()
1699 .into_iter()
1700 .chain(lang_items.slice_u8_impl())
1701 .chain(lang_items.slice_alloc_impl())
1702 .chain(lang_items.slice_u8_alloc_impl())
1703 .collect()
1704 },
1705 Array => single(lang_items.array_impl()),
1706 Tuple => ArrayVec::new(),
1707 Unit => ArrayVec::new(),
1708 RawPointer => {
1709 lang_items
1710 .const_ptr_impl()
1711 .into_iter()
1712 .chain(lang_items.mut_ptr_impl())
1713 .chain(lang_items.const_slice_ptr_impl())
1714 .chain(lang_items.mut_slice_ptr_impl())
1715 .collect()
1716 },
1717 Reference => ArrayVec::new(),
1718 Fn => ArrayVec::new(),
1719 Never => ArrayVec::new(),
1720 }
1721 })
1722 }
1723
as_sym(&self) -> Symbol1724 crate fn as_sym(&self) -> Symbol {
1725 use PrimitiveType::*;
1726 match self {
1727 Isize => sym::isize,
1728 I8 => sym::i8,
1729 I16 => sym::i16,
1730 I32 => sym::i32,
1731 I64 => sym::i64,
1732 I128 => sym::i128,
1733 Usize => sym::usize,
1734 U8 => sym::u8,
1735 U16 => sym::u16,
1736 U32 => sym::u32,
1737 U64 => sym::u64,
1738 U128 => sym::u128,
1739 F32 => sym::f32,
1740 F64 => sym::f64,
1741 Str => sym::str,
1742 Bool => sym::bool,
1743 Char => sym::char,
1744 Array => sym::array,
1745 Slice => sym::slice,
1746 Tuple => sym::tuple,
1747 Unit => sym::unit,
1748 RawPointer => sym::pointer,
1749 Reference => sym::reference,
1750 Fn => kw::Fn,
1751 Never => sym::never,
1752 }
1753 }
1754
1755 /// Returns the DefId of the module with `doc(primitive)` for this primitive type.
1756 /// Panics if there is no such module.
1757 ///
1758 /// This gives precedence to primitives defined in the current crate, and deprioritizes primitives defined in `core`,
1759 /// but otherwise, if multiple crates define the same primitive, there is no guarantee of which will be picked.
1760 /// In particular, if a crate depends on both `std` and another crate that also defines `doc(primitive)`, then
1761 /// it's entirely random whether `std` or the other crate is picked. (no_std crates are usually fine unless multiple dependencies define a primitive.)
primitive_locations(tcx: TyCtxt<'_>) -> &FxHashMap<PrimitiveType, DefId>1762 crate fn primitive_locations(tcx: TyCtxt<'_>) -> &FxHashMap<PrimitiveType, DefId> {
1763 static PRIMITIVE_LOCATIONS: OnceCell<FxHashMap<PrimitiveType, DefId>> = OnceCell::new();
1764 PRIMITIVE_LOCATIONS.get_or_init(|| {
1765 let mut primitive_locations = FxHashMap::default();
1766 // NOTE: technically this misses crates that are only passed with `--extern` and not loaded when checking the crate.
1767 // This is a degenerate case that I don't plan to support.
1768 for &crate_num in tcx.crates(()) {
1769 let e = ExternalCrate { crate_num };
1770 let crate_name = e.name(tcx);
1771 debug!(?crate_num, ?crate_name);
1772 for &(def_id, prim) in &e.primitives(tcx) {
1773 // HACK: try to link to std instead where possible
1774 if crate_name == sym::core && primitive_locations.contains_key(&prim) {
1775 continue;
1776 }
1777 primitive_locations.insert(prim, def_id);
1778 }
1779 }
1780 let local_primitives = ExternalCrate { crate_num: LOCAL_CRATE }.primitives(tcx);
1781 for (def_id, prim) in local_primitives {
1782 primitive_locations.insert(prim, def_id);
1783 }
1784 primitive_locations
1785 })
1786 }
1787 }
1788
1789 impl From<ast::IntTy> for PrimitiveType {
from(int_ty: ast::IntTy) -> PrimitiveType1790 fn from(int_ty: ast::IntTy) -> PrimitiveType {
1791 match int_ty {
1792 ast::IntTy::Isize => PrimitiveType::Isize,
1793 ast::IntTy::I8 => PrimitiveType::I8,
1794 ast::IntTy::I16 => PrimitiveType::I16,
1795 ast::IntTy::I32 => PrimitiveType::I32,
1796 ast::IntTy::I64 => PrimitiveType::I64,
1797 ast::IntTy::I128 => PrimitiveType::I128,
1798 }
1799 }
1800 }
1801
1802 impl From<ast::UintTy> for PrimitiveType {
from(uint_ty: ast::UintTy) -> PrimitiveType1803 fn from(uint_ty: ast::UintTy) -> PrimitiveType {
1804 match uint_ty {
1805 ast::UintTy::Usize => PrimitiveType::Usize,
1806 ast::UintTy::U8 => PrimitiveType::U8,
1807 ast::UintTy::U16 => PrimitiveType::U16,
1808 ast::UintTy::U32 => PrimitiveType::U32,
1809 ast::UintTy::U64 => PrimitiveType::U64,
1810 ast::UintTy::U128 => PrimitiveType::U128,
1811 }
1812 }
1813 }
1814
1815 impl From<ast::FloatTy> for PrimitiveType {
from(float_ty: ast::FloatTy) -> PrimitiveType1816 fn from(float_ty: ast::FloatTy) -> PrimitiveType {
1817 match float_ty {
1818 ast::FloatTy::F32 => PrimitiveType::F32,
1819 ast::FloatTy::F64 => PrimitiveType::F64,
1820 }
1821 }
1822 }
1823
1824 impl From<ty::IntTy> for PrimitiveType {
from(int_ty: ty::IntTy) -> PrimitiveType1825 fn from(int_ty: ty::IntTy) -> PrimitiveType {
1826 match int_ty {
1827 ty::IntTy::Isize => PrimitiveType::Isize,
1828 ty::IntTy::I8 => PrimitiveType::I8,
1829 ty::IntTy::I16 => PrimitiveType::I16,
1830 ty::IntTy::I32 => PrimitiveType::I32,
1831 ty::IntTy::I64 => PrimitiveType::I64,
1832 ty::IntTy::I128 => PrimitiveType::I128,
1833 }
1834 }
1835 }
1836
1837 impl From<ty::UintTy> for PrimitiveType {
from(uint_ty: ty::UintTy) -> PrimitiveType1838 fn from(uint_ty: ty::UintTy) -> PrimitiveType {
1839 match uint_ty {
1840 ty::UintTy::Usize => PrimitiveType::Usize,
1841 ty::UintTy::U8 => PrimitiveType::U8,
1842 ty::UintTy::U16 => PrimitiveType::U16,
1843 ty::UintTy::U32 => PrimitiveType::U32,
1844 ty::UintTy::U64 => PrimitiveType::U64,
1845 ty::UintTy::U128 => PrimitiveType::U128,
1846 }
1847 }
1848 }
1849
1850 impl From<ty::FloatTy> for PrimitiveType {
from(float_ty: ty::FloatTy) -> PrimitiveType1851 fn from(float_ty: ty::FloatTy) -> PrimitiveType {
1852 match float_ty {
1853 ty::FloatTy::F32 => PrimitiveType::F32,
1854 ty::FloatTy::F64 => PrimitiveType::F64,
1855 }
1856 }
1857 }
1858
1859 impl From<hir::PrimTy> for PrimitiveType {
from(prim_ty: hir::PrimTy) -> PrimitiveType1860 fn from(prim_ty: hir::PrimTy) -> PrimitiveType {
1861 match prim_ty {
1862 hir::PrimTy::Int(int_ty) => int_ty.into(),
1863 hir::PrimTy::Uint(uint_ty) => uint_ty.into(),
1864 hir::PrimTy::Float(float_ty) => float_ty.into(),
1865 hir::PrimTy::Str => PrimitiveType::Str,
1866 hir::PrimTy::Bool => PrimitiveType::Bool,
1867 hir::PrimTy::Char => PrimitiveType::Char,
1868 }
1869 }
1870 }
1871
1872 #[derive(Copy, Clone, Debug)]
1873 crate enum Visibility {
1874 /// `pub`
1875 Public,
1876 /// Visibility inherited from parent.
1877 ///
1878 /// For example, this is the visibility of private items and of enum variants.
1879 Inherited,
1880 /// `pub(crate)`, `pub(super)`, or `pub(in path::to::somewhere)`
1881 Restricted(DefId),
1882 }
1883
1884 impl Visibility {
is_public(&self) -> bool1885 crate fn is_public(&self) -> bool {
1886 matches!(self, Visibility::Public)
1887 }
1888 }
1889
1890 #[derive(Clone, Debug)]
1891 crate struct Struct {
1892 crate struct_type: CtorKind,
1893 crate generics: Generics,
1894 crate fields: Vec<Item>,
1895 crate fields_stripped: bool,
1896 }
1897
1898 #[derive(Clone, Debug)]
1899 crate struct Union {
1900 crate generics: Generics,
1901 crate fields: Vec<Item>,
1902 crate fields_stripped: bool,
1903 }
1904
1905 /// This is a more limited form of the standard Struct, different in that
1906 /// it lacks the things most items have (name, id, parameterization). Found
1907 /// only as a variant in an enum.
1908 #[derive(Clone, Debug)]
1909 crate struct VariantStruct {
1910 crate struct_type: CtorKind,
1911 crate fields: Vec<Item>,
1912 crate fields_stripped: bool,
1913 }
1914
1915 #[derive(Clone, Debug)]
1916 crate struct Enum {
1917 crate variants: IndexVec<VariantIdx, Item>,
1918 crate generics: Generics,
1919 crate variants_stripped: bool,
1920 }
1921
1922 #[derive(Clone, Debug)]
1923 crate enum Variant {
1924 CLike,
1925 Tuple(Vec<Item>),
1926 Struct(VariantStruct),
1927 }
1928
1929 /// Small wrapper around [`rustc_span::Span`] that adds helper methods
1930 /// and enforces calling [`rustc_span::Span::source_callsite()`].
1931 #[derive(Copy, Clone, Debug)]
1932 crate struct Span(rustc_span::Span);
1933
1934 impl Span {
1935 /// Wraps a [`rustc_span::Span`]. In case this span is the result of a macro expansion, the
1936 /// span will be updated to point to the macro invocation instead of the macro definition.
1937 ///
1938 /// (See rust-lang/rust#39726)
new(sp: rustc_span::Span) -> Self1939 crate fn new(sp: rustc_span::Span) -> Self {
1940 Self(sp.source_callsite())
1941 }
1942
inner(&self) -> rustc_span::Span1943 crate fn inner(&self) -> rustc_span::Span {
1944 self.0
1945 }
1946
dummy() -> Self1947 crate fn dummy() -> Self {
1948 Self(rustc_span::DUMMY_SP)
1949 }
1950
is_dummy(&self) -> bool1951 crate fn is_dummy(&self) -> bool {
1952 self.0.is_dummy()
1953 }
1954
filename(&self, sess: &Session) -> FileName1955 crate fn filename(&self, sess: &Session) -> FileName {
1956 sess.source_map().span_to_filename(self.0)
1957 }
1958
lo(&self, sess: &Session) -> Loc1959 crate fn lo(&self, sess: &Session) -> Loc {
1960 sess.source_map().lookup_char_pos(self.0.lo())
1961 }
1962
hi(&self, sess: &Session) -> Loc1963 crate fn hi(&self, sess: &Session) -> Loc {
1964 sess.source_map().lookup_char_pos(self.0.hi())
1965 }
1966
cnum(&self, sess: &Session) -> CrateNum1967 crate fn cnum(&self, sess: &Session) -> CrateNum {
1968 // FIXME: is there a time when the lo and hi crate would be different?
1969 self.lo(sess).file.cnum
1970 }
1971 }
1972
1973 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
1974 crate struct Path {
1975 crate res: Res,
1976 crate segments: Vec<PathSegment>,
1977 }
1978
1979 impl Path {
def_id(&self) -> DefId1980 crate fn def_id(&self) -> DefId {
1981 self.res.def_id()
1982 }
1983
last(&self) -> Symbol1984 crate fn last(&self) -> Symbol {
1985 self.segments.last().expect("segments were empty").name
1986 }
1987
last_name(&self) -> SymbolStr1988 crate fn last_name(&self) -> SymbolStr {
1989 self.segments.last().expect("segments were empty").name.as_str()
1990 }
1991
whole_name(&self) -> String1992 crate fn whole_name(&self) -> String {
1993 self.segments
1994 .iter()
1995 .map(|s| if s.name == kw::PathRoot { String::new() } else { s.name.to_string() })
1996 .intersperse("::".into())
1997 .collect()
1998 }
1999
2000 /// Checks if this is a `T::Name` path for an associated type.
is_assoc_ty(&self) -> bool2001 crate fn is_assoc_ty(&self) -> bool {
2002 match self.res {
2003 Res::SelfTy(..) if self.segments.len() != 1 => true,
2004 Res::Def(DefKind::TyParam, _) if self.segments.len() != 1 => true,
2005 Res::Def(DefKind::AssocTy, _) => true,
2006 _ => false,
2007 }
2008 }
2009
generics(&self) -> Option<Vec<&Type>>2010 crate fn generics(&self) -> Option<Vec<&Type>> {
2011 self.segments.last().and_then(|seg| {
2012 if let GenericArgs::AngleBracketed { ref args, .. } = seg.args {
2013 Some(
2014 args.iter()
2015 .filter_map(|arg| match arg {
2016 GenericArg::Type(ty) => Some(ty),
2017 _ => None,
2018 })
2019 .collect(),
2020 )
2021 } else {
2022 None
2023 }
2024 })
2025 }
2026
bindings(&self) -> Option<&[TypeBinding]>2027 crate fn bindings(&self) -> Option<&[TypeBinding]> {
2028 self.segments.last().and_then(|seg| {
2029 if let GenericArgs::AngleBracketed { ref bindings, .. } = seg.args {
2030 Some(&**bindings)
2031 } else {
2032 None
2033 }
2034 })
2035 }
2036 }
2037
2038 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
2039 crate enum GenericArg {
2040 Lifetime(Lifetime),
2041 Type(Type),
2042 Const(Box<Constant>),
2043 Infer,
2044 }
2045
2046 // `GenericArg` can occur many times in a single `Path`, so make sure it
2047 // doesn't increase in size unexpectedly.
2048 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
2049 rustc_data_structures::static_assert_size!(GenericArg, 80);
2050
2051 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
2052 crate enum GenericArgs {
2053 AngleBracketed { args: Vec<GenericArg>, bindings: Vec<TypeBinding> },
2054 Parenthesized { inputs: Vec<Type>, output: Option<Box<Type>> },
2055 }
2056
2057 // `GenericArgs` is in every `PathSegment`, so its size can significantly
2058 // affect rustdoc's memory usage.
2059 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
2060 rustc_data_structures::static_assert_size!(GenericArgs, 56);
2061
2062 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
2063 crate struct PathSegment {
2064 crate name: Symbol,
2065 crate args: GenericArgs,
2066 }
2067
2068 // `PathSegment` usually occurs multiple times in every `Path`, so its size can
2069 // significantly affect rustdoc's memory usage.
2070 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
2071 rustc_data_structures::static_assert_size!(PathSegment, 64);
2072
2073 #[derive(Clone, Debug)]
2074 crate struct Typedef {
2075 crate type_: Type,
2076 crate generics: Generics,
2077 /// `type_` can come from either the HIR or from metadata. If it comes from HIR, it may be a type
2078 /// alias instead of the final type. This will always have the final type, regardless of whether
2079 /// `type_` came from HIR or from metadata.
2080 ///
2081 /// If `item_type.is_none()`, `type_` is guarenteed to come from metadata (and therefore hold the
2082 /// final type).
2083 crate item_type: Option<Type>,
2084 }
2085
2086 #[derive(Clone, Debug)]
2087 crate struct OpaqueTy {
2088 crate bounds: Vec<GenericBound>,
2089 crate generics: Generics,
2090 }
2091
2092 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
2093 crate struct BareFunctionDecl {
2094 crate unsafety: hir::Unsafety,
2095 crate generic_params: Vec<GenericParamDef>,
2096 crate decl: FnDecl,
2097 crate abi: Abi,
2098 }
2099
2100 #[derive(Clone, Debug)]
2101 crate struct Static {
2102 crate type_: Type,
2103 crate mutability: Mutability,
2104 crate expr: Option<BodyId>,
2105 }
2106
2107 #[derive(Clone, PartialEq, Eq, Hash, Debug)]
2108 crate struct Constant {
2109 crate type_: Type,
2110 crate kind: ConstantKind,
2111 }
2112
2113 #[derive(Clone, PartialEq, Eq, Hash, Debug)]
2114 crate enum ConstantKind {
2115 /// This is the wrapper around `ty::Const` for a non-local constant. Because it doesn't have a
2116 /// `BodyId`, we need to handle it on its own.
2117 ///
2118 /// Note that `ty::Const` includes generic parameters, and may not always be uniquely identified
2119 /// by a DefId. So this field must be different from `Extern`.
2120 TyConst { expr: String },
2121 /// A constant (expression) that's not an item or associated item. These are usually found
2122 /// nested inside types (e.g., array lengths) or expressions (e.g., repeat counts), and also
2123 /// used to define explicit discriminant values for enum variants.
2124 Anonymous { body: BodyId },
2125 /// A constant from a different crate.
2126 Extern { def_id: DefId },
2127 /// `const FOO: u32 = ...;`
2128 Local { def_id: DefId, body: BodyId },
2129 }
2130
2131 impl Constant {
expr(&self, tcx: TyCtxt<'_>) -> String2132 crate fn expr(&self, tcx: TyCtxt<'_>) -> String {
2133 match self.kind {
2134 ConstantKind::TyConst { ref expr } => expr.clone(),
2135 ConstantKind::Extern { def_id } => print_inlined_const(tcx, def_id),
2136 ConstantKind::Local { body, .. } | ConstantKind::Anonymous { body } => {
2137 print_const_expr(tcx, body)
2138 }
2139 }
2140 }
2141
value(&self, tcx: TyCtxt<'_>) -> Option<String>2142 crate fn value(&self, tcx: TyCtxt<'_>) -> Option<String> {
2143 match self.kind {
2144 ConstantKind::TyConst { .. } | ConstantKind::Anonymous { .. } => None,
2145 ConstantKind::Extern { def_id } | ConstantKind::Local { def_id, .. } => {
2146 print_evaluated_const(tcx, def_id)
2147 }
2148 }
2149 }
2150
is_literal(&self, tcx: TyCtxt<'_>) -> bool2151 crate fn is_literal(&self, tcx: TyCtxt<'_>) -> bool {
2152 match self.kind {
2153 ConstantKind::TyConst { .. } => false,
2154 ConstantKind::Extern { def_id } => def_id.as_local().map_or(false, |def_id| {
2155 is_literal_expr(tcx, tcx.hir().local_def_id_to_hir_id(def_id))
2156 }),
2157 ConstantKind::Local { body, .. } | ConstantKind::Anonymous { body } => {
2158 is_literal_expr(tcx, body.hir_id)
2159 }
2160 }
2161 }
2162 }
2163
2164 #[derive(Clone, Debug)]
2165 crate struct Impl {
2166 crate unsafety: hir::Unsafety,
2167 crate generics: Generics,
2168 crate trait_: Option<Path>,
2169 crate for_: Type,
2170 crate items: Vec<Item>,
2171 crate polarity: ty::ImplPolarity,
2172 crate kind: ImplKind,
2173 }
2174
2175 impl Impl {
provided_trait_methods(&self, tcx: TyCtxt<'_>) -> FxHashSet<Symbol>2176 crate fn provided_trait_methods(&self, tcx: TyCtxt<'_>) -> FxHashSet<Symbol> {
2177 self.trait_
2178 .as_ref()
2179 .map(|t| t.def_id())
2180 .map(|did| tcx.provided_trait_methods(did).map(|meth| meth.ident.name).collect())
2181 .unwrap_or_default()
2182 }
2183 }
2184
2185 #[derive(Clone, Debug)]
2186 crate enum ImplKind {
2187 Normal,
2188 Auto,
2189 Blanket(Box<Type>),
2190 }
2191
2192 impl ImplKind {
is_auto(&self) -> bool2193 crate fn is_auto(&self) -> bool {
2194 matches!(self, ImplKind::Auto)
2195 }
2196
is_blanket(&self) -> bool2197 crate fn is_blanket(&self) -> bool {
2198 matches!(self, ImplKind::Blanket(_))
2199 }
2200
as_blanket_ty(&self) -> Option<&Type>2201 crate fn as_blanket_ty(&self) -> Option<&Type> {
2202 match self {
2203 ImplKind::Blanket(ty) => Some(ty),
2204 _ => None,
2205 }
2206 }
2207 }
2208
2209 #[derive(Clone, Debug)]
2210 crate struct Import {
2211 crate kind: ImportKind,
2212 crate source: ImportSource,
2213 crate should_be_displayed: bool,
2214 }
2215
2216 impl Import {
new_simple(name: Symbol, source: ImportSource, should_be_displayed: bool) -> Self2217 crate fn new_simple(name: Symbol, source: ImportSource, should_be_displayed: bool) -> Self {
2218 Self { kind: ImportKind::Simple(name), source, should_be_displayed }
2219 }
2220
new_glob(source: ImportSource, should_be_displayed: bool) -> Self2221 crate fn new_glob(source: ImportSource, should_be_displayed: bool) -> Self {
2222 Self { kind: ImportKind::Glob, source, should_be_displayed }
2223 }
2224 }
2225
2226 #[derive(Clone, Debug)]
2227 crate enum ImportKind {
2228 // use source as str;
2229 Simple(Symbol),
2230 // use source::*;
2231 Glob,
2232 }
2233
2234 #[derive(Clone, Debug)]
2235 crate struct ImportSource {
2236 crate path: Path,
2237 crate did: Option<DefId>,
2238 }
2239
2240 #[derive(Clone, Debug)]
2241 crate struct Macro {
2242 crate source: String,
2243 }
2244
2245 #[derive(Clone, Debug)]
2246 crate struct ProcMacro {
2247 crate kind: MacroKind,
2248 crate helpers: Vec<Symbol>,
2249 }
2250
2251 /// An type binding on an associated type (e.g., `A = Bar` in `Foo<A = Bar>` or
2252 /// `A: Send + Sync` in `Foo<A: Send + Sync>`).
2253 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
2254 crate struct TypeBinding {
2255 crate name: Symbol,
2256 crate kind: TypeBindingKind,
2257 }
2258
2259 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
2260 crate enum TypeBindingKind {
2261 Equality { ty: Type },
2262 Constraint { bounds: Vec<GenericBound> },
2263 }
2264
2265 impl TypeBinding {
ty(&self) -> &Type2266 crate fn ty(&self) -> &Type {
2267 match self.kind {
2268 TypeBindingKind::Equality { ref ty } => ty,
2269 _ => panic!("expected equality type binding for parenthesized generic args"),
2270 }
2271 }
2272 }
2273
2274 /// The type, lifetime, or constant that a private type alias's parameter should be
2275 /// replaced with when expanding a use of that type alias.
2276 ///
2277 /// For example:
2278 ///
2279 /// ```
2280 /// type PrivAlias<T> = Vec<T>;
2281 ///
2282 /// pub fn public_fn() -> PrivAlias<i32> { vec![] }
2283 /// ```
2284 ///
2285 /// `public_fn`'s docs will show it as returning `Vec<i32>`, since `PrivAlias` is private.
2286 /// [`SubstParam`] is used to record that `T` should be mapped to `i32`.
2287 crate enum SubstParam {
2288 Type(Type),
2289 Lifetime(Lifetime),
2290 Constant(Constant),
2291 }
2292
2293 impl SubstParam {
as_ty(&self) -> Option<&Type>2294 crate fn as_ty(&self) -> Option<&Type> {
2295 if let Self::Type(ty) = self { Some(ty) } else { None }
2296 }
2297
as_lt(&self) -> Option<&Lifetime>2298 crate fn as_lt(&self) -> Option<&Lifetime> {
2299 if let Self::Lifetime(lt) = self { Some(lt) } else { None }
2300 }
2301 }
2302