Skip to content

Commit 54831f1

Browse files
committed
rustdoc: Render where clauses as appropriate
Fix rust-lang#16546
1 parent 5e13d3a commit 54831f1

File tree

6 files changed

+131
-21
lines changed

6 files changed

+131
-21
lines changed

src/librustdoc/clean/mod.rs

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -641,18 +641,35 @@ impl Clean<Option<Lifetime>> for ty::Region {
641641
}
642642
}
643643

644+
#[deriving(Clone, Encodable, Decodable, PartialEq)]
645+
pub struct WherePredicate {
646+
pub name: String,
647+
pub bounds: Vec<TyParamBound>
648+
}
649+
650+
impl Clean<WherePredicate> for ast::WherePredicate {
651+
fn clean(&self, cx: &DocContext) -> WherePredicate {
652+
WherePredicate {
653+
name: self.ident.clean(cx),
654+
bounds: self.bounds.clean(cx)
655+
}
656+
}
657+
}
658+
644659
// maybe use a Generic enum and use ~[Generic]?
645660
#[deriving(Clone, Encodable, Decodable, PartialEq)]
646661
pub struct Generics {
647662
pub lifetimes: Vec<Lifetime>,
648663
pub type_params: Vec<TyParam>,
664+
pub where_predicates: Vec<WherePredicate>
649665
}
650666

651667
impl Clean<Generics> for ast::Generics {
652668
fn clean(&self, cx: &DocContext) -> Generics {
653669
Generics {
654670
lifetimes: self.lifetimes.clean(cx),
655671
type_params: self.ty_params.clean(cx),
672+
where_predicates: self.where_clause.predicates.clean(cx)
656673
}
657674
}
658675
}
@@ -663,6 +680,7 @@ impl<'a> Clean<Generics> for (&'a ty::Generics, subst::ParamSpace) {
663680
Generics {
664681
type_params: me.types.get_slice(space).to_vec().clean(cx),
665682
lifetimes: me.regions.get_slice(space).to_vec().clean(cx),
683+
where_predicates: vec![]
666684
}
667685
}
668686
}
@@ -1260,7 +1278,9 @@ impl Clean<Type> for ty::t {
12601278
ty::ty_bare_fn(ref fty) => BareFunction(box BareFunctionDecl {
12611279
fn_style: fty.fn_style,
12621280
generics: Generics {
1263-
lifetimes: Vec::new(), type_params: Vec::new()
1281+
lifetimes: Vec::new(),
1282+
type_params: Vec::new(),
1283+
where_predicates: Vec::new()
12641284
},
12651285
decl: (ast_util::local_def(0), &fty.sig).clean(cx),
12661286
abi: fty.abi.to_string(),
@@ -1670,6 +1690,7 @@ impl Clean<BareFunctionDecl> for ast::BareFnTy {
16701690
generics: Generics {
16711691
lifetimes: self.lifetimes.clean(cx),
16721692
type_params: Vec::new(),
1693+
where_predicates: Vec::new()
16731694
},
16741695
decl: self.decl.clean(cx),
16751696
abi: self.abi.to_string(),
@@ -2172,6 +2193,7 @@ impl Clean<Item> for ast::Typedef {
21722193
generics: Generics {
21732194
lifetimes: Vec::new(),
21742195
type_params: Vec::new(),
2196+
where_predicates: Vec::new()
21752197
},
21762198
}),
21772199
visibility: None,

src/librustdoc/html/format.rs

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,11 @@ pub struct RawMutableSpace(pub clean::Mutability);
4444
pub struct Stability<'a>(pub &'a Option<clean::Stability>);
4545
/// Wrapper struct for emitting the stability level concisely.
4646
pub struct ConciseStability<'a>(pub &'a Option<clean::Stability>);
47+
/// Wrapper struct for emitting a where clause from Generics.
48+
pub struct WhereClause<'a>(pub &'a clean::Generics);
49+
50+
/// Wrapper struct for emitting type parameter bounds.
51+
struct TyParamBounds<'a>(pub &'a [clean::TyParamBound]);
4752

4853
impl VisSpace {
4954
pub fn get(&self) -> Option<ast::Visibility> {
@@ -57,6 +62,19 @@ impl FnStyleSpace {
5762
}
5863
}
5964

65+
impl<'a> fmt::Show for TyParamBounds<'a> {
66+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
67+
let &TyParamBounds(bounds) = self;
68+
for (i, bound) in bounds.iter().enumerate() {
69+
if i > 0 {
70+
try!(f.write(" + ".as_bytes()));
71+
}
72+
try!(write!(f, "{}", *bound));
73+
}
74+
Ok(())
75+
}
76+
}
77+
6078
impl fmt::Show for clean::Generics {
6179
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
6280
if self.lifetimes.len() == 0 && self.type_params.len() == 0 { return Ok(()) }
@@ -73,21 +91,14 @@ impl fmt::Show for clean::Generics {
7391
if self.lifetimes.len() > 0 {
7492
try!(f.write(", ".as_bytes()));
7593
}
76-
7794
for (i, tp) in self.type_params.iter().enumerate() {
7895
if i > 0 {
7996
try!(f.write(", ".as_bytes()))
8097
}
8198
try!(f.write(tp.name.as_bytes()));
8299

83100
if tp.bounds.len() > 0 {
84-
try!(f.write(": ".as_bytes()));
85-
for (i, bound) in tp.bounds.iter().enumerate() {
86-
if i > 0 {
87-
try!(f.write(" + ".as_bytes()));
88-
}
89-
try!(write!(f, "{}", *bound));
90-
}
101+
try!(write!(f, ": {}", TyParamBounds(tp.bounds.as_slice())));
91102
}
92103

93104
match tp.default {
@@ -101,6 +112,24 @@ impl fmt::Show for clean::Generics {
101112
}
102113
}
103114

115+
impl<'a> fmt::Show for WhereClause<'a> {
116+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
117+
let &WhereClause(gens) = self;
118+
if gens.where_predicates.len() == 0 {
119+
return Ok(());
120+
}
121+
try!(f.write(" where ".as_bytes()));
122+
for (i, pred) in gens.where_predicates.iter().enumerate() {
123+
if i > 0 {
124+
try!(f.write(", ".as_bytes()));
125+
}
126+
let bounds = pred.bounds.as_slice();
127+
try!(write!(f, "{}: {}", pred.name, TyParamBounds(bounds)));
128+
}
129+
Ok(())
130+
}
131+
}
132+
104133
impl fmt::Show for clean::Lifetime {
105134
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
106135
try!(f.write(self.get_ref().as_bytes()));

src/librustdoc/html/render.rs

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ use clean;
5656
use doctree;
5757
use fold::DocFolder;
5858
use html::format::{VisSpace, Method, FnStyleSpace, MutableSpace, Stability};
59-
use html::format::{ConciseStability};
59+
use html::format::{ConciseStability, WhereClause};
6060
use html::highlight;
6161
use html::item_type::{ItemType, shortty};
6262
use html::item_type;
@@ -1609,11 +1609,12 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context,
16091609
fn item_function(w: &mut fmt::Formatter, it: &clean::Item,
16101610
f: &clean::Function) -> fmt::Result {
16111611
try!(write!(w, "<pre class='rust fn'>{vis}{fn_style}fn \
1612-
{name}{generics}{decl}</pre>",
1612+
{name}{generics}{decl}{where_clause}</pre>",
16131613
vis = VisSpace(it.visibility),
16141614
fn_style = FnStyleSpace(f.fn_style),
16151615
name = it.name.get_ref().as_slice(),
16161616
generics = f.generics,
1617+
where_clause = WhereClause(&f.generics),
16171618
decl = f.decl));
16181619
document(w, it)
16191620
}
@@ -1630,11 +1631,12 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
16301631
}
16311632

16321633
// Output the trait definition
1633-
try!(write!(w, "<pre class='rust trait'>{}trait {}{}{} ",
1634+
try!(write!(w, "<pre class='rust trait'>{}trait {}{}{}{} ",
16341635
VisSpace(it.visibility),
16351636
it.name.get_ref().as_slice(),
16361637
t.generics,
1637-
bounds));
1638+
bounds,
1639+
WhereClause(&t.generics)));
16381640
let required = t.items.iter()
16391641
.filter(|m| {
16401642
match **m {
@@ -1718,9 +1720,9 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
17181720
match cache.implementors.find(&it.def_id) {
17191721
Some(implementors) => {
17201722
for i in implementors.iter() {
1721-
try!(writeln!(w, "<li>{}<code>impl{} {} for {}</code></li>",
1723+
try!(writeln!(w, "<li>{}<code>impl{} {} for {}{}</code></li>",
17221724
ConciseStability(&i.stability),
1723-
i.generics, i.trait_, i.for_));
1725+
i.generics, i.trait_, i.for_, WhereClause(&i.generics)));
17241726
}
17251727
}
17261728
None => {}
@@ -1746,15 +1748,16 @@ fn render_method(w: &mut fmt::Formatter, meth: &clean::Item) -> fmt::Result {
17461748
g: &clean::Generics, selfty: &clean::SelfTy,
17471749
d: &clean::FnDecl) -> fmt::Result {
17481750
write!(w, "{}fn <a href='#{ty}.{name}' class='fnname'>{name}</a>\
1749-
{generics}{decl}",
1751+
{generics}{decl}{where_clause}",
17501752
match fn_style {
17511753
ast::UnsafeFn => "unsafe ",
17521754
_ => "",
17531755
},
17541756
ty = shortty(it),
17551757
name = it.name.get_ref().as_slice(),
17561758
generics = *g,
1757-
decl = Method(selfty, d))
1759+
decl = Method(selfty, d),
1760+
where_clause = WhereClause(g))
17581761
}
17591762
match meth.inner {
17601763
clean::TyMethodItem(ref m) => {
@@ -1809,10 +1812,11 @@ fn item_struct(w: &mut fmt::Formatter, it: &clean::Item,
18091812

18101813
fn item_enum(w: &mut fmt::Formatter, it: &clean::Item,
18111814
e: &clean::Enum) -> fmt::Result {
1812-
try!(write!(w, "<pre class='rust enum'>{}enum {}{}",
1815+
try!(write!(w, "<pre class='rust enum'>{}enum {}{}{}",
18131816
VisSpace(it.visibility),
18141817
it.name.get_ref().as_slice(),
1815-
e.generics));
1818+
e.generics,
1819+
WhereClause(&e.generics)));
18161820
if e.variants.len() == 0 && !e.variants_stripped {
18171821
try!(write!(w, " {{}}"));
18181822
} else {
@@ -1916,7 +1920,7 @@ fn render_struct(w: &mut fmt::Formatter, it: &clean::Item,
19161920
if structhead {"struct "} else {""},
19171921
it.name.get_ref().as_slice()));
19181922
match g {
1919-
Some(g) => try!(write!(w, "{}", *g)),
1923+
Some(g) => try!(write!(w, "{}{}", *g, WhereClause(g))),
19201924
None => {}
19211925
}
19221926
match ty {
@@ -2008,7 +2012,7 @@ fn render_impl(w: &mut fmt::Formatter, i: &Impl) -> fmt::Result {
20082012
Some(ref ty) => try!(write!(w, "{} for ", *ty)),
20092013
None => {}
20102014
}
2011-
try!(write!(w, "{}</code></h3>", i.impl_.for_));
2015+
try!(write!(w, "{}{}</code></h3>", i.impl_.for_, WhereClause(&i.impl_.generics)));
20122016
match i.dox {
20132017
Some(ref dox) => {
20142018
try!(write!(w, "<div class='docblock'>{}</div>",
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
-include ../tools.mk
2+
3+
all: verify.sh foo.rs
4+
$(HOST_RPATH_ENV) $(RUSTDOC) -w html -o $(TMPDIR)/doc foo.rs
5+
cp verify.sh $(TMPDIR)
6+
$(call RUN,verify.sh) $(TMPDIR)
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
pub trait MyTrait {}
12+
13+
pub struct Alpha<A> where A: MyTrait;
14+
pub trait Bravo<B> where B: MyTrait {}
15+
pub fn charlie<C>() where C: MyTrait {}
16+
17+
pub struct Delta<D>;
18+
impl<D> Delta<D> where D: MyTrait {
19+
pub fn delta() {}
20+
}
21+
22+
pub struct Echo<E>;
23+
impl<E> MyTrait for Echo<E> where E: MyTrait {}
24+
25+
pub enum Foxtrot<F> {}
26+
impl<F> MyTrait for Foxtrot<F> where F: MyTrait {}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#!/bin/bash
2+
set -e
3+
4+
# $1 is the TMPDIR
5+
DOC=$1/doc/foo
6+
7+
grep "Alpha.*where.*A:.*MyTrait" $DOC/struct.Alpha.html > /dev/null
8+
echo "Alpha"
9+
grep "Bravo.*where.*B:.*MyTrait" $DOC/trait.Bravo.html > /dev/null
10+
echo "Bravo"
11+
grep "charlie.*where.*C:.*MyTrait" $DOC/fn.charlie.html > /dev/null
12+
echo "Charlie"
13+
grep "impl.*Delta.*where.*D:.*MyTrait" $DOC/struct.Delta.html > /dev/null
14+
echo "Delta"
15+
grep "impl.*MyTrait.*for.*Echo.*where.*E:.*MyTrait" $DOC/struct.Echo.html > /dev/null
16+
echo "Echo"
17+
grep "impl.*MyTrait.*for.*Foxtrot.*where.*F:.*MyTrait" $DOC/enum.Foxtrot.html > /dev/null
18+
echo "Foxtrot"
19+
20+
# check "Implementors" section of MyTrait
21+
grep "impl.*MyTrait.*for.*Echo.*where.*E:.*MyTrait" $DOC/trait.MyTrait.html > /dev/null
22+
grep "impl.*MyTrait.*for.*Foxtrot.*where.*F:.*MyTrait" $DOC/trait.MyTrait.html > /dev/null
23+
echo "Implementors OK"

0 commit comments

Comments
 (0)