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