]> git.lizzy.rs Git - rust.git/commitdiff
rustdoc: add new "Implementations on Foreign Types" section to traits
authorQuietMisdreavus <grey@quietmisdreavus.net>
Tue, 8 Aug 2017 20:22:04 +0000 (15:22 -0500)
committerQuietMisdreavus <grey@quietmisdreavus.net>
Tue, 5 Sep 2017 16:21:14 +0000 (11:21 -0500)
src/librustdoc/clean/mod.rs
src/librustdoc/html/render.rs

index aab44ddce0e6af711a15d6c6e5c68f0b0df8cead..60651bd617f959066d3bdf080145be4c08e4a3f5 100644 (file)
@@ -1651,6 +1651,16 @@ impl GetDefId for Type {
     fn def_id(&self) -> Option<DefId> {
         match *self {
             ResolvedPath { did, .. } => Some(did),
+            Primitive(p) => ::html::render::cache().primitive_locations.get(&p).cloned(),
+            BorrowedRef { type_: box Generic(..), .. } =>
+                Primitive(PrimitiveType::Reference).def_id(),
+            BorrowedRef { ref type_, .. } => type_.def_id(),
+            Tuple(..) => Primitive(PrimitiveType::Tuple).def_id(),
+            BareFunction(..) => Primitive(PrimitiveType::Fn).def_id(),
+            Slice(..) => Primitive(PrimitiveType::Slice).def_id(),
+            Array(..) => Primitive(PrimitiveType::Array).def_id(),
+            RawPointer(..) => Primitive(PrimitiveType::RawPointer).def_id(),
+            QPath { ref self_type, .. } => self_type.def_id(),
             _ => None,
         }
     }
index cc84e340c74f8bf1b6fdd937bb9f19dbdd534262..8e0ce73c4ad429f3065cd6ec8cc2e60aa1d84c80 100644 (file)
@@ -2416,12 +2416,12 @@ fn trait_item(w: &mut fmt::Formatter, cx: &Context, m: &clean::Item, t: &clean::
     render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)?;
 
     let cache = cache();
-    write!(w, "
+    let impl_header = "
         <h2 id='implementors' class='small-section-header'>
           Implementors<a href='#implementors' class='anchor'></a>
         </h2>
         <ul class='item-list' id='implementors-list'>
-    ")?;
+    ";
     if let Some(implementors) = cache.implementors.get(&it.def_id) {
         // The DefId is for the first Type found with that name. The bool is
         // if any Types with the same name but different DefId have been found.
@@ -2443,7 +2443,38 @@ fn trait_item(w: &mut fmt::Formatter, cx: &Context, m: &clean::Item, t: &clean::
             }
         }
 
-        for implementor in implementors {
+        let (local, foreign) = implementors.iter()
+            .partition::<Vec<_>, _>(|i| i.impl_.for_.def_id()
+                                         .map_or(true, |d| cache.paths.contains_key(&d)));
+
+        if !foreign.is_empty() {
+            write!(w, "
+                <h2 id='foreign-impls' class='section-header'>
+                  Implementations on Foreign Types<a href='#foreign-impls' class='anchor'></a>
+                </h2>
+            ")?;
+
+            for implementor in foreign {
+                // need to get from a clean::Impl to a clean::Item so i can use render_impl
+                if let Some(t_did) = implementor.impl_.for_.def_id() {
+                    if let Some(impl_item) = cache.impls.get(&t_did).and_then(|i| i.iter()
+                        .find(|i| i.impl_item.def_id == implementor.def_id))
+                    {
+                        let i = &impl_item.impl_item;
+                        let impl_ = Impl { impl_item: i.clone() };
+                        let assoc_link = AssocItemLink::GotoSource(
+                            i.def_id, &implementor.impl_.provided_trait_methods
+                        );
+                        render_impl(w, cx, &impl_, assoc_link,
+                                    RenderMode::Normal, i.stable_since(), false)?;
+                    }
+                }
+            }
+        }
+
+        write!(w, "{}", impl_header)?;
+
+        for implementor in local {
             write!(w, "<li><code>")?;
             // If there's already another implementor that has the same abbridged name, use the
             // full path, for example in `std::iter::ExactSizeIterator`
@@ -2465,6 +2496,10 @@ fn trait_item(w: &mut fmt::Formatter, cx: &Context, m: &clean::Item, t: &clean::
             }
             writeln!(w, "</code></li>")?;
         }
+    } else {
+        // even without any implementations to write in, we still want the heading and list, so the
+        // implementors javascript file pulled in below has somewhere to write the impls into
+        write!(w, "{}", impl_header)?;
     }
     write!(w, "</ul>")?;
     write!(w, r#"<script type="text/javascript" async
@@ -3069,7 +3104,7 @@ fn render_assoc_items(w: &mut fmt::Formatter,
         };
         for i in &non_trait {
             render_impl(w, cx, i, AssocItemLink::Anchor(None), render_mode,
-                        containing_item.stable_since())?;
+                        containing_item.stable_since(), true)?;
         }
     }
     if let AssocItemRender::DerefFor { .. } = what {
@@ -3094,7 +3129,7 @@ fn render_assoc_items(w: &mut fmt::Formatter,
             let did = i.trait_did().unwrap();
             let assoc_link = AssocItemLink::GotoSource(did, &i.inner_impl().provided_trait_methods);
             render_impl(w, cx, i, assoc_link,
-                        RenderMode::Normal, containing_item.stable_since())?;
+                        RenderMode::Normal, containing_item.stable_since(), true)?;
         }
     }
     Ok(())
@@ -3124,7 +3159,8 @@ fn render_deref_methods(w: &mut fmt::Formatter, cx: &Context, impl_: &Impl,
 }
 
 fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLink,
-               render_mode: RenderMode, outer_version: Option<&str>) -> fmt::Result {
+               render_mode: RenderMode, outer_version: Option<&str>,
+               show_def_docs: bool) -> fmt::Result {
     if render_mode == RenderMode::Normal {
         let id = derive_id(match i.inner_impl().trait_ {
             Some(ref t) => format!("impl-{}", Escape(&format!("{:#}", t))),
@@ -3153,7 +3189,7 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi
     fn doc_impl_item(w: &mut fmt::Formatter, cx: &Context, item: &clean::Item,
                      link: AssocItemLink, render_mode: RenderMode,
                      is_default_item: bool, outer_version: Option<&str>,
-                     trait_: Option<&clean::Trait>) -> fmt::Result {
+                     trait_: Option<&clean::Trait>, show_def_docs: bool) -> fmt::Result {
         let item_type = item.type_();
         let name = item.name.as_ref().unwrap();
 
@@ -3248,7 +3284,7 @@ fn doc_impl_item(w: &mut fmt::Formatter, cx: &Context, item: &clean::Item,
                         document_stability(w, cx, it)?;
                         if item.doc_value().is_some() {
                             document_full(w, item, cx, &prefix)?;
-                        } else {
+                        } else if show_def_docs {
                             // In case the item isn't documented,
                             // provide short documentation from the trait.
                             document_short(w, it, link, cx, &prefix)?;
@@ -3256,11 +3292,15 @@ fn doc_impl_item(w: &mut fmt::Formatter, cx: &Context, item: &clean::Item,
                     }
                 } else {
                     document_stability(w, cx, item)?;
-                    document_full(w, item, cx, &prefix)?;
+                    if show_def_docs {
+                        document_full(w, item, cx, &prefix)?;
+                    }
                 }
             } else {
                 document_stability(w, cx, item)?;
-                document_short(w, item, link, cx, &prefix)?;
+                if show_def_docs {
+                    document_short(w, item, link, cx, &prefix)?;
+                }
             }
         }
         Ok(())
@@ -3272,7 +3312,7 @@ fn doc_impl_item(w: &mut fmt::Formatter, cx: &Context, item: &clean::Item,
     write!(w, "<div class='impl-items'>")?;
     for trait_item in &i.inner_impl().items {
         doc_impl_item(w, cx, trait_item, link, render_mode,
-                      false, outer_version, trait_)?;
+                      false, outer_version, trait_, show_def_docs)?;
     }
 
     fn render_default_items(w: &mut fmt::Formatter,
@@ -3280,7 +3320,8 @@ fn render_default_items(w: &mut fmt::Formatter,
                             t: &clean::Trait,
                             i: &clean::Impl,
                             render_mode: RenderMode,
-                            outer_version: Option<&str>) -> fmt::Result {
+                            outer_version: Option<&str>,
+                            show_def_docs: bool) -> fmt::Result {
         for trait_item in &t.items {
             let n = trait_item.name.clone();
             if i.items.iter().find(|m| m.name == n).is_some() {
@@ -3290,7 +3331,7 @@ fn render_default_items(w: &mut fmt::Formatter,
             let assoc_link = AssocItemLink::GotoSource(did, &i.provided_trait_methods);
 
             doc_impl_item(w, cx, trait_item, assoc_link, render_mode, true,
-                          outer_version, None)?;
+                          outer_version, None, show_def_docs)?;
         }
         Ok(())
     }
@@ -3298,7 +3339,8 @@ fn render_default_items(w: &mut fmt::Formatter,
     // If we've implemented a trait, then also emit documentation for all
     // default items which weren't overridden in the implementation block.
     if let Some(t) = trait_ {
-        render_default_items(w, cx, t, &i.inner_impl(), render_mode, outer_version)?;
+        render_default_items(w, cx, t, &i.inner_impl(),
+                             render_mode, outer_version, show_def_docs)?;
     }
     write!(w, "</div>")?;
     Ok(())