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