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