]> git.lizzy.rs Git - rust.git/blob - src/librustdoc/html/render/mod.rs
Rollup merge of #84444 - notriddle:num-docs-from-undocumented-items-toggle, r=yaahc
[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 crate mod cache;
27
28 #[cfg(test)]
29 mod tests;
30
31 mod context;
32 mod print_item;
33 mod write_shared;
34
35 crate use context::*;
36 crate use write_shared::FILES_UNVERSIONED;
37
38 use std::collections::VecDeque;
39 use std::default::Default;
40 use std::fmt;
41 use std::path::PathBuf;
42 use std::str;
43 use std::string::ToString;
44
45 use rustc_ast_pretty::pprust;
46 use rustc_attr::{Deprecation, StabilityLevel};
47 use rustc_data_structures::fx::FxHashSet;
48 use rustc_hir as hir;
49 use rustc_hir::def::CtorKind;
50 use rustc_hir::def_id::DefId;
51 use rustc_hir::Mutability;
52 use rustc_middle::middle::stability;
53 use rustc_span::symbol::{kw, sym, Symbol};
54 use serde::ser::SerializeSeq;
55 use serde::{Serialize, Serializer};
56
57 use crate::clean::{self, GetDefId, RenderedLink, SelfTy, TypeKind};
58 use crate::docfs::PathError;
59 use crate::error::Error;
60 use crate::formats::cache::Cache;
61 use crate::formats::item_type::ItemType;
62 use crate::formats::{AssocItemRender, Impl, RenderMode};
63 use crate::html::escape::Escape;
64 use crate::html::format::{
65     href, print_abi_with_space, print_default_space, print_generic_bounds, print_where_clause,
66     Buffer, PrintWithSpace,
67 };
68 use crate::html::markdown::{Markdown, MarkdownHtml, MarkdownSummaryLine};
69
70 /// A pair of name and its optional document.
71 crate type NameDoc = (String, Option<String>);
72
73 crate fn ensure_trailing_slash(v: &str) -> impl fmt::Display + '_ {
74     crate::html::format::display_fn(move |f| {
75         if !v.ends_with('/') && !v.is_empty() { write!(f, "{}/", v) } else { f.write_str(v) }
76     })
77 }
78
79 // Helper structs for rendering items/sidebars and carrying along contextual
80 // information
81
82 /// Struct representing one entry in the JS search index. These are all emitted
83 /// by hand to a large JS file at the end of cache-creation.
84 #[derive(Debug)]
85 crate struct IndexItem {
86     crate ty: ItemType,
87     crate name: String,
88     crate path: String,
89     crate desc: String,
90     crate parent: Option<DefId>,
91     crate parent_idx: Option<usize>,
92     crate search_type: Option<IndexItemFunctionType>,
93     crate aliases: Box<[String]>,
94 }
95
96 /// A type used for the search index.
97 #[derive(Debug)]
98 crate struct RenderType {
99     ty: Option<DefId>,
100     idx: Option<usize>,
101     name: Option<String>,
102     generics: Option<Vec<Generic>>,
103 }
104
105 impl Serialize for RenderType {
106     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
107     where
108         S: Serializer,
109     {
110         if let Some(name) = &self.name {
111             let mut seq = serializer.serialize_seq(None)?;
112             if let Some(id) = self.idx {
113                 seq.serialize_element(&id)?;
114             } else {
115                 seq.serialize_element(&name)?;
116             }
117             if let Some(generics) = &self.generics {
118                 seq.serialize_element(&generics)?;
119             }
120             seq.end()
121         } else {
122             serializer.serialize_none()
123         }
124     }
125 }
126
127 /// A type used for the search index.
128 #[derive(Debug)]
129 crate struct Generic {
130     name: String,
131     defid: Option<DefId>,
132     idx: Option<usize>,
133 }
134
135 impl Serialize for Generic {
136     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
137     where
138         S: Serializer,
139     {
140         if let Some(id) = self.idx {
141             serializer.serialize_some(&id)
142         } else {
143             serializer.serialize_some(&self.name)
144         }
145     }
146 }
147
148 /// Full type of functions/methods in the search index.
149 #[derive(Debug)]
150 crate struct IndexItemFunctionType {
151     inputs: Vec<TypeWithKind>,
152     output: Option<Vec<TypeWithKind>>,
153 }
154
155 impl Serialize for IndexItemFunctionType {
156     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
157     where
158         S: Serializer,
159     {
160         // If we couldn't figure out a type, just write `null`.
161         let mut iter = self.inputs.iter();
162         if match self.output {
163             Some(ref output) => iter.chain(output.iter()).any(|ref i| i.ty.name.is_none()),
164             None => iter.any(|ref i| i.ty.name.is_none()),
165         } {
166             serializer.serialize_none()
167         } else {
168             let mut seq = serializer.serialize_seq(None)?;
169             seq.serialize_element(&self.inputs)?;
170             if let Some(output) = &self.output {
171                 if output.len() > 1 {
172                     seq.serialize_element(&output)?;
173                 } else {
174                     seq.serialize_element(&output[0])?;
175                 }
176             }
177             seq.end()
178         }
179     }
180 }
181
182 #[derive(Debug)]
183 crate struct TypeWithKind {
184     ty: RenderType,
185     kind: TypeKind,
186 }
187
188 impl From<(RenderType, TypeKind)> for TypeWithKind {
189     fn from(x: (RenderType, TypeKind)) -> TypeWithKind {
190         TypeWithKind { ty: x.0, kind: x.1 }
191     }
192 }
193
194 impl Serialize for TypeWithKind {
195     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
196     where
197         S: Serializer,
198     {
199         (&self.ty.name, ItemType::from(self.kind)).serialize(serializer)
200     }
201 }
202
203 #[derive(Debug, Clone)]
204 crate struct StylePath {
205     /// The path to the theme
206     crate path: PathBuf,
207     /// What the `disabled` attribute should be set to in the HTML tag
208     crate disabled: bool,
209 }
210
211 fn write_srclink(cx: &Context<'_>, item: &clean::Item, buf: &mut Buffer) {
212     if let Some(l) = cx.src_href(item) {
213         write!(buf, "<a class=\"srclink\" href=\"{}\" title=\"goto source code\">[src]</a>", l)
214     }
215 }
216
217 #[derive(Debug, Eq, PartialEq, Hash)]
218 struct ItemEntry {
219     url: String,
220     name: String,
221 }
222
223 impl ItemEntry {
224     fn new(mut url: String, name: String) -> ItemEntry {
225         while url.starts_with('/') {
226             url.remove(0);
227         }
228         ItemEntry { url, name }
229     }
230 }
231
232 impl ItemEntry {
233     crate fn print(&self) -> impl fmt::Display + '_ {
234         crate::html::format::display_fn(move |f| {
235             write!(f, "<a href=\"{}\">{}</a>", self.url, Escape(&self.name))
236         })
237     }
238 }
239
240 impl PartialOrd for ItemEntry {
241     fn partial_cmp(&self, other: &ItemEntry) -> Option<::std::cmp::Ordering> {
242         Some(self.cmp(other))
243     }
244 }
245
246 impl Ord for ItemEntry {
247     fn cmp(&self, other: &ItemEntry) -> ::std::cmp::Ordering {
248         self.name.cmp(&other.name)
249     }
250 }
251
252 #[derive(Debug)]
253 struct AllTypes {
254     structs: FxHashSet<ItemEntry>,
255     enums: FxHashSet<ItemEntry>,
256     unions: FxHashSet<ItemEntry>,
257     primitives: FxHashSet<ItemEntry>,
258     traits: FxHashSet<ItemEntry>,
259     macros: FxHashSet<ItemEntry>,
260     functions: FxHashSet<ItemEntry>,
261     typedefs: FxHashSet<ItemEntry>,
262     opaque_tys: FxHashSet<ItemEntry>,
263     statics: FxHashSet<ItemEntry>,
264     constants: FxHashSet<ItemEntry>,
265     keywords: FxHashSet<ItemEntry>,
266     attributes: FxHashSet<ItemEntry>,
267     derives: FxHashSet<ItemEntry>,
268     trait_aliases: FxHashSet<ItemEntry>,
269 }
270
271 impl AllTypes {
272     fn new() -> AllTypes {
273         let new_set = |cap| FxHashSet::with_capacity_and_hasher(cap, Default::default());
274         AllTypes {
275             structs: new_set(100),
276             enums: new_set(100),
277             unions: new_set(100),
278             primitives: new_set(26),
279             traits: new_set(100),
280             macros: new_set(100),
281             functions: new_set(100),
282             typedefs: new_set(100),
283             opaque_tys: new_set(100),
284             statics: new_set(100),
285             constants: new_set(100),
286             keywords: new_set(100),
287             attributes: new_set(100),
288             derives: new_set(100),
289             trait_aliases: new_set(100),
290         }
291     }
292
293     fn append(&mut self, item_name: String, item_type: &ItemType) {
294         let mut url: Vec<_> = item_name.split("::").skip(1).collect();
295         if let Some(name) = url.pop() {
296             let new_url = format!("{}/{}.{}.html", url.join("/"), item_type, name);
297             url.push(name);
298             let name = url.join("::");
299             match *item_type {
300                 ItemType::Struct => self.structs.insert(ItemEntry::new(new_url, name)),
301                 ItemType::Enum => self.enums.insert(ItemEntry::new(new_url, name)),
302                 ItemType::Union => self.unions.insert(ItemEntry::new(new_url, name)),
303                 ItemType::Primitive => self.primitives.insert(ItemEntry::new(new_url, name)),
304                 ItemType::Trait => self.traits.insert(ItemEntry::new(new_url, name)),
305                 ItemType::Macro => self.macros.insert(ItemEntry::new(new_url, name)),
306                 ItemType::Function => self.functions.insert(ItemEntry::new(new_url, name)),
307                 ItemType::Typedef => self.typedefs.insert(ItemEntry::new(new_url, name)),
308                 ItemType::OpaqueTy => self.opaque_tys.insert(ItemEntry::new(new_url, name)),
309                 ItemType::Static => self.statics.insert(ItemEntry::new(new_url, name)),
310                 ItemType::Constant => self.constants.insert(ItemEntry::new(new_url, name)),
311                 ItemType::ProcAttribute => self.attributes.insert(ItemEntry::new(new_url, name)),
312                 ItemType::ProcDerive => self.derives.insert(ItemEntry::new(new_url, name)),
313                 ItemType::TraitAlias => self.trait_aliases.insert(ItemEntry::new(new_url, name)),
314                 _ => true,
315             };
316         }
317     }
318 }
319
320 impl AllTypes {
321     fn print(self, f: &mut Buffer) {
322         fn print_entries(f: &mut Buffer, e: &FxHashSet<ItemEntry>, title: &str, class: &str) {
323             if !e.is_empty() {
324                 let mut e: Vec<&ItemEntry> = e.iter().collect();
325                 e.sort();
326                 write!(f, "<h3 id=\"{}\">{}</h3><ul class=\"{} docblock\">", title, title, class);
327
328                 for s in e.iter() {
329                     write!(f, "<li>{}</li>", s.print());
330                 }
331
332                 f.write_str("</ul>");
333             }
334         }
335
336         f.write_str(
337             "<h1 class=\"fqn\">\
338                  <span class=\"in-band\">List of all items</span>\
339                  <span class=\"out-of-band\">\
340                      <span id=\"render-detail\">\
341                          <a id=\"toggle-all-docs\" href=\"javascript:void(0)\" \
342                             title=\"collapse all docs\">\
343                              [<span class=\"inner\">&#x2212;</span>]\
344                          </a>\
345                      </span>
346                  </span>
347              </h1>",
348         );
349         // Note: print_entries does not escape the title, because we know the current set of titles
350         // don't require escaping.
351         print_entries(f, &self.structs, "Structs", "structs");
352         print_entries(f, &self.enums, "Enums", "enums");
353         print_entries(f, &self.unions, "Unions", "unions");
354         print_entries(f, &self.primitives, "Primitives", "primitives");
355         print_entries(f, &self.traits, "Traits", "traits");
356         print_entries(f, &self.macros, "Macros", "macros");
357         print_entries(f, &self.attributes, "Attribute Macros", "attributes");
358         print_entries(f, &self.derives, "Derive Macros", "derives");
359         print_entries(f, &self.functions, "Functions", "functions");
360         print_entries(f, &self.typedefs, "Typedefs", "typedefs");
361         print_entries(f, &self.trait_aliases, "Trait Aliases", "trait-aliases");
362         print_entries(f, &self.opaque_tys, "Opaque Types", "opaque-types");
363         print_entries(f, &self.statics, "Statics", "statics");
364         print_entries(f, &self.constants, "Constants", "constants")
365     }
366 }
367
368 #[derive(Debug)]
369 enum Setting {
370     Section {
371         description: &'static str,
372         sub_settings: Vec<Setting>,
373     },
374     Toggle {
375         js_data_name: &'static str,
376         description: &'static str,
377         default_value: bool,
378     },
379     Select {
380         js_data_name: &'static str,
381         description: &'static str,
382         default_value: &'static str,
383         options: Vec<(String, String)>,
384     },
385 }
386
387 impl Setting {
388     fn display(&self, root_path: &str, suffix: &str) -> String {
389         match *self {
390             Setting::Section { description, ref sub_settings } => format!(
391                 "<div class=\"setting-line\">\
392                      <div class=\"title\">{}</div>\
393                      <div class=\"sub-settings\">{}</div>
394                  </div>",
395                 description,
396                 sub_settings.iter().map(|s| s.display(root_path, suffix)).collect::<String>()
397             ),
398             Setting::Toggle { js_data_name, description, default_value } => format!(
399                 "<div class=\"setting-line\">\
400                      <label class=\"toggle\">\
401                      <input type=\"checkbox\" id=\"{}\" {}>\
402                      <span class=\"slider\"></span>\
403                      </label>\
404                      <div>{}</div>\
405                  </div>",
406                 js_data_name,
407                 if default_value { " checked" } else { "" },
408                 description,
409             ),
410             Setting::Select { js_data_name, description, default_value, ref options } => format!(
411                 "<div class=\"setting-line\">\
412                      <div>{}</div>\
413                      <label class=\"select-wrapper\">\
414                          <select id=\"{}\" autocomplete=\"off\">{}</select>\
415                          <img src=\"{}down-arrow{}.svg\" alt=\"Select item\">\
416                      </label>\
417                  </div>",
418                 description,
419                 js_data_name,
420                 options
421                     .iter()
422                     .map(|opt| format!(
423                         "<option value=\"{}\" {}>{}</option>",
424                         opt.0,
425                         if opt.0 == default_value { "selected" } else { "" },
426                         opt.1,
427                     ))
428                     .collect::<String>(),
429                 root_path,
430                 suffix,
431             ),
432         }
433     }
434 }
435
436 impl From<(&'static str, &'static str, bool)> for Setting {
437     fn from(values: (&'static str, &'static str, bool)) -> Setting {
438         Setting::Toggle { js_data_name: values.0, description: values.1, default_value: values.2 }
439     }
440 }
441
442 impl<T: Into<Setting>> From<(&'static str, Vec<T>)> for Setting {
443     fn from(values: (&'static str, Vec<T>)) -> Setting {
444         Setting::Section {
445             description: values.0,
446             sub_settings: values.1.into_iter().map(|v| v.into()).collect::<Vec<_>>(),
447         }
448     }
449 }
450
451 fn settings(root_path: &str, suffix: &str, themes: &[StylePath]) -> Result<String, Error> {
452     let theme_names: Vec<(String, String)> = themes
453         .iter()
454         .map(|entry| {
455             let theme =
456                 try_none!(try_none!(entry.path.file_stem(), &entry.path).to_str(), &entry.path)
457                     .to_string();
458
459             Ok((theme.clone(), theme))
460         })
461         .collect::<Result<_, Error>>()?;
462
463     // (id, explanation, default value)
464     let settings: &[Setting] = &[
465         (
466             "Theme preferences",
467             vec![
468                 Setting::from(("use-system-theme", "Use system theme", true)),
469                 Setting::Select {
470                     js_data_name: "preferred-dark-theme",
471                     description: "Preferred dark theme",
472                     default_value: "dark",
473                     options: theme_names.clone(),
474                 },
475                 Setting::Select {
476                     js_data_name: "preferred-light-theme",
477                     description: "Preferred light theme",
478                     default_value: "light",
479                     options: theme_names,
480                 },
481             ],
482         )
483             .into(),
484         ("auto-hide-large-items", "Auto-hide item contents for large items.", true).into(),
485         ("auto-hide-method-docs", "Auto-hide item methods' documentation", false).into(),
486         ("auto-hide-trait-implementations", "Auto-hide trait implementation documentation", true)
487             .into(),
488         ("auto-collapse-implementors", "Auto-hide implementors of a trait", true).into(),
489         ("go-to-only-result", "Directly go to item in search if there is only one result", false)
490             .into(),
491         ("line-numbers", "Show line numbers on code examples", false).into(),
492         ("disable-shortcuts", "Disable keyboard shortcuts", false).into(),
493     ];
494
495     Ok(format!(
496         "<h1 class=\"fqn\">\
497             <span class=\"in-band\">Rustdoc settings</span>\
498         </h1>\
499         <div class=\"settings\">{}</div>\
500         <script src=\"{}settings{}.js\"></script>",
501         settings.iter().map(|s| s.display(root_path, suffix)).collect::<String>(),
502         root_path,
503         suffix
504     ))
505 }
506
507 fn document(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, parent: Option<&clean::Item>) {
508     if let Some(ref name) = item.name {
509         info!("Documenting {}", name);
510     }
511     document_item_info(w, cx, item, false, parent);
512     document_full(w, item, cx, false);
513 }
514
515 /// Render md_text as markdown.
516 fn render_markdown(
517     w: &mut Buffer,
518     cx: &Context<'_>,
519     md_text: &str,
520     links: Vec<RenderedLink>,
521     is_hidden: bool,
522 ) {
523     let mut ids = cx.id_map.borrow_mut();
524     write!(
525         w,
526         "<div class=\"docblock{}\">{}</div>",
527         if is_hidden { " hidden" } else { "" },
528         Markdown(
529             md_text,
530             &links,
531             &mut ids,
532             cx.shared.codes,
533             cx.shared.edition,
534             &cx.shared.playground
535         )
536         .into_string()
537     )
538 }
539
540 /// Writes a documentation block containing only the first paragraph of the documentation. If the
541 /// docs are longer, a "Read more" link is appended to the end.
542 fn document_short(
543     w: &mut Buffer,
544     item: &clean::Item,
545     cx: &Context<'_>,
546     link: AssocItemLink<'_>,
547     is_hidden: bool,
548     parent: &clean::Item,
549     show_def_docs: bool,
550 ) {
551     document_item_info(w, cx, item, is_hidden, Some(parent));
552     if !show_def_docs {
553         return;
554     }
555     if let Some(s) = item.doc_value() {
556         let mut summary_html = MarkdownSummaryLine(&s, &item.links(cx)).into_string();
557
558         if s.contains('\n') {
559             let link = format!(r#" <a href="{}">Read more</a>"#, naive_assoc_href(item, link, cx));
560
561             if let Some(idx) = summary_html.rfind("</p>") {
562                 summary_html.insert_str(idx, &link);
563             } else {
564                 summary_html.push_str(&link);
565             }
566         }
567
568         write!(
569             w,
570             "<div class='docblock{}'>{}</div>",
571             if is_hidden { " hidden" } else { "" },
572             summary_html,
573         );
574     }
575 }
576
577 fn document_full(w: &mut Buffer, item: &clean::Item, cx: &Context<'_>, is_hidden: bool) {
578     if let Some(s) = cx.shared.maybe_collapsed_doc_value(item) {
579         debug!("Doc block: =====\n{}\n=====", s);
580         render_markdown(w, cx, &s, item.links(cx), is_hidden);
581     }
582 }
583
584 /// Add extra information about an item such as:
585 ///
586 /// * Stability
587 /// * Deprecated
588 /// * Required features (through the `doc_cfg` feature)
589 fn document_item_info(
590     w: &mut Buffer,
591     cx: &Context<'_>,
592     item: &clean::Item,
593     is_hidden: bool,
594     parent: Option<&clean::Item>,
595 ) {
596     let item_infos = short_item_info(item, cx, parent);
597     if !item_infos.is_empty() {
598         if is_hidden {
599             w.write_str("<div class=\"item-info hidden\">");
600         } else {
601             w.write_str("<div class=\"item-info\">");
602         }
603         for info in item_infos {
604             w.write_str(&info);
605         }
606         w.write_str("</div>");
607     }
608 }
609
610 fn portability(item: &clean::Item, parent: Option<&clean::Item>) -> Option<String> {
611     let cfg = match (&item.attrs.cfg, parent.and_then(|p| p.attrs.cfg.as_ref())) {
612         (Some(cfg), Some(parent_cfg)) => cfg.simplify_with(parent_cfg),
613         (cfg, _) => cfg.as_deref().cloned(),
614     };
615
616     debug!(
617         "Portability {:?} - {:?} = {:?}",
618         item.attrs.cfg,
619         parent.and_then(|p| p.attrs.cfg.as_ref()),
620         cfg
621     );
622
623     Some(format!("<div class=\"stab portability\">{}</div>", cfg?.render_long_html()))
624 }
625
626 /// Render the stability, deprecation and portability information that is displayed at the top of
627 /// the item's documentation.
628 fn short_item_info(
629     item: &clean::Item,
630     cx: &Context<'_>,
631     parent: Option<&clean::Item>,
632 ) -> Vec<String> {
633     let mut extra_info = vec![];
634     let error_codes = cx.shared.codes;
635
636     if let Some(Deprecation { note, since, is_since_rustc_version, suggestion: _ }) =
637         item.deprecation(cx.tcx())
638     {
639         // We display deprecation messages for #[deprecated] and #[rustc_deprecated]
640         // but only display the future-deprecation messages for #[rustc_deprecated].
641         let mut message = if let Some(since) = since {
642             let since = &since.as_str();
643             if !stability::deprecation_in_effect(is_since_rustc_version, Some(since)) {
644                 if *since == "TBD" {
645                     String::from("Deprecating in a future Rust version")
646                 } else {
647                     format!("Deprecating in {}", Escape(since))
648                 }
649             } else {
650                 format!("Deprecated since {}", Escape(since))
651             }
652         } else {
653             String::from("Deprecated")
654         };
655
656         if let Some(note) = note {
657             let note = note.as_str();
658             let mut ids = cx.id_map.borrow_mut();
659             let html = MarkdownHtml(
660                 &note,
661                 &mut ids,
662                 error_codes,
663                 cx.shared.edition,
664                 &cx.shared.playground,
665             );
666             message.push_str(&format!(": {}", html.into_string()));
667         }
668         extra_info.push(format!(
669             "<div class=\"stab deprecated\"><span class=\"emoji\">👎</span> {}</div>",
670             message,
671         ));
672     }
673
674     // Render unstable items. But don't render "rustc_private" crates (internal compiler crates).
675     // Those crates are permanently unstable so it makes no sense to render "unstable" everywhere.
676     if let Some((StabilityLevel::Unstable { reason, issue, .. }, feature)) = item
677         .stability(cx.tcx())
678         .as_ref()
679         .filter(|stab| stab.feature != sym::rustc_private)
680         .map(|stab| (stab.level, stab.feature))
681     {
682         let mut message =
683             "<span class=\"emoji\">🔬</span> This is a nightly-only experimental API.".to_owned();
684
685         let mut feature = format!("<code>{}</code>", Escape(&feature.as_str()));
686         if let (Some(url), Some(issue)) = (&cx.shared.issue_tracker_base_url, issue) {
687             feature.push_str(&format!(
688                 "&nbsp;<a href=\"{url}{issue}\">#{issue}</a>",
689                 url = url,
690                 issue = issue
691             ));
692         }
693
694         message.push_str(&format!(" ({})", feature));
695
696         if let Some(unstable_reason) = reason {
697             let mut ids = cx.id_map.borrow_mut();
698             message = format!(
699                 "<details><summary>{}</summary>{}</details>",
700                 message,
701                 MarkdownHtml(
702                     &unstable_reason.as_str(),
703                     &mut ids,
704                     error_codes,
705                     cx.shared.edition,
706                     &cx.shared.playground,
707                 )
708                 .into_string()
709             );
710         }
711
712         extra_info.push(format!("<div class=\"stab unstable\">{}</div>", message));
713     }
714
715     if let Some(portability) = portability(item, parent) {
716         extra_info.push(portability);
717     }
718
719     extra_info
720 }
721
722 fn render_impls(
723     cx: &Context<'_>,
724     w: &mut Buffer,
725     traits: &[&&Impl],
726     containing_item: &clean::Item,
727 ) {
728     let cache = cx.cache();
729     let tcx = cx.tcx();
730     let mut impls = traits
731         .iter()
732         .map(|i| {
733             let did = i.trait_did_full(cache).unwrap();
734             let assoc_link = AssocItemLink::GotoSource(did, &i.inner_impl().provided_trait_methods);
735             let mut buffer = if w.is_for_html() { Buffer::html() } else { Buffer::new() };
736             render_impl(
737                 &mut buffer,
738                 cx,
739                 i,
740                 containing_item,
741                 assoc_link,
742                 RenderMode::Normal,
743                 containing_item.stable_since(tcx).as_deref(),
744                 containing_item.const_stable_since(tcx).as_deref(),
745                 true,
746                 None,
747                 false,
748                 true,
749                 &[],
750             );
751             buffer.into_inner()
752         })
753         .collect::<Vec<_>>();
754     impls.sort();
755     w.write_str(&impls.join(""));
756 }
757
758 fn naive_assoc_href(it: &clean::Item, link: AssocItemLink<'_>, cx: &Context<'_>) -> String {
759     use crate::formats::item_type::ItemType::*;
760
761     let name = it.name.as_ref().unwrap();
762     let ty = match it.type_() {
763         Typedef | AssocType => AssocType,
764         s => s,
765     };
766
767     let anchor = format!("#{}.{}", ty, name);
768     match link {
769         AssocItemLink::Anchor(Some(ref id)) => format!("#{}", id),
770         AssocItemLink::Anchor(None) => anchor,
771         AssocItemLink::GotoSource(did, _) => {
772             href(did, cx).map(|p| format!("{}{}", p.0, anchor)).unwrap_or(anchor)
773         }
774     }
775 }
776
777 fn assoc_const(
778     w: &mut Buffer,
779     it: &clean::Item,
780     ty: &clean::Type,
781     _default: Option<&String>,
782     link: AssocItemLink<'_>,
783     extra: &str,
784     cx: &Context<'_>,
785 ) {
786     write!(
787         w,
788         "{}{}const <a href=\"{}\" class=\"constant\"><b>{}</b></a>: {}",
789         extra,
790         it.visibility.print_with_space(it.def_id, cx),
791         naive_assoc_href(it, link, cx),
792         it.name.as_ref().unwrap(),
793         ty.print(cx)
794     );
795 }
796
797 fn assoc_type(
798     w: &mut Buffer,
799     it: &clean::Item,
800     bounds: &[clean::GenericBound],
801     default: Option<&clean::Type>,
802     link: AssocItemLink<'_>,
803     extra: &str,
804     cx: &Context<'_>,
805 ) {
806     write!(
807         w,
808         "{}type <a href=\"{}\" class=\"type\">{}</a>",
809         extra,
810         naive_assoc_href(it, link, cx),
811         it.name.as_ref().unwrap()
812     );
813     if !bounds.is_empty() {
814         write!(w, ": {}", print_generic_bounds(bounds, cx))
815     }
816     if let Some(default) = default {
817         write!(w, " = {}", default.print(cx))
818     }
819 }
820
821 fn render_stability_since_raw(
822     w: &mut Buffer,
823     ver: Option<&str>,
824     const_ver: Option<&str>,
825     containing_ver: Option<&str>,
826     containing_const_ver: Option<&str>,
827 ) {
828     let ver = ver.filter(|inner| !inner.is_empty());
829     let const_ver = const_ver.filter(|inner| !inner.is_empty());
830
831     match (ver, const_ver) {
832         (Some(v), Some(cv)) if const_ver != containing_const_ver => {
833             write!(
834                 w,
835                 "<span class=\"since\" title=\"Stable since Rust version {0}, const since {1}\">{0} (const: {1})</span>",
836                 v, cv
837             );
838         }
839         (Some(v), _) if ver != containing_ver => {
840             write!(
841                 w,
842                 "<span class=\"since\" title=\"Stable since Rust version {0}\">{0}</span>",
843                 v
844             );
845         }
846         _ => {}
847     }
848 }
849
850 fn render_assoc_item(
851     w: &mut Buffer,
852     item: &clean::Item,
853     link: AssocItemLink<'_>,
854     parent: ItemType,
855     cx: &Context<'_>,
856 ) {
857     fn method(
858         w: &mut Buffer,
859         meth: &clean::Item,
860         header: hir::FnHeader,
861         g: &clean::Generics,
862         d: &clean::FnDecl,
863         link: AssocItemLink<'_>,
864         parent: ItemType,
865         cx: &Context<'_>,
866     ) {
867         let name = meth.name.as_ref().unwrap();
868         let href = match link {
869             AssocItemLink::Anchor(Some(ref id)) => format!("#{}", id),
870             AssocItemLink::Anchor(None) => format!("#{}.{}", meth.type_(), name),
871             AssocItemLink::GotoSource(did, provided_methods) => {
872                 // We're creating a link from an impl-item to the corresponding
873                 // trait-item and need to map the anchored type accordingly.
874                 let ty = if provided_methods.contains(&name) {
875                     ItemType::Method
876                 } else {
877                     ItemType::TyMethod
878                 };
879
880                 href(did, cx)
881                     .map(|p| format!("{}#{}.{}", p.0, ty, name))
882                     .unwrap_or_else(|| format!("#{}.{}", ty, name))
883             }
884         };
885         let vis = meth.visibility.print_with_space(meth.def_id, cx).to_string();
886         let constness = header.constness.print_with_space();
887         let asyncness = header.asyncness.print_with_space();
888         let unsafety = header.unsafety.print_with_space();
889         let defaultness = print_default_space(meth.is_default());
890         let abi = print_abi_with_space(header.abi).to_string();
891         // NOTE: `{:#}` does not print HTML formatting, `{}` does. So `g.print` can't be reused between the length calculation and `write!`.
892         let generics_len = format!("{:#}", g.print(cx)).len();
893         let mut header_len = "fn ".len()
894             + vis.len()
895             + constness.len()
896             + asyncness.len()
897             + unsafety.len()
898             + defaultness.len()
899             + abi.len()
900             + name.as_str().len()
901             + generics_len;
902
903         let (indent, indent_str, end_newline) = if parent == ItemType::Trait {
904             header_len += 4;
905             let indent_str = "    ";
906             render_attributes_in_pre(w, meth, indent_str);
907             (4, indent_str, false)
908         } else {
909             render_attributes_in_code(w, meth);
910             (0, "", true)
911         };
912         w.reserve(header_len + "<a href=\"\" class=\"fnname\">{".len() + "</a>".len());
913         write!(
914             w,
915             "{}{}{}{}{}{}{}fn <a href=\"{href}\" class=\"fnname\">{name}</a>\
916              {generics}{decl}{notable_traits}{where_clause}",
917             indent_str,
918             vis,
919             constness,
920             asyncness,
921             unsafety,
922             defaultness,
923             abi,
924             href = href,
925             name = name,
926             generics = g.print(cx),
927             decl = d.full_print(header_len, indent, header.asyncness, cx),
928             notable_traits = notable_traits_decl(&d, cx),
929             where_clause = print_where_clause(g, cx, indent, end_newline),
930         )
931     }
932     match *item.kind {
933         clean::StrippedItem(..) => {}
934         clean::TyMethodItem(ref m) => {
935             method(w, item, m.header, &m.generics, &m.decl, link, parent, cx)
936         }
937         clean::MethodItem(ref m, _) => {
938             method(w, item, m.header, &m.generics, &m.decl, link, parent, cx)
939         }
940         clean::AssocConstItem(ref ty, ref default) => assoc_const(
941             w,
942             item,
943             ty,
944             default.as_ref(),
945             link,
946             if parent == ItemType::Trait { "    " } else { "" },
947             cx,
948         ),
949         clean::AssocTypeItem(ref bounds, ref default) => assoc_type(
950             w,
951             item,
952             bounds,
953             default.as_ref(),
954             link,
955             if parent == ItemType::Trait { "    " } else { "" },
956             cx,
957         ),
958         _ => panic!("render_assoc_item called on non-associated-item"),
959     }
960 }
961
962 const ALLOWED_ATTRIBUTES: &[Symbol] = &[
963     sym::export_name,
964     sym::link_section,
965     sym::must_use,
966     sym::no_mangle,
967     sym::repr,
968     sym::non_exhaustive,
969 ];
970
971 fn attributes(it: &clean::Item) -> Vec<String> {
972     it.attrs
973         .other_attrs
974         .iter()
975         .filter_map(|attr| {
976             if ALLOWED_ATTRIBUTES.contains(&attr.name_or_empty()) {
977                 Some(pprust::attribute_to_string(&attr).replace("\n", "").replace("  ", " "))
978             } else {
979                 None
980             }
981         })
982         .collect()
983 }
984
985 // When an attribute is rendered inside a `<pre>` tag, it is formatted using
986 // a whitespace prefix and newline.
987 fn render_attributes_in_pre(w: &mut Buffer, it: &clean::Item, prefix: &str) {
988     for a in attributes(it) {
989         write!(w, "{}{}\n", prefix, a);
990     }
991 }
992
993 // When an attribute is rendered inside a <code> tag, it is formatted using
994 // a div to produce a newline after it.
995 fn render_attributes_in_code(w: &mut Buffer, it: &clean::Item) {
996     for a in attributes(it) {
997         write!(w, "<div class=\"code-attribute\">{}</div>", a);
998     }
999 }
1000
1001 #[derive(Copy, Clone)]
1002 enum AssocItemLink<'a> {
1003     Anchor(Option<&'a str>),
1004     GotoSource(DefId, &'a FxHashSet<Symbol>),
1005 }
1006
1007 impl<'a> AssocItemLink<'a> {
1008     fn anchor(&self, id: &'a str) -> Self {
1009         match *self {
1010             AssocItemLink::Anchor(_) => AssocItemLink::Anchor(Some(&id)),
1011             ref other => *other,
1012         }
1013     }
1014 }
1015
1016 fn render_assoc_items(
1017     w: &mut Buffer,
1018     cx: &Context<'_>,
1019     containing_item: &clean::Item,
1020     it: DefId,
1021     what: AssocItemRender<'_>,
1022 ) {
1023     info!("Documenting associated items of {:?}", containing_item.name);
1024     let v = match cx.cache.impls.get(&it) {
1025         Some(v) => v,
1026         None => return,
1027     };
1028     let tcx = cx.tcx();
1029     let cache = cx.cache();
1030     let (non_trait, traits): (Vec<_>, _) = v.iter().partition(|i| i.inner_impl().trait_.is_none());
1031     if !non_trait.is_empty() {
1032         let render_mode = match what {
1033             AssocItemRender::All => {
1034                 w.write_str(
1035                     "<h2 id=\"implementations\" class=\"small-section-header\">\
1036                          Implementations<a href=\"#implementations\" class=\"anchor\"></a>\
1037                     </h2>",
1038                 );
1039                 RenderMode::Normal
1040             }
1041             AssocItemRender::DerefFor { trait_, type_, deref_mut_ } => {
1042                 let id =
1043                     cx.derive_id(small_url_encode(format!("deref-methods-{:#}", type_.print(cx))));
1044                 debug!("Adding {} to deref id map", type_.print(cx));
1045                 cx.deref_id_map.borrow_mut().insert(type_.def_id_full(cache).unwrap(), id.clone());
1046                 write!(
1047                     w,
1048                     "<h2 id=\"{id}\" class=\"small-section-header\">\
1049                          Methods from {trait_}&lt;Target = {type_}&gt;\
1050                          <a href=\"#{id}\" class=\"anchor\"></a>\
1051                      </h2>",
1052                     id = id,
1053                     trait_ = trait_.print(cx),
1054                     type_ = type_.print(cx),
1055                 );
1056                 RenderMode::ForDeref { mut_: deref_mut_ }
1057             }
1058         };
1059         for i in &non_trait {
1060             render_impl(
1061                 w,
1062                 cx,
1063                 i,
1064                 containing_item,
1065                 AssocItemLink::Anchor(None),
1066                 render_mode,
1067                 containing_item.stable_since(tcx).as_deref(),
1068                 containing_item.const_stable_since(tcx).as_deref(),
1069                 true,
1070                 None,
1071                 false,
1072                 true,
1073                 &[],
1074             );
1075         }
1076     }
1077     if !traits.is_empty() {
1078         let deref_impl = traits
1079             .iter()
1080             .find(|t| t.inner_impl().trait_.def_id_full(cache) == cx.cache.deref_trait_did);
1081         if let Some(impl_) = deref_impl {
1082             let has_deref_mut = traits
1083                 .iter()
1084                 .any(|t| t.inner_impl().trait_.def_id_full(cache) == cx.cache.deref_mut_trait_did);
1085             render_deref_methods(w, cx, impl_, containing_item, has_deref_mut);
1086         }
1087
1088         // If we were already one level into rendering deref methods, we don't want to render
1089         // anything after recursing into any further deref methods above.
1090         if let AssocItemRender::DerefFor { .. } = what {
1091             return;
1092         }
1093
1094         let (synthetic, concrete): (Vec<&&Impl>, Vec<&&Impl>) =
1095             traits.iter().partition(|t| t.inner_impl().synthetic);
1096         let (blanket_impl, concrete): (Vec<&&Impl>, _) =
1097             concrete.into_iter().partition(|t| t.inner_impl().blanket_impl.is_some());
1098
1099         let mut impls = Buffer::empty_from(&w);
1100         render_impls(cx, &mut impls, &concrete, containing_item);
1101         let impls = impls.into_inner();
1102         if !impls.is_empty() {
1103             write!(
1104                 w,
1105                 "<h2 id=\"trait-implementations\" class=\"small-section-header\">\
1106                      Trait Implementations<a href=\"#trait-implementations\" class=\"anchor\"></a>\
1107                  </h2>\
1108                  <div id=\"trait-implementations-list\">{}</div>",
1109                 impls
1110             );
1111         }
1112
1113         if !synthetic.is_empty() {
1114             w.write_str(
1115                 "<h2 id=\"synthetic-implementations\" class=\"small-section-header\">\
1116                      Auto Trait Implementations\
1117                      <a href=\"#synthetic-implementations\" class=\"anchor\"></a>\
1118                  </h2>\
1119                  <div id=\"synthetic-implementations-list\">",
1120             );
1121             render_impls(cx, w, &synthetic, containing_item);
1122             w.write_str("</div>");
1123         }
1124
1125         if !blanket_impl.is_empty() {
1126             w.write_str(
1127                 "<h2 id=\"blanket-implementations\" class=\"small-section-header\">\
1128                      Blanket Implementations\
1129                      <a href=\"#blanket-implementations\" class=\"anchor\"></a>\
1130                  </h2>\
1131                  <div id=\"blanket-implementations-list\">",
1132             );
1133             render_impls(cx, w, &blanket_impl, containing_item);
1134             w.write_str("</div>");
1135         }
1136     }
1137 }
1138
1139 fn render_deref_methods(
1140     w: &mut Buffer,
1141     cx: &Context<'_>,
1142     impl_: &Impl,
1143     container_item: &clean::Item,
1144     deref_mut: bool,
1145 ) {
1146     let deref_type = impl_.inner_impl().trait_.as_ref().unwrap();
1147     let (target, real_target) = impl_
1148         .inner_impl()
1149         .items
1150         .iter()
1151         .find_map(|item| match *item.kind {
1152             clean::TypedefItem(ref t, true) => Some(match *t {
1153                 clean::Typedef { item_type: Some(ref type_), .. } => (type_, &t.type_),
1154                 _ => (&t.type_, &t.type_),
1155             }),
1156             _ => None,
1157         })
1158         .expect("Expected associated type binding");
1159     debug!("Render deref methods for {:#?}, target {:#?}", impl_.inner_impl().for_, target);
1160     let what =
1161         AssocItemRender::DerefFor { trait_: deref_type, type_: real_target, deref_mut_: deref_mut };
1162     if let Some(did) = target.def_id_full(cx.cache()) {
1163         if let Some(type_did) = impl_.inner_impl().for_.def_id_full(cx.cache()) {
1164             // `impl Deref<Target = S> for S`
1165             if did == type_did {
1166                 // Avoid infinite cycles
1167                 return;
1168             }
1169         }
1170         render_assoc_items(w, cx, container_item, did, what);
1171     } else {
1172         if let Some(prim) = target.primitive_type() {
1173             if let Some(&did) = cx.cache.primitive_locations.get(&prim) {
1174                 render_assoc_items(w, cx, container_item, did, what);
1175             }
1176         }
1177     }
1178 }
1179
1180 fn should_render_item(item: &clean::Item, deref_mut_: bool, cache: &Cache) -> bool {
1181     let self_type_opt = match *item.kind {
1182         clean::MethodItem(ref method, _) => method.decl.self_type(),
1183         clean::TyMethodItem(ref method) => method.decl.self_type(),
1184         _ => None,
1185     };
1186
1187     if let Some(self_ty) = self_type_opt {
1188         let (by_mut_ref, by_box, by_value) = match self_ty {
1189             SelfTy::SelfBorrowed(_, mutability)
1190             | SelfTy::SelfExplicit(clean::BorrowedRef { mutability, .. }) => {
1191                 (mutability == Mutability::Mut, false, false)
1192             }
1193             SelfTy::SelfExplicit(clean::ResolvedPath { did, .. }) => {
1194                 (false, Some(did) == cache.owned_box_did, false)
1195             }
1196             SelfTy::SelfValue => (false, false, true),
1197             _ => (false, false, false),
1198         };
1199
1200         (deref_mut_ || !by_mut_ref) && !by_box && !by_value
1201     } else {
1202         false
1203     }
1204 }
1205
1206 fn notable_traits_decl(decl: &clean::FnDecl, cx: &Context<'_>) -> String {
1207     let mut out = Buffer::html();
1208     let mut trait_ = String::new();
1209
1210     if let Some(did) = decl.output.def_id_full(cx.cache()) {
1211         if let Some(impls) = cx.cache().impls.get(&did) {
1212             for i in impls {
1213                 let impl_ = i.inner_impl();
1214                 if impl_.trait_.def_id().map_or(false, |d| {
1215                     cx.cache().traits.get(&d).map(|t| t.is_notable).unwrap_or(false)
1216                 }) {
1217                     if out.is_empty() {
1218                         write!(
1219                             &mut out,
1220                             "<h3 class=\"notable\">Notable traits for {}</h3>\
1221                              <code class=\"content\">",
1222                             impl_.for_.print(cx)
1223                         );
1224                         trait_.push_str(&impl_.for_.print(cx).to_string());
1225                     }
1226
1227                     //use the "where" class here to make it small
1228                     write!(
1229                         &mut out,
1230                         "<span class=\"where fmt-newline\">{}</span>",
1231                         impl_.print(false, cx)
1232                     );
1233                     let t_did = impl_.trait_.def_id_full(cx.cache()).unwrap();
1234                     for it in &impl_.items {
1235                         if let clean::TypedefItem(ref tydef, _) = *it.kind {
1236                             out.push_str("<span class=\"where fmt-newline\">    ");
1237                             assoc_type(
1238                                 &mut out,
1239                                 it,
1240                                 &[],
1241                                 Some(&tydef.type_),
1242                                 AssocItemLink::GotoSource(t_did, &FxHashSet::default()),
1243                                 "",
1244                                 cx,
1245                             );
1246                             out.push_str(";</span>");
1247                         }
1248                     }
1249                 }
1250             }
1251         }
1252     }
1253
1254     if !out.is_empty() {
1255         out.insert_str(
1256             0,
1257             "<span class=\"notable-traits\"><span class=\"notable-traits-tooltip\">ⓘ\
1258             <div class=\"notable-traits-tooltiptext\"><span class=\"docblock\">",
1259         );
1260         out.push_str("</code></span></div></span></span>");
1261     }
1262
1263     out.into_inner()
1264 }
1265
1266 fn render_impl(
1267     w: &mut Buffer,
1268     cx: &Context<'_>,
1269     i: &Impl,
1270     parent: &clean::Item,
1271     link: AssocItemLink<'_>,
1272     render_mode: RenderMode,
1273     outer_version: Option<&str>,
1274     outer_const_version: Option<&str>,
1275     show_def_docs: bool,
1276     use_absolute: Option<bool>,
1277     is_on_foreign_type: bool,
1278     show_default_items: bool,
1279     // This argument is used to reference same type with different paths to avoid duplication
1280     // in documentation pages for trait with automatic implementations like "Send" and "Sync".
1281     aliases: &[String],
1282 ) {
1283     let tcx = cx.tcx();
1284     let cache = cx.cache();
1285     let traits = &cache.traits;
1286     let trait_ = i.trait_did_full(cache).map(|did| &traits[&did]);
1287
1288     if render_mode == RenderMode::Normal {
1289         let id = cx.derive_id(match i.inner_impl().trait_ {
1290             Some(ref t) => {
1291                 if is_on_foreign_type {
1292                     get_id_for_impl_on_foreign_type(&i.inner_impl().for_, t, cx)
1293                 } else {
1294                     format!("impl-{}", small_url_encode(format!("{:#}", t.print(cx))))
1295                 }
1296             }
1297             None => "impl".to_string(),
1298         });
1299         let aliases = if aliases.is_empty() {
1300             String::new()
1301         } else {
1302             format!(" aliases=\"{}\"", aliases.join(","))
1303         };
1304         if let Some(use_absolute) = use_absolute {
1305             write!(w, "<h3 id=\"{}\" class=\"impl\"{}><code class=\"in-band\">", id, aliases);
1306             write!(w, "{}", i.inner_impl().print(use_absolute, cx));
1307             if show_def_docs {
1308                 for it in &i.inner_impl().items {
1309                     if let clean::TypedefItem(ref tydef, _) = *it.kind {
1310                         w.write_str("<span class=\"where fmt-newline\">  ");
1311                         assoc_type(
1312                             w,
1313                             it,
1314                             &[],
1315                             Some(&tydef.type_),
1316                             AssocItemLink::Anchor(None),
1317                             "",
1318                             cx,
1319                         );
1320                         w.write_str(";</span>");
1321                     }
1322                 }
1323             }
1324             w.write_str("</code>");
1325         } else {
1326             write!(
1327                 w,
1328                 "<h3 id=\"{}\" class=\"impl\"{}><code class=\"in-band\">{}</code>",
1329                 id,
1330                 aliases,
1331                 i.inner_impl().print(false, cx)
1332             );
1333         }
1334         write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
1335         render_stability_since_raw(
1336             w,
1337             i.impl_item.stable_since(tcx).as_deref(),
1338             i.impl_item.const_stable_since(tcx).as_deref(),
1339             outer_version,
1340             outer_const_version,
1341         );
1342         write_srclink(cx, &i.impl_item, w);
1343         w.write_str("</h3>");
1344
1345         if trait_.is_some() {
1346             if let Some(portability) = portability(&i.impl_item, Some(parent)) {
1347                 write!(w, "<div class=\"item-info\">{}</div>", portability);
1348             }
1349         }
1350
1351         if let Some(ref dox) = cx.shared.maybe_collapsed_doc_value(&i.impl_item) {
1352             let mut ids = cx.id_map.borrow_mut();
1353             write!(
1354                 w,
1355                 "<div class=\"docblock\">{}</div>",
1356                 Markdown(
1357                     &*dox,
1358                     &i.impl_item.links(cx),
1359                     &mut ids,
1360                     cx.shared.codes,
1361                     cx.shared.edition,
1362                     &cx.shared.playground
1363                 )
1364                 .into_string()
1365             );
1366         }
1367     }
1368
1369     fn doc_impl_item(
1370         w: &mut Buffer,
1371         cx: &Context<'_>,
1372         item: &clean::Item,
1373         parent: &clean::Item,
1374         link: AssocItemLink<'_>,
1375         render_mode: RenderMode,
1376         is_default_item: bool,
1377         outer_version: Option<&str>,
1378         outer_const_version: Option<&str>,
1379         trait_: Option<&clean::Trait>,
1380         show_def_docs: bool,
1381     ) {
1382         let item_type = item.type_();
1383         let name = item.name.as_ref().unwrap();
1384         let tcx = cx.tcx();
1385
1386         let render_method_item = match render_mode {
1387             RenderMode::Normal => true,
1388             RenderMode::ForDeref { mut_: deref_mut_ } => {
1389                 should_render_item(&item, deref_mut_, &cx.cache)
1390             }
1391         };
1392
1393         let (is_hidden, extra_class) =
1394             if (trait_.is_none() || item.doc_value().is_some() || item.kind.is_type_alias())
1395                 && !is_default_item
1396             {
1397                 (false, "")
1398             } else {
1399                 (true, " hidden")
1400             };
1401         let in_trait_class = if trait_.is_some() { " trait-impl" } else { "" };
1402         match *item.kind {
1403             clean::MethodItem(..) | clean::TyMethodItem(_) => {
1404                 // Only render when the method is not static or we allow static methods
1405                 if render_method_item {
1406                     let id = cx.derive_id(format!("{}.{}", item_type, name));
1407                     let source_id = trait_
1408                         .and_then(|trait_| {
1409                             trait_.items.iter().find(|item| {
1410                                 item.name.map(|n| n.as_str().eq(&name.as_str())).unwrap_or(false)
1411                             })
1412                         })
1413                         .map(|item| format!("{}.{}", item.type_(), name));
1414                     write!(
1415                         w,
1416                         "<h4 id=\"{}\" class=\"{}{}{}\">",
1417                         id, item_type, extra_class, in_trait_class,
1418                     );
1419                     w.write_str("<code>");
1420                     render_assoc_item(
1421                         w,
1422                         item,
1423                         link.anchor(source_id.as_ref().unwrap_or(&id)),
1424                         ItemType::Impl,
1425                         cx,
1426                     );
1427                     w.write_str("</code>");
1428                     render_stability_since_raw(
1429                         w,
1430                         item.stable_since(tcx).as_deref(),
1431                         item.const_stable_since(tcx).as_deref(),
1432                         outer_version,
1433                         outer_const_version,
1434                     );
1435                     write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
1436                     write_srclink(cx, item, w);
1437                     w.write_str("</h4>");
1438                 }
1439             }
1440             clean::TypedefItem(ref tydef, _) => {
1441                 let source_id = format!("{}.{}", ItemType::AssocType, name);
1442                 let id = cx.derive_id(source_id.clone());
1443                 write!(
1444                     w,
1445                     "<h4 id=\"{}\" class=\"{}{}{}\"><code>",
1446                     id, item_type, extra_class, in_trait_class
1447                 );
1448                 assoc_type(
1449                     w,
1450                     item,
1451                     &Vec::new(),
1452                     Some(&tydef.type_),
1453                     link.anchor(if trait_.is_some() { &source_id } else { &id }),
1454                     "",
1455                     cx,
1456                 );
1457                 w.write_str("</code>");
1458                 write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
1459                 w.write_str("</h4>");
1460             }
1461             clean::AssocConstItem(ref ty, ref default) => {
1462                 let source_id = format!("{}.{}", item_type, name);
1463                 let id = cx.derive_id(source_id.clone());
1464                 write!(
1465                     w,
1466                     "<h4 id=\"{}\" class=\"{}{}{}\"><code>",
1467                     id, item_type, extra_class, in_trait_class
1468                 );
1469                 assoc_const(
1470                     w,
1471                     item,
1472                     ty,
1473                     default.as_ref(),
1474                     link.anchor(if trait_.is_some() { &source_id } else { &id }),
1475                     "",
1476                     cx,
1477                 );
1478                 w.write_str("</code>");
1479                 render_stability_since_raw(
1480                     w,
1481                     item.stable_since(tcx).as_deref(),
1482                     item.const_stable_since(tcx).as_deref(),
1483                     outer_version,
1484                     outer_const_version,
1485                 );
1486                 write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
1487                 write_srclink(cx, item, w);
1488                 w.write_str("</h4>");
1489             }
1490             clean::AssocTypeItem(ref bounds, ref default) => {
1491                 let source_id = format!("{}.{}", item_type, name);
1492                 let id = cx.derive_id(source_id.clone());
1493                 write!(
1494                     w,
1495                     "<h4 id=\"{}\" class=\"{}{}{}\"><code>",
1496                     id, item_type, extra_class, in_trait_class
1497                 );
1498                 assoc_type(
1499                     w,
1500                     item,
1501                     bounds,
1502                     default.as_ref(),
1503                     link.anchor(if trait_.is_some() { &source_id } else { &id }),
1504                     "",
1505                     cx,
1506                 );
1507                 w.write_str("</code>");
1508                 write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
1509                 w.write_str("</h4>");
1510             }
1511             clean::StrippedItem(..) => return,
1512             _ => panic!("can't make docs for trait item with name {:?}", item.name),
1513         }
1514
1515         if render_method_item {
1516             if !is_default_item {
1517                 if let Some(t) = trait_ {
1518                     // The trait item may have been stripped so we might not
1519                     // find any documentation or stability for it.
1520                     if let Some(it) = t.items.iter().find(|i| i.name == item.name) {
1521                         // We need the stability of the item from the trait
1522                         // because impls can't have a stability.
1523                         if item.doc_value().is_some() {
1524                             document_item_info(w, cx, it, is_hidden, Some(parent));
1525                             document_full(w, item, cx, is_hidden);
1526                         } else {
1527                             // In case the item isn't documented,
1528                             // provide short documentation from the trait.
1529                             document_short(w, it, cx, link, is_hidden, parent, show_def_docs);
1530                         }
1531                     }
1532                 } else {
1533                     document_item_info(w, cx, item, is_hidden, Some(parent));
1534                     if show_def_docs {
1535                         document_full(w, item, cx, is_hidden);
1536                     }
1537                 }
1538             } else {
1539                 document_short(w, item, cx, link, is_hidden, parent, show_def_docs);
1540             }
1541         }
1542     }
1543
1544     w.write_str("<div class=\"impl-items\">");
1545     for trait_item in &i.inner_impl().items {
1546         doc_impl_item(
1547             w,
1548             cx,
1549             trait_item,
1550             if trait_.is_some() { &i.impl_item } else { parent },
1551             link,
1552             render_mode,
1553             false,
1554             outer_version,
1555             outer_const_version,
1556             trait_.map(|t| &t.trait_),
1557             show_def_docs,
1558         );
1559     }
1560
1561     fn render_default_items(
1562         w: &mut Buffer,
1563         cx: &Context<'_>,
1564         t: &clean::Trait,
1565         i: &clean::Impl,
1566         parent: &clean::Item,
1567         render_mode: RenderMode,
1568         outer_version: Option<&str>,
1569         outer_const_version: Option<&str>,
1570         show_def_docs: bool,
1571     ) {
1572         for trait_item in &t.items {
1573             let n = trait_item.name;
1574             if i.items.iter().any(|m| m.name == n) {
1575                 continue;
1576             }
1577             let did = i.trait_.as_ref().unwrap().def_id_full(cx.cache()).unwrap();
1578             let assoc_link = AssocItemLink::GotoSource(did, &i.provided_trait_methods);
1579
1580             doc_impl_item(
1581                 w,
1582                 cx,
1583                 trait_item,
1584                 parent,
1585                 assoc_link,
1586                 render_mode,
1587                 true,
1588                 outer_version,
1589                 outer_const_version,
1590                 Some(t),
1591                 show_def_docs,
1592             );
1593         }
1594     }
1595
1596     // If we've implemented a trait, then also emit documentation for all
1597     // default items which weren't overridden in the implementation block.
1598     // We don't emit documentation for default items if they appear in the
1599     // Implementations on Foreign Types or Implementors sections.
1600     if show_default_items {
1601         if let Some(t) = trait_ {
1602             render_default_items(
1603                 w,
1604                 cx,
1605                 &t.trait_,
1606                 &i.inner_impl(),
1607                 &i.impl_item,
1608                 render_mode,
1609                 outer_version,
1610                 outer_const_version,
1611                 show_def_docs,
1612             );
1613         }
1614     }
1615     w.write_str("</div>");
1616 }
1617
1618 fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buffer) {
1619     let parentlen = cx.current.len() - if it.is_mod() { 1 } else { 0 };
1620
1621     if it.is_struct()
1622         || it.is_trait()
1623         || it.is_primitive()
1624         || it.is_union()
1625         || it.is_enum()
1626         || it.is_mod()
1627         || it.is_typedef()
1628     {
1629         write!(
1630             buffer,
1631             "<p class=\"location\">{}{}</p>",
1632             match *it.kind {
1633                 clean::StructItem(..) => "Struct ",
1634                 clean::TraitItem(..) => "Trait ",
1635                 clean::PrimitiveItem(..) => "Primitive Type ",
1636                 clean::UnionItem(..) => "Union ",
1637                 clean::EnumItem(..) => "Enum ",
1638                 clean::TypedefItem(..) => "Type Definition ",
1639                 clean::ForeignTypeItem => "Foreign Type ",
1640                 clean::ModuleItem(..) =>
1641                     if it.is_crate() {
1642                         "Crate "
1643                     } else {
1644                         "Module "
1645                     },
1646                 _ => "",
1647             },
1648             it.name.as_ref().unwrap()
1649         );
1650     }
1651
1652     if it.is_crate() {
1653         if let Some(ref version) = cx.cache.crate_version {
1654             write!(
1655                 buffer,
1656                 "<div class=\"block version\">\
1657                      <p>Version {}</p>\
1658                  </div>",
1659                 Escape(version)
1660             );
1661         }
1662     }
1663
1664     buffer.write_str("<div class=\"sidebar-elems\">");
1665     if it.is_crate() {
1666         write!(
1667             buffer,
1668             "<a id=\"all-types\" href=\"all.html\"><p>See all {}'s items</p></a>",
1669             it.name.as_ref().expect("crates always have a name")
1670         );
1671     }
1672     match *it.kind {
1673         clean::StructItem(ref s) => sidebar_struct(cx, buffer, it, s),
1674         clean::TraitItem(ref t) => sidebar_trait(cx, buffer, it, t),
1675         clean::PrimitiveItem(_) => sidebar_primitive(cx, buffer, it),
1676         clean::UnionItem(ref u) => sidebar_union(cx, buffer, it, u),
1677         clean::EnumItem(ref e) => sidebar_enum(cx, buffer, it, e),
1678         clean::TypedefItem(_, _) => sidebar_typedef(cx, buffer, it),
1679         clean::ModuleItem(ref m) => sidebar_module(buffer, &m.items),
1680         clean::ForeignTypeItem => sidebar_foreign_type(cx, buffer, it),
1681         _ => (),
1682     }
1683
1684     // The sidebar is designed to display sibling functions, modules and
1685     // other miscellaneous information. since there are lots of sibling
1686     // items (and that causes quadratic growth in large modules),
1687     // we refactor common parts into a shared JavaScript file per module.
1688     // still, we don't move everything into JS because we want to preserve
1689     // as much HTML as possible in order to allow non-JS-enabled browsers
1690     // to navigate the documentation (though slightly inefficiently).
1691
1692     buffer.write_str("<p class=\"location\">");
1693     for (i, name) in cx.current.iter().take(parentlen).enumerate() {
1694         if i > 0 {
1695             buffer.write_str("::<wbr>");
1696         }
1697         write!(
1698             buffer,
1699             "<a href=\"{}index.html\">{}</a>",
1700             &cx.root_path()[..(cx.current.len() - i - 1) * 3],
1701             *name
1702         );
1703     }
1704     buffer.write_str("</p>");
1705
1706     // Sidebar refers to the enclosing module, not this module.
1707     let relpath = if it.is_mod() { "../" } else { "" };
1708     write!(
1709         buffer,
1710         "<div id=\"sidebar-vars\" data-name=\"{name}\" data-ty=\"{ty}\" data-relpath=\"{path}\">\
1711         </div>",
1712         name = it.name.unwrap_or(kw::Empty),
1713         ty = it.type_(),
1714         path = relpath
1715     );
1716     if parentlen == 0 {
1717         // There is no sidebar-items.js beyond the crate root path
1718         // FIXME maybe dynamic crate loading can be merged here
1719     } else {
1720         write!(buffer, "<script defer src=\"{path}sidebar-items.js\"></script>", path = relpath);
1721     }
1722     // Closes sidebar-elems div.
1723     buffer.write_str("</div>");
1724 }
1725
1726 fn get_next_url(used_links: &mut FxHashSet<String>, url: String) -> String {
1727     if used_links.insert(url.clone()) {
1728         return url;
1729     }
1730     let mut add = 1;
1731     while !used_links.insert(format!("{}-{}", url, add)) {
1732         add += 1;
1733     }
1734     format!("{}-{}", url, add)
1735 }
1736
1737 fn get_methods(
1738     i: &clean::Impl,
1739     for_deref: bool,
1740     used_links: &mut FxHashSet<String>,
1741     deref_mut: bool,
1742     cache: &Cache,
1743 ) -> Vec<String> {
1744     i.items
1745         .iter()
1746         .filter_map(|item| match item.name {
1747             Some(ref name) if !name.is_empty() && item.is_method() => {
1748                 if !for_deref || should_render_item(item, deref_mut, cache) {
1749                     Some(format!(
1750                         "<a href=\"#{}\">{}</a>",
1751                         get_next_url(used_links, format!("method.{}", name)),
1752                         name
1753                     ))
1754                 } else {
1755                     None
1756                 }
1757             }
1758             _ => None,
1759         })
1760         .collect::<Vec<_>>()
1761 }
1762
1763 // The point is to url encode any potential character from a type with genericity.
1764 fn small_url_encode(s: String) -> String {
1765     let mut st = String::new();
1766     let mut last_match = 0;
1767     for (idx, c) in s.char_indices() {
1768         let escaped = match c {
1769             '<' => "%3C",
1770             '>' => "%3E",
1771             ' ' => "%20",
1772             '?' => "%3F",
1773             '\'' => "%27",
1774             '&' => "%26",
1775             ',' => "%2C",
1776             ':' => "%3A",
1777             ';' => "%3B",
1778             '[' => "%5B",
1779             ']' => "%5D",
1780             '"' => "%22",
1781             _ => continue,
1782         };
1783
1784         st += &s[last_match..idx];
1785         st += escaped;
1786         // NOTE: we only expect single byte characters here - which is fine as long as we
1787         // only match single byte characters
1788         last_match = idx + 1;
1789     }
1790
1791     if last_match != 0 {
1792         st += &s[last_match..];
1793         st
1794     } else {
1795         s
1796     }
1797 }
1798
1799 fn sidebar_assoc_items(cx: &Context<'_>, out: &mut Buffer, it: &clean::Item) {
1800     if let Some(v) = cx.cache.impls.get(&it.def_id) {
1801         let mut used_links = FxHashSet::default();
1802         let cache = cx.cache();
1803
1804         {
1805             let used_links_bor = &mut used_links;
1806             let mut ret = v
1807                 .iter()
1808                 .filter(|i| i.inner_impl().trait_.is_none())
1809                 .flat_map(move |i| {
1810                     get_methods(i.inner_impl(), false, used_links_bor, false, &cx.cache)
1811                 })
1812                 .collect::<Vec<_>>();
1813             if !ret.is_empty() {
1814                 // We want links' order to be reproducible so we don't use unstable sort.
1815                 ret.sort();
1816
1817                 out.push_str(
1818                     "<a class=\"sidebar-title\" href=\"#implementations\">Methods</a>\
1819                      <div class=\"sidebar-links\">",
1820                 );
1821                 for line in ret {
1822                     out.push_str(&line);
1823                 }
1824                 out.push_str("</div>");
1825             }
1826         }
1827
1828         if v.iter().any(|i| i.inner_impl().trait_.is_some()) {
1829             let format_impls = |impls: Vec<&Impl>| {
1830                 let mut links = FxHashSet::default();
1831
1832                 let mut ret = impls
1833                     .iter()
1834                     .filter_map(|it| {
1835                         if let Some(ref i) = it.inner_impl().trait_ {
1836                             let i_display = format!("{:#}", i.print(cx));
1837                             let out = Escape(&i_display);
1838                             let encoded = small_url_encode(format!("{:#}", i.print(cx)));
1839                             let generated = format!(
1840                                 "<a href=\"#impl-{}\">{}{}</a>",
1841                                 encoded,
1842                                 if it.inner_impl().negative_polarity { "!" } else { "" },
1843                                 out
1844                             );
1845                             if links.insert(generated.clone()) { Some(generated) } else { None }
1846                         } else {
1847                             None
1848                         }
1849                     })
1850                     .collect::<Vec<String>>();
1851                 ret.sort();
1852                 ret
1853             };
1854
1855             let write_sidebar_links = |out: &mut Buffer, links: Vec<String>| {
1856                 out.push_str("<div class=\"sidebar-links\">");
1857                 for link in links {
1858                     out.push_str(&link);
1859                 }
1860                 out.push_str("</div>");
1861             };
1862
1863             let (synthetic, concrete): (Vec<&Impl>, Vec<&Impl>) =
1864                 v.iter().partition::<Vec<_>, _>(|i| i.inner_impl().synthetic);
1865             let (blanket_impl, concrete): (Vec<&Impl>, Vec<&Impl>) = concrete
1866                 .into_iter()
1867                 .partition::<Vec<_>, _>(|i| i.inner_impl().blanket_impl.is_some());
1868
1869             let concrete_format = format_impls(concrete);
1870             let synthetic_format = format_impls(synthetic);
1871             let blanket_format = format_impls(blanket_impl);
1872
1873             if !concrete_format.is_empty() {
1874                 out.push_str(
1875                     "<a class=\"sidebar-title\" href=\"#trait-implementations\">\
1876                         Trait Implementations</a>",
1877                 );
1878                 write_sidebar_links(out, concrete_format);
1879             }
1880
1881             if !synthetic_format.is_empty() {
1882                 out.push_str(
1883                     "<a class=\"sidebar-title\" href=\"#synthetic-implementations\">\
1884                         Auto Trait Implementations</a>",
1885                 );
1886                 write_sidebar_links(out, synthetic_format);
1887             }
1888
1889             if !blanket_format.is_empty() {
1890                 out.push_str(
1891                     "<a class=\"sidebar-title\" href=\"#blanket-implementations\">\
1892                         Blanket Implementations</a>",
1893                 );
1894                 write_sidebar_links(out, blanket_format);
1895             }
1896
1897             if let Some(impl_) = v
1898                 .iter()
1899                 .filter(|i| i.inner_impl().trait_.is_some())
1900                 .find(|i| i.inner_impl().trait_.def_id_full(cache) == cx.cache.deref_trait_did)
1901             {
1902                 sidebar_deref_methods(cx, out, impl_, v);
1903             }
1904         }
1905     }
1906 }
1907
1908 fn sidebar_deref_methods(cx: &Context<'_>, out: &mut Buffer, impl_: &Impl, v: &Vec<Impl>) {
1909     let c = cx.cache();
1910
1911     debug!("found Deref: {:?}", impl_);
1912     if let Some((target, real_target)) =
1913         impl_.inner_impl().items.iter().find_map(|item| match *item.kind {
1914             clean::TypedefItem(ref t, true) => Some(match *t {
1915                 clean::Typedef { item_type: Some(ref type_), .. } => (type_, &t.type_),
1916                 _ => (&t.type_, &t.type_),
1917             }),
1918             _ => None,
1919         })
1920     {
1921         debug!("found target, real_target: {:?} {:?}", target, real_target);
1922         if let Some(did) = target.def_id_full(c) {
1923             if let Some(type_did) = impl_.inner_impl().for_.def_id_full(c) {
1924                 // `impl Deref<Target = S> for S`
1925                 if did == type_did {
1926                     // Avoid infinite cycles
1927                     return;
1928                 }
1929             }
1930         }
1931         let deref_mut = v
1932             .iter()
1933             .filter(|i| i.inner_impl().trait_.is_some())
1934             .any(|i| i.inner_impl().trait_.def_id_full(c) == c.deref_mut_trait_did);
1935         let inner_impl = target
1936             .def_id_full(c)
1937             .or_else(|| {
1938                 target.primitive_type().and_then(|prim| c.primitive_locations.get(&prim).cloned())
1939             })
1940             .and_then(|did| c.impls.get(&did));
1941         if let Some(impls) = inner_impl {
1942             debug!("found inner_impl: {:?}", impls);
1943             let mut used_links = FxHashSet::default();
1944             let mut ret = impls
1945                 .iter()
1946                 .filter(|i| i.inner_impl().trait_.is_none())
1947                 .flat_map(|i| get_methods(i.inner_impl(), true, &mut used_links, deref_mut, c))
1948                 .collect::<Vec<_>>();
1949             if !ret.is_empty() {
1950                 let deref_id_map = cx.deref_id_map.borrow();
1951                 let id = deref_id_map
1952                     .get(&real_target.def_id_full(c).unwrap())
1953                     .expect("Deref section without derived id");
1954                 write!(
1955                     out,
1956                     "<a class=\"sidebar-title\" href=\"#{}\">Methods from {}&lt;Target={}&gt;</a>",
1957                     id,
1958                     Escape(&format!("{:#}", impl_.inner_impl().trait_.as_ref().unwrap().print(cx))),
1959                     Escape(&format!("{:#}", real_target.print(cx))),
1960                 );
1961                 // We want links' order to be reproducible so we don't use unstable sort.
1962                 ret.sort();
1963                 out.push_str("<div class=\"sidebar-links\">");
1964                 for link in ret {
1965                     out.push_str(&link);
1966                 }
1967                 out.push_str("</div>");
1968             }
1969         }
1970
1971         // Recurse into any further impls that might exist for `target`
1972         if let Some(target_did) = target.def_id_full(c) {
1973             if let Some(target_impls) = c.impls.get(&target_did) {
1974                 if let Some(target_deref_impl) = target_impls
1975                     .iter()
1976                     .filter(|i| i.inner_impl().trait_.is_some())
1977                     .find(|i| i.inner_impl().trait_.def_id_full(c) == c.deref_trait_did)
1978                 {
1979                     sidebar_deref_methods(cx, out, target_deref_impl, target_impls);
1980                 }
1981             }
1982         }
1983     }
1984 }
1985
1986 fn sidebar_struct(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, s: &clean::Struct) {
1987     let mut sidebar = Buffer::new();
1988     let fields = get_struct_fields_name(&s.fields);
1989
1990     if !fields.is_empty() {
1991         if let CtorKind::Fictive = s.struct_type {
1992             sidebar.push_str(
1993                 "<a class=\"sidebar-title\" href=\"#fields\">Fields</a>\
1994                 <div class=\"sidebar-links\">",
1995             );
1996
1997             for field in fields {
1998                 sidebar.push_str(&field);
1999             }
2000
2001             sidebar.push_str("</div>");
2002         }
2003     }
2004
2005     sidebar_assoc_items(cx, &mut sidebar, it);
2006
2007     if !sidebar.is_empty() {
2008         write!(buf, "<div class=\"block items\">{}</div>", sidebar.into_inner());
2009     }
2010 }
2011
2012 fn get_id_for_impl_on_foreign_type(
2013     for_: &clean::Type,
2014     trait_: &clean::Type,
2015     cx: &Context<'_>,
2016 ) -> String {
2017     small_url_encode(format!("impl-{:#}-for-{:#}", trait_.print(cx), for_.print(cx),))
2018 }
2019
2020 fn extract_for_impl_name(item: &clean::Item, cx: &Context<'_>) -> Option<(String, String)> {
2021     match *item.kind {
2022         clean::ItemKind::ImplItem(ref i) => {
2023             if let Some(ref trait_) = i.trait_ {
2024                 // Alternative format produces no URLs,
2025                 // so this parameter does nothing.
2026                 Some((
2027                     format!("{:#}", i.for_.print(cx)),
2028                     get_id_for_impl_on_foreign_type(&i.for_, trait_, cx),
2029                 ))
2030             } else {
2031                 None
2032             }
2033         }
2034         _ => None,
2035     }
2036 }
2037
2038 fn sidebar_trait(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, t: &clean::Trait) {
2039     buf.write_str("<div class=\"block items\">");
2040
2041     fn print_sidebar_section(
2042         out: &mut Buffer,
2043         items: &[clean::Item],
2044         before: &str,
2045         filter: impl Fn(&clean::Item) -> bool,
2046         write: impl Fn(&mut Buffer, &str),
2047         after: &str,
2048     ) {
2049         let mut items = items
2050             .iter()
2051             .filter_map(|m| match m.name {
2052                 Some(ref name) if filter(m) => Some(name.as_str()),
2053                 _ => None,
2054             })
2055             .collect::<Vec<_>>();
2056
2057         if !items.is_empty() {
2058             items.sort_unstable();
2059             out.push_str(before);
2060             for item in items.into_iter() {
2061                 write(out, &item);
2062             }
2063             out.push_str(after);
2064         }
2065     }
2066
2067     print_sidebar_section(
2068         buf,
2069         &t.items,
2070         "<a class=\"sidebar-title\" href=\"#associated-types\">\
2071             Associated Types</a><div class=\"sidebar-links\">",
2072         |m| m.is_associated_type(),
2073         |out, sym| write!(out, "<a href=\"#associatedtype.{0}\">{0}</a>", sym),
2074         "</div>",
2075     );
2076
2077     print_sidebar_section(
2078         buf,
2079         &t.items,
2080         "<a class=\"sidebar-title\" href=\"#associated-const\">\
2081             Associated Constants</a><div class=\"sidebar-links\">",
2082         |m| m.is_associated_const(),
2083         |out, sym| write!(out, "<a href=\"#associatedconstant.{0}\">{0}</a>", sym),
2084         "</div>",
2085     );
2086
2087     print_sidebar_section(
2088         buf,
2089         &t.items,
2090         "<a class=\"sidebar-title\" href=\"#required-methods\">\
2091             Required Methods</a><div class=\"sidebar-links\">",
2092         |m| m.is_ty_method(),
2093         |out, sym| write!(out, "<a href=\"#tymethod.{0}\">{0}</a>", sym),
2094         "</div>",
2095     );
2096
2097     print_sidebar_section(
2098         buf,
2099         &t.items,
2100         "<a class=\"sidebar-title\" href=\"#provided-methods\">\
2101             Provided Methods</a><div class=\"sidebar-links\">",
2102         |m| m.is_method(),
2103         |out, sym| write!(out, "<a href=\"#method.{0}\">{0}</a>", sym),
2104         "</div>",
2105     );
2106
2107     if let Some(implementors) = cx.cache.implementors.get(&it.def_id) {
2108         let cache = cx.cache();
2109         let mut res = implementors
2110             .iter()
2111             .filter(|i| {
2112                 i.inner_impl()
2113                     .for_
2114                     .def_id_full(cache)
2115                     .map_or(false, |d| !cx.cache.paths.contains_key(&d))
2116             })
2117             .filter_map(|i| extract_for_impl_name(&i.impl_item, cx))
2118             .collect::<Vec<_>>();
2119
2120         if !res.is_empty() {
2121             res.sort();
2122             buf.push_str(
2123                 "<a class=\"sidebar-title\" href=\"#foreign-impls\">\
2124                     Implementations on Foreign Types</a>\
2125                  <div class=\"sidebar-links\">",
2126             );
2127             for (name, id) in res.into_iter() {
2128                 write!(buf, "<a href=\"#{}\">{}</a>", id, Escape(&name));
2129             }
2130             buf.push_str("</div>");
2131         }
2132     }
2133
2134     sidebar_assoc_items(cx, buf, it);
2135
2136     buf.push_str("<a class=\"sidebar-title\" href=\"#implementors\">Implementors</a>");
2137     if t.is_auto {
2138         buf.push_str(
2139             "<a class=\"sidebar-title\" \
2140                 href=\"#synthetic-implementors\">Auto Implementors</a>",
2141         );
2142     }
2143
2144     buf.push_str("</div>")
2145 }
2146
2147 fn sidebar_primitive(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item) {
2148     let mut sidebar = Buffer::new();
2149     sidebar_assoc_items(cx, &mut sidebar, it);
2150
2151     if !sidebar.is_empty() {
2152         write!(buf, "<div class=\"block items\">{}</div>", sidebar.into_inner());
2153     }
2154 }
2155
2156 fn sidebar_typedef(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item) {
2157     let mut sidebar = Buffer::new();
2158     sidebar_assoc_items(cx, &mut sidebar, it);
2159
2160     if !sidebar.is_empty() {
2161         write!(buf, "<div class=\"block items\">{}</div>", sidebar.into_inner());
2162     }
2163 }
2164
2165 fn get_struct_fields_name(fields: &[clean::Item]) -> Vec<String> {
2166     let mut fields = fields
2167         .iter()
2168         .filter(|f| matches!(*f.kind, clean::StructFieldItem(..)))
2169         .filter_map(|f| {
2170             f.name.map(|name| format!("<a href=\"#structfield.{name}\">{name}</a>", name = name))
2171         })
2172         .collect::<Vec<_>>();
2173     fields.sort();
2174     fields
2175 }
2176
2177 fn sidebar_union(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, u: &clean::Union) {
2178     let mut sidebar = Buffer::new();
2179     let fields = get_struct_fields_name(&u.fields);
2180
2181     if !fields.is_empty() {
2182         sidebar.push_str(
2183             "<a class=\"sidebar-title\" href=\"#fields\">Fields</a>\
2184             <div class=\"sidebar-links\">",
2185         );
2186
2187         for field in fields {
2188             sidebar.push_str(&field);
2189         }
2190
2191         sidebar.push_str("</div>");
2192     }
2193
2194     sidebar_assoc_items(cx, &mut sidebar, it);
2195
2196     if !sidebar.is_empty() {
2197         write!(buf, "<div class=\"block items\">{}</div>", sidebar.into_inner());
2198     }
2199 }
2200
2201 fn sidebar_enum(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, e: &clean::Enum) {
2202     let mut sidebar = Buffer::new();
2203
2204     let mut variants = e
2205         .variants
2206         .iter()
2207         .filter_map(|v| match v.name {
2208             Some(ref name) => Some(format!("<a href=\"#variant.{name}\">{name}</a>", name = name)),
2209             _ => None,
2210         })
2211         .collect::<Vec<_>>();
2212     if !variants.is_empty() {
2213         variants.sort_unstable();
2214         sidebar.push_str(&format!(
2215             "<a class=\"sidebar-title\" href=\"#variants\">Variants</a>\
2216              <div class=\"sidebar-links\">{}</div>",
2217             variants.join(""),
2218         ));
2219     }
2220
2221     sidebar_assoc_items(cx, &mut sidebar, it);
2222
2223     if !sidebar.is_empty() {
2224         write!(buf, "<div class=\"block items\">{}</div>", sidebar.into_inner());
2225     }
2226 }
2227
2228 fn item_ty_to_strs(ty: &ItemType) -> (&'static str, &'static str) {
2229     match *ty {
2230         ItemType::ExternCrate | ItemType::Import => ("reexports", "Re-exports"),
2231         ItemType::Module => ("modules", "Modules"),
2232         ItemType::Struct => ("structs", "Structs"),
2233         ItemType::Union => ("unions", "Unions"),
2234         ItemType::Enum => ("enums", "Enums"),
2235         ItemType::Function => ("functions", "Functions"),
2236         ItemType::Typedef => ("types", "Type Definitions"),
2237         ItemType::Static => ("statics", "Statics"),
2238         ItemType::Constant => ("constants", "Constants"),
2239         ItemType::Trait => ("traits", "Traits"),
2240         ItemType::Impl => ("impls", "Implementations"),
2241         ItemType::TyMethod => ("tymethods", "Type Methods"),
2242         ItemType::Method => ("methods", "Methods"),
2243         ItemType::StructField => ("fields", "Struct Fields"),
2244         ItemType::Variant => ("variants", "Variants"),
2245         ItemType::Macro => ("macros", "Macros"),
2246         ItemType::Primitive => ("primitives", "Primitive Types"),
2247         ItemType::AssocType => ("associated-types", "Associated Types"),
2248         ItemType::AssocConst => ("associated-consts", "Associated Constants"),
2249         ItemType::ForeignType => ("foreign-types", "Foreign Types"),
2250         ItemType::Keyword => ("keywords", "Keywords"),
2251         ItemType::OpaqueTy => ("opaque-types", "Opaque Types"),
2252         ItemType::ProcAttribute => ("attributes", "Attribute Macros"),
2253         ItemType::ProcDerive => ("derives", "Derive Macros"),
2254         ItemType::TraitAlias => ("trait-aliases", "Trait aliases"),
2255     }
2256 }
2257
2258 fn sidebar_module(buf: &mut Buffer, items: &[clean::Item]) {
2259     let mut sidebar = String::new();
2260
2261     if items.iter().any(|it| {
2262         it.type_() == ItemType::ExternCrate || (it.type_() == ItemType::Import && !it.is_stripped())
2263     }) {
2264         sidebar.push_str("<li><a href=\"#reexports\">Re-exports</a></li>");
2265     }
2266
2267     // ordering taken from item_module, reorder, where it prioritized elements in a certain order
2268     // to print its headings
2269     for &myty in &[
2270         ItemType::Primitive,
2271         ItemType::Module,
2272         ItemType::Macro,
2273         ItemType::Struct,
2274         ItemType::Enum,
2275         ItemType::Constant,
2276         ItemType::Static,
2277         ItemType::Trait,
2278         ItemType::Function,
2279         ItemType::Typedef,
2280         ItemType::Union,
2281         ItemType::Impl,
2282         ItemType::TyMethod,
2283         ItemType::Method,
2284         ItemType::StructField,
2285         ItemType::Variant,
2286         ItemType::AssocType,
2287         ItemType::AssocConst,
2288         ItemType::ForeignType,
2289         ItemType::Keyword,
2290     ] {
2291         if items.iter().any(|it| !it.is_stripped() && it.type_() == myty) {
2292             let (short, name) = item_ty_to_strs(&myty);
2293             sidebar.push_str(&format!(
2294                 "<li><a href=\"#{id}\">{name}</a></li>",
2295                 id = short,
2296                 name = name
2297             ));
2298         }
2299     }
2300
2301     if !sidebar.is_empty() {
2302         write!(buf, "<div class=\"block items\"><ul>{}</ul></div>", sidebar);
2303     }
2304 }
2305
2306 fn sidebar_foreign_type(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item) {
2307     let mut sidebar = Buffer::new();
2308     sidebar_assoc_items(cx, &mut sidebar, it);
2309
2310     if !sidebar.is_empty() {
2311         write!(buf, "<div class=\"block items\">{}</div>", sidebar.into_inner());
2312     }
2313 }
2314
2315 crate const BASIC_KEYWORDS: &str = "rust, rustlang, rust-lang";
2316
2317 /// Returns a list of all paths used in the type.
2318 /// This is used to help deduplicate imported impls
2319 /// for reexported types. If any of the contained
2320 /// types are re-exported, we don't use the corresponding
2321 /// entry from the js file, as inlining will have already
2322 /// picked up the impl
2323 fn collect_paths_for_type(first_ty: clean::Type, cache: &Cache) -> Vec<String> {
2324     let mut out = Vec::new();
2325     let mut visited = FxHashSet::default();
2326     let mut work = VecDeque::new();
2327
2328     work.push_back(first_ty);
2329
2330     while let Some(ty) = work.pop_front() {
2331         if !visited.insert(ty.clone()) {
2332             continue;
2333         }
2334
2335         match ty {
2336             clean::Type::ResolvedPath { did, .. } => {
2337                 let get_extern = || cache.external_paths.get(&did).map(|s| s.0.clone());
2338                 let fqp = cache.exact_paths.get(&did).cloned().or_else(get_extern);
2339
2340                 if let Some(path) = fqp {
2341                     out.push(path.join("::"));
2342                 }
2343             }
2344             clean::Type::Tuple(tys) => {
2345                 work.extend(tys.into_iter());
2346             }
2347             clean::Type::Slice(ty) => {
2348                 work.push_back(*ty);
2349             }
2350             clean::Type::Array(ty, _) => {
2351                 work.push_back(*ty);
2352             }
2353             clean::Type::RawPointer(_, ty) => {
2354                 work.push_back(*ty);
2355             }
2356             clean::Type::BorrowedRef { type_, .. } => {
2357                 work.push_back(*type_);
2358             }
2359             clean::Type::QPath { self_type, trait_, .. } => {
2360                 work.push_back(*self_type);
2361                 work.push_back(*trait_);
2362             }
2363             _ => {}
2364         }
2365     }
2366     out
2367 }