diff --git a/src/comp/syntax/print/pprust.rs b/src/comp/syntax/print/pprust.rs index cf2f09d50ea..3bb47ce6c46 100644 --- a/src/comp/syntax/print/pprust.rs +++ b/src/comp/syntax/print/pprust.rs @@ -90,6 +90,10 @@ fn stmt_to_str(s: ast::stmt) -> str { be to_str(s, print_stmt); } fn item_to_str(i: @ast::item) -> str { be to_str(i, print_item); } +fn typarams_to_str(tps: [ast::ty_param]) -> str { + be to_str(tps, print_type_params) +} + fn path_to_str(&&p: @ast::path) -> str { be to_str(p, bind print_path(_, _, false)); } @@ -1253,7 +1257,7 @@ fn print_bounds(s: ps, bounds: @[ast::ty_param_bound]) { } } -fn print_type_params(s: ps, params: [ast::ty_param]) { +fn print_type_params(s: ps, &¶ms: [ast::ty_param]) { if vec::len(params) > 0u { word(s.s, "<"); fn printParam(s: ps, param: ast::ty_param) { diff --git a/src/rustdoc/attr_parser.rs b/src/rustdoc/attr_parser.rs index 818efe018fe..8e44960cf44 100644 --- a/src/rustdoc/attr_parser.rs +++ b/src/rustdoc/attr_parser.rs @@ -11,10 +11,10 @@ import core::tuple; export crate_attrs, mod_attrs, fn_attrs, arg_attrs, const_attrs, enum_attrs, variant_attrs, res_attrs, - iface_attrs, method_attrs, impl_attrs; + iface_attrs, method_attrs, impl_attrs, type_attrs; export parse_crate, parse_mod, parse_fn, parse_const, parse_enum, parse_variant, parse_res, - parse_iface, parse_method, parse_impl; + parse_iface, parse_method, parse_impl, parse_type; type crate_attrs = { name: option @@ -70,6 +70,11 @@ type impl_attrs = { type method_attrs = fn_attrs; +type type_attrs = { + brief: option, + desc: option +}; + #[cfg(test)] mod test { @@ -507,4 +512,8 @@ fn parse_method(attrs: [ast::attribute]) -> method_attrs { fn parse_impl(attrs: [ast::attribute]) -> impl_attrs { parse_basic(attrs) +} + +fn parse_type(attrs: [ast::attribute]) -> type_attrs { + parse_basic(attrs) } \ No newline at end of file diff --git a/src/rustdoc/attr_pass.rs b/src/rustdoc/attr_pass.rs index 4e0c85c8ac3..3d12fdaaa67 100644 --- a/src/rustdoc/attr_pass.rs +++ b/src/rustdoc/attr_pass.rs @@ -27,7 +27,8 @@ fn run( fold_enum: fold_enum, fold_res: fold_res, fold_iface: fold_iface, - fold_impl: fold_impl + fold_impl: fold_impl, + fold_type: fold_type with *fold::default_seq_fold(srv) }); fold.fold_crate(fold, doc) @@ -449,6 +450,30 @@ fn should_extract_impl_method_docs() { assert doc.topmod.impls()[0].methods[0].failure == some("failure"); } +fn fold_type( + fold: fold::fold, + doc: doc::tydoc +) -> doc::tydoc { + let srv = fold.ctxt; + let doc = fold::default_seq_fold_type(fold, doc); + let attrs = parse_item_attrs(srv, doc.id, attr_parser::parse_type); + + { + brief: attrs.brief, + desc: attrs.desc + with doc + } +} + +#[test] +fn should_extract_type_docs() { + let doc = test::mk_doc( + "#[doc(brief = \"brief\", desc = \"desc\")]\ + type t = int;"); + assert doc.topmod.types()[0].brief == some("brief"); + assert doc.topmod.types()[0].desc == some("desc"); +} + #[cfg(test)] mod test { fn mk_doc(source: str) -> doc::cratedoc { diff --git a/src/rustdoc/desc_pass.rs b/src/rustdoc/desc_pass.rs index 317c1f70a43..c7a204f53c5 100644 --- a/src/rustdoc/desc_pass.rs +++ b/src/rustdoc/desc_pass.rs @@ -22,7 +22,8 @@ fn run( fold_enum: fold_enum, fold_res: fold_res, fold_iface: fold_iface, - fold_impl: fold_impl + fold_impl: fold_impl, + fold_type: fold_type with *fold::default_seq_fold(op) }); fold.fold_crate(fold, doc) @@ -140,6 +141,14 @@ fn fold_impl(fold: fold::fold, doc: doc::impldoc) -> doc::impldoc { } } +fn fold_type(fold: fold::fold, doc: doc::tydoc) -> doc::tydoc { + { + brief: maybe_apply_op(fold.ctxt, doc.brief), + desc: maybe_apply_op(fold.ctxt, doc.desc) + with doc + } +} + #[test] fn should_execute_op_on_enum_brief() { let doc = test::mk_doc("#[doc(brief = \" a \")] enum a { b }"); @@ -274,6 +283,21 @@ fn should_execute_op_on_impl_method_failure_condition() { assert doc.topmod.impls()[0].methods[0].failure == some("a"); } + +#[test] +fn should_execute_op_on_type_brief() { + let doc = test::mk_doc( + "#[doc(brief = \" a \")] type t = int;"); + assert doc.topmod.types()[0].brief == some("a"); +} + +#[test] +fn should_execute_op_on_type_desc() { + let doc = test::mk_doc( + "#[doc(desc = \" a \")] type t = int;"); + assert doc.topmod.types()[0].desc == some("a"); +} + #[cfg(test)] mod test { fn mk_doc(source: str) -> doc::cratedoc { diff --git a/src/rustdoc/desc_to_brief_pass.rs b/src/rustdoc/desc_to_brief_pass.rs index 315138db3d3..89b2b5d97bc 100644 --- a/src/rustdoc/desc_to_brief_pass.rs +++ b/src/rustdoc/desc_to_brief_pass.rs @@ -24,7 +24,8 @@ fn run( fold_enum: fold_enum, fold_res: fold_res, fold_iface: fold_iface, - fold_impl: fold_impl + fold_impl: fold_impl, + fold_type: fold_type with *fold::default_seq_fold(()) }); fold.fold_crate(fold, doc) @@ -125,6 +126,17 @@ fn fold_impl(fold: fold::fold<()>, doc: doc::impldoc) -> doc::impldoc { } } +fn fold_type(fold: fold::fold<()>, doc: doc::tydoc) -> doc::tydoc { + let doc = fold::default_seq_fold_type(fold, doc); + let (brief, desc) = modify(doc.brief, doc.desc); + + { + brief: brief, + desc: desc + with doc + } +} + #[test] fn should_promote_mod_desc() { let doc = test::mk_doc("#[doc(desc = \"desc\")] mod m { }"); @@ -191,6 +203,13 @@ fn should_promote_impl_method_desc() { assert doc.topmod.impls()[0].methods[0].desc == none; } +#[test] +fn should_promote_type_desc() { + let doc = test::mk_doc("#[doc(desc = \"desc\")] type t = int;"); + assert doc.topmod.types()[0].brief == some("desc"); + assert doc.topmod.types()[0].desc == none; +} + #[cfg(test)] mod test { fn mk_doc(source: str) -> doc::cratedoc { diff --git a/src/rustdoc/doc.rs b/src/rustdoc/doc.rs index 9370ffb6c51..ed2aa2af1cc 100644 --- a/src/rustdoc/doc.rs +++ b/src/rustdoc/doc.rs @@ -13,7 +13,8 @@ enum itemtag { enumtag(enumdoc), restag(resdoc), ifacetag(ifacedoc), - impltag(impldoc) + impltag(impldoc), + tytag(tydoc) } type moddoc = { @@ -107,6 +108,14 @@ type impldoc = { methods: [methoddoc] }; +type tydoc = { + id: ast_id, + name: str, + brief: option, + desc: option, + sig: option +}; + #[doc = "Some helper methods on moddoc, mostly for testing"] impl util for moddoc { @@ -172,6 +181,15 @@ impl util for moddoc { } } } + + fn types() -> [tydoc] { + vec::filter_map(*self.items) {|itemtag| + alt itemtag { + tytag(tydoc) { some(tydoc) } + _ { none } + } + } + } } #[doc = "Helper methods on itemtag"] @@ -185,6 +203,7 @@ impl util for itemtag { doc::restag({name, _}) { name } doc::ifacetag({name, _}) { name } doc::impltag({name, _}) { name } + doc::tytag({name, _}) { name } } } } diff --git a/src/rustdoc/extract.rs b/src/rustdoc/extract.rs index a36536fd3e8..8e337e3d236 100644 --- a/src/rustdoc/extract.rs +++ b/src/rustdoc/extract.rs @@ -80,6 +80,11 @@ fn moddoc_from_mod( impldoc_from_impl(methods, item.ident, item.id) )) } + ast::item_ty(_, _) { + some(doc::tytag( + tydoc_from_ty(item.ident, item.id) + )) + } _ { none } @@ -317,6 +322,25 @@ fn should_extract_impl_method_args() { assert doc.topmod.impls()[0].methods[0].args[0].name == "a"; } +fn tydoc_from_ty( + name: str, + id: ast::node_id +) -> doc::tydoc { + { + id: id, + name: name, + brief: none, + desc: none, + sig: none + } +} + +#[test] +fn should_extract_tys() { + let doc = test::mk_doc("type a = int;"); + assert doc.topmod.types()[0].name == "a"; +} + #[cfg(test)] mod test { diff --git a/src/rustdoc/fold.rs b/src/rustdoc/fold.rs index ba5283bd6ff..667bb5d8580 100644 --- a/src/rustdoc/fold.rs +++ b/src/rustdoc/fold.rs @@ -12,6 +12,7 @@ export default_seq_fold_enum; export default_seq_fold_res; export default_seq_fold_iface; export default_seq_fold_impl; +export default_seq_fold_type; enum fold = t; @@ -23,6 +24,7 @@ type fold_enum = fn~(fold: fold, doc: doc::enumdoc) -> doc::enumdoc; type fold_res = fn~(fold: fold, doc: doc::resdoc) -> doc::resdoc; type fold_iface = fn~(fold: fold, doc: doc::ifacedoc) -> doc::ifacedoc; type fold_impl = fn~(fold: fold, doc: doc::impldoc) -> doc::impldoc; +type fold_type = fn~(fold: fold, doc: doc::tydoc) -> doc::tydoc; type t = { ctxt: T, @@ -33,7 +35,8 @@ type t = { fold_enum: fold_enum, fold_res: fold_res, fold_iface: fold_iface, - fold_impl: fold_impl + fold_impl: fold_impl, + fold_type: fold_type }; @@ -48,7 +51,8 @@ fn mk_fold( fold_enum: fold_enum, fold_res: fold_res, fold_iface: fold_iface, - fold_impl: fold_impl + fold_impl: fold_impl, + fold_type: fold_type ) -> fold { fold({ ctxt: ctxt, @@ -59,7 +63,8 @@ fn mk_fold( fold_enum: fold_enum, fold_res: fold_res, fold_iface: fold_iface, - fold_impl: fold_impl + fold_impl: fold_impl, + fold_type: fold_type }) } @@ -73,7 +78,8 @@ fn default_seq_fold(ctxt: T) -> fold { {|f, d| default_seq_fold_enum(f, d)}, {|f, d| default_seq_fold_res(f, d)}, {|f, d| default_seq_fold_iface(f, d)}, - {|f, d| default_seq_fold_impl(f, d)} + {|f, d| default_seq_fold_impl(f, d)}, + {|f, d| default_seq_fold_type(f, d)} ) } @@ -114,6 +120,9 @@ fn default_seq_fold_mod( doc::impltag(impldoc) { doc::impltag(fold.fold_impl(fold, impldoc)) } + doc::tytag(tydoc) { + doc::tytag(fold.fold_type(fold, tydoc)) + } } } with doc @@ -162,6 +171,13 @@ fn default_seq_fold_impl( doc } +fn default_seq_fold_type( + _fold: fold, + doc: doc::tydoc +) -> doc::tydoc { + doc +} + #[test] fn default_fold_should_produce_same_doc() { let source = "mod a { fn b() { } mod c { fn d() { } } }"; diff --git a/src/rustdoc/markdown_pass.rs b/src/rustdoc/markdown_pass.rs index 4aab41e38cc..c15d6adc7ba 100644 --- a/src/rustdoc/markdown_pass.rs +++ b/src/rustdoc/markdown_pass.rs @@ -139,6 +139,7 @@ fn write_mod_contents( doc::restag(resdoc) { write_res(ctxt, resdoc) } doc::ifacetag(ifacedoc) { write_iface(ctxt, ifacedoc) } doc::impltag(impldoc) { write_impl(ctxt, impldoc) } + doc::tytag(tydoc) { write_type(ctxt, tydoc) } } } } @@ -743,6 +744,42 @@ fn should_write_impl_method_failure_conditions() { assert str::contains(markdown, "Failure conditions: nuked"); } +fn write_type( + ctxt: ctxt, + doc: doc::tydoc +) { + write_header(ctxt, h2, #fmt("Type `%s`", doc.name)); + write_sig(ctxt, doc.sig); + write_brief(ctxt, doc.brief); + write_desc(ctxt, doc.desc); +} + +#[test] +fn should_write_type_header() { + let markdown = test::render("type t = int;"); + assert str::contains(markdown, "## Type `t`"); +} + +#[test] +fn should_write_type_brief() { + let markdown = test::render( + "#[doc(brief = \"brief\")] type t = int;"); + assert str::contains(markdown, "\n\nbrief\n\n"); +} + +#[test] +fn should_write_type_desc() { + let markdown = test::render( + "#[doc(desc = \"desc\")] type t = int;"); + assert str::contains(markdown, "\n\ndesc\n\n"); +} + +#[test] +fn should_write_type_signature() { + let markdown = test::render("type t = int;"); + assert str::contains(markdown, "\n\n type t = int\n\n"); +} + #[cfg(test)] mod test { fn render(source: str) -> str { diff --git a/src/rustdoc/prune_undoc_items_pass.rs b/src/rustdoc/prune_undoc_items_pass.rs index 3fa3298bdc5..3ff29bd0e89 100644 --- a/src/rustdoc/prune_undoc_items_pass.rs +++ b/src/rustdoc/prune_undoc_items_pass.rs @@ -24,7 +24,8 @@ fn run( fold_enum: fold_enum, fold_res: fold_res, fold_iface: fold_iface, - fold_impl: fold_impl + fold_impl: fold_impl, + fold_type: fold_type with *fold::default_seq_fold(ctxt) }); fold.fold_crate(fold, doc) @@ -93,6 +94,14 @@ fn fold_mod( none } } + doc::tytag(tydoc) { + let doc = fold.fold_type(fold, tydoc); + if fold.ctxt.have_docs { + some(doc::tytag(doc)) + } else { + none + } + } _ { some(itemtag) } } } @@ -335,6 +344,24 @@ fn should_not_elide_undocumented_impl_methods() { assert vec::is_not_empty(doc.topmod.impls()[0].methods); } +fn fold_type( + fold: fold::fold, + doc: doc::tydoc +) -> doc::tydoc { + let doc = fold::default_seq_fold_type(fold, doc); + + fold.ctxt.have_docs = + doc.brief != none + || doc.desc != none; + ret doc; +} + +#[test] +fn should_elide_undocumented_types() { + let doc = test::mk_doc("type t = int;"); + assert vec::is_empty(doc.topmod.types()); +} + #[cfg(test)] mod test { fn mk_doc(source: str) -> doc::cratedoc { diff --git a/src/rustdoc/prune_unexported_pass.rs b/src/rustdoc/prune_unexported_pass.rs index 94e7332e2cc..110b6952e96 100644 --- a/src/rustdoc/prune_unexported_pass.rs +++ b/src/rustdoc/prune_unexported_pass.rs @@ -220,6 +220,12 @@ fn should_prune_unexported_impls_from_top_mod() { assert vec::is_empty(doc.topmod.impls()) } +#[test] +fn should_prune_unexported_types() { + let doc = test::mk_doc("export a; mod a { } type b = int;"); + assert vec::is_empty(doc.topmod.types()); +} + #[cfg(test)] mod test { fn mk_doc(source: str) -> doc::cratedoc { diff --git a/src/rustdoc/tystr_pass.rs b/src/rustdoc/tystr_pass.rs index 604e411dde0..a80905538b2 100644 --- a/src/rustdoc/tystr_pass.rs +++ b/src/rustdoc/tystr_pass.rs @@ -21,7 +21,8 @@ fn run( fold_enum: fold_enum, fold_res: fold_res, fold_iface: fold_iface, - fold_impl: fold_impl + fold_impl: fold_impl, + fold_type: fold_type with *fold::default_seq_fold(srv) }); fold.fold_crate(fold, doc) @@ -537,6 +538,40 @@ fn should_add_impl_method_arg_types() { assert fn_.args[1].ty == some("bool"); } +fn fold_type( + fold: fold::fold, + doc: doc::tydoc +) -> doc::tydoc { + + let srv = fold.ctxt; + + { + sig: astsrv::exec(srv) {|ctxt| + alt ctxt.ast_map.get(doc.id) { + ast_map::node_item(@{ + ident: ident, + node: ast::item_ty(ty, params), _ + }) { + some(#fmt( + "type %s%s = %s", + ident, + pprust::typarams_to_str(params), + pprust::ty_to_str(ty) + )) + } + _ { fail "expected type" } + } + } + with doc + } +} + +#[test] +fn should_add_type_signatures() { + let doc = test::mk_doc("type t = int;"); + assert doc.topmod.types()[0].sig == some("type t = int"); +} + #[cfg(test)] mod test { fn mk_doc(source: str) -> doc::cratedoc {