]> git.lizzy.rs Git - rust.git/blob - src/librustdoc/html/render/mod.rs
Auto merge of #105612 - oli-obk:bind_rustdoc, r=GuillaumeGomez
[rust.git] / src / librustdoc / html / render / mod.rs
1 //! Rustdoc's HTML rendering module.
2 //!
3 //! This modules contains the bulk of the logic necessary for rendering a
4 //! rustdoc `clean::Crate` instance to a set of static HTML pages. This
5 //! rendering process is largely driven by the `format!` syntax extension to
6 //! perform all I/O into files and streams.
7 //!
8 //! The rendering process is largely driven by the `Context` and `Cache`
9 //! structures. The cache is pre-populated by crawling the crate in question,
10 //! and then it is shared among the various rendering threads. The cache is meant
11 //! to be a fairly large structure not implementing `Clone` (because it's shared
12 //! among threads). The context, however, should be a lightweight structure. This
13 //! is cloned per-thread and contains information about what is currently being
14 //! rendered.
15 //!
16 //! In order to speed up rendering (mostly because of markdown rendering), the
17 //! rendering process has been parallelized. This parallelization is only
18 //! exposed through the `crate` method on the context, and then also from the
19 //! fact that the shared cache is stored in TLS (and must be accessed as such).
20 //!
21 //! In addition to rendering the crate itself, this module is also responsible
22 //! for creating the corresponding search index and source file renderings.
23 //! These threads are not parallelized (they haven't been a bottleneck yet), and
24 //! both occur before the crate is rendered.
25
26 pub(crate) mod search_index;
27
28 #[cfg(test)]
29 mod tests;
30
31 mod context;
32 mod print_item;
33 mod span_map;
34 mod write_shared;
35
36 pub(crate) use self::context::*;
37 pub(crate) use self::span_map::{collect_spans_and_sources, LinkFromSrc};
38
39 use std::collections::VecDeque;
40 use std::default::Default;
41 use std::fmt;
42 use std::fs;
43 use std::iter::Peekable;
44 use std::path::PathBuf;
45 use std::rc::Rc;
46 use std::str;
47 use std::string::ToString;
48
49 use rustc_ast_pretty::pprust;
50 use rustc_attr::{ConstStability, Deprecation, StabilityLevel};
51 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
52 use rustc_hir::def::CtorKind;
53 use rustc_hir::def_id::DefId;
54 use rustc_hir::Mutability;
55 use rustc_middle::middle::stability;
56 use rustc_middle::ty;
57 use rustc_middle::ty::TyCtxt;
58 use rustc_span::{
59     symbol::{sym, Symbol},
60     BytePos, FileName, RealFileName,
61 };
62 use serde::ser::{SerializeMap, SerializeSeq};
63 use serde::{Serialize, Serializer};
64
65 use crate::clean::{self, ItemId, RenderedLink, SelfTy};
66 use crate::error::Error;
67 use crate::formats::cache::Cache;
68 use crate::formats::item_type::ItemType;
69 use crate::formats::{AssocItemRender, Impl, RenderMode};
70 use crate::html::escape::Escape;
71 use crate::html::format::{
72     href, join_with_double_colon, print_abi_with_space, print_constness_with_space,
73     print_default_space, print_generic_bounds, print_where_clause, visibility_print_with_space,
74     Buffer, Ending, HrefError, PrintWithSpace,
75 };
76 use crate::html::highlight;
77 use crate::html::markdown::{
78     HeadingOffset, IdMap, Markdown, MarkdownItemInfo, MarkdownSummaryLine,
79 };
80 use crate::html::sources;
81 use crate::html::static_files::SCRAPE_EXAMPLES_HELP_MD;
82 use crate::scrape_examples::{CallData, CallLocation};
83 use crate::try_none;
84 use crate::DOC_RUST_LANG_ORG_CHANNEL;
85
86 /// A pair of name and its optional document.
87 pub(crate) type NameDoc = (String, Option<String>);
88
89 pub(crate) fn ensure_trailing_slash(v: &str) -> impl fmt::Display + '_ {
90     crate::html::format::display_fn(move |f| {
91         if !v.ends_with('/') && !v.is_empty() { write!(f, "{}/", v) } else { f.write_str(v) }
92     })
93 }
94
95 // Helper structs for rendering items/sidebars and carrying along contextual
96 // information
97
98 /// Struct representing one entry in the JS search index. These are all emitted
99 /// by hand to a large JS file at the end of cache-creation.
100 #[derive(Debug)]
101 pub(crate) struct IndexItem {
102     pub(crate) ty: ItemType,
103     pub(crate) name: String,
104     pub(crate) path: String,
105     pub(crate) desc: String,
106     pub(crate) parent: Option<DefId>,
107     pub(crate) parent_idx: Option<usize>,
108     pub(crate) search_type: Option<IndexItemFunctionType>,
109     pub(crate) aliases: Box<[Symbol]>,
110 }
111
112 /// A type used for the search index.
113 #[derive(Debug)]
114 pub(crate) struct RenderType {
115     id: Option<RenderTypeId>,
116     generics: Option<Vec<RenderType>>,
117 }
118
119 impl Serialize for RenderType {
120     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
121     where
122         S: Serializer,
123     {
124         let id = match &self.id {
125             // 0 is a sentinel, everything else is one-indexed
126             None => 0,
127             Some(RenderTypeId::Index(idx)) => idx + 1,
128             _ => panic!("must convert render types to indexes before serializing"),
129         };
130         if let Some(generics) = &self.generics {
131             let mut seq = serializer.serialize_seq(None)?;
132             seq.serialize_element(&id)?;
133             seq.serialize_element(generics)?;
134             seq.end()
135         } else {
136             id.serialize(serializer)
137         }
138     }
139 }
140
141 #[derive(Clone, Debug)]
142 pub(crate) enum RenderTypeId {
143     DefId(DefId),
144     Primitive(clean::PrimitiveType),
145     Index(usize),
146 }
147
148 /// Full type of functions/methods in the search index.
149 #[derive(Debug)]
150 pub(crate) struct IndexItemFunctionType {
151     inputs: Vec<RenderType>,
152     output: Vec<RenderType>,
153 }
154
155 impl Serialize for IndexItemFunctionType {
156     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
157     where
158         S: Serializer,
159     {
160         // If we couldn't figure out a type, just write `0`.
161         let has_missing = self
162             .inputs
163             .iter()
164             .chain(self.output.iter())
165             .any(|i| i.id.is_none() && i.generics.is_none());
166         if has_missing {
167             0.serialize(serializer)
168         } else {
169             let mut seq = serializer.serialize_seq(None)?;
170             match &self.inputs[..] {
171                 [one] if one.generics.is_none() => seq.serialize_element(one)?,
172                 _ => seq.serialize_element(&self.inputs)?,
173             }
174             match &self.output[..] {
175                 [] => {}
176                 [one] if one.generics.is_none() => seq.serialize_element(one)?,
177                 _ => seq.serialize_element(&self.output)?,
178             }
179             seq.end()
180         }
181     }
182 }
183
184 #[derive(Debug, Clone)]
185 pub(crate) struct StylePath {
186     /// The path to the theme
187     pub(crate) path: PathBuf,
188 }
189
190 impl StylePath {
191     pub(crate) fn basename(&self) -> Result<String, Error> {
192         Ok(try_none!(try_none!(self.path.file_stem(), &self.path).to_str(), &self.path).to_string())
193     }
194 }
195
196 #[derive(Debug, Eq, PartialEq, Hash)]
197 struct ItemEntry {
198     url: String,
199     name: String,
200 }
201
202 impl ItemEntry {
203     fn new(mut url: String, name: String) -> ItemEntry {
204         while url.starts_with('/') {
205             url.remove(0);
206         }
207         ItemEntry { url, name }
208     }
209 }
210
211 impl ItemEntry {
212     pub(crate) fn print(&self) -> impl fmt::Display + '_ {
213         crate::html::format::display_fn(move |f| {
214             write!(f, "<a href=\"{}\">{}</a>", self.url, Escape(&self.name))
215         })
216     }
217 }
218
219 impl PartialOrd for ItemEntry {
220     fn partial_cmp(&self, other: &ItemEntry) -> Option<::std::cmp::Ordering> {
221         Some(self.cmp(other))
222     }
223 }
224
225 impl Ord for ItemEntry {
226     fn cmp(&self, other: &ItemEntry) -> ::std::cmp::Ordering {
227         self.name.cmp(&other.name)
228     }
229 }
230
231 #[derive(Debug)]
232 struct AllTypes {
233     structs: FxHashSet<ItemEntry>,
234     enums: FxHashSet<ItemEntry>,
235     unions: FxHashSet<ItemEntry>,
236     primitives: FxHashSet<ItemEntry>,
237     traits: FxHashSet<ItemEntry>,
238     macros: FxHashSet<ItemEntry>,
239     functions: FxHashSet<ItemEntry>,
240     typedefs: FxHashSet<ItemEntry>,
241     opaque_tys: FxHashSet<ItemEntry>,
242     statics: FxHashSet<ItemEntry>,
243     constants: FxHashSet<ItemEntry>,
244     attribute_macros: FxHashSet<ItemEntry>,
245     derive_macros: FxHashSet<ItemEntry>,
246     trait_aliases: FxHashSet<ItemEntry>,
247 }
248
249 impl AllTypes {
250     fn new() -> AllTypes {
251         let new_set = |cap| FxHashSet::with_capacity_and_hasher(cap, Default::default());
252         AllTypes {
253             structs: new_set(100),
254             enums: new_set(100),
255             unions: new_set(100),
256             primitives: new_set(26),
257             traits: new_set(100),
258             macros: new_set(100),
259             functions: new_set(100),
260             typedefs: new_set(100),
261             opaque_tys: new_set(100),
262             statics: new_set(100),
263             constants: new_set(100),
264             attribute_macros: new_set(100),
265             derive_macros: new_set(100),
266             trait_aliases: new_set(100),
267         }
268     }
269
270     fn append(&mut self, item_name: String, item_type: &ItemType) {
271         let mut url: Vec<_> = item_name.split("::").skip(1).collect();
272         if let Some(name) = url.pop() {
273             let new_url = format!("{}/{}.{}.html", url.join("/"), item_type, name);
274             url.push(name);
275             let name = url.join("::");
276             match *item_type {
277                 ItemType::Struct => self.structs.insert(ItemEntry::new(new_url, name)),
278                 ItemType::Enum => self.enums.insert(ItemEntry::new(new_url, name)),
279                 ItemType::Union => self.unions.insert(ItemEntry::new(new_url, name)),
280                 ItemType::Primitive => self.primitives.insert(ItemEntry::new(new_url, name)),
281                 ItemType::Trait => self.traits.insert(ItemEntry::new(new_url, name)),
282                 ItemType::Macro => self.macros.insert(ItemEntry::new(new_url, name)),
283                 ItemType::Function => self.functions.insert(ItemEntry::new(new_url, name)),
284                 ItemType::Typedef => self.typedefs.insert(ItemEntry::new(new_url, name)),
285                 ItemType::OpaqueTy => self.opaque_tys.insert(ItemEntry::new(new_url, name)),
286                 ItemType::Static => self.statics.insert(ItemEntry::new(new_url, name)),
287                 ItemType::Constant => self.constants.insert(ItemEntry::new(new_url, name)),
288                 ItemType::ProcAttribute => {
289                     self.attribute_macros.insert(ItemEntry::new(new_url, name))
290                 }
291                 ItemType::ProcDerive => self.derive_macros.insert(ItemEntry::new(new_url, name)),
292                 ItemType::TraitAlias => self.trait_aliases.insert(ItemEntry::new(new_url, name)),
293                 _ => true,
294             };
295         }
296     }
297
298     fn item_sections(&self) -> FxHashSet<ItemSection> {
299         let mut sections = FxHashSet::default();
300
301         if !self.structs.is_empty() {
302             sections.insert(ItemSection::Structs);
303         }
304         if !self.enums.is_empty() {
305             sections.insert(ItemSection::Enums);
306         }
307         if !self.unions.is_empty() {
308             sections.insert(ItemSection::Unions);
309         }
310         if !self.primitives.is_empty() {
311             sections.insert(ItemSection::PrimitiveTypes);
312         }
313         if !self.traits.is_empty() {
314             sections.insert(ItemSection::Traits);
315         }
316         if !self.macros.is_empty() {
317             sections.insert(ItemSection::Macros);
318         }
319         if !self.functions.is_empty() {
320             sections.insert(ItemSection::Functions);
321         }
322         if !self.typedefs.is_empty() {
323             sections.insert(ItemSection::TypeDefinitions);
324         }
325         if !self.opaque_tys.is_empty() {
326             sections.insert(ItemSection::OpaqueTypes);
327         }
328         if !self.statics.is_empty() {
329             sections.insert(ItemSection::Statics);
330         }
331         if !self.constants.is_empty() {
332             sections.insert(ItemSection::Constants);
333         }
334         if !self.attribute_macros.is_empty() {
335             sections.insert(ItemSection::AttributeMacros);
336         }
337         if !self.derive_macros.is_empty() {
338             sections.insert(ItemSection::DeriveMacros);
339         }
340         if !self.trait_aliases.is_empty() {
341             sections.insert(ItemSection::TraitAliases);
342         }
343
344         sections
345     }
346
347     fn print(self, f: &mut Buffer) {
348         fn print_entries(f: &mut Buffer, e: &FxHashSet<ItemEntry>, kind: ItemSection) {
349             if !e.is_empty() {
350                 let mut e: Vec<&ItemEntry> = e.iter().collect();
351                 e.sort();
352                 write!(
353                     f,
354                     "<h3 id=\"{id}\">{title}</h3><ul class=\"all-items\">",
355                     id = kind.id(),
356                     title = kind.name(),
357                 );
358
359                 for s in e.iter() {
360                     write!(f, "<li>{}</li>", s.print());
361                 }
362
363                 f.write_str("</ul>");
364             }
365         }
366
367         f.write_str("<h1 class=\"fqn\">List of all items</h1>");
368         // Note: print_entries does not escape the title, because we know the current set of titles
369         // doesn't require escaping.
370         print_entries(f, &self.structs, ItemSection::Structs);
371         print_entries(f, &self.enums, ItemSection::Enums);
372         print_entries(f, &self.unions, ItemSection::Unions);
373         print_entries(f, &self.primitives, ItemSection::PrimitiveTypes);
374         print_entries(f, &self.traits, ItemSection::Traits);
375         print_entries(f, &self.macros, ItemSection::Macros);
376         print_entries(f, &self.attribute_macros, ItemSection::AttributeMacros);
377         print_entries(f, &self.derive_macros, ItemSection::DeriveMacros);
378         print_entries(f, &self.functions, ItemSection::Functions);
379         print_entries(f, &self.typedefs, ItemSection::TypeDefinitions);
380         print_entries(f, &self.trait_aliases, ItemSection::TraitAliases);
381         print_entries(f, &self.opaque_tys, ItemSection::OpaqueTypes);
382         print_entries(f, &self.statics, ItemSection::Statics);
383         print_entries(f, &self.constants, ItemSection::Constants);
384     }
385 }
386
387 fn scrape_examples_help(shared: &SharedContext<'_>) -> String {
388     let mut content = SCRAPE_EXAMPLES_HELP_MD.to_owned();
389     content.push_str(&format!(
390       "## More information\n\n\
391       If you want more information about this feature, please read the [corresponding chapter in the Rustdoc book]({}/rustdoc/scraped-examples.html).",
392       DOC_RUST_LANG_ORG_CHANNEL));
393
394     let mut ids = IdMap::default();
395     format!(
396         "<div class=\"main-heading\">\
397             <h1 class=\"fqn\">About scraped examples</h1>\
398         </div>\
399         <div>{}</div>",
400         Markdown {
401             content: &content,
402             links: &[],
403             ids: &mut ids,
404             error_codes: shared.codes,
405             edition: shared.edition(),
406             playground: &shared.playground,
407             heading_offset: HeadingOffset::H1
408         }
409         .into_string()
410     )
411 }
412
413 fn document(
414     w: &mut Buffer,
415     cx: &mut Context<'_>,
416     item: &clean::Item,
417     parent: Option<&clean::Item>,
418     heading_offset: HeadingOffset,
419 ) {
420     if let Some(ref name) = item.name {
421         info!("Documenting {}", name);
422     }
423     document_item_info(w, cx, item, parent);
424     if parent.is_none() {
425         document_full_collapsible(w, item, cx, heading_offset);
426     } else {
427         document_full(w, item, cx, heading_offset);
428     }
429 }
430
431 /// Render md_text as markdown.
432 fn render_markdown(
433     w: &mut Buffer,
434     cx: &mut Context<'_>,
435     md_text: &str,
436     links: Vec<RenderedLink>,
437     heading_offset: HeadingOffset,
438 ) {
439     write!(
440         w,
441         "<div class=\"docblock\">{}</div>",
442         Markdown {
443             content: md_text,
444             links: &links,
445             ids: &mut cx.id_map,
446             error_codes: cx.shared.codes,
447             edition: cx.shared.edition(),
448             playground: &cx.shared.playground,
449             heading_offset,
450         }
451         .into_string()
452     )
453 }
454
455 /// Writes a documentation block containing only the first paragraph of the documentation. If the
456 /// docs are longer, a "Read more" link is appended to the end.
457 fn document_short(
458     w: &mut Buffer,
459     item: &clean::Item,
460     cx: &mut Context<'_>,
461     link: AssocItemLink<'_>,
462     parent: &clean::Item,
463     show_def_docs: bool,
464 ) {
465     document_item_info(w, cx, item, Some(parent));
466     if !show_def_docs {
467         return;
468     }
469     if let Some(s) = item.doc_value() {
470         let mut summary_html = MarkdownSummaryLine(&s, &item.links(cx)).into_string();
471
472         if s.contains('\n') {
473             let link = format!(r#" <a{}>Read more</a>"#, assoc_href_attr(item, link, cx));
474
475             if let Some(idx) = summary_html.rfind("</p>") {
476                 summary_html.insert_str(idx, &link);
477             } else {
478                 summary_html.push_str(&link);
479             }
480         }
481
482         write!(w, "<div class='docblock'>{}</div>", summary_html,);
483     }
484 }
485
486 fn document_full_collapsible(
487     w: &mut Buffer,
488     item: &clean::Item,
489     cx: &mut Context<'_>,
490     heading_offset: HeadingOffset,
491 ) {
492     document_full_inner(w, item, cx, true, heading_offset);
493 }
494
495 fn document_full(
496     w: &mut Buffer,
497     item: &clean::Item,
498     cx: &mut Context<'_>,
499     heading_offset: HeadingOffset,
500 ) {
501     document_full_inner(w, item, cx, false, heading_offset);
502 }
503
504 fn document_full_inner(
505     w: &mut Buffer,
506     item: &clean::Item,
507     cx: &mut Context<'_>,
508     is_collapsible: bool,
509     heading_offset: HeadingOffset,
510 ) {
511     if let Some(s) = item.collapsed_doc_value() {
512         debug!("Doc block: =====\n{}\n=====", s);
513         if is_collapsible {
514             w.write_str(
515                 "<details class=\"rustdoc-toggle top-doc\" open>\
516                 <summary class=\"hideme\">\
517                      <span>Expand description</span>\
518                 </summary>",
519             );
520             render_markdown(w, cx, &s, item.links(cx), heading_offset);
521             w.write_str("</details>");
522         } else {
523             render_markdown(w, cx, &s, item.links(cx), heading_offset);
524         }
525     }
526
527     let kind = match &*item.kind {
528         clean::ItemKind::StrippedItem(box kind) | kind => kind,
529     };
530
531     if let clean::ItemKind::FunctionItem(..) | clean::ItemKind::MethodItem(..) = kind {
532         render_call_locations(w, cx, item);
533     }
534 }
535
536 /// Add extra information about an item such as:
537 ///
538 /// * Stability
539 /// * Deprecated
540 /// * Required features (through the `doc_cfg` feature)
541 fn document_item_info(
542     w: &mut Buffer,
543     cx: &mut Context<'_>,
544     item: &clean::Item,
545     parent: Option<&clean::Item>,
546 ) {
547     let item_infos = short_item_info(item, cx, parent);
548     if !item_infos.is_empty() {
549         w.write_str("<span class=\"item-info\">");
550         for info in item_infos {
551             w.write_str(&info);
552         }
553         w.write_str("</span>");
554     }
555 }
556
557 fn portability(item: &clean::Item, parent: Option<&clean::Item>) -> Option<String> {
558     let cfg = match (&item.cfg, parent.and_then(|p| p.cfg.as_ref())) {
559         (Some(cfg), Some(parent_cfg)) => cfg.simplify_with(parent_cfg),
560         (cfg, _) => cfg.as_deref().cloned(),
561     };
562
563     debug!(
564         "Portability {:?} {:?} (parent: {:?}) - {:?} = {:?}",
565         item.name,
566         item.cfg,
567         parent,
568         parent.and_then(|p| p.cfg.as_ref()),
569         cfg
570     );
571
572     Some(format!("<div class=\"stab portability\">{}</div>", cfg?.render_long_html()))
573 }
574
575 /// Render the stability, deprecation and portability information that is displayed at the top of
576 /// the item's documentation.
577 fn short_item_info(
578     item: &clean::Item,
579     cx: &mut Context<'_>,
580     parent: Option<&clean::Item>,
581 ) -> Vec<String> {
582     let mut extra_info = vec![];
583
584     if let Some(depr @ Deprecation { note, since, is_since_rustc_version: _, suggestion: _ }) =
585         item.deprecation(cx.tcx())
586     {
587         // We display deprecation messages for #[deprecated], but only display
588         // the future-deprecation messages for rustc versions.
589         let mut message = if let Some(since) = since {
590             let since = since.as_str();
591             if !stability::deprecation_in_effect(&depr) {
592                 if since == "TBD" {
593                     String::from("Deprecating in a future Rust version")
594                 } else {
595                     format!("Deprecating in {}", Escape(since))
596                 }
597             } else {
598                 format!("Deprecated since {}", Escape(since))
599             }
600         } else {
601             String::from("Deprecated")
602         };
603
604         if let Some(note) = note {
605             let note = note.as_str();
606             let html = MarkdownItemInfo(note, &mut cx.id_map);
607             message.push_str(&format!(": {}", html.into_string()));
608         }
609         extra_info.push(format!(
610             "<div class=\"stab deprecated\">\
611                  <span class=\"emoji\">👎</span>\
612                  <span>{}</span>\
613              </div>",
614             message,
615         ));
616     }
617
618     // Render unstable items. But don't render "rustc_private" crates (internal compiler crates).
619     // Those crates are permanently unstable so it makes no sense to render "unstable" everywhere.
620     if let Some((StabilityLevel::Unstable { reason: _, issue, .. }, feature)) = item
621         .stability(cx.tcx())
622         .as_ref()
623         .filter(|stab| stab.feature != sym::rustc_private)
624         .map(|stab| (stab.level, stab.feature))
625     {
626         let mut message = "<span class=\"emoji\">🔬</span>\
627              <span>This is a nightly-only experimental API."
628             .to_owned();
629
630         let mut feature = format!("<code>{}</code>", Escape(feature.as_str()));
631         if let (Some(url), Some(issue)) = (&cx.shared.issue_tracker_base_url, issue) {
632             feature.push_str(&format!(
633                 "&nbsp;<a href=\"{url}{issue}\">#{issue}</a>",
634                 url = url,
635                 issue = issue
636             ));
637         }
638
639         message.push_str(&format!(" ({})</span>", feature));
640
641         extra_info.push(format!("<div class=\"stab unstable\">{}</div>", message));
642     }
643
644     if let Some(portability) = portability(item, parent) {
645         extra_info.push(portability);
646     }
647
648     extra_info
649 }
650
651 // Render the list of items inside one of the sections "Trait Implementations",
652 // "Auto Trait Implementations," "Blanket Trait Implementations" (on struct/enum pages).
653 pub(crate) fn render_impls(
654     cx: &mut Context<'_>,
655     w: &mut Buffer,
656     impls: &[&Impl],
657     containing_item: &clean::Item,
658     toggle_open_by_default: bool,
659 ) {
660     let tcx = cx.tcx();
661     let mut rendered_impls = impls
662         .iter()
663         .map(|i| {
664             let did = i.trait_did().unwrap();
665             let provided_trait_methods = i.inner_impl().provided_trait_methods(tcx);
666             let assoc_link = AssocItemLink::GotoSource(did.into(), &provided_trait_methods);
667             let mut buffer = if w.is_for_html() { Buffer::html() } else { Buffer::new() };
668             render_impl(
669                 &mut buffer,
670                 cx,
671                 i,
672                 containing_item,
673                 assoc_link,
674                 RenderMode::Normal,
675                 None,
676                 &[],
677                 ImplRenderingParameters {
678                     show_def_docs: true,
679                     show_default_items: true,
680                     show_non_assoc_items: true,
681                     toggle_open_by_default,
682                 },
683             );
684             buffer.into_inner()
685         })
686         .collect::<Vec<_>>();
687     rendered_impls.sort();
688     w.write_str(&rendered_impls.join(""));
689 }
690
691 /// Build a (possibly empty) `href` attribute (a key-value pair) for the given associated item.
692 fn assoc_href_attr(it: &clean::Item, link: AssocItemLink<'_>, cx: &Context<'_>) -> String {
693     let name = it.name.unwrap();
694     let item_type = it.type_();
695
696     let href = match link {
697         AssocItemLink::Anchor(Some(ref id)) => Some(format!("#{}", id)),
698         AssocItemLink::Anchor(None) => Some(format!("#{}.{}", item_type, name)),
699         AssocItemLink::GotoSource(did, provided_methods) => {
700             // We're creating a link from the implementation of an associated item to its
701             // declaration in the trait declaration.
702             let item_type = match item_type {
703                 // For historical but not technical reasons, the item type of methods in
704                 // trait declarations depends on whether the method is required (`TyMethod`) or
705                 // provided (`Method`).
706                 ItemType::Method | ItemType::TyMethod => {
707                     if provided_methods.contains(&name) {
708                         ItemType::Method
709                     } else {
710                         ItemType::TyMethod
711                     }
712                 }
713                 // For associated types and constants, no such distinction exists.
714                 item_type => item_type,
715             };
716
717             match href(did.expect_def_id(), cx) {
718                 Ok((url, ..)) => Some(format!("{}#{}.{}", url, item_type, name)),
719                 // The link is broken since it points to an external crate that wasn't documented.
720                 // Do not create any link in such case. This is better than falling back to a
721                 // dummy anchor like `#{item_type}.{name}` representing the `id` of *this* impl item
722                 // (that used to happen in older versions). Indeed, in most cases this dummy would
723                 // coincide with the `id`. However, it would not always do so.
724                 // In general, this dummy would be incorrect:
725                 // If the type with the trait impl also had an inherent impl with an assoc. item of
726                 // the *same* name as this impl item, the dummy would link to that one even though
727                 // those two items are distinct!
728                 // In this scenario, the actual `id` of this impl item would be
729                 // `#{item_type}.{name}-{n}` for some number `n` (a disambiguator).
730                 Err(HrefError::DocumentationNotBuilt) => None,
731                 Err(_) => Some(format!("#{}.{}", item_type, name)),
732             }
733         }
734     };
735
736     // If there is no `href` for the reason explained above, simply do not render it which is valid:
737     // https://html.spec.whatwg.org/multipage/links.html#links-created-by-a-and-area-elements
738     href.map(|href| format!(" href=\"{}\"", href)).unwrap_or_default()
739 }
740
741 fn assoc_const(
742     w: &mut Buffer,
743     it: &clean::Item,
744     ty: &clean::Type,
745     default: Option<&clean::ConstantKind>,
746     link: AssocItemLink<'_>,
747     extra: &str,
748     cx: &Context<'_>,
749 ) {
750     let tcx = cx.tcx();
751     write!(
752         w,
753         "{extra}{vis}const <a{href} class=\"constant\">{name}</a>: {ty}",
754         extra = extra,
755         vis = visibility_print_with_space(it.visibility(tcx), it.item_id, cx),
756         href = assoc_href_attr(it, link, cx),
757         name = it.name.as_ref().unwrap(),
758         ty = ty.print(cx),
759     );
760     if let Some(default) = default {
761         write!(w, " = ");
762
763         // FIXME: `.value()` uses `clean::utils::format_integer_with_underscore_sep` under the
764         //        hood which adds noisy underscores and a type suffix to number literals.
765         //        This hurts readability in this context especially when more complex expressions
766         //        are involved and it doesn't add much of value.
767         //        Find a way to print constants here without all that jazz.
768         write!(w, "{}", Escape(&default.value(tcx).unwrap_or_else(|| default.expr(tcx))));
769     }
770 }
771
772 fn assoc_type(
773     w: &mut Buffer,
774     it: &clean::Item,
775     generics: &clean::Generics,
776     bounds: &[clean::GenericBound],
777     default: Option<&clean::Type>,
778     link: AssocItemLink<'_>,
779     indent: usize,
780     cx: &Context<'_>,
781 ) {
782     write!(
783         w,
784         "{indent}type <a{href} class=\"associatedtype\">{name}</a>{generics}",
785         indent = " ".repeat(indent),
786         href = assoc_href_attr(it, link, cx),
787         name = it.name.as_ref().unwrap(),
788         generics = generics.print(cx),
789     );
790     if !bounds.is_empty() {
791         write!(w, ": {}", print_generic_bounds(bounds, cx))
792     }
793     write!(w, "{}", print_where_clause(generics, cx, indent, Ending::NoNewline));
794     if let Some(default) = default {
795         write!(w, " = {}", default.print(cx))
796     }
797 }
798
799 fn assoc_method(
800     w: &mut Buffer,
801     meth: &clean::Item,
802     g: &clean::Generics,
803     d: &clean::FnDecl,
804     link: AssocItemLink<'_>,
805     parent: ItemType,
806     cx: &mut Context<'_>,
807     render_mode: RenderMode,
808 ) {
809     let tcx = cx.tcx();
810     let header = meth.fn_header(tcx).expect("Trying to get header from a non-function item");
811     let name = meth.name.as_ref().unwrap();
812     let vis = visibility_print_with_space(meth.visibility(tcx), meth.item_id, cx).to_string();
813     // FIXME: Once https://github.com/rust-lang/rust/issues/67792 is implemented, we can remove
814     // this condition.
815     let constness = match render_mode {
816         RenderMode::Normal => {
817             print_constness_with_space(&header.constness, meth.const_stability(tcx))
818         }
819         RenderMode::ForDeref { .. } => "",
820     };
821     let asyncness = header.asyncness.print_with_space();
822     let unsafety = header.unsafety.print_with_space();
823     let defaultness = print_default_space(meth.is_default());
824     let abi = print_abi_with_space(header.abi).to_string();
825     let href = assoc_href_attr(meth, link, cx);
826
827     // NOTE: `{:#}` does not print HTML formatting, `{}` does. So `g.print` can't be reused between the length calculation and `write!`.
828     let generics_len = format!("{:#}", g.print(cx)).len();
829     let mut header_len = "fn ".len()
830         + vis.len()
831         + constness.len()
832         + asyncness.len()
833         + unsafety.len()
834         + defaultness.len()
835         + abi.len()
836         + name.as_str().len()
837         + generics_len;
838
839     let notable_traits = d.output.as_return().and_then(|output| notable_traits_button(output, cx));
840
841     let (indent, indent_str, end_newline) = if parent == ItemType::Trait {
842         header_len += 4;
843         let indent_str = "    ";
844         render_attributes_in_pre(w, meth, indent_str);
845         (4, indent_str, Ending::NoNewline)
846     } else {
847         render_attributes_in_code(w, meth);
848         (0, "", Ending::Newline)
849     };
850     w.reserve(header_len + "<a href=\"\" class=\"fn\">{".len() + "</a>".len());
851     write!(
852         w,
853         "{indent}{vis}{constness}{asyncness}{unsafety}{defaultness}{abi}fn <a{href} class=\"fn\">{name}</a>\
854          {generics}{decl}{notable_traits}{where_clause}",
855         indent = indent_str,
856         vis = vis,
857         constness = constness,
858         asyncness = asyncness,
859         unsafety = unsafety,
860         defaultness = defaultness,
861         abi = abi,
862         href = href,
863         name = name,
864         generics = g.print(cx),
865         decl = d.full_print(header_len, indent, cx),
866         notable_traits = notable_traits.unwrap_or_default(),
867         where_clause = print_where_clause(g, cx, indent, end_newline),
868     );
869 }
870
871 /// Writes a span containing the versions at which an item became stable and/or const-stable. For
872 /// example, if the item became stable at 1.0.0, and const-stable at 1.45.0, this function would
873 /// write a span containing "1.0.0 (const: 1.45.0)".
874 ///
875 /// Returns `true` if a stability annotation was rendered.
876 ///
877 /// Stability and const-stability are considered separately. If the item is unstable, no version
878 /// will be written. If the item is const-unstable, "const: unstable" will be appended to the
879 /// span, with a link to the tracking issue if present. If an item's stability or const-stability
880 /// version matches the version of its enclosing item, that version will be omitted.
881 ///
882 /// Note that it is possible for an unstable function to be const-stable. In that case, the span
883 /// will include the const-stable version, but no stable version will be emitted, as a natural
884 /// consequence of the above rules.
885 fn render_stability_since_raw_with_extra(
886     w: &mut Buffer,
887     ver: Option<Symbol>,
888     const_stability: Option<ConstStability>,
889     containing_ver: Option<Symbol>,
890     containing_const_ver: Option<Symbol>,
891     extra_class: &str,
892 ) -> bool {
893     let stable_version = ver.filter(|inner| !inner.is_empty() && Some(*inner) != containing_ver);
894
895     let mut title = String::new();
896     let mut stability = String::new();
897
898     if let Some(ver) = stable_version {
899         stability.push_str(ver.as_str());
900         title.push_str(&format!("Stable since Rust version {}", ver));
901     }
902
903     let const_title_and_stability = match const_stability {
904         Some(ConstStability { level: StabilityLevel::Stable { since, .. }, .. })
905             if Some(since) != containing_const_ver =>
906         {
907             Some((format!("const since {}", since), format!("const: {}", since)))
908         }
909         Some(ConstStability { level: StabilityLevel::Unstable { issue, .. }, feature, .. }) => {
910             let unstable = if let Some(n) = issue {
911                 format!(
912                     r#"<a href="https://github.com/rust-lang/rust/issues/{}" title="Tracking issue for {}">unstable</a>"#,
913                     n, feature
914                 )
915             } else {
916                 String::from("unstable")
917             };
918
919             Some((String::from("const unstable"), format!("const: {}", unstable)))
920         }
921         _ => None,
922     };
923
924     if let Some((const_title, const_stability)) = const_title_and_stability {
925         if !title.is_empty() {
926             title.push_str(&format!(", {}", const_title));
927         } else {
928             title.push_str(&const_title);
929         }
930
931         if !stability.is_empty() {
932             stability.push_str(&format!(" ({})", const_stability));
933         } else {
934             stability.push_str(&const_stability);
935         }
936     }
937
938     if !stability.is_empty() {
939         write!(w, r#"<span class="since{extra_class}" title="{title}">{stability}</span>"#);
940     }
941
942     !stability.is_empty()
943 }
944
945 #[inline]
946 fn render_stability_since_raw(
947     w: &mut Buffer,
948     ver: Option<Symbol>,
949     const_stability: Option<ConstStability>,
950     containing_ver: Option<Symbol>,
951     containing_const_ver: Option<Symbol>,
952 ) -> bool {
953     render_stability_since_raw_with_extra(
954         w,
955         ver,
956         const_stability,
957         containing_ver,
958         containing_const_ver,
959         "",
960     )
961 }
962
963 fn render_assoc_item(
964     w: &mut Buffer,
965     item: &clean::Item,
966     link: AssocItemLink<'_>,
967     parent: ItemType,
968     cx: &mut Context<'_>,
969     render_mode: RenderMode,
970 ) {
971     match &*item.kind {
972         clean::StrippedItem(..) => {}
973         clean::TyMethodItem(m) => {
974             assoc_method(w, item, &m.generics, &m.decl, link, parent, cx, render_mode)
975         }
976         clean::MethodItem(m, _) => {
977             assoc_method(w, item, &m.generics, &m.decl, link, parent, cx, render_mode)
978         }
979         kind @ (clean::TyAssocConstItem(ty) | clean::AssocConstItem(ty, _)) => assoc_const(
980             w,
981             item,
982             ty,
983             match kind {
984                 clean::TyAssocConstItem(_) => None,
985                 clean::AssocConstItem(_, default) => Some(default),
986                 _ => unreachable!(),
987             },
988             link,
989             if parent == ItemType::Trait { "    " } else { "" },
990             cx,
991         ),
992         clean::TyAssocTypeItem(ref generics, ref bounds) => assoc_type(
993             w,
994             item,
995             generics,
996             bounds,
997             None,
998             link,
999             if parent == ItemType::Trait { 4 } else { 0 },
1000             cx,
1001         ),
1002         clean::AssocTypeItem(ref ty, ref bounds) => assoc_type(
1003             w,
1004             item,
1005             &ty.generics,
1006             bounds,
1007             Some(ty.item_type.as_ref().unwrap_or(&ty.type_)),
1008             link,
1009             if parent == ItemType::Trait { 4 } else { 0 },
1010             cx,
1011         ),
1012         _ => panic!("render_assoc_item called on non-associated-item"),
1013     }
1014 }
1015
1016 const ALLOWED_ATTRIBUTES: &[Symbol] =
1017     &[sym::export_name, sym::link_section, sym::no_mangle, sym::repr, sym::non_exhaustive];
1018
1019 fn attributes(it: &clean::Item) -> Vec<String> {
1020     it.attrs
1021         .other_attrs
1022         .iter()
1023         .filter_map(|attr| {
1024             if ALLOWED_ATTRIBUTES.contains(&attr.name_or_empty()) {
1025                 Some(
1026                     pprust::attribute_to_string(attr)
1027                         .replace("\\\n", "")
1028                         .replace('\n', "")
1029                         .replace("  ", " "),
1030                 )
1031             } else {
1032                 None
1033             }
1034         })
1035         .collect()
1036 }
1037
1038 // When an attribute is rendered inside a `<pre>` tag, it is formatted using
1039 // a whitespace prefix and newline.
1040 fn render_attributes_in_pre(w: &mut Buffer, it: &clean::Item, prefix: &str) {
1041     for a in attributes(it) {
1042         writeln!(w, "{}{}", prefix, a);
1043     }
1044 }
1045
1046 // When an attribute is rendered inside a <code> tag, it is formatted using
1047 // a div to produce a newline after it.
1048 fn render_attributes_in_code(w: &mut Buffer, it: &clean::Item) {
1049     for a in attributes(it) {
1050         write!(w, "<div class=\"code-attribute\">{}</div>", a);
1051     }
1052 }
1053
1054 #[derive(Copy, Clone)]
1055 enum AssocItemLink<'a> {
1056     Anchor(Option<&'a str>),
1057     GotoSource(ItemId, &'a FxHashSet<Symbol>),
1058 }
1059
1060 impl<'a> AssocItemLink<'a> {
1061     fn anchor(&self, id: &'a str) -> Self {
1062         match *self {
1063             AssocItemLink::Anchor(_) => AssocItemLink::Anchor(Some(id)),
1064             ref other => *other,
1065         }
1066     }
1067 }
1068
1069 fn write_impl_section_heading(w: &mut Buffer, title: &str, id: &str) {
1070     write!(
1071         w,
1072         "<h2 id=\"{id}\" class=\"small-section-header\">\
1073             {title}\
1074             <a href=\"#{id}\" class=\"anchor\">§</a>\
1075          </h2>"
1076     );
1077 }
1078
1079 pub(crate) fn render_all_impls(
1080     w: &mut Buffer,
1081     cx: &mut Context<'_>,
1082     containing_item: &clean::Item,
1083     concrete: &[&Impl],
1084     synthetic: &[&Impl],
1085     blanket_impl: &[&Impl],
1086 ) {
1087     let mut impls = Buffer::empty_from(w);
1088     render_impls(cx, &mut impls, concrete, containing_item, true);
1089     let impls = impls.into_inner();
1090     if !impls.is_empty() {
1091         write_impl_section_heading(w, "Trait Implementations", "trait-implementations");
1092         write!(w, "<div id=\"trait-implementations-list\">{}</div>", impls);
1093     }
1094
1095     if !synthetic.is_empty() {
1096         write_impl_section_heading(w, "Auto Trait Implementations", "synthetic-implementations");
1097         w.write_str("<div id=\"synthetic-implementations-list\">");
1098         render_impls(cx, w, synthetic, containing_item, false);
1099         w.write_str("</div>");
1100     }
1101
1102     if !blanket_impl.is_empty() {
1103         write_impl_section_heading(w, "Blanket Implementations", "blanket-implementations");
1104         w.write_str("<div id=\"blanket-implementations-list\">");
1105         render_impls(cx, w, blanket_impl, containing_item, false);
1106         w.write_str("</div>");
1107     }
1108 }
1109
1110 fn render_assoc_items(
1111     w: &mut Buffer,
1112     cx: &mut Context<'_>,
1113     containing_item: &clean::Item,
1114     it: DefId,
1115     what: AssocItemRender<'_>,
1116 ) {
1117     let mut derefs = FxHashSet::default();
1118     derefs.insert(it);
1119     render_assoc_items_inner(w, cx, containing_item, it, what, &mut derefs)
1120 }
1121
1122 fn render_assoc_items_inner(
1123     w: &mut Buffer,
1124     cx: &mut Context<'_>,
1125     containing_item: &clean::Item,
1126     it: DefId,
1127     what: AssocItemRender<'_>,
1128     derefs: &mut FxHashSet<DefId>,
1129 ) {
1130     info!("Documenting associated items of {:?}", containing_item.name);
1131     let shared = Rc::clone(&cx.shared);
1132     let cache = &shared.cache;
1133     let Some(v) = cache.impls.get(&it) else { return };
1134     let (non_trait, traits): (Vec<_>, _) = v.iter().partition(|i| i.inner_impl().trait_.is_none());
1135     if !non_trait.is_empty() {
1136         let mut tmp_buf = Buffer::empty_from(w);
1137         let (render_mode, id) = match what {
1138             AssocItemRender::All => {
1139                 write_impl_section_heading(&mut tmp_buf, "Implementations", "implementations");
1140                 (RenderMode::Normal, "implementations-list".to_owned())
1141             }
1142             AssocItemRender::DerefFor { trait_, type_, deref_mut_ } => {
1143                 let id =
1144                     cx.derive_id(small_url_encode(format!("deref-methods-{:#}", type_.print(cx))));
1145                 if let Some(def_id) = type_.def_id(cx.cache()) {
1146                     cx.deref_id_map.insert(def_id, id.clone());
1147                 }
1148                 write_impl_section_heading(
1149                     &mut tmp_buf,
1150                     &format!(
1151                         "<span>Methods from {trait_}&lt;Target = {type_}&gt;</span>",
1152                         trait_ = trait_.print(cx),
1153                         type_ = type_.print(cx),
1154                     ),
1155                     &id,
1156                 );
1157                 (RenderMode::ForDeref { mut_: deref_mut_ }, cx.derive_id(id))
1158             }
1159         };
1160         let mut impls_buf = Buffer::empty_from(w);
1161         for i in &non_trait {
1162             render_impl(
1163                 &mut impls_buf,
1164                 cx,
1165                 i,
1166                 containing_item,
1167                 AssocItemLink::Anchor(None),
1168                 render_mode,
1169                 None,
1170                 &[],
1171                 ImplRenderingParameters {
1172                     show_def_docs: true,
1173                     show_default_items: true,
1174                     show_non_assoc_items: true,
1175                     toggle_open_by_default: true,
1176                 },
1177             );
1178         }
1179         if !impls_buf.is_empty() {
1180             w.push_buffer(tmp_buf);
1181             write!(w, "<div id=\"{}\">", id);
1182             w.push_buffer(impls_buf);
1183             w.write_str("</div>");
1184         }
1185     }
1186
1187     if !traits.is_empty() {
1188         let deref_impl =
1189             traits.iter().find(|t| t.trait_did() == cx.tcx().lang_items().deref_trait());
1190         if let Some(impl_) = deref_impl {
1191             let has_deref_mut =
1192                 traits.iter().any(|t| t.trait_did() == cx.tcx().lang_items().deref_mut_trait());
1193             render_deref_methods(w, cx, impl_, containing_item, has_deref_mut, derefs);
1194         }
1195
1196         // If we were already one level into rendering deref methods, we don't want to render
1197         // anything after recursing into any further deref methods above.
1198         if let AssocItemRender::DerefFor { .. } = what {
1199             return;
1200         }
1201
1202         let (synthetic, concrete): (Vec<&Impl>, Vec<&Impl>) =
1203             traits.into_iter().partition(|t| t.inner_impl().kind.is_auto());
1204         let (blanket_impl, concrete): (Vec<&Impl>, _) =
1205             concrete.into_iter().partition(|t| t.inner_impl().kind.is_blanket());
1206
1207         render_all_impls(w, cx, containing_item, &concrete, &synthetic, &blanket_impl);
1208     }
1209 }
1210
1211 fn render_deref_methods(
1212     w: &mut Buffer,
1213     cx: &mut Context<'_>,
1214     impl_: &Impl,
1215     container_item: &clean::Item,
1216     deref_mut: bool,
1217     derefs: &mut FxHashSet<DefId>,
1218 ) {
1219     let cache = cx.cache();
1220     let deref_type = impl_.inner_impl().trait_.as_ref().unwrap();
1221     let (target, real_target) = impl_
1222         .inner_impl()
1223         .items
1224         .iter()
1225         .find_map(|item| match *item.kind {
1226             clean::AssocTypeItem(box ref t, _) => Some(match *t {
1227                 clean::Typedef { item_type: Some(ref type_), .. } => (type_, &t.type_),
1228                 _ => (&t.type_, &t.type_),
1229             }),
1230             _ => None,
1231         })
1232         .expect("Expected associated type binding");
1233     debug!("Render deref methods for {:#?}, target {:#?}", impl_.inner_impl().for_, target);
1234     let what =
1235         AssocItemRender::DerefFor { trait_: deref_type, type_: real_target, deref_mut_: deref_mut };
1236     if let Some(did) = target.def_id(cache) {
1237         if let Some(type_did) = impl_.inner_impl().for_.def_id(cache) {
1238             // `impl Deref<Target = S> for S`
1239             if did == type_did || !derefs.insert(did) {
1240                 // Avoid infinite cycles
1241                 return;
1242             }
1243         }
1244         render_assoc_items_inner(w, cx, container_item, did, what, derefs);
1245     } else if let Some(prim) = target.primitive_type() {
1246         if let Some(&did) = cache.primitive_locations.get(&prim) {
1247             render_assoc_items_inner(w, cx, container_item, did, what, derefs);
1248         }
1249     }
1250 }
1251
1252 fn should_render_item(item: &clean::Item, deref_mut_: bool, tcx: TyCtxt<'_>) -> bool {
1253     let self_type_opt = match *item.kind {
1254         clean::MethodItem(ref method, _) => method.decl.self_type(),
1255         clean::TyMethodItem(ref method) => method.decl.self_type(),
1256         _ => None,
1257     };
1258
1259     if let Some(self_ty) = self_type_opt {
1260         let (by_mut_ref, by_box, by_value) = match self_ty {
1261             SelfTy::SelfBorrowed(_, mutability)
1262             | SelfTy::SelfExplicit(clean::BorrowedRef { mutability, .. }) => {
1263                 (mutability == Mutability::Mut, false, false)
1264             }
1265             SelfTy::SelfExplicit(clean::Type::Path { path }) => {
1266                 (false, Some(path.def_id()) == tcx.lang_items().owned_box(), false)
1267             }
1268             SelfTy::SelfValue => (false, false, true),
1269             _ => (false, false, false),
1270         };
1271
1272         (deref_mut_ || !by_mut_ref) && !by_box && !by_value
1273     } else {
1274         false
1275     }
1276 }
1277
1278 pub(crate) fn notable_traits_button(ty: &clean::Type, cx: &mut Context<'_>) -> Option<String> {
1279     let mut has_notable_trait = false;
1280
1281     let did = ty.def_id(cx.cache())?;
1282
1283     // Box has pass-through impls for Read, Write, Iterator, and Future when the
1284     // boxed type implements one of those. We don't want to treat every Box return
1285     // as being notably an Iterator (etc), though, so we exempt it. Pin has the same
1286     // issue, with a pass-through impl for Future.
1287     if Some(did) == cx.tcx().lang_items().owned_box()
1288         || Some(did) == cx.tcx().lang_items().pin_type()
1289     {
1290         return None;
1291     }
1292
1293     if let Some(impls) = cx.cache().impls.get(&did) {
1294         for i in impls {
1295             let impl_ = i.inner_impl();
1296             if !impl_.for_.without_borrowed_ref().is_same(ty.without_borrowed_ref(), cx.cache()) {
1297                 // Two different types might have the same did,
1298                 // without actually being the same.
1299                 continue;
1300             }
1301             if let Some(trait_) = &impl_.trait_ {
1302                 let trait_did = trait_.def_id();
1303
1304                 if cx.cache().traits.get(&trait_did).map_or(false, |t| t.is_notable_trait(cx.tcx()))
1305                 {
1306                     has_notable_trait = true;
1307                 }
1308             }
1309         }
1310     }
1311
1312     if has_notable_trait {
1313         cx.types_with_notable_traits.insert(ty.clone());
1314         Some(format!(
1315             " <a href=\"#\" class=\"notable-traits\" data-ty=\"{ty}\">ⓘ</a>",
1316             ty = Escape(&format!("{:#}", ty.print(cx))),
1317         ))
1318     } else {
1319         None
1320     }
1321 }
1322
1323 fn notable_traits_decl(ty: &clean::Type, cx: &Context<'_>) -> (String, String) {
1324     let mut out = Buffer::html();
1325
1326     let did = ty.def_id(cx.cache()).expect("notable_traits_button already checked this");
1327
1328     let impls = cx.cache().impls.get(&did).expect("notable_traits_button already checked this");
1329
1330     for i in impls {
1331         let impl_ = i.inner_impl();
1332         if !impl_.for_.without_borrowed_ref().is_same(ty.without_borrowed_ref(), cx.cache()) {
1333             // Two different types might have the same did,
1334             // without actually being the same.
1335             continue;
1336         }
1337         if let Some(trait_) = &impl_.trait_ {
1338             let trait_did = trait_.def_id();
1339
1340             if cx.cache().traits.get(&trait_did).map_or(false, |t| t.is_notable_trait(cx.tcx())) {
1341                 if out.is_empty() {
1342                     write!(
1343                         &mut out,
1344                         "<h3>Notable traits for <code>{}</code></h3>\
1345                      <pre class=\"content\"><code>",
1346                         impl_.for_.print(cx)
1347                     );
1348                 }
1349
1350                 //use the "where" class here to make it small
1351                 write!(
1352                     &mut out,
1353                     "<span class=\"where fmt-newline\">{}</span>",
1354                     impl_.print(false, cx)
1355                 );
1356                 for it in &impl_.items {
1357                     if let clean::AssocTypeItem(ref tydef, ref _bounds) = *it.kind {
1358                         out.push_str("<span class=\"where fmt-newline\">    ");
1359                         let empty_set = FxHashSet::default();
1360                         let src_link = AssocItemLink::GotoSource(trait_did.into(), &empty_set);
1361                         assoc_type(
1362                             &mut out,
1363                             it,
1364                             &tydef.generics,
1365                             &[], // intentionally leaving out bounds
1366                             Some(&tydef.type_),
1367                             src_link,
1368                             0,
1369                             cx,
1370                         );
1371                         out.push_str(";</span>");
1372                     }
1373                 }
1374             }
1375         }
1376     }
1377     if out.is_empty() {
1378         write!(&mut out, "</code></pre>",);
1379     }
1380
1381     (format!("{:#}", ty.print(cx)), out.into_inner())
1382 }
1383
1384 pub(crate) fn notable_traits_json<'a>(
1385     tys: impl Iterator<Item = &'a clean::Type>,
1386     cx: &Context<'_>,
1387 ) -> String {
1388     let mut mp: Vec<(String, String)> = tys.map(|ty| notable_traits_decl(ty, cx)).collect();
1389     mp.sort_by(|(name1, _html1), (name2, _html2)| name1.cmp(name2));
1390     struct NotableTraitsMap(Vec<(String, String)>);
1391     impl Serialize for NotableTraitsMap {
1392         fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1393         where
1394             S: Serializer,
1395         {
1396             let mut map = serializer.serialize_map(Some(self.0.len()))?;
1397             for item in &self.0 {
1398                 map.serialize_entry(&item.0, &item.1)?;
1399             }
1400             map.end()
1401         }
1402     }
1403     serde_json::to_string(&NotableTraitsMap(mp))
1404         .expect("serialize (string, string) -> json object cannot fail")
1405 }
1406
1407 #[derive(Clone, Copy, Debug)]
1408 struct ImplRenderingParameters {
1409     show_def_docs: bool,
1410     show_default_items: bool,
1411     /// Whether or not to show methods.
1412     show_non_assoc_items: bool,
1413     toggle_open_by_default: bool,
1414 }
1415
1416 fn render_impl(
1417     w: &mut Buffer,
1418     cx: &mut Context<'_>,
1419     i: &Impl,
1420     parent: &clean::Item,
1421     link: AssocItemLink<'_>,
1422     render_mode: RenderMode,
1423     use_absolute: Option<bool>,
1424     aliases: &[String],
1425     rendering_params: ImplRenderingParameters,
1426 ) {
1427     let shared = Rc::clone(&cx.shared);
1428     let cache = &shared.cache;
1429     let traits = &cache.traits;
1430     let trait_ = i.trait_did().map(|did| &traits[&did]);
1431     let mut close_tags = String::new();
1432
1433     // For trait implementations, the `interesting` output contains all methods that have doc
1434     // comments, and the `boring` output contains all methods that do not. The distinction is
1435     // used to allow hiding the boring methods.
1436     // `containing_item` is used for rendering stability info. If the parent is a trait impl,
1437     // `containing_item` will the grandparent, since trait impls can't have stability attached.
1438     fn doc_impl_item(
1439         boring: &mut Buffer,
1440         interesting: &mut Buffer,
1441         cx: &mut Context<'_>,
1442         item: &clean::Item,
1443         parent: &clean::Item,
1444         containing_item: &clean::Item,
1445         link: AssocItemLink<'_>,
1446         render_mode: RenderMode,
1447         is_default_item: bool,
1448         trait_: Option<&clean::Trait>,
1449         rendering_params: ImplRenderingParameters,
1450     ) {
1451         let item_type = item.type_();
1452         let name = item.name.as_ref().unwrap();
1453
1454         let render_method_item = rendering_params.show_non_assoc_items
1455             && match render_mode {
1456                 RenderMode::Normal => true,
1457                 RenderMode::ForDeref { mut_: deref_mut_ } => {
1458                     should_render_item(item, deref_mut_, cx.tcx())
1459                 }
1460             };
1461
1462         let in_trait_class = if trait_.is_some() { " trait-impl" } else { "" };
1463
1464         let mut doc_buffer = Buffer::empty_from(boring);
1465         let mut info_buffer = Buffer::empty_from(boring);
1466         let mut short_documented = true;
1467
1468         if render_method_item {
1469             if !is_default_item {
1470                 if let Some(t) = trait_ {
1471                     // The trait item may have been stripped so we might not
1472                     // find any documentation or stability for it.
1473                     if let Some(it) = t.items.iter().find(|i| i.name == item.name) {
1474                         // We need the stability of the item from the trait
1475                         // because impls can't have a stability.
1476                         if item.doc_value().is_some() {
1477                             document_item_info(&mut info_buffer, cx, it, Some(parent));
1478                             document_full(&mut doc_buffer, item, cx, HeadingOffset::H5);
1479                             short_documented = false;
1480                         } else {
1481                             // In case the item isn't documented,
1482                             // provide short documentation from the trait.
1483                             document_short(
1484                                 &mut doc_buffer,
1485                                 it,
1486                                 cx,
1487                                 link,
1488                                 parent,
1489                                 rendering_params.show_def_docs,
1490                             );
1491                         }
1492                     }
1493                 } else {
1494                     document_item_info(&mut info_buffer, cx, item, Some(parent));
1495                     if rendering_params.show_def_docs {
1496                         document_full(&mut doc_buffer, item, cx, HeadingOffset::H5);
1497                         short_documented = false;
1498                     }
1499                 }
1500             } else {
1501                 document_short(
1502                     &mut doc_buffer,
1503                     item,
1504                     cx,
1505                     link,
1506                     parent,
1507                     rendering_params.show_def_docs,
1508                 );
1509             }
1510         }
1511         let w = if short_documented && trait_.is_some() { interesting } else { boring };
1512
1513         let toggled = !doc_buffer.is_empty();
1514         if toggled {
1515             let method_toggle_class = if item_type.is_method() { " method-toggle" } else { "" };
1516             write!(w, "<details class=\"rustdoc-toggle{}\" open><summary>", method_toggle_class);
1517         }
1518         match &*item.kind {
1519             clean::MethodItem(..) | clean::TyMethodItem(_) => {
1520                 // Only render when the method is not static or we allow static methods
1521                 if render_method_item {
1522                     let id = cx.derive_id(format!("{}.{}", item_type, name));
1523                     let source_id = trait_
1524                         .and_then(|trait_| {
1525                             trait_.items.iter().find(|item| {
1526                                 item.name.map(|n| n.as_str().eq(name.as_str())).unwrap_or(false)
1527                             })
1528                         })
1529                         .map(|item| format!("{}.{}", item.type_(), name));
1530                     write!(
1531                         w,
1532                         "<section id=\"{}\" class=\"{}{} has-srclink\">",
1533                         id, item_type, in_trait_class,
1534                     );
1535                     render_rightside(w, cx, item, containing_item, render_mode);
1536                     if trait_.is_some() {
1537                         // Anchors are only used on trait impls.
1538                         write!(w, "<a href=\"#{}\" class=\"anchor\">§</a>", id);
1539                     }
1540                     w.write_str("<h4 class=\"code-header\">");
1541                     render_assoc_item(
1542                         w,
1543                         item,
1544                         link.anchor(source_id.as_ref().unwrap_or(&id)),
1545                         ItemType::Impl,
1546                         cx,
1547                         render_mode,
1548                     );
1549                     w.write_str("</h4>");
1550                     w.write_str("</section>");
1551                 }
1552             }
1553             kind @ (clean::TyAssocConstItem(ty) | clean::AssocConstItem(ty, _)) => {
1554                 let source_id = format!("{}.{}", item_type, name);
1555                 let id = cx.derive_id(source_id.clone());
1556                 write!(
1557                     w,
1558                     "<section id=\"{}\" class=\"{}{} has-srclink\">",
1559                     id, item_type, in_trait_class
1560                 );
1561                 render_rightside(w, cx, item, containing_item, render_mode);
1562                 if trait_.is_some() {
1563                     // Anchors are only used on trait impls.
1564                     write!(w, "<a href=\"#{}\" class=\"anchor\">§</a>", id);
1565                 }
1566                 w.write_str("<h4 class=\"code-header\">");
1567                 assoc_const(
1568                     w,
1569                     item,
1570                     ty,
1571                     match kind {
1572                         clean::TyAssocConstItem(_) => None,
1573                         clean::AssocConstItem(_, default) => Some(default),
1574                         _ => unreachable!(),
1575                     },
1576                     link.anchor(if trait_.is_some() { &source_id } else { &id }),
1577                     "",
1578                     cx,
1579                 );
1580                 w.write_str("</h4>");
1581                 w.write_str("</section>");
1582             }
1583             clean::TyAssocTypeItem(generics, bounds) => {
1584                 let source_id = format!("{}.{}", item_type, name);
1585                 let id = cx.derive_id(source_id.clone());
1586                 write!(w, "<section id=\"{}\" class=\"{}{}\">", id, item_type, in_trait_class);
1587                 if trait_.is_some() {
1588                     // Anchors are only used on trait impls.
1589                     write!(w, "<a href=\"#{}\" class=\"anchor\">§</a>", id);
1590                 }
1591                 w.write_str("<h4 class=\"code-header\">");
1592                 assoc_type(
1593                     w,
1594                     item,
1595                     generics,
1596                     bounds,
1597                     None,
1598                     link.anchor(if trait_.is_some() { &source_id } else { &id }),
1599                     0,
1600                     cx,
1601                 );
1602                 w.write_str("</h4>");
1603                 w.write_str("</section>");
1604             }
1605             clean::AssocTypeItem(tydef, _bounds) => {
1606                 let source_id = format!("{}.{}", item_type, name);
1607                 let id = cx.derive_id(source_id.clone());
1608                 write!(
1609                     w,
1610                     "<section id=\"{}\" class=\"{}{} has-srclink\">",
1611                     id, item_type, in_trait_class
1612                 );
1613                 if trait_.is_some() {
1614                     // Anchors are only used on trait impls.
1615                     write!(w, "<a href=\"#{}\" class=\"anchor\">§</a>", id);
1616                 }
1617                 w.write_str("<h4 class=\"code-header\">");
1618                 assoc_type(
1619                     w,
1620                     item,
1621                     &tydef.generics,
1622                     &[], // intentionally leaving out bounds
1623                     Some(tydef.item_type.as_ref().unwrap_or(&tydef.type_)),
1624                     link.anchor(if trait_.is_some() { &source_id } else { &id }),
1625                     0,
1626                     cx,
1627                 );
1628                 w.write_str("</h4>");
1629                 w.write_str("</section>");
1630             }
1631             clean::StrippedItem(..) => return,
1632             _ => panic!("can't make docs for trait item with name {:?}", item.name),
1633         }
1634
1635         w.push_buffer(info_buffer);
1636         if toggled {
1637             w.write_str("</summary>");
1638             w.push_buffer(doc_buffer);
1639             w.push_str("</details>");
1640         }
1641     }
1642
1643     let mut impl_items = Buffer::empty_from(w);
1644     let mut default_impl_items = Buffer::empty_from(w);
1645
1646     for trait_item in &i.inner_impl().items {
1647         doc_impl_item(
1648             &mut default_impl_items,
1649             &mut impl_items,
1650             cx,
1651             trait_item,
1652             if trait_.is_some() { &i.impl_item } else { parent },
1653             parent,
1654             link,
1655             render_mode,
1656             false,
1657             trait_,
1658             rendering_params,
1659         );
1660     }
1661
1662     fn render_default_items(
1663         boring: &mut Buffer,
1664         interesting: &mut Buffer,
1665         cx: &mut Context<'_>,
1666         t: &clean::Trait,
1667         i: &clean::Impl,
1668         parent: &clean::Item,
1669         containing_item: &clean::Item,
1670         render_mode: RenderMode,
1671         rendering_params: ImplRenderingParameters,
1672     ) {
1673         for trait_item in &t.items {
1674             // Skip over any default trait items that are impossible to call
1675             // (e.g. if it has a `Self: Sized` bound on an unsized type).
1676             if let Some(impl_def_id) = parent.item_id.as_def_id()
1677                 && let Some(trait_item_def_id) = trait_item.item_id.as_def_id()
1678                 && cx.tcx().is_impossible_method((impl_def_id, trait_item_def_id))
1679             {
1680                 continue;
1681             }
1682
1683             let n = trait_item.name;
1684             if i.items.iter().any(|m| m.name == n) {
1685                 continue;
1686             }
1687             let did = i.trait_.as_ref().unwrap().def_id();
1688             let provided_methods = i.provided_trait_methods(cx.tcx());
1689             let assoc_link = AssocItemLink::GotoSource(did.into(), &provided_methods);
1690
1691             doc_impl_item(
1692                 boring,
1693                 interesting,
1694                 cx,
1695                 trait_item,
1696                 parent,
1697                 containing_item,
1698                 assoc_link,
1699                 render_mode,
1700                 true,
1701                 Some(t),
1702                 rendering_params,
1703             );
1704         }
1705     }
1706
1707     // If we've implemented a trait, then also emit documentation for all
1708     // default items which weren't overridden in the implementation block.
1709     // We don't emit documentation for default items if they appear in the
1710     // Implementations on Foreign Types or Implementors sections.
1711     if rendering_params.show_default_items {
1712         if let Some(t) = trait_ {
1713             render_default_items(
1714                 &mut default_impl_items,
1715                 &mut impl_items,
1716                 cx,
1717                 t,
1718                 i.inner_impl(),
1719                 &i.impl_item,
1720                 parent,
1721                 render_mode,
1722                 rendering_params,
1723             );
1724         }
1725     }
1726     if render_mode == RenderMode::Normal {
1727         let toggled = !(impl_items.is_empty() && default_impl_items.is_empty());
1728         if toggled {
1729             close_tags.insert_str(0, "</details>");
1730             write!(
1731                 w,
1732                 "<details class=\"rustdoc-toggle implementors-toggle\"{}>",
1733                 if rendering_params.toggle_open_by_default { " open" } else { "" }
1734             );
1735             write!(w, "<summary>")
1736         }
1737         render_impl_summary(
1738             w,
1739             cx,
1740             i,
1741             parent,
1742             parent,
1743             rendering_params.show_def_docs,
1744             use_absolute,
1745             aliases,
1746         );
1747         if toggled {
1748             write!(w, "</summary>")
1749         }
1750
1751         if let Some(ref dox) = i.impl_item.collapsed_doc_value() {
1752             if trait_.is_none() && i.inner_impl().items.is_empty() {
1753                 w.write_str(
1754                     "<div class=\"item-info\">\
1755                     <div class=\"stab empty-impl\">This impl block contains no items.</div>
1756                 </div>",
1757                 );
1758             }
1759             write!(
1760                 w,
1761                 "<div class=\"docblock\">{}</div>",
1762                 Markdown {
1763                     content: &*dox,
1764                     links: &i.impl_item.links(cx),
1765                     ids: &mut cx.id_map,
1766                     error_codes: cx.shared.codes,
1767                     edition: cx.shared.edition(),
1768                     playground: &cx.shared.playground,
1769                     heading_offset: HeadingOffset::H4
1770                 }
1771                 .into_string()
1772             );
1773         }
1774     }
1775     if !default_impl_items.is_empty() || !impl_items.is_empty() {
1776         w.write_str("<div class=\"impl-items\">");
1777         w.push_buffer(default_impl_items);
1778         w.push_buffer(impl_items);
1779         close_tags.insert_str(0, "</div>");
1780     }
1781     w.write_str(&close_tags);
1782 }
1783
1784 // Render the items that appear on the right side of methods, impls, and
1785 // associated types. For example "1.0.0 (const: 1.39.0) Â· source".
1786 fn render_rightside(
1787     w: &mut Buffer,
1788     cx: &Context<'_>,
1789     item: &clean::Item,
1790     containing_item: &clean::Item,
1791     render_mode: RenderMode,
1792 ) {
1793     let tcx = cx.tcx();
1794
1795     // FIXME: Once https://github.com/rust-lang/rust/issues/67792 is implemented, we can remove
1796     // this condition.
1797     let (const_stability, const_stable_since) = match render_mode {
1798         RenderMode::Normal => (item.const_stability(tcx), containing_item.const_stable_since(tcx)),
1799         RenderMode::ForDeref { .. } => (None, None),
1800     };
1801     let src_href = cx.src_href(item);
1802     let has_src_ref = src_href.is_some();
1803
1804     let mut rightside = Buffer::new();
1805     let has_stability = render_stability_since_raw_with_extra(
1806         &mut rightside,
1807         item.stable_since(tcx),
1808         const_stability,
1809         containing_item.stable_since(tcx),
1810         const_stable_since,
1811         if has_src_ref { "" } else { " rightside" },
1812     );
1813     if let Some(l) = src_href {
1814         if has_stability {
1815             write!(rightside, " Â· <a class=\"srclink\" href=\"{}\">source</a>", l)
1816         } else {
1817             write!(rightside, "<a class=\"srclink rightside\" href=\"{}\">source</a>", l)
1818         }
1819     }
1820     if has_stability && has_src_ref {
1821         write!(w, "<span class=\"rightside\">{}</span>", rightside.into_inner());
1822     } else {
1823         w.push_buffer(rightside);
1824     }
1825 }
1826
1827 pub(crate) fn render_impl_summary(
1828     w: &mut Buffer,
1829     cx: &mut Context<'_>,
1830     i: &Impl,
1831     parent: &clean::Item,
1832     containing_item: &clean::Item,
1833     show_def_docs: bool,
1834     use_absolute: Option<bool>,
1835     // This argument is used to reference same type with different paths to avoid duplication
1836     // in documentation pages for trait with automatic implementations like "Send" and "Sync".
1837     aliases: &[String],
1838 ) {
1839     let inner_impl = i.inner_impl();
1840     let id = cx.derive_id(get_id_for_impl(&inner_impl.for_, inner_impl.trait_.as_ref(), cx));
1841     let aliases = if aliases.is_empty() {
1842         String::new()
1843     } else {
1844         format!(" data-aliases=\"{}\"", aliases.join(","))
1845     };
1846     write!(w, "<section id=\"{}\" class=\"impl has-srclink\"{}>", id, aliases);
1847     render_rightside(w, cx, &i.impl_item, containing_item, RenderMode::Normal);
1848     write!(w, "<a href=\"#{}\" class=\"anchor\">§</a>", id);
1849     write!(w, "<h3 class=\"code-header\">");
1850
1851     if let Some(use_absolute) = use_absolute {
1852         write!(w, "{}", inner_impl.print(use_absolute, cx));
1853         if show_def_docs {
1854             for it in &inner_impl.items {
1855                 if let clean::AssocTypeItem(ref tydef, ref _bounds) = *it.kind {
1856                     w.write_str("<span class=\"where fmt-newline\">  ");
1857                     assoc_type(
1858                         w,
1859                         it,
1860                         &tydef.generics,
1861                         &[], // intentionally leaving out bounds
1862                         Some(&tydef.type_),
1863                         AssocItemLink::Anchor(None),
1864                         0,
1865                         cx,
1866                     );
1867                     w.write_str(";</span>");
1868                 }
1869             }
1870         }
1871     } else {
1872         write!(w, "{}", inner_impl.print(false, cx));
1873     }
1874     write!(w, "</h3>");
1875
1876     let is_trait = inner_impl.trait_.is_some();
1877     if is_trait {
1878         if let Some(portability) = portability(&i.impl_item, Some(parent)) {
1879             write!(w, "<span class=\"item-info\">{}</span>", portability);
1880         }
1881     }
1882
1883     w.write_str("</section>");
1884 }
1885
1886 fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buffer) {
1887     if it.is_struct()
1888         || it.is_trait()
1889         || it.is_primitive()
1890         || it.is_union()
1891         || it.is_enum()
1892         || it.is_mod()
1893         || it.is_typedef()
1894     {
1895         write!(
1896             buffer,
1897             "<h2 class=\"location\"><a href=\"#\">{}{}</a></h2>",
1898             match *it.kind {
1899                 clean::ModuleItem(..) =>
1900                     if it.is_crate() {
1901                         "Crate "
1902                     } else {
1903                         "Module "
1904                     },
1905                 _ => "",
1906             },
1907             it.name.as_ref().unwrap()
1908         );
1909     }
1910
1911     buffer.write_str("<div class=\"sidebar-elems\">");
1912     if it.is_crate() {
1913         write!(buffer, "<ul class=\"block\">");
1914         if let Some(ref version) = cx.cache().crate_version {
1915             write!(buffer, "<li class=\"version\">Version {}</li>", Escape(version));
1916         }
1917         write!(buffer, "<li><a id=\"all-types\" href=\"all.html\">All Items</a></li>");
1918         buffer.write_str("</ul>");
1919     }
1920
1921     match *it.kind {
1922         clean::StructItem(ref s) => sidebar_struct(cx, buffer, it, s),
1923         clean::TraitItem(ref t) => sidebar_trait(cx, buffer, it, t),
1924         clean::PrimitiveItem(_) => sidebar_primitive(cx, buffer, it),
1925         clean::UnionItem(ref u) => sidebar_union(cx, buffer, it, u),
1926         clean::EnumItem(ref e) => sidebar_enum(cx, buffer, it, e),
1927         clean::TypedefItem(_) => sidebar_typedef(cx, buffer, it),
1928         clean::ModuleItem(ref m) => sidebar_module(buffer, &m.items),
1929         clean::ForeignTypeItem => sidebar_foreign_type(cx, buffer, it),
1930         _ => {}
1931     }
1932
1933     // The sidebar is designed to display sibling functions, modules and
1934     // other miscellaneous information. since there are lots of sibling
1935     // items (and that causes quadratic growth in large modules),
1936     // we refactor common parts into a shared JavaScript file per module.
1937     // still, we don't move everything into JS because we want to preserve
1938     // as much HTML as possible in order to allow non-JS-enabled browsers
1939     // to navigate the documentation (though slightly inefficiently).
1940
1941     if !it.is_mod() {
1942         let path: String = cx.current.iter().map(|s| s.as_str()).intersperse("::").collect();
1943
1944         write!(buffer, "<h2><a href=\"index.html\">In {}</a></h2>", path);
1945     }
1946
1947     // Closes sidebar-elems div.
1948     buffer.write_str("</div>");
1949 }
1950
1951 fn get_next_url(used_links: &mut FxHashSet<String>, url: String) -> String {
1952     if used_links.insert(url.clone()) {
1953         return url;
1954     }
1955     let mut add = 1;
1956     while !used_links.insert(format!("{}-{}", url, add)) {
1957         add += 1;
1958     }
1959     format!("{}-{}", url, add)
1960 }
1961
1962 struct SidebarLink {
1963     name: Symbol,
1964     url: String,
1965 }
1966
1967 impl fmt::Display for SidebarLink {
1968     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1969         write!(f, "<a href=\"#{}\">{}</a>", self.url, self.name)
1970     }
1971 }
1972
1973 impl PartialEq for SidebarLink {
1974     fn eq(&self, other: &Self) -> bool {
1975         self.url == other.url
1976     }
1977 }
1978
1979 impl Eq for SidebarLink {}
1980
1981 impl PartialOrd for SidebarLink {
1982     fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
1983         Some(self.cmp(other))
1984     }
1985 }
1986
1987 impl Ord for SidebarLink {
1988     fn cmp(&self, other: &Self) -> std::cmp::Ordering {
1989         self.url.cmp(&other.url)
1990     }
1991 }
1992
1993 fn get_methods(
1994     i: &clean::Impl,
1995     for_deref: bool,
1996     used_links: &mut FxHashSet<String>,
1997     deref_mut: bool,
1998     tcx: TyCtxt<'_>,
1999 ) -> Vec<SidebarLink> {
2000     i.items
2001         .iter()
2002         .filter_map(|item| match item.name {
2003             Some(name) if !name.is_empty() && item.is_method() => {
2004                 if !for_deref || should_render_item(item, deref_mut, tcx) {
2005                     Some(SidebarLink {
2006                         name,
2007                         url: get_next_url(used_links, format!("{}.{}", ItemType::Method, name)),
2008                     })
2009                 } else {
2010                     None
2011                 }
2012             }
2013             _ => None,
2014         })
2015         .collect::<Vec<_>>()
2016 }
2017
2018 fn get_associated_constants(
2019     i: &clean::Impl,
2020     used_links: &mut FxHashSet<String>,
2021 ) -> Vec<SidebarLink> {
2022     i.items
2023         .iter()
2024         .filter_map(|item| match item.name {
2025             Some(name) if !name.is_empty() && item.is_associated_const() => Some(SidebarLink {
2026                 name,
2027                 url: get_next_url(used_links, format!("{}.{}", ItemType::AssocConst, name)),
2028             }),
2029             _ => None,
2030         })
2031         .collect::<Vec<_>>()
2032 }
2033
2034 // The point is to url encode any potential character from a type with genericity.
2035 fn small_url_encode(s: String) -> String {
2036     let mut st = String::new();
2037     let mut last_match = 0;
2038     for (idx, c) in s.char_indices() {
2039         let escaped = match c {
2040             '<' => "%3C",
2041             '>' => "%3E",
2042             ' ' => "%20",
2043             '?' => "%3F",
2044             '\'' => "%27",
2045             '&' => "%26",
2046             ',' => "%2C",
2047             ':' => "%3A",
2048             ';' => "%3B",
2049             '[' => "%5B",
2050             ']' => "%5D",
2051             '"' => "%22",
2052             _ => continue,
2053         };
2054
2055         st += &s[last_match..idx];
2056         st += escaped;
2057         // NOTE: we only expect single byte characters here - which is fine as long as we
2058         // only match single byte characters
2059         last_match = idx + 1;
2060     }
2061
2062     if last_match != 0 {
2063         st += &s[last_match..];
2064         st
2065     } else {
2066         s
2067     }
2068 }
2069
2070 pub(crate) fn sidebar_render_assoc_items(
2071     cx: &Context<'_>,
2072     out: &mut Buffer,
2073     id_map: &mut IdMap,
2074     concrete: Vec<&Impl>,
2075     synthetic: Vec<&Impl>,
2076     blanket_impl: Vec<&Impl>,
2077 ) {
2078     let format_impls = |impls: Vec<&Impl>, id_map: &mut IdMap| {
2079         let mut links = FxHashSet::default();
2080
2081         let mut ret = impls
2082             .iter()
2083             .filter_map(|it| {
2084                 let trait_ = it.inner_impl().trait_.as_ref()?;
2085                 let encoded =
2086                     id_map.derive(get_id_for_impl(&it.inner_impl().for_, Some(trait_), cx));
2087
2088                 let i_display = format!("{:#}", trait_.print(cx));
2089                 let out = Escape(&i_display);
2090                 let prefix = match it.inner_impl().polarity {
2091                     ty::ImplPolarity::Positive | ty::ImplPolarity::Reservation => "",
2092                     ty::ImplPolarity::Negative => "!",
2093                 };
2094                 let generated = format!("<a href=\"#{}\">{}{}</a>", encoded, prefix, out);
2095                 if links.insert(generated.clone()) { Some(generated) } else { None }
2096             })
2097             .collect::<Vec<String>>();
2098         ret.sort();
2099         ret
2100     };
2101
2102     let concrete_format = format_impls(concrete, id_map);
2103     let synthetic_format = format_impls(synthetic, id_map);
2104     let blanket_format = format_impls(blanket_impl, id_map);
2105
2106     if !concrete_format.is_empty() {
2107         print_sidebar_block(
2108             out,
2109             "trait-implementations",
2110             "Trait Implementations",
2111             concrete_format.iter(),
2112         );
2113     }
2114
2115     if !synthetic_format.is_empty() {
2116         print_sidebar_block(
2117             out,
2118             "synthetic-implementations",
2119             "Auto Trait Implementations",
2120             synthetic_format.iter(),
2121         );
2122     }
2123
2124     if !blanket_format.is_empty() {
2125         print_sidebar_block(
2126             out,
2127             "blanket-implementations",
2128             "Blanket Implementations",
2129             blanket_format.iter(),
2130         );
2131     }
2132 }
2133
2134 fn sidebar_assoc_items(cx: &Context<'_>, out: &mut Buffer, it: &clean::Item) {
2135     let did = it.item_id.expect_def_id();
2136     let cache = cx.cache();
2137
2138     if let Some(v) = cache.impls.get(&did) {
2139         let mut used_links = FxHashSet::default();
2140         let mut id_map = IdMap::new();
2141
2142         {
2143             let used_links_bor = &mut used_links;
2144             let mut assoc_consts = v
2145                 .iter()
2146                 .filter(|i| i.inner_impl().trait_.is_none())
2147                 .flat_map(|i| get_associated_constants(i.inner_impl(), used_links_bor))
2148                 .collect::<Vec<_>>();
2149             if !assoc_consts.is_empty() {
2150                 // We want links' order to be reproducible so we don't use unstable sort.
2151                 assoc_consts.sort();
2152
2153                 print_sidebar_block(
2154                     out,
2155                     "implementations",
2156                     "Associated Constants",
2157                     assoc_consts.iter(),
2158                 );
2159             }
2160             let mut methods = v
2161                 .iter()
2162                 .filter(|i| i.inner_impl().trait_.is_none())
2163                 .flat_map(|i| get_methods(i.inner_impl(), false, used_links_bor, false, cx.tcx()))
2164                 .collect::<Vec<_>>();
2165             if !methods.is_empty() {
2166                 // We want links' order to be reproducible so we don't use unstable sort.
2167                 methods.sort();
2168
2169                 print_sidebar_block(out, "implementations", "Methods", methods.iter());
2170             }
2171         }
2172
2173         if v.iter().any(|i| i.inner_impl().trait_.is_some()) {
2174             if let Some(impl_) =
2175                 v.iter().find(|i| i.trait_did() == cx.tcx().lang_items().deref_trait())
2176             {
2177                 let mut derefs = FxHashSet::default();
2178                 derefs.insert(did);
2179                 sidebar_deref_methods(cx, out, impl_, v, &mut derefs, &mut used_links);
2180             }
2181
2182             let (synthetic, concrete): (Vec<&Impl>, Vec<&Impl>) =
2183                 v.iter().partition::<Vec<_>, _>(|i| i.inner_impl().kind.is_auto());
2184             let (blanket_impl, concrete): (Vec<&Impl>, Vec<&Impl>) =
2185                 concrete.into_iter().partition::<Vec<_>, _>(|i| i.inner_impl().kind.is_blanket());
2186
2187             sidebar_render_assoc_items(cx, out, &mut id_map, concrete, synthetic, blanket_impl);
2188         }
2189     }
2190 }
2191
2192 fn sidebar_deref_methods(
2193     cx: &Context<'_>,
2194     out: &mut Buffer,
2195     impl_: &Impl,
2196     v: &[Impl],
2197     derefs: &mut FxHashSet<DefId>,
2198     used_links: &mut FxHashSet<String>,
2199 ) {
2200     let c = cx.cache();
2201
2202     debug!("found Deref: {:?}", impl_);
2203     if let Some((target, real_target)) =
2204         impl_.inner_impl().items.iter().find_map(|item| match *item.kind {
2205             clean::AssocTypeItem(box ref t, _) => Some(match *t {
2206                 clean::Typedef { item_type: Some(ref type_), .. } => (type_, &t.type_),
2207                 _ => (&t.type_, &t.type_),
2208             }),
2209             _ => None,
2210         })
2211     {
2212         debug!("found target, real_target: {:?} {:?}", target, real_target);
2213         if let Some(did) = target.def_id(c) {
2214             if let Some(type_did) = impl_.inner_impl().for_.def_id(c) {
2215                 // `impl Deref<Target = S> for S`
2216                 if did == type_did || !derefs.insert(did) {
2217                     // Avoid infinite cycles
2218                     return;
2219                 }
2220             }
2221         }
2222         let deref_mut = v.iter().any(|i| i.trait_did() == cx.tcx().lang_items().deref_mut_trait());
2223         let inner_impl = target
2224             .def_id(c)
2225             .or_else(|| {
2226                 target.primitive_type().and_then(|prim| c.primitive_locations.get(&prim).cloned())
2227             })
2228             .and_then(|did| c.impls.get(&did));
2229         if let Some(impls) = inner_impl {
2230             debug!("found inner_impl: {:?}", impls);
2231             let mut ret = impls
2232                 .iter()
2233                 .filter(|i| i.inner_impl().trait_.is_none())
2234                 .flat_map(|i| get_methods(i.inner_impl(), true, used_links, deref_mut, cx.tcx()))
2235                 .collect::<Vec<_>>();
2236             if !ret.is_empty() {
2237                 let id = if let Some(target_def_id) = real_target.def_id(c) {
2238                     cx.deref_id_map.get(&target_def_id).expect("Deref section without derived id")
2239                 } else {
2240                     "deref-methods"
2241                 };
2242                 let title = format!(
2243                     "Methods from {}&lt;Target={}&gt;",
2244                     Escape(&format!("{:#}", impl_.inner_impl().trait_.as_ref().unwrap().print(cx))),
2245                     Escape(&format!("{:#}", real_target.print(cx))),
2246                 );
2247                 // We want links' order to be reproducible so we don't use unstable sort.
2248                 ret.sort();
2249                 print_sidebar_block(out, id, &title, ret.iter());
2250             }
2251         }
2252
2253         // Recurse into any further impls that might exist for `target`
2254         if let Some(target_did) = target.def_id(c) {
2255             if let Some(target_impls) = c.impls.get(&target_did) {
2256                 if let Some(target_deref_impl) = target_impls.iter().find(|i| {
2257                     i.inner_impl()
2258                         .trait_
2259                         .as_ref()
2260                         .map(|t| Some(t.def_id()) == cx.tcx().lang_items().deref_trait())
2261                         .unwrap_or(false)
2262                 }) {
2263                     sidebar_deref_methods(
2264                         cx,
2265                         out,
2266                         target_deref_impl,
2267                         target_impls,
2268                         derefs,
2269                         used_links,
2270                     );
2271                 }
2272             }
2273         }
2274     }
2275 }
2276
2277 fn sidebar_struct(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, s: &clean::Struct) {
2278     let mut sidebar = Buffer::new();
2279     let fields = get_struct_fields_name(&s.fields);
2280
2281     if !fields.is_empty() {
2282         match s.ctor_kind {
2283             None => {
2284                 print_sidebar_block(&mut sidebar, "fields", "Fields", fields.iter());
2285             }
2286             Some(CtorKind::Fn) => print_sidebar_title(&mut sidebar, "fields", "Tuple Fields"),
2287             Some(CtorKind::Const) => {}
2288         }
2289     }
2290
2291     sidebar_assoc_items(cx, &mut sidebar, it);
2292
2293     if !sidebar.is_empty() {
2294         write!(buf, "<section>{}</section>", sidebar.into_inner());
2295     }
2296 }
2297
2298 fn get_id_for_impl(for_: &clean::Type, trait_: Option<&clean::Path>, cx: &Context<'_>) -> String {
2299     match trait_ {
2300         Some(t) => small_url_encode(format!("impl-{:#}-for-{:#}", t.print(cx), for_.print(cx))),
2301         None => small_url_encode(format!("impl-{:#}", for_.print(cx))),
2302     }
2303 }
2304
2305 fn extract_for_impl_name(item: &clean::Item, cx: &Context<'_>) -> Option<(String, String)> {
2306     match *item.kind {
2307         clean::ItemKind::ImplItem(ref i) => {
2308             i.trait_.as_ref().map(|trait_| {
2309                 // Alternative format produces no URLs,
2310                 // so this parameter does nothing.
2311                 (format!("{:#}", i.for_.print(cx)), get_id_for_impl(&i.for_, Some(trait_), cx))
2312             })
2313         }
2314         _ => None,
2315     }
2316 }
2317
2318 fn print_sidebar_title(buf: &mut Buffer, id: &str, title: &str) {
2319     write!(buf, "<h3><a href=\"#{}\">{}</a></h3>", id, title);
2320 }
2321
2322 fn print_sidebar_block(
2323     buf: &mut Buffer,
2324     id: &str,
2325     title: &str,
2326     items: impl Iterator<Item = impl fmt::Display>,
2327 ) {
2328     print_sidebar_title(buf, id, title);
2329     buf.push_str("<ul class=\"block\">");
2330     for item in items {
2331         write!(buf, "<li>{}</li>", item);
2332     }
2333     buf.push_str("</ul>");
2334 }
2335
2336 fn sidebar_trait(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, t: &clean::Trait) {
2337     buf.write_str("<section>");
2338
2339     fn print_sidebar_section(
2340         out: &mut Buffer,
2341         items: &[clean::Item],
2342         id: &str,
2343         title: &str,
2344         filter: impl Fn(&clean::Item) -> bool,
2345         mapper: impl Fn(&str) -> String,
2346     ) {
2347         let mut items: Vec<&str> = items
2348             .iter()
2349             .filter_map(|m| match m.name {
2350                 Some(ref name) if filter(m) => Some(name.as_str()),
2351                 _ => None,
2352             })
2353             .collect::<Vec<_>>();
2354
2355         if !items.is_empty() {
2356             items.sort_unstable();
2357             print_sidebar_block(out, id, title, items.into_iter().map(mapper));
2358         }
2359     }
2360
2361     print_sidebar_section(
2362         buf,
2363         &t.items,
2364         "required-associated-types",
2365         "Required Associated Types",
2366         |m| m.is_ty_associated_type(),
2367         |sym| format!("<a href=\"#{1}.{0}\">{0}</a>", sym, ItemType::AssocType),
2368     );
2369
2370     print_sidebar_section(
2371         buf,
2372         &t.items,
2373         "provided-associated-types",
2374         "Provided Associated Types",
2375         |m| m.is_associated_type(),
2376         |sym| format!("<a href=\"#{1}.{0}\">{0}</a>", sym, ItemType::AssocType),
2377     );
2378
2379     print_sidebar_section(
2380         buf,
2381         &t.items,
2382         "required-associated-consts",
2383         "Required Associated Constants",
2384         |m| m.is_ty_associated_const(),
2385         |sym| format!("<a href=\"#{1}.{0}\">{0}</a>", sym, ItemType::AssocConst),
2386     );
2387
2388     print_sidebar_section(
2389         buf,
2390         &t.items,
2391         "provided-associated-consts",
2392         "Provided Associated Constants",
2393         |m| m.is_associated_const(),
2394         |sym| format!("<a href=\"#{1}.{0}\">{0}</a>", sym, ItemType::AssocConst),
2395     );
2396
2397     print_sidebar_section(
2398         buf,
2399         &t.items,
2400         "required-methods",
2401         "Required Methods",
2402         |m| m.is_ty_method(),
2403         |sym| format!("<a href=\"#{1}.{0}\">{0}</a>", sym, ItemType::TyMethod),
2404     );
2405
2406     print_sidebar_section(
2407         buf,
2408         &t.items,
2409         "provided-methods",
2410         "Provided Methods",
2411         |m| m.is_method(),
2412         |sym| format!("<a href=\"#{1}.{0}\">{0}</a>", sym, ItemType::Method),
2413     );
2414
2415     if let Some(implementors) = cx.cache().implementors.get(&it.item_id.expect_def_id()) {
2416         let mut res = implementors
2417             .iter()
2418             .filter(|i| !i.is_on_local_type(cx))
2419             .filter_map(|i| extract_for_impl_name(&i.impl_item, cx))
2420             .collect::<Vec<_>>();
2421
2422         if !res.is_empty() {
2423             res.sort();
2424             print_sidebar_block(
2425                 buf,
2426                 "foreign-impls",
2427                 "Implementations on Foreign Types",
2428                 res.iter().map(|(name, id)| format!("<a href=\"#{}\">{}</a>", id, Escape(name))),
2429             );
2430         }
2431     }
2432
2433     sidebar_assoc_items(cx, buf, it);
2434
2435     print_sidebar_title(buf, "implementors", "Implementors");
2436     if t.is_auto(cx.tcx()) {
2437         print_sidebar_title(buf, "synthetic-implementors", "Auto Implementors");
2438     }
2439
2440     buf.push_str("</section>")
2441 }
2442
2443 /// Returns the list of implementations for the primitive reference type, filtering out any
2444 /// implementations that are on concrete or partially generic types, only keeping implementations
2445 /// of the form `impl<T> Trait for &T`.
2446 pub(crate) fn get_filtered_impls_for_reference<'a>(
2447     shared: &'a Rc<SharedContext<'_>>,
2448     it: &clean::Item,
2449 ) -> (Vec<&'a Impl>, Vec<&'a Impl>, Vec<&'a Impl>) {
2450     let def_id = it.item_id.expect_def_id();
2451     // If the reference primitive is somehow not defined, exit early.
2452     let Some(v) = shared.cache.impls.get(&def_id) else { return (Vec::new(), Vec::new(), Vec::new()) };
2453     // Since there is no "direct implementation" on the reference primitive type, we filter out
2454     // every implementation which isn't a trait implementation.
2455     let traits = v.iter().filter(|i| i.inner_impl().trait_.is_some());
2456     let (synthetic, concrete): (Vec<&Impl>, Vec<&Impl>) =
2457         traits.partition(|t| t.inner_impl().kind.is_auto());
2458
2459     let (blanket_impl, concrete): (Vec<&Impl>, _) =
2460         concrete.into_iter().partition(|t| t.inner_impl().kind.is_blanket());
2461     // Now we keep only references over full generic types.
2462     let concrete: Vec<_> = concrete
2463         .into_iter()
2464         .filter(|t| match t.inner_impl().for_ {
2465             clean::Type::BorrowedRef { ref type_, .. } => type_.is_full_generic(),
2466             _ => false,
2467         })
2468         .collect();
2469
2470     (concrete, synthetic, blanket_impl)
2471 }
2472
2473 fn sidebar_primitive(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item) {
2474     let mut sidebar = Buffer::new();
2475
2476     if it.name.map(|n| n.as_str() != "reference").unwrap_or(false) {
2477         sidebar_assoc_items(cx, &mut sidebar, it);
2478     } else {
2479         let shared = Rc::clone(&cx.shared);
2480         let (concrete, synthetic, blanket_impl) = get_filtered_impls_for_reference(&shared, it);
2481
2482         sidebar_render_assoc_items(
2483             cx,
2484             &mut sidebar,
2485             &mut IdMap::new(),
2486             concrete,
2487             synthetic,
2488             blanket_impl,
2489         );
2490     }
2491
2492     if !sidebar.is_empty() {
2493         write!(buf, "<section>{}</section>", sidebar.into_inner());
2494     }
2495 }
2496
2497 fn sidebar_typedef(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item) {
2498     let mut sidebar = Buffer::new();
2499     sidebar_assoc_items(cx, &mut sidebar, it);
2500
2501     if !sidebar.is_empty() {
2502         write!(buf, "<section>{}</section>", sidebar.into_inner());
2503     }
2504 }
2505
2506 fn get_struct_fields_name(fields: &[clean::Item]) -> Vec<String> {
2507     let mut fields = fields
2508         .iter()
2509         .filter(|f| matches!(*f.kind, clean::StructFieldItem(..)))
2510         .filter_map(|f| {
2511             f.name.map(|name| format!("<a href=\"#structfield.{name}\">{name}</a>", name = name))
2512         })
2513         .collect::<Vec<_>>();
2514     fields.sort();
2515     fields
2516 }
2517
2518 fn sidebar_union(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, u: &clean::Union) {
2519     let mut sidebar = Buffer::new();
2520     let fields = get_struct_fields_name(&u.fields);
2521
2522     if !fields.is_empty() {
2523         print_sidebar_block(&mut sidebar, "fields", "Fields", fields.iter());
2524     }
2525
2526     sidebar_assoc_items(cx, &mut sidebar, it);
2527
2528     if !sidebar.is_empty() {
2529         write!(buf, "<section>{}</section>", sidebar.into_inner());
2530     }
2531 }
2532
2533 fn sidebar_enum(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, e: &clean::Enum) {
2534     let mut sidebar = Buffer::new();
2535
2536     let mut variants = e
2537         .variants()
2538         .filter_map(|v| {
2539             v.name
2540                 .as_ref()
2541                 .map(|name| format!("<a href=\"#variant.{name}\">{name}</a>", name = name))
2542         })
2543         .collect::<Vec<_>>();
2544     if !variants.is_empty() {
2545         variants.sort_unstable();
2546         print_sidebar_block(&mut sidebar, "variants", "Variants", variants.iter());
2547     }
2548
2549     sidebar_assoc_items(cx, &mut sidebar, it);
2550
2551     if !sidebar.is_empty() {
2552         write!(buf, "<section>{}</section>", sidebar.into_inner());
2553     }
2554 }
2555
2556 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
2557 pub(crate) enum ItemSection {
2558     Reexports,
2559     PrimitiveTypes,
2560     Modules,
2561     Macros,
2562     Structs,
2563     Enums,
2564     Constants,
2565     Statics,
2566     Traits,
2567     Functions,
2568     TypeDefinitions,
2569     Unions,
2570     Implementations,
2571     TypeMethods,
2572     Methods,
2573     StructFields,
2574     Variants,
2575     AssociatedTypes,
2576     AssociatedConstants,
2577     ForeignTypes,
2578     Keywords,
2579     OpaqueTypes,
2580     AttributeMacros,
2581     DeriveMacros,
2582     TraitAliases,
2583 }
2584
2585 impl ItemSection {
2586     const ALL: &'static [Self] = {
2587         use ItemSection::*;
2588         // NOTE: The order here affects the order in the UI.
2589         &[
2590             Reexports,
2591             PrimitiveTypes,
2592             Modules,
2593             Macros,
2594             Structs,
2595             Enums,
2596             Constants,
2597             Statics,
2598             Traits,
2599             Functions,
2600             TypeDefinitions,
2601             Unions,
2602             Implementations,
2603             TypeMethods,
2604             Methods,
2605             StructFields,
2606             Variants,
2607             AssociatedTypes,
2608             AssociatedConstants,
2609             ForeignTypes,
2610             Keywords,
2611             OpaqueTypes,
2612             AttributeMacros,
2613             DeriveMacros,
2614             TraitAliases,
2615         ]
2616     };
2617
2618     fn id(self) -> &'static str {
2619         match self {
2620             Self::Reexports => "reexports",
2621             Self::Modules => "modules",
2622             Self::Structs => "structs",
2623             Self::Unions => "unions",
2624             Self::Enums => "enums",
2625             Self::Functions => "functions",
2626             Self::TypeDefinitions => "types",
2627             Self::Statics => "statics",
2628             Self::Constants => "constants",
2629             Self::Traits => "traits",
2630             Self::Implementations => "impls",
2631             Self::TypeMethods => "tymethods",
2632             Self::Methods => "methods",
2633             Self::StructFields => "fields",
2634             Self::Variants => "variants",
2635             Self::Macros => "macros",
2636             Self::PrimitiveTypes => "primitives",
2637             Self::AssociatedTypes => "associated-types",
2638             Self::AssociatedConstants => "associated-consts",
2639             Self::ForeignTypes => "foreign-types",
2640             Self::Keywords => "keywords",
2641             Self::OpaqueTypes => "opaque-types",
2642             Self::AttributeMacros => "attributes",
2643             Self::DeriveMacros => "derives",
2644             Self::TraitAliases => "trait-aliases",
2645         }
2646     }
2647
2648     fn name(self) -> &'static str {
2649         match self {
2650             Self::Reexports => "Re-exports",
2651             Self::Modules => "Modules",
2652             Self::Structs => "Structs",
2653             Self::Unions => "Unions",
2654             Self::Enums => "Enums",
2655             Self::Functions => "Functions",
2656             Self::TypeDefinitions => "Type Definitions",
2657             Self::Statics => "Statics",
2658             Self::Constants => "Constants",
2659             Self::Traits => "Traits",
2660             Self::Implementations => "Implementations",
2661             Self::TypeMethods => "Type Methods",
2662             Self::Methods => "Methods",
2663             Self::StructFields => "Struct Fields",
2664             Self::Variants => "Variants",
2665             Self::Macros => "Macros",
2666             Self::PrimitiveTypes => "Primitive Types",
2667             Self::AssociatedTypes => "Associated Types",
2668             Self::AssociatedConstants => "Associated Constants",
2669             Self::ForeignTypes => "Foreign Types",
2670             Self::Keywords => "Keywords",
2671             Self::OpaqueTypes => "Opaque Types",
2672             Self::AttributeMacros => "Attribute Macros",
2673             Self::DeriveMacros => "Derive Macros",
2674             Self::TraitAliases => "Trait Aliases",
2675         }
2676     }
2677 }
2678
2679 fn item_ty_to_section(ty: ItemType) -> ItemSection {
2680     match ty {
2681         ItemType::ExternCrate | ItemType::Import => ItemSection::Reexports,
2682         ItemType::Module => ItemSection::Modules,
2683         ItemType::Struct => ItemSection::Structs,
2684         ItemType::Union => ItemSection::Unions,
2685         ItemType::Enum => ItemSection::Enums,
2686         ItemType::Function => ItemSection::Functions,
2687         ItemType::Typedef => ItemSection::TypeDefinitions,
2688         ItemType::Static => ItemSection::Statics,
2689         ItemType::Constant => ItemSection::Constants,
2690         ItemType::Trait => ItemSection::Traits,
2691         ItemType::Impl => ItemSection::Implementations,
2692         ItemType::TyMethod => ItemSection::TypeMethods,
2693         ItemType::Method => ItemSection::Methods,
2694         ItemType::StructField => ItemSection::StructFields,
2695         ItemType::Variant => ItemSection::Variants,
2696         ItemType::Macro => ItemSection::Macros,
2697         ItemType::Primitive => ItemSection::PrimitiveTypes,
2698         ItemType::AssocType => ItemSection::AssociatedTypes,
2699         ItemType::AssocConst => ItemSection::AssociatedConstants,
2700         ItemType::ForeignType => ItemSection::ForeignTypes,
2701         ItemType::Keyword => ItemSection::Keywords,
2702         ItemType::OpaqueTy => ItemSection::OpaqueTypes,
2703         ItemType::ProcAttribute => ItemSection::AttributeMacros,
2704         ItemType::ProcDerive => ItemSection::DeriveMacros,
2705         ItemType::TraitAlias => ItemSection::TraitAliases,
2706     }
2707 }
2708
2709 pub(crate) fn sidebar_module_like(buf: &mut Buffer, item_sections_in_use: FxHashSet<ItemSection>) {
2710     use std::fmt::Write as _;
2711
2712     let mut sidebar = String::new();
2713
2714     for &sec in ItemSection::ALL.iter().filter(|sec| item_sections_in_use.contains(sec)) {
2715         let _ = write!(sidebar, "<li><a href=\"#{}\">{}</a></li>", sec.id(), sec.name());
2716     }
2717
2718     if !sidebar.is_empty() {
2719         write!(
2720             buf,
2721             "<section>\
2722                  <ul class=\"block\">{}</ul>\
2723              </section>",
2724             sidebar
2725         );
2726     }
2727 }
2728
2729 fn sidebar_module(buf: &mut Buffer, items: &[clean::Item]) {
2730     let item_sections_in_use: FxHashSet<_> = items
2731         .iter()
2732         .filter(|it| {
2733             !it.is_stripped()
2734                 && it
2735                     .name
2736                     .or_else(|| {
2737                         if let clean::ImportItem(ref i) = *it.kind &&
2738                             let clean::ImportKind::Simple(s) = i.kind { Some(s) } else { None }
2739                     })
2740                     .is_some()
2741         })
2742         .map(|it| item_ty_to_section(it.type_()))
2743         .collect();
2744
2745     sidebar_module_like(buf, item_sections_in_use);
2746 }
2747
2748 fn sidebar_foreign_type(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item) {
2749     let mut sidebar = Buffer::new();
2750     sidebar_assoc_items(cx, &mut sidebar, it);
2751
2752     if !sidebar.is_empty() {
2753         write!(buf, "<section>{}</section>", sidebar.into_inner());
2754     }
2755 }
2756
2757 pub(crate) const BASIC_KEYWORDS: &str = "rust, rustlang, rust-lang";
2758
2759 /// Returns a list of all paths used in the type.
2760 /// This is used to help deduplicate imported impls
2761 /// for reexported types. If any of the contained
2762 /// types are re-exported, we don't use the corresponding
2763 /// entry from the js file, as inlining will have already
2764 /// picked up the impl
2765 fn collect_paths_for_type(first_ty: clean::Type, cache: &Cache) -> Vec<String> {
2766     let mut out = Vec::new();
2767     let mut visited = FxHashSet::default();
2768     let mut work = VecDeque::new();
2769
2770     let mut process_path = |did: DefId| {
2771         let get_extern = || cache.external_paths.get(&did).map(|s| s.0.clone());
2772         let fqp = cache.exact_paths.get(&did).cloned().or_else(get_extern);
2773
2774         if let Some(path) = fqp {
2775             out.push(join_with_double_colon(&path));
2776         }
2777     };
2778
2779     work.push_back(first_ty);
2780
2781     while let Some(ty) = work.pop_front() {
2782         if !visited.insert(ty.clone()) {
2783             continue;
2784         }
2785
2786         match ty {
2787             clean::Type::Path { path } => process_path(path.def_id()),
2788             clean::Type::Tuple(tys) => {
2789                 work.extend(tys.into_iter());
2790             }
2791             clean::Type::Slice(ty) => {
2792                 work.push_back(*ty);
2793             }
2794             clean::Type::Array(ty, _) => {
2795                 work.push_back(*ty);
2796             }
2797             clean::Type::RawPointer(_, ty) => {
2798                 work.push_back(*ty);
2799             }
2800             clean::Type::BorrowedRef { type_, .. } => {
2801                 work.push_back(*type_);
2802             }
2803             clean::Type::QPath(box clean::QPathData { self_type, trait_, .. }) => {
2804                 work.push_back(self_type);
2805                 process_path(trait_.def_id());
2806             }
2807             _ => {}
2808         }
2809     }
2810     out
2811 }
2812
2813 const MAX_FULL_EXAMPLES: usize = 5;
2814 const NUM_VISIBLE_LINES: usize = 10;
2815
2816 /// Generates the HTML for example call locations generated via the --scrape-examples flag.
2817 fn render_call_locations(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item) {
2818     let tcx = cx.tcx();
2819     let def_id = item.item_id.expect_def_id();
2820     let key = tcx.def_path_hash(def_id);
2821     let Some(call_locations) = cx.shared.call_locations.get(&key) else { return };
2822
2823     // Generate a unique ID so users can link to this section for a given method
2824     let id = cx.id_map.derive("scraped-examples");
2825     write!(
2826         w,
2827         "<div class=\"docblock scraped-example-list\">\
2828           <span></span>\
2829           <h5 id=\"{id}\">\
2830              <a href=\"#{id}\">Examples found in repository</a>\
2831              <a class=\"scrape-help\" href=\"{root_path}scrape-examples-help.html\">?</a>\
2832           </h5>",
2833         root_path = cx.root_path(),
2834         id = id
2835     );
2836
2837     // Create a URL to a particular location in a reverse-dependency's source file
2838     let link_to_loc = |call_data: &CallData, loc: &CallLocation| -> (String, String) {
2839         let (line_lo, line_hi) = loc.call_expr.line_span;
2840         let (anchor, title) = if line_lo == line_hi {
2841             ((line_lo + 1).to_string(), format!("line {}", line_lo + 1))
2842         } else {
2843             (
2844                 format!("{}-{}", line_lo + 1, line_hi + 1),
2845                 format!("lines {}-{}", line_lo + 1, line_hi + 1),
2846             )
2847         };
2848         let url = format!("{}{}#{}", cx.root_path(), call_data.url, anchor);
2849         (url, title)
2850     };
2851
2852     // Generate the HTML for a single example, being the title and code block
2853     let write_example = |w: &mut Buffer, (path, call_data): (&PathBuf, &CallData)| -> bool {
2854         let contents = match fs::read_to_string(&path) {
2855             Ok(contents) => contents,
2856             Err(err) => {
2857                 let span = item.span(tcx).map_or(rustc_span::DUMMY_SP, |span| span.inner());
2858                 tcx.sess
2859                     .span_err(span, &format!("failed to read file {}: {}", path.display(), err));
2860                 return false;
2861             }
2862         };
2863
2864         // To reduce file sizes, we only want to embed the source code needed to understand the example, not
2865         // the entire file. So we find the smallest byte range that covers all items enclosing examples.
2866         assert!(!call_data.locations.is_empty());
2867         let min_loc =
2868             call_data.locations.iter().min_by_key(|loc| loc.enclosing_item.byte_span.0).unwrap();
2869         let byte_min = min_loc.enclosing_item.byte_span.0;
2870         let line_min = min_loc.enclosing_item.line_span.0;
2871         let max_loc =
2872             call_data.locations.iter().max_by_key(|loc| loc.enclosing_item.byte_span.1).unwrap();
2873         let byte_max = max_loc.enclosing_item.byte_span.1;
2874         let line_max = max_loc.enclosing_item.line_span.1;
2875
2876         // The output code is limited to that byte range.
2877         let contents_subset = &contents[(byte_min as usize)..(byte_max as usize)];
2878
2879         // The call locations need to be updated to reflect that the size of the program has changed.
2880         // Specifically, the ranges are all subtracted by `byte_min` since that's the new zero point.
2881         let (mut byte_ranges, line_ranges): (Vec<_>, Vec<_>) = call_data
2882             .locations
2883             .iter()
2884             .map(|loc| {
2885                 let (byte_lo, byte_hi) = loc.call_ident.byte_span;
2886                 let (line_lo, line_hi) = loc.call_expr.line_span;
2887                 let byte_range = (byte_lo - byte_min, byte_hi - byte_min);
2888
2889                 let line_range = (line_lo - line_min, line_hi - line_min);
2890                 let (line_url, line_title) = link_to_loc(call_data, loc);
2891
2892                 (byte_range, (line_range, line_url, line_title))
2893             })
2894             .unzip();
2895
2896         let (_, init_url, init_title) = &line_ranges[0];
2897         let needs_expansion = line_max - line_min > NUM_VISIBLE_LINES;
2898         let locations_encoded = serde_json::to_string(&line_ranges).unwrap();
2899
2900         write!(
2901             w,
2902             "<div class=\"scraped-example {expanded_cls}\" data-locs=\"{locations}\">\
2903                 <div class=\"scraped-example-title\">\
2904                    {name} (<a href=\"{url}\">{title}</a>)\
2905                 </div>\
2906                 <div class=\"code-wrapper\">",
2907             expanded_cls = if needs_expansion { "" } else { "expanded" },
2908             name = call_data.display_name,
2909             url = init_url,
2910             title = init_title,
2911             // The locations are encoded as a data attribute, so they can be read
2912             // later by the JS for interactions.
2913             locations = Escape(&locations_encoded)
2914         );
2915
2916         if line_ranges.len() > 1 {
2917             write!(w, r#"<button class="prev">&pr;</button> <button class="next">&sc;</button>"#);
2918         }
2919
2920         // Look for the example file in the source map if it exists, otherwise return a dummy span
2921         let file_span = (|| {
2922             let source_map = tcx.sess.source_map();
2923             let crate_src = tcx.sess.local_crate_source_file.as_ref()?;
2924             let abs_crate_src = crate_src.canonicalize().ok()?;
2925             let crate_root = abs_crate_src.parent()?.parent()?;
2926             let rel_path = path.strip_prefix(crate_root).ok()?;
2927             let files = source_map.files();
2928             let file = files.iter().find(|file| match &file.name {
2929                 FileName::Real(RealFileName::LocalPath(other_path)) => rel_path == other_path,
2930                 _ => false,
2931             })?;
2932             Some(rustc_span::Span::with_root_ctxt(
2933                 file.start_pos + BytePos(byte_min),
2934                 file.start_pos + BytePos(byte_max),
2935             ))
2936         })()
2937         .unwrap_or(rustc_span::DUMMY_SP);
2938
2939         let mut decoration_info = FxHashMap::default();
2940         decoration_info.insert("highlight focus", vec![byte_ranges.remove(0)]);
2941         decoration_info.insert("highlight", byte_ranges);
2942
2943         sources::print_src(
2944             w,
2945             contents_subset,
2946             file_span,
2947             cx,
2948             &cx.root_path(),
2949             highlight::DecorationInfo(decoration_info),
2950             sources::SourceContext::Embedded { offset: line_min, needs_expansion },
2951         );
2952         write!(w, "</div></div>");
2953
2954         true
2955     };
2956
2957     // The call locations are output in sequence, so that sequence needs to be determined.
2958     // Ideally the most "relevant" examples would be shown first, but there's no general algorithm
2959     // for determining relevance. We instead proxy relevance with the following heuristics:
2960     //   1. Code written to be an example is better than code not written to be an example, e.g.
2961     //      a snippet from examples/foo.rs is better than src/lib.rs. We don't know the Cargo
2962     //      directory structure in Rustdoc, so we proxy this by prioritizing code that comes from
2963     //      a --crate-type bin.
2964     //   2. Smaller examples are better than large examples. So we prioritize snippets that have
2965     //      the smallest number of lines in their enclosing item.
2966     //   3. Finally we sort by the displayed file name, which is arbitrary but prevents the
2967     //      ordering of examples from randomly changing between Rustdoc invocations.
2968     let ordered_locations = {
2969         fn sort_criterion<'a>(
2970             (_, call_data): &(&PathBuf, &'a CallData),
2971         ) -> (bool, u32, &'a String) {
2972             // Use the first location because that's what the user will see initially
2973             let (lo, hi) = call_data.locations[0].enclosing_item.byte_span;
2974             (!call_data.is_bin, hi - lo, &call_data.display_name)
2975         }
2976
2977         let mut locs = call_locations.iter().collect::<Vec<_>>();
2978         locs.sort_by_key(sort_criterion);
2979         locs
2980     };
2981
2982     let mut it = ordered_locations.into_iter().peekable();
2983
2984     // An example may fail to write if its source can't be read for some reason, so this method
2985     // continues iterating until a write succeeds
2986     let write_and_skip_failure = |w: &mut Buffer, it: &mut Peekable<_>| {
2987         while let Some(example) = it.next() {
2988             if write_example(&mut *w, example) {
2989                 break;
2990             }
2991         }
2992     };
2993
2994     // Write just one example that's visible by default in the method's description.
2995     write_and_skip_failure(w, &mut it);
2996
2997     // Then add the remaining examples in a hidden section.
2998     if it.peek().is_some() {
2999         write!(
3000             w,
3001             "<details class=\"rustdoc-toggle more-examples-toggle\">\
3002                   <summary class=\"hideme\">\
3003                      <span>More examples</span>\
3004                   </summary>\
3005                   <div class=\"hide-more\">Hide additional examples</div>\
3006                   <div class=\"more-scraped-examples\">\
3007                     <div class=\"toggle-line\"><div class=\"toggle-line-inner\"></div></div>\
3008                     <div class=\"more-scraped-examples-inner\">"
3009         );
3010
3011         // Only generate inline code for MAX_FULL_EXAMPLES number of examples. Otherwise we could
3012         // make the page arbitrarily huge!
3013         for _ in 0..MAX_FULL_EXAMPLES {
3014             write_and_skip_failure(w, &mut it);
3015         }
3016
3017         // For the remaining examples, generate a <ul> containing links to the source files.
3018         if it.peek().is_some() {
3019             write!(w, r#"<div class="example-links">Additional examples can be found in:<br><ul>"#);
3020             it.for_each(|(_, call_data)| {
3021                 let (url, _) = link_to_loc(call_data, &call_data.locations[0]);
3022                 write!(
3023                     w,
3024                     r#"<li><a href="{url}">{name}</a></li>"#,
3025                     url = url,
3026                     name = call_data.display_name
3027                 );
3028             });
3029             write!(w, "</ul></div>");
3030         }
3031
3032         write!(w, "</div></div></details>");
3033     }
3034
3035     write!(w, "</div>");
3036 }