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