Skip to content

Commit 7f5d7e1

Browse files
committed
auto merge of #5549 : brson/rust/rustdoc, r=brson
r?
2 parents de7d558 + 4d745c2 commit 7f5d7e1

File tree

8 files changed

+224
-21
lines changed

8 files changed

+224
-21
lines changed

doc/rust.css

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,4 +101,9 @@ td {
101101
#TOC ul {
102102
list-style: none;
103103
padding-left: 0px;
104+
}
105+
106+
/* Adjust list alignment so rustdoc indexes don't align with blockquotes */
107+
div.index ul {
108+
padding-left: 1em;
104109
}

src/librustdoc/doc.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ pub struct MethodDoc {
135135
#[deriving(Eq)]
136136
pub struct ImplDoc {
137137
item: ItemDoc,
138+
bounds_str: Option<~str>,
138139
trait_types: ~[~str],
139140
self_ty: Option<~str>,
140141
methods: ~[MethodDoc]

src/librustdoc/extract.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,7 @@ fn impldoc_from_impl(
277277
) -> doc::ImplDoc {
278278
doc::ImplDoc {
279279
item: itemdoc,
280+
bounds_str: None,
280281
trait_types: ~[],
281282
self_ty: None,
282283
methods: do vec::map(methods) |method| {

src/librustdoc/markdown_index_pass.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,12 +143,16 @@ fn pandoc_header_id(header: &str) -> ~str {
143143
let s = str::replace(s, ~":", ~"");
144144
let s = str::replace(s, ~"&", ~"");
145145
let s = str::replace(s, ~"^", ~"");
146+
let s = str::replace(s, ~",", ~"");
147+
let s = str::replace(s, ~"'", ~"");
148+
let s = str::replace(s, ~"+", ~"");
146149
return s;
147150
}
148151
fn replace_with_hyphens(s: &str) -> ~str {
149152
// Collapse sequences of whitespace to a single dash
150153
// XXX: Hacky implementation here that only covers
151154
// one or two spaces.
155+
let s = str::trim(s);
152156
let s = str::replace(s, ~" ", ~"-");
153157
let s = str::replace(s, ~" ", ~"-");
154158
return s;
@@ -170,6 +174,17 @@ fn should_remove_punctuation_from_headers() {
170174
== ~"impl-of-numnum-for-int");
171175
fail_unless!(pandoc_header_id(~"impl for & condvar")
172176
== ~"impl-for-condvar");
177+
fail_unless!(pandoc_header_id(~"impl of Select<T, U> for (Left, Right)")
178+
== ~"impl-of-selectt-u-for-left-right");
179+
fail_unless!(pandoc_header_id(~"impl of Condition<'self, T, U>")
180+
== ~"impl-of-conditionself-t-u");
181+
fail_unless!(pandoc_header_id(~"impl of Condition<T: Copy + Clone>")
182+
== ~"impl-of-conditiont-copy-clone");
183+
}
184+
185+
#[test]
186+
fn should_trim_whitespace_after_removing_punctuation() {
187+
fail_unless!(pandoc_header_id("impl foo for ()") == ~"impl-foo-for");
173188
}
174189
175190
#[test]

src/librustdoc/markdown_pass.rs

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,11 @@ pub fn header_name(doc: doc::ItemTag) -> ~str {
249249
}
250250
&doc::ImplTag(ref doc) => {
251251
fail_unless!(doc.self_ty.is_some());
252+
let bounds = if (&doc.bounds_str).is_some() {
253+
fmt!(" where %s", (&doc.bounds_str).get())
254+
} else {
255+
~""
256+
};
252257
let self_ty = (&doc.self_ty).get();
253258
let mut trait_part = ~"";
254259
for doc.trait_types.eachi |i, trait_type| {
@@ -259,7 +264,7 @@ pub fn header_name(doc: doc::ItemTag) -> ~str {
259264
}
260265
trait_part += *trait_type;
261266
}
262-
fmt!("%s for %s", trait_part, self_ty)
267+
fmt!("%s for %s%s", trait_part, self_ty, bounds)
263268
}
264269
_ => {
265270
doc.name()
@@ -271,11 +276,18 @@ pub fn header_text(doc: doc::ItemTag) -> ~str {
271276
match &doc {
272277
&doc::ImplTag(ref ImplDoc) => {
273278
let header_kind = header_kind(copy doc);
279+
let bounds = if (&ImplDoc.bounds_str).is_some() {
280+
fmt!(" where `%s`", (&ImplDoc.bounds_str).get())
281+
} else {
282+
~""
283+
};
274284
let desc = if ImplDoc.trait_types.is_empty() {
275-
fmt!("for `%s`", (&ImplDoc.self_ty).get())
285+
fmt!("for `%s`%s", (&ImplDoc.self_ty).get(), bounds)
276286
} else {
277-
fmt!("of `%s` for `%s`", ImplDoc.trait_types[0],
278-
(&ImplDoc.self_ty).get())
287+
fmt!("of `%s` for `%s`%s",
288+
ImplDoc.trait_types[0],
289+
(&ImplDoc.self_ty).get(),
290+
bounds)
279291
};
280292
return fmt!("%s %s", header_kind, desc);
281293
}
@@ -424,6 +436,9 @@ fn write_index(ctxt: &Ctxt, index: doc::Index) {
424436
return;
425437
}
426438
439+
ctxt.w.put_line(~"<div class='index'>");
440+
ctxt.w.put_line(~"");
441+
427442
for index.entries.each |entry| {
428443
let header = header_text_(entry.kind, entry.name);
429444
let id = copy entry.link;
@@ -435,6 +450,8 @@ fn write_index(ctxt: &Ctxt, index: doc::Index) {
435450
}
436451
}
437452
ctxt.w.put_line(~"");
453+
ctxt.w.put_line(~"</div>");
454+
ctxt.w.put_line(~"");
438455
}
439456
440457
#[test]
@@ -749,6 +766,12 @@ fn should_write_impl_header() {
749766
fail_unless!(str::contains(markdown, ~"## Implementation for `int`"));
750767
}
751768

769+
#[test]
770+
fn should_write_impl_header_with_bounds() {
771+
let markdown = test::render(~"impl <T> int<T> { }");
772+
fail_unless!(str::contains(markdown, ~"## Implementation for `int<T>` where `<T>`"));
773+
}
774+
752775
#[test]
753776
fn should_write_impl_header_with_trait() {
754777
let markdown = test::render(~"impl j for int { fn a() { } }");

src/librustdoc/parse.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,5 +39,5 @@ pub fn from_str_sess(sess: session::Session, source: ~str) -> @ast::crate {
3939
}
4040
4141
fn cfg(sess: session::Session, input: driver::input) -> ast::crate_cfg {
42-
driver::default_configuration(sess, ~"rustdoc", input)
42+
driver::build_configuration(sess, ~"rustdoc", input)
4343
}

src/librustdoc/prune_private_pass.rs

Lines changed: 161 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
1313
use core::prelude::*;
1414

15+
use extract;
16+
use syntax::ast;
17+
use syntax::ast_map;
1518
use astsrv;
1619
use doc;
1720
use fold::Fold;
@@ -28,12 +31,73 @@ pub fn mk_pass() -> Pass {
2831
}
2932

3033
pub fn run(srv: astsrv::Srv, doc: doc::Doc) -> doc::Doc {
34+
// First strip private methods out of impls
35+
let fold = Fold {
36+
ctxt: srv.clone(),
37+
fold_impl: fold_impl,
38+
.. fold::default_any_fold(srv.clone())
39+
};
40+
let doc = (fold.fold_doc)(&fold, doc);
41+
42+
// Then strip private items and empty impls
3143
let fold = Fold {
3244
ctxt: srv.clone(),
3345
fold_mod: fold_mod,
3446
.. fold::default_any_fold(srv)
3547
};
36-
(fold.fold_doc)(&fold, doc)
48+
let doc = (fold.fold_doc)(&fold, doc);
49+
50+
return doc;
51+
}
52+
53+
fn fold_impl(
54+
fold: &fold::Fold<astsrv::Srv>,
55+
doc: doc::ImplDoc
56+
) -> doc::ImplDoc {
57+
let doc = fold::default_seq_fold_impl(fold, doc);
58+
59+
do astsrv::exec(fold.ctxt.clone()) |ctxt| {
60+
match ctxt.ast_map.get(&doc.item.id) {
61+
ast_map::node_item(item, _) => {
62+
match item.node {
63+
ast::item_impl(_, None, _, ref methods) => {
64+
// Associated impls have complex rules for method visibility
65+
strip_priv_methods(copy doc, *methods, item.vis)
66+
}
67+
ast::item_impl(_, Some(_), _ ,_) => {
68+
// Trait impls don't
69+
copy doc
70+
}
71+
_ => fail!()
72+
}
73+
}
74+
_ => fail!()
75+
}
76+
}
77+
}
78+
79+
fn strip_priv_methods(
80+
doc: doc::ImplDoc,
81+
methods: &[@ast::method],
82+
item_vis: ast::visibility
83+
) -> doc::ImplDoc {
84+
let methods = do (&doc.methods).filtered |method| {
85+
let ast_method = do methods.find |m| {
86+
extract::to_str(m.ident) == method.name
87+
};
88+
fail_unless!(ast_method.is_some());
89+
let ast_method = ast_method.unwrap();
90+
match ast_method.vis {
91+
ast::public => true,
92+
ast::private => false,
93+
ast::inherited => item_vis == ast::public
94+
}
95+
};
96+
97+
doc::ImplDoc {
98+
methods: methods,
99+
.. doc
100+
}
37101
}
38102

39103
fn fold_mod(
@@ -44,28 +108,40 @@ fn fold_mod(
44108

45109
doc::ModDoc {
46110
items: doc.items.filtered(|ItemTag| {
47-
is_visible(fold.ctxt.clone(), ItemTag.item())
111+
match ItemTag {
112+
&doc::ImplTag(ref doc) => {
113+
if doc.trait_types.is_empty() {
114+
// This is an associated impl. We have already pruned the
115+
// non-visible methods. If there are any left then
116+
// retain the impl, otherwise throw it away
117+
!doc.methods.is_empty()
118+
} else {
119+
// This is a trait implementation, make it visible
120+
// NOTE: This is not quite right since this could be an impl
121+
// of a private trait. We can't know that without running
122+
// resolve though.
123+
true
124+
}
125+
}
126+
_ => {
127+
is_visible(fold.ctxt.clone(), ItemTag.item())
128+
}
129+
}
48130
}),
49131
.. doc
50132
}
51133
}
52134

53135
fn is_visible(srv: astsrv::Srv, doc: doc::ItemDoc) -> bool {
54-
use syntax::ast_map;
55-
use syntax::ast;
56-
57136
let id = doc.id;
58137

59138
do astsrv::exec(srv) |ctxt| {
60139
match ctxt.ast_map.get(&id) {
61140
ast_map::node_item(item, _) => {
62-
match item.node {
63-
ast::item_impl(_, Some(_), _, _) => {
64-
// This is a trait implementation, make it visible
65-
// NOTE: This is not quite right since this could be an impl
66-
// of a private trait. We can't know that without running
67-
// resolve though.
68-
true
141+
match &item.node {
142+
&ast::item_impl(*) => {
143+
// Impls handled elsewhere
144+
fail!()
69145
}
70146
_ => {
71147
// Otherwise just look at the visibility
@@ -85,7 +161,8 @@ fn should_prune_items_without_pub_modifier() {
85161
}
86162

87163
#[test]
88-
fn unless_they_are_trait_impls() {
164+
fn should_not_prune_trait_impls() {
165+
// Impls are more complicated
89166
let doc = test::mk_doc(
90167
~" \
91168
trait Foo { } \
@@ -94,16 +171,87 @@ fn unless_they_are_trait_impls() {
94171
fail_unless!(!doc.cratemod().impls().is_empty());
95172
}
96173
174+
#[test]
175+
fn should_prune_associated_methods_without_vis_modifier_on_impls_without_vis_modifier() {
176+
let doc = test::mk_doc(
177+
~"impl Foo {\
178+
pub fn bar() { }\
179+
fn baz() { }\
180+
}");
181+
fail_unless!(doc.cratemod().impls()[0].methods.len() == 1);
182+
}
183+
184+
#[test]
185+
fn should_prune_priv_associated_methods_on_impls_without_vis_modifier() {
186+
let doc = test::mk_doc(
187+
~"impl Foo {\
188+
pub fn bar() { }\
189+
priv fn baz() { }\
190+
}");
191+
fail_unless!(doc.cratemod().impls()[0].methods.len() == 1);
192+
}
193+
194+
#[test]
195+
fn should_prune_priv_associated_methods_on_pub_impls() {
196+
let doc = test::mk_doc(
197+
~"pub impl Foo {\
198+
fn bar() { }\
199+
priv fn baz() { }\
200+
}");
201+
fail_unless!(doc.cratemod().impls()[0].methods.len() == 1);
202+
}
203+
204+
#[test]
205+
fn should_prune_associated_methods_without_vis_modifier_on_priv_impls() {
206+
let doc = test::mk_doc(
207+
~"priv impl Foo {\
208+
pub fn bar() { }\
209+
fn baz() { }\
210+
}");
211+
fail_unless!(doc.cratemod().impls()[0].methods.len() == 1);
212+
}
213+
214+
#[test]
215+
fn should_prune_priv_associated_methods_on_priv_impls() {
216+
let doc = test::mk_doc(
217+
~"priv impl Foo {\
218+
pub fn bar() { }\
219+
priv fn baz() { }\
220+
}");
221+
fail_unless!(doc.cratemod().impls()[0].methods.len() == 1);
222+
}
223+
224+
#[test]
225+
fn should_prune_associated_impls_with_no_pub_methods() {
226+
let doc = test::mk_doc(
227+
~"priv impl Foo {\
228+
fn baz() { }\
229+
}");
230+
fail_unless!(doc.cratemod().impls().is_empty());
231+
}
232+
233+
#[test]
234+
fn should_not_prune_associated_impls_with_pub_methods() {
235+
let doc = test::mk_doc(
236+
~" \
237+
impl Foo { pub fn bar() { } } \
238+
");
239+
fail_unless!(!doc.cratemod().impls().is_empty());
240+
}
241+
242+
97243
#[cfg(test)]
98244
pub mod test {
99245
use astsrv;
100246
use doc;
101247
use extract;
248+
use tystr_pass;
102249
use prune_private_pass::run;
103250
104251
pub fn mk_doc(source: ~str) -> doc::Doc {
105252
do astsrv::from_str(copy source) |srv| {
106253
let doc = extract::from_srv(srv.clone(), ~"");
254+
let doc = tystr_pass::run(srv.clone(), doc);
107255
run(srv.clone(), doc)
108256
}
109257
}

0 commit comments

Comments
 (0)