rustdoc: Add support for type items

This commit is contained in:
Brian Anderson 2012-02-01 22:41:41 -08:00
parent ae0d49aa06
commit 2b67de06c8
12 changed files with 258 additions and 13 deletions

View File

@ -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, &&params: [ast::ty_param]) {
if vec::len(params) > 0u {
word(s.s, "<");
fn printParam(s: ps, param: ast::ty_param) {

View File

@ -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<str>
@ -70,6 +70,11 @@ type impl_attrs = {
type method_attrs = fn_attrs;
type type_attrs = {
brief: option<str>,
desc: option<str>
};
#[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)
}

View File

@ -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<astsrv::srv>,
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 {

View File

@ -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<op>, doc: doc::impldoc) -> doc::impldoc {
}
}
fn fold_type(fold: fold::fold<op>, 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 {

View File

@ -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 {

View File

@ -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<str>,
desc: option<str>,
sig: option<str>
};
#[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 }
}
}
}

View File

@ -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 {

View File

@ -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> = t<T>;
@ -23,6 +24,7 @@ type fold_enum<T> = fn~(fold: fold<T>, doc: doc::enumdoc) -> doc::enumdoc;
type fold_res<T> = fn~(fold: fold<T>, doc: doc::resdoc) -> doc::resdoc;
type fold_iface<T> = fn~(fold: fold<T>, doc: doc::ifacedoc) -> doc::ifacedoc;
type fold_impl<T> = fn~(fold: fold<T>, doc: doc::impldoc) -> doc::impldoc;
type fold_type<T> = fn~(fold: fold<T>, doc: doc::tydoc) -> doc::tydoc;
type t<T> = {
ctxt: T,
@ -33,7 +35,8 @@ type t<T> = {
fold_enum: fold_enum<T>,
fold_res: fold_res<T>,
fold_iface: fold_iface<T>,
fold_impl: fold_impl<T>
fold_impl: fold_impl<T>,
fold_type: fold_type<T>
};
@ -48,7 +51,8 @@ fn mk_fold<T:copy>(
fold_enum: fold_enum<T>,
fold_res: fold_res<T>,
fold_iface: fold_iface<T>,
fold_impl: fold_impl<T>
fold_impl: fold_impl<T>,
fold_type: fold_type<T>
) -> fold<T> {
fold({
ctxt: ctxt,
@ -59,7 +63,8 @@ fn mk_fold<T:copy>(
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<T:copy>(ctxt: T) -> fold<T> {
{|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<T>(
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<T>(
doc
}
fn default_seq_fold_type<T>(
_fold: fold<T>,
doc: doc::tydoc
) -> doc::tydoc {
doc
}
#[test]
fn default_fold_should_produce_same_doc() {
let source = "mod a { fn b() { } mod c { fn d() { } } }";

View File

@ -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 {

View File

@ -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<ctxt>,
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 {

View File

@ -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 {

View File

@ -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<astsrv::srv>,
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<T> = int;");
assert doc.topmod.types()[0].sig == some("type t<T> = int");
}
#[cfg(test)]
mod test {
fn mk_doc(source: str) -> doc::cratedoc {