]> git.lizzy.rs Git - rust.git/blob - src/librustdoc/html/render/mod.rs
Auto merge of #103779 - the8472:simd-str-contains, r=thomcc
[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=\"fnname\">{".len() + "</a>".len());
851     write!(
852         w,
853         "{indent}{vis}{constness}{asyncness}{unsafety}{defaultness}{abi}fn <a{href} class=\"fnname\">{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 =
1516                 if item_type == ItemType::Method { " method-toggle" } else { "" };
1517             write!(w, "<details class=\"rustdoc-toggle{}\" open><summary>", method_toggle_class);
1518         }
1519         match &*item.kind {
1520             clean::MethodItem(..) | clean::TyMethodItem(_) => {
1521                 // Only render when the method is not static or we allow static methods
1522                 if render_method_item {
1523                     let id = cx.derive_id(format!("{}.{}", item_type, name));
1524                     let source_id = trait_
1525                         .and_then(|trait_| {
1526                             trait_.items.iter().find(|item| {
1527                                 item.name.map(|n| n.as_str().eq(name.as_str())).unwrap_or(false)
1528                             })
1529                         })
1530                         .map(|item| format!("{}.{}", item.type_(), name));
1531                     write!(
1532                         w,
1533                         "<section id=\"{}\" class=\"{}{} has-srclink\">",
1534                         id, item_type, in_trait_class,
1535                     );
1536                     render_rightside(w, cx, item, containing_item, render_mode);
1537                     if trait_.is_some() {
1538                         // Anchors are only used on trait impls.
1539                         write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
1540                     }
1541                     w.write_str("<h4 class=\"code-header\">");
1542                     render_assoc_item(
1543                         w,
1544                         item,
1545                         link.anchor(source_id.as_ref().unwrap_or(&id)),
1546                         ItemType::Impl,
1547                         cx,
1548                         render_mode,
1549                     );
1550                     w.write_str("</h4>");
1551                     w.write_str("</section>");
1552                 }
1553             }
1554             kind @ (clean::TyAssocConstItem(ty) | clean::AssocConstItem(ty, _)) => {
1555                 let source_id = format!("{}.{}", item_type, name);
1556                 let id = cx.derive_id(source_id.clone());
1557                 write!(
1558                     w,
1559                     "<section id=\"{}\" class=\"{}{} has-srclink\">",
1560                     id, item_type, in_trait_class
1561                 );
1562                 render_rightside(w, cx, item, containing_item, render_mode);
1563                 if trait_.is_some() {
1564                     // Anchors are only used on trait impls.
1565                     write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
1566                 }
1567                 w.write_str("<h4 class=\"code-header\">");
1568                 assoc_const(
1569                     w,
1570                     item,
1571                     ty,
1572                     match kind {
1573                         clean::TyAssocConstItem(_) => None,
1574                         clean::AssocConstItem(_, default) => Some(default),
1575                         _ => unreachable!(),
1576                     },
1577                     link.anchor(if trait_.is_some() { &source_id } else { &id }),
1578                     "",
1579                     cx,
1580                 );
1581                 w.write_str("</h4>");
1582                 w.write_str("</section>");
1583             }
1584             clean::TyAssocTypeItem(generics, bounds) => {
1585                 let source_id = format!("{}.{}", item_type, name);
1586                 let id = cx.derive_id(source_id.clone());
1587                 write!(w, "<section id=\"{}\" class=\"{}{}\">", id, item_type, in_trait_class);
1588                 if trait_.is_some() {
1589                     // Anchors are only used on trait impls.
1590                     write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
1591                 }
1592                 w.write_str("<h4 class=\"code-header\">");
1593                 assoc_type(
1594                     w,
1595                     item,
1596                     generics,
1597                     bounds,
1598                     None,
1599                     link.anchor(if trait_.is_some() { &source_id } else { &id }),
1600                     0,
1601                     cx,
1602                 );
1603                 w.write_str("</h4>");
1604                 w.write_str("</section>");
1605             }
1606             clean::AssocTypeItem(tydef, _bounds) => {
1607                 let source_id = format!("{}.{}", item_type, name);
1608                 let id = cx.derive_id(source_id.clone());
1609                 write!(
1610                     w,
1611                     "<section id=\"{}\" class=\"{}{} has-srclink\">",
1612                     id, item_type, in_trait_class
1613                 );
1614                 if trait_.is_some() {
1615                     // Anchors are only used on trait impls.
1616                     write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
1617                 }
1618                 w.write_str("<h4 class=\"code-header\">");
1619                 assoc_type(
1620                     w,
1621                     item,
1622                     &tydef.generics,
1623                     &[], // intentionally leaving out bounds
1624                     Some(tydef.item_type.as_ref().unwrap_or(&tydef.type_)),
1625                     link.anchor(if trait_.is_some() { &source_id } else { &id }),
1626                     0,
1627                     cx,
1628                 );
1629                 w.write_str("</h4>");
1630                 w.write_str("</section>");
1631             }
1632             clean::StrippedItem(..) => return,
1633             _ => panic!("can't make docs for trait item with name {:?}", item.name),
1634         }
1635
1636         w.push_buffer(info_buffer);
1637         if toggled {
1638             w.write_str("</summary>");
1639             w.push_buffer(doc_buffer);
1640             w.push_str("</details>");
1641         }
1642     }
1643
1644     let mut impl_items = Buffer::empty_from(w);
1645     let mut default_impl_items = Buffer::empty_from(w);
1646
1647     for trait_item in &i.inner_impl().items {
1648         doc_impl_item(
1649             &mut default_impl_items,
1650             &mut impl_items,
1651             cx,
1652             trait_item,
1653             if trait_.is_some() { &i.impl_item } else { parent },
1654             parent,
1655             link,
1656             render_mode,
1657             false,
1658             trait_,
1659             rendering_params,
1660         );
1661     }
1662
1663     fn render_default_items(
1664         boring: &mut Buffer,
1665         interesting: &mut Buffer,
1666         cx: &mut Context<'_>,
1667         t: &clean::Trait,
1668         i: &clean::Impl,
1669         parent: &clean::Item,
1670         containing_item: &clean::Item,
1671         render_mode: RenderMode,
1672         rendering_params: ImplRenderingParameters,
1673     ) {
1674         for trait_item in &t.items {
1675             // Skip over any default trait items that are impossible to call
1676             // (e.g. if it has a `Self: Sized` bound on an unsized type).
1677             if let Some(impl_def_id) = parent.item_id.as_def_id()
1678                 && let Some(trait_item_def_id) = trait_item.item_id.as_def_id()
1679                 && cx.tcx().is_impossible_method((impl_def_id, trait_item_def_id))
1680             {
1681                 continue;
1682             }
1683
1684             let n = trait_item.name;
1685             if i.items.iter().any(|m| m.name == n) {
1686                 continue;
1687             }
1688             let did = i.trait_.as_ref().unwrap().def_id();
1689             let provided_methods = i.provided_trait_methods(cx.tcx());
1690             let assoc_link = AssocItemLink::GotoSource(did.into(), &provided_methods);
1691
1692             doc_impl_item(
1693                 boring,
1694                 interesting,
1695                 cx,
1696                 trait_item,
1697                 parent,
1698                 containing_item,
1699                 assoc_link,
1700                 render_mode,
1701                 true,
1702                 Some(t),
1703                 rendering_params,
1704             );
1705         }
1706     }
1707
1708     // If we've implemented a trait, then also emit documentation for all
1709     // default items which weren't overridden in the implementation block.
1710     // We don't emit documentation for default items if they appear in the
1711     // Implementations on Foreign Types or Implementors sections.
1712     if rendering_params.show_default_items {
1713         if let Some(t) = trait_ {
1714             render_default_items(
1715                 &mut default_impl_items,
1716                 &mut impl_items,
1717                 cx,
1718                 t,
1719                 i.inner_impl(),
1720                 &i.impl_item,
1721                 parent,
1722                 render_mode,
1723                 rendering_params,
1724             );
1725         }
1726     }
1727     if render_mode == RenderMode::Normal {
1728         let toggled = !(impl_items.is_empty() && default_impl_items.is_empty());
1729         if toggled {
1730             close_tags.insert_str(0, "</details>");
1731             write!(
1732                 w,
1733                 "<details class=\"rustdoc-toggle implementors-toggle\"{}>",
1734                 if rendering_params.toggle_open_by_default { " open" } else { "" }
1735             );
1736             write!(w, "<summary>")
1737         }
1738         render_impl_summary(
1739             w,
1740             cx,
1741             i,
1742             parent,
1743             parent,
1744             rendering_params.show_def_docs,
1745             use_absolute,
1746             aliases,
1747         );
1748         if toggled {
1749             write!(w, "</summary>")
1750         }
1751
1752         if let Some(ref dox) = i.impl_item.collapsed_doc_value() {
1753             if trait_.is_none() && i.inner_impl().items.is_empty() {
1754                 w.write_str(
1755                     "<div class=\"item-info\">\
1756                     <div class=\"stab empty-impl\">This impl block contains no items.</div>
1757                 </div>",
1758                 );
1759             }
1760             write!(
1761                 w,
1762                 "<div class=\"docblock\">{}</div>",
1763                 Markdown {
1764                     content: &*dox,
1765                     links: &i.impl_item.links(cx),
1766                     ids: &mut cx.id_map,
1767                     error_codes: cx.shared.codes,
1768                     edition: cx.shared.edition(),
1769                     playground: &cx.shared.playground,
1770                     heading_offset: HeadingOffset::H4
1771                 }
1772                 .into_string()
1773             );
1774         }
1775     }
1776     if !default_impl_items.is_empty() || !impl_items.is_empty() {
1777         w.write_str("<div class=\"impl-items\">");
1778         w.push_buffer(default_impl_items);
1779         w.push_buffer(impl_items);
1780         close_tags.insert_str(0, "</div>");
1781     }
1782     w.write_str(&close_tags);
1783 }
1784
1785 // Render the items that appear on the right side of methods, impls, and
1786 // associated types. For example "1.0.0 (const: 1.39.0) Â· source".
1787 fn render_rightside(
1788     w: &mut Buffer,
1789     cx: &Context<'_>,
1790     item: &clean::Item,
1791     containing_item: &clean::Item,
1792     render_mode: RenderMode,
1793 ) {
1794     let tcx = cx.tcx();
1795
1796     // FIXME: Once https://github.com/rust-lang/rust/issues/67792 is implemented, we can remove
1797     // this condition.
1798     let (const_stability, const_stable_since) = match render_mode {
1799         RenderMode::Normal => (item.const_stability(tcx), containing_item.const_stable_since(tcx)),
1800         RenderMode::ForDeref { .. } => (None, None),
1801     };
1802     let src_href = cx.src_href(item);
1803     let has_src_ref = src_href.is_some();
1804
1805     let mut rightside = Buffer::new();
1806     let has_stability = render_stability_since_raw_with_extra(
1807         &mut rightside,
1808         item.stable_since(tcx),
1809         const_stability,
1810         containing_item.stable_since(tcx),
1811         const_stable_since,
1812         if has_src_ref { "" } else { " rightside" },
1813     );
1814     if let Some(l) = src_href {
1815         if has_stability {
1816             write!(rightside, " Â· <a class=\"srclink\" href=\"{}\">source</a>", l)
1817         } else {
1818             write!(rightside, "<a class=\"srclink rightside\" href=\"{}\">source</a>", l)
1819         }
1820     }
1821     if has_stability && has_src_ref {
1822         write!(w, "<span class=\"rightside\">{}</span>", rightside.into_inner());
1823     } else {
1824         w.push_buffer(rightside);
1825     }
1826 }
1827
1828 pub(crate) fn render_impl_summary(
1829     w: &mut Buffer,
1830     cx: &mut Context<'_>,
1831     i: &Impl,
1832     parent: &clean::Item,
1833     containing_item: &clean::Item,
1834     show_def_docs: bool,
1835     use_absolute: Option<bool>,
1836     // This argument is used to reference same type with different paths to avoid duplication
1837     // in documentation pages for trait with automatic implementations like "Send" and "Sync".
1838     aliases: &[String],
1839 ) {
1840     let inner_impl = i.inner_impl();
1841     let id = cx.derive_id(get_id_for_impl(&inner_impl.for_, inner_impl.trait_.as_ref(), cx));
1842     let aliases = if aliases.is_empty() {
1843         String::new()
1844     } else {
1845         format!(" data-aliases=\"{}\"", aliases.join(","))
1846     };
1847     write!(w, "<section id=\"{}\" class=\"impl has-srclink\"{}>", id, aliases);
1848     render_rightside(w, cx, &i.impl_item, containing_item, RenderMode::Normal);
1849     write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
1850     write!(w, "<h3 class=\"code-header\">");
1851
1852     if let Some(use_absolute) = use_absolute {
1853         write!(w, "{}", inner_impl.print(use_absolute, cx));
1854         if show_def_docs {
1855             for it in &inner_impl.items {
1856                 if let clean::AssocTypeItem(ref tydef, ref _bounds) = *it.kind {
1857                     w.write_str("<span class=\"where fmt-newline\">  ");
1858                     assoc_type(
1859                         w,
1860                         it,
1861                         &tydef.generics,
1862                         &[], // intentionally leaving out bounds
1863                         Some(&tydef.type_),
1864                         AssocItemLink::Anchor(None),
1865                         0,
1866                         cx,
1867                     );
1868                     w.write_str(";</span>");
1869                 }
1870             }
1871         }
1872     } else {
1873         write!(w, "{}", inner_impl.print(false, cx));
1874     }
1875     write!(w, "</h3>");
1876
1877     let is_trait = inner_impl.trait_.is_some();
1878     if is_trait {
1879         if let Some(portability) = portability(&i.impl_item, Some(parent)) {
1880             write!(w, "<span class=\"item-info\">{}</span>", portability);
1881         }
1882     }
1883
1884     w.write_str("</section>");
1885 }
1886
1887 fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buffer) {
1888     if it.is_struct()
1889         || it.is_trait()
1890         || it.is_primitive()
1891         || it.is_union()
1892         || it.is_enum()
1893         || it.is_mod()
1894         || it.is_typedef()
1895     {
1896         write!(
1897             buffer,
1898             "<h2 class=\"location\"><a href=\"#\">{}{}</a></h2>",
1899             match *it.kind {
1900                 clean::ModuleItem(..) =>
1901                     if it.is_crate() {
1902                         "Crate "
1903                     } else {
1904                         "Module "
1905                     },
1906                 _ => "",
1907             },
1908             it.name.as_ref().unwrap()
1909         );
1910     }
1911
1912     buffer.write_str("<div class=\"sidebar-elems\">");
1913     if it.is_crate() {
1914         write!(buffer, "<ul class=\"block\">");
1915         if let Some(ref version) = cx.cache().crate_version {
1916             write!(buffer, "<li class=\"version\">Version {}</li>", Escape(version));
1917         }
1918         write!(buffer, "<li><a id=\"all-types\" href=\"all.html\">All Items</a></li>");
1919         buffer.write_str("</ul>");
1920     }
1921
1922     match *it.kind {
1923         clean::StructItem(ref s) => sidebar_struct(cx, buffer, it, s),
1924         clean::TraitItem(ref t) => sidebar_trait(cx, buffer, it, t),
1925         clean::PrimitiveItem(_) => sidebar_primitive(cx, buffer, it),
1926         clean::UnionItem(ref u) => sidebar_union(cx, buffer, it, u),
1927         clean::EnumItem(ref e) => sidebar_enum(cx, buffer, it, e),
1928         clean::TypedefItem(_) => sidebar_typedef(cx, buffer, it),
1929         clean::ModuleItem(ref m) => sidebar_module(buffer, &m.items),
1930         clean::ForeignTypeItem => sidebar_foreign_type(cx, buffer, it),
1931         _ => {}
1932     }
1933
1934     // The sidebar is designed to display sibling functions, modules and
1935     // other miscellaneous information. since there are lots of sibling
1936     // items (and that causes quadratic growth in large modules),
1937     // we refactor common parts into a shared JavaScript file per module.
1938     // still, we don't move everything into JS because we want to preserve
1939     // as much HTML as possible in order to allow non-JS-enabled browsers
1940     // to navigate the documentation (though slightly inefficiently).
1941
1942     if !it.is_mod() {
1943         let path: String = cx.current.iter().map(|s| s.as_str()).intersperse("::").collect();
1944
1945         write!(buffer, "<h2><a href=\"index.html\">In {}</a></h2>", path);
1946     }
1947
1948     // Closes sidebar-elems div.
1949     buffer.write_str("</div>");
1950 }
1951
1952 fn get_next_url(used_links: &mut FxHashSet<String>, url: String) -> String {
1953     if used_links.insert(url.clone()) {
1954         return url;
1955     }
1956     let mut add = 1;
1957     while !used_links.insert(format!("{}-{}", url, add)) {
1958         add += 1;
1959     }
1960     format!("{}-{}", url, add)
1961 }
1962
1963 struct SidebarLink {
1964     name: Symbol,
1965     url: String,
1966 }
1967
1968 impl fmt::Display for SidebarLink {
1969     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1970         write!(f, "<a href=\"#{}\">{}</a>", self.url, self.name)
1971     }
1972 }
1973
1974 impl PartialEq for SidebarLink {
1975     fn eq(&self, other: &Self) -> bool {
1976         self.url == other.url
1977     }
1978 }
1979
1980 impl Eq for SidebarLink {}
1981
1982 impl PartialOrd for SidebarLink {
1983     fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
1984         Some(self.cmp(other))
1985     }
1986 }
1987
1988 impl Ord for SidebarLink {
1989     fn cmp(&self, other: &Self) -> std::cmp::Ordering {
1990         self.url.cmp(&other.url)
1991     }
1992 }
1993
1994 fn get_methods(
1995     i: &clean::Impl,
1996     for_deref: bool,
1997     used_links: &mut FxHashSet<String>,
1998     deref_mut: bool,
1999     tcx: TyCtxt<'_>,
2000 ) -> Vec<SidebarLink> {
2001     i.items
2002         .iter()
2003         .filter_map(|item| match item.name {
2004             Some(name) if !name.is_empty() && item.is_method() => {
2005                 if !for_deref || should_render_item(item, deref_mut, tcx) {
2006                     Some(SidebarLink {
2007                         name,
2008                         url: get_next_url(used_links, format!("{}.{}", ItemType::Method, name)),
2009                     })
2010                 } else {
2011                     None
2012                 }
2013             }
2014             _ => None,
2015         })
2016         .collect::<Vec<_>>()
2017 }
2018
2019 fn get_associated_constants(
2020     i: &clean::Impl,
2021     used_links: &mut FxHashSet<String>,
2022 ) -> Vec<SidebarLink> {
2023     i.items
2024         .iter()
2025         .filter_map(|item| match item.name {
2026             Some(name) if !name.is_empty() && item.is_associated_const() => Some(SidebarLink {
2027                 name,
2028                 url: get_next_url(used_links, format!("{}.{}", ItemType::AssocConst, name)),
2029             }),
2030             _ => None,
2031         })
2032         .collect::<Vec<_>>()
2033 }
2034
2035 // The point is to url encode any potential character from a type with genericity.
2036 fn small_url_encode(s: String) -> String {
2037     let mut st = String::new();
2038     let mut last_match = 0;
2039     for (idx, c) in s.char_indices() {
2040         let escaped = match c {
2041             '<' => "%3C",
2042             '>' => "%3E",
2043             ' ' => "%20",
2044             '?' => "%3F",
2045             '\'' => "%27",
2046             '&' => "%26",
2047             ',' => "%2C",
2048             ':' => "%3A",
2049             ';' => "%3B",
2050             '[' => "%5B",
2051             ']' => "%5D",
2052             '"' => "%22",
2053             _ => continue,
2054         };
2055
2056         st += &s[last_match..idx];
2057         st += escaped;
2058         // NOTE: we only expect single byte characters here - which is fine as long as we
2059         // only match single byte characters
2060         last_match = idx + 1;
2061     }
2062
2063     if last_match != 0 {
2064         st += &s[last_match..];
2065         st
2066     } else {
2067         s
2068     }
2069 }
2070
2071 pub(crate) fn sidebar_render_assoc_items(
2072     cx: &Context<'_>,
2073     out: &mut Buffer,
2074     id_map: &mut IdMap,
2075     concrete: Vec<&Impl>,
2076     synthetic: Vec<&Impl>,
2077     blanket_impl: Vec<&Impl>,
2078 ) {
2079     let format_impls = |impls: Vec<&Impl>, id_map: &mut IdMap| {
2080         let mut links = FxHashSet::default();
2081
2082         let mut ret = impls
2083             .iter()
2084             .filter_map(|it| {
2085                 let trait_ = it.inner_impl().trait_.as_ref()?;
2086                 let encoded =
2087                     id_map.derive(get_id_for_impl(&it.inner_impl().for_, Some(trait_), cx));
2088
2089                 let i_display = format!("{:#}", trait_.print(cx));
2090                 let out = Escape(&i_display);
2091                 let prefix = match it.inner_impl().polarity {
2092                     ty::ImplPolarity::Positive | ty::ImplPolarity::Reservation => "",
2093                     ty::ImplPolarity::Negative => "!",
2094                 };
2095                 let generated = format!("<a href=\"#{}\">{}{}</a>", encoded, prefix, out);
2096                 if links.insert(generated.clone()) { Some(generated) } else { None }
2097             })
2098             .collect::<Vec<String>>();
2099         ret.sort();
2100         ret
2101     };
2102
2103     let concrete_format = format_impls(concrete, id_map);
2104     let synthetic_format = format_impls(synthetic, id_map);
2105     let blanket_format = format_impls(blanket_impl, id_map);
2106
2107     if !concrete_format.is_empty() {
2108         print_sidebar_block(
2109             out,
2110             "trait-implementations",
2111             "Trait Implementations",
2112             concrete_format.iter(),
2113         );
2114     }
2115
2116     if !synthetic_format.is_empty() {
2117         print_sidebar_block(
2118             out,
2119             "synthetic-implementations",
2120             "Auto Trait Implementations",
2121             synthetic_format.iter(),
2122         );
2123     }
2124
2125     if !blanket_format.is_empty() {
2126         print_sidebar_block(
2127             out,
2128             "blanket-implementations",
2129             "Blanket Implementations",
2130             blanket_format.iter(),
2131         );
2132     }
2133 }
2134
2135 fn sidebar_assoc_items(cx: &Context<'_>, out: &mut Buffer, it: &clean::Item) {
2136     let did = it.item_id.expect_def_id();
2137     let cache = cx.cache();
2138
2139     if let Some(v) = cache.impls.get(&did) {
2140         let mut used_links = FxHashSet::default();
2141         let mut id_map = IdMap::new();
2142
2143         {
2144             let used_links_bor = &mut used_links;
2145             let mut assoc_consts = v
2146                 .iter()
2147                 .filter(|i| i.inner_impl().trait_.is_none())
2148                 .flat_map(|i| get_associated_constants(i.inner_impl(), used_links_bor))
2149                 .collect::<Vec<_>>();
2150             if !assoc_consts.is_empty() {
2151                 // We want links' order to be reproducible so we don't use unstable sort.
2152                 assoc_consts.sort();
2153
2154                 print_sidebar_block(
2155                     out,
2156                     "implementations",
2157                     "Associated Constants",
2158                     assoc_consts.iter(),
2159                 );
2160             }
2161             let mut methods = v
2162                 .iter()
2163                 .filter(|i| i.inner_impl().trait_.is_none())
2164                 .flat_map(|i| get_methods(i.inner_impl(), false, used_links_bor, false, cx.tcx()))
2165                 .collect::<Vec<_>>();
2166             if !methods.is_empty() {
2167                 // We want links' order to be reproducible so we don't use unstable sort.
2168                 methods.sort();
2169
2170                 print_sidebar_block(out, "implementations", "Methods", methods.iter());
2171             }
2172         }
2173
2174         if v.iter().any(|i| i.inner_impl().trait_.is_some()) {
2175             if let Some(impl_) =
2176                 v.iter().find(|i| i.trait_did() == cx.tcx().lang_items().deref_trait())
2177             {
2178                 let mut derefs = FxHashSet::default();
2179                 derefs.insert(did);
2180                 sidebar_deref_methods(cx, out, impl_, v, &mut derefs, &mut used_links);
2181             }
2182
2183             let (synthetic, concrete): (Vec<&Impl>, Vec<&Impl>) =
2184                 v.iter().partition::<Vec<_>, _>(|i| i.inner_impl().kind.is_auto());
2185             let (blanket_impl, concrete): (Vec<&Impl>, Vec<&Impl>) =
2186                 concrete.into_iter().partition::<Vec<_>, _>(|i| i.inner_impl().kind.is_blanket());
2187
2188             sidebar_render_assoc_items(cx, out, &mut id_map, concrete, synthetic, blanket_impl);
2189         }
2190     }
2191 }
2192
2193 fn sidebar_deref_methods(
2194     cx: &Context<'_>,
2195     out: &mut Buffer,
2196     impl_: &Impl,
2197     v: &[Impl],
2198     derefs: &mut FxHashSet<DefId>,
2199     used_links: &mut FxHashSet<String>,
2200 ) {
2201     let c = cx.cache();
2202
2203     debug!("found Deref: {:?}", impl_);
2204     if let Some((target, real_target)) =
2205         impl_.inner_impl().items.iter().find_map(|item| match *item.kind {
2206             clean::AssocTypeItem(box ref t, _) => Some(match *t {
2207                 clean::Typedef { item_type: Some(ref type_), .. } => (type_, &t.type_),
2208                 _ => (&t.type_, &t.type_),
2209             }),
2210             _ => None,
2211         })
2212     {
2213         debug!("found target, real_target: {:?} {:?}", target, real_target);
2214         if let Some(did) = target.def_id(c) {
2215             if let Some(type_did) = impl_.inner_impl().for_.def_id(c) {
2216                 // `impl Deref<Target = S> for S`
2217                 if did == type_did || !derefs.insert(did) {
2218                     // Avoid infinite cycles
2219                     return;
2220                 }
2221             }
2222         }
2223         let deref_mut = v.iter().any(|i| i.trait_did() == cx.tcx().lang_items().deref_mut_trait());
2224         let inner_impl = target
2225             .def_id(c)
2226             .or_else(|| {
2227                 target.primitive_type().and_then(|prim| c.primitive_locations.get(&prim).cloned())
2228             })
2229             .and_then(|did| c.impls.get(&did));
2230         if let Some(impls) = inner_impl {
2231             debug!("found inner_impl: {:?}", impls);
2232             let mut ret = impls
2233                 .iter()
2234                 .filter(|i| i.inner_impl().trait_.is_none())
2235                 .flat_map(|i| get_methods(i.inner_impl(), true, used_links, deref_mut, cx.tcx()))
2236                 .collect::<Vec<_>>();
2237             if !ret.is_empty() {
2238                 let id = if let Some(target_def_id) = real_target.def_id(c) {
2239                     cx.deref_id_map.get(&target_def_id).expect("Deref section without derived id")
2240                 } else {
2241                     "deref-methods"
2242                 };
2243                 let title = format!(
2244                     "Methods from {}&lt;Target={}&gt;",
2245                     Escape(&format!("{:#}", impl_.inner_impl().trait_.as_ref().unwrap().print(cx))),
2246                     Escape(&format!("{:#}", real_target.print(cx))),
2247                 );
2248                 // We want links' order to be reproducible so we don't use unstable sort.
2249                 ret.sort();
2250                 print_sidebar_block(out, id, &title, ret.iter());
2251             }
2252         }
2253
2254         // Recurse into any further impls that might exist for `target`
2255         if let Some(target_did) = target.def_id(c) {
2256             if let Some(target_impls) = c.impls.get(&target_did) {
2257                 if let Some(target_deref_impl) = target_impls.iter().find(|i| {
2258                     i.inner_impl()
2259                         .trait_
2260                         .as_ref()
2261                         .map(|t| Some(t.def_id()) == cx.tcx().lang_items().deref_trait())
2262                         .unwrap_or(false)
2263                 }) {
2264                     sidebar_deref_methods(
2265                         cx,
2266                         out,
2267                         target_deref_impl,
2268                         target_impls,
2269                         derefs,
2270                         used_links,
2271                     );
2272                 }
2273             }
2274         }
2275     }
2276 }
2277
2278 fn sidebar_struct(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, s: &clean::Struct) {
2279     let mut sidebar = Buffer::new();
2280     let fields = get_struct_fields_name(&s.fields);
2281
2282     if !fields.is_empty() {
2283         match s.struct_type {
2284             CtorKind::Fictive => {
2285                 print_sidebar_block(&mut sidebar, "fields", "Fields", fields.iter());
2286             }
2287             CtorKind::Fn => print_sidebar_title(&mut sidebar, "fields", "Tuple Fields"),
2288             CtorKind::Const => {}
2289         }
2290     }
2291
2292     sidebar_assoc_items(cx, &mut sidebar, it);
2293
2294     if !sidebar.is_empty() {
2295         write!(buf, "<section>{}</section>", sidebar.into_inner());
2296     }
2297 }
2298
2299 fn get_id_for_impl(for_: &clean::Type, trait_: Option<&clean::Path>, cx: &Context<'_>) -> String {
2300     match trait_ {
2301         Some(t) => small_url_encode(format!("impl-{:#}-for-{:#}", t.print(cx), for_.print(cx))),
2302         None => small_url_encode(format!("impl-{:#}", for_.print(cx))),
2303     }
2304 }
2305
2306 fn extract_for_impl_name(item: &clean::Item, cx: &Context<'_>) -> Option<(String, String)> {
2307     match *item.kind {
2308         clean::ItemKind::ImplItem(ref i) => {
2309             i.trait_.as_ref().map(|trait_| {
2310                 // Alternative format produces no URLs,
2311                 // so this parameter does nothing.
2312                 (format!("{:#}", i.for_.print(cx)), get_id_for_impl(&i.for_, Some(trait_), cx))
2313             })
2314         }
2315         _ => None,
2316     }
2317 }
2318
2319 fn print_sidebar_title(buf: &mut Buffer, id: &str, title: &str) {
2320     write!(buf, "<h3><a href=\"#{}\">{}</a></h3>", id, title);
2321 }
2322
2323 fn print_sidebar_block(
2324     buf: &mut Buffer,
2325     id: &str,
2326     title: &str,
2327     items: impl Iterator<Item = impl fmt::Display>,
2328 ) {
2329     print_sidebar_title(buf, id, title);
2330     buf.push_str("<ul class=\"block\">");
2331     for item in items {
2332         write!(buf, "<li>{}</li>", item);
2333     }
2334     buf.push_str("</ul>");
2335 }
2336
2337 fn sidebar_trait(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, t: &clean::Trait) {
2338     buf.write_str("<section>");
2339
2340     fn print_sidebar_section(
2341         out: &mut Buffer,
2342         items: &[clean::Item],
2343         id: &str,
2344         title: &str,
2345         filter: impl Fn(&clean::Item) -> bool,
2346         mapper: impl Fn(&str) -> String,
2347     ) {
2348         let mut items: Vec<&str> = items
2349             .iter()
2350             .filter_map(|m| match m.name {
2351                 Some(ref name) if filter(m) => Some(name.as_str()),
2352                 _ => None,
2353             })
2354             .collect::<Vec<_>>();
2355
2356         if !items.is_empty() {
2357             items.sort_unstable();
2358             print_sidebar_block(out, id, title, items.into_iter().map(mapper));
2359         }
2360     }
2361
2362     print_sidebar_section(
2363         buf,
2364         &t.items,
2365         "required-associated-types",
2366         "Required Associated Types",
2367         |m| m.is_ty_associated_type(),
2368         |sym| format!("<a href=\"#{1}.{0}\">{0}</a>", sym, ItemType::AssocType),
2369     );
2370
2371     print_sidebar_section(
2372         buf,
2373         &t.items,
2374         "provided-associated-types",
2375         "Provided Associated Types",
2376         |m| m.is_associated_type(),
2377         |sym| format!("<a href=\"#{1}.{0}\">{0}</a>", sym, ItemType::AssocType),
2378     );
2379
2380     print_sidebar_section(
2381         buf,
2382         &t.items,
2383         "required-associated-consts",
2384         "Required Associated Constants",
2385         |m| m.is_ty_associated_const(),
2386         |sym| format!("<a href=\"#{1}.{0}\">{0}</a>", sym, ItemType::AssocConst),
2387     );
2388
2389     print_sidebar_section(
2390         buf,
2391         &t.items,
2392         "provided-associated-consts",
2393         "Provided Associated Constants",
2394         |m| m.is_associated_const(),
2395         |sym| format!("<a href=\"#{1}.{0}\">{0}</a>", sym, ItemType::AssocConst),
2396     );
2397
2398     print_sidebar_section(
2399         buf,
2400         &t.items,
2401         "required-methods",
2402         "Required Methods",
2403         |m| m.is_ty_method(),
2404         |sym| format!("<a href=\"#{1}.{0}\">{0}</a>", sym, ItemType::TyMethod),
2405     );
2406
2407     print_sidebar_section(
2408         buf,
2409         &t.items,
2410         "provided-methods",
2411         "Provided Methods",
2412         |m| m.is_method(),
2413         |sym| format!("<a href=\"#{1}.{0}\">{0}</a>", sym, ItemType::Method),
2414     );
2415
2416     if let Some(implementors) = cx.cache().implementors.get(&it.item_id.expect_def_id()) {
2417         let mut res = implementors
2418             .iter()
2419             .filter(|i| !i.is_on_local_type(cx))
2420             .filter_map(|i| extract_for_impl_name(&i.impl_item, cx))
2421             .collect::<Vec<_>>();
2422
2423         if !res.is_empty() {
2424             res.sort();
2425             print_sidebar_block(
2426                 buf,
2427                 "foreign-impls",
2428                 "Implementations on Foreign Types",
2429                 res.iter().map(|(name, id)| format!("<a href=\"#{}\">{}</a>", id, Escape(name))),
2430             );
2431         }
2432     }
2433
2434     sidebar_assoc_items(cx, buf, it);
2435
2436     print_sidebar_title(buf, "implementors", "Implementors");
2437     if t.is_auto(cx.tcx()) {
2438         print_sidebar_title(buf, "synthetic-implementors", "Auto Implementors");
2439     }
2440
2441     buf.push_str("</section>")
2442 }
2443
2444 /// Returns the list of implementations for the primitive reference type, filtering out any
2445 /// implementations that are on concrete or partially generic types, only keeping implementations
2446 /// of the form `impl<T> Trait for &T`.
2447 pub(crate) fn get_filtered_impls_for_reference<'a>(
2448     shared: &'a Rc<SharedContext<'_>>,
2449     it: &clean::Item,
2450 ) -> (Vec<&'a Impl>, Vec<&'a Impl>, Vec<&'a Impl>) {
2451     let def_id = it.item_id.expect_def_id();
2452     // If the reference primitive is somehow not defined, exit early.
2453     let Some(v) = shared.cache.impls.get(&def_id) else { return (Vec::new(), Vec::new(), Vec::new()) };
2454     // Since there is no "direct implementation" on the reference primitive type, we filter out
2455     // every implementation which isn't a trait implementation.
2456     let traits = v.iter().filter(|i| i.inner_impl().trait_.is_some());
2457     let (synthetic, concrete): (Vec<&Impl>, Vec<&Impl>) =
2458         traits.partition(|t| t.inner_impl().kind.is_auto());
2459
2460     let (blanket_impl, concrete): (Vec<&Impl>, _) =
2461         concrete.into_iter().partition(|t| t.inner_impl().kind.is_blanket());
2462     // Now we keep only references over full generic types.
2463     let concrete: Vec<_> = concrete
2464         .into_iter()
2465         .filter(|t| match t.inner_impl().for_ {
2466             clean::Type::BorrowedRef { ref type_, .. } => type_.is_full_generic(),
2467             _ => false,
2468         })
2469         .collect();
2470
2471     (concrete, synthetic, blanket_impl)
2472 }
2473
2474 fn sidebar_primitive(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item) {
2475     let mut sidebar = Buffer::new();
2476
2477     if it.name.map(|n| n.as_str() != "reference").unwrap_or(false) {
2478         sidebar_assoc_items(cx, &mut sidebar, it);
2479     } else {
2480         let shared = Rc::clone(&cx.shared);
2481         let (concrete, synthetic, blanket_impl) = get_filtered_impls_for_reference(&shared, it);
2482
2483         sidebar_render_assoc_items(
2484             cx,
2485             &mut sidebar,
2486             &mut IdMap::new(),
2487             concrete,
2488             synthetic,
2489             blanket_impl,
2490         );
2491     }
2492
2493     if !sidebar.is_empty() {
2494         write!(buf, "<section>{}</section>", sidebar.into_inner());
2495     }
2496 }
2497
2498 fn sidebar_typedef(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item) {
2499     let mut sidebar = Buffer::new();
2500     sidebar_assoc_items(cx, &mut sidebar, it);
2501
2502     if !sidebar.is_empty() {
2503         write!(buf, "<section>{}</section>", sidebar.into_inner());
2504     }
2505 }
2506
2507 fn get_struct_fields_name(fields: &[clean::Item]) -> Vec<String> {
2508     let mut fields = fields
2509         .iter()
2510         .filter(|f| matches!(*f.kind, clean::StructFieldItem(..)))
2511         .filter_map(|f| {
2512             f.name.map(|name| format!("<a href=\"#structfield.{name}\">{name}</a>", name = name))
2513         })
2514         .collect::<Vec<_>>();
2515     fields.sort();
2516     fields
2517 }
2518
2519 fn sidebar_union(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, u: &clean::Union) {
2520     let mut sidebar = Buffer::new();
2521     let fields = get_struct_fields_name(&u.fields);
2522
2523     if !fields.is_empty() {
2524         print_sidebar_block(&mut sidebar, "fields", "Fields", fields.iter());
2525     }
2526
2527     sidebar_assoc_items(cx, &mut sidebar, it);
2528
2529     if !sidebar.is_empty() {
2530         write!(buf, "<section>{}</section>", sidebar.into_inner());
2531     }
2532 }
2533
2534 fn sidebar_enum(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, e: &clean::Enum) {
2535     let mut sidebar = Buffer::new();
2536
2537     let mut variants = e
2538         .variants()
2539         .filter_map(|v| {
2540             v.name
2541                 .as_ref()
2542                 .map(|name| format!("<a href=\"#variant.{name}\">{name}</a>", name = name))
2543         })
2544         .collect::<Vec<_>>();
2545     if !variants.is_empty() {
2546         variants.sort_unstable();
2547         print_sidebar_block(&mut sidebar, "variants", "Variants", variants.iter());
2548     }
2549
2550     sidebar_assoc_items(cx, &mut sidebar, it);
2551
2552     if !sidebar.is_empty() {
2553         write!(buf, "<section>{}</section>", sidebar.into_inner());
2554     }
2555 }
2556
2557 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
2558 pub(crate) enum ItemSection {
2559     Reexports,
2560     PrimitiveTypes,
2561     Modules,
2562     Macros,
2563     Structs,
2564     Enums,
2565     Constants,
2566     Statics,
2567     Traits,
2568     Functions,
2569     TypeDefinitions,
2570     Unions,
2571     Implementations,
2572     TypeMethods,
2573     Methods,
2574     StructFields,
2575     Variants,
2576     AssociatedTypes,
2577     AssociatedConstants,
2578     ForeignTypes,
2579     Keywords,
2580     OpaqueTypes,
2581     AttributeMacros,
2582     DeriveMacros,
2583     TraitAliases,
2584 }
2585
2586 impl ItemSection {
2587     const ALL: &'static [Self] = {
2588         use ItemSection::*;
2589         // NOTE: The order here affects the order in the UI.
2590         &[
2591             Reexports,
2592             PrimitiveTypes,
2593             Modules,
2594             Macros,
2595             Structs,
2596             Enums,
2597             Constants,
2598             Statics,
2599             Traits,
2600             Functions,
2601             TypeDefinitions,
2602             Unions,
2603             Implementations,
2604             TypeMethods,
2605             Methods,
2606             StructFields,
2607             Variants,
2608             AssociatedTypes,
2609             AssociatedConstants,
2610             ForeignTypes,
2611             Keywords,
2612             OpaqueTypes,
2613             AttributeMacros,
2614             DeriveMacros,
2615             TraitAliases,
2616         ]
2617     };
2618
2619     fn id(self) -> &'static str {
2620         match self {
2621             Self::Reexports => "reexports",
2622             Self::Modules => "modules",
2623             Self::Structs => "structs",
2624             Self::Unions => "unions",
2625             Self::Enums => "enums",
2626             Self::Functions => "functions",
2627             Self::TypeDefinitions => "types",
2628             Self::Statics => "statics",
2629             Self::Constants => "constants",
2630             Self::Traits => "traits",
2631             Self::Implementations => "impls",
2632             Self::TypeMethods => "tymethods",
2633             Self::Methods => "methods",
2634             Self::StructFields => "fields",
2635             Self::Variants => "variants",
2636             Self::Macros => "macros",
2637             Self::PrimitiveTypes => "primitives",
2638             Self::AssociatedTypes => "associated-types",
2639             Self::AssociatedConstants => "associated-consts",
2640             Self::ForeignTypes => "foreign-types",
2641             Self::Keywords => "keywords",
2642             Self::OpaqueTypes => "opaque-types",
2643             Self::AttributeMacros => "attributes",
2644             Self::DeriveMacros => "derives",
2645             Self::TraitAliases => "trait-aliases",
2646         }
2647     }
2648
2649     fn name(self) -> &'static str {
2650         match self {
2651             Self::Reexports => "Re-exports",
2652             Self::Modules => "Modules",
2653             Self::Structs => "Structs",
2654             Self::Unions => "Unions",
2655             Self::Enums => "Enums",
2656             Self::Functions => "Functions",
2657             Self::TypeDefinitions => "Type Definitions",
2658             Self::Statics => "Statics",
2659             Self::Constants => "Constants",
2660             Self::Traits => "Traits",
2661             Self::Implementations => "Implementations",
2662             Self::TypeMethods => "Type Methods",
2663             Self::Methods => "Methods",
2664             Self::StructFields => "Struct Fields",
2665             Self::Variants => "Variants",
2666             Self::Macros => "Macros",
2667             Self::PrimitiveTypes => "Primitive Types",
2668             Self::AssociatedTypes => "Associated Types",
2669             Self::AssociatedConstants => "Associated Constants",
2670             Self::ForeignTypes => "Foreign Types",
2671             Self::Keywords => "Keywords",
2672             Self::OpaqueTypes => "Opaque Types",
2673             Self::AttributeMacros => "Attribute Macros",
2674             Self::DeriveMacros => "Derive Macros",
2675             Self::TraitAliases => "Trait Aliases",
2676         }
2677     }
2678 }
2679
2680 fn item_ty_to_section(ty: ItemType) -> ItemSection {
2681     match ty {
2682         ItemType::ExternCrate | ItemType::Import => ItemSection::Reexports,
2683         ItemType::Module => ItemSection::Modules,
2684         ItemType::Struct => ItemSection::Structs,
2685         ItemType::Union => ItemSection::Unions,
2686         ItemType::Enum => ItemSection::Enums,
2687         ItemType::Function => ItemSection::Functions,
2688         ItemType::Typedef => ItemSection::TypeDefinitions,
2689         ItemType::Static => ItemSection::Statics,
2690         ItemType::Constant => ItemSection::Constants,
2691         ItemType::Trait => ItemSection::Traits,
2692         ItemType::Impl => ItemSection::Implementations,
2693         ItemType::TyMethod => ItemSection::TypeMethods,
2694         ItemType::Method => ItemSection::Methods,
2695         ItemType::StructField => ItemSection::StructFields,
2696         ItemType::Variant => ItemSection::Variants,
2697         ItemType::Macro => ItemSection::Macros,
2698         ItemType::Primitive => ItemSection::PrimitiveTypes,
2699         ItemType::AssocType => ItemSection::AssociatedTypes,
2700         ItemType::AssocConst => ItemSection::AssociatedConstants,
2701         ItemType::ForeignType => ItemSection::ForeignTypes,
2702         ItemType::Keyword => ItemSection::Keywords,
2703         ItemType::OpaqueTy => ItemSection::OpaqueTypes,
2704         ItemType::ProcAttribute => ItemSection::AttributeMacros,
2705         ItemType::ProcDerive => ItemSection::DeriveMacros,
2706         ItemType::TraitAlias => ItemSection::TraitAliases,
2707     }
2708 }
2709
2710 pub(crate) fn sidebar_module_like(buf: &mut Buffer, item_sections_in_use: FxHashSet<ItemSection>) {
2711     use std::fmt::Write as _;
2712
2713     let mut sidebar = String::new();
2714
2715     for &sec in ItemSection::ALL.iter().filter(|sec| item_sections_in_use.contains(sec)) {
2716         let _ = write!(sidebar, "<li><a href=\"#{}\">{}</a></li>", sec.id(), sec.name());
2717     }
2718
2719     if !sidebar.is_empty() {
2720         write!(
2721             buf,
2722             "<section>\
2723                  <ul class=\"block\">{}</ul>\
2724              </section>",
2725             sidebar
2726         );
2727     }
2728 }
2729
2730 fn sidebar_module(buf: &mut Buffer, items: &[clean::Item]) {
2731     let item_sections_in_use: FxHashSet<_> = items
2732         .iter()
2733         .filter(|it| {
2734             !it.is_stripped()
2735                 && it
2736                     .name
2737                     .or_else(|| {
2738                         if let clean::ImportItem(ref i) = *it.kind &&
2739                             let clean::ImportKind::Simple(s) = i.kind { Some(s) } else { None }
2740                     })
2741                     .is_some()
2742         })
2743         .map(|it| item_ty_to_section(it.type_()))
2744         .collect();
2745
2746     sidebar_module_like(buf, item_sections_in_use);
2747 }
2748
2749 fn sidebar_foreign_type(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item) {
2750     let mut sidebar = Buffer::new();
2751     sidebar_assoc_items(cx, &mut sidebar, it);
2752
2753     if !sidebar.is_empty() {
2754         write!(buf, "<section>{}</section>", sidebar.into_inner());
2755     }
2756 }
2757
2758 pub(crate) const BASIC_KEYWORDS: &str = "rust, rustlang, rust-lang";
2759
2760 /// Returns a list of all paths used in the type.
2761 /// This is used to help deduplicate imported impls
2762 /// for reexported types. If any of the contained
2763 /// types are re-exported, we don't use the corresponding
2764 /// entry from the js file, as inlining will have already
2765 /// picked up the impl
2766 fn collect_paths_for_type(first_ty: clean::Type, cache: &Cache) -> Vec<String> {
2767     let mut out = Vec::new();
2768     let mut visited = FxHashSet::default();
2769     let mut work = VecDeque::new();
2770
2771     let mut process_path = |did: DefId| {
2772         let get_extern = || cache.external_paths.get(&did).map(|s| s.0.clone());
2773         let fqp = cache.exact_paths.get(&did).cloned().or_else(get_extern);
2774
2775         if let Some(path) = fqp {
2776             out.push(join_with_double_colon(&path));
2777         }
2778     };
2779
2780     work.push_back(first_ty);
2781
2782     while let Some(ty) = work.pop_front() {
2783         if !visited.insert(ty.clone()) {
2784             continue;
2785         }
2786
2787         match ty {
2788             clean::Type::Path { path } => process_path(path.def_id()),
2789             clean::Type::Tuple(tys) => {
2790                 work.extend(tys.into_iter());
2791             }
2792             clean::Type::Slice(ty) => {
2793                 work.push_back(*ty);
2794             }
2795             clean::Type::Array(ty, _) => {
2796                 work.push_back(*ty);
2797             }
2798             clean::Type::RawPointer(_, ty) => {
2799                 work.push_back(*ty);
2800             }
2801             clean::Type::BorrowedRef { type_, .. } => {
2802                 work.push_back(*type_);
2803             }
2804             clean::Type::QPath(box clean::QPathData { self_type, trait_, .. }) => {
2805                 work.push_back(self_type);
2806                 process_path(trait_.def_id());
2807             }
2808             _ => {}
2809         }
2810     }
2811     out
2812 }
2813
2814 const MAX_FULL_EXAMPLES: usize = 5;
2815 const NUM_VISIBLE_LINES: usize = 10;
2816
2817 /// Generates the HTML for example call locations generated via the --scrape-examples flag.
2818 fn render_call_locations(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item) {
2819     let tcx = cx.tcx();
2820     let def_id = item.item_id.expect_def_id();
2821     let key = tcx.def_path_hash(def_id);
2822     let Some(call_locations) = cx.shared.call_locations.get(&key) else { return };
2823
2824     // Generate a unique ID so users can link to this section for a given method
2825     let id = cx.id_map.derive("scraped-examples");
2826     write!(
2827         w,
2828         "<div class=\"docblock scraped-example-list\">\
2829           <span></span>\
2830           <h5 id=\"{id}\">\
2831              <a href=\"#{id}\">Examples found in repository</a>\
2832              <a class=\"scrape-help\" href=\"{root_path}scrape-examples-help.html\">?</a>\
2833           </h5>",
2834         root_path = cx.root_path(),
2835         id = id
2836     );
2837
2838     // Create a URL to a particular location in a reverse-dependency's source file
2839     let link_to_loc = |call_data: &CallData, loc: &CallLocation| -> (String, String) {
2840         let (line_lo, line_hi) = loc.call_expr.line_span;
2841         let (anchor, title) = if line_lo == line_hi {
2842             ((line_lo + 1).to_string(), format!("line {}", line_lo + 1))
2843         } else {
2844             (
2845                 format!("{}-{}", line_lo + 1, line_hi + 1),
2846                 format!("lines {}-{}", line_lo + 1, line_hi + 1),
2847             )
2848         };
2849         let url = format!("{}{}#{}", cx.root_path(), call_data.url, anchor);
2850         (url, title)
2851     };
2852
2853     // Generate the HTML for a single example, being the title and code block
2854     let write_example = |w: &mut Buffer, (path, call_data): (&PathBuf, &CallData)| -> bool {
2855         let contents = match fs::read_to_string(&path) {
2856             Ok(contents) => contents,
2857             Err(err) => {
2858                 let span = item.span(tcx).map_or(rustc_span::DUMMY_SP, |span| span.inner());
2859                 tcx.sess
2860                     .span_err(span, &format!("failed to read file {}: {}", path.display(), err));
2861                 return false;
2862             }
2863         };
2864
2865         // To reduce file sizes, we only want to embed the source code needed to understand the example, not
2866         // the entire file. So we find the smallest byte range that covers all items enclosing examples.
2867         assert!(!call_data.locations.is_empty());
2868         let min_loc =
2869             call_data.locations.iter().min_by_key(|loc| loc.enclosing_item.byte_span.0).unwrap();
2870         let byte_min = min_loc.enclosing_item.byte_span.0;
2871         let line_min = min_loc.enclosing_item.line_span.0;
2872         let max_loc =
2873             call_data.locations.iter().max_by_key(|loc| loc.enclosing_item.byte_span.1).unwrap();
2874         let byte_max = max_loc.enclosing_item.byte_span.1;
2875         let line_max = max_loc.enclosing_item.line_span.1;
2876
2877         // The output code is limited to that byte range.
2878         let contents_subset = &contents[(byte_min as usize)..(byte_max as usize)];
2879
2880         // The call locations need to be updated to reflect that the size of the program has changed.
2881         // Specifically, the ranges are all subtracted by `byte_min` since that's the new zero point.
2882         let (mut byte_ranges, line_ranges): (Vec<_>, Vec<_>) = call_data
2883             .locations
2884             .iter()
2885             .map(|loc| {
2886                 let (byte_lo, byte_hi) = loc.call_ident.byte_span;
2887                 let (line_lo, line_hi) = loc.call_expr.line_span;
2888                 let byte_range = (byte_lo - byte_min, byte_hi - byte_min);
2889
2890                 let line_range = (line_lo - line_min, line_hi - line_min);
2891                 let (line_url, line_title) = link_to_loc(call_data, loc);
2892
2893                 (byte_range, (line_range, line_url, line_title))
2894             })
2895             .unzip();
2896
2897         let (_, init_url, init_title) = &line_ranges[0];
2898         let needs_expansion = line_max - line_min > NUM_VISIBLE_LINES;
2899         let locations_encoded = serde_json::to_string(&line_ranges).unwrap();
2900
2901         write!(
2902             w,
2903             "<div class=\"scraped-example {expanded_cls}\" data-locs=\"{locations}\">\
2904                 <div class=\"scraped-example-title\">\
2905                    {name} (<a href=\"{url}\">{title}</a>)\
2906                 </div>\
2907                 <div class=\"code-wrapper\">",
2908             expanded_cls = if needs_expansion { "" } else { "expanded" },
2909             name = call_data.display_name,
2910             url = init_url,
2911             title = init_title,
2912             // The locations are encoded as a data attribute, so they can be read
2913             // later by the JS for interactions.
2914             locations = Escape(&locations_encoded)
2915         );
2916
2917         if line_ranges.len() > 1 {
2918             write!(w, r#"<span class="prev">&pr;</span> <span class="next">&sc;</span>"#);
2919         }
2920
2921         // Look for the example file in the source map if it exists, otherwise return a dummy span
2922         let file_span = (|| {
2923             let source_map = tcx.sess.source_map();
2924             let crate_src = tcx.sess.local_crate_source_file.as_ref()?;
2925             let abs_crate_src = crate_src.canonicalize().ok()?;
2926             let crate_root = abs_crate_src.parent()?.parent()?;
2927             let rel_path = path.strip_prefix(crate_root).ok()?;
2928             let files = source_map.files();
2929             let file = files.iter().find(|file| match &file.name {
2930                 FileName::Real(RealFileName::LocalPath(other_path)) => rel_path == other_path,
2931                 _ => false,
2932             })?;
2933             Some(rustc_span::Span::with_root_ctxt(
2934                 file.start_pos + BytePos(byte_min),
2935                 file.start_pos + BytePos(byte_max),
2936             ))
2937         })()
2938         .unwrap_or(rustc_span::DUMMY_SP);
2939
2940         let mut decoration_info = FxHashMap::default();
2941         decoration_info.insert("highlight focus", vec![byte_ranges.remove(0)]);
2942         decoration_info.insert("highlight", byte_ranges);
2943
2944         sources::print_src(
2945             w,
2946             contents_subset,
2947             file_span,
2948             cx,
2949             &cx.root_path(),
2950             highlight::DecorationInfo(decoration_info),
2951             sources::SourceContext::Embedded { offset: line_min, needs_expansion },
2952         );
2953         write!(w, "</div></div>");
2954
2955         true
2956     };
2957
2958     // The call locations are output in sequence, so that sequence needs to be determined.
2959     // Ideally the most "relevant" examples would be shown first, but there's no general algorithm
2960     // for determining relevance. Instead, we prefer the smallest examples being likely the easiest to
2961     // understand at a glance.
2962     let ordered_locations = {
2963         let sort_criterion = |(_, call_data): &(_, &CallData)| {
2964             // Use the first location because that's what the user will see initially
2965             let (lo, hi) = call_data.locations[0].enclosing_item.byte_span;
2966             hi - lo
2967         };
2968
2969         let mut locs = call_locations.iter().collect::<Vec<_>>();
2970         locs.sort_by_key(sort_criterion);
2971         locs
2972     };
2973
2974     let mut it = ordered_locations.into_iter().peekable();
2975
2976     // An example may fail to write if its source can't be read for some reason, so this method
2977     // continues iterating until a write succeeds
2978     let write_and_skip_failure = |w: &mut Buffer, it: &mut Peekable<_>| {
2979         while let Some(example) = it.next() {
2980             if write_example(&mut *w, example) {
2981                 break;
2982             }
2983         }
2984     };
2985
2986     // Write just one example that's visible by default in the method's description.
2987     write_and_skip_failure(w, &mut it);
2988
2989     // Then add the remaining examples in a hidden section.
2990     if it.peek().is_some() {
2991         write!(
2992             w,
2993             "<details class=\"rustdoc-toggle more-examples-toggle\">\
2994                   <summary class=\"hideme\">\
2995                      <span>More examples</span>\
2996                   </summary>\
2997                   <div class=\"hide-more\">Hide additional examples</div>\
2998                   <div class=\"more-scraped-examples\">\
2999                     <div class=\"toggle-line\"><div class=\"toggle-line-inner\"></div></div>\
3000                     <div class=\"more-scraped-examples-inner\">"
3001         );
3002
3003         // Only generate inline code for MAX_FULL_EXAMPLES number of examples. Otherwise we could
3004         // make the page arbitrarily huge!
3005         for _ in 0..MAX_FULL_EXAMPLES {
3006             write_and_skip_failure(w, &mut it);
3007         }
3008
3009         // For the remaining examples, generate a <ul> containing links to the source files.
3010         if it.peek().is_some() {
3011             write!(w, r#"<div class="example-links">Additional examples can be found in:<br><ul>"#);
3012             it.for_each(|(_, call_data)| {
3013                 let (url, _) = link_to_loc(call_data, &call_data.locations[0]);
3014                 write!(
3015                     w,
3016                     r#"<li><a href="{url}">{name}</a></li>"#,
3017                     url = url,
3018                     name = call_data.display_name
3019                 );
3020             });
3021             write!(w, "</ul></div>");
3022         }
3023
3024         write!(w, "</div></div></details>");
3025     }
3026
3027     write!(w, "</div>");
3028 }