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