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