]> git.lizzy.rs Git - rust.git/blobdiff - src/librustdoc/html/render.rs
Rollup merge of #58303 - GuillaumeGomez:stability-tags-display, r=QuietMisdreavus
[rust.git] / src / librustdoc / html / render.rs
index 7951d056666eea187fe336c535abe7ac9ac7e264..744c4ae65c6e027bcfc4320cabb296bd9469f2be 100644 (file)
@@ -1,4 +1,4 @@
-//! Rustdoc's HTML Rendering module
+//! Rustdoc's HTML rendering module.
 //!
 //! This modules contains the bulk of the logic necessary for rendering a
 //! rustdoc `clean::Crate` instance to a set of static HTML pages. This
@@ -62,7 +62,7 @@
 use html::escape::Escape;
 use html::format::{AsyncSpace, ConstnessSpace};
 use html::format::{GenericBounds, WhereClause, href, AbiSpace};
-use html::format::{VisSpace, Method, UnsafetySpace, MutableSpace};
+use html::format::{VisSpace, Function, UnsafetySpace, MutableSpace};
 use html::format::fmt_impl_for_trait_page;
 use html::item_type::ItemType;
 use html::markdown::{self, Markdown, MarkdownHtml, MarkdownSummaryLine, ErrorCodes, IdMap};
@@ -148,6 +148,8 @@ struct SharedContext {
     /// If false, the `select` element to have search filtering by crates on rendered docs
     /// won't be generated.
     pub generate_search_filter: bool,
+    /// Option disabled by default to generate files used by RLS and some other tools.
+    pub generate_redirect_pages: bool,
 }
 
 impl SharedContext {
@@ -163,7 +165,7 @@ fn ensure_dir(&self, dst: &Path) -> io::Result<()> {
 }
 
 impl SharedContext {
-    /// Returns whether the `collapse-docs` pass was run on this crate.
+    /// Returns `true` if the `collapse-docs` pass was run on this crate.
     pub fn was_collapsed(&self) -> bool {
         self.passes.contains("collapse-docs")
     }
@@ -267,11 +269,11 @@ macro_rules! try_err {
 #[derive(Default)]
 pub struct Cache {
     /// Mapping of typaram ids to the name of the type parameter. This is used
-    /// when pretty-printing a type (so pretty printing doesn't have to
+    /// when pretty-printing a type (so pretty-printing doesn't have to
     /// painfully maintain a context like this)
     pub typarams: FxHashMap<DefId, String>,
 
-    /// Maps a type id to all known implementations for that type. This is only
+    /// Maps a type ID to all known implementations for that type. This is only
     /// recognized for intra-crate `ResolvedPath` types, and is used to print
     /// out extra documentation on the page of an enum/struct.
     ///
@@ -279,7 +281,7 @@ pub struct Cache {
     /// found on that implementation.
     pub impls: FxHashMap<DefId, Vec<Impl>>,
 
-    /// Maintains a mapping of local crate node ids to the fully qualified name
+    /// Maintains a mapping of local crate `NodeId`s to the fully qualified name
     /// and "short type description" of that node. This is used when generating
     /// URLs when a type is being linked to. External paths are not located in
     /// this map because the `External` type itself has all the information
@@ -290,7 +292,7 @@ pub struct Cache {
     /// generating explicit hyperlinks to other crates.
     pub external_paths: FxHashMap<DefId, (Vec<String>, ItemType)>,
 
-    /// Maps local def ids of exported types to fully qualified paths.
+    /// Maps local `DefId`s of exported types to fully qualified paths.
     /// Unlike 'paths', this mapping ignores any renames that occur
     /// due to 'use' statements.
     ///
@@ -516,6 +518,7 @@ pub fn run(mut krate: clean::Crate,
         resource_suffix,
         static_root_path,
         generate_search_filter,
+        generate_redirect_pages,
         ..
     } = options;
 
@@ -545,6 +548,7 @@ pub fn run(mut krate: clean::Crate,
         resource_suffix,
         static_root_path,
         generate_search_filter,
+        generate_redirect_pages,
     };
 
     // If user passed in `--playground-url` arg, we fill in crate name here
@@ -692,7 +696,7 @@ pub fn run(mut krate: clean::Crate,
     cx.krate(krate)
 }
 
-/// Build the search index from the collected metadata
+/// Builds the search index from the collected metadata
 fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String {
     let mut nodeid_to_pathid = FxHashMap::default();
     let mut crate_items = Vec::with_capacity(cache.search_index.len());
@@ -1746,7 +1750,8 @@ fn generics(&mut self, generics: &clean::Generics) {
         for param in &generics.params {
             match param.kind {
                 clean::GenericParamDefKind::Lifetime => {}
-                clean::GenericParamDefKind::Type { did, .. } => {
+                clean::GenericParamDefKind::Type { did, .. } |
+                clean::GenericParamDefKind::Const { did, .. } => {
                     self.typarams.insert(did, param.name.clone());
                 }
             }
@@ -1836,6 +1841,7 @@ struct AllTypes {
     keywords: FxHashSet<ItemEntry>,
     attributes: FxHashSet<ItemEntry>,
     derives: FxHashSet<ItemEntry>,
+    trait_aliases: FxHashSet<ItemEntry>,
 }
 
 impl AllTypes {
@@ -1856,6 +1862,7 @@ fn new() -> AllTypes {
             keywords: new_set(100),
             attributes: new_set(100),
             derives: new_set(100),
+            trait_aliases: new_set(100),
         }
     }
 
@@ -1879,6 +1886,7 @@ fn append(&mut self, item_name: String, item_type: &ItemType) {
                 ItemType::Constant => self.constants.insert(ItemEntry::new(new_url, name)),
                 ItemType::ProcAttribute => self.attributes.insert(ItemEntry::new(new_url, name)),
                 ItemType::ProcDerive => self.derives.insert(ItemEntry::new(new_url, name)),
+                ItemType::TraitAlias => self.trait_aliases.insert(ItemEntry::new(new_url, name)),
                 _ => true,
             };
         }
@@ -1922,6 +1930,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         print_entries(f, &self.derives, "Derive Macros", "derives")?;
         print_entries(f, &self.functions, "Functions", "functions")?;
         print_entries(f, &self.typedefs, "Typedefs", "typedefs")?;
+        print_entries(f, &self.trait_aliases, "Trait Aliases", "trait-aliases")?;
         print_entries(f, &self.existentials, "Existentials", "existentials")?;
         print_entries(f, &self.statics, "Statics", "statics")?;
         print_entries(f, &self.constants, "Constants", "constants")
@@ -2242,17 +2251,18 @@ fn item<F>(&mut self, item: clean::Item, all: &mut AllTypes, mut f: F) -> Result
                 if !self.render_redirect_pages {
                     all.append(full_path(self, &item), &item_type);
                 }
-                // Redirect from a sane URL using the namespace to Rustdoc's
-                // URL for the page.
-                let redir_name = format!("{}.{}.html", name, item_type.name_space());
-                let redir_dst = self.dst.join(redir_name);
-                if let Ok(redirect_out) = OpenOptions::new().create_new(true)
-                                                            .write(true)
-                                                            .open(&redir_dst) {
-                    let mut redirect_out = BufWriter::new(redirect_out);
-                    try_err!(layout::redirect(&mut redirect_out, file_name), &redir_dst);
+                if self.shared.generate_redirect_pages {
+                    // Redirect from a sane URL using the namespace to Rustdoc's
+                    // URL for the page.
+                    let redir_name = format!("{}.{}.html", name, item_type.name_space());
+                    let redir_dst = self.dst.join(redir_name);
+                    if let Ok(redirect_out) = OpenOptions::new().create_new(true)
+                                                                .write(true)
+                                                                .open(&redir_dst) {
+                        let mut redirect_out = BufWriter::new(redirect_out);
+                        try_err!(layout::redirect(&mut redirect_out, file_name), &redir_dst);
+                    }
                 }
-
                 // If the item is a macro, redirect from the old macro URL (with !)
                 // to the new one (without).
                 if item_type == ItemType::Macro {
@@ -2293,7 +2303,7 @@ fn build_sidebar_items(&self, m: &clean::Module) -> BTreeMap<String, Vec<NameDoc
 }
 
 impl<'a> Item<'a> {
-    /// Generate a url appropriate for an `href` attribute back to the source of
+    /// Generates a url appropriate for an `href` attribute back to the source of
     /// this item.
     ///
     /// The url generated, when clicked, will redirect the browser back to the
@@ -2419,6 +2429,7 @@ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
             clean::ForeignTypeItem => write!(fmt, "Foreign Type ")?,
             clean::KeywordItem(..) => write!(fmt, "Keyword ")?,
             clean::ExistentialItem(..) => write!(fmt, "Existential Type ")?,
+            clean::TraitAliasItem(..) => write!(fmt, "Trait Alias ")?,
             _ => {
                 // We don't generate pages for any other type.
                 unreachable!();
@@ -2457,6 +2468,7 @@ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
             clean::ForeignTypeItem => item_foreign_type(fmt, self.cx, self.item),
             clean::KeywordItem(ref k) => item_keyword(fmt, self.cx, self.item, k),
             clean::ExistentialItem(ref e, _) => item_existential(fmt, self.cx, self.item, e),
+            clean::TraitAliasItem(ref ta) => item_trait_alias(fmt, self.cx, self.item, ta),
             _ => {
                 // We don't generate pages for any other type.
                 unreachable!();
@@ -2816,7 +2828,17 @@ fn tag_html(class: &str, contents: &str) -> String {
 
     // The trailing space after each tag is to space it properly against the rest of the docs.
     if item.deprecation().is_some() {
-        tags += &tag_html("deprecated", "Deprecated");
+        let mut message = "Deprecated";
+        if let Some(ref stab) = item.stability {
+            if let Some(ref depr) = stab.deprecation {
+                if let Some(ref since) = depr.since {
+                    if !stability::deprecation_in_effect(&since) {
+                        message = "Deprecation planned";
+                    }
+                }
+            }
+        }
+        tags += &tag_html("deprecated", message);
     }
 
     if let Some(stab) = item
@@ -2844,16 +2866,23 @@ fn short_stability(item: &clean::Item, cx: &Context) -> Vec<String> {
     let mut stability = vec![];
     let error_codes = ErrorCodes::from(UnstableFeatures::from_environment().is_nightly_build());
 
-    if let Some(Deprecation { since, note }) = &item.deprecation() {
+    if let Some(Deprecation { note, since }) = &item.deprecation() {
+        // We display deprecation messages for #[deprecated] and #[rustc_deprecated]
+        // but only display the future-deprecation messages for #[rustc_deprecated].
         let mut message = if let Some(since) = since {
-            if stability::deprecation_in_effect(since) {
-                format!("Deprecated since {}", Escape(since))
-            } else {
-                format!("Deprecating in {}", Escape(since))
-            }
+            format!("Deprecated since {}", Escape(since))
         } else {
             String::from("Deprecated")
         };
+        if let Some(ref stab) = item.stability {
+            if let Some(ref depr) = stab.deprecation {
+                if let Some(ref since) = depr.since {
+                    if !stability::deprecation_in_effect(&since) {
+                        message = format!("Deprecating in {}", Escape(&since));
+                    }
+                }
+            }
+        }
 
         if let Some(note) = note {
             let mut ids = cx.id_map.borrow_mut();
@@ -2976,10 +3005,11 @@ fn item_function(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
            name = it.name.as_ref().unwrap(),
            generics = f.generics,
            where_clause = WhereClause { gens: &f.generics, indent: 0, end_newline: true },
-           decl = Method {
+           decl = Function {
               decl: &f.decl,
               name_len,
               indent: 0,
+              asyncness: f.header.asyncness,
            })?;
     document(w, cx, it)
 }
@@ -3013,23 +3043,17 @@ fn render_impls(cx: &Context, w: &mut fmt::Formatter,
     Ok(())
 }
 
-fn bounds(t_bounds: &[clean::GenericBound]) -> String {
+fn bounds(t_bounds: &[clean::GenericBound], trait_alias: bool) -> String {
     let mut bounds = String::new();
-    let mut bounds_plain = String::new();
     if !t_bounds.is_empty() {
-        if !bounds.is_empty() {
-            bounds.push(' ');
-            bounds_plain.push(' ');
+        if !trait_alias {
+            bounds.push_str(": ");
         }
-        bounds.push_str(": ");
-        bounds_plain.push_str(": ");
         for (i, p) in t_bounds.iter().enumerate() {
             if i > 0 {
                 bounds.push_str(" + ");
-                bounds_plain.push_str(" + ");
             }
             bounds.push_str(&(*p).to_string());
-            bounds_plain.push_str(&format!("{:#}", *p));
         }
     }
     bounds
@@ -3049,7 +3073,7 @@ fn item_trait(
     it: &clean::Item,
     t: &clean::Trait,
 ) -> fmt::Result {
-    let bounds = bounds(&t.bounds);
+    let bounds = bounds(&t.bounds, false);
     let types = t.items.iter().filter(|m| m.is_associated_type()).collect::<Vec<_>>();
     let consts = t.items.iter().filter(|m| m.is_associated_const()).collect::<Vec<_>>();
     let required = t.items.iter().filter(|m| m.is_ty_method()).collect::<Vec<_>>();
@@ -3423,10 +3447,11 @@ fn method(w: &mut fmt::Formatter,
                href = href,
                name = name,
                generics = *g,
-               decl = Method {
+               decl = Function {
                    decl: d,
                    name_len: head_len,
                    indent,
+                   asyncness: header.asyncness,
                },
                where_clause = WhereClause {
                    gens: g,
@@ -4279,7 +4304,26 @@ fn item_existential(
            it.name.as_ref().unwrap(),
            t.generics,
            where_clause = WhereClause { gens: &t.generics, indent: 0, end_newline: true },
-           bounds = bounds(&t.bounds))?;
+           bounds = bounds(&t.bounds, false))?;
+
+    document(w, cx, it)?;
+
+    // Render any items associated directly to this alias, as otherwise they
+    // won't be visible anywhere in the docs. It would be nice to also show
+    // associated items from the aliased type (see discussion in #32077), but
+    // we need #14072 to make sense of the generics.
+    render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)
+}
+
+fn item_trait_alias(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
+                    t: &clean::TraitAlias) -> fmt::Result {
+    write!(w, "<pre class='rust trait-alias'>")?;
+    render_attributes(w, it)?;
+    write!(w, "trait {}{}{} = {};</pre>",
+           it.name.as_ref().unwrap(),
+           t.generics,
+           WhereClause { gens: &t.generics, indent: 0, end_newline: true },
+           bounds(&t.bounds, true))?;
 
     document(w, cx, it)?;
 
@@ -4843,6 +4887,7 @@ fn item_ty_to_strs(ty: &ItemType) -> (&'static str, &'static str) {
         ItemType::Existential     => ("existentials", "Existentials"),
         ItemType::ProcAttribute   => ("attributes", "Attribute Macros"),
         ItemType::ProcDerive      => ("derives", "Derive Macros"),
+        ItemType::TraitAlias      => ("trait-aliases", "Trait aliases"),
     }
 }