]> git.lizzy.rs Git - rust.git/blob - src/librustdoc/html/render.rs
2774f2b4751bac64ec759942f1f872a8c94423e7
[rust.git] / src / librustdoc / html / render.rs
1 // ignore-tidy-filelength
2
3 //! Rustdoc's HTML rendering module.
4 //!
5 //! This modules contains the bulk of the logic necessary for rendering a
6 //! rustdoc `clean::Crate` instance to a set of static HTML pages. This
7 //! rendering process is largely driven by the `format!` syntax extension to
8 //! perform all I/O into files and streams.
9 //!
10 //! The rendering process is largely driven by the `Context` and `Cache`
11 //! structures. The cache is pre-populated by crawling the crate in question,
12 //! and then it is shared among the various rendering threads. The cache is meant
13 //! to be a fairly large structure not implementing `Clone` (because it's shared
14 //! among threads). The context, however, should be a lightweight structure. This
15 //! is cloned per-thread and contains information about what is currently being
16 //! rendered.
17 //!
18 //! In order to speed up rendering (mostly because of markdown rendering), the
19 //! rendering process has been parallelized. This parallelization is only
20 //! exposed through the `crate` method on the context, and then also from the
21 //! fact that the shared cache is stored in TLS (and must be accessed as such).
22 //!
23 //! In addition to rendering the crate itself, this module is also responsible
24 //! for creating the corresponding search index and source file renderings.
25 //! These threads are not parallelized (they haven't been a bottleneck yet), and
26 //! both occur before the crate is rendered.
27
28 pub use self::ExternalLocation::*;
29
30 use std::borrow::Cow;
31 use std::cell::RefCell;
32 use std::cmp::Ordering;
33 use std::collections::{BTreeMap, VecDeque};
34 use std::default::Default;
35 use std::error;
36 use std::fmt::{self, Display, Formatter, Write as FmtWrite};
37 use std::ffi::OsStr;
38 use std::fs::{self, File};
39 use std::io::prelude::*;
40 use std::io::{self, BufReader};
41 use std::mem;
42 use std::path::{PathBuf, Path, Component};
43 use std::str;
44 use std::sync::Arc;
45 use std::rc::Rc;
46
47 use errors;
48 use serialize::json::{ToJson, Json, as_json};
49 use syntax::ast;
50 use syntax::edition::Edition;
51 use syntax::ext::base::MacroKind;
52 use syntax::source_map::FileName;
53 use syntax::feature_gate::UnstableFeatures;
54 use syntax::symbol::{Symbol, sym};
55 use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId};
56 use rustc::middle::privacy::AccessLevels;
57 use rustc::middle::stability;
58 use rustc::hir;
59 use rustc::util::nodemap::{FxHashMap, FxHashSet};
60 use rustc_data_structures::flock;
61
62 use crate::clean::{self, AttributesExt, Deprecation, GetDefId, SelfTy, Mutability};
63 use crate::config::RenderOptions;
64 use crate::docfs::{DocFS, ErrorStorage, PathError};
65 use crate::doctree;
66 use crate::fold::DocFolder;
67 use crate::html::escape::Escape;
68 use crate::html::format::{AsyncSpace, ConstnessSpace};
69 use crate::html::format::{GenericBounds, WhereClause, href, AbiSpace, DefaultSpace};
70 use crate::html::format::{VisSpace, Function, UnsafetySpace, MutableSpace};
71 use crate::html::format::fmt_impl_for_trait_page;
72 use crate::html::item_type::ItemType;
73 use crate::html::markdown::{self, Markdown, MarkdownHtml, MarkdownSummaryLine, ErrorCodes, IdMap};
74 use crate::html::{highlight, layout, static_files};
75
76 use minifier;
77
78 #[cfg(test)]
79 mod tests;
80
81 /// A pair of name and its optional document.
82 pub type NameDoc = (String, Option<String>);
83
84 pub struct SlashChecker<'a>(pub &'a str);
85
86 impl<'a> Display for SlashChecker<'a> {
87     fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
88         if !self.0.ends_with("/") && !self.0.is_empty() {
89             write!(f, "{}/", self.0)
90         } else {
91             write!(f, "{}", self.0)
92         }
93     }
94 }
95
96 #[derive(Debug)]
97 pub struct Error {
98     pub file: PathBuf,
99     pub error: io::Error,
100 }
101
102 impl error::Error for Error {
103     fn description(&self) -> &str {
104         self.error.description()
105     }
106 }
107
108 impl Display for Error {
109     fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
110         let file = self.file.display().to_string();
111         if file.is_empty() {
112             write!(f, "{}", self.error)
113         } else {
114             write!(f, "\"{}\": {}", self.file.display(), self.error)
115         }
116     }
117 }
118
119 impl PathError for Error {
120     fn new<P: AsRef<Path>>(e: io::Error, path: P) -> Error {
121         Error {
122             file: path.as_ref().to_path_buf(),
123             error: e,
124         }
125     }
126 }
127
128 macro_rules! try_none {
129     ($e:expr, $file:expr) => ({
130         use std::io;
131         match $e {
132             Some(e) => e,
133             None => return Err(Error::new(io::Error::new(io::ErrorKind::Other, "not found"),
134                                           $file))
135         }
136     })
137 }
138
139 macro_rules! try_err {
140     ($e:expr, $file:expr) => ({
141         match $e {
142             Ok(e) => e,
143             Err(e) => return Err(Error::new(e, $file)),
144         }
145     })
146 }
147
148 /// Major driving force in all rustdoc rendering. This contains information
149 /// about where in the tree-like hierarchy rendering is occurring and controls
150 /// how the current page is being rendered.
151 ///
152 /// It is intended that this context is a lightweight object which can be fairly
153 /// easily cloned because it is cloned per work-job (about once per item in the
154 /// rustdoc tree).
155 #[derive(Clone)]
156 struct Context {
157     /// Current hierarchy of components leading down to what's currently being
158     /// rendered
159     pub current: Vec<String>,
160     /// The current destination folder of where HTML artifacts should be placed.
161     /// This changes as the context descends into the module hierarchy.
162     pub dst: PathBuf,
163     /// A flag, which when `true`, will render pages which redirect to the
164     /// real location of an item. This is used to allow external links to
165     /// publicly reused items to redirect to the right location.
166     pub render_redirect_pages: bool,
167     pub codes: ErrorCodes,
168     /// The default edition used to parse doctests.
169     pub edition: Edition,
170     /// The map used to ensure all generated 'id=' attributes are unique.
171     id_map: Rc<RefCell<IdMap>>,
172     pub shared: Arc<SharedContext>,
173 }
174
175 struct SharedContext {
176     /// The path to the crate root source minus the file name.
177     /// Used for simplifying paths to the highlighted source code files.
178     pub src_root: PathBuf,
179     /// This describes the layout of each page, and is not modified after
180     /// creation of the context (contains info like the favicon and added html).
181     pub layout: layout::Layout,
182     /// This flag indicates whether `[src]` links should be generated or not. If
183     /// the source files are present in the html rendering, then this will be
184     /// `true`.
185     pub include_sources: bool,
186     /// The local file sources we've emitted and their respective url-paths.
187     pub local_sources: FxHashMap<PathBuf, String>,
188     /// All the passes that were run on this crate.
189     pub passes: FxHashSet<String>,
190     /// The base-URL of the issue tracker for when an item has been tagged with
191     /// an issue number.
192     pub issue_tracker_base_url: Option<String>,
193     /// The given user css file which allow to customize the generated
194     /// documentation theme.
195     pub css_file_extension: Option<PathBuf>,
196     /// The directories that have already been created in this doc run. Used to reduce the number
197     /// of spurious `create_dir_all` calls.
198     pub created_dirs: RefCell<FxHashSet<PathBuf>>,
199     /// This flag indicates whether listings of modules (in the side bar and documentation itself)
200     /// should be ordered alphabetically or in order of appearance (in the source code).
201     pub sort_modules_alphabetically: bool,
202     /// Additional themes to be added to the generated docs.
203     pub themes: Vec<PathBuf>,
204     /// Suffix to be added on resource files (if suffix is "-v2" then "light.css" becomes
205     /// "light-v2.css").
206     pub resource_suffix: String,
207     /// Optional path string to be used to load static files on output pages. If not set, uses
208     /// combinations of `../` to reach the documentation root.
209     pub static_root_path: Option<String>,
210     /// If false, the `select` element to have search filtering by crates on rendered docs
211     /// won't be generated.
212     pub generate_search_filter: bool,
213     /// Option disabled by default to generate files used by RLS and some other tools.
214     pub generate_redirect_pages: bool,
215     /// The fs handle we are working with.
216     pub fs: DocFS,
217 }
218
219 impl SharedContext {
220     fn ensure_dir(&self, dst: &Path) -> Result<(), Error> {
221         let mut dirs = self.created_dirs.borrow_mut();
222         if !dirs.contains(dst) {
223             try_err!(self.fs.create_dir_all(dst), dst);
224             dirs.insert(dst.to_path_buf());
225         }
226
227         Ok(())
228     }
229 }
230
231 impl SharedContext {
232     /// Returns `true` if the `collapse-docs` pass was run on this crate.
233     pub fn was_collapsed(&self) -> bool {
234         self.passes.contains("collapse-docs")
235     }
236
237     /// Based on whether the `collapse-docs` pass was run, return either the `doc_value` or the
238     /// `collapsed_doc_value` of the given item.
239     pub fn maybe_collapsed_doc_value<'a>(&self, item: &'a clean::Item) -> Option<Cow<'a, str>> {
240         if self.was_collapsed() {
241             item.collapsed_doc_value().map(|s| s.into())
242         } else {
243             item.doc_value().map(|s| s.into())
244         }
245     }
246 }
247
248 /// Indicates where an external crate can be found.
249 pub enum ExternalLocation {
250     /// Remote URL root of the external crate
251     Remote(String),
252     /// This external crate can be found in the local doc/ folder
253     Local,
254     /// The external crate could not be found.
255     Unknown,
256 }
257
258 /// Metadata about implementations for a type or trait.
259 #[derive(Clone, Debug)]
260 pub struct Impl {
261     pub impl_item: clean::Item,
262 }
263
264 impl Impl {
265     fn inner_impl(&self) -> &clean::Impl {
266         match self.impl_item.inner {
267             clean::ImplItem(ref impl_) => impl_,
268             _ => panic!("non-impl item found in impl")
269         }
270     }
271
272     fn trait_did(&self) -> Option<DefId> {
273         self.inner_impl().trait_.def_id()
274     }
275 }
276
277 /// This cache is used to store information about the `clean::Crate` being
278 /// rendered in order to provide more useful documentation. This contains
279 /// information like all implementors of a trait, all traits a type implements,
280 /// documentation for all known traits, etc.
281 ///
282 /// This structure purposefully does not implement `Clone` because it's intended
283 /// to be a fairly large and expensive structure to clone. Instead this adheres
284 /// to `Send` so it may be stored in a `Arc` instance and shared among the various
285 /// rendering threads.
286 #[derive(Default)]
287 pub struct Cache {
288     /// Mapping of typaram ids to the name of the type parameter. This is used
289     /// when pretty-printing a type (so pretty-printing doesn't have to
290     /// painfully maintain a context like this)
291     pub param_names: FxHashMap<DefId, String>,
292
293     /// Maps a type ID to all known implementations for that type. This is only
294     /// recognized for intra-crate `ResolvedPath` types, and is used to print
295     /// out extra documentation on the page of an enum/struct.
296     ///
297     /// The values of the map are a list of implementations and documentation
298     /// found on that implementation.
299     pub impls: FxHashMap<DefId, Vec<Impl>>,
300
301     /// Maintains a mapping of local crate `NodeId`s to the fully qualified name
302     /// and "short type description" of that node. This is used when generating
303     /// URLs when a type is being linked to. External paths are not located in
304     /// this map because the `External` type itself has all the information
305     /// necessary.
306     pub paths: FxHashMap<DefId, (Vec<String>, ItemType)>,
307
308     /// Similar to `paths`, but only holds external paths. This is only used for
309     /// generating explicit hyperlinks to other crates.
310     pub external_paths: FxHashMap<DefId, (Vec<String>, ItemType)>,
311
312     /// Maps local `DefId`s of exported types to fully qualified paths.
313     /// Unlike 'paths', this mapping ignores any renames that occur
314     /// due to 'use' statements.
315     ///
316     /// This map is used when writing out the special 'implementors'
317     /// javascript file. By using the exact path that the type
318     /// is declared with, we ensure that each path will be identical
319     /// to the path used if the corresponding type is inlined. By
320     /// doing this, we can detect duplicate impls on a trait page, and only display
321     /// the impl for the inlined type.
322     pub exact_paths: FxHashMap<DefId, Vec<String>>,
323
324     /// This map contains information about all known traits of this crate.
325     /// Implementations of a crate should inherit the documentation of the
326     /// parent trait if no extra documentation is specified, and default methods
327     /// should show up in documentation about trait implementations.
328     pub traits: FxHashMap<DefId, clean::Trait>,
329
330     /// When rendering traits, it's often useful to be able to list all
331     /// implementors of the trait, and this mapping is exactly, that: a mapping
332     /// of trait ids to the list of known implementors of the trait
333     pub implementors: FxHashMap<DefId, Vec<Impl>>,
334
335     /// Cache of where external crate documentation can be found.
336     pub extern_locations: FxHashMap<CrateNum, (String, PathBuf, ExternalLocation)>,
337
338     /// Cache of where documentation for primitives can be found.
339     pub primitive_locations: FxHashMap<clean::PrimitiveType, DefId>,
340
341     // Note that external items for which `doc(hidden)` applies to are shown as
342     // non-reachable while local items aren't. This is because we're reusing
343     // the access levels from the privacy check pass.
344     pub access_levels: AccessLevels<DefId>,
345
346     /// The version of the crate being documented, if given from the `--crate-version` flag.
347     pub crate_version: Option<String>,
348
349     // Private fields only used when initially crawling a crate to build a cache
350
351     stack: Vec<String>,
352     parent_stack: Vec<DefId>,
353     parent_is_trait_impl: bool,
354     search_index: Vec<IndexItem>,
355     stripped_mod: bool,
356     deref_trait_did: Option<DefId>,
357     deref_mut_trait_did: Option<DefId>,
358     owned_box_did: Option<DefId>,
359     masked_crates: FxHashSet<CrateNum>,
360
361     // In rare case where a structure is defined in one module but implemented
362     // in another, if the implementing module is parsed before defining module,
363     // then the fully qualified name of the structure isn't presented in `paths`
364     // yet when its implementation methods are being indexed. Caches such methods
365     // and their parent id here and indexes them at the end of crate parsing.
366     orphan_impl_items: Vec<(DefId, clean::Item)>,
367
368     // Similarly to `orphan_impl_items`, sometimes trait impls are picked up
369     // even though the trait itself is not exported. This can happen if a trait
370     // was defined in function/expression scope, since the impl will be picked
371     // up by `collect-trait-impls` but the trait won't be scraped out in the HIR
372     // crawl. In order to prevent crashes when looking for spotlight traits or
373     // when gathering trait documentation on a type, hold impls here while
374     // folding and add them to the cache later on if we find the trait.
375     orphan_trait_impls: Vec<(DefId, FxHashSet<DefId>, Impl)>,
376
377     /// Aliases added through `#[doc(alias = "...")]`. Since a few items can have the same alias,
378     /// we need the alias element to have an array of items.
379     aliases: FxHashMap<String, Vec<IndexItem>>,
380 }
381
382 /// Temporary storage for data obtained during `RustdocVisitor::clean()`.
383 /// Later on moved into `CACHE_KEY`.
384 #[derive(Default)]
385 pub struct RenderInfo {
386     pub inlined: FxHashSet<DefId>,
387     pub external_paths: crate::core::ExternalPaths,
388     pub external_param_names: FxHashMap<DefId, String>,
389     pub exact_paths: FxHashMap<DefId, Vec<String>>,
390     pub access_levels: AccessLevels<DefId>,
391     pub deref_trait_did: Option<DefId>,
392     pub deref_mut_trait_did: Option<DefId>,
393     pub owned_box_did: Option<DefId>,
394 }
395
396 /// Helper struct to render all source code to HTML pages
397 struct SourceCollector<'a> {
398     scx: &'a mut SharedContext,
399
400     /// Root destination to place all HTML output into
401     dst: PathBuf,
402 }
403
404 /// Wrapper struct to render the source code of a file. This will do things like
405 /// adding line numbers to the left-hand side.
406 struct Source<'a>(&'a str);
407
408 // Helper structs for rendering items/sidebars and carrying along contextual
409 // information
410
411 #[derive(Copy, Clone)]
412 struct Item<'a> {
413     cx: &'a Context,
414     item: &'a clean::Item,
415 }
416
417 struct Sidebar<'a> { cx: &'a Context, item: &'a clean::Item, }
418
419 /// Struct representing one entry in the JS search index. These are all emitted
420 /// by hand to a large JS file at the end of cache-creation.
421 #[derive(Debug)]
422 struct IndexItem {
423     ty: ItemType,
424     name: String,
425     path: String,
426     desc: String,
427     parent: Option<DefId>,
428     parent_idx: Option<usize>,
429     search_type: Option<IndexItemFunctionType>,
430 }
431
432 impl ToJson for IndexItem {
433     fn to_json(&self) -> Json {
434         assert_eq!(self.parent.is_some(), self.parent_idx.is_some());
435
436         let mut data = Vec::with_capacity(6);
437         data.push((self.ty as usize).to_json());
438         data.push(self.name.to_json());
439         data.push(self.path.to_json());
440         data.push(self.desc.to_json());
441         data.push(self.parent_idx.to_json());
442         data.push(self.search_type.to_json());
443
444         Json::Array(data)
445     }
446 }
447
448 /// A type used for the search index.
449 #[derive(Debug)]
450 struct Type {
451     name: Option<String>,
452     generics: Option<Vec<String>>,
453 }
454
455 impl ToJson for Type {
456     fn to_json(&self) -> Json {
457         match self.name {
458             Some(ref name) => {
459                 let mut data = Vec::with_capacity(2);
460                 data.push(name.to_json());
461                 if let Some(ref generics) = self.generics {
462                     data.push(generics.to_json());
463                 }
464                 Json::Array(data)
465             }
466             None => Json::Null,
467         }
468     }
469 }
470
471 /// Full type of functions/methods in the search index.
472 #[derive(Debug)]
473 struct IndexItemFunctionType {
474     inputs: Vec<Type>,
475     output: Option<Vec<Type>>,
476 }
477
478 impl ToJson for IndexItemFunctionType {
479     fn to_json(&self) -> Json {
480         // If we couldn't figure out a type, just write `null`.
481         let mut iter = self.inputs.iter();
482         if match self.output {
483             Some(ref output) => iter.chain(output.iter()).any(|ref i| i.name.is_none()),
484             None => iter.any(|ref i| i.name.is_none()),
485         } {
486             Json::Null
487         } else {
488             let mut data = Vec::with_capacity(2);
489             data.push(self.inputs.to_json());
490             if let Some(ref output) = self.output {
491                 if output.len() > 1 {
492                     data.push(output.to_json());
493                 } else {
494                     data.push(output[0].to_json());
495                 }
496             }
497             Json::Array(data)
498         }
499     }
500 }
501
502 thread_local!(static CACHE_KEY: RefCell<Arc<Cache>> = Default::default());
503 thread_local!(pub static CURRENT_LOCATION_KEY: RefCell<Vec<String>> = RefCell::new(Vec::new()));
504
505 pub fn initial_ids() -> Vec<String> {
506     [
507      "main",
508      "search",
509      "help",
510      "TOC",
511      "render-detail",
512      "associated-types",
513      "associated-const",
514      "required-methods",
515      "provided-methods",
516      "implementors",
517      "synthetic-implementors",
518      "implementors-list",
519      "synthetic-implementors-list",
520      "methods",
521      "deref-methods",
522      "implementations",
523     ].iter().map(|id| (String::from(*id))).collect()
524 }
525
526 /// Generates the documentation for `crate` into the directory `dst`
527 pub fn run(mut krate: clean::Crate,
528            options: RenderOptions,
529            passes: FxHashSet<String>,
530            renderinfo: RenderInfo,
531            diag: &errors::Handler,
532            edition: Edition) -> Result<(), Error> {
533     // need to save a copy of the options for rendering the index page
534     let md_opts = options.clone();
535     let RenderOptions {
536         output,
537         external_html,
538         id_map,
539         playground_url,
540         sort_modules_alphabetically,
541         themes,
542         extension_css,
543         extern_html_root_urls,
544         resource_suffix,
545         static_root_path,
546         generate_search_filter,
547         generate_redirect_pages,
548         ..
549     } = options;
550
551     let src_root = match krate.src {
552         FileName::Real(ref p) => match p.parent() {
553             Some(p) => p.to_path_buf(),
554             None => PathBuf::new(),
555         },
556         _ => PathBuf::new(),
557     };
558     let mut errors = Arc::new(ErrorStorage::new());
559     let mut scx = SharedContext {
560         src_root,
561         passes,
562         include_sources: true,
563         local_sources: Default::default(),
564         issue_tracker_base_url: None,
565         layout: layout::Layout {
566             logo: String::new(),
567             favicon: String::new(),
568             external_html,
569             krate: krate.name.clone(),
570         },
571         css_file_extension: extension_css,
572         created_dirs: Default::default(),
573         sort_modules_alphabetically,
574         themes,
575         resource_suffix,
576         static_root_path,
577         generate_search_filter,
578         generate_redirect_pages,
579         fs: DocFS::new(&errors),
580     };
581
582     // If user passed in `--playground-url` arg, we fill in crate name here
583     if let Some(url) = playground_url {
584         markdown::PLAYGROUND.with(|slot| {
585             *slot.borrow_mut() = Some((Some(krate.name.clone()), url));
586         });
587     }
588
589     // Crawl the crate attributes looking for attributes which control how we're
590     // going to emit HTML
591     if let Some(attrs) = krate.module.as_ref().map(|m| &m.attrs) {
592         for attr in attrs.lists(sym::doc) {
593             match (attr.name_or_empty(), attr.value_str()) {
594                 (sym::html_favicon_url, Some(s)) => {
595                     scx.layout.favicon = s.to_string();
596                 }
597                 (sym::html_logo_url, Some(s)) => {
598                     scx.layout.logo = s.to_string();
599                 }
600                 (sym::html_playground_url, Some(s)) => {
601                     markdown::PLAYGROUND.with(|slot| {
602                         let name = krate.name.clone();
603                         *slot.borrow_mut() = Some((Some(name), s.to_string()));
604                     });
605                 }
606                 (sym::issue_tracker_base_url, Some(s)) => {
607                     scx.issue_tracker_base_url = Some(s.to_string());
608                 }
609                 (sym::html_no_source, None) if attr.is_word() => {
610                     scx.include_sources = false;
611                 }
612                 _ => {}
613             }
614         }
615     }
616     let dst = output;
617     scx.ensure_dir(&dst)?;
618     krate = render_sources(&dst, &mut scx, krate)?;
619     let mut cx = Context {
620         current: Vec::new(),
621         dst,
622         render_redirect_pages: false,
623         codes: ErrorCodes::from(UnstableFeatures::from_environment().is_nightly_build()),
624         edition,
625         id_map: Rc::new(RefCell::new(id_map)),
626         shared: Arc::new(scx),
627     };
628
629     // Crawl the crate to build various caches used for the output
630     let RenderInfo {
631         inlined: _,
632         external_paths,
633         external_param_names,
634         exact_paths,
635         access_levels,
636         deref_trait_did,
637         deref_mut_trait_did,
638         owned_box_did,
639     } = renderinfo;
640
641     let external_paths = external_paths.into_iter()
642         .map(|(k, (v, t))| (k, (v, ItemType::from(t))))
643         .collect();
644
645     let mut cache = Cache {
646         impls: Default::default(),
647         external_paths,
648         exact_paths,
649         paths: Default::default(),
650         implementors: Default::default(),
651         stack: Vec::new(),
652         parent_stack: Vec::new(),
653         search_index: Vec::new(),
654         parent_is_trait_impl: false,
655         extern_locations: Default::default(),
656         primitive_locations: Default::default(),
657         stripped_mod: false,
658         access_levels,
659         crate_version: krate.version.take(),
660         orphan_impl_items: Vec::new(),
661         orphan_trait_impls: Vec::new(),
662         traits: krate.external_traits.lock().replace(Default::default()),
663         deref_trait_did,
664         deref_mut_trait_did,
665         owned_box_did,
666         masked_crates: mem::take(&mut krate.masked_crates),
667         param_names: external_param_names,
668         aliases: Default::default(),
669     };
670
671     // Cache where all our extern crates are located
672     for &(n, ref e) in &krate.externs {
673         let src_root = match e.src {
674             FileName::Real(ref p) => match p.parent() {
675                 Some(p) => p.to_path_buf(),
676                 None => PathBuf::new(),
677             },
678             _ => PathBuf::new(),
679         };
680         let extern_url = extern_html_root_urls.get(&e.name).map(|u| &**u);
681         cache.extern_locations.insert(n, (e.name.clone(), src_root,
682                                           extern_location(e, extern_url, &cx.dst)));
683
684         let did = DefId { krate: n, index: CRATE_DEF_INDEX };
685         cache.external_paths.insert(did, (vec![e.name.to_string()], ItemType::Module));
686     }
687
688     // Cache where all known primitives have their documentation located.
689     //
690     // Favor linking to as local extern as possible, so iterate all crates in
691     // reverse topological order.
692     for &(_, ref e) in krate.externs.iter().rev() {
693         for &(def_id, prim, _) in &e.primitives {
694             cache.primitive_locations.insert(prim, def_id);
695         }
696     }
697     for &(def_id, prim, _) in &krate.primitives {
698         cache.primitive_locations.insert(prim, def_id);
699     }
700
701     cache.stack.push(krate.name.clone());
702     krate = cache.fold_crate(krate);
703
704     for (trait_did, dids, impl_) in cache.orphan_trait_impls.drain(..) {
705         if cache.traits.contains_key(&trait_did) {
706             for did in dids {
707                 cache.impls.entry(did).or_insert(vec![]).push(impl_.clone());
708             }
709         }
710     }
711
712     // Build our search index
713     let index = build_index(&krate, &mut cache);
714
715     // Freeze the cache now that the index has been built. Put an Arc into TLS
716     // for future parallelization opportunities
717     let cache = Arc::new(cache);
718     CACHE_KEY.with(|v| *v.borrow_mut() = cache.clone());
719     CURRENT_LOCATION_KEY.with(|s| s.borrow_mut().clear());
720
721     // Write shared runs within a flock; disable thread dispatching of IO temporarily.
722     Arc::get_mut(&mut cx.shared).unwrap().fs.set_sync_only(true);
723     write_shared(&cx, &krate, &*cache, index, &md_opts, diag)?;
724     Arc::get_mut(&mut cx.shared).unwrap().fs.set_sync_only(false);
725
726     // And finally render the whole crate's documentation
727     let ret = cx.krate(krate);
728     let nb_errors = Arc::get_mut(&mut errors).map_or_else(|| 0, |errors| errors.write_errors(diag));
729     if ret.is_err() {
730         ret
731     } else if nb_errors > 0 {
732         Err(Error::new(io::Error::new(io::ErrorKind::Other, "I/O error"), ""))
733     } else {
734         Ok(())
735     }
736 }
737
738 /// Builds the search index from the collected metadata
739 fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String {
740     let mut nodeid_to_pathid = FxHashMap::default();
741     let mut crate_items = Vec::with_capacity(cache.search_index.len());
742     let mut crate_paths = Vec::<Json>::new();
743
744     let Cache { ref mut search_index,
745                 ref orphan_impl_items,
746                 ref mut paths, .. } = *cache;
747
748     // Attach all orphan items to the type's definition if the type
749     // has since been learned.
750     for &(did, ref item) in orphan_impl_items {
751         if let Some(&(ref fqp, _)) = paths.get(&did) {
752             search_index.push(IndexItem {
753                 ty: item.type_(),
754                 name: item.name.clone().unwrap(),
755                 path: fqp[..fqp.len() - 1].join("::"),
756                 desc: plain_summary_line_short(item.doc_value()),
757                 parent: Some(did),
758                 parent_idx: None,
759                 search_type: get_index_search_type(&item),
760             });
761         }
762     }
763
764     // Reduce `NodeId` in paths into smaller sequential numbers,
765     // and prune the paths that do not appear in the index.
766     let mut lastpath = String::new();
767     let mut lastpathid = 0usize;
768
769     for item in search_index {
770         item.parent_idx = item.parent.map(|nodeid| {
771             if nodeid_to_pathid.contains_key(&nodeid) {
772                 *nodeid_to_pathid.get(&nodeid).unwrap()
773             } else {
774                 let pathid = lastpathid;
775                 nodeid_to_pathid.insert(nodeid, pathid);
776                 lastpathid += 1;
777
778                 let &(ref fqp, short) = paths.get(&nodeid).unwrap();
779                 crate_paths.push(((short as usize), fqp.last().unwrap().clone()).to_json());
780                 pathid
781             }
782         });
783
784         // Omit the parent path if it is same to that of the prior item.
785         if lastpath == item.path {
786             item.path.clear();
787         } else {
788             lastpath = item.path.clone();
789         }
790         crate_items.push(item.to_json());
791     }
792
793     let crate_doc = krate.module.as_ref().map(|module| {
794         plain_summary_line_short(module.doc_value())
795     }).unwrap_or(String::new());
796
797     let mut crate_data = BTreeMap::new();
798     crate_data.insert("doc".to_owned(), Json::String(crate_doc));
799     crate_data.insert("i".to_owned(), Json::Array(crate_items));
800     crate_data.insert("p".to_owned(), Json::Array(crate_paths));
801
802     // Collect the index into a string
803     format!("searchIndex[{}] = {};",
804             as_json(&krate.name),
805             Json::Object(crate_data))
806 }
807
808 fn write_shared(
809     cx: &Context,
810     krate: &clean::Crate,
811     cache: &Cache,
812     search_index: String,
813     options: &RenderOptions,
814     diag: &errors::Handler,
815 ) -> Result<(), Error> {
816     // Write out the shared files. Note that these are shared among all rustdoc
817     // docs placed in the output directory, so this needs to be a synchronized
818     // operation with respect to all other rustdocs running around.
819     let _lock = flock::Lock::panicking_new(&cx.dst.join(".lock"), true, true, true);
820
821     // Add all the static files. These may already exist, but we just
822     // overwrite them anyway to make sure that they're fresh and up-to-date.
823
824     write_minify(&cx.shared.fs, cx.dst.join(&format!("rustdoc{}.css", cx.shared.resource_suffix)),
825                  static_files::RUSTDOC_CSS,
826                  options.enable_minification)?;
827     write_minify(&cx.shared.fs, cx.dst.join(&format!("settings{}.css", cx.shared.resource_suffix)),
828                  static_files::SETTINGS_CSS,
829                  options.enable_minification)?;
830     write_minify(&cx.shared.fs, cx.dst.join(&format!("noscript{}.css", cx.shared.resource_suffix)),
831                  static_files::NOSCRIPT_CSS,
832                  options.enable_minification)?;
833
834     // To avoid "light.css" to be overwritten, we'll first run over the received themes and only
835     // then we'll run over the "official" styles.
836     let mut themes: FxHashSet<String> = FxHashSet::default();
837
838     for entry in &cx.shared.themes {
839         let content = try_err!(fs::read(&entry), &entry);
840         let theme = try_none!(try_none!(entry.file_stem(), &entry).to_str(), &entry);
841         let extension = try_none!(try_none!(entry.extension(), &entry).to_str(), &entry);
842         cx.shared.fs.write(
843             cx.dst.join(format!("{}{}.{}", theme, cx.shared.resource_suffix, extension)),
844             content.as_slice())?;
845         themes.insert(theme.to_owned());
846     }
847
848     let write = |p, c| { cx.shared.fs.write(p, c) };
849     if (*cx.shared).layout.logo.is_empty() {
850         write(cx.dst.join(&format!("rust-logo{}.png", cx.shared.resource_suffix)),
851               static_files::RUST_LOGO)?;
852     }
853     if (*cx.shared).layout.favicon.is_empty() {
854         write(cx.dst.join(&format!("favicon{}.ico", cx.shared.resource_suffix)),
855               static_files::RUST_FAVICON)?;
856     }
857     write(cx.dst.join(&format!("brush{}.svg", cx.shared.resource_suffix)),
858           static_files::BRUSH_SVG)?;
859     write(cx.dst.join(&format!("wheel{}.svg", cx.shared.resource_suffix)),
860           static_files::WHEEL_SVG)?;
861     write(cx.dst.join(&format!("down-arrow{}.svg", cx.shared.resource_suffix)),
862           static_files::DOWN_ARROW_SVG)?;
863     write_minify(&cx.shared.fs, cx.dst.join(&format!("light{}.css", cx.shared.resource_suffix)),
864                  static_files::themes::LIGHT,
865                  options.enable_minification)?;
866     themes.insert("light".to_owned());
867     write_minify(&cx.shared.fs, cx.dst.join(&format!("dark{}.css", cx.shared.resource_suffix)),
868                  static_files::themes::DARK,
869                  options.enable_minification)?;
870     themes.insert("dark".to_owned());
871
872     let mut themes: Vec<&String> = themes.iter().collect();
873     themes.sort();
874     // To avoid theme switch latencies as much as possible, we put everything theme related
875     // at the beginning of the html files into another js file.
876     let theme_js = format!(
877 r#"var themes = document.getElementById("theme-choices");
878 var themePicker = document.getElementById("theme-picker");
879
880 function switchThemeButtonState() {{
881     if (themes.style.display === "block") {{
882         themes.style.display = "none";
883         themePicker.style.borderBottomRightRadius = "3px";
884         themePicker.style.borderBottomLeftRadius = "3px";
885     }} else {{
886         themes.style.display = "block";
887         themePicker.style.borderBottomRightRadius = "0";
888         themePicker.style.borderBottomLeftRadius = "0";
889     }}
890 }};
891
892 function handleThemeButtonsBlur(e) {{
893     var active = document.activeElement;
894     var related = e.relatedTarget;
895
896     if (active.id !== "themePicker" &&
897         (!active.parentNode || active.parentNode.id !== "theme-choices") &&
898         (!related ||
899          (related.id !== "themePicker" &&
900           (!related.parentNode || related.parentNode.id !== "theme-choices")))) {{
901         switchThemeButtonState();
902     }}
903 }}
904
905 themePicker.onclick = switchThemeButtonState;
906 themePicker.onblur = handleThemeButtonsBlur;
907 [{}].forEach(function(item) {{
908     var but = document.createElement('button');
909     but.innerHTML = item;
910     but.onclick = function(el) {{
911         switchTheme(currentTheme, mainTheme, item);
912     }};
913     but.onblur = handleThemeButtonsBlur;
914     themes.appendChild(but);
915 }});"#,
916                  themes.iter()
917                        .map(|s| format!("\"{}\"", s))
918                        .collect::<Vec<String>>()
919                        .join(","));
920     write(cx.dst.join(&format!("theme{}.js", cx.shared.resource_suffix)),
921           theme_js.as_bytes()
922     )?;
923
924     write_minify(&cx.shared.fs, cx.dst.join(&format!("main{}.js", cx.shared.resource_suffix)),
925                  static_files::MAIN_JS,
926                  options.enable_minification)?;
927     write_minify(&cx.shared.fs, cx.dst.join(&format!("settings{}.js", cx.shared.resource_suffix)),
928                  static_files::SETTINGS_JS,
929                  options.enable_minification)?;
930     if cx.shared.include_sources {
931         write_minify(
932             &cx.shared.fs,
933             cx.dst.join(&format!("source-script{}.js", cx.shared.resource_suffix)),
934             static_files::sidebar::SOURCE_SCRIPT,
935             options.enable_minification)?;
936     }
937
938     {
939         write_minify(
940             &cx.shared.fs,
941             cx.dst.join(&format!("storage{}.js", cx.shared.resource_suffix)),
942             &format!("var resourcesSuffix = \"{}\";{}",
943                      cx.shared.resource_suffix,
944                      static_files::STORAGE_JS),
945             options.enable_minification)?;
946     }
947
948     if let Some(ref css) = cx.shared.css_file_extension {
949         let out = cx.dst.join(&format!("theme{}.css", cx.shared.resource_suffix));
950         let buffer = try_err!(fs::read_to_string(css), css);
951         if !options.enable_minification {
952             cx.shared.fs.write(&out, &buffer)?;
953         } else {
954             write_minify(&cx.shared.fs, out, &buffer, options.enable_minification)?;
955         }
956     }
957     write_minify(&cx.shared.fs, cx.dst.join(&format!("normalize{}.css", cx.shared.resource_suffix)),
958                  static_files::NORMALIZE_CSS,
959                  options.enable_minification)?;
960     write(cx.dst.join("FiraSans-Regular.woff"),
961           static_files::fira_sans::REGULAR)?;
962     write(cx.dst.join("FiraSans-Medium.woff"),
963           static_files::fira_sans::MEDIUM)?;
964     write(cx.dst.join("FiraSans-LICENSE.txt"),
965           static_files::fira_sans::LICENSE)?;
966     write(cx.dst.join("SourceSerifPro-Regular.ttf.woff"),
967           static_files::source_serif_pro::REGULAR)?;
968     write(cx.dst.join("SourceSerifPro-Bold.ttf.woff"),
969           static_files::source_serif_pro::BOLD)?;
970     write(cx.dst.join("SourceSerifPro-It.ttf.woff"),
971           static_files::source_serif_pro::ITALIC)?;
972     write(cx.dst.join("SourceSerifPro-LICENSE.md"),
973           static_files::source_serif_pro::LICENSE)?;
974     write(cx.dst.join("SourceCodePro-Regular.woff"),
975           static_files::source_code_pro::REGULAR)?;
976     write(cx.dst.join("SourceCodePro-Semibold.woff"),
977           static_files::source_code_pro::SEMIBOLD)?;
978     write(cx.dst.join("SourceCodePro-LICENSE.txt"),
979           static_files::source_code_pro::LICENSE)?;
980     write(cx.dst.join("LICENSE-MIT.txt"),
981           static_files::LICENSE_MIT)?;
982     write(cx.dst.join("LICENSE-APACHE.txt"),
983           static_files::LICENSE_APACHE)?;
984     write(cx.dst.join("COPYRIGHT.txt"),
985           static_files::COPYRIGHT)?;
986
987     fn collect(
988         path: &Path,
989         krate: &str,
990         key: &str,
991         for_search_index: bool,
992     ) -> io::Result<(Vec<String>, Vec<String>, Vec<String>)> {
993         let mut ret = Vec::new();
994         let mut krates = Vec::new();
995         let mut variables = Vec::new();
996
997         if path.exists() {
998             for line in BufReader::new(File::open(path)?).lines() {
999                 let line = line?;
1000                 if for_search_index && line.starts_with("var R") {
1001                     variables.push(line.clone());
1002                     continue;
1003                 }
1004                 if !line.starts_with(key) {
1005                     continue;
1006                 }
1007                 if line.starts_with(&format!(r#"{}["{}"]"#, key, krate)) {
1008                     continue;
1009                 }
1010                 ret.push(line.to_string());
1011                 krates.push(line[key.len() + 2..].split('"')
1012                                                  .next()
1013                                                  .map(|s| s.to_owned())
1014                                                  .unwrap_or_else(|| String::new()));
1015             }
1016         }
1017         Ok((ret, krates, variables))
1018     }
1019
1020     fn show_item(item: &IndexItem, krate: &str) -> String {
1021         format!("{{'crate':'{}','ty':{},'name':'{}','desc':'{}','p':'{}'{}}}",
1022                 krate, item.ty as usize, item.name, item.desc.replace("'", "\\'"), item.path,
1023                 if let Some(p) = item.parent_idx {
1024                     format!(",'parent':{}", p)
1025                 } else {
1026                     String::new()
1027                 })
1028     }
1029
1030     let dst = cx.dst.join(&format!("aliases{}.js", cx.shared.resource_suffix));
1031     {
1032         let (mut all_aliases, _, _) = try_err!(collect(&dst, &krate.name, "ALIASES", false), &dst);
1033         let mut output = String::with_capacity(100);
1034         for (alias, items) in &cache.aliases {
1035             if items.is_empty() {
1036                 continue
1037             }
1038             output.push_str(&format!("\"{}\":[{}],",
1039                                      alias,
1040                                      items.iter()
1041                                           .map(|v| show_item(v, &krate.name))
1042                                           .collect::<Vec<_>>()
1043                                           .join(",")));
1044         }
1045         all_aliases.push(format!("ALIASES[\"{}\"] = {{{}}};", krate.name, output));
1046         all_aliases.sort();
1047         let mut v = Vec::new();
1048         try_err!(writeln!(&mut v, "var ALIASES = {{}};"), &dst);
1049         for aliases in &all_aliases {
1050             try_err!(writeln!(&mut v, "{}", aliases), &dst);
1051         }
1052         cx.shared.fs.write(&dst, &v)?;
1053     }
1054
1055     use std::ffi::OsString;
1056
1057     #[derive(Debug)]
1058     struct Hierarchy {
1059         elem: OsString,
1060         children: FxHashMap<OsString, Hierarchy>,
1061         elems: FxHashSet<OsString>,
1062     }
1063
1064     impl Hierarchy {
1065         fn new(elem: OsString) -> Hierarchy {
1066             Hierarchy {
1067                 elem,
1068                 children: FxHashMap::default(),
1069                 elems: FxHashSet::default(),
1070             }
1071         }
1072
1073         fn to_json_string(&self) -> String {
1074             let mut subs: Vec<&Hierarchy> = self.children.values().collect();
1075             subs.sort_unstable_by(|a, b| a.elem.cmp(&b.elem));
1076             let mut files = self.elems.iter()
1077                                       .map(|s| format!("\"{}\"",
1078                                                        s.to_str()
1079                                                         .expect("invalid osstring conversion")))
1080                                       .collect::<Vec<_>>();
1081             files.sort_unstable_by(|a, b| a.cmp(b));
1082             let subs = subs.iter().map(|s| s.to_json_string()).collect::<Vec<_>>().join(",");
1083             let dirs = if subs.is_empty() {
1084                 String::new()
1085             } else {
1086                 format!(",\"dirs\":[{}]", subs)
1087             };
1088             let files = files.join(",");
1089             let files = if files.is_empty() {
1090                 String::new()
1091             } else {
1092                 format!(",\"files\":[{}]", files)
1093             };
1094             format!("{{\"name\":\"{name}\"{dirs}{files}}}",
1095                     name=self.elem.to_str().expect("invalid osstring conversion"),
1096                     dirs=dirs,
1097                     files=files)
1098         }
1099     }
1100
1101     if cx.shared.include_sources {
1102         let mut hierarchy = Hierarchy::new(OsString::new());
1103         for source in cx.shared.local_sources.iter()
1104                                              .filter_map(|p| p.0.strip_prefix(&cx.shared.src_root)
1105                                                                 .ok()) {
1106             let mut h = &mut hierarchy;
1107             let mut elems = source.components()
1108                                   .filter_map(|s| {
1109                                       match s {
1110                                           Component::Normal(s) => Some(s.to_owned()),
1111                                           _ => None,
1112                                       }
1113                                   })
1114                                   .peekable();
1115             loop {
1116                 let cur_elem = elems.next().expect("empty file path");
1117                 if elems.peek().is_none() {
1118                     h.elems.insert(cur_elem);
1119                     break;
1120                 } else {
1121                     let e = cur_elem.clone();
1122                     h.children.entry(cur_elem.clone()).or_insert_with(|| Hierarchy::new(e));
1123                     h = h.children.get_mut(&cur_elem).expect("not found child");
1124                 }
1125             }
1126         }
1127
1128         let dst = cx.dst.join(&format!("source-files{}.js", cx.shared.resource_suffix));
1129         let (mut all_sources, _krates, _) = try_err!(collect(&dst, &krate.name, "sourcesIndex",
1130                                                              false),
1131                                                      &dst);
1132         all_sources.push(format!("sourcesIndex[\"{}\"] = {};",
1133                                  &krate.name,
1134                                  hierarchy.to_json_string()));
1135         all_sources.sort();
1136         let mut v = Vec::new();
1137         try_err!(writeln!(&mut v,
1138                           "var N = null;var sourcesIndex = {{}};\n{}\ncreateSourceSidebar();",
1139                           all_sources.join("\n")),
1140                  &dst);
1141         cx.shared.fs.write(&dst, &v)?;
1142     }
1143
1144     // Update the search index
1145     let dst = cx.dst.join(&format!("search-index{}.js", cx.shared.resource_suffix));
1146     let (mut all_indexes, mut krates, variables) = try_err!(collect(&dst,
1147                                                                     &krate.name,
1148                                                                     "searchIndex",
1149                                                                     true), &dst);
1150     all_indexes.push(search_index);
1151
1152     // Sort the indexes by crate so the file will be generated identically even
1153     // with rustdoc running in parallel.
1154     all_indexes.sort();
1155     {
1156         let mut v = Vec::new();
1157         try_err!(writeln!(&mut v, "var N=null,E=\"\",T=\"t\",U=\"u\",searchIndex={{}};"), &dst);
1158         try_err!(write_minify_replacer(
1159             &mut v,
1160             &format!("{}\n{}", variables.join(""), all_indexes.join("\n")),
1161             options.enable_minification),
1162             &dst);
1163         try_err!(write!(&mut v, "initSearch(searchIndex);addSearchOptions(searchIndex);"), &dst);
1164         cx.shared.fs.write(&dst, &v)?;
1165     }
1166     if options.enable_index_page {
1167         if let Some(index_page) = options.index_page.clone() {
1168             let mut md_opts = options.clone();
1169             md_opts.output = cx.dst.clone();
1170             md_opts.external_html = (*cx.shared).layout.external_html.clone();
1171
1172             crate::markdown::render(index_page, md_opts, diag, cx.edition);
1173         } else {
1174             let dst = cx.dst.join("index.html");
1175             let page = layout::Page {
1176                 title: "Index of crates",
1177                 css_class: "mod",
1178                 root_path: "./",
1179                 static_root_path: cx.shared.static_root_path.as_deref(),
1180                 description: "List of crates",
1181                 keywords: BASIC_KEYWORDS,
1182                 resource_suffix: &cx.shared.resource_suffix,
1183                 extra_scripts: &[],
1184                 static_extra_scripts: &[],
1185             };
1186             krates.push(krate.name.clone());
1187             krates.sort();
1188             krates.dedup();
1189
1190             let content = format!(
1191 "<h1 class='fqn'>\
1192      <span class='in-band'>List of all crates</span>\
1193 </h1><ul class='mod'>{}</ul>",
1194                                   krates
1195                                     .iter()
1196                                     .map(|s| {
1197                                         format!("<li><a href=\"{}index.html\">{}</li>",
1198                                                 SlashChecker(s), s)
1199                                     })
1200                                     .collect::<String>());
1201             let mut v = Vec::new();
1202             try_err!(layout::render(&mut v, &cx.shared.layout,
1203                                     &page, &(""), &content,
1204                                     cx.shared.css_file_extension.is_some(),
1205                                     &cx.shared.themes,
1206                                     cx.shared.generate_search_filter), &dst);
1207             cx.shared.fs.write(&dst, &v)?;
1208         }
1209     }
1210
1211     // Update the list of all implementors for traits
1212     let dst = cx.dst.join("implementors");
1213     for (&did, imps) in &cache.implementors {
1214         // Private modules can leak through to this phase of rustdoc, which
1215         // could contain implementations for otherwise private types. In some
1216         // rare cases we could find an implementation for an item which wasn't
1217         // indexed, so we just skip this step in that case.
1218         //
1219         // FIXME: this is a vague explanation for why this can't be a `get`, in
1220         //        theory it should be...
1221         let &(ref remote_path, remote_item_type) = match cache.paths.get(&did) {
1222             Some(p) => p,
1223             None => match cache.external_paths.get(&did) {
1224                 Some(p) => p,
1225                 None => continue,
1226             }
1227         };
1228
1229         let mut have_impls = false;
1230         let mut implementors = format!(r#"implementors["{}"] = ["#, krate.name);
1231         for imp in imps {
1232             // If the trait and implementation are in the same crate, then
1233             // there's no need to emit information about it (there's inlining
1234             // going on). If they're in different crates then the crate defining
1235             // the trait will be interested in our implementation.
1236             if imp.impl_item.def_id.krate == did.krate { continue }
1237             // If the implementation is from another crate then that crate
1238             // should add it.
1239             if !imp.impl_item.def_id.is_local() { continue }
1240             have_impls = true;
1241             write!(implementors, "{{text:{},synthetic:{},types:{}}},",
1242                    as_json(&imp.inner_impl().to_string()),
1243                    imp.inner_impl().synthetic,
1244                    as_json(&collect_paths_for_type(imp.inner_impl().for_.clone()))).unwrap();
1245         }
1246         implementors.push_str("];");
1247
1248         // Only create a js file if we have impls to add to it. If the trait is
1249         // documented locally though we always create the file to avoid dead
1250         // links.
1251         if !have_impls && !cache.paths.contains_key(&did) {
1252             continue;
1253         }
1254
1255         let mut mydst = dst.clone();
1256         for part in &remote_path[..remote_path.len() - 1] {
1257             mydst.push(part);
1258         }
1259         cx.shared.ensure_dir(&mydst)?;
1260         mydst.push(&format!("{}.{}.js",
1261                             remote_item_type.css_class(),
1262                             remote_path[remote_path.len() - 1]));
1263
1264         let (mut all_implementors, _, _) = try_err!(collect(&mydst, &krate.name, "implementors",
1265                                                             false),
1266                                                     &mydst);
1267         all_implementors.push(implementors);
1268         // Sort the implementors by crate so the file will be generated
1269         // identically even with rustdoc running in parallel.
1270         all_implementors.sort();
1271
1272         let mut v = Vec::new();
1273         try_err!(writeln!(&mut v, "(function() {{var implementors = {{}};"), &mydst);
1274         for implementor in &all_implementors {
1275             try_err!(writeln!(&mut v, "{}", *implementor), &mydst);
1276         }
1277         try_err!(writeln!(&mut v, "{}", r"
1278             if (window.register_implementors) {
1279                 window.register_implementors(implementors);
1280             } else {
1281                 window.pending_implementors = implementors;
1282             }
1283         "), &mydst);
1284         try_err!(writeln!(&mut v, r"}})()"), &mydst);
1285         cx.shared.fs.write(&mydst, &v)?;
1286     }
1287     Ok(())
1288 }
1289
1290 fn render_sources(dst: &Path, scx: &mut SharedContext,
1291                   krate: clean::Crate) -> Result<clean::Crate, Error> {
1292     info!("emitting source files");
1293     let dst = dst.join("src").join(&krate.name);
1294     scx.ensure_dir(&dst)?;
1295     let mut folder = SourceCollector {
1296         dst,
1297         scx,
1298     };
1299     Ok(folder.fold_crate(krate))
1300 }
1301
1302 fn write_minify(fs:&DocFS, dst: PathBuf, contents: &str, enable_minification: bool
1303                 ) -> Result<(), Error> {
1304     if enable_minification {
1305         if dst.extension() == Some(&OsStr::new("css")) {
1306             let res = try_none!(minifier::css::minify(contents).ok(), &dst);
1307             fs.write(dst, res.as_bytes())
1308         } else {
1309             fs.write(dst, minifier::js::minify(contents).as_bytes())
1310         }
1311     } else {
1312         fs.write(dst, contents.as_bytes())
1313     }
1314 }
1315
1316 fn write_minify_replacer<W: Write>(
1317     dst: &mut W,
1318     contents: &str,
1319     enable_minification: bool,
1320 ) -> io::Result<()> {
1321     use minifier::js::{simple_minify, Keyword, ReservedChar, Token, Tokens};
1322
1323     if enable_minification {
1324         writeln!(dst, "{}",
1325                  {
1326                     let tokens: Tokens<'_> = simple_minify(contents)
1327                         .into_iter()
1328                         .filter(|(f, next)| {
1329                             // We keep backlines.
1330                             minifier::js::clean_token_except(f, next, &|c: &Token<'_>| {
1331                                 c.get_char() != Some(ReservedChar::Backline)
1332                             })
1333                         })
1334                         .map(|(f, _)| {
1335                             minifier::js::replace_token_with(f, &|t: &Token<'_>| {
1336                                 match *t {
1337                                     Token::Keyword(Keyword::Null) => Some(Token::Other("N")),
1338                                     Token::String(s) => {
1339                                         let s = &s[1..s.len() -1]; // The quotes are included
1340                                         if s.is_empty() {
1341                                             Some(Token::Other("E"))
1342                                         } else if s == "t" {
1343                                             Some(Token::Other("T"))
1344                                         } else if s == "u" {
1345                                             Some(Token::Other("U"))
1346                                         } else {
1347                                             None
1348                                         }
1349                                     }
1350                                     _ => None,
1351                                 }
1352                             })
1353                         })
1354                         .collect::<Vec<_>>()
1355                         .into();
1356                     tokens.apply(|f| {
1357                         // We add a backline after the newly created variables.
1358                         minifier::js::aggregate_strings_into_array_with_separation_filter(
1359                             f,
1360                             "R",
1361                             Token::Char(ReservedChar::Backline),
1362                             // This closure prevents crates' names from being aggregated.
1363                             //
1364                             // The point here is to check if the string is preceded by '[' and
1365                             // "searchIndex". If so, it means this is a crate name and that it
1366                             // shouldn't be aggregated.
1367                             |tokens, pos| {
1368                                 pos < 2 ||
1369                                 !tokens[pos - 1].eq_char(ReservedChar::OpenBracket) ||
1370                                 tokens[pos - 2].get_other() != Some("searchIndex")
1371                             }
1372                         )
1373                     })
1374                     .to_string()
1375                 })
1376     } else {
1377         writeln!(dst, "{}", contents)
1378     }
1379 }
1380
1381 /// Takes a path to a source file and cleans the path to it. This canonicalizes
1382 /// things like ".." to components which preserve the "top down" hierarchy of a
1383 /// static HTML tree. Each component in the cleaned path will be passed as an
1384 /// argument to `f`. The very last component of the path (ie the file name) will
1385 /// be passed to `f` if `keep_filename` is true, and ignored otherwise.
1386 fn clean_srcpath<F>(src_root: &Path, p: &Path, keep_filename: bool, mut f: F)
1387 where
1388     F: FnMut(&OsStr),
1389 {
1390     // make it relative, if possible
1391     let p = p.strip_prefix(src_root).unwrap_or(p);
1392
1393     let mut iter = p.components().peekable();
1394
1395     while let Some(c) = iter.next() {
1396         if !keep_filename && iter.peek().is_none() {
1397             break;
1398         }
1399
1400         match c {
1401             Component::ParentDir => f("up".as_ref()),
1402             Component::Normal(c) => f(c),
1403             _ => continue,
1404         }
1405     }
1406 }
1407
1408 /// Attempts to find where an external crate is located, given that we're
1409 /// rendering in to the specified source destination.
1410 fn extern_location(e: &clean::ExternalCrate, extern_url: Option<&str>, dst: &Path)
1411     -> ExternalLocation
1412 {
1413     // See if there's documentation generated into the local directory
1414     let local_location = dst.join(&e.name);
1415     if local_location.is_dir() {
1416         return Local;
1417     }
1418
1419     if let Some(url) = extern_url {
1420         let mut url = url.to_string();
1421         if !url.ends_with("/") {
1422             url.push('/');
1423         }
1424         return Remote(url);
1425     }
1426
1427     // Failing that, see if there's an attribute specifying where to find this
1428     // external crate
1429     e.attrs.lists(sym::doc)
1430      .filter(|a| a.check_name(sym::html_root_url))
1431      .filter_map(|a| a.value_str())
1432      .map(|url| {
1433         let mut url = url.to_string();
1434         if !url.ends_with("/") {
1435             url.push('/')
1436         }
1437         Remote(url)
1438     }).next().unwrap_or(Unknown) // Well, at least we tried.
1439 }
1440
1441 impl<'a> DocFolder for SourceCollector<'a> {
1442     fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
1443         // If we're including source files, and we haven't seen this file yet,
1444         // then we need to render it out to the filesystem.
1445         if self.scx.include_sources
1446             // skip all invalid or macro spans
1447             && item.source.filename.is_real()
1448             // skip non-local items
1449             && item.def_id.is_local() {
1450
1451             // If it turns out that we couldn't read this file, then we probably
1452             // can't read any of the files (generating html output from json or
1453             // something like that), so just don't include sources for the
1454             // entire crate. The other option is maintaining this mapping on a
1455             // per-file basis, but that's probably not worth it...
1456             self.scx
1457                 .include_sources = match self.emit_source(&item.source.filename) {
1458                 Ok(()) => true,
1459                 Err(e) => {
1460                     println!("warning: source code was requested to be rendered, \
1461                               but processing `{}` had an error: {}",
1462                              item.source.filename, e);
1463                     println!("         skipping rendering of source code");
1464                     false
1465                 }
1466             };
1467         }
1468         self.fold_item_recur(item)
1469     }
1470 }
1471
1472 impl<'a> SourceCollector<'a> {
1473     /// Renders the given filename into its corresponding HTML source file.
1474     fn emit_source(&mut self, filename: &FileName) -> Result<(), Error> {
1475         let p = match *filename {
1476             FileName::Real(ref file) => file,
1477             _ => return Ok(()),
1478         };
1479         if self.scx.local_sources.contains_key(&**p) {
1480             // We've already emitted this source
1481             return Ok(());
1482         }
1483
1484         let contents = try_err!(fs::read_to_string(&p), &p);
1485
1486         // Remove the utf-8 BOM if any
1487         let contents = if contents.starts_with("\u{feff}") {
1488             &contents[3..]
1489         } else {
1490             &contents[..]
1491         };
1492
1493         // Create the intermediate directories
1494         let mut cur = self.dst.clone();
1495         let mut root_path = String::from("../../");
1496         let mut href = String::new();
1497         clean_srcpath(&self.scx.src_root, &p, false, |component| {
1498             cur.push(component);
1499             root_path.push_str("../");
1500             href.push_str(&component.to_string_lossy());
1501             href.push('/');
1502         });
1503         self.scx.ensure_dir(&cur)?;
1504         let mut fname = p.file_name()
1505                          .expect("source has no filename")
1506                          .to_os_string();
1507         fname.push(".html");
1508         cur.push(&fname);
1509         href.push_str(&fname.to_string_lossy());
1510
1511         let mut v = Vec::new();
1512         let title = format!("{} -- source", cur.file_name().expect("failed to get file name")
1513                                                .to_string_lossy());
1514         let desc = format!("Source to the Rust file `{}`.", filename);
1515         let page = layout::Page {
1516             title: &title,
1517             css_class: "source",
1518             root_path: &root_path,
1519             static_root_path: self.scx.static_root_path.as_deref(),
1520             description: &desc,
1521             keywords: BASIC_KEYWORDS,
1522             resource_suffix: &self.scx.resource_suffix,
1523             extra_scripts: &[&format!("source-files{}", self.scx.resource_suffix)],
1524             static_extra_scripts: &[&format!("source-script{}", self.scx.resource_suffix)],
1525         };
1526         try_err!(layout::render(&mut v, &self.scx.layout,
1527                        &page, &(""), &Source(contents),
1528                        self.scx.css_file_extension.is_some(),
1529                        &self.scx.themes,
1530                        self.scx.generate_search_filter), &cur);
1531         self.scx.fs.write(&cur, &v)?;
1532         self.scx.local_sources.insert(p.clone(), href);
1533         Ok(())
1534     }
1535 }
1536
1537 impl DocFolder for Cache {
1538     fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
1539         if item.def_id.is_local() {
1540             debug!("folding {} \"{:?}\", id {:?}", item.type_(), item.name, item.def_id);
1541         }
1542
1543         // If this is a stripped module,
1544         // we don't want it or its children in the search index.
1545         let orig_stripped_mod = match item.inner {
1546             clean::StrippedItem(box clean::ModuleItem(..)) => {
1547                 mem::replace(&mut self.stripped_mod, true)
1548             }
1549             _ => self.stripped_mod,
1550         };
1551
1552         // If the impl is from a masked crate or references something from a
1553         // masked crate then remove it completely.
1554         if let clean::ImplItem(ref i) = item.inner {
1555             if self.masked_crates.contains(&item.def_id.krate) ||
1556                i.trait_.def_id().map_or(false, |d| self.masked_crates.contains(&d.krate)) ||
1557                i.for_.def_id().map_or(false, |d| self.masked_crates.contains(&d.krate)) {
1558                 return None;
1559             }
1560         }
1561
1562         // Register any generics to their corresponding string. This is used
1563         // when pretty-printing types.
1564         if let Some(generics) = item.inner.generics() {
1565             self.generics(generics);
1566         }
1567
1568         // Propagate a trait method's documentation to all implementors of the
1569         // trait.
1570         if let clean::TraitItem(ref t) = item.inner {
1571             self.traits.entry(item.def_id).or_insert_with(|| t.clone());
1572         }
1573
1574         // Collect all the implementors of traits.
1575         if let clean::ImplItem(ref i) = item.inner {
1576             if let Some(did) = i.trait_.def_id() {
1577                 if i.blanket_impl.is_none() {
1578                     self.implementors.entry(did).or_default().push(Impl {
1579                         impl_item: item.clone(),
1580                     });
1581                 }
1582             }
1583         }
1584
1585         // Index this method for searching later on.
1586         if let Some(ref s) = item.name {
1587             let (parent, is_inherent_impl_item) = match item.inner {
1588                 clean::StrippedItem(..) => ((None, None), false),
1589                 clean::AssocConstItem(..) |
1590                 clean::TypedefItem(_, true) if self.parent_is_trait_impl => {
1591                     // skip associated items in trait impls
1592                     ((None, None), false)
1593                 }
1594                 clean::AssocTypeItem(..) |
1595                 clean::TyMethodItem(..) |
1596                 clean::StructFieldItem(..) |
1597                 clean::VariantItem(..) => {
1598                     ((Some(*self.parent_stack.last().unwrap()),
1599                       Some(&self.stack[..self.stack.len() - 1])),
1600                      false)
1601                 }
1602                 clean::MethodItem(..) | clean::AssocConstItem(..) => {
1603                     if self.parent_stack.is_empty() {
1604                         ((None, None), false)
1605                     } else {
1606                         let last = self.parent_stack.last().unwrap();
1607                         let did = *last;
1608                         let path = match self.paths.get(&did) {
1609                             // The current stack not necessarily has correlation
1610                             // for where the type was defined. On the other
1611                             // hand, `paths` always has the right
1612                             // information if present.
1613                             Some(&(ref fqp, ItemType::Trait)) |
1614                             Some(&(ref fqp, ItemType::Struct)) |
1615                             Some(&(ref fqp, ItemType::Union)) |
1616                             Some(&(ref fqp, ItemType::Enum)) =>
1617                                 Some(&fqp[..fqp.len() - 1]),
1618                             Some(..) => Some(&*self.stack),
1619                             None => None
1620                         };
1621                         ((Some(*last), path), true)
1622                     }
1623                 }
1624                 _ => ((None, Some(&*self.stack)), false)
1625             };
1626
1627             match parent {
1628                 (parent, Some(path)) if is_inherent_impl_item || (!self.stripped_mod) => {
1629                     debug_assert!(!item.is_stripped());
1630
1631                     // A crate has a module at its root, containing all items,
1632                     // which should not be indexed. The crate-item itself is
1633                     // inserted later on when serializing the search-index.
1634                     if item.def_id.index != CRATE_DEF_INDEX {
1635                         self.search_index.push(IndexItem {
1636                             ty: item.type_(),
1637                             name: s.to_string(),
1638                             path: path.join("::"),
1639                             desc: plain_summary_line_short(item.doc_value()),
1640                             parent,
1641                             parent_idx: None,
1642                             search_type: get_index_search_type(&item),
1643                         });
1644                     }
1645                 }
1646                 (Some(parent), None) if is_inherent_impl_item => {
1647                     // We have a parent, but we don't know where they're
1648                     // defined yet. Wait for later to index this item.
1649                     self.orphan_impl_items.push((parent, item.clone()));
1650                 }
1651                 _ => {}
1652             }
1653         }
1654
1655         // Keep track of the fully qualified path for this item.
1656         let pushed = match item.name {
1657             Some(ref n) if !n.is_empty() => {
1658                 self.stack.push(n.to_string());
1659                 true
1660             }
1661             _ => false,
1662         };
1663
1664         match item.inner {
1665             clean::StructItem(..) | clean::EnumItem(..) |
1666             clean::TypedefItem(..) | clean::TraitItem(..) |
1667             clean::FunctionItem(..) | clean::ModuleItem(..) |
1668             clean::ForeignFunctionItem(..) | clean::ForeignStaticItem(..) |
1669             clean::ConstantItem(..) | clean::StaticItem(..) |
1670             clean::UnionItem(..) | clean::ForeignTypeItem |
1671             clean::MacroItem(..) | clean::ProcMacroItem(..)
1672             if !self.stripped_mod => {
1673                 // Re-exported items mean that the same id can show up twice
1674                 // in the rustdoc ast that we're looking at. We know,
1675                 // however, that a re-exported item doesn't show up in the
1676                 // `public_items` map, so we can skip inserting into the
1677                 // paths map if there was already an entry present and we're
1678                 // not a public item.
1679                 if !self.paths.contains_key(&item.def_id) ||
1680                    self.access_levels.is_public(item.def_id)
1681                 {
1682                     self.paths.insert(item.def_id,
1683                                       (self.stack.clone(), item.type_()));
1684                 }
1685                 self.add_aliases(&item);
1686             }
1687             // Link variants to their parent enum because pages aren't emitted
1688             // for each variant.
1689             clean::VariantItem(..) if !self.stripped_mod => {
1690                 let mut stack = self.stack.clone();
1691                 stack.pop();
1692                 self.paths.insert(item.def_id, (stack, ItemType::Enum));
1693             }
1694
1695             clean::PrimitiveItem(..) if item.visibility.is_some() => {
1696                 self.add_aliases(&item);
1697                 self.paths.insert(item.def_id, (self.stack.clone(),
1698                                                 item.type_()));
1699             }
1700
1701             _ => {}
1702         }
1703
1704         // Maintain the parent stack
1705         let orig_parent_is_trait_impl = self.parent_is_trait_impl;
1706         let parent_pushed = match item.inner {
1707             clean::TraitItem(..) | clean::EnumItem(..) | clean::ForeignTypeItem |
1708             clean::StructItem(..) | clean::UnionItem(..) => {
1709                 self.parent_stack.push(item.def_id);
1710                 self.parent_is_trait_impl = false;
1711                 true
1712             }
1713             clean::ImplItem(ref i) => {
1714                 self.parent_is_trait_impl = i.trait_.is_some();
1715                 match i.for_ {
1716                     clean::ResolvedPath{ did, .. } => {
1717                         self.parent_stack.push(did);
1718                         true
1719                     }
1720                     ref t => {
1721                         let prim_did = t.primitive_type().and_then(|t| {
1722                             self.primitive_locations.get(&t).cloned()
1723                         });
1724                         match prim_did {
1725                             Some(did) => {
1726                                 self.parent_stack.push(did);
1727                                 true
1728                             }
1729                             None => false,
1730                         }
1731                     }
1732                 }
1733             }
1734             _ => false
1735         };
1736
1737         // Once we've recursively found all the generics, hoard off all the
1738         // implementations elsewhere.
1739         let ret = self.fold_item_recur(item).and_then(|item| {
1740             if let clean::Item { inner: clean::ImplItem(_), .. } = item {
1741                 // Figure out the id of this impl. This may map to a
1742                 // primitive rather than always to a struct/enum.
1743                 // Note: matching twice to restrict the lifetime of the `i` borrow.
1744                 let mut dids = FxHashSet::default();
1745                 if let clean::Item { inner: clean::ImplItem(ref i), .. } = item {
1746                     match i.for_ {
1747                         clean::ResolvedPath { did, .. } |
1748                         clean::BorrowedRef {
1749                             type_: box clean::ResolvedPath { did, .. }, ..
1750                         } => {
1751                             dids.insert(did);
1752                         }
1753                         ref t => {
1754                             let did = t.primitive_type().and_then(|t| {
1755                                 self.primitive_locations.get(&t).cloned()
1756                             });
1757
1758                             if let Some(did) = did {
1759                                 dids.insert(did);
1760                             }
1761                         }
1762                     }
1763
1764                     if let Some(generics) = i.trait_.as_ref().and_then(|t| t.generics()) {
1765                         for bound in generics {
1766                             if let Some(did) = bound.def_id() {
1767                                 dids.insert(did);
1768                             }
1769                         }
1770                     }
1771                 } else {
1772                     unreachable!()
1773                 };
1774                 let impl_item = Impl {
1775                     impl_item: item,
1776                 };
1777                 if impl_item.trait_did().map_or(true, |d| self.traits.contains_key(&d)) {
1778                     for did in dids {
1779                         self.impls.entry(did).or_insert(vec![]).push(impl_item.clone());
1780                     }
1781                 } else {
1782                     let trait_did = impl_item.trait_did().unwrap();
1783                     self.orphan_trait_impls.push((trait_did, dids, impl_item));
1784                 }
1785                 None
1786             } else {
1787                 Some(item)
1788             }
1789         });
1790
1791         if pushed { self.stack.pop().unwrap(); }
1792         if parent_pushed { self.parent_stack.pop().unwrap(); }
1793         self.stripped_mod = orig_stripped_mod;
1794         self.parent_is_trait_impl = orig_parent_is_trait_impl;
1795         ret
1796     }
1797 }
1798
1799 impl Cache {
1800     fn generics(&mut self, generics: &clean::Generics) {
1801         for param in &generics.params {
1802             match param.kind {
1803                 clean::GenericParamDefKind::Lifetime => {}
1804                 clean::GenericParamDefKind::Type { did, .. } |
1805                 clean::GenericParamDefKind::Const { did, .. } => {
1806                     self.param_names.insert(did, param.name.clone());
1807                 }
1808             }
1809         }
1810     }
1811
1812     fn add_aliases(&mut self, item: &clean::Item) {
1813         if item.def_id.index == CRATE_DEF_INDEX {
1814             return
1815         }
1816         if let Some(ref item_name) = item.name {
1817             let path = self.paths.get(&item.def_id)
1818                                  .map(|p| p.0[..p.0.len() - 1].join("::"))
1819                                  .unwrap_or("std".to_owned());
1820             for alias in item.attrs.lists(sym::doc)
1821                                    .filter(|a| a.check_name(sym::alias))
1822                                    .filter_map(|a| a.value_str()
1823                                                     .map(|s| s.to_string().replace("\"", "")))
1824                                    .filter(|v| !v.is_empty())
1825                                    .collect::<FxHashSet<_>>()
1826                                    .into_iter() {
1827                 self.aliases.entry(alias)
1828                             .or_insert(Vec::with_capacity(1))
1829                             .push(IndexItem {
1830                                 ty: item.type_(),
1831                                 name: item_name.to_string(),
1832                                 path: path.clone(),
1833                                 desc: plain_summary_line_short(item.doc_value()),
1834                                 parent: None,
1835                                 parent_idx: None,
1836                                 search_type: get_index_search_type(&item),
1837                             });
1838             }
1839         }
1840     }
1841 }
1842
1843 #[derive(Debug, Eq, PartialEq, Hash)]
1844 struct ItemEntry {
1845     url: String,
1846     name: String,
1847 }
1848
1849 impl ItemEntry {
1850     fn new(mut url: String, name: String) -> ItemEntry {
1851         while url.starts_with('/') {
1852             url.remove(0);
1853         }
1854         ItemEntry {
1855             url,
1856             name,
1857         }
1858     }
1859 }
1860
1861 impl fmt::Display for ItemEntry {
1862     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1863         write!(f, "<a href='{}'>{}</a>", self.url, Escape(&self.name))
1864     }
1865 }
1866
1867 impl PartialOrd for ItemEntry {
1868     fn partial_cmp(&self, other: &ItemEntry) -> Option<::std::cmp::Ordering> {
1869         Some(self.cmp(other))
1870     }
1871 }
1872
1873 impl Ord for ItemEntry {
1874     fn cmp(&self, other: &ItemEntry) -> ::std::cmp::Ordering {
1875         self.name.cmp(&other.name)
1876     }
1877 }
1878
1879 #[derive(Debug)]
1880 struct AllTypes {
1881     structs: FxHashSet<ItemEntry>,
1882     enums: FxHashSet<ItemEntry>,
1883     unions: FxHashSet<ItemEntry>,
1884     primitives: FxHashSet<ItemEntry>,
1885     traits: FxHashSet<ItemEntry>,
1886     macros: FxHashSet<ItemEntry>,
1887     functions: FxHashSet<ItemEntry>,
1888     typedefs: FxHashSet<ItemEntry>,
1889     opaque_tys: FxHashSet<ItemEntry>,
1890     statics: FxHashSet<ItemEntry>,
1891     constants: FxHashSet<ItemEntry>,
1892     keywords: FxHashSet<ItemEntry>,
1893     attributes: FxHashSet<ItemEntry>,
1894     derives: FxHashSet<ItemEntry>,
1895     trait_aliases: FxHashSet<ItemEntry>,
1896 }
1897
1898 impl AllTypes {
1899     fn new() -> AllTypes {
1900         let new_set = |cap| FxHashSet::with_capacity_and_hasher(cap, Default::default());
1901         AllTypes {
1902             structs: new_set(100),
1903             enums: new_set(100),
1904             unions: new_set(100),
1905             primitives: new_set(26),
1906             traits: new_set(100),
1907             macros: new_set(100),
1908             functions: new_set(100),
1909             typedefs: new_set(100),
1910             opaque_tys: new_set(100),
1911             statics: new_set(100),
1912             constants: new_set(100),
1913             keywords: new_set(100),
1914             attributes: new_set(100),
1915             derives: new_set(100),
1916             trait_aliases: new_set(100),
1917         }
1918     }
1919
1920     fn append(&mut self, item_name: String, item_type: &ItemType) {
1921         let mut url: Vec<_> = item_name.split("::").skip(1).collect();
1922         if let Some(name) = url.pop() {
1923             let new_url = format!("{}/{}.{}.html", url.join("/"), item_type, name);
1924             url.push(name);
1925             let name = url.join("::");
1926             match *item_type {
1927                 ItemType::Struct => self.structs.insert(ItemEntry::new(new_url, name)),
1928                 ItemType::Enum => self.enums.insert(ItemEntry::new(new_url, name)),
1929                 ItemType::Union => self.unions.insert(ItemEntry::new(new_url, name)),
1930                 ItemType::Primitive => self.primitives.insert(ItemEntry::new(new_url, name)),
1931                 ItemType::Trait => self.traits.insert(ItemEntry::new(new_url, name)),
1932                 ItemType::Macro => self.macros.insert(ItemEntry::new(new_url, name)),
1933                 ItemType::Function => self.functions.insert(ItemEntry::new(new_url, name)),
1934                 ItemType::Typedef => self.typedefs.insert(ItemEntry::new(new_url, name)),
1935                 ItemType::OpaqueTy => self.opaque_tys.insert(ItemEntry::new(new_url, name)),
1936                 ItemType::Static => self.statics.insert(ItemEntry::new(new_url, name)),
1937                 ItemType::Constant => self.constants.insert(ItemEntry::new(new_url, name)),
1938                 ItemType::ProcAttribute => self.attributes.insert(ItemEntry::new(new_url, name)),
1939                 ItemType::ProcDerive => self.derives.insert(ItemEntry::new(new_url, name)),
1940                 ItemType::TraitAlias => self.trait_aliases.insert(ItemEntry::new(new_url, name)),
1941                 _ => true,
1942             };
1943         }
1944     }
1945 }
1946
1947 fn print_entries(f: &mut fmt::Formatter<'_>, e: &FxHashSet<ItemEntry>, title: &str,
1948                  class: &str) -> fmt::Result {
1949     if !e.is_empty() {
1950         let mut e: Vec<&ItemEntry> = e.iter().collect();
1951         e.sort();
1952         write!(f, "<h3 id='{}'>{}</h3><ul class='{} docblock'>{}</ul>",
1953                title,
1954                Escape(title),
1955                class,
1956                e.iter().map(|s| format!("<li>{}</li>", s)).collect::<String>())?;
1957     }
1958     Ok(())
1959 }
1960
1961 impl fmt::Display for AllTypes {
1962     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1963         write!(f,
1964 "<h1 class='fqn'>\
1965      <span class='out-of-band'>\
1966          <span id='render-detail'>\
1967              <a id=\"toggle-all-docs\" href=\"javascript:void(0)\" title=\"collapse all docs\">\
1968                  [<span class='inner'>&#x2212;</span>]\
1969              </a>\
1970          </span>
1971      </span>
1972      <span class='in-band'>List of all items</span>\
1973 </h1>")?;
1974         print_entries(f, &self.structs, "Structs", "structs")?;
1975         print_entries(f, &self.enums, "Enums", "enums")?;
1976         print_entries(f, &self.unions, "Unions", "unions")?;
1977         print_entries(f, &self.primitives, "Primitives", "primitives")?;
1978         print_entries(f, &self.traits, "Traits", "traits")?;
1979         print_entries(f, &self.macros, "Macros", "macros")?;
1980         print_entries(f, &self.attributes, "Attribute Macros", "attributes")?;
1981         print_entries(f, &self.derives, "Derive Macros", "derives")?;
1982         print_entries(f, &self.functions, "Functions", "functions")?;
1983         print_entries(f, &self.typedefs, "Typedefs", "typedefs")?;
1984         print_entries(f, &self.trait_aliases, "Trait Aliases", "trait-aliases")?;
1985         print_entries(f, &self.opaque_tys, "Opaque Types", "opaque-types")?;
1986         print_entries(f, &self.statics, "Statics", "statics")?;
1987         print_entries(f, &self.constants, "Constants", "constants")
1988     }
1989 }
1990
1991 #[derive(Debug)]
1992 struct Settings<'a> {
1993     // (id, explanation, default value)
1994     settings: Vec<(&'static str, &'static str, bool)>,
1995     root_path: &'a str,
1996     suffix: &'a str,
1997 }
1998
1999 impl<'a> Settings<'a> {
2000     pub fn new(root_path: &'a str, suffix: &'a str) -> Settings<'a> {
2001         Settings {
2002             settings: vec![
2003                 ("item-declarations", "Auto-hide item declarations.", true),
2004                 ("item-attributes", "Auto-hide item attributes.", true),
2005                 ("trait-implementations", "Auto-hide trait implementations documentation",
2006                  true),
2007                 ("method-docs", "Auto-hide item methods' documentation", false),
2008                 ("go-to-only-result", "Directly go to item in search if there is only one result",
2009                  false),
2010                 ("line-numbers", "Show line numbers on code examples", false),
2011             ],
2012             root_path,
2013             suffix,
2014         }
2015     }
2016 }
2017
2018 impl<'a> fmt::Display for Settings<'a> {
2019     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2020         write!(f,
2021 "<h1 class='fqn'>\
2022      <span class='in-band'>Rustdoc settings</span>\
2023 </h1>\
2024 <div class='settings'>{}</div>\
2025 <script src='{}settings{}.js'></script>",
2026                self.settings.iter()
2027                             .map(|(id, text, enabled)| {
2028                                 format!("<div class='setting-line'>\
2029                                              <label class='toggle'>\
2030                                                 <input type='checkbox' id='{}' {}>\
2031                                                 <span class='slider'></span>\
2032                                              </label>\
2033                                              <div>{}</div>\
2034                                          </div>", id, if *enabled { " checked" } else { "" }, text)
2035                             })
2036                             .collect::<String>(),
2037                self.root_path,
2038                self.suffix)
2039     }
2040 }
2041
2042 impl Context {
2043     fn derive_id(&self, id: String) -> String {
2044         let mut map = self.id_map.borrow_mut();
2045         map.derive(id)
2046     }
2047
2048     /// String representation of how to get back to the root path of the 'doc/'
2049     /// folder in terms of a relative URL.
2050     fn root_path(&self) -> String {
2051         "../".repeat(self.current.len())
2052     }
2053
2054     /// Recurse in the directory structure and change the "root path" to make
2055     /// sure it always points to the top (relatively).
2056     fn recurse<T, F>(&mut self, s: String, f: F) -> T where
2057         F: FnOnce(&mut Context) -> T,
2058     {
2059         if s.is_empty() {
2060             panic!("Unexpected empty destination: {:?}", self.current);
2061         }
2062         let prev = self.dst.clone();
2063         self.dst.push(&s);
2064         self.current.push(s);
2065
2066         info!("Recursing into {}", self.dst.display());
2067
2068         let ret = f(self);
2069
2070         info!("Recursed; leaving {}", self.dst.display());
2071
2072         // Go back to where we were at
2073         self.dst = prev;
2074         self.current.pop().unwrap();
2075
2076         ret
2077     }
2078
2079     /// Main method for rendering a crate.
2080     ///
2081     /// This currently isn't parallelized, but it'd be pretty easy to add
2082     /// parallelization to this function.
2083     fn krate(self, mut krate: clean::Crate) -> Result<(), Error> {
2084         let mut item = match krate.module.take() {
2085             Some(i) => i,
2086             None => return Ok(()),
2087         };
2088         let final_file = self.dst.join(&krate.name)
2089                                  .join("all.html");
2090         let settings_file = self.dst.join("settings.html");
2091
2092         let crate_name = krate.name.clone();
2093         item.name = Some(krate.name);
2094
2095         let mut all = AllTypes::new();
2096
2097         {
2098             // Render the crate documentation
2099             let mut work = vec![(self.clone(), item)];
2100
2101             while let Some((mut cx, item)) = work.pop() {
2102                 cx.item(item, &mut all, |cx, item| {
2103                     work.push((cx.clone(), item))
2104                 })?
2105             }
2106         }
2107
2108         let mut root_path = self.dst.to_str().expect("invalid path").to_owned();
2109         if !root_path.ends_with('/') {
2110             root_path.push('/');
2111         }
2112         let mut page = layout::Page {
2113             title: "List of all items in this crate",
2114             css_class: "mod",
2115             root_path: "../",
2116             static_root_path: self.shared.static_root_path.as_deref(),
2117             description: "List of all items in this crate",
2118             keywords: BASIC_KEYWORDS,
2119             resource_suffix: &self.shared.resource_suffix,
2120             extra_scripts: &[],
2121             static_extra_scripts: &[],
2122         };
2123         let sidebar = if let Some(ref version) = cache().crate_version {
2124             format!("<p class='location'>Crate {}</p>\
2125                      <div class='block version'>\
2126                          <p>Version {}</p>\
2127                      </div>\
2128                      <a id='all-types' href='index.html'><p>Back to index</p></a>",
2129                     crate_name, version)
2130         } else {
2131             String::new()
2132         };
2133         let mut v = Vec::new();
2134         try_err!(layout::render(&mut v, &self.shared.layout,
2135                                 &page, &sidebar, &all,
2136                                 self.shared.css_file_extension.is_some(),
2137                                 &self.shared.themes,
2138                                 self.shared.generate_search_filter),
2139                  &final_file);
2140         self.shared.fs.write(&final_file, &v)?;
2141
2142         // Generating settings page.
2143         let settings = Settings::new(self.shared.static_root_path.as_deref().unwrap_or("./"),
2144                                      &self.shared.resource_suffix);
2145         page.title = "Rustdoc settings";
2146         page.description = "Settings of Rustdoc";
2147         page.root_path = "./";
2148
2149         let mut themes = self.shared.themes.clone();
2150         let sidebar = "<p class='location'>Settings</p><div class='sidebar-elems'></div>";
2151         themes.push(PathBuf::from("settings.css"));
2152         let layout = self.shared.layout.clone();
2153         let mut v = Vec::new();
2154         try_err!(layout::render(&mut v, &layout,
2155                                 &page, &sidebar, &settings,
2156                                 self.shared.css_file_extension.is_some(),
2157                                 &themes,
2158                                 self.shared.generate_search_filter),
2159                  &settings_file);
2160         self.shared.fs.write(&settings_file, &v)?;
2161
2162         Ok(())
2163     }
2164
2165     fn render_item(&self,
2166                    writer: &mut dyn io::Write,
2167                    it: &clean::Item,
2168                    pushname: bool)
2169                    -> io::Result<()> {
2170         // A little unfortunate that this is done like this, but it sure
2171         // does make formatting *a lot* nicer.
2172         CURRENT_LOCATION_KEY.with(|slot| {
2173             *slot.borrow_mut() = self.current.clone();
2174         });
2175
2176         let mut title = if it.is_primitive() || it.is_keyword() {
2177             // No need to include the namespace for primitive types and keywords
2178             String::new()
2179         } else {
2180             self.current.join("::")
2181         };
2182         if pushname {
2183             if !title.is_empty() {
2184                 title.push_str("::");
2185             }
2186             title.push_str(it.name.as_ref().unwrap());
2187         }
2188         title.push_str(" - Rust");
2189         let tyname = it.type_().css_class();
2190         let desc = if it.is_crate() {
2191             format!("API documentation for the Rust `{}` crate.",
2192                     self.shared.layout.krate)
2193         } else {
2194             format!("API documentation for the Rust `{}` {} in crate `{}`.",
2195                     it.name.as_ref().unwrap(), tyname, self.shared.layout.krate)
2196         };
2197         let keywords = make_item_keywords(it);
2198         let page = layout::Page {
2199             css_class: tyname,
2200             root_path: &self.root_path(),
2201             static_root_path: self.shared.static_root_path.as_deref(),
2202             title: &title,
2203             description: &desc,
2204             keywords: &keywords,
2205             resource_suffix: &self.shared.resource_suffix,
2206             extra_scripts: &[],
2207             static_extra_scripts: &[],
2208         };
2209
2210         {
2211             self.id_map.borrow_mut().reset();
2212             self.id_map.borrow_mut().populate(initial_ids());
2213         }
2214
2215         if !self.render_redirect_pages {
2216             layout::render(writer, &self.shared.layout, &page,
2217                            &Sidebar{ cx: self, item: it },
2218                            &Item{ cx: self, item: it },
2219                            self.shared.css_file_extension.is_some(),
2220                            &self.shared.themes,
2221                            self.shared.generate_search_filter)?;
2222         } else {
2223             let mut url = self.root_path();
2224             if let Some(&(ref names, ty)) = cache().paths.get(&it.def_id) {
2225                 for name in &names[..names.len() - 1] {
2226                     url.push_str(name);
2227                     url.push_str("/");
2228                 }
2229                 url.push_str(&item_path(ty, names.last().unwrap()));
2230                 layout::redirect(writer, &url)?;
2231             }
2232         }
2233         Ok(())
2234     }
2235
2236     /// Non-parallelized version of rendering an item. This will take the input
2237     /// item, render its contents, and then invoke the specified closure with
2238     /// all sub-items which need to be rendered.
2239     ///
2240     /// The rendering driver uses this closure to queue up more work.
2241     fn item<F>(&mut self, item: clean::Item, all: &mut AllTypes, mut f: F) -> Result<(), Error>
2242         where F: FnMut(&mut Context, clean::Item),
2243     {
2244         // Stripped modules survive the rustdoc passes (i.e., `strip-private`)
2245         // if they contain impls for public types. These modules can also
2246         // contain items such as publicly re-exported structures.
2247         //
2248         // External crates will provide links to these structures, so
2249         // these modules are recursed into, but not rendered normally
2250         // (a flag on the context).
2251         if !self.render_redirect_pages {
2252             self.render_redirect_pages = item.is_stripped();
2253         }
2254
2255         if item.is_mod() {
2256             // modules are special because they add a namespace. We also need to
2257             // recurse into the items of the module as well.
2258             let name = item.name.as_ref().unwrap().to_string();
2259             let mut item = Some(item);
2260             let scx = self.shared.clone();
2261             self.recurse(name, |this| {
2262                 let item = item.take().unwrap();
2263
2264                 let mut buf = Vec::new();
2265                 this.render_item(&mut buf, &item, false).unwrap();
2266                 // buf will be empty if the module is stripped and there is no redirect for it
2267                 if !buf.is_empty() {
2268                     this.shared.ensure_dir(&this.dst)?;
2269                     let joint_dst = this.dst.join("index.html");
2270                     scx.fs.write(&joint_dst, buf)?;
2271                 }
2272
2273                 let m = match item.inner {
2274                     clean::StrippedItem(box clean::ModuleItem(m)) |
2275                     clean::ModuleItem(m) => m,
2276                     _ => unreachable!()
2277                 };
2278
2279                 // Render sidebar-items.js used throughout this module.
2280                 if !this.render_redirect_pages {
2281                     let items = this.build_sidebar_items(&m);
2282                     let js_dst = this.dst.join("sidebar-items.js");
2283                     let mut v = Vec::new();
2284                     try_err!(write!(&mut v, "initSidebarItems({});",
2285                                     as_json(&items)), &js_dst);
2286                     scx.fs.write(&js_dst, &v)?;
2287                 }
2288
2289                 for item in m.items {
2290                     f(this, item);
2291                 }
2292
2293                 Ok(())
2294             })?;
2295         } else if item.name.is_some() {
2296             let mut buf = Vec::new();
2297             self.render_item(&mut buf, &item, true).unwrap();
2298             // buf will be empty if the item is stripped and there is no redirect for it
2299             if !buf.is_empty() {
2300                 let name = item.name.as_ref().unwrap();
2301                 let item_type = item.type_();
2302                 let file_name = &item_path(item_type, name);
2303                 self.shared.ensure_dir(&self.dst)?;
2304                 let joint_dst = self.dst.join(file_name);
2305                 self.shared.fs.write(&joint_dst, buf)?;
2306
2307                 if !self.render_redirect_pages {
2308                     all.append(full_path(self, &item), &item_type);
2309                 }
2310                 if self.shared.generate_redirect_pages {
2311                     // Redirect from a sane URL using the namespace to Rustdoc's
2312                     // URL for the page.
2313                     let redir_name = format!("{}.{}.html", name, item_type.name_space());
2314                     let redir_dst = self.dst.join(redir_name);
2315                     let mut v = Vec::new();
2316                     try_err!(layout::redirect(&mut v, file_name), &redir_dst);
2317                     self.shared.fs.write(&redir_dst, &v)?;
2318                 }
2319                 // If the item is a macro, redirect from the old macro URL (with !)
2320                 // to the new one (without).
2321                 if item_type == ItemType::Macro {
2322                     let redir_name = format!("{}.{}!.html", item_type, name);
2323                     let redir_dst = self.dst.join(redir_name);
2324                     let mut v = Vec::new();
2325                     try_err!(layout::redirect(&mut v, file_name), &redir_dst);
2326                     self.shared.fs.write(&redir_dst, &v)?;
2327                 }
2328             }
2329         }
2330         Ok(())
2331     }
2332
2333     fn build_sidebar_items(&self, m: &clean::Module) -> BTreeMap<String, Vec<NameDoc>> {
2334         // BTreeMap instead of HashMap to get a sorted output
2335         let mut map: BTreeMap<_, Vec<_>> = BTreeMap::new();
2336         for item in &m.items {
2337             if item.is_stripped() { continue }
2338
2339             let short = item.type_().css_class();
2340             let myname = match item.name {
2341                 None => continue,
2342                 Some(ref s) => s.to_string(),
2343             };
2344             let short = short.to_string();
2345             map.entry(short).or_default()
2346                 .push((myname, Some(plain_summary_line(item.doc_value()))));
2347         }
2348
2349         if self.shared.sort_modules_alphabetically {
2350             for (_, items) in &mut map {
2351                 items.sort();
2352             }
2353         }
2354         map
2355     }
2356 }
2357
2358 impl<'a> Item<'a> {
2359     /// Generates a url appropriate for an `href` attribute back to the source of
2360     /// this item.
2361     ///
2362     /// The url generated, when clicked, will redirect the browser back to the
2363     /// original source code.
2364     ///
2365     /// If `None` is returned, then a source link couldn't be generated. This
2366     /// may happen, for example, with externally inlined items where the source
2367     /// of their crate documentation isn't known.
2368     fn src_href(&self) -> Option<String> {
2369         let mut root = self.cx.root_path();
2370
2371         let cache = cache();
2372         let mut path = String::new();
2373
2374         // We can safely ignore macros from other libraries
2375         let file = match self.item.source.filename {
2376             FileName::Real(ref path) => path,
2377             _ => return None,
2378         };
2379
2380         let (krate, path) = if self.item.def_id.is_local() {
2381             if let Some(path) = self.cx.shared.local_sources.get(file) {
2382                 (&self.cx.shared.layout.krate, path)
2383             } else {
2384                 return None;
2385             }
2386         } else {
2387             let (krate, src_root) = match *cache.extern_locations.get(&self.item.def_id.krate)? {
2388                 (ref name, ref src, Local) => (name, src),
2389                 (ref name, ref src, Remote(ref s)) => {
2390                     root = s.to_string();
2391                     (name, src)
2392                 }
2393                 (_, _, Unknown) => return None,
2394             };
2395
2396             clean_srcpath(&src_root, file, false, |component| {
2397                 path.push_str(&component.to_string_lossy());
2398                 path.push('/');
2399             });
2400             let mut fname = file.file_name().expect("source has no filename")
2401                                 .to_os_string();
2402             fname.push(".html");
2403             path.push_str(&fname.to_string_lossy());
2404             (krate, &path)
2405         };
2406
2407         let lines = if self.item.source.loline == self.item.source.hiline {
2408             self.item.source.loline.to_string()
2409         } else {
2410             format!("{}-{}", self.item.source.loline, self.item.source.hiline)
2411         };
2412         Some(format!("{root}src/{krate}/{path}#{lines}",
2413                      root = Escape(&root),
2414                      krate = krate,
2415                      path = path,
2416                      lines = lines))
2417     }
2418 }
2419
2420 fn wrap_into_docblock<F>(w: &mut fmt::Formatter<'_>,
2421                          f: F) -> fmt::Result
2422 where F: Fn(&mut fmt::Formatter<'_>) -> fmt::Result {
2423     write!(w, "<div class=\"docblock type-decl hidden-by-usual-hider\">")?;
2424     f(w)?;
2425     write!(w, "</div>")
2426 }
2427
2428 impl<'a> fmt::Display for Item<'a> {
2429     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
2430         debug_assert!(!self.item.is_stripped());
2431         // Write the breadcrumb trail header for the top
2432         write!(fmt, "<h1 class='fqn'><span class='out-of-band'>")?;
2433         if let Some(version) = self.item.stable_since() {
2434             write!(fmt, "<span class='since' title='Stable since Rust version {0}'>{0}</span>",
2435                    version)?;
2436         }
2437         write!(fmt,
2438                "<span id='render-detail'>\
2439                    <a id=\"toggle-all-docs\" href=\"javascript:void(0)\" \
2440                       title=\"collapse all docs\">\
2441                        [<span class='inner'>&#x2212;</span>]\
2442                    </a>\
2443                </span>")?;
2444
2445         // Write `src` tag
2446         //
2447         // When this item is part of a `pub use` in a downstream crate, the
2448         // [src] link in the downstream documentation will actually come back to
2449         // this page, and this link will be auto-clicked. The `id` attribute is
2450         // used to find the link to auto-click.
2451         if self.cx.shared.include_sources && !self.item.is_primitive() {
2452             if let Some(l) = self.src_href() {
2453                 write!(fmt, "<a class='srclink' href='{}' title='{}'>[src]</a>",
2454                        l, "goto source code")?;
2455             }
2456         }
2457
2458         write!(fmt, "</span>")?; // out-of-band
2459         write!(fmt, "<span class='in-band'>")?;
2460         match self.item.inner {
2461             clean::ModuleItem(ref m) => if m.is_crate {
2462                     write!(fmt, "Crate ")?;
2463                 } else {
2464                     write!(fmt, "Module ")?;
2465                 },
2466             clean::FunctionItem(..) | clean::ForeignFunctionItem(..) => write!(fmt, "Function ")?,
2467             clean::TraitItem(..) => write!(fmt, "Trait ")?,
2468             clean::StructItem(..) => write!(fmt, "Struct ")?,
2469             clean::UnionItem(..) => write!(fmt, "Union ")?,
2470             clean::EnumItem(..) => write!(fmt, "Enum ")?,
2471             clean::TypedefItem(..) => write!(fmt, "Type Definition ")?,
2472             clean::MacroItem(..) => write!(fmt, "Macro ")?,
2473             clean::ProcMacroItem(ref mac) => match mac.kind {
2474                 MacroKind::Bang => write!(fmt, "Macro ")?,
2475                 MacroKind::Attr => write!(fmt, "Attribute Macro ")?,
2476                 MacroKind::Derive => write!(fmt, "Derive Macro ")?,
2477             }
2478             clean::PrimitiveItem(..) => write!(fmt, "Primitive Type ")?,
2479             clean::StaticItem(..) | clean::ForeignStaticItem(..) => write!(fmt, "Static ")?,
2480             clean::ConstantItem(..) => write!(fmt, "Constant ")?,
2481             clean::ForeignTypeItem => write!(fmt, "Foreign Type ")?,
2482             clean::KeywordItem(..) => write!(fmt, "Keyword ")?,
2483             clean::OpaqueTyItem(..) => write!(fmt, "Opaque Type ")?,
2484             clean::TraitAliasItem(..) => write!(fmt, "Trait Alias ")?,
2485             _ => {
2486                 // We don't generate pages for any other type.
2487                 unreachable!();
2488             }
2489         }
2490         if !self.item.is_primitive() && !self.item.is_keyword() {
2491             let cur = &self.cx.current;
2492             let amt = if self.item.is_mod() { cur.len() - 1 } else { cur.len() };
2493             for (i, component) in cur.iter().enumerate().take(amt) {
2494                 write!(fmt, "<a href='{}index.html'>{}</a>::<wbr>",
2495                        "../".repeat(cur.len() - i - 1),
2496                        component)?;
2497             }
2498         }
2499         write!(fmt, "<a class=\"{}\" href=''>{}</a>",
2500                self.item.type_(), self.item.name.as_ref().unwrap())?;
2501
2502         write!(fmt, "</span></h1>")?; // in-band
2503
2504         match self.item.inner {
2505             clean::ModuleItem(ref m) =>
2506                 item_module(fmt, self.cx, self.item, &m.items),
2507             clean::FunctionItem(ref f) | clean::ForeignFunctionItem(ref f) =>
2508                 item_function(fmt, self.cx, self.item, f),
2509             clean::TraitItem(ref t) => item_trait(fmt, self.cx, self.item, t),
2510             clean::StructItem(ref s) => item_struct(fmt, self.cx, self.item, s),
2511             clean::UnionItem(ref s) => item_union(fmt, self.cx, self.item, s),
2512             clean::EnumItem(ref e) => item_enum(fmt, self.cx, self.item, e),
2513             clean::TypedefItem(ref t, _) => item_typedef(fmt, self.cx, self.item, t),
2514             clean::MacroItem(ref m) => item_macro(fmt, self.cx, self.item, m),
2515             clean::ProcMacroItem(ref m) => item_proc_macro(fmt, self.cx, self.item, m),
2516             clean::PrimitiveItem(ref p) => item_primitive(fmt, self.cx, self.item, p),
2517             clean::StaticItem(ref i) | clean::ForeignStaticItem(ref i) =>
2518                 item_static(fmt, self.cx, self.item, i),
2519             clean::ConstantItem(ref c) => item_constant(fmt, self.cx, self.item, c),
2520             clean::ForeignTypeItem => item_foreign_type(fmt, self.cx, self.item),
2521             clean::KeywordItem(ref k) => item_keyword(fmt, self.cx, self.item, k),
2522             clean::OpaqueTyItem(ref e, _) => item_opaque_ty(fmt, self.cx, self.item, e),
2523             clean::TraitAliasItem(ref ta) => item_trait_alias(fmt, self.cx, self.item, ta),
2524             _ => {
2525                 // We don't generate pages for any other type.
2526                 unreachable!();
2527             }
2528         }
2529     }
2530 }
2531
2532 fn item_path(ty: ItemType, name: &str) -> String {
2533     match ty {
2534         ItemType::Module => format!("{}index.html", SlashChecker(name)),
2535         _ => format!("{}.{}.html", ty.css_class(), name),
2536     }
2537 }
2538
2539 fn full_path(cx: &Context, item: &clean::Item) -> String {
2540     let mut s = cx.current.join("::");
2541     s.push_str("::");
2542     s.push_str(item.name.as_ref().unwrap());
2543     s
2544 }
2545
2546 fn shorter(s: Option<&str>) -> String {
2547     match s {
2548         Some(s) => s.lines()
2549             .skip_while(|s| s.chars().all(|c| c.is_whitespace()))
2550             .take_while(|line|{
2551             (*line).chars().any(|chr|{
2552                 !chr.is_whitespace()
2553             })
2554         }).collect::<Vec<_>>().join("\n"),
2555         None => String::new()
2556     }
2557 }
2558
2559 #[inline]
2560 fn plain_summary_line(s: Option<&str>) -> String {
2561     let line = shorter(s).replace("\n", " ");
2562     markdown::plain_summary_line_full(&line[..], false)
2563 }
2564
2565 #[inline]
2566 fn plain_summary_line_short(s: Option<&str>) -> String {
2567     let line = shorter(s).replace("\n", " ");
2568     markdown::plain_summary_line_full(&line[..], true)
2569 }
2570
2571 fn document(w: &mut fmt::Formatter<'_>, cx: &Context, item: &clean::Item) -> fmt::Result {
2572     if let Some(ref name) = item.name {
2573         info!("Documenting {}", name);
2574     }
2575     document_stability(w, cx, item, false)?;
2576     document_full(w, item, cx, "", false)?;
2577     Ok(())
2578 }
2579
2580 /// Render md_text as markdown.
2581 fn render_markdown(w: &mut fmt::Formatter<'_>,
2582                    cx: &Context,
2583                    md_text: &str,
2584                    links: Vec<(String, String)>,
2585                    prefix: &str,
2586                    is_hidden: bool)
2587                    -> fmt::Result {
2588     let mut ids = cx.id_map.borrow_mut();
2589     write!(w, "<div class='docblock{}'>{}{}</div>",
2590            if is_hidden { " hidden" } else { "" },
2591            prefix,
2592            Markdown(md_text, &links, RefCell::new(&mut ids),
2593            cx.codes, cx.edition))
2594 }
2595
2596 fn document_short(
2597     w: &mut fmt::Formatter<'_>,
2598     cx: &Context,
2599     item: &clean::Item,
2600     link: AssocItemLink<'_>,
2601     prefix: &str, is_hidden: bool
2602 ) -> fmt::Result {
2603     if let Some(s) = item.doc_value() {
2604         let markdown = if s.contains('\n') {
2605             format!("{} [Read more]({})",
2606                     &plain_summary_line(Some(s)), naive_assoc_href(item, link))
2607         } else {
2608             plain_summary_line(Some(s))
2609         };
2610         render_markdown(w, cx, &markdown, item.links(), prefix, is_hidden)?;
2611     } else if !prefix.is_empty() {
2612         write!(w, "<div class='docblock{}'>{}</div>",
2613                if is_hidden { " hidden" } else { "" },
2614                prefix)?;
2615     }
2616     Ok(())
2617 }
2618
2619 fn document_full(w: &mut fmt::Formatter<'_>, item: &clean::Item,
2620                  cx: &Context, prefix: &str, is_hidden: bool) -> fmt::Result {
2621     if let Some(s) = cx.shared.maybe_collapsed_doc_value(item) {
2622         debug!("Doc block: =====\n{}\n=====", s);
2623         render_markdown(w, cx, &*s, item.links(), prefix, is_hidden)?;
2624     } else if !prefix.is_empty() {
2625         write!(w, "<div class='docblock{}'>{}</div>",
2626                if is_hidden { " hidden" } else { "" },
2627                prefix)?;
2628     }
2629     Ok(())
2630 }
2631
2632 fn document_stability(w: &mut fmt::Formatter<'_>, cx: &Context, item: &clean::Item,
2633                       is_hidden: bool) -> fmt::Result {
2634     let stabilities = short_stability(item, cx);
2635     if !stabilities.is_empty() {
2636         write!(w, "<div class='stability{}'>", if is_hidden { " hidden" } else { "" })?;
2637         for stability in stabilities {
2638             write!(w, "{}", stability)?;
2639         }
2640         write!(w, "</div>")?;
2641     }
2642     Ok(())
2643 }
2644
2645 fn document_non_exhaustive_header(item: &clean::Item) -> &str {
2646     if item.is_non_exhaustive() { " (Non-exhaustive)" } else { "" }
2647 }
2648
2649 fn document_non_exhaustive(w: &mut fmt::Formatter<'_>, item: &clean::Item) -> fmt::Result {
2650     if item.is_non_exhaustive() {
2651         write!(w, "<div class='docblock non-exhaustive non-exhaustive-{}'>", {
2652             if item.is_struct() {
2653                 "struct"
2654             } else if item.is_enum() {
2655                 "enum"
2656             } else if item.is_variant() {
2657                 "variant"
2658             } else {
2659                 "type"
2660             }
2661         })?;
2662
2663         if item.is_struct() {
2664             write!(w, "Non-exhaustive structs could have additional fields added in future. \
2665                        Therefore, non-exhaustive structs cannot be constructed in external crates \
2666                        using the traditional <code>Struct {{ .. }}</code> syntax; cannot be \
2667                        matched against without a wildcard <code>..</code>; and \
2668                        struct update syntax will not work.")?;
2669         } else if item.is_enum() {
2670             write!(w, "Non-exhaustive enums could have additional variants added in future. \
2671                        Therefore, when matching against variants of non-exhaustive enums, an \
2672                        extra wildcard arm must be added to account for any future variants.")?;
2673         } else if item.is_variant() {
2674             write!(w, "Non-exhaustive enum variants could have additional fields added in future. \
2675                        Therefore, non-exhaustive enum variants cannot be constructed in external \
2676                        crates and cannot be matched against.")?;
2677         } else {
2678             write!(w, "This type will require a wildcard arm in any match statements or \
2679                        constructors.")?;
2680         }
2681
2682         write!(w, "</div>")?;
2683     }
2684
2685     Ok(())
2686 }
2687
2688 fn name_key(name: &str) -> (&str, u64, usize) {
2689     let end = name.bytes()
2690         .rposition(|b| b.is_ascii_digit()).map_or(name.len(), |i| i + 1);
2691
2692     // find number at end
2693     let split = name[0..end].bytes()
2694         .rposition(|b| !b.is_ascii_digit()).map_or(0, |i| i + 1);
2695
2696     // count leading zeroes
2697     let after_zeroes =
2698         name[split..end].bytes().position(|b| b != b'0').map_or(name.len(), |extra| split + extra);
2699
2700     // sort leading zeroes last
2701     let num_zeroes = after_zeroes - split;
2702
2703     match name[split..end].parse() {
2704         Ok(n) => (&name[..split], n, num_zeroes),
2705         Err(_) => (name, 0, num_zeroes),
2706     }
2707 }
2708
2709 fn item_module(w: &mut fmt::Formatter<'_>, cx: &Context,
2710                item: &clean::Item, items: &[clean::Item]) -> fmt::Result {
2711     document(w, cx, item)?;
2712
2713     let mut indices = (0..items.len()).filter(|i| !items[*i].is_stripped()).collect::<Vec<usize>>();
2714
2715     // the order of item types in the listing
2716     fn reorder(ty: ItemType) -> u8 {
2717         match ty {
2718             ItemType::ExternCrate     => 0,
2719             ItemType::Import          => 1,
2720             ItemType::Primitive       => 2,
2721             ItemType::Module          => 3,
2722             ItemType::Macro           => 4,
2723             ItemType::Struct          => 5,
2724             ItemType::Enum            => 6,
2725             ItemType::Constant        => 7,
2726             ItemType::Static          => 8,
2727             ItemType::Trait           => 9,
2728             ItemType::Function        => 10,
2729             ItemType::Typedef         => 12,
2730             ItemType::Union           => 13,
2731             _                         => 14 + ty as u8,
2732         }
2733     }
2734
2735     fn cmp(i1: &clean::Item, i2: &clean::Item, idx1: usize, idx2: usize) -> Ordering {
2736         let ty1 = i1.type_();
2737         let ty2 = i2.type_();
2738         if ty1 != ty2 {
2739             return (reorder(ty1), idx1).cmp(&(reorder(ty2), idx2))
2740         }
2741         let s1 = i1.stability.as_ref().map(|s| s.level);
2742         let s2 = i2.stability.as_ref().map(|s| s.level);
2743         match (s1, s2) {
2744             (Some(stability::Unstable), Some(stability::Stable)) => return Ordering::Greater,
2745             (Some(stability::Stable), Some(stability::Unstable)) => return Ordering::Less,
2746             _ => {}
2747         }
2748         let lhs = i1.name.as_ref().map_or("", |s| &**s);
2749         let rhs = i2.name.as_ref().map_or("", |s| &**s);
2750         name_key(lhs).cmp(&name_key(rhs))
2751     }
2752
2753     if cx.shared.sort_modules_alphabetically {
2754         indices.sort_by(|&i1, &i2| cmp(&items[i1], &items[i2], i1, i2));
2755     }
2756     // This call is to remove re-export duplicates in cases such as:
2757     //
2758     // ```
2759     // pub mod foo {
2760     //     pub mod bar {
2761     //         pub trait Double { fn foo(); }
2762     //     }
2763     // }
2764     //
2765     // pub use foo::bar::*;
2766     // pub use foo::*;
2767     // ```
2768     //
2769     // `Double` will appear twice in the generated docs.
2770     //
2771     // FIXME: This code is quite ugly and could be improved. Small issue: DefId
2772     // can be identical even if the elements are different (mostly in imports).
2773     // So in case this is an import, we keep everything by adding a "unique id"
2774     // (which is the position in the vector).
2775     indices.dedup_by_key(|i| (items[*i].def_id,
2776                               if items[*i].name.as_ref().is_some() {
2777                                   Some(full_path(cx, &items[*i]))
2778                               } else {
2779                                   None
2780                               },
2781                               items[*i].type_(),
2782                               if items[*i].is_import() {
2783                                   *i
2784                               } else {
2785                                   0
2786                               }));
2787
2788     debug!("{:?}", indices);
2789     let mut curty = None;
2790     for &idx in &indices {
2791         let myitem = &items[idx];
2792         if myitem.is_stripped() {
2793             continue;
2794         }
2795
2796         let myty = Some(myitem.type_());
2797         if curty == Some(ItemType::ExternCrate) && myty == Some(ItemType::Import) {
2798             // Put `extern crate` and `use` re-exports in the same section.
2799             curty = myty;
2800         } else if myty != curty {
2801             if curty.is_some() {
2802                 write!(w, "</table>")?;
2803             }
2804             curty = myty;
2805             let (short, name) = item_ty_to_strs(&myty.unwrap());
2806             write!(w, "<h2 id='{id}' class='section-header'>\
2807                        <a href=\"#{id}\">{name}</a></h2>\n<table>",
2808                    id = cx.derive_id(short.to_owned()), name = name)?;
2809         }
2810
2811         match myitem.inner {
2812             clean::ExternCrateItem(ref name, ref src) => {
2813                 use crate::html::format::HRef;
2814
2815                 match *src {
2816                     Some(ref src) => {
2817                         write!(w, "<tr><td><code>{}extern crate {} as {};",
2818                                VisSpace(&myitem.visibility),
2819                                HRef::new(myitem.def_id, src),
2820                                name)?
2821                     }
2822                     None => {
2823                         write!(w, "<tr><td><code>{}extern crate {};",
2824                                VisSpace(&myitem.visibility),
2825                                HRef::new(myitem.def_id, name))?
2826                     }
2827                 }
2828                 write!(w, "</code></td></tr>")?;
2829             }
2830
2831             clean::ImportItem(ref import) => {
2832                 write!(w, "<tr><td><code>{}{}</code></td></tr>",
2833                        VisSpace(&myitem.visibility), *import)?;
2834             }
2835
2836             _ => {
2837                 if myitem.name.is_none() { continue }
2838
2839                 let unsafety_flag = match myitem.inner {
2840                     clean::FunctionItem(ref func) | clean::ForeignFunctionItem(ref func)
2841                     if func.header.unsafety == hir::Unsafety::Unsafe => {
2842                         "<a title='unsafe function' href='#'><sup>⚠</sup></a>"
2843                     }
2844                     _ => "",
2845                 };
2846
2847                 let stab = myitem.stability_class();
2848                 let add = if stab.is_some() {
2849                     " "
2850                 } else {
2851                     ""
2852                 };
2853
2854                 let doc_value = myitem.doc_value().unwrap_or("");
2855                 write!(w, "\
2856                        <tr class='{stab}{add}module-item'>\
2857                            <td><a class=\"{class}\" href=\"{href}\" \
2858                                   title='{title}'>{name}</a>{unsafety_flag}</td>\
2859                            <td class='docblock-short'>{stab_tags}{docs}</td>\
2860                        </tr>",
2861                        name = *myitem.name.as_ref().unwrap(),
2862                        stab_tags = stability_tags(myitem),
2863                        docs = MarkdownSummaryLine(doc_value, &myitem.links()),
2864                        class = myitem.type_(),
2865                        add = add,
2866                        stab = stab.unwrap_or_else(|| String::new()),
2867                        unsafety_flag = unsafety_flag,
2868                        href = item_path(myitem.type_(), myitem.name.as_ref().unwrap()),
2869                        title = [full_path(cx, myitem), myitem.type_().to_string()]
2870                                 .iter()
2871                                 .filter_map(|s| if !s.is_empty() {
2872                                     Some(s.as_str())
2873                                 } else {
2874                                     None
2875                                 })
2876                                 .collect::<Vec<_>>()
2877                                 .join(" "),
2878                       )?;
2879             }
2880         }
2881     }
2882
2883     if curty.is_some() {
2884         write!(w, "</table>")?;
2885     }
2886     Ok(())
2887 }
2888
2889 /// Render the stability and deprecation tags that are displayed in the item's summary at the
2890 /// module level.
2891 fn stability_tags(item: &clean::Item) -> String {
2892     let mut tags = String::new();
2893
2894     fn tag_html(class: &str, contents: &str) -> String {
2895         format!(r#"<span class="stab {}">{}</span>"#, class, contents)
2896     }
2897
2898     // The trailing space after each tag is to space it properly against the rest of the docs.
2899     if item.deprecation().is_some() {
2900         let mut message = "Deprecated";
2901         if let Some(ref stab) = item.stability {
2902             if let Some(ref depr) = stab.deprecation {
2903                 if let Some(ref since) = depr.since {
2904                     if !stability::deprecation_in_effect(&since) {
2905                         message = "Deprecation planned";
2906                     }
2907                 }
2908             }
2909         }
2910         tags += &tag_html("deprecated", message);
2911     }
2912
2913     if let Some(stab) = item
2914         .stability
2915         .as_ref()
2916         .filter(|s| s.level == stability::Unstable)
2917     {
2918         if stab.feature.as_ref().map(|s| &**s) == Some("rustc_private") {
2919             tags += &tag_html("internal", "Internal");
2920         } else {
2921             tags += &tag_html("unstable", "Experimental");
2922         }
2923     }
2924
2925     if let Some(ref cfg) = item.attrs.cfg {
2926         tags += &tag_html("portability", &cfg.render_short_html());
2927     }
2928
2929     tags
2930 }
2931
2932 /// Render the stability and/or deprecation warning that is displayed at the top of the item's
2933 /// documentation.
2934 fn short_stability(item: &clean::Item, cx: &Context) -> Vec<String> {
2935     let mut stability = vec![];
2936     let error_codes = ErrorCodes::from(UnstableFeatures::from_environment().is_nightly_build());
2937
2938     if let Some(Deprecation { note, since }) = &item.deprecation() {
2939         // We display deprecation messages for #[deprecated] and #[rustc_deprecated]
2940         // but only display the future-deprecation messages for #[rustc_deprecated].
2941         let mut message = if let Some(since) = since {
2942             format!("Deprecated since {}", Escape(since))
2943         } else {
2944             String::from("Deprecated")
2945         };
2946         if let Some(ref stab) = item.stability {
2947             if let Some(ref depr) = stab.deprecation {
2948                 if let Some(ref since) = depr.since {
2949                     if !stability::deprecation_in_effect(&since) {
2950                         message = format!("Deprecating in {}", Escape(&since));
2951                     }
2952                 }
2953             }
2954         }
2955
2956         if let Some(note) = note {
2957             let mut ids = cx.id_map.borrow_mut();
2958             let html = MarkdownHtml(&note, RefCell::new(&mut ids), error_codes, cx.edition);
2959             message.push_str(&format!(": {}", html));
2960         }
2961         stability.push(format!("<div class='stab deprecated'>{}</div>", message));
2962     }
2963
2964     if let Some(stab) = item
2965         .stability
2966         .as_ref()
2967         .filter(|stab| stab.level == stability::Unstable)
2968     {
2969         let is_rustc_private = stab.feature.as_ref().map(|s| &**s) == Some("rustc_private");
2970
2971         let mut message = if is_rustc_private {
2972             "<span class='emoji'>⚙️</span> This is an internal compiler API."
2973         } else {
2974             "<span class='emoji'>🔬</span> This is a nightly-only experimental API."
2975         }
2976         .to_owned();
2977
2978         if let Some(feature) = stab.feature.as_ref() {
2979             let mut feature = format!("<code>{}</code>", Escape(&feature));
2980             if let (Some(url), Some(issue)) = (&cx.shared.issue_tracker_base_url, stab.issue) {
2981                 feature.push_str(&format!(
2982                     "&nbsp;<a href=\"{url}{issue}\">#{issue}</a>",
2983                     url = url,
2984                     issue = issue
2985                 ));
2986             }
2987
2988             message.push_str(&format!(" ({})", feature));
2989         }
2990
2991         if let Some(unstable_reason) = &stab.unstable_reason {
2992             // Provide a more informative message than the compiler help.
2993             let unstable_reason = if is_rustc_private {
2994                 "This crate is being loaded from the sysroot, a permanently unstable location \
2995                 for private compiler dependencies. It is not intended for general use. Prefer \
2996                 using a public version of this crate from \
2997                 [crates.io](https://crates.io) via [`Cargo.toml`]\
2998                 (https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html)."
2999             } else {
3000                 unstable_reason
3001             };
3002
3003             let mut ids = cx.id_map.borrow_mut();
3004             message = format!(
3005                 "<details><summary>{}</summary>{}</details>",
3006                 message,
3007                 MarkdownHtml(&unstable_reason, RefCell::new(&mut ids), error_codes, cx.edition)
3008             );
3009         }
3010
3011         let class = if is_rustc_private {
3012             "internal"
3013         } else {
3014             "unstable"
3015         };
3016         stability.push(format!("<div class='stab {}'>{}</div>", class, message));
3017     }
3018
3019     if let Some(ref cfg) = item.attrs.cfg {
3020         stability.push(format!(
3021             "<div class='stab portability'>{}</div>",
3022             cfg.render_long_html()
3023         ));
3024     }
3025
3026     stability
3027 }
3028
3029 fn item_constant(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item,
3030                  c: &clean::Constant) -> fmt::Result {
3031     write!(w, "<pre class='rust const'>")?;
3032     render_attributes(w, it, false)?;
3033     write!(w, "{vis}const \
3034                {name}: {typ}</pre>",
3035            vis = VisSpace(&it.visibility),
3036            name = it.name.as_ref().unwrap(),
3037            typ = c.type_)?;
3038     document(w, cx, it)
3039 }
3040
3041 fn item_static(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item,
3042                s: &clean::Static) -> fmt::Result {
3043     write!(w, "<pre class='rust static'>")?;
3044     render_attributes(w, it, false)?;
3045     write!(w, "{vis}static {mutability}\
3046                {name}: {typ}</pre>",
3047            vis = VisSpace(&it.visibility),
3048            mutability = MutableSpace(s.mutability),
3049            name = it.name.as_ref().unwrap(),
3050            typ = s.type_)?;
3051     document(w, cx, it)
3052 }
3053
3054 fn item_function(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item,
3055                  f: &clean::Function) -> fmt::Result {
3056     let header_len = format!(
3057         "{}{}{}{}{:#}fn {}{:#}",
3058         VisSpace(&it.visibility),
3059         ConstnessSpace(f.header.constness),
3060         UnsafetySpace(f.header.unsafety),
3061         AsyncSpace(f.header.asyncness),
3062         AbiSpace(f.header.abi),
3063         it.name.as_ref().unwrap(),
3064         f.generics
3065     ).len();
3066     write!(w, "{}<pre class='rust fn'>", render_spotlight_traits(it)?)?;
3067     render_attributes(w, it, false)?;
3068     write!(w,
3069            "{vis}{constness}{unsafety}{asyncness}{abi}fn \
3070            {name}{generics}{decl}{where_clause}</pre>",
3071            vis = VisSpace(&it.visibility),
3072            constness = ConstnessSpace(f.header.constness),
3073            unsafety = UnsafetySpace(f.header.unsafety),
3074            asyncness = AsyncSpace(f.header.asyncness),
3075            abi = AbiSpace(f.header.abi),
3076            name = it.name.as_ref().unwrap(),
3077            generics = f.generics,
3078            where_clause = WhereClause { gens: &f.generics, indent: 0, end_newline: true },
3079            decl = Function {
3080               decl: &f.decl,
3081               header_len,
3082               indent: 0,
3083               asyncness: f.header.asyncness,
3084            })?;
3085     document(w, cx, it)
3086 }
3087
3088 fn render_implementor(cx: &Context, implementor: &Impl, w: &mut fmt::Formatter<'_>,
3089                       implementor_dups: &FxHashMap<&str, (DefId, bool)>) -> fmt::Result {
3090     // If there's already another implementor that has the same abbridged name, use the
3091     // full path, for example in `std::iter::ExactSizeIterator`
3092     let use_absolute = match implementor.inner_impl().for_ {
3093         clean::ResolvedPath { ref path, is_generic: false, .. } |
3094         clean::BorrowedRef {
3095             type_: box clean::ResolvedPath { ref path, is_generic: false, .. },
3096             ..
3097         } => implementor_dups[path.last_name()].1,
3098         _ => false,
3099     };
3100     render_impl(w, cx, implementor, AssocItemLink::Anchor(None), RenderMode::Normal,
3101                 implementor.impl_item.stable_since(), false, Some(use_absolute), false, false)?;
3102     Ok(())
3103 }
3104
3105 fn render_impls(cx: &Context, w: &mut fmt::Formatter<'_>,
3106                 traits: &[&&Impl],
3107                 containing_item: &clean::Item) -> fmt::Result {
3108     for i in traits {
3109         let did = i.trait_did().unwrap();
3110         let assoc_link = AssocItemLink::GotoSource(did, &i.inner_impl().provided_trait_methods);
3111         render_impl(w, cx, i, assoc_link,
3112                     RenderMode::Normal, containing_item.stable_since(), true, None, false, true)?;
3113     }
3114     Ok(())
3115 }
3116
3117 fn bounds(t_bounds: &[clean::GenericBound], trait_alias: bool) -> String {
3118     let mut bounds = String::new();
3119     if !t_bounds.is_empty() {
3120         if !trait_alias {
3121             bounds.push_str(": ");
3122         }
3123         for (i, p) in t_bounds.iter().enumerate() {
3124             if i > 0 {
3125                 bounds.push_str(" + ");
3126             }
3127             bounds.push_str(&(*p).to_string());
3128         }
3129     }
3130     bounds
3131 }
3132
3133 fn compare_impl<'a, 'b>(lhs: &'a &&Impl, rhs: &'b &&Impl) -> Ordering {
3134     let lhs = format!("{}", lhs.inner_impl());
3135     let rhs = format!("{}", rhs.inner_impl());
3136
3137     // lhs and rhs are formatted as HTML, which may be unnecessary
3138     name_key(&lhs).cmp(&name_key(&rhs))
3139 }
3140
3141 fn item_trait(
3142     w: &mut fmt::Formatter<'_>,
3143     cx: &Context,
3144     it: &clean::Item,
3145     t: &clean::Trait,
3146 ) -> fmt::Result {
3147     let bounds = bounds(&t.bounds, false);
3148     let types = t.items.iter().filter(|m| m.is_associated_type()).collect::<Vec<_>>();
3149     let consts = t.items.iter().filter(|m| m.is_associated_const()).collect::<Vec<_>>();
3150     let required = t.items.iter().filter(|m| m.is_ty_method()).collect::<Vec<_>>();
3151     let provided = t.items.iter().filter(|m| m.is_method()).collect::<Vec<_>>();
3152
3153     // Output the trait definition
3154     wrap_into_docblock(w, |w| {
3155         write!(w, "<pre class='rust trait'>")?;
3156         render_attributes(w, it, true)?;
3157         write!(w, "{}{}{}trait {}{}{}",
3158                VisSpace(&it.visibility),
3159                UnsafetySpace(t.unsafety),
3160                if t.is_auto { "auto " } else { "" },
3161                it.name.as_ref().unwrap(),
3162                t.generics,
3163                bounds)?;
3164
3165         if !t.generics.where_predicates.is_empty() {
3166             write!(w, "{}", WhereClause { gens: &t.generics, indent: 0, end_newline: true })?;
3167         } else {
3168             write!(w, " ")?;
3169         }
3170
3171         if t.items.is_empty() {
3172             write!(w, "{{ }}")?;
3173         } else {
3174             // FIXME: we should be using a derived_id for the Anchors here
3175             write!(w, "{{\n")?;
3176             for t in &types {
3177                 render_assoc_item(w, t, AssocItemLink::Anchor(None), ItemType::Trait)?;
3178                 write!(w, ";\n")?;
3179             }
3180             if !types.is_empty() && !consts.is_empty() {
3181                 w.write_str("\n")?;
3182             }
3183             for t in &consts {
3184                 render_assoc_item(w, t, AssocItemLink::Anchor(None), ItemType::Trait)?;
3185                 write!(w, ";\n")?;
3186             }
3187             if !consts.is_empty() && !required.is_empty() {
3188                 w.write_str("\n")?;
3189             }
3190             for (pos, m) in required.iter().enumerate() {
3191                 render_assoc_item(w, m, AssocItemLink::Anchor(None), ItemType::Trait)?;
3192                 write!(w, ";\n")?;
3193
3194                 if pos < required.len() - 1 {
3195                    write!(w, "<div class='item-spacer'></div>")?;
3196                 }
3197             }
3198             if !required.is_empty() && !provided.is_empty() {
3199                 w.write_str("\n")?;
3200             }
3201             for (pos, m) in provided.iter().enumerate() {
3202                 render_assoc_item(w, m, AssocItemLink::Anchor(None), ItemType::Trait)?;
3203                 match m.inner {
3204                     clean::MethodItem(ref inner) if !inner.generics.where_predicates.is_empty() => {
3205                         write!(w, ",\n    {{ ... }}\n")?;
3206                     },
3207                     _ => {
3208                         write!(w, " {{ ... }}\n")?;
3209                     },
3210                 }
3211                 if pos < provided.len() - 1 {
3212                    write!(w, "<div class='item-spacer'></div>")?;
3213                 }
3214             }
3215             write!(w, "}}")?;
3216         }
3217         write!(w, "</pre>")
3218     })?;
3219
3220     // Trait documentation
3221     document(w, cx, it)?;
3222
3223     fn write_small_section_header(
3224         w: &mut fmt::Formatter<'_>,
3225         id: &str,
3226         title: &str,
3227         extra_content: &str,
3228     ) -> fmt::Result {
3229         write!(w, "
3230             <h2 id='{0}' class='small-section-header'>\
3231               {1}<a href='#{0}' class='anchor'></a>\
3232             </h2>{2}", id, title, extra_content)
3233     }
3234
3235     fn write_loading_content(w: &mut fmt::Formatter<'_>, extra_content: &str) -> fmt::Result {
3236         write!(w, "{}<span class='loading-content'>Loading content...</span>", extra_content)
3237     }
3238
3239     fn trait_item(w: &mut fmt::Formatter<'_>, cx: &Context, m: &clean::Item, t: &clean::Item)
3240                   -> fmt::Result {
3241         let name = m.name.as_ref().unwrap();
3242         let item_type = m.type_();
3243         let id = cx.derive_id(format!("{}.{}", item_type, name));
3244         let ns_id = cx.derive_id(format!("{}.{}", name, item_type.name_space()));
3245         write!(w, "<h3 id='{id}' class='method'>{extra}<code id='{ns_id}'>",
3246                extra = render_spotlight_traits(m)?,
3247                id = id,
3248                ns_id = ns_id)?;
3249         render_assoc_item(w, m, AssocItemLink::Anchor(Some(&id)), ItemType::Impl)?;
3250         write!(w, "</code>")?;
3251         render_stability_since(w, m, t)?;
3252         write!(w, "</h3>")?;
3253         document(w, cx, m)?;
3254         Ok(())
3255     }
3256
3257     if !types.is_empty() {
3258         write_small_section_header(w, "associated-types", "Associated Types",
3259                                    "<div class='methods'>")?;
3260         for t in &types {
3261             trait_item(w, cx, *t, it)?;
3262         }
3263         write_loading_content(w, "</div>")?;
3264     }
3265
3266     if !consts.is_empty() {
3267         write_small_section_header(w, "associated-const", "Associated Constants",
3268                                    "<div class='methods'>")?;
3269         for t in &consts {
3270             trait_item(w, cx, *t, it)?;
3271         }
3272         write_loading_content(w, "</div>")?;
3273     }
3274
3275     // Output the documentation for each function individually
3276     if !required.is_empty() {
3277         write_small_section_header(w, "required-methods", "Required methods",
3278                                    "<div class='methods'>")?;
3279         for m in &required {
3280             trait_item(w, cx, *m, it)?;
3281         }
3282         write_loading_content(w, "</div>")?;
3283     }
3284     if !provided.is_empty() {
3285         write_small_section_header(w, "provided-methods", "Provided methods",
3286                                    "<div class='methods'>")?;
3287         for m in &provided {
3288             trait_item(w, cx, *m, it)?;
3289         }
3290         write_loading_content(w, "</div>")?;
3291     }
3292
3293     // If there are methods directly on this trait object, render them here.
3294     render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)?;
3295
3296     let cache = cache();
3297
3298     let mut synthetic_types = Vec::new();
3299
3300     if let Some(implementors) = cache.implementors.get(&it.def_id) {
3301         // The DefId is for the first Type found with that name. The bool is
3302         // if any Types with the same name but different DefId have been found.
3303         let mut implementor_dups: FxHashMap<&str, (DefId, bool)> = FxHashMap::default();
3304         for implementor in implementors {
3305             match implementor.inner_impl().for_ {
3306                 clean::ResolvedPath { ref path, did, is_generic: false, .. } |
3307                 clean::BorrowedRef {
3308                     type_: box clean::ResolvedPath { ref path, did, is_generic: false, .. },
3309                     ..
3310                 } => {
3311                     let &mut (prev_did, ref mut has_duplicates) =
3312                         implementor_dups.entry(path.last_name()).or_insert((did, false));
3313                     if prev_did != did {
3314                         *has_duplicates = true;
3315                     }
3316                 }
3317                 _ => {}
3318             }
3319         }
3320
3321         let (local, foreign) = implementors.iter()
3322             .partition::<Vec<_>, _>(|i| i.inner_impl().for_.def_id()
3323                                          .map_or(true, |d| cache.paths.contains_key(&d)));
3324
3325
3326         let (mut synthetic, mut concrete): (Vec<&&Impl>, Vec<&&Impl>) = local.iter()
3327             .partition(|i| i.inner_impl().synthetic);
3328
3329         synthetic.sort_by(compare_impl);
3330         concrete.sort_by(compare_impl);
3331
3332         if !foreign.is_empty() {
3333             write_small_section_header(w, "foreign-impls", "Implementations on Foreign Types", "")?;
3334
3335             for implementor in foreign {
3336                 let assoc_link = AssocItemLink::GotoSource(
3337                     implementor.impl_item.def_id,
3338                     &implementor.inner_impl().provided_trait_methods
3339                 );
3340                 render_impl(w, cx, &implementor, assoc_link,
3341                             RenderMode::Normal, implementor.impl_item.stable_since(), false,
3342                             None, true, false)?;
3343             }
3344             write_loading_content(w, "")?;
3345         }
3346
3347         write_small_section_header(w, "implementors", "Implementors",
3348                                    "<div class='item-list' id='implementors-list'>")?;
3349         for implementor in concrete {
3350             render_implementor(cx, implementor, w, &implementor_dups)?;
3351         }
3352         write_loading_content(w, "</div>")?;
3353
3354         if t.auto {
3355             write_small_section_header(w, "synthetic-implementors", "Auto implementors",
3356                                        "<div class='item-list' id='synthetic-implementors-list'>")?;
3357             for implementor in synthetic {
3358                 synthetic_types.extend(
3359                     collect_paths_for_type(implementor.inner_impl().for_.clone())
3360                 );
3361                 render_implementor(cx, implementor, w, &implementor_dups)?;
3362             }
3363             write_loading_content(w, "</div>")?;
3364         }
3365     } else {
3366         // even without any implementations to write in, we still want the heading and list, so the
3367         // implementors javascript file pulled in below has somewhere to write the impls into
3368         write_small_section_header(w, "implementors", "Implementors",
3369                                    "<div class='item-list' id='implementors-list'>")?;
3370         write_loading_content(w, "</div>")?;
3371
3372         if t.auto {
3373             write_small_section_header(w, "synthetic-implementors", "Auto implementors",
3374                                        "<div class='item-list' id='synthetic-implementors-list'>")?;
3375             write_loading_content(w, "</div>")?;
3376         }
3377     }
3378     write!(w, r#"<script type="text/javascript">window.inlined_types=new Set({});</script>"#,
3379            as_json(&synthetic_types))?;
3380
3381     write!(w, r#"<script type="text/javascript" async
3382                          src="{root_path}/implementors/{path}/{ty}.{name}.js">
3383                  </script>"#,
3384            root_path = vec![".."; cx.current.len()].join("/"),
3385            path = if it.def_id.is_local() {
3386                cx.current.join("/")
3387            } else {
3388                let (ref path, _) = cache.external_paths[&it.def_id];
3389                path[..path.len() - 1].join("/")
3390            },
3391            ty = it.type_().css_class(),
3392            name = *it.name.as_ref().unwrap())?;
3393     Ok(())
3394 }
3395
3396 fn naive_assoc_href(it: &clean::Item, link: AssocItemLink<'_>) -> String {
3397     use crate::html::item_type::ItemType::*;
3398
3399     let name = it.name.as_ref().unwrap();
3400     let ty = match it.type_() {
3401         Typedef | AssocType => AssocType,
3402         s@_ => s,
3403     };
3404
3405     let anchor = format!("#{}.{}", ty, name);
3406     match link {
3407         AssocItemLink::Anchor(Some(ref id)) => format!("#{}", id),
3408         AssocItemLink::Anchor(None) => anchor,
3409         AssocItemLink::GotoSource(did, _) => {
3410             href(did).map(|p| format!("{}{}", p.0, anchor)).unwrap_or(anchor)
3411         }
3412     }
3413 }
3414
3415 fn assoc_const(w: &mut fmt::Formatter<'_>,
3416                it: &clean::Item,
3417                ty: &clean::Type,
3418                _default: Option<&String>,
3419                link: AssocItemLink<'_>,
3420                extra: &str) -> fmt::Result {
3421     write!(w, "{}{}const <a href='{}' class=\"constant\"><b>{}</b></a>: {}",
3422            extra,
3423            VisSpace(&it.visibility),
3424            naive_assoc_href(it, link),
3425            it.name.as_ref().unwrap(),
3426            ty)?;
3427     Ok(())
3428 }
3429
3430 fn assoc_type<W: fmt::Write>(w: &mut W, it: &clean::Item,
3431                              bounds: &[clean::GenericBound],
3432                              default: Option<&clean::Type>,
3433                              link: AssocItemLink<'_>,
3434                              extra: &str) -> fmt::Result {
3435     write!(w, "{}type <a href='{}' class=\"type\">{}</a>",
3436            extra,
3437            naive_assoc_href(it, link),
3438            it.name.as_ref().unwrap())?;
3439     if !bounds.is_empty() {
3440         write!(w, ": {}", GenericBounds(bounds))?
3441     }
3442     if let Some(default) = default {
3443         write!(w, " = {}", default)?;
3444     }
3445     Ok(())
3446 }
3447
3448 fn render_stability_since_raw<'a, T: fmt::Write>(
3449     w: &mut T,
3450     ver: Option<&'a str>,
3451     containing_ver: Option<&'a str>,
3452 ) -> fmt::Result {
3453     if let Some(v) = ver {
3454         if containing_ver != ver && v.len() > 0 {
3455             write!(w, "<span class='since' title='Stable since Rust version {0}'>{0}</span>", v)?
3456         }
3457     }
3458     Ok(())
3459 }
3460
3461 fn render_stability_since(w: &mut fmt::Formatter<'_>,
3462                           item: &clean::Item,
3463                           containing_item: &clean::Item) -> fmt::Result {
3464     render_stability_since_raw(w, item.stable_since(), containing_item.stable_since())
3465 }
3466
3467 fn render_assoc_item(w: &mut fmt::Formatter<'_>,
3468                      item: &clean::Item,
3469                      link: AssocItemLink<'_>,
3470                      parent: ItemType) -> fmt::Result {
3471     fn method(w: &mut fmt::Formatter<'_>,
3472               meth: &clean::Item,
3473               header: hir::FnHeader,
3474               g: &clean::Generics,
3475               d: &clean::FnDecl,
3476               link: AssocItemLink<'_>,
3477               parent: ItemType)
3478               -> fmt::Result {
3479         let name = meth.name.as_ref().unwrap();
3480         let anchor = format!("#{}.{}", meth.type_(), name);
3481         let href = match link {
3482             AssocItemLink::Anchor(Some(ref id)) => format!("#{}", id),
3483             AssocItemLink::Anchor(None) => anchor,
3484             AssocItemLink::GotoSource(did, provided_methods) => {
3485                 // We're creating a link from an impl-item to the corresponding
3486                 // trait-item and need to map the anchored type accordingly.
3487                 let ty = if provided_methods.contains(name) {
3488                     ItemType::Method
3489                 } else {
3490                     ItemType::TyMethod
3491                 };
3492
3493                 href(did).map(|p| format!("{}#{}.{}", p.0, ty, name)).unwrap_or(anchor)
3494             }
3495         };
3496         let mut header_len = format!(
3497             "{}{}{}{}{}{:#}fn {}{:#}",
3498             VisSpace(&meth.visibility),
3499             ConstnessSpace(header.constness),
3500             UnsafetySpace(header.unsafety),
3501             AsyncSpace(header.asyncness),
3502             DefaultSpace(meth.is_default()),
3503             AbiSpace(header.abi),
3504             name,
3505             *g
3506         ).len();
3507         let (indent, end_newline) = if parent == ItemType::Trait {
3508             header_len += 4;
3509             (4, false)
3510         } else {
3511             (0, true)
3512         };
3513         render_attributes(w, meth, false)?;
3514         write!(w, "{}{}{}{}{}{}{}fn <a href='{href}' class='fnname'>{name}</a>\
3515                    {generics}{decl}{where_clause}",
3516                if parent == ItemType::Trait { "    " } else { "" },
3517                VisSpace(&meth.visibility),
3518                ConstnessSpace(header.constness),
3519                UnsafetySpace(header.unsafety),
3520                AsyncSpace(header.asyncness),
3521                DefaultSpace(meth.is_default()),
3522                AbiSpace(header.abi),
3523                href = href,
3524                name = name,
3525                generics = *g,
3526                decl = Function {
3527                    decl: d,
3528                    header_len,
3529                    indent,
3530                    asyncness: header.asyncness,
3531                },
3532                where_clause = WhereClause {
3533                    gens: g,
3534                    indent,
3535                    end_newline,
3536                })
3537     }
3538     match item.inner {
3539         clean::StrippedItem(..) => Ok(()),
3540         clean::TyMethodItem(ref m) => {
3541             method(w, item, m.header, &m.generics, &m.decl, link, parent)
3542         }
3543         clean::MethodItem(ref m) => {
3544             method(w, item, m.header, &m.generics, &m.decl, link, parent)
3545         }
3546         clean::AssocConstItem(ref ty, ref default) => {
3547             assoc_const(w, item, ty, default.as_ref(), link,
3548                         if parent == ItemType::Trait { "    " } else { "" })
3549         }
3550         clean::AssocTypeItem(ref bounds, ref default) => {
3551             assoc_type(w, item, bounds, default.as_ref(), link,
3552                        if parent == ItemType::Trait { "    " } else { "" })
3553         }
3554         _ => panic!("render_assoc_item called on non-associated-item")
3555     }
3556 }
3557
3558 fn item_struct(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item,
3559                s: &clean::Struct) -> fmt::Result {
3560     wrap_into_docblock(w, |w| {
3561         write!(w, "<pre class='rust struct'>")?;
3562         render_attributes(w, it, true)?;
3563         render_struct(w,
3564                       it,
3565                       Some(&s.generics),
3566                       s.struct_type,
3567                       &s.fields,
3568                       "",
3569                       true)?;
3570         write!(w, "</pre>")
3571     })?;
3572
3573     document(w, cx, it)?;
3574     let mut fields = s.fields.iter().filter_map(|f| {
3575         match f.inner {
3576             clean::StructFieldItem(ref ty) => Some((f, ty)),
3577             _ => None,
3578         }
3579     }).peekable();
3580     if let doctree::Plain = s.struct_type {
3581         if fields.peek().is_some() {
3582             write!(w, "<h2 id='fields' class='fields small-section-header'>
3583                        Fields{}<a href='#fields' class='anchor'></a></h2>",
3584                        document_non_exhaustive_header(it))?;
3585             document_non_exhaustive(w, it)?;
3586             for (field, ty) in fields {
3587                 let id = cx.derive_id(format!("{}.{}",
3588                                            ItemType::StructField,
3589                                            field.name.as_ref().unwrap()));
3590                 let ns_id = cx.derive_id(format!("{}.{}",
3591                                               field.name.as_ref().unwrap(),
3592                                               ItemType::StructField.name_space()));
3593                 write!(w, "<span id=\"{id}\" class=\"{item_type} small-section-header\">\
3594                            <a href=\"#{id}\" class=\"anchor field\"></a>\
3595                            <code id=\"{ns_id}\">{name}: {ty}</code>\
3596                            </span>",
3597                        item_type = ItemType::StructField,
3598                        id = id,
3599                        ns_id = ns_id,
3600                        name = field.name.as_ref().unwrap(),
3601                        ty = ty)?;
3602                 document(w, cx, field)?;
3603             }
3604         }
3605     }
3606     render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)
3607 }
3608
3609 fn item_union(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item,
3610                s: &clean::Union) -> fmt::Result {
3611     wrap_into_docblock(w, |w| {
3612         write!(w, "<pre class='rust union'>")?;
3613         render_attributes(w, it, true)?;
3614         render_union(w,
3615                      it,
3616                      Some(&s.generics),
3617                      &s.fields,
3618                      "",
3619                      true)?;
3620         write!(w, "</pre>")
3621     })?;
3622
3623     document(w, cx, it)?;
3624     let mut fields = s.fields.iter().filter_map(|f| {
3625         match f.inner {
3626             clean::StructFieldItem(ref ty) => Some((f, ty)),
3627             _ => None,
3628         }
3629     }).peekable();
3630     if fields.peek().is_some() {
3631         write!(w, "<h2 id='fields' class='fields small-section-header'>
3632                    Fields<a href='#fields' class='anchor'></a></h2>")?;
3633         for (field, ty) in fields {
3634             let name = field.name.as_ref().expect("union field name");
3635             let id = format!("{}.{}", ItemType::StructField, name);
3636             write!(w, "<span id=\"{id}\" class=\"{shortty} small-section-header\">\
3637                            <a href=\"#{id}\" class=\"anchor field\"></a>\
3638                            <code>{name}: {ty}</code>\
3639                        </span>",
3640                    id = id,
3641                    name = name,
3642                    shortty = ItemType::StructField,
3643                    ty = ty)?;
3644             if let Some(stability_class) = field.stability_class() {
3645                 write!(w, "<span class='stab {stab}'></span>",
3646                     stab = stability_class)?;
3647             }
3648             document(w, cx, field)?;
3649         }
3650     }
3651     render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)
3652 }
3653
3654 fn item_enum(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item,
3655              e: &clean::Enum) -> fmt::Result {
3656     wrap_into_docblock(w, |w| {
3657         write!(w, "<pre class='rust enum'>")?;
3658         render_attributes(w, it, true)?;
3659         write!(w, "{}enum {}{}{}",
3660                VisSpace(&it.visibility),
3661                it.name.as_ref().unwrap(),
3662                e.generics,
3663                WhereClause { gens: &e.generics, indent: 0, end_newline: true })?;
3664         if e.variants.is_empty() && !e.variants_stripped {
3665             write!(w, " {{}}")?;
3666         } else {
3667             write!(w, " {{\n")?;
3668             for v in &e.variants {
3669                 write!(w, "    ")?;
3670                 let name = v.name.as_ref().unwrap();
3671                 match v.inner {
3672                     clean::VariantItem(ref var) => {
3673                         match var.kind {
3674                             clean::VariantKind::CLike => write!(w, "{}", name)?,
3675                             clean::VariantKind::Tuple(ref tys) => {
3676                                 write!(w, "{}(", name)?;
3677                                 for (i, ty) in tys.iter().enumerate() {
3678                                     if i > 0 {
3679                                         write!(w, ",&nbsp;")?
3680                                     }
3681                                     write!(w, "{}", *ty)?;
3682                                 }
3683                                 write!(w, ")")?;
3684                             }
3685                             clean::VariantKind::Struct(ref s) => {
3686                                 render_struct(w,
3687                                               v,
3688                                               None,
3689                                               s.struct_type,
3690                                               &s.fields,
3691                                               "    ",
3692                                               false)?;
3693                             }
3694                         }
3695                     }
3696                     _ => unreachable!()
3697                 }
3698                 write!(w, ",\n")?;
3699             }
3700
3701             if e.variants_stripped {
3702                 write!(w, "    // some variants omitted\n")?;
3703             }
3704             write!(w, "}}")?;
3705         }
3706         write!(w, "</pre>")
3707     })?;
3708
3709     document(w, cx, it)?;
3710     if !e.variants.is_empty() {
3711         write!(w, "<h2 id='variants' class='variants small-section-header'>
3712                    Variants{}<a href='#variants' class='anchor'></a></h2>\n",
3713                    document_non_exhaustive_header(it))?;
3714         document_non_exhaustive(w, it)?;
3715         for variant in &e.variants {
3716             let id = cx.derive_id(format!("{}.{}",
3717                                        ItemType::Variant,
3718                                        variant.name.as_ref().unwrap()));
3719             let ns_id = cx.derive_id(format!("{}.{}",
3720                                           variant.name.as_ref().unwrap(),
3721                                           ItemType::Variant.name_space()));
3722             write!(w, "<span id=\"{id}\" class=\"variant small-section-header\">\
3723                        <a href=\"#{id}\" class=\"anchor field\"></a>\
3724                        <code id='{ns_id}'>{name}",
3725                    id = id,
3726                    ns_id = ns_id,
3727                    name = variant.name.as_ref().unwrap())?;
3728             if let clean::VariantItem(ref var) = variant.inner {
3729                 if let clean::VariantKind::Tuple(ref tys) = var.kind {
3730                     write!(w, "(")?;
3731                     for (i, ty) in tys.iter().enumerate() {
3732                         if i > 0 {
3733                             write!(w, ",&nbsp;")?;
3734                         }
3735                         write!(w, "{}", *ty)?;
3736                     }
3737                     write!(w, ")")?;
3738                 }
3739             }
3740             write!(w, "</code></span>")?;
3741             document(w, cx, variant)?;
3742             document_non_exhaustive(w, variant)?;
3743
3744             use crate::clean::{Variant, VariantKind};
3745             if let clean::VariantItem(Variant {
3746                 kind: VariantKind::Struct(ref s)
3747             }) = variant.inner {
3748                 let variant_id = cx.derive_id(format!("{}.{}.fields",
3749                                                    ItemType::Variant,
3750                                                    variant.name.as_ref().unwrap()));
3751                 write!(w, "<span class='autohide sub-variant' id='{id}'>",
3752                        id = variant_id)?;
3753                 write!(w, "<h3>Fields of <b>{name}</b></h3><div>",
3754                        name = variant.name.as_ref().unwrap())?;
3755                 for field in &s.fields {
3756                     use crate::clean::StructFieldItem;
3757                     if let StructFieldItem(ref ty) = field.inner {
3758                         let id = cx.derive_id(format!("variant.{}.field.{}",
3759                                                    variant.name.as_ref().unwrap(),
3760                                                    field.name.as_ref().unwrap()));
3761                         let ns_id = cx.derive_id(format!("{}.{}.{}.{}",
3762                                                       variant.name.as_ref().unwrap(),
3763                                                       ItemType::Variant.name_space(),
3764                                                       field.name.as_ref().unwrap(),
3765                                                       ItemType::StructField.name_space()));
3766                         write!(w, "<span id=\"{id}\" class=\"variant small-section-header\">\
3767                                    <a href=\"#{id}\" class=\"anchor field\"></a>\
3768                                    <code id='{ns_id}'>{f}:&nbsp;{t}\
3769                                    </code></span>",
3770                                id = id,
3771                                ns_id = ns_id,
3772                                f = field.name.as_ref().unwrap(),
3773                                t = *ty)?;
3774                         document(w, cx, field)?;
3775                     }
3776                 }
3777                 write!(w, "</div></span>")?;
3778             }
3779             render_stability_since(w, variant, it)?;
3780         }
3781     }
3782     render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)?;
3783     Ok(())
3784 }
3785
3786 fn render_attribute(attr: &ast::MetaItem) -> Option<String> {
3787     let path = attr.path.to_string();
3788
3789     if attr.is_word() {
3790         Some(path)
3791     } else if let Some(v) = attr.value_str() {
3792         Some(format!("{} = {:?}", path, v.as_str()))
3793     } else if let Some(values) = attr.meta_item_list() {
3794         let display: Vec<_> = values.iter().filter_map(|attr| {
3795             attr.meta_item().and_then(|mi| render_attribute(mi))
3796         }).collect();
3797
3798         if display.len() > 0 {
3799             Some(format!("{}({})", path, display.join(", ")))
3800         } else {
3801             None
3802         }
3803     } else {
3804         None
3805     }
3806 }
3807
3808 const ATTRIBUTE_WHITELIST: &'static [Symbol] = &[
3809     sym::export_name,
3810     sym::lang,
3811     sym::link_section,
3812     sym::must_use,
3813     sym::no_mangle,
3814     sym::repr,
3815     sym::non_exhaustive
3816 ];
3817
3818 // The `top` parameter is used when generating the item declaration to ensure it doesn't have a
3819 // left padding. For example:
3820 //
3821 // #[foo] <----- "top" attribute
3822 // struct Foo {
3823 //     #[bar] <---- not "top" attribute
3824 //     bar: usize,
3825 // }
3826 fn render_attributes(w: &mut dyn fmt::Write, it: &clean::Item, top: bool) -> fmt::Result {
3827     let mut attrs = String::new();
3828
3829     for attr in &it.attrs.other_attrs {
3830         if !ATTRIBUTE_WHITELIST.contains(&attr.name_or_empty()) {
3831             continue;
3832         }
3833         if let Some(s) = render_attribute(&attr.meta().unwrap()) {
3834             attrs.push_str(&format!("#[{}]\n", s));
3835         }
3836     }
3837     if attrs.len() > 0 {
3838         write!(w, "<span class=\"docblock attributes{}\">{}</span>",
3839                if top { " top-attr" } else { "" }, &attrs)?;
3840     }
3841     Ok(())
3842 }
3843
3844 fn render_struct(w: &mut fmt::Formatter<'_>, it: &clean::Item,
3845                  g: Option<&clean::Generics>,
3846                  ty: doctree::StructType,
3847                  fields: &[clean::Item],
3848                  tab: &str,
3849                  structhead: bool) -> fmt::Result {
3850     write!(w, "{}{}{}",
3851            VisSpace(&it.visibility),
3852            if structhead {"struct "} else {""},
3853            it.name.as_ref().unwrap())?;
3854     if let Some(g) = g {
3855         write!(w, "{}", g)?
3856     }
3857     match ty {
3858         doctree::Plain => {
3859             if let Some(g) = g {
3860                 write!(w, "{}", WhereClause { gens: g, indent: 0, end_newline: true })?
3861             }
3862             let mut has_visible_fields = false;
3863             write!(w, " {{")?;
3864             for field in fields {
3865                 if let clean::StructFieldItem(ref ty) = field.inner {
3866                     write!(w, "\n{}    {}{}: {},",
3867                            tab,
3868                            VisSpace(&field.visibility),
3869                            field.name.as_ref().unwrap(),
3870                            *ty)?;
3871                     has_visible_fields = true;
3872                 }
3873             }
3874
3875             if has_visible_fields {
3876                 if it.has_stripped_fields().unwrap() {
3877                     write!(w, "\n{}    // some fields omitted", tab)?;
3878                 }
3879                 write!(w, "\n{}", tab)?;
3880             } else if it.has_stripped_fields().unwrap() {
3881                 // If there are no visible fields we can just display
3882                 // `{ /* fields omitted */ }` to save space.
3883                 write!(w, " /* fields omitted */ ")?;
3884             }
3885             write!(w, "}}")?;
3886         }
3887         doctree::Tuple => {
3888             write!(w, "(")?;
3889             for (i, field) in fields.iter().enumerate() {
3890                 if i > 0 {
3891                     write!(w, ", ")?;
3892                 }
3893                 match field.inner {
3894                     clean::StrippedItem(box clean::StructFieldItem(..)) => {
3895                         write!(w, "_")?
3896                     }
3897                     clean::StructFieldItem(ref ty) => {
3898                         write!(w, "{}{}", VisSpace(&field.visibility), *ty)?
3899                     }
3900                     _ => unreachable!()
3901                 }
3902             }
3903             write!(w, ")")?;
3904             if let Some(g) = g {
3905                 write!(w, "{}", WhereClause { gens: g, indent: 0, end_newline: false })?
3906             }
3907             write!(w, ";")?;
3908         }
3909         doctree::Unit => {
3910             // Needed for PhantomData.
3911             if let Some(g) = g {
3912                 write!(w, "{}", WhereClause { gens: g, indent: 0, end_newline: false })?
3913             }
3914             write!(w, ";")?;
3915         }
3916     }
3917     Ok(())
3918 }
3919
3920 fn render_union(w: &mut fmt::Formatter<'_>, it: &clean::Item,
3921                 g: Option<&clean::Generics>,
3922                 fields: &[clean::Item],
3923                 tab: &str,
3924                 structhead: bool) -> fmt::Result {
3925     write!(w, "{}{}{}",
3926            VisSpace(&it.visibility),
3927            if structhead {"union "} else {""},
3928            it.name.as_ref().unwrap())?;
3929     if let Some(g) = g {
3930         write!(w, "{}", g)?;
3931         write!(w, "{}", WhereClause { gens: g, indent: 0, end_newline: true })?;
3932     }
3933
3934     write!(w, " {{\n{}", tab)?;
3935     for field in fields {
3936         if let clean::StructFieldItem(ref ty) = field.inner {
3937             write!(w, "    {}{}: {},\n{}",
3938                    VisSpace(&field.visibility),
3939                    field.name.as_ref().unwrap(),
3940                    *ty,
3941                    tab)?;
3942         }
3943     }
3944
3945     if it.has_stripped_fields().unwrap() {
3946         write!(w, "    // some fields omitted\n{}", tab)?;
3947     }
3948     write!(w, "}}")?;
3949     Ok(())
3950 }
3951
3952 #[derive(Copy, Clone)]
3953 enum AssocItemLink<'a> {
3954     Anchor(Option<&'a str>),
3955     GotoSource(DefId, &'a FxHashSet<String>),
3956 }
3957
3958 impl<'a> AssocItemLink<'a> {
3959     fn anchor(&self, id: &'a String) -> Self {
3960         match *self {
3961             AssocItemLink::Anchor(_) => { AssocItemLink::Anchor(Some(&id)) },
3962             ref other => *other,
3963         }
3964     }
3965 }
3966
3967 enum AssocItemRender<'a> {
3968     All,
3969     DerefFor { trait_: &'a clean::Type, type_: &'a clean::Type, deref_mut_: bool }
3970 }
3971
3972 #[derive(Copy, Clone, PartialEq)]
3973 enum RenderMode {
3974     Normal,
3975     ForDeref { mut_: bool },
3976 }
3977
3978 fn render_assoc_items(w: &mut fmt::Formatter<'_>,
3979                       cx: &Context,
3980                       containing_item: &clean::Item,
3981                       it: DefId,
3982                       what: AssocItemRender<'_>) -> fmt::Result {
3983     let c = cache();
3984     let v = match c.impls.get(&it) {
3985         Some(v) => v,
3986         None => return Ok(()),
3987     };
3988     let (non_trait, traits): (Vec<_>, _) = v.iter().partition(|i| {
3989         i.inner_impl().trait_.is_none()
3990     });
3991     if !non_trait.is_empty() {
3992         let render_mode = match what {
3993             AssocItemRender::All => {
3994                 write!(w, "\
3995                     <h2 id='methods' class='small-section-header'>\
3996                       Methods<a href='#methods' class='anchor'></a>\
3997                     </h2>\
3998                 ")?;
3999                 RenderMode::Normal
4000             }
4001             AssocItemRender::DerefFor { trait_, type_, deref_mut_ } => {
4002                 write!(w, "\
4003                     <h2 id='deref-methods' class='small-section-header'>\
4004                       Methods from {}&lt;Target = {}&gt;\
4005                       <a href='#deref-methods' class='anchor'></a>\
4006                     </h2>\
4007                 ", trait_, type_)?;
4008                 RenderMode::ForDeref { mut_: deref_mut_ }
4009             }
4010         };
4011         for i in &non_trait {
4012             render_impl(w, cx, i, AssocItemLink::Anchor(None), render_mode,
4013                         containing_item.stable_since(), true, None, false, true)?;
4014         }
4015     }
4016     if let AssocItemRender::DerefFor { .. } = what {
4017         return Ok(());
4018     }
4019     if !traits.is_empty() {
4020         let deref_impl = traits.iter().find(|t| {
4021             t.inner_impl().trait_.def_id() == c.deref_trait_did
4022         });
4023         if let Some(impl_) = deref_impl {
4024             let has_deref_mut = traits.iter().find(|t| {
4025                 t.inner_impl().trait_.def_id() == c.deref_mut_trait_did
4026             }).is_some();
4027             render_deref_methods(w, cx, impl_, containing_item, has_deref_mut)?;
4028         }
4029
4030         let (synthetic, concrete): (Vec<&&Impl>, Vec<&&Impl>) = traits
4031             .iter()
4032             .partition(|t| t.inner_impl().synthetic);
4033         let (blanket_impl, concrete) = concrete
4034             .into_iter()
4035             .partition(|t| t.inner_impl().blanket_impl.is_some());
4036
4037         struct RendererStruct<'a, 'b, 'c>(&'a Context, Vec<&'b &'b Impl>, &'c clean::Item);
4038
4039         impl<'a, 'b, 'c> fmt::Display for RendererStruct<'a, 'b, 'c> {
4040             fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
4041                 render_impls(self.0, fmt, &self.1, self.2)
4042             }
4043         }
4044
4045         let impls = RendererStruct(cx, concrete, containing_item).to_string();
4046         if !impls.is_empty() {
4047             write!(w, "\
4048                 <h2 id='implementations' class='small-section-header'>\
4049                   Trait Implementations<a href='#implementations' class='anchor'></a>\
4050                 </h2>\
4051                 <div id='implementations-list'>{}</div>", impls)?;
4052         }
4053
4054         if !synthetic.is_empty() {
4055             write!(w, "\
4056                 <h2 id='synthetic-implementations' class='small-section-header'>\
4057                   Auto Trait Implementations\
4058                   <a href='#synthetic-implementations' class='anchor'></a>\
4059                 </h2>\
4060                 <div id='synthetic-implementations-list'>\
4061             ")?;
4062             render_impls(cx, w, &synthetic, containing_item)?;
4063             write!(w, "</div>")?;
4064         }
4065
4066         if !blanket_impl.is_empty() {
4067             write!(w, "\
4068                 <h2 id='blanket-implementations' class='small-section-header'>\
4069                   Blanket Implementations\
4070                   <a href='#blanket-implementations' class='anchor'></a>\
4071                 </h2>\
4072                 <div id='blanket-implementations-list'>\
4073             ")?;
4074             render_impls(cx, w, &blanket_impl, containing_item)?;
4075             write!(w, "</div>")?;
4076         }
4077     }
4078     Ok(())
4079 }
4080
4081 fn render_deref_methods(w: &mut fmt::Formatter<'_>, cx: &Context, impl_: &Impl,
4082                         container_item: &clean::Item, deref_mut: bool) -> fmt::Result {
4083     let deref_type = impl_.inner_impl().trait_.as_ref().unwrap();
4084     let target = impl_.inner_impl().items.iter().filter_map(|item| {
4085         match item.inner {
4086             clean::TypedefItem(ref t, true) => Some(&t.type_),
4087             _ => None,
4088         }
4089     }).next().expect("Expected associated type binding");
4090     let what = AssocItemRender::DerefFor { trait_: deref_type, type_: target,
4091                                            deref_mut_: deref_mut };
4092     if let Some(did) = target.def_id() {
4093         render_assoc_items(w, cx, container_item, did, what)
4094     } else {
4095         if let Some(prim) = target.primitive_type() {
4096             if let Some(&did) = cache().primitive_locations.get(&prim) {
4097                 render_assoc_items(w, cx, container_item, did, what)?;
4098             }
4099         }
4100         Ok(())
4101     }
4102 }
4103
4104 fn should_render_item(item: &clean::Item, deref_mut_: bool) -> bool {
4105     let self_type_opt = match item.inner {
4106         clean::MethodItem(ref method) => method.decl.self_type(),
4107         clean::TyMethodItem(ref method) => method.decl.self_type(),
4108         _ => None
4109     };
4110
4111     if let Some(self_ty) = self_type_opt {
4112         let (by_mut_ref, by_box, by_value) = match self_ty {
4113             SelfTy::SelfBorrowed(_, mutability) |
4114             SelfTy::SelfExplicit(clean::BorrowedRef { mutability, .. }) => {
4115                 (mutability == Mutability::Mutable, false, false)
4116             },
4117             SelfTy::SelfExplicit(clean::ResolvedPath { did, .. }) => {
4118                 (false, Some(did) == cache().owned_box_did, false)
4119             },
4120             SelfTy::SelfValue => (false, false, true),
4121             _ => (false, false, false),
4122         };
4123
4124         (deref_mut_ || !by_mut_ref) && !by_box && !by_value
4125     } else {
4126         false
4127     }
4128 }
4129
4130 fn render_spotlight_traits(item: &clean::Item) -> Result<String, fmt::Error> {
4131     let mut out = String::new();
4132
4133     match item.inner {
4134         clean::FunctionItem(clean::Function { ref decl, .. }) |
4135         clean::TyMethodItem(clean::TyMethod { ref decl, .. }) |
4136         clean::MethodItem(clean::Method { ref decl, .. }) |
4137         clean::ForeignFunctionItem(clean::Function { ref decl, .. }) => {
4138             out = spotlight_decl(decl)?;
4139         }
4140         _ => {}
4141     }
4142
4143     Ok(out)
4144 }
4145
4146 fn spotlight_decl(decl: &clean::FnDecl) -> Result<String, fmt::Error> {
4147     let mut out = String::new();
4148     let mut trait_ = String::new();
4149
4150     if let Some(did) = decl.output.def_id() {
4151         let c = cache();
4152         if let Some(impls) = c.impls.get(&did) {
4153             for i in impls {
4154                 let impl_ = i.inner_impl();
4155                 if impl_.trait_.def_id().map_or(false, |d| c.traits[&d].is_spotlight) {
4156                     if out.is_empty() {
4157                         out.push_str(
4158                             &format!("<h3 class=\"important\">Important traits for {}</h3>\
4159                                       <code class=\"content\">",
4160                                      impl_.for_));
4161                         trait_.push_str(&impl_.for_.to_string());
4162                     }
4163
4164                     //use the "where" class here to make it small
4165                     out.push_str(&format!("<span class=\"where fmt-newline\">{}</span>", impl_));
4166                     let t_did = impl_.trait_.def_id().unwrap();
4167                     for it in &impl_.items {
4168                         if let clean::TypedefItem(ref tydef, _) = it.inner {
4169                             out.push_str("<span class=\"where fmt-newline\">    ");
4170                             assoc_type(&mut out, it, &[],
4171                                        Some(&tydef.type_),
4172                                        AssocItemLink::GotoSource(t_did, &FxHashSet::default()),
4173                                        "")?;
4174                             out.push_str(";</span>");
4175                         }
4176                     }
4177                 }
4178             }
4179         }
4180     }
4181
4182     if !out.is_empty() {
4183         out.insert_str(0, &format!("<div class=\"important-traits\"><div class='tooltip'>ⓘ\
4184                                     <span class='tooltiptext'>Important traits for {}</span></div>\
4185                                     <div class=\"content hidden\">",
4186                                    trait_));
4187         out.push_str("</code></div></div>");
4188     }
4189
4190     Ok(out)
4191 }
4192
4193 fn render_impl(w: &mut fmt::Formatter<'_>, cx: &Context, i: &Impl, link: AssocItemLink<'_>,
4194                render_mode: RenderMode, outer_version: Option<&str>, show_def_docs: bool,
4195                use_absolute: Option<bool>, is_on_foreign_type: bool,
4196                show_default_items: bool) -> fmt::Result {
4197     if render_mode == RenderMode::Normal {
4198         let id = cx.derive_id(match i.inner_impl().trait_ {
4199             Some(ref t) => if is_on_foreign_type {
4200                 get_id_for_impl_on_foreign_type(&i.inner_impl().for_, t)
4201             } else {
4202                 format!("impl-{}", small_url_encode(&format!("{:#}", t)))
4203             },
4204             None => "impl".to_string(),
4205         });
4206         if let Some(use_absolute) = use_absolute {
4207             write!(w, "<h3 id='{}' class='impl'><code class='in-band'>", id)?;
4208             fmt_impl_for_trait_page(&i.inner_impl(), w, use_absolute)?;
4209             if show_def_docs {
4210                 for it in &i.inner_impl().items {
4211                     if let clean::TypedefItem(ref tydef, _) = it.inner {
4212                         write!(w, "<span class=\"where fmt-newline\">  ")?;
4213                         assoc_type(w, it, &vec![], Some(&tydef.type_),
4214                                    AssocItemLink::Anchor(None),
4215                                    "")?;
4216                         write!(w, ";</span>")?;
4217                     }
4218                 }
4219             }
4220             write!(w, "</code>")?;
4221         } else {
4222             write!(w, "<h3 id='{}' class='impl'><code class='in-band'>{}</code>",
4223                 id, i.inner_impl()
4224             )?;
4225         }
4226         write!(w, "<a href='#{}' class='anchor'></a>", id)?;
4227         let since = i.impl_item.stability.as_ref().map(|s| &s.since[..]);
4228         render_stability_since_raw(w, since, outer_version)?;
4229         if let Some(l) = (Item { item: &i.impl_item, cx: cx }).src_href() {
4230             write!(w, "<a class='srclink' href='{}' title='{}'>[src]</a>",
4231                    l, "goto source code")?;
4232         }
4233         write!(w, "</h3>")?;
4234         if let Some(ref dox) = cx.shared.maybe_collapsed_doc_value(&i.impl_item) {
4235             let mut ids = cx.id_map.borrow_mut();
4236             write!(w, "<div class='docblock'>{}</div>",
4237                    Markdown(&*dox, &i.impl_item.links(), RefCell::new(&mut ids),
4238                             cx.codes, cx.edition))?;
4239         }
4240     }
4241
4242     fn doc_impl_item(w: &mut fmt::Formatter<'_>, cx: &Context, item: &clean::Item,
4243                      link: AssocItemLink<'_>, render_mode: RenderMode,
4244                      is_default_item: bool, outer_version: Option<&str>,
4245                      trait_: Option<&clean::Trait>, show_def_docs: bool) -> fmt::Result {
4246         let item_type = item.type_();
4247         let name = item.name.as_ref().unwrap();
4248
4249         let render_method_item: bool = match render_mode {
4250             RenderMode::Normal => true,
4251             RenderMode::ForDeref { mut_: deref_mut_ } => should_render_item(&item, deref_mut_),
4252         };
4253
4254         let (is_hidden, extra_class) = if trait_.is_none() ||
4255                                           item.doc_value().is_some() ||
4256                                           item.inner.is_associated() {
4257             (false, "")
4258         } else {
4259             (true, " hidden")
4260         };
4261         match item.inner {
4262             clean::MethodItem(clean::Method { ref decl, .. }) |
4263             clean::TyMethodItem(clean::TyMethod { ref decl, .. }) => {
4264                 // Only render when the method is not static or we allow static methods
4265                 if render_method_item {
4266                     let id = cx.derive_id(format!("{}.{}", item_type, name));
4267                     let ns_id = cx.derive_id(format!("{}.{}", name, item_type.name_space()));
4268                     write!(w, "<h4 id='{}' class=\"{}{}\">", id, item_type, extra_class)?;
4269                     write!(w, "{}", spotlight_decl(decl)?)?;
4270                     write!(w, "<code id='{}'>", ns_id)?;
4271                     render_assoc_item(w, item, link.anchor(&id), ItemType::Impl)?;
4272                     write!(w, "</code>")?;
4273                     render_stability_since_raw(w, item.stable_since(), outer_version)?;
4274                     if let Some(l) = (Item { cx, item }).src_href() {
4275                         write!(w, "<a class='srclink' href='{}' title='{}'>[src]</a>",
4276                                l, "goto source code")?;
4277                     }
4278                     write!(w, "</h4>")?;
4279                 }
4280             }
4281             clean::TypedefItem(ref tydef, _) => {
4282                 let id = cx.derive_id(format!("{}.{}", ItemType::AssocType, name));
4283                 let ns_id = cx.derive_id(format!("{}.{}", name, item_type.name_space()));
4284                 write!(w, "<h4 id='{}' class=\"{}{}\">", id, item_type, extra_class)?;
4285                 write!(w, "<code id='{}'>", ns_id)?;
4286                 assoc_type(w, item, &Vec::new(), Some(&tydef.type_), link.anchor(&id), "")?;
4287                 write!(w, "</code></h4>")?;
4288             }
4289             clean::AssocConstItem(ref ty, ref default) => {
4290                 let id = cx.derive_id(format!("{}.{}", item_type, name));
4291                 let ns_id = cx.derive_id(format!("{}.{}", name, item_type.name_space()));
4292                 write!(w, "<h4 id='{}' class=\"{}{}\">", id, item_type, extra_class)?;
4293                 write!(w, "<code id='{}'>", ns_id)?;
4294                 assoc_const(w, item, ty, default.as_ref(), link.anchor(&id), "")?;
4295                 write!(w, "</code>")?;
4296                 render_stability_since_raw(w, item.stable_since(), outer_version)?;
4297                 if let Some(l) = (Item { cx, item }).src_href() {
4298                     write!(w, "<a class='srclink' href='{}' title='{}'>[src]</a>",
4299                             l, "goto source code")?;
4300                 }
4301                 write!(w, "</h4>")?;
4302             }
4303             clean::AssocTypeItem(ref bounds, ref default) => {
4304                 let id = cx.derive_id(format!("{}.{}", item_type, name));
4305                 let ns_id = cx.derive_id(format!("{}.{}", name, item_type.name_space()));
4306                 write!(w, "<h4 id='{}' class=\"{}{}\">", id, item_type, extra_class)?;
4307                 write!(w, "<code id='{}'>", ns_id)?;
4308                 assoc_type(w, item, bounds, default.as_ref(), link.anchor(&id), "")?;
4309                 write!(w, "</code></h4>")?;
4310             }
4311             clean::StrippedItem(..) => return Ok(()),
4312             _ => panic!("can't make docs for trait item with name {:?}", item.name)
4313         }
4314
4315         if render_method_item || render_mode == RenderMode::Normal {
4316             if !is_default_item {
4317                 if let Some(t) = trait_ {
4318                     // The trait item may have been stripped so we might not
4319                     // find any documentation or stability for it.
4320                     if let Some(it) = t.items.iter().find(|i| i.name == item.name) {
4321                         // We need the stability of the item from the trait
4322                         // because impls can't have a stability.
4323                         document_stability(w, cx, it, is_hidden)?;
4324                         if item.doc_value().is_some() {
4325                             document_full(w, item, cx, "", is_hidden)?;
4326                         } else if show_def_docs {
4327                             // In case the item isn't documented,
4328                             // provide short documentation from the trait.
4329                             document_short(w, cx, it, link, "", is_hidden)?;
4330                         }
4331                     }
4332                 } else {
4333                     document_stability(w, cx, item, is_hidden)?;
4334                     if show_def_docs {
4335                         document_full(w, item, cx, "", is_hidden)?;
4336                     }
4337                 }
4338             } else {
4339                 document_stability(w, cx, item, is_hidden)?;
4340                 if show_def_docs {
4341                     document_short(w, cx, item, link, "", is_hidden)?;
4342                 }
4343             }
4344         }
4345         Ok(())
4346     }
4347
4348     let traits = &cache().traits;
4349     let trait_ = i.trait_did().map(|did| &traits[&did]);
4350
4351     write!(w, "<div class='impl-items'>")?;
4352     for trait_item in &i.inner_impl().items {
4353         doc_impl_item(w, cx, trait_item, link, render_mode,
4354                       false, outer_version, trait_, show_def_docs)?;
4355     }
4356
4357     fn render_default_items(w: &mut fmt::Formatter<'_>,
4358                             cx: &Context,
4359                             t: &clean::Trait,
4360                             i: &clean::Impl,
4361                             render_mode: RenderMode,
4362                             outer_version: Option<&str>,
4363                             show_def_docs: bool) -> fmt::Result {
4364         for trait_item in &t.items {
4365             let n = trait_item.name.clone();
4366             if i.items.iter().find(|m| m.name == n).is_some() {
4367                 continue;
4368             }
4369             let did = i.trait_.as_ref().unwrap().def_id().unwrap();
4370             let assoc_link = AssocItemLink::GotoSource(did, &i.provided_trait_methods);
4371
4372             doc_impl_item(w, cx, trait_item, assoc_link, render_mode, true,
4373                           outer_version, None, show_def_docs)?;
4374         }
4375         Ok(())
4376     }
4377
4378     // If we've implemented a trait, then also emit documentation for all
4379     // default items which weren't overridden in the implementation block.
4380     // We don't emit documentation for default items if they appear in the
4381     // Implementations on Foreign Types or Implementors sections.
4382     if show_default_items {
4383         if let Some(t) = trait_ {
4384             render_default_items(w, cx, t, &i.inner_impl(),
4385                                 render_mode, outer_version, show_def_docs)?;
4386         }
4387     }
4388     write!(w, "</div>")?;
4389
4390     Ok(())
4391 }
4392
4393 fn item_opaque_ty(
4394     w: &mut fmt::Formatter<'_>,
4395     cx: &Context,
4396     it: &clean::Item,
4397     t: &clean::OpaqueTy,
4398 ) -> fmt::Result {
4399     write!(w, "<pre class='rust opaque'>")?;
4400     render_attributes(w, it, false)?;
4401     write!(w, "type {}{}{where_clause} = impl {bounds};</pre>",
4402            it.name.as_ref().unwrap(),
4403            t.generics,
4404            where_clause = WhereClause { gens: &t.generics, indent: 0, end_newline: true },
4405            bounds = bounds(&t.bounds, false))?;
4406
4407     document(w, cx, it)?;
4408
4409     // Render any items associated directly to this alias, as otherwise they
4410     // won't be visible anywhere in the docs. It would be nice to also show
4411     // associated items from the aliased type (see discussion in #32077), but
4412     // we need #14072 to make sense of the generics.
4413     render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)
4414 }
4415
4416 fn item_trait_alias(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item,
4417                     t: &clean::TraitAlias) -> fmt::Result {
4418     write!(w, "<pre class='rust trait-alias'>")?;
4419     render_attributes(w, it, false)?;
4420     write!(w, "trait {}{}{} = {};</pre>",
4421            it.name.as_ref().unwrap(),
4422            t.generics,
4423            WhereClause { gens: &t.generics, indent: 0, end_newline: true },
4424            bounds(&t.bounds, true))?;
4425
4426     document(w, cx, it)?;
4427
4428     // Render any items associated directly to this alias, as otherwise they
4429     // won't be visible anywhere in the docs. It would be nice to also show
4430     // associated items from the aliased type (see discussion in #32077), but
4431     // we need #14072 to make sense of the generics.
4432     render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)
4433 }
4434
4435 fn item_typedef(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item,
4436                 t: &clean::Typedef) -> fmt::Result {
4437     write!(w, "<pre class='rust typedef'>")?;
4438     render_attributes(w, it, false)?;
4439     write!(w, "type {}{}{where_clause} = {type_};</pre>",
4440            it.name.as_ref().unwrap(),
4441            t.generics,
4442            where_clause = WhereClause { gens: &t.generics, indent: 0, end_newline: true },
4443            type_ = t.type_)?;
4444
4445     document(w, cx, it)?;
4446
4447     // Render any items associated directly to this alias, as otherwise they
4448     // won't be visible anywhere in the docs. It would be nice to also show
4449     // associated items from the aliased type (see discussion in #32077), but
4450     // we need #14072 to make sense of the generics.
4451     render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)
4452 }
4453
4454 fn item_foreign_type(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item) -> fmt::Result {
4455     writeln!(w, "<pre class='rust foreigntype'>extern {{")?;
4456     render_attributes(w, it, false)?;
4457     write!(
4458         w,
4459         "    {}type {};\n}}</pre>",
4460         VisSpace(&it.visibility),
4461         it.name.as_ref().unwrap(),
4462     )?;
4463
4464     document(w, cx, it)?;
4465
4466     render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)
4467 }
4468
4469 impl<'a> fmt::Display for Sidebar<'a> {
4470     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
4471         let cx = self.cx;
4472         let it = self.item;
4473         let parentlen = cx.current.len() - if it.is_mod() {1} else {0};
4474
4475         if it.is_struct() || it.is_trait() || it.is_primitive() || it.is_union()
4476             || it.is_enum() || it.is_mod() || it.is_typedef() {
4477             write!(fmt, "<p class='location'>{}{}</p>",
4478                 match it.inner {
4479                     clean::StructItem(..) => "Struct ",
4480                     clean::TraitItem(..) => "Trait ",
4481                     clean::PrimitiveItem(..) => "Primitive Type ",
4482                     clean::UnionItem(..) => "Union ",
4483                     clean::EnumItem(..) => "Enum ",
4484                     clean::TypedefItem(..) => "Type Definition ",
4485                     clean::ForeignTypeItem => "Foreign Type ",
4486                     clean::ModuleItem(..) => if it.is_crate() {
4487                         "Crate "
4488                     } else {
4489                         "Module "
4490                     },
4491                     _ => "",
4492                 },
4493                 it.name.as_ref().unwrap())?;
4494         }
4495
4496         if it.is_crate() {
4497             if let Some(ref version) = cache().crate_version {
4498                 write!(fmt,
4499                        "<div class='block version'>\
4500                         <p>Version {}</p>\
4501                         </div>",
4502                        version)?;
4503             }
4504         }
4505
4506         write!(fmt, "<div class=\"sidebar-elems\">")?;
4507         if it.is_crate() {
4508             write!(fmt, "<a id='all-types' href='all.html'><p>See all {}'s items</p></a>",
4509                    it.name.as_ref().expect("crates always have a name"))?;
4510         }
4511         match it.inner {
4512             clean::StructItem(ref s) => sidebar_struct(fmt, it, s)?,
4513             clean::TraitItem(ref t) => sidebar_trait(fmt, it, t)?,
4514             clean::PrimitiveItem(ref p) => sidebar_primitive(fmt, it, p)?,
4515             clean::UnionItem(ref u) => sidebar_union(fmt, it, u)?,
4516             clean::EnumItem(ref e) => sidebar_enum(fmt, it, e)?,
4517             clean::TypedefItem(ref t, _) => sidebar_typedef(fmt, it, t)?,
4518             clean::ModuleItem(ref m) => sidebar_module(fmt, it, &m.items)?,
4519             clean::ForeignTypeItem => sidebar_foreign_type(fmt, it)?,
4520             _ => (),
4521         }
4522
4523         // The sidebar is designed to display sibling functions, modules and
4524         // other miscellaneous information. since there are lots of sibling
4525         // items (and that causes quadratic growth in large modules),
4526         // we refactor common parts into a shared JavaScript file per module.
4527         // still, we don't move everything into JS because we want to preserve
4528         // as much HTML as possible in order to allow non-JS-enabled browsers
4529         // to navigate the documentation (though slightly inefficiently).
4530
4531         write!(fmt, "<p class='location'>")?;
4532         for (i, name) in cx.current.iter().take(parentlen).enumerate() {
4533             if i > 0 {
4534                 write!(fmt, "::<wbr>")?;
4535             }
4536             write!(fmt, "<a href='{}index.html'>{}</a>",
4537                    &cx.root_path()[..(cx.current.len() - i - 1) * 3],
4538                    *name)?;
4539         }
4540         write!(fmt, "</p>")?;
4541
4542         // Sidebar refers to the enclosing module, not this module.
4543         let relpath = if it.is_mod() { "../" } else { "" };
4544         write!(fmt,
4545                "<script>window.sidebarCurrent = {{\
4546                    name: '{name}', \
4547                    ty: '{ty}', \
4548                    relpath: '{path}'\
4549                 }};</script>",
4550                name = it.name.as_ref().map(|x| &x[..]).unwrap_or(""),
4551                ty = it.type_().css_class(),
4552                path = relpath)?;
4553         if parentlen == 0 {
4554             // There is no sidebar-items.js beyond the crate root path
4555             // FIXME maybe dynamic crate loading can be merged here
4556         } else {
4557             write!(fmt, "<script defer src=\"{path}sidebar-items.js\"></script>",
4558                    path = relpath)?;
4559         }
4560         // Closes sidebar-elems div.
4561         write!(fmt, "</div>")?;
4562
4563         Ok(())
4564     }
4565 }
4566
4567 fn get_next_url(used_links: &mut FxHashSet<String>, url: String) -> String {
4568     if used_links.insert(url.clone()) {
4569         return url;
4570     }
4571     let mut add = 1;
4572     while used_links.insert(format!("{}-{}", url, add)) == false {
4573         add += 1;
4574     }
4575     format!("{}-{}", url, add)
4576 }
4577
4578 fn get_methods(
4579     i: &clean::Impl,
4580     for_deref: bool,
4581     used_links: &mut FxHashSet<String>,
4582 ) -> Vec<String> {
4583     i.items.iter().filter_map(|item| {
4584         match item.name {
4585             // Maybe check with clean::Visibility::Public as well?
4586             Some(ref name) if !name.is_empty() && item.visibility.is_some() && item.is_method() => {
4587                 if !for_deref || should_render_item(item, false) {
4588                     Some(format!("<a href=\"#{}\">{}</a>",
4589                                  get_next_url(used_links, format!("method.{}", name)),
4590                                  name))
4591                 } else {
4592                     None
4593                 }
4594             }
4595             _ => None,
4596         }
4597     }).collect::<Vec<_>>()
4598 }
4599
4600 // The point is to url encode any potential character from a type with genericity.
4601 fn small_url_encode(s: &str) -> String {
4602     s.replace("<", "%3C")
4603      .replace(">", "%3E")
4604      .replace(" ", "%20")
4605      .replace("?", "%3F")
4606      .replace("'", "%27")
4607      .replace("&", "%26")
4608      .replace(",", "%2C")
4609      .replace(":", "%3A")
4610      .replace(";", "%3B")
4611      .replace("[", "%5B")
4612      .replace("]", "%5D")
4613      .replace("\"", "%22")
4614 }
4615
4616 fn sidebar_assoc_items(it: &clean::Item) -> String {
4617     let mut out = String::new();
4618     let c = cache();
4619     if let Some(v) = c.impls.get(&it.def_id) {
4620         let mut used_links = FxHashSet::default();
4621
4622         {
4623             let used_links_bor = Rc::new(RefCell::new(&mut used_links));
4624             let mut ret = v.iter()
4625                            .filter(|i| i.inner_impl().trait_.is_none())
4626                            .flat_map(move |i| get_methods(i.inner_impl(),
4627                                                           false,
4628                                                           &mut used_links_bor.borrow_mut()))
4629                            .collect::<Vec<_>>();
4630             // We want links' order to be reproducible so we don't use unstable sort.
4631             ret.sort();
4632             if !ret.is_empty() {
4633                 out.push_str(&format!("<a class=\"sidebar-title\" href=\"#methods\">Methods\
4634                                        </a><div class=\"sidebar-links\">{}</div>", ret.join("")));
4635             }
4636         }
4637
4638         if v.iter().any(|i| i.inner_impl().trait_.is_some()) {
4639             if let Some(impl_) = v.iter()
4640                                   .filter(|i| i.inner_impl().trait_.is_some())
4641                                   .find(|i| i.inner_impl().trait_.def_id() == c.deref_trait_did) {
4642                 if let Some(target) = impl_.inner_impl().items.iter().filter_map(|item| {
4643                     match item.inner {
4644                         clean::TypedefItem(ref t, true) => Some(&t.type_),
4645                         _ => None,
4646                     }
4647                 }).next() {
4648                     let inner_impl = target.def_id().or(target.primitive_type().and_then(|prim| {
4649                         c.primitive_locations.get(&prim).cloned()
4650                     })).and_then(|did| c.impls.get(&did));
4651                     if let Some(impls) = inner_impl {
4652                         out.push_str("<a class=\"sidebar-title\" href=\"#deref-methods\">");
4653                         out.push_str(&format!("Methods from {}&lt;Target={}&gt;",
4654                                               Escape(&format!("{:#}",
4655                                                      impl_.inner_impl().trait_.as_ref().unwrap())),
4656                                               Escape(&format!("{:#}", target))));
4657                         out.push_str("</a>");
4658                         let mut ret = impls.iter()
4659                                            .filter(|i| i.inner_impl().trait_.is_none())
4660                                            .flat_map(|i| get_methods(i.inner_impl(),
4661                                                                      true,
4662                                                                      &mut used_links))
4663                                            .collect::<Vec<_>>();
4664                         // We want links' order to be reproducible so we don't use unstable sort.
4665                         ret.sort();
4666                         if !ret.is_empty() {
4667                             out.push_str(&format!("<div class=\"sidebar-links\">{}</div>",
4668                                                   ret.join("")));
4669                         }
4670                     }
4671                 }
4672             }
4673             let format_impls = |impls: Vec<&Impl>| {
4674                 let mut links = FxHashSet::default();
4675
4676                 let mut ret = impls.iter()
4677                     .filter_map(|i| {
4678                         let is_negative_impl = is_negative_impl(i.inner_impl());
4679                         if let Some(ref i) = i.inner_impl().trait_ {
4680                             let i_display = format!("{:#}", i);
4681                             let out = Escape(&i_display);
4682                             let encoded = small_url_encode(&format!("{:#}", i));
4683                             let generated = format!("<a href=\"#impl-{}\">{}{}</a>",
4684                                                     encoded,
4685                                                     if is_negative_impl { "!" } else { "" },
4686                                                     out);
4687                             if links.insert(generated.clone()) {
4688                                 Some(generated)
4689                             } else {
4690                                 None
4691                             }
4692                         } else {
4693                             None
4694                         }
4695                     })
4696                     .collect::<Vec<String>>();
4697                 ret.sort();
4698                 ret.join("")
4699             };
4700
4701             let (synthetic, concrete): (Vec<&Impl>, Vec<&Impl>) = v
4702                 .iter()
4703                 .partition::<Vec<_>, _>(|i| i.inner_impl().synthetic);
4704             let (blanket_impl, concrete): (Vec<&Impl>, Vec<&Impl>) = concrete
4705                 .into_iter()
4706                 .partition::<Vec<_>, _>(|i| i.inner_impl().blanket_impl.is_some());
4707
4708             let concrete_format = format_impls(concrete);
4709             let synthetic_format = format_impls(synthetic);
4710             let blanket_format = format_impls(blanket_impl);
4711
4712             if !concrete_format.is_empty() {
4713                 out.push_str("<a class=\"sidebar-title\" href=\"#implementations\">\
4714                               Trait Implementations</a>");
4715                 out.push_str(&format!("<div class=\"sidebar-links\">{}</div>", concrete_format));
4716             }
4717
4718             if !synthetic_format.is_empty() {
4719                 out.push_str("<a class=\"sidebar-title\" href=\"#synthetic-implementations\">\
4720                               Auto Trait Implementations</a>");
4721                 out.push_str(&format!("<div class=\"sidebar-links\">{}</div>", synthetic_format));
4722             }
4723
4724             if !blanket_format.is_empty() {
4725                 out.push_str("<a class=\"sidebar-title\" href=\"#blanket-implementations\">\
4726                               Blanket Implementations</a>");
4727                 out.push_str(&format!("<div class=\"sidebar-links\">{}</div>", blanket_format));
4728             }
4729         }
4730     }
4731
4732     out
4733 }
4734
4735 fn sidebar_struct(fmt: &mut fmt::Formatter<'_>, it: &clean::Item,
4736                   s: &clean::Struct) -> fmt::Result {
4737     let mut sidebar = String::new();
4738     let fields = get_struct_fields_name(&s.fields);
4739
4740     if !fields.is_empty() {
4741         if let doctree::Plain = s.struct_type {
4742             sidebar.push_str(&format!("<a class=\"sidebar-title\" href=\"#fields\">Fields</a>\
4743                                        <div class=\"sidebar-links\">{}</div>", fields));
4744         }
4745     }
4746
4747     sidebar.push_str(&sidebar_assoc_items(it));
4748
4749     if !sidebar.is_empty() {
4750         write!(fmt, "<div class=\"block items\">{}</div>", sidebar)?;
4751     }
4752     Ok(())
4753 }
4754
4755 fn get_id_for_impl_on_foreign_type(for_: &clean::Type, trait_: &clean::Type) -> String {
4756     small_url_encode(&format!("impl-{:#}-for-{:#}", trait_, for_))
4757 }
4758
4759 fn extract_for_impl_name(item: &clean::Item) -> Option<(String, String)> {
4760     match item.inner {
4761         clean::ItemEnum::ImplItem(ref i) => {
4762             if let Some(ref trait_) = i.trait_ {
4763                 Some((format!("{:#}", i.for_), get_id_for_impl_on_foreign_type(&i.for_, trait_)))
4764             } else {
4765                 None
4766             }
4767         },
4768         _ => None,
4769     }
4770 }
4771
4772 fn is_negative_impl(i: &clean::Impl) -> bool {
4773     i.polarity == Some(clean::ImplPolarity::Negative)
4774 }
4775
4776 fn sidebar_trait(fmt: &mut fmt::Formatter<'_>, it: &clean::Item,
4777                  t: &clean::Trait) -> fmt::Result {
4778     let mut sidebar = String::new();
4779
4780     let types = t.items
4781                  .iter()
4782                  .filter_map(|m| {
4783                      match m.name {
4784                          Some(ref name) if m.is_associated_type() => {
4785                              Some(format!("<a href=\"#associatedtype.{name}\">{name}</a>",
4786                                           name=name))
4787                          }
4788                          _ => None,
4789                      }
4790                  })
4791                  .collect::<String>();
4792     let consts = t.items
4793                   .iter()
4794                   .filter_map(|m| {
4795                       match m.name {
4796                           Some(ref name) if m.is_associated_const() => {
4797                               Some(format!("<a href=\"#associatedconstant.{name}\">{name}</a>",
4798                                            name=name))
4799                           }
4800                           _ => None,
4801                       }
4802                   })
4803                   .collect::<String>();
4804     let mut required = t.items
4805                         .iter()
4806                         .filter_map(|m| {
4807                             match m.name {
4808                                 Some(ref name) if m.is_ty_method() => {
4809                                     Some(format!("<a href=\"#tymethod.{name}\">{name}</a>",
4810                                                  name=name))
4811                                 }
4812                                 _ => None,
4813                             }
4814                         })
4815                         .collect::<Vec<String>>();
4816     let mut provided = t.items
4817                         .iter()
4818                         .filter_map(|m| {
4819                             match m.name {
4820                                 Some(ref name) if m.is_method() => {
4821                                     Some(format!("<a href=\"#method.{0}\">{0}</a>", name))
4822                                 }
4823                                 _ => None,
4824                             }
4825                         })
4826                         .collect::<Vec<String>>();
4827
4828     if !types.is_empty() {
4829         sidebar.push_str(&format!("<a class=\"sidebar-title\" href=\"#associated-types\">\
4830                                    Associated Types</a><div class=\"sidebar-links\">{}</div>",
4831                                   types));
4832     }
4833     if !consts.is_empty() {
4834         sidebar.push_str(&format!("<a class=\"sidebar-title\" href=\"#associated-const\">\
4835                                    Associated Constants</a><div class=\"sidebar-links\">{}</div>",
4836                                   consts));
4837     }
4838     if !required.is_empty() {
4839         required.sort();
4840         sidebar.push_str(&format!("<a class=\"sidebar-title\" href=\"#required-methods\">\
4841                                    Required Methods</a><div class=\"sidebar-links\">{}</div>",
4842                                   required.join("")));
4843     }
4844     if !provided.is_empty() {
4845         provided.sort();
4846         sidebar.push_str(&format!("<a class=\"sidebar-title\" href=\"#provided-methods\">\
4847                                    Provided Methods</a><div class=\"sidebar-links\">{}</div>",
4848                                   provided.join("")));
4849     }
4850
4851     let c = cache();
4852
4853     if let Some(implementors) = c.implementors.get(&it.def_id) {
4854         let mut res = implementors.iter()
4855                                   .filter(|i| i.inner_impl().for_.def_id()
4856                                   .map_or(false, |d| !c.paths.contains_key(&d)))
4857                                   .filter_map(|i| {
4858                                       match extract_for_impl_name(&i.impl_item) {
4859                                           Some((ref name, ref id)) => {
4860                                               Some(format!("<a href=\"#{}\">{}</a>",
4861                                                           id,
4862                                                           Escape(name)))
4863                                           }
4864                                           _ => None,
4865                                       }
4866                                   })
4867                                   .collect::<Vec<String>>();
4868         if !res.is_empty() {
4869             res.sort();
4870             sidebar.push_str(&format!("<a class=\"sidebar-title\" href=\"#foreign-impls\">\
4871                                        Implementations on Foreign Types</a><div \
4872                                        class=\"sidebar-links\">{}</div>",
4873                                       res.join("")));
4874         }
4875     }
4876
4877     sidebar.push_str("<a class=\"sidebar-title\" href=\"#implementors\">Implementors</a>");
4878     if t.auto {
4879         sidebar.push_str("<a class=\"sidebar-title\" \
4880                           href=\"#synthetic-implementors\">Auto Implementors</a>");
4881     }
4882
4883     sidebar.push_str(&sidebar_assoc_items(it));
4884
4885     write!(fmt, "<div class=\"block items\">{}</div>", sidebar)
4886 }
4887
4888 fn sidebar_primitive(fmt: &mut fmt::Formatter<'_>, it: &clean::Item,
4889                      _p: &clean::PrimitiveType) -> fmt::Result {
4890     let sidebar = sidebar_assoc_items(it);
4891
4892     if !sidebar.is_empty() {
4893         write!(fmt, "<div class=\"block items\">{}</div>", sidebar)?;
4894     }
4895     Ok(())
4896 }
4897
4898 fn sidebar_typedef(fmt: &mut fmt::Formatter<'_>, it: &clean::Item,
4899                    _t: &clean::Typedef) -> fmt::Result {
4900     let sidebar = sidebar_assoc_items(it);
4901
4902     if !sidebar.is_empty() {
4903         write!(fmt, "<div class=\"block items\">{}</div>", sidebar)?;
4904     }
4905     Ok(())
4906 }
4907
4908 fn get_struct_fields_name(fields: &[clean::Item]) -> String {
4909     fields.iter()
4910           .filter(|f| if let clean::StructFieldItem(..) = f.inner {
4911               true
4912           } else {
4913               false
4914           })
4915           .filter_map(|f| match f.name {
4916               Some(ref name) => Some(format!("<a href=\"#structfield.{name}\">\
4917                                               {name}</a>", name=name)),
4918               _ => None,
4919           })
4920           .collect()
4921 }
4922
4923 fn sidebar_union(fmt: &mut fmt::Formatter<'_>, it: &clean::Item,
4924                  u: &clean::Union) -> fmt::Result {
4925     let mut sidebar = String::new();
4926     let fields = get_struct_fields_name(&u.fields);
4927
4928     if !fields.is_empty() {
4929         sidebar.push_str(&format!("<a class=\"sidebar-title\" href=\"#fields\">Fields</a>\
4930                                    <div class=\"sidebar-links\">{}</div>", fields));
4931     }
4932
4933     sidebar.push_str(&sidebar_assoc_items(it));
4934
4935     if !sidebar.is_empty() {
4936         write!(fmt, "<div class=\"block items\">{}</div>", sidebar)?;
4937     }
4938     Ok(())
4939 }
4940
4941 fn sidebar_enum(fmt: &mut fmt::Formatter<'_>, it: &clean::Item,
4942                 e: &clean::Enum) -> fmt::Result {
4943     let mut sidebar = String::new();
4944
4945     let variants = e.variants.iter()
4946                              .filter_map(|v| match v.name {
4947                                  Some(ref name) => Some(format!("<a href=\"#variant.{name}\">{name}\
4948                                                                  </a>", name = name)),
4949                                  _ => None,
4950                              })
4951                              .collect::<String>();
4952     if !variants.is_empty() {
4953         sidebar.push_str(&format!("<a class=\"sidebar-title\" href=\"#variants\">Variants</a>\
4954                                    <div class=\"sidebar-links\">{}</div>", variants));
4955     }
4956
4957     sidebar.push_str(&sidebar_assoc_items(it));
4958
4959     if !sidebar.is_empty() {
4960         write!(fmt, "<div class=\"block items\">{}</div>", sidebar)?;
4961     }
4962     Ok(())
4963 }
4964
4965 fn item_ty_to_strs(ty: &ItemType) -> (&'static str, &'static str) {
4966     match *ty {
4967         ItemType::ExternCrate |
4968         ItemType::Import          => ("reexports", "Re-exports"),
4969         ItemType::Module          => ("modules", "Modules"),
4970         ItemType::Struct          => ("structs", "Structs"),
4971         ItemType::Union           => ("unions", "Unions"),
4972         ItemType::Enum            => ("enums", "Enums"),
4973         ItemType::Function        => ("functions", "Functions"),
4974         ItemType::Typedef         => ("types", "Type Definitions"),
4975         ItemType::Static          => ("statics", "Statics"),
4976         ItemType::Constant        => ("constants", "Constants"),
4977         ItemType::Trait           => ("traits", "Traits"),
4978         ItemType::Impl            => ("impls", "Implementations"),
4979         ItemType::TyMethod        => ("tymethods", "Type Methods"),
4980         ItemType::Method          => ("methods", "Methods"),
4981         ItemType::StructField     => ("fields", "Struct Fields"),
4982         ItemType::Variant         => ("variants", "Variants"),
4983         ItemType::Macro           => ("macros", "Macros"),
4984         ItemType::Primitive       => ("primitives", "Primitive Types"),
4985         ItemType::AssocType       => ("associated-types", "Associated Types"),
4986         ItemType::AssocConst      => ("associated-consts", "Associated Constants"),
4987         ItemType::ForeignType     => ("foreign-types", "Foreign Types"),
4988         ItemType::Keyword         => ("keywords", "Keywords"),
4989         ItemType::OpaqueTy        => ("opaque-types", "Opaque Types"),
4990         ItemType::ProcAttribute   => ("attributes", "Attribute Macros"),
4991         ItemType::ProcDerive      => ("derives", "Derive Macros"),
4992         ItemType::TraitAlias      => ("trait-aliases", "Trait aliases"),
4993     }
4994 }
4995
4996 fn sidebar_module(fmt: &mut fmt::Formatter<'_>, _it: &clean::Item,
4997                   items: &[clean::Item]) -> fmt::Result {
4998     let mut sidebar = String::new();
4999
5000     if items.iter().any(|it| it.type_() == ItemType::ExternCrate ||
5001                              it.type_() == ItemType::Import) {
5002         sidebar.push_str(&format!("<li><a href=\"#{id}\">{name}</a></li>",
5003                                   id = "reexports",
5004                                   name = "Re-exports"));
5005     }
5006
5007     // ordering taken from item_module, reorder, where it prioritized elements in a certain order
5008     // to print its headings
5009     for &myty in &[ItemType::Primitive, ItemType::Module, ItemType::Macro, ItemType::Struct,
5010                    ItemType::Enum, ItemType::Constant, ItemType::Static, ItemType::Trait,
5011                    ItemType::Function, ItemType::Typedef, ItemType::Union, ItemType::Impl,
5012                    ItemType::TyMethod, ItemType::Method, ItemType::StructField, ItemType::Variant,
5013                    ItemType::AssocType, ItemType::AssocConst, ItemType::ForeignType,
5014                    ItemType::Keyword] {
5015         if items.iter().any(|it| !it.is_stripped() && it.type_() == myty) {
5016             let (short, name) = item_ty_to_strs(&myty);
5017             sidebar.push_str(&format!("<li><a href=\"#{id}\">{name}</a></li>",
5018                                       id = short,
5019                                       name = name));
5020         }
5021     }
5022
5023     if !sidebar.is_empty() {
5024         write!(fmt, "<div class=\"block items\"><ul>{}</ul></div>", sidebar)?;
5025     }
5026     Ok(())
5027 }
5028
5029 fn sidebar_foreign_type(fmt: &mut fmt::Formatter<'_>, it: &clean::Item) -> fmt::Result {
5030     let sidebar = sidebar_assoc_items(it);
5031     if !sidebar.is_empty() {
5032         write!(fmt, "<div class=\"block items\">{}</div>", sidebar)?;
5033     }
5034     Ok(())
5035 }
5036
5037 impl<'a> fmt::Display for Source<'a> {
5038     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
5039         let Source(s) = *self;
5040         let lines = s.lines().count();
5041         let mut cols = 0;
5042         let mut tmp = lines;
5043         while tmp > 0 {
5044             cols += 1;
5045             tmp /= 10;
5046         }
5047         write!(fmt, "<pre class=\"line-numbers\">")?;
5048         for i in 1..=lines {
5049             write!(fmt, "<span id=\"{0}\">{0:1$}</span>\n", i, cols)?;
5050         }
5051         write!(fmt, "</pre>")?;
5052         write!(fmt, "{}",
5053                highlight::render_with_highlighting(s, None, None, None))?;
5054         Ok(())
5055     }
5056 }
5057
5058 fn item_macro(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item,
5059               t: &clean::Macro) -> fmt::Result {
5060     wrap_into_docblock(w, |w| {
5061         w.write_str(&highlight::render_with_highlighting(&t.source,
5062                                                          Some("macro"),
5063                                                          None,
5064                                                          None))
5065     })?;
5066     document(w, cx, it)
5067 }
5068
5069 fn item_proc_macro(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item, m: &clean::ProcMacro)
5070     -> fmt::Result
5071 {
5072     let name = it.name.as_ref().expect("proc-macros always have names");
5073     match m.kind {
5074         MacroKind::Bang => {
5075             write!(w, "<pre class='rust macro'>")?;
5076             write!(w, "{}!() {{ /* proc-macro */ }}", name)?;
5077             write!(w, "</pre>")?;
5078         }
5079         MacroKind::Attr => {
5080             write!(w, "<pre class='rust attr'>")?;
5081             write!(w, "#[{}]", name)?;
5082             write!(w, "</pre>")?;
5083         }
5084         MacroKind::Derive => {
5085             write!(w, "<pre class='rust derive'>")?;
5086             write!(w, "#[derive({})]", name)?;
5087             if !m.helpers.is_empty() {
5088                 writeln!(w, "\n{{")?;
5089                 writeln!(w, "    // Attributes available to this derive:")?;
5090                 for attr in &m.helpers {
5091                     writeln!(w, "    #[{}]", attr)?;
5092                 }
5093                 write!(w, "}}")?;
5094             }
5095             write!(w, "</pre>")?;
5096         }
5097     }
5098     document(w, cx, it)
5099 }
5100
5101 fn item_primitive(w: &mut fmt::Formatter<'_>, cx: &Context,
5102                   it: &clean::Item,
5103                   _p: &clean::PrimitiveType) -> fmt::Result {
5104     document(w, cx, it)?;
5105     render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)
5106 }
5107
5108 fn item_keyword(w: &mut fmt::Formatter<'_>, cx: &Context,
5109                 it: &clean::Item,
5110                 _p: &str) -> fmt::Result {
5111     document(w, cx, it)
5112 }
5113
5114 const BASIC_KEYWORDS: &'static str = "rust, rustlang, rust-lang";
5115
5116 fn make_item_keywords(it: &clean::Item) -> String {
5117     format!("{}, {}", BASIC_KEYWORDS, it.name.as_ref().unwrap())
5118 }
5119
5120 fn get_index_search_type(item: &clean::Item) -> Option<IndexItemFunctionType> {
5121     let (all_types, ret_types) = match item.inner {
5122         clean::FunctionItem(ref f) => (&f.all_types, &f.ret_types),
5123         clean::MethodItem(ref m) => (&m.all_types, &m.ret_types),
5124         clean::TyMethodItem(ref m) => (&m.all_types, &m.ret_types),
5125         _ => return None,
5126     };
5127
5128     let inputs = all_types.iter().map(|arg| {
5129         get_index_type(&arg)
5130     }).filter(|a| a.name.is_some()).collect();
5131     let output = ret_types.iter().map(|arg| {
5132         get_index_type(&arg)
5133     }).filter(|a| a.name.is_some()).collect::<Vec<_>>();
5134     let output = if output.is_empty() {
5135         None
5136     } else {
5137         Some(output)
5138     };
5139
5140     Some(IndexItemFunctionType { inputs, output })
5141 }
5142
5143 fn get_index_type(clean_type: &clean::Type) -> Type {
5144     let t = Type {
5145         name: get_index_type_name(clean_type, true).map(|s| s.to_ascii_lowercase()),
5146         generics: get_generics(clean_type),
5147     };
5148     t
5149 }
5150
5151 /// Returns a list of all paths used in the type.
5152 /// This is used to help deduplicate imported impls
5153 /// for reexported types. If any of the contained
5154 /// types are re-exported, we don't use the corresponding
5155 /// entry from the js file, as inlining will have already
5156 /// picked up the impl
5157 fn collect_paths_for_type(first_ty: clean::Type) -> Vec<String> {
5158     let mut out = Vec::new();
5159     let mut visited = FxHashSet::default();
5160     let mut work = VecDeque::new();
5161     let cache = cache();
5162
5163     work.push_back(first_ty);
5164
5165     while let Some(ty) = work.pop_front() {
5166         if !visited.insert(ty.clone()) {
5167             continue;
5168         }
5169
5170         match ty {
5171             clean::Type::ResolvedPath { did, .. } => {
5172                 let get_extern = || cache.external_paths.get(&did).map(|s| s.0.clone());
5173                 let fqp = cache.exact_paths.get(&did).cloned().or_else(get_extern);
5174
5175                 match fqp {
5176                     Some(path) => {
5177                         out.push(path.join("::"));
5178                     },
5179                     _ => {}
5180                 };
5181
5182             },
5183             clean::Type::Tuple(tys) => {
5184                 work.extend(tys.into_iter());
5185             },
5186             clean::Type::Slice(ty) => {
5187                 work.push_back(*ty);
5188             }
5189             clean::Type::Array(ty, _) => {
5190                 work.push_back(*ty);
5191             },
5192             clean::Type::RawPointer(_, ty) => {
5193                 work.push_back(*ty);
5194             },
5195             clean::Type::BorrowedRef { type_, .. } => {
5196                 work.push_back(*type_);
5197             },
5198             clean::Type::QPath { self_type, trait_, .. } => {
5199                 work.push_back(*self_type);
5200                 work.push_back(*trait_);
5201             },
5202             _ => {}
5203         }
5204     };
5205     out
5206 }
5207
5208 fn get_index_type_name(clean_type: &clean::Type, accept_generic: bool) -> Option<String> {
5209     match *clean_type {
5210         clean::ResolvedPath { ref path, .. } => {
5211             let segments = &path.segments;
5212             let path_segment = segments.into_iter().last().unwrap_or_else(|| panic!(
5213                 "get_index_type_name(clean_type: {:?}, accept_generic: {:?}) had length zero path",
5214                 clean_type, accept_generic
5215             ));
5216             Some(path_segment.name.clone())
5217         }
5218         clean::Generic(ref s) if accept_generic => Some(s.clone()),
5219         clean::Primitive(ref p) => Some(format!("{:?}", p)),
5220         clean::BorrowedRef { ref type_, .. } => get_index_type_name(type_, accept_generic),
5221         // FIXME: add all from clean::Type.
5222         _ => None
5223     }
5224 }
5225
5226 fn get_generics(clean_type: &clean::Type) -> Option<Vec<String>> {
5227     clean_type.generics()
5228               .and_then(|types| {
5229                   let r = types.iter()
5230                                .filter_map(|t| get_index_type_name(t, false))
5231                                .map(|s| s.to_ascii_lowercase())
5232                                .collect::<Vec<_>>();
5233                   if r.is_empty() {
5234                       None
5235                   } else {
5236                       Some(r)
5237                   }
5238               })
5239 }
5240
5241 pub fn cache() -> Arc<Cache> {
5242     CACHE_KEY.with(|c| c.borrow().clone())
5243 }