about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2014-09-29 08:10:47 -0700
committerAlex Crichton <alex@alexcrichton.com>2014-09-29 08:10:47 -0700
commit6c23789ad1f62e39220e5e178928ecdad9db2a38 (patch)
tree571b63ca082e79600f9403d18f14ca5b959c88aa
parent655b7269c865b8ff446296bdb7640c6ad5c4f965 (diff)
parent54831f128fac3ad92bd7244aafaf52763452e51b (diff)
downloadrust-6c23789ad1f62e39220e5e178928ecdad9db2a38.tar.gz
rust-6c23789ad1f62e39220e5e178928ecdad9db2a38.zip
rollup merge of #17531 : tomjakubowski/rustdoc-where-clauses
-rw-r--r--src/librustdoc/clean/mod.rs24
-rw-r--r--src/librustdoc/html/format.rs45
-rw-r--r--src/librustdoc/html/render.rs28
-rw-r--r--src/test/run-make/rustdoc-where/Makefile6
-rw-r--r--src/test/run-make/rustdoc-where/foo.rs26
-rwxr-xr-xsrc/test/run-make/rustdoc-where/verify.sh23
6 files changed, 131 insertions, 21 deletions
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 5ac7baaa6d1..666be2debda 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -641,11 +641,27 @@ impl Clean<Option<Lifetime>> for ty::Region {
     }
 }
 
+#[deriving(Clone, Encodable, Decodable, PartialEq)]
+pub struct WherePredicate {
+    pub name: String,
+    pub bounds: Vec<TyParamBound>
+}
+
+impl Clean<WherePredicate> for ast::WherePredicate {
+    fn clean(&self, cx: &DocContext) -> WherePredicate {
+        WherePredicate {
+            name: self.ident.clean(cx),
+            bounds: self.bounds.clean(cx)
+        }
+    }
+}
+
 // maybe use a Generic enum and use ~[Generic]?
 #[deriving(Clone, Encodable, Decodable, PartialEq)]
 pub struct Generics {
     pub lifetimes: Vec<Lifetime>,
     pub type_params: Vec<TyParam>,
+    pub where_predicates: Vec<WherePredicate>
 }
 
 impl Clean<Generics> for ast::Generics {
@@ -653,6 +669,7 @@ impl Clean<Generics> for ast::Generics {
         Generics {
             lifetimes: self.lifetimes.clean(cx),
             type_params: self.ty_params.clean(cx),
+            where_predicates: self.where_clause.predicates.clean(cx)
         }
     }
 }
@@ -663,6 +680,7 @@ impl<'a> Clean<Generics> for (&'a ty::Generics, subst::ParamSpace) {
         Generics {
             type_params: me.types.get_slice(space).to_vec().clean(cx),
             lifetimes: me.regions.get_slice(space).to_vec().clean(cx),
+            where_predicates: vec![]
         }
     }
 }
@@ -1260,7 +1278,9 @@ impl Clean<Type> for ty::t {
             ty::ty_bare_fn(ref fty) => BareFunction(box BareFunctionDecl {
                 fn_style: fty.fn_style,
                 generics: Generics {
-                    lifetimes: Vec::new(), type_params: Vec::new()
+                    lifetimes: Vec::new(),
+                    type_params: Vec::new(),
+                    where_predicates: Vec::new()
                 },
                 decl: (ast_util::local_def(0), &fty.sig).clean(cx),
                 abi: fty.abi.to_string(),
@@ -1670,6 +1690,7 @@ impl Clean<BareFunctionDecl> for ast::BareFnTy {
             generics: Generics {
                 lifetimes: self.lifetimes.clean(cx),
                 type_params: Vec::new(),
+                where_predicates: Vec::new()
             },
             decl: self.decl.clean(cx),
             abi: self.abi.to_string(),
@@ -2172,6 +2193,7 @@ impl Clean<Item> for ast::Typedef {
                 generics: Generics {
                     lifetimes: Vec::new(),
                     type_params: Vec::new(),
+                    where_predicates: Vec::new()
                 },
             }),
             visibility: None,
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index c807c180e64..947d9f05ae2 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -44,6 +44,11 @@ pub struct RawMutableSpace(pub clean::Mutability);
 pub struct Stability<'a>(pub &'a Option<clean::Stability>);
 /// Wrapper struct for emitting the stability level concisely.
 pub struct ConciseStability<'a>(pub &'a Option<clean::Stability>);
+/// Wrapper struct for emitting a where clause from Generics.
+pub struct WhereClause<'a>(pub &'a clean::Generics);
+
+/// Wrapper struct for emitting type parameter bounds.
+struct TyParamBounds<'a>(pub &'a [clean::TyParamBound]);
 
 impl VisSpace {
     pub fn get(&self) -> Option<ast::Visibility> {
@@ -57,6 +62,19 @@ impl FnStyleSpace {
     }
 }
 
+impl<'a> fmt::Show for TyParamBounds<'a> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        let &TyParamBounds(bounds) = self;
+        for (i, bound) in bounds.iter().enumerate() {
+            if i > 0 {
+                try!(f.write(" + ".as_bytes()));
+            }
+            try!(write!(f, "{}", *bound));
+        }
+        Ok(())
+    }
+}
+
 impl fmt::Show for clean::Generics {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         if self.lifetimes.len() == 0 && self.type_params.len() == 0 { return Ok(()) }
@@ -73,7 +91,6 @@ impl fmt::Show for clean::Generics {
             if self.lifetimes.len() > 0 {
                 try!(f.write(", ".as_bytes()));
             }
-
             for (i, tp) in self.type_params.iter().enumerate() {
                 if i > 0 {
                     try!(f.write(", ".as_bytes()))
@@ -81,13 +98,7 @@ impl fmt::Show for clean::Generics {
                 try!(f.write(tp.name.as_bytes()));
 
                 if tp.bounds.len() > 0 {
-                    try!(f.write(": ".as_bytes()));
-                    for (i, bound) in tp.bounds.iter().enumerate() {
-                        if i > 0 {
-                            try!(f.write(" + ".as_bytes()));
-                        }
-                        try!(write!(f, "{}", *bound));
-                    }
+                    try!(write!(f, ": {}", TyParamBounds(tp.bounds.as_slice())));
                 }
 
                 match tp.default {
@@ -101,6 +112,24 @@ impl fmt::Show for clean::Generics {
     }
 }
 
+impl<'a> fmt::Show for WhereClause<'a> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        let &WhereClause(gens) = self;
+        if gens.where_predicates.len() == 0 {
+            return Ok(());
+        }
+        try!(f.write(" where ".as_bytes()));
+        for (i, pred) in gens.where_predicates.iter().enumerate() {
+            if i > 0 {
+                try!(f.write(", ".as_bytes()));
+            }
+            let bounds = pred.bounds.as_slice();
+            try!(write!(f, "{}: {}", pred.name, TyParamBounds(bounds)));
+        }
+        Ok(())
+    }
+}
+
 impl fmt::Show for clean::Lifetime {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         try!(f.write(self.get_ref().as_bytes()));
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index 3cd3fe3053a..8668e684c2d 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -56,7 +56,7 @@ use clean;
 use doctree;
 use fold::DocFolder;
 use html::format::{VisSpace, Method, FnStyleSpace, MutableSpace, Stability};
-use html::format::{ConciseStability};
+use html::format::{ConciseStability, WhereClause};
 use html::highlight;
 use html::item_type::{ItemType, shortty};
 use html::item_type;
@@ -1610,11 +1610,12 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context,
 fn item_function(w: &mut fmt::Formatter, it: &clean::Item,
                  f: &clean::Function) -> fmt::Result {
     try!(write!(w, "<pre class='rust fn'>{vis}{fn_style}fn \
-                    {name}{generics}{decl}</pre>",
+                    {name}{generics}{decl}{where_clause}</pre>",
            vis = VisSpace(it.visibility),
            fn_style = FnStyleSpace(f.fn_style),
            name = it.name.get_ref().as_slice(),
            generics = f.generics,
+           where_clause = WhereClause(&f.generics),
            decl = f.decl));
     document(w, it)
 }
@@ -1631,11 +1632,12 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
     }
 
     // Output the trait definition
-    try!(write!(w, "<pre class='rust trait'>{}trait {}{}{} ",
+    try!(write!(w, "<pre class='rust trait'>{}trait {}{}{}{} ",
                   VisSpace(it.visibility),
                   it.name.get_ref().as_slice(),
                   t.generics,
-                  bounds));
+                  bounds,
+                  WhereClause(&t.generics)));
     let required = t.items.iter()
                           .filter(|m| {
                               match **m {
@@ -1719,9 +1721,9 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
     match cache.implementors.find(&it.def_id) {
         Some(implementors) => {
             for i in implementors.iter() {
-                try!(writeln!(w, "<li>{}<code>impl{} {} for {}</code></li>",
+                try!(writeln!(w, "<li>{}<code>impl{} {} for {}{}</code></li>",
                               ConciseStability(&i.stability),
-                              i.generics, i.trait_, i.for_));
+                              i.generics, i.trait_, i.for_, WhereClause(&i.generics)));
             }
         }
         None => {}
@@ -1747,7 +1749,7 @@ fn render_method(w: &mut fmt::Formatter, meth: &clean::Item) -> fmt::Result {
            g: &clean::Generics, selfty: &clean::SelfTy,
            d: &clean::FnDecl) -> fmt::Result {
         write!(w, "{}fn <a href='#{ty}.{name}' class='fnname'>{name}</a>\
-                   {generics}{decl}",
+                   {generics}{decl}{where_clause}",
                match fn_style {
                    ast::UnsafeFn => "unsafe ",
                    _ => "",
@@ -1755,7 +1757,8 @@ fn render_method(w: &mut fmt::Formatter, meth: &clean::Item) -> fmt::Result {
                ty = shortty(it),
                name = it.name.get_ref().as_slice(),
                generics = *g,
-               decl = Method(selfty, d))
+               decl = Method(selfty, d),
+               where_clause = WhereClause(g))
     }
     match meth.inner {
         clean::TyMethodItem(ref m) => {
@@ -1810,10 +1813,11 @@ fn item_struct(w: &mut fmt::Formatter, it: &clean::Item,
 
 fn item_enum(w: &mut fmt::Formatter, it: &clean::Item,
              e: &clean::Enum) -> fmt::Result {
-    try!(write!(w, "<pre class='rust enum'>{}enum {}{}",
+    try!(write!(w, "<pre class='rust enum'>{}enum {}{}{}",
                   VisSpace(it.visibility),
                   it.name.get_ref().as_slice(),
-                  e.generics));
+                  e.generics,
+                  WhereClause(&e.generics)));
     if e.variants.len() == 0 && !e.variants_stripped {
         try!(write!(w, " {{}}"));
     } else {
@@ -1917,7 +1921,7 @@ fn render_struct(w: &mut fmt::Formatter, it: &clean::Item,
                   if structhead {"struct "} else {""},
                   it.name.get_ref().as_slice()));
     match g {
-        Some(g) => try!(write!(w, "{}", *g)),
+        Some(g) => try!(write!(w, "{}{}", *g, WhereClause(g))),
         None => {}
     }
     match ty {
@@ -2009,7 +2013,7 @@ fn render_impl(w: &mut fmt::Formatter, i: &Impl) -> fmt::Result {
         Some(ref ty) => try!(write!(w, "{} for ", *ty)),
         None => {}
     }
-    try!(write!(w, "{}</code></h3>", i.impl_.for_));
+    try!(write!(w, "{}{}</code></h3>", i.impl_.for_, WhereClause(&i.impl_.generics)));
     match i.dox {
         Some(ref dox) => {
             try!(write!(w, "<div class='docblock'>{}</div>",
diff --git a/src/test/run-make/rustdoc-where/Makefile b/src/test/run-make/rustdoc-where/Makefile
new file mode 100644
index 00000000000..864d594cf99
--- /dev/null
+++ b/src/test/run-make/rustdoc-where/Makefile
@@ -0,0 +1,6 @@
+-include ../tools.mk
+
+all: verify.sh foo.rs
+	$(HOST_RPATH_ENV) $(RUSTDOC) -w html -o $(TMPDIR)/doc foo.rs
+	cp verify.sh $(TMPDIR)
+	$(call RUN,verify.sh) $(TMPDIR)
diff --git a/src/test/run-make/rustdoc-where/foo.rs b/src/test/run-make/rustdoc-where/foo.rs
new file mode 100644
index 00000000000..7e6df7f011a
--- /dev/null
+++ b/src/test/run-make/rustdoc-where/foo.rs
@@ -0,0 +1,26 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub trait MyTrait {}
+
+pub struct Alpha<A> where A: MyTrait;
+pub trait Bravo<B> where B: MyTrait {}
+pub fn charlie<C>() where C: MyTrait {}
+
+pub struct Delta<D>;
+impl<D> Delta<D> where D: MyTrait {
+    pub fn delta() {}
+}
+
+pub struct Echo<E>;
+impl<E> MyTrait for Echo<E> where E: MyTrait {}
+
+pub enum Foxtrot<F> {}
+impl<F> MyTrait for Foxtrot<F> where F: MyTrait {}
diff --git a/src/test/run-make/rustdoc-where/verify.sh b/src/test/run-make/rustdoc-where/verify.sh
new file mode 100755
index 00000000000..5d424da02ad
--- /dev/null
+++ b/src/test/run-make/rustdoc-where/verify.sh
@@ -0,0 +1,23 @@
+#!/bin/bash
+set -e
+
+# $1 is the TMPDIR
+DOC=$1/doc/foo
+
+grep "Alpha.*where.*A:.*MyTrait" $DOC/struct.Alpha.html > /dev/null
+echo "Alpha"
+grep "Bravo.*where.*B:.*MyTrait" $DOC/trait.Bravo.html > /dev/null
+echo "Bravo"
+grep "charlie.*where.*C:.*MyTrait" $DOC/fn.charlie.html > /dev/null
+echo "Charlie"
+grep "impl.*Delta.*where.*D:.*MyTrait" $DOC/struct.Delta.html > /dev/null
+echo "Delta"
+grep "impl.*MyTrait.*for.*Echo.*where.*E:.*MyTrait" $DOC/struct.Echo.html > /dev/null
+echo "Echo"
+grep "impl.*MyTrait.*for.*Foxtrot.*where.*F:.*MyTrait" $DOC/enum.Foxtrot.html > /dev/null
+echo "Foxtrot"
+
+# check "Implementors" section of MyTrait
+grep "impl.*MyTrait.*for.*Echo.*where.*E:.*MyTrait" $DOC/trait.MyTrait.html > /dev/null
+grep "impl.*MyTrait.*for.*Foxtrot.*where.*F:.*MyTrait" $DOC/trait.MyTrait.html > /dev/null
+echo "Implementors OK"