]> git.lizzy.rs Git - rust.git/blob - src/librustdoc/html/render/mod.rs
Rollup merge of #106946 - dtolnay:hashlinecolumn, r=m-ou-se
[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, DefIdSet};
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: Symbol,
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>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>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, has_more_content) =
471             MarkdownSummaryLine(&s, &item.links(cx)).into_string_with_has_more_content();
472
473         if has_more_content {
474             let link = format!(r#" <a{}>Read more</a>"#, assoc_href_attr(item, link, cx));
475
476             if let Some(idx) = summary_html.rfind("</p>") {
477                 summary_html.insert_str(idx, &link);
478             } else {
479                 summary_html.push_str(&link);
480             }
481         }
482
483         write!(w, "<div class='docblock'>{}</div>", summary_html,);
484     }
485 }
486
487 fn document_full_collapsible(
488     w: &mut Buffer,
489     item: &clean::Item,
490     cx: &mut Context<'_>,
491     heading_offset: HeadingOffset,
492 ) {
493     document_full_inner(w, item, cx, true, heading_offset);
494 }
495
496 fn document_full(
497     w: &mut Buffer,
498     item: &clean::Item,
499     cx: &mut Context<'_>,
500     heading_offset: HeadingOffset,
501 ) {
502     document_full_inner(w, item, cx, false, heading_offset);
503 }
504
505 fn document_full_inner(
506     w: &mut Buffer,
507     item: &clean::Item,
508     cx: &mut Context<'_>,
509     is_collapsible: bool,
510     heading_offset: HeadingOffset,
511 ) {
512     if let Some(s) = item.collapsed_doc_value() {
513         debug!("Doc block: =====\n{}\n=====", s);
514         if is_collapsible {
515             w.write_str(
516                 "<details class=\"toggle top-doc\" open>\
517                 <summary class=\"hideme\">\
518                      <span>Expand description</span>\
519                 </summary>",
520             );
521             render_markdown(w, cx, &s, item.links(cx), heading_offset);
522             w.write_str("</details>");
523         } else {
524             render_markdown(w, cx, &s, item.links(cx), heading_offset);
525         }
526     }
527
528     let kind = match &*item.kind {
529         clean::ItemKind::StrippedItem(box kind) | kind => kind,
530     };
531
532     if let clean::ItemKind::FunctionItem(..) | clean::ItemKind::MethodItem(..) = kind {
533         render_call_locations(w, cx, item);
534     }
535 }
536
537 /// Add extra information about an item such as:
538 ///
539 /// * Stability
540 /// * Deprecated
541 /// * Required features (through the `doc_cfg` feature)
542 fn document_item_info(
543     w: &mut Buffer,
544     cx: &mut Context<'_>,
545     item: &clean::Item,
546     parent: Option<&clean::Item>,
547 ) {
548     let item_infos = short_item_info(item, cx, parent);
549     if !item_infos.is_empty() {
550         w.write_str("<span class=\"item-info\">");
551         for info in item_infos {
552             w.write_str(&info);
553         }
554         w.write_str("</span>");
555     }
556 }
557
558 fn portability(item: &clean::Item, parent: Option<&clean::Item>) -> Option<String> {
559     let cfg = match (&item.cfg, parent.and_then(|p| p.cfg.as_ref())) {
560         (Some(cfg), Some(parent_cfg)) => cfg.simplify_with(parent_cfg),
561         (cfg, _) => cfg.as_deref().cloned(),
562     };
563
564     debug!(
565         "Portability {:?} {:?} (parent: {:?}) - {:?} = {:?}",
566         item.name,
567         item.cfg,
568         parent,
569         parent.and_then(|p| p.cfg.as_ref()),
570         cfg
571     );
572
573     Some(format!("<div class=\"stab portability\">{}</div>", cfg?.render_long_html()))
574 }
575
576 /// Render the stability, deprecation and portability information that is displayed at the top of
577 /// the item's documentation.
578 fn short_item_info(
579     item: &clean::Item,
580     cx: &mut Context<'_>,
581     parent: Option<&clean::Item>,
582 ) -> Vec<String> {
583     let mut extra_info = vec![];
584
585     if let Some(depr @ Deprecation { note, since, is_since_rustc_version: _, suggestion: _ }) =
586         item.deprecation(cx.tcx())
587     {
588         // We display deprecation messages for #[deprecated], but only display
589         // the future-deprecation messages for rustc versions.
590         let mut message = if let Some(since) = since {
591             let since = since.as_str();
592             if !stability::deprecation_in_effect(&depr) {
593                 if since == "TBD" {
594                     String::from("Deprecating in a future Rust version")
595                 } else {
596                     format!("Deprecating in {}", Escape(since))
597                 }
598             } else {
599                 format!("Deprecated since {}", Escape(since))
600             }
601         } else {
602             String::from("Deprecated")
603         };
604
605         if let Some(note) = note {
606             let note = note.as_str();
607             let html = MarkdownItemInfo(note, &mut cx.id_map);
608             message.push_str(&format!(": {}", html.into_string()));
609         }
610         extra_info.push(format!(
611             "<div class=\"stab deprecated\">\
612                  <span class=\"emoji\">👎</span>\
613                  <span>{}</span>\
614              </div>",
615             message,
616         ));
617     }
618
619     // Render unstable items. But don't render "rustc_private" crates (internal compiler crates).
620     // Those crates are permanently unstable so it makes no sense to render "unstable" everywhere.
621     if let Some((StabilityLevel::Unstable { reason: _, issue, .. }, feature)) = item
622         .stability(cx.tcx())
623         .as_ref()
624         .filter(|stab| stab.feature != sym::rustc_private)
625         .map(|stab| (stab.level, stab.feature))
626     {
627         let mut message = "<span class=\"emoji\">🔬</span>\
628              <span>This is a nightly-only experimental API."
629             .to_owned();
630
631         let mut feature = format!("<code>{}</code>", Escape(feature.as_str()));
632         if let (Some(url), Some(issue)) = (&cx.shared.issue_tracker_base_url, issue) {
633             feature.push_str(&format!(
634                 "&nbsp;<a href=\"{url}{issue}\">#{issue}</a>",
635                 url = url,
636                 issue = issue
637             ));
638         }
639
640         message.push_str(&format!(" ({})</span>", feature));
641
642         extra_info.push(format!("<div class=\"stab unstable\">{}</div>", message));
643     }
644
645     if let Some(portability) = portability(item, parent) {
646         extra_info.push(portability);
647     }
648
649     extra_info
650 }
651
652 // Render the list of items inside one of the sections "Trait Implementations",
653 // "Auto Trait Implementations," "Blanket Trait Implementations" (on struct/enum pages).
654 pub(crate) fn render_impls(
655     cx: &mut Context<'_>,
656     w: &mut Buffer,
657     impls: &[&Impl],
658     containing_item: &clean::Item,
659     toggle_open_by_default: bool,
660 ) {
661     let tcx = cx.tcx();
662     let mut rendered_impls = impls
663         .iter()
664         .map(|i| {
665             let did = i.trait_did().unwrap();
666             let provided_trait_methods = i.inner_impl().provided_trait_methods(tcx);
667             let assoc_link = AssocItemLink::GotoSource(did.into(), &provided_trait_methods);
668             let mut buffer = if w.is_for_html() { Buffer::html() } else { Buffer::new() };
669             render_impl(
670                 &mut buffer,
671                 cx,
672                 i,
673                 containing_item,
674                 assoc_link,
675                 RenderMode::Normal,
676                 None,
677                 &[],
678                 ImplRenderingParameters {
679                     show_def_docs: true,
680                     show_default_items: true,
681                     show_non_assoc_items: true,
682                     toggle_open_by_default,
683                 },
684             );
685             buffer.into_inner()
686         })
687         .collect::<Vec<_>>();
688     rendered_impls.sort();
689     w.write_str(&rendered_impls.join(""));
690 }
691
692 /// Build a (possibly empty) `href` attribute (a key-value pair) for the given associated item.
693 fn assoc_href_attr(it: &clean::Item, link: AssocItemLink<'_>, cx: &Context<'_>) -> String {
694     let name = it.name.unwrap();
695     let item_type = it.type_();
696
697     let href = match link {
698         AssocItemLink::Anchor(Some(ref id)) => Some(format!("#{}", id)),
699         AssocItemLink::Anchor(None) => Some(format!("#{}.{}", item_type, name)),
700         AssocItemLink::GotoSource(did, provided_methods) => {
701             // We're creating a link from the implementation of an associated item to its
702             // declaration in the trait declaration.
703             let item_type = match item_type {
704                 // For historical but not technical reasons, the item type of methods in
705                 // trait declarations depends on whether the method is required (`TyMethod`) or
706                 // provided (`Method`).
707                 ItemType::Method | ItemType::TyMethod => {
708                     if provided_methods.contains(&name) {
709                         ItemType::Method
710                     } else {
711                         ItemType::TyMethod
712                     }
713                 }
714                 // For associated types and constants, no such distinction exists.
715                 item_type => item_type,
716             };
717
718             match href(did.expect_def_id(), cx) {
719                 Ok((url, ..)) => Some(format!("{}#{}.{}", url, item_type, name)),
720                 // The link is broken since it points to an external crate that wasn't documented.
721                 // Do not create any link in such case. This is better than falling back to a
722                 // dummy anchor like `#{item_type}.{name}` representing the `id` of *this* impl item
723                 // (that used to happen in older versions). Indeed, in most cases this dummy would
724                 // coincide with the `id`. However, it would not always do so.
725                 // In general, this dummy would be incorrect:
726                 // If the type with the trait impl also had an inherent impl with an assoc. item of
727                 // the *same* name as this impl item, the dummy would link to that one even though
728                 // those two items are distinct!
729                 // In this scenario, the actual `id` of this impl item would be
730                 // `#{item_type}.{name}-{n}` for some number `n` (a disambiguator).
731                 Err(HrefError::DocumentationNotBuilt) => None,
732                 Err(_) => Some(format!("#{}.{}", item_type, name)),
733             }
734         }
735     };
736
737     // If there is no `href` for the reason explained above, simply do not render it which is valid:
738     // https://html.spec.whatwg.org/multipage/links.html#links-created-by-a-and-area-elements
739     href.map(|href| format!(" href=\"{}\"", href)).unwrap_or_default()
740 }
741
742 fn assoc_const(
743     w: &mut Buffer,
744     it: &clean::Item,
745     ty: &clean::Type,
746     default: Option<&clean::ConstantKind>,
747     link: AssocItemLink<'_>,
748     extra: &str,
749     cx: &Context<'_>,
750 ) {
751     let tcx = cx.tcx();
752     write!(
753         w,
754         "{extra}{vis}const <a{href} class=\"constant\">{name}</a>: {ty}",
755         extra = extra,
756         vis = visibility_print_with_space(it.visibility(tcx), it.item_id, cx),
757         href = assoc_href_attr(it, link, cx),
758         name = it.name.as_ref().unwrap(),
759         ty = ty.print(cx),
760     );
761     if let Some(default) = default {
762         write!(w, " = ");
763
764         // FIXME: `.value()` uses `clean::utils::format_integer_with_underscore_sep` under the
765         //        hood which adds noisy underscores and a type suffix to number literals.
766         //        This hurts readability in this context especially when more complex expressions
767         //        are involved and it doesn't add much of value.
768         //        Find a way to print constants here without all that jazz.
769         write!(w, "{}", Escape(&default.value(tcx).unwrap_or_else(|| default.expr(tcx))));
770     }
771 }
772
773 fn assoc_type(
774     w: &mut Buffer,
775     it: &clean::Item,
776     generics: &clean::Generics,
777     bounds: &[clean::GenericBound],
778     default: Option<&clean::Type>,
779     link: AssocItemLink<'_>,
780     indent: usize,
781     cx: &Context<'_>,
782 ) {
783     write!(
784         w,
785         "{indent}type <a{href} class=\"associatedtype\">{name}</a>{generics}",
786         indent = " ".repeat(indent),
787         href = assoc_href_attr(it, link, cx),
788         name = it.name.as_ref().unwrap(),
789         generics = generics.print(cx),
790     );
791     if !bounds.is_empty() {
792         write!(w, ": {}", print_generic_bounds(bounds, cx))
793     }
794     write!(w, "{}", print_where_clause(generics, cx, indent, Ending::NoNewline));
795     if let Some(default) = default {
796         write!(w, " = {}", default.print(cx))
797     }
798 }
799
800 fn assoc_method(
801     w: &mut Buffer,
802     meth: &clean::Item,
803     g: &clean::Generics,
804     d: &clean::FnDecl,
805     link: AssocItemLink<'_>,
806     parent: ItemType,
807     cx: &mut Context<'_>,
808     render_mode: RenderMode,
809 ) {
810     let tcx = cx.tcx();
811     let header = meth.fn_header(tcx).expect("Trying to get header from a non-function item");
812     let name = meth.name.as_ref().unwrap();
813     let vis = visibility_print_with_space(meth.visibility(tcx), meth.item_id, cx).to_string();
814     // FIXME: Once https://github.com/rust-lang/rust/issues/67792 is implemented, we can remove
815     // this condition.
816     let constness = match render_mode {
817         RenderMode::Normal => {
818             print_constness_with_space(&header.constness, meth.const_stability(tcx))
819         }
820         RenderMode::ForDeref { .. } => "",
821     };
822     let asyncness = header.asyncness.print_with_space();
823     let unsafety = header.unsafety.print_with_space();
824     let defaultness = print_default_space(meth.is_default());
825     let abi = print_abi_with_space(header.abi).to_string();
826     let href = assoc_href_attr(meth, link, cx);
827
828     // NOTE: `{:#}` does not print HTML formatting, `{}` does. So `g.print` can't be reused between the length calculation and `write!`.
829     let generics_len = format!("{:#}", g.print(cx)).len();
830     let mut header_len = "fn ".len()
831         + vis.len()
832         + constness.len()
833         + asyncness.len()
834         + unsafety.len()
835         + defaultness.len()
836         + abi.len()
837         + name.as_str().len()
838         + generics_len;
839
840     let notable_traits = d.output.as_return().and_then(|output| notable_traits_button(output, cx));
841
842     let (indent, indent_str, end_newline) = if parent == ItemType::Trait {
843         header_len += 4;
844         let indent_str = "    ";
845         render_attributes_in_pre(w, meth, indent_str);
846         (4, indent_str, Ending::NoNewline)
847     } else {
848         render_attributes_in_code(w, meth);
849         (0, "", Ending::Newline)
850     };
851     w.reserve(header_len + "<a href=\"\" class=\"fn\">{".len() + "</a>".len());
852     write!(
853         w,
854         "{indent}{vis}{constness}{asyncness}{unsafety}{defaultness}{abi}fn <a{href} class=\"fn\">{name}</a>\
855          {generics}{decl}{notable_traits}{where_clause}",
856         indent = indent_str,
857         vis = vis,
858         constness = constness,
859         asyncness = asyncness,
860         unsafety = unsafety,
861         defaultness = defaultness,
862         abi = abi,
863         href = href,
864         name = name,
865         generics = g.print(cx),
866         decl = d.full_print(header_len, indent, cx),
867         notable_traits = notable_traits.unwrap_or_default(),
868         where_clause = print_where_clause(g, cx, indent, end_newline),
869     );
870 }
871
872 /// Writes a span containing the versions at which an item became stable and/or const-stable. For
873 /// example, if the item became stable at 1.0.0, and const-stable at 1.45.0, this function would
874 /// write a span containing "1.0.0 (const: 1.45.0)".
875 ///
876 /// Returns `true` if a stability annotation was rendered.
877 ///
878 /// Stability and const-stability are considered separately. If the item is unstable, no version
879 /// will be written. If the item is const-unstable, "const: unstable" will be appended to the
880 /// span, with a link to the tracking issue if present. If an item's stability or const-stability
881 /// version matches the version of its enclosing item, that version will be omitted.
882 ///
883 /// Note that it is possible for an unstable function to be const-stable. In that case, the span
884 /// will include the const-stable version, but no stable version will be emitted, as a natural
885 /// consequence of the above rules.
886 fn render_stability_since_raw_with_extra(
887     w: &mut Buffer,
888     ver: Option<Symbol>,
889     const_stability: Option<ConstStability>,
890     containing_ver: Option<Symbol>,
891     containing_const_ver: Option<Symbol>,
892     extra_class: &str,
893 ) -> bool {
894     let stable_version = ver.filter(|inner| !inner.is_empty() && Some(*inner) != containing_ver);
895
896     let mut title = String::new();
897     let mut stability = String::new();
898
899     if let Some(ver) = stable_version {
900         stability.push_str(ver.as_str());
901         title.push_str(&format!("Stable since Rust version {}", ver));
902     }
903
904     let const_title_and_stability = match const_stability {
905         Some(ConstStability { level: StabilityLevel::Stable { since, .. }, .. })
906             if Some(since) != containing_const_ver =>
907         {
908             Some((format!("const since {}", since), format!("const: {}", since)))
909         }
910         Some(ConstStability { level: StabilityLevel::Unstable { issue, .. }, feature, .. }) => {
911             let unstable = if let Some(n) = issue {
912                 format!(
913                     r#"<a href="https://github.com/rust-lang/rust/issues/{}" title="Tracking issue for {}">unstable</a>"#,
914                     n, feature
915                 )
916             } else {
917                 String::from("unstable")
918             };
919
920             Some((String::from("const unstable"), format!("const: {}", unstable)))
921         }
922         _ => None,
923     };
924
925     if let Some((const_title, const_stability)) = const_title_and_stability {
926         if !title.is_empty() {
927             title.push_str(&format!(", {}", const_title));
928         } else {
929             title.push_str(&const_title);
930         }
931
932         if !stability.is_empty() {
933             stability.push_str(&format!(" ({})", const_stability));
934         } else {
935             stability.push_str(&const_stability);
936         }
937     }
938
939     if !stability.is_empty() {
940         write!(w, r#"<span class="since{extra_class}" title="{title}">{stability}</span>"#);
941     }
942
943     !stability.is_empty()
944 }
945
946 #[inline]
947 fn render_stability_since_raw(
948     w: &mut Buffer,
949     ver: Option<Symbol>,
950     const_stability: Option<ConstStability>,
951     containing_ver: Option<Symbol>,
952     containing_const_ver: Option<Symbol>,
953 ) -> bool {
954     render_stability_since_raw_with_extra(
955         w,
956         ver,
957         const_stability,
958         containing_ver,
959         containing_const_ver,
960         "",
961     )
962 }
963
964 fn render_assoc_item(
965     w: &mut Buffer,
966     item: &clean::Item,
967     link: AssocItemLink<'_>,
968     parent: ItemType,
969     cx: &mut Context<'_>,
970     render_mode: RenderMode,
971 ) {
972     match &*item.kind {
973         clean::StrippedItem(..) => {}
974         clean::TyMethodItem(m) => {
975             assoc_method(w, item, &m.generics, &m.decl, link, parent, cx, render_mode)
976         }
977         clean::MethodItem(m, _) => {
978             assoc_method(w, item, &m.generics, &m.decl, link, parent, cx, render_mode)
979         }
980         kind @ (clean::TyAssocConstItem(ty) | clean::AssocConstItem(ty, _)) => assoc_const(
981             w,
982             item,
983             ty,
984             match kind {
985                 clean::TyAssocConstItem(_) => None,
986                 clean::AssocConstItem(_, default) => Some(default),
987                 _ => unreachable!(),
988             },
989             link,
990             if parent == ItemType::Trait { "    " } else { "" },
991             cx,
992         ),
993         clean::TyAssocTypeItem(ref generics, ref bounds) => assoc_type(
994             w,
995             item,
996             generics,
997             bounds,
998             None,
999             link,
1000             if parent == ItemType::Trait { 4 } else { 0 },
1001             cx,
1002         ),
1003         clean::AssocTypeItem(ref ty, ref bounds) => assoc_type(
1004             w,
1005             item,
1006             &ty.generics,
1007             bounds,
1008             Some(ty.item_type.as_ref().unwrap_or(&ty.type_)),
1009             link,
1010             if parent == ItemType::Trait { 4 } else { 0 },
1011             cx,
1012         ),
1013         _ => panic!("render_assoc_item called on non-associated-item"),
1014     }
1015 }
1016
1017 const ALLOWED_ATTRIBUTES: &[Symbol] =
1018     &[sym::export_name, sym::link_section, sym::no_mangle, sym::repr, sym::non_exhaustive];
1019
1020 fn attributes(it: &clean::Item) -> Vec<String> {
1021     it.attrs
1022         .other_attrs
1023         .iter()
1024         .filter_map(|attr| {
1025             if ALLOWED_ATTRIBUTES.contains(&attr.name_or_empty()) {
1026                 Some(
1027                     pprust::attribute_to_string(attr)
1028                         .replace("\\\n", "")
1029                         .replace('\n', "")
1030                         .replace("  ", " "),
1031                 )
1032             } else {
1033                 None
1034             }
1035         })
1036         .collect()
1037 }
1038
1039 // When an attribute is rendered inside a `<pre>` tag, it is formatted using
1040 // a whitespace prefix and newline.
1041 fn render_attributes_in_pre(w: &mut Buffer, it: &clean::Item, prefix: &str) {
1042     for a in attributes(it) {
1043         writeln!(w, "{}{}", prefix, a);
1044     }
1045 }
1046
1047 // When an attribute is rendered inside a <code> tag, it is formatted using
1048 // a div to produce a newline after it.
1049 fn render_attributes_in_code(w: &mut Buffer, it: &clean::Item) {
1050     for a in attributes(it) {
1051         write!(w, "<div class=\"code-attribute\">{}</div>", a);
1052     }
1053 }
1054
1055 #[derive(Copy, Clone)]
1056 enum AssocItemLink<'a> {
1057     Anchor(Option<&'a str>),
1058     GotoSource(ItemId, &'a FxHashSet<Symbol>),
1059 }
1060
1061 impl<'a> AssocItemLink<'a> {
1062     fn anchor(&self, id: &'a str) -> Self {
1063         match *self {
1064             AssocItemLink::Anchor(_) => AssocItemLink::Anchor(Some(id)),
1065             ref other => *other,
1066         }
1067     }
1068 }
1069
1070 fn write_impl_section_heading(w: &mut Buffer, title: &str, id: &str) {
1071     write!(
1072         w,
1073         "<h2 id=\"{id}\" class=\"small-section-header\">\
1074             {title}\
1075             <a href=\"#{id}\" class=\"anchor\">§</a>\
1076          </h2>"
1077     );
1078 }
1079
1080 pub(crate) fn render_all_impls(
1081     w: &mut Buffer,
1082     cx: &mut Context<'_>,
1083     containing_item: &clean::Item,
1084     concrete: &[&Impl],
1085     synthetic: &[&Impl],
1086     blanket_impl: &[&Impl],
1087 ) {
1088     let mut impls = Buffer::empty_from(w);
1089     render_impls(cx, &mut impls, concrete, containing_item, true);
1090     let impls = impls.into_inner();
1091     if !impls.is_empty() {
1092         write_impl_section_heading(w, "Trait Implementations", "trait-implementations");
1093         write!(w, "<div id=\"trait-implementations-list\">{}</div>", impls);
1094     }
1095
1096     if !synthetic.is_empty() {
1097         write_impl_section_heading(w, "Auto Trait Implementations", "synthetic-implementations");
1098         w.write_str("<div id=\"synthetic-implementations-list\">");
1099         render_impls(cx, w, synthetic, containing_item, false);
1100         w.write_str("</div>");
1101     }
1102
1103     if !blanket_impl.is_empty() {
1104         write_impl_section_heading(w, "Blanket Implementations", "blanket-implementations");
1105         w.write_str("<div id=\"blanket-implementations-list\">");
1106         render_impls(cx, w, blanket_impl, containing_item, false);
1107         w.write_str("</div>");
1108     }
1109 }
1110
1111 fn render_assoc_items(
1112     w: &mut Buffer,
1113     cx: &mut Context<'_>,
1114     containing_item: &clean::Item,
1115     it: DefId,
1116     what: AssocItemRender<'_>,
1117 ) {
1118     let mut derefs = DefIdSet::default();
1119     derefs.insert(it);
1120     render_assoc_items_inner(w, cx, containing_item, it, what, &mut derefs)
1121 }
1122
1123 fn render_assoc_items_inner(
1124     w: &mut Buffer,
1125     cx: &mut Context<'_>,
1126     containing_item: &clean::Item,
1127     it: DefId,
1128     what: AssocItemRender<'_>,
1129     derefs: &mut DefIdSet,
1130 ) {
1131     info!("Documenting associated items of {:?}", containing_item.name);
1132     let shared = Rc::clone(&cx.shared);
1133     let cache = &shared.cache;
1134     let Some(v) = cache.impls.get(&it) else { return };
1135     let (non_trait, traits): (Vec<_>, _) = v.iter().partition(|i| i.inner_impl().trait_.is_none());
1136     if !non_trait.is_empty() {
1137         let mut tmp_buf = Buffer::empty_from(w);
1138         let (render_mode, id) = match what {
1139             AssocItemRender::All => {
1140                 write_impl_section_heading(&mut tmp_buf, "Implementations", "implementations");
1141                 (RenderMode::Normal, "implementations-list".to_owned())
1142             }
1143             AssocItemRender::DerefFor { trait_, type_, deref_mut_ } => {
1144                 let id =
1145                     cx.derive_id(small_url_encode(format!("deref-methods-{:#}", type_.print(cx))));
1146                 if let Some(def_id) = type_.def_id(cx.cache()) {
1147                     cx.deref_id_map.insert(def_id, id.clone());
1148                 }
1149                 write_impl_section_heading(
1150                     &mut tmp_buf,
1151                     &format!(
1152                         "<span>Methods from {trait_}&lt;Target = {type_}&gt;</span>",
1153                         trait_ = trait_.print(cx),
1154                         type_ = type_.print(cx),
1155                     ),
1156                     &id,
1157                 );
1158                 (RenderMode::ForDeref { mut_: deref_mut_ }, cx.derive_id(id))
1159             }
1160         };
1161         let mut impls_buf = Buffer::empty_from(w);
1162         for i in &non_trait {
1163             render_impl(
1164                 &mut impls_buf,
1165                 cx,
1166                 i,
1167                 containing_item,
1168                 AssocItemLink::Anchor(None),
1169                 render_mode,
1170                 None,
1171                 &[],
1172                 ImplRenderingParameters {
1173                     show_def_docs: true,
1174                     show_default_items: true,
1175                     show_non_assoc_items: true,
1176                     toggle_open_by_default: true,
1177                 },
1178             );
1179         }
1180         if !impls_buf.is_empty() {
1181             w.push_buffer(tmp_buf);
1182             write!(w, "<div id=\"{}\">", id);
1183             w.push_buffer(impls_buf);
1184             w.write_str("</div>");
1185         }
1186     }
1187
1188     if !traits.is_empty() {
1189         let deref_impl =
1190             traits.iter().find(|t| t.trait_did() == cx.tcx().lang_items().deref_trait());
1191         if let Some(impl_) = deref_impl {
1192             let has_deref_mut =
1193                 traits.iter().any(|t| t.trait_did() == cx.tcx().lang_items().deref_mut_trait());
1194             render_deref_methods(w, cx, impl_, containing_item, has_deref_mut, derefs);
1195         }
1196
1197         // If we were already one level into rendering deref methods, we don't want to render
1198         // anything after recursing into any further deref methods above.
1199         if let AssocItemRender::DerefFor { .. } = what {
1200             return;
1201         }
1202
1203         let (synthetic, concrete): (Vec<&Impl>, Vec<&Impl>) =
1204             traits.into_iter().partition(|t| t.inner_impl().kind.is_auto());
1205         let (blanket_impl, concrete): (Vec<&Impl>, _) =
1206             concrete.into_iter().partition(|t| t.inner_impl().kind.is_blanket());
1207
1208         render_all_impls(w, cx, containing_item, &concrete, &synthetic, &blanket_impl);
1209     }
1210 }
1211
1212 fn render_deref_methods(
1213     w: &mut Buffer,
1214     cx: &mut Context<'_>,
1215     impl_: &Impl,
1216     container_item: &clean::Item,
1217     deref_mut: bool,
1218     derefs: &mut DefIdSet,
1219 ) {
1220     let cache = cx.cache();
1221     let deref_type = impl_.inner_impl().trait_.as_ref().unwrap();
1222     let (target, real_target) = impl_
1223         .inner_impl()
1224         .items
1225         .iter()
1226         .find_map(|item| match *item.kind {
1227             clean::AssocTypeItem(box ref t, _) => Some(match *t {
1228                 clean::Typedef { item_type: Some(ref type_), .. } => (type_, &t.type_),
1229                 _ => (&t.type_, &t.type_),
1230             }),
1231             _ => None,
1232         })
1233         .expect("Expected associated type binding");
1234     debug!("Render deref methods for {:#?}, target {:#?}", impl_.inner_impl().for_, target);
1235     let what =
1236         AssocItemRender::DerefFor { trait_: deref_type, type_: real_target, deref_mut_: deref_mut };
1237     if let Some(did) = target.def_id(cache) {
1238         if let Some(type_did) = impl_.inner_impl().for_.def_id(cache) {
1239             // `impl Deref<Target = S> for S`
1240             if did == type_did || !derefs.insert(did) {
1241                 // Avoid infinite cycles
1242                 return;
1243             }
1244         }
1245         render_assoc_items_inner(w, cx, container_item, did, what, derefs);
1246     } else if let Some(prim) = target.primitive_type() {
1247         if let Some(&did) = cache.primitive_locations.get(&prim) {
1248             render_assoc_items_inner(w, cx, container_item, did, what, derefs);
1249         }
1250     }
1251 }
1252
1253 fn should_render_item(item: &clean::Item, deref_mut_: bool, tcx: TyCtxt<'_>) -> bool {
1254     let self_type_opt = match *item.kind {
1255         clean::MethodItem(ref method, _) => method.decl.self_type(),
1256         clean::TyMethodItem(ref method) => method.decl.self_type(),
1257         _ => None,
1258     };
1259
1260     if let Some(self_ty) = self_type_opt {
1261         let (by_mut_ref, by_box, by_value) = match self_ty {
1262             SelfTy::SelfBorrowed(_, mutability)
1263             | SelfTy::SelfExplicit(clean::BorrowedRef { mutability, .. }) => {
1264                 (mutability == Mutability::Mut, false, false)
1265             }
1266             SelfTy::SelfExplicit(clean::Type::Path { path }) => {
1267                 (false, Some(path.def_id()) == tcx.lang_items().owned_box(), false)
1268             }
1269             SelfTy::SelfValue => (false, false, true),
1270             _ => (false, false, false),
1271         };
1272
1273         (deref_mut_ || !by_mut_ref) && !by_box && !by_value
1274     } else {
1275         false
1276     }
1277 }
1278
1279 pub(crate) fn notable_traits_button(ty: &clean::Type, cx: &mut Context<'_>) -> Option<String> {
1280     let mut has_notable_trait = false;
1281
1282     let did = ty.def_id(cx.cache())?;
1283
1284     // Box has pass-through impls for Read, Write, Iterator, and Future when the
1285     // boxed type implements one of those. We don't want to treat every Box return
1286     // as being notably an Iterator (etc), though, so we exempt it. Pin has the same
1287     // issue, with a pass-through impl for Future.
1288     if Some(did) == cx.tcx().lang_items().owned_box()
1289         || Some(did) == cx.tcx().lang_items().pin_type()
1290     {
1291         return None;
1292     }
1293
1294     if let Some(impls) = cx.cache().impls.get(&did) {
1295         for i in impls {
1296             let impl_ = i.inner_impl();
1297             if !impl_.for_.without_borrowed_ref().is_same(ty.without_borrowed_ref(), cx.cache()) {
1298                 // Two different types might have the same did,
1299                 // without actually being the same.
1300                 continue;
1301             }
1302             if let Some(trait_) = &impl_.trait_ {
1303                 let trait_did = trait_.def_id();
1304
1305                 if cx.cache().traits.get(&trait_did).map_or(false, |t| t.is_notable_trait(cx.tcx()))
1306                 {
1307                     has_notable_trait = true;
1308                 }
1309             }
1310         }
1311     }
1312
1313     if has_notable_trait {
1314         cx.types_with_notable_traits.insert(ty.clone());
1315         Some(format!(
1316             " <a href=\"#\" class=\"notable-traits\" data-ty=\"{ty}\">ⓘ</a>",
1317             ty = Escape(&format!("{:#}", ty.print(cx))),
1318         ))
1319     } else {
1320         None
1321     }
1322 }
1323
1324 fn notable_traits_decl(ty: &clean::Type, cx: &Context<'_>) -> (String, String) {
1325     let mut out = Buffer::html();
1326
1327     let did = ty.def_id(cx.cache()).expect("notable_traits_button already checked this");
1328
1329     let impls = cx.cache().impls.get(&did).expect("notable_traits_button already checked this");
1330
1331     for i in impls {
1332         let impl_ = i.inner_impl();
1333         if !impl_.for_.without_borrowed_ref().is_same(ty.without_borrowed_ref(), cx.cache()) {
1334             // Two different types might have the same did,
1335             // without actually being the same.
1336             continue;
1337         }
1338         if let Some(trait_) = &impl_.trait_ {
1339             let trait_did = trait_.def_id();
1340
1341             if cx.cache().traits.get(&trait_did).map_or(false, |t| t.is_notable_trait(cx.tcx())) {
1342                 if out.is_empty() {
1343                     write!(
1344                         &mut out,
1345                         "<h3>Notable traits for <code>{}</code></h3>\
1346                      <pre><code>",
1347                         impl_.for_.print(cx)
1348                     );
1349                 }
1350
1351                 //use the "where" class here to make it small
1352                 write!(
1353                     &mut out,
1354                     "<span class=\"where fmt-newline\">{}</span>",
1355                     impl_.print(false, cx)
1356                 );
1357                 for it in &impl_.items {
1358                     if let clean::AssocTypeItem(ref tydef, ref _bounds) = *it.kind {
1359                         out.push_str("<span class=\"where fmt-newline\">    ");
1360                         let empty_set = FxHashSet::default();
1361                         let src_link = AssocItemLink::GotoSource(trait_did.into(), &empty_set);
1362                         assoc_type(
1363                             &mut out,
1364                             it,
1365                             &tydef.generics,
1366                             &[], // intentionally leaving out bounds
1367                             Some(&tydef.type_),
1368                             src_link,
1369                             0,
1370                             cx,
1371                         );
1372                         out.push_str(";</span>");
1373                     }
1374                 }
1375             }
1376         }
1377     }
1378     if out.is_empty() {
1379         write!(&mut out, "</code></pre>",);
1380     }
1381
1382     (format!("{:#}", ty.print(cx)), out.into_inner())
1383 }
1384
1385 pub(crate) fn notable_traits_json<'a>(
1386     tys: impl Iterator<Item = &'a clean::Type>,
1387     cx: &Context<'_>,
1388 ) -> String {
1389     let mut mp: Vec<(String, String)> = tys.map(|ty| notable_traits_decl(ty, cx)).collect();
1390     mp.sort_by(|(name1, _html1), (name2, _html2)| name1.cmp(name2));
1391     struct NotableTraitsMap(Vec<(String, String)>);
1392     impl Serialize for NotableTraitsMap {
1393         fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1394         where
1395             S: Serializer,
1396         {
1397             let mut map = serializer.serialize_map(Some(self.0.len()))?;
1398             for item in &self.0 {
1399                 map.serialize_entry(&item.0, &item.1)?;
1400             }
1401             map.end()
1402         }
1403     }
1404     serde_json::to_string(&NotableTraitsMap(mp))
1405         .expect("serialize (string, string) -> json object cannot fail")
1406 }
1407
1408 #[derive(Clone, Copy, Debug)]
1409 struct ImplRenderingParameters {
1410     show_def_docs: bool,
1411     show_default_items: bool,
1412     /// Whether or not to show methods.
1413     show_non_assoc_items: bool,
1414     toggle_open_by_default: bool,
1415 }
1416
1417 fn render_impl(
1418     w: &mut Buffer,
1419     cx: &mut Context<'_>,
1420     i: &Impl,
1421     parent: &clean::Item,
1422     link: AssocItemLink<'_>,
1423     render_mode: RenderMode,
1424     use_absolute: Option<bool>,
1425     aliases: &[String],
1426     rendering_params: ImplRenderingParameters,
1427 ) {
1428     let shared = Rc::clone(&cx.shared);
1429     let cache = &shared.cache;
1430     let traits = &cache.traits;
1431     let trait_ = i.trait_did().map(|did| &traits[&did]);
1432     let mut close_tags = String::new();
1433
1434     // For trait implementations, the `interesting` output contains all methods that have doc
1435     // comments, and the `boring` output contains all methods that do not. The distinction is
1436     // used to allow hiding the boring methods.
1437     // `containing_item` is used for rendering stability info. If the parent is a trait impl,
1438     // `containing_item` will the grandparent, since trait impls can't have stability attached.
1439     fn doc_impl_item(
1440         boring: &mut Buffer,
1441         interesting: &mut Buffer,
1442         cx: &mut Context<'_>,
1443         item: &clean::Item,
1444         parent: &clean::Item,
1445         containing_item: &clean::Item,
1446         link: AssocItemLink<'_>,
1447         render_mode: RenderMode,
1448         is_default_item: bool,
1449         trait_: Option<&clean::Trait>,
1450         rendering_params: ImplRenderingParameters,
1451     ) {
1452         let item_type = item.type_();
1453         let name = item.name.as_ref().unwrap();
1454
1455         let render_method_item = rendering_params.show_non_assoc_items
1456             && match render_mode {
1457                 RenderMode::Normal => true,
1458                 RenderMode::ForDeref { mut_: deref_mut_ } => {
1459                     should_render_item(item, deref_mut_, cx.tcx())
1460                 }
1461             };
1462
1463         let in_trait_class = if trait_.is_some() { " trait-impl" } else { "" };
1464
1465         let mut doc_buffer = Buffer::empty_from(boring);
1466         let mut info_buffer = Buffer::empty_from(boring);
1467         let mut short_documented = true;
1468
1469         if render_method_item {
1470             if !is_default_item {
1471                 if let Some(t) = trait_ {
1472                     // The trait item may have been stripped so we might not
1473                     // find any documentation or stability for it.
1474                     if let Some(it) = t.items.iter().find(|i| i.name == item.name) {
1475                         // We need the stability of the item from the trait
1476                         // because impls can't have a stability.
1477                         if item.doc_value().is_some() {
1478                             document_item_info(&mut info_buffer, cx, it, Some(parent));
1479                             document_full(&mut doc_buffer, item, cx, HeadingOffset::H5);
1480                             short_documented = false;
1481                         } else {
1482                             // In case the item isn't documented,
1483                             // provide short documentation from the trait.
1484                             document_short(
1485                                 &mut doc_buffer,
1486                                 it,
1487                                 cx,
1488                                 link,
1489                                 parent,
1490                                 rendering_params.show_def_docs,
1491                             );
1492                         }
1493                     }
1494                 } else {
1495                     document_item_info(&mut info_buffer, cx, item, Some(parent));
1496                     if rendering_params.show_def_docs {
1497                         document_full(&mut doc_buffer, item, cx, HeadingOffset::H5);
1498                         short_documented = false;
1499                     }
1500                 }
1501             } else {
1502                 document_short(
1503                     &mut doc_buffer,
1504                     item,
1505                     cx,
1506                     link,
1507                     parent,
1508                     rendering_params.show_def_docs,
1509                 );
1510             }
1511         }
1512         let w = if short_documented && trait_.is_some() { interesting } else { boring };
1513
1514         let toggled = !doc_buffer.is_empty();
1515         if toggled {
1516             let method_toggle_class = if item_type.is_method() { " method-toggle" } else { "" };
1517             write!(w, "<details class=\"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=\"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 = DefIdSet::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 DefIdSet,
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.ctor_kind {
2284             None => {
2285                 print_sidebar_block(&mut sidebar, "fields", "Fields", fields.iter());
2286             }
2287             Some(CtorKind::Fn) => print_sidebar_title(&mut sidebar, "fields", "Tuple Fields"),
2288             Some(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);
2773         let fqp = cache.exact_paths.get(&did).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#"<button class="prev">&pr;</button> <button class="next">&sc;</button>"#);
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()?;
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. We instead proxy relevance with the following heuristics:
2961     //   1. Code written to be an example is better than code not written to be an example, e.g.
2962     //      a snippet from examples/foo.rs is better than src/lib.rs. We don't know the Cargo
2963     //      directory structure in Rustdoc, so we proxy this by prioritizing code that comes from
2964     //      a --crate-type bin.
2965     //   2. Smaller examples are better than large examples. So we prioritize snippets that have
2966     //      the smallest number of lines in their enclosing item.
2967     //   3. Finally we sort by the displayed file name, which is arbitrary but prevents the
2968     //      ordering of examples from randomly changing between Rustdoc invocations.
2969     let ordered_locations = {
2970         fn sort_criterion<'a>(
2971             (_, call_data): &(&PathBuf, &'a CallData),
2972         ) -> (bool, u32, &'a String) {
2973             // Use the first location because that's what the user will see initially
2974             let (lo, hi) = call_data.locations[0].enclosing_item.byte_span;
2975             (!call_data.is_bin, hi - lo, &call_data.display_name)
2976         }
2977
2978         let mut locs = call_locations.iter().collect::<Vec<_>>();
2979         locs.sort_by_key(sort_criterion);
2980         locs
2981     };
2982
2983     let mut it = ordered_locations.into_iter().peekable();
2984
2985     // An example may fail to write if its source can't be read for some reason, so this method
2986     // continues iterating until a write succeeds
2987     let write_and_skip_failure = |w: &mut Buffer, it: &mut Peekable<_>| {
2988         while let Some(example) = it.next() {
2989             if write_example(&mut *w, example) {
2990                 break;
2991             }
2992         }
2993     };
2994
2995     // Write just one example that's visible by default in the method's description.
2996     write_and_skip_failure(w, &mut it);
2997
2998     // Then add the remaining examples in a hidden section.
2999     if it.peek().is_some() {
3000         write!(
3001             w,
3002             "<details class=\"toggle more-examples-toggle\">\
3003                   <summary class=\"hideme\">\
3004                      <span>More examples</span>\
3005                   </summary>\
3006                   <div class=\"hide-more\">Hide additional examples</div>\
3007                   <div class=\"more-scraped-examples\">\
3008                     <div class=\"toggle-line\"><div class=\"toggle-line-inner\"></div></div>"
3009         );
3010
3011         // Only generate inline code for MAX_FULL_EXAMPLES number of examples. Otherwise we could
3012         // make the page arbitrarily huge!
3013         for _ in 0..MAX_FULL_EXAMPLES {
3014             write_and_skip_failure(w, &mut it);
3015         }
3016
3017         // For the remaining examples, generate a <ul> containing links to the source files.
3018         if it.peek().is_some() {
3019             write!(w, r#"<div class="example-links">Additional examples can be found in:<br><ul>"#);
3020             it.for_each(|(_, call_data)| {
3021                 let (url, _) = link_to_loc(call_data, &call_data.locations[0]);
3022                 write!(
3023                     w,
3024                     r#"<li><a href="{url}">{name}</a></li>"#,
3025                     url = url,
3026                     name = call_data.display_name
3027                 );
3028             });
3029             write!(w, "</ul></div>");
3030         }
3031
3032         write!(w, "</div></details>");
3033     }
3034
3035     write!(w, "</div>");
3036 }