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