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