diff --git a/src/libcore/core.rc b/src/libcore/core.rc index b90c1c16d1a8..3bc5a0319493 100644 --- a/src/libcore/core.rc +++ b/src/libcore/core.rc @@ -30,7 +30,7 @@ This behavior can be disabled with the `no_core` crate attribute." export box, char, float, bessel, f32, f64, int, str, ptr; export uint, u8, u32, u64, vec, bool; -export either, option, result; +export either, option, result, iter; export ctypes, sys, unsafe, comm, task, logging; export extfmt; export math; @@ -64,7 +64,7 @@ mod either; mod option; mod result; mod tuple; - +mod iter; // Runtime and language-primitive support diff --git a/src/libcore/iter.rs b/src/libcore/iter.rs new file mode 100644 index 000000000000..7aa08a6980c3 --- /dev/null +++ b/src/libcore/iter.rs @@ -0,0 +1,171 @@ +iface iterable { + fn iter(blk: fn(A)); +} + +impl of iterable for fn@(fn(A)) { + fn iter(blk: fn(A)) { + self(blk); + } +} + +// accomodate the fact that int/uint are passed by value by default: +impl of iterable for fn@(fn(int)) { + fn iter(blk: fn(&&int)) { + self {|i| blk(i)} + } +} + +impl of iterable for fn@(fn(uint)) { + fn iter(blk: fn(&&uint)) { + self {|i| blk(i)} + } +} + +impl of iterable for [A] { + fn iter(blk: fn(A)) { + vec::iter(self, blk) + } +} + +impl of iterable for option { + fn iter(blk: fn(A)) { + option::may(self, blk) + } +} + +fn enumerate>(self: IA, blk: fn(uint, A)) { + let i = 0u; + self.iter {|a| + blk(i, a); + i += 1u; + } +} + +// Here: we have to use fn@ for predicates and map functions, because +// we will be binding them up into a closure. Disappointing. A true +// region type system might be able to do better than this. + +fn filter>(self: IA, prd: fn@(A) -> bool, blk: fn(A)) { + self.iter {|a| + if prd(a) { blk(a) } + } +} + +fn map>(self: IA, cnv: fn@(A) -> B, blk: fn(B)) { + self.iter {|a| + let b = cnv(a); + blk(b); + } +} + +fn flat_map,IB:iterable>( + self: IA, cnv: fn@(A) -> IB, blk: fn(B)) { + self.iter {|a| + cnv(a).iter(blk) + } +} + +fn foldl>(self: IA, b0: B, blk: fn(B, A) -> B) -> B { + let b = b0; + self.iter {|a| + b = blk(b, a); + } + ret b; +} + +fn to_list>(self: IA) -> [A] { + foldl::(self, [], {|r, a| r + [a]}) +} + +fn repeat(times: uint, blk: fn()) { + let i = 0u; + while i < times { + blk(); + i += 1u; + } +} + + +#[test] +fn test_enumerate() { + enumerate(["0", "1", "2"]) {|i,j| + assert #fmt["%u",i] == j; + } +} + +#[test] +fn test_map_and_to_list() { + let a = bind vec::iter([0, 1, 2], _); + let b = bind map(a, {|i| i*2}, _); + let c = to_list(b); + assert c == [0, 2, 4]; +} + +#[test] +fn test_map_directly_on_vec() { + let b = bind map([0, 1, 2], {|i| i*2}, _); + let c = to_list(b); + assert c == [0, 2, 4]; +} + +#[test] +fn test_filter_on_int_range() { + fn is_even(&&i: int) -> bool { + ret (i % 2) == 0; + } + + let l = to_list(bind filter(bind int::range(0, 10, _), is_even, _)); + assert l == [0, 2, 4, 6, 8]; +} + +#[test] +fn test_filter_on_uint_range() { + fn is_even(&&i: uint) -> bool { + ret (i % 2u) == 0u; + } + + let l = to_list(bind filter(bind uint::range(0u, 10u, _), is_even, _)); + assert l == [0u, 2u, 4u, 6u, 8u]; +} + +#[test] +fn test_flat_map_with_option() { + fn if_even(&&i: int) -> option { + if (i % 2) == 0 { some(i) } + else { none } + } + + let a = bind vec::iter([0, 1, 2], _); + let b = bind flat_map(a, if_even, _); + let c = to_list(b); + assert c == [0, 2]; +} + +#[test] +fn test_flat_map_with_list() { + fn repeat(&&i: int) -> [int] { + let r = []; + int::range(0, i) {|_j| r += [i]; } + r + } + + let a = bind vec::iter([0, 1, 2, 3], _); + let b = bind flat_map(a, repeat, _); + let c = to_list(b); + #debug["c = %?", c]; + assert c == [1, 2, 2, 3, 3, 3]; +} + +#[test] +fn test_repeat() { + let c = [], + i = 0u; + repeat(5u) {|| + c += [(i * i)]; + i += 1u; + }; + #debug["c = %?", c]; + assert c == [0u, 1u, 4u, 9u, 16u]; +} + + diff --git a/src/rustdoc/attr_parser.rs b/src/rustdoc/attr_parser.rs index 9d886b6d4c91..818efe018fe0 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; + iface_attrs, method_attrs, impl_attrs; export parse_crate, parse_mod, parse_fn, parse_const, parse_enum, parse_variant, parse_res, - parse_iface, parse_method; + parse_iface, parse_method, parse_impl; type crate_attrs = { name: option @@ -63,6 +63,11 @@ type iface_attrs = { desc: option }; +type impl_attrs = { + brief: option, + desc: option +}; + type method_attrs = fn_attrs; #[cfg(test)] @@ -499,3 +504,7 @@ fn parse_iface(attrs: [ast::attribute]) -> iface_attrs { fn parse_method(attrs: [ast::attribute]) -> method_attrs { parse_fn(attrs) } + +fn parse_impl(attrs: [ast::attribute]) -> impl_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 91e065f310b0..4e0c85c8ac38 100644 --- a/src/rustdoc/attr_pass.rs +++ b/src/rustdoc/attr_pass.rs @@ -26,7 +26,8 @@ fn run( fold_const: fold_const, fold_enum: fold_enum, fold_res: fold_res, - fold_iface: fold_iface + fold_iface: fold_iface, + fold_impl: fold_impl with *fold::default_seq_fold(srv) }); fold.fold_crate(fold, doc) @@ -55,11 +56,7 @@ fn fold_crate( #[test] fn should_replace_top_module_name_with_crate_name() { - let source = "#[link(name = \"bond\")];"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let fold = fold::default_seq_fold(srv); - let doc = fold_crate(fold, doc); + let doc = test::mk_doc("#[link(name = \"bond\")];"); assert doc.topmod.name == "bond"; } @@ -105,22 +102,14 @@ fn fold_mod(fold: fold::fold, doc: doc::moddoc) -> doc::moddoc { #[test] fn fold_mod_should_extract_mod_attributes() { - let source = "#[doc = \"test\"] mod a { }"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let fold = fold::default_seq_fold(srv); - let doc = fold_mod(fold, doc.topmod.mods()[0]); - assert doc.desc == some("test"); + let doc = test::mk_doc("#[doc = \"test\"] mod a { }"); + assert doc.topmod.mods()[0].desc == some("test"); } #[test] fn fold_mod_should_extract_top_mod_attributes() { - let source = "#[doc = \"test\"];"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let fold = fold::default_seq_fold(srv); - let doc = fold_mod(fold, doc.topmod); - assert doc.desc == some("test"); + let doc = test::mk_doc("#[doc = \"test\"];"); + assert doc.topmod.desc == some("test"); } fn fold_fn( @@ -181,22 +170,14 @@ fn merge_ret_attrs( #[test] fn fold_fn_should_extract_fn_attributes() { - let source = "#[doc = \"test\"] fn a() -> int { }"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let fold = fold::default_seq_fold(srv); - let doc = fold_fn(fold, doc.topmod.fns()[0]); - assert doc.desc == some("test"); + let doc = test::mk_doc("#[doc = \"test\"] fn a() -> int { }"); + assert doc.topmod.fns()[0].desc == some("test"); } #[test] fn fold_fn_should_extract_arg_attributes() { - let source = "#[doc(args(a = \"b\"))] fn c(a: bool) { }"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let fold = fold::default_seq_fold(srv); - let doc = fold_fn(fold, doc.topmod.fns()[0]); - assert doc.args[0].desc == some("b"); + let doc = test::mk_doc("#[doc(args(a = \"b\"))] fn c(a: bool) { }"); + assert doc.topmod.fns()[0].args[0].desc == some("b"); } #[test] @@ -223,12 +204,8 @@ fn fold_fn_should_preserve_sig() { #[test] fn fold_fn_should_extract_failure_conditions() { - let source = "#[doc(failure = \"what\")] fn a() { }"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let fold = fold::default_seq_fold(srv); - let doc = fold_fn(fold, doc.topmod.fns()[0]); - assert doc.failure == some("what"); + let doc = test::mk_doc("#[doc(failure = \"what\")] fn a() { }"); + assert doc.topmod.fns()[0].failure == some("what"); } fn fold_const( @@ -247,14 +224,10 @@ fn fold_const( #[test] fn fold_const_should_extract_docs() { - let source = "#[doc(brief = \"foo\", desc = \"bar\")]\ - const a: bool = true;"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let fold = fold::default_seq_fold(srv); - let doc = fold_const(fold, doc.topmod.consts()[0]); - assert doc.brief == some("foo"); - assert doc.desc == some("bar"); + let doc = test::mk_doc("#[doc(brief = \"foo\", desc = \"bar\")]\ + const a: bool = true;"); + assert doc.topmod.consts()[0].brief == some("foo"); + assert doc.topmod.consts()[0].desc == some("bar"); } fn fold_enum( @@ -295,24 +268,16 @@ fn fold_enum( #[test] fn fold_enum_should_extract_docs() { - let source = "#[doc(brief = \"a\", desc = \"b\")]\ - enum a { v }"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let fold = fold::default_seq_fold(srv); - let doc = fold_enum(fold, doc.topmod.enums()[0]); - assert doc.brief == some("a"); - assert doc.desc == some("b"); + let doc = test::mk_doc("#[doc(brief = \"a\", desc = \"b\")]\ + enum a { v }"); + assert doc.topmod.enums()[0].brief == some("a"); + assert doc.topmod.enums()[0].desc == some("b"); } #[test] fn fold_enum_should_extract_variant_docs() { - let source = "enum a { #[doc = \"c\"] v }"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let fold = fold::default_seq_fold(srv); - let doc = fold_enum(fold, doc.topmod.enums()[0]); - assert doc.variants[0].desc == some("c"); + let doc = test::mk_doc("enum a { #[doc = \"c\"] v }"); + assert doc.topmod.enums()[0].variants[0].desc == some("c"); } fn fold_res( @@ -345,26 +310,18 @@ fn fold_res( #[test] fn fold_res_should_extract_docs() { - let source = "#[doc(brief = \"a\", desc = \"b\")]\ - resource r(b: bool) { }"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let fold = fold::default_seq_fold(srv); - let doc = fold_res(fold, doc.topmod.resources()[0]); - assert doc.brief == some("a"); - assert doc.desc == some("b"); + let doc = test::mk_doc("#[doc(brief = \"a\", desc = \"b\")]\ + resource r(b: bool) { }"); + assert doc.topmod.resources()[0].brief == some("a"); + assert doc.topmod.resources()[0].desc == some("b"); } #[test] fn fold_res_should_extract_arg_docs() { - let source = "#[doc(args(a = \"b\"))]\ - resource r(a: bool) { }"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let fold = fold::default_seq_fold(srv); - let doc = fold_res(fold, doc.topmod.resources()[0]); - assert doc.args[0].name == "a"; - assert doc.args[0].desc == some("b"); + let doc = test::mk_doc("#[doc(args(a = \"b\"))]\ + resource r(a: bool) { }"); + assert doc.topmod.resources()[0].args[0].name == "a"; + assert doc.topmod.resources()[0].args[0].desc == some("b"); } fn fold_iface( @@ -398,9 +355,14 @@ fn merge_method_attrs( (method.ident, attr_parser::parse_method(method.attrs)) } } - _ { - fail "Undocumented invariant in merge_method_attrs"; + ast_map::node_item(@{ + node: ast::item_impl(_, _, _, methods), _ + }) { + vec::map(methods) {|method| + (method.ident, attr_parser::parse_method(method.attrs)) + } } + _ { fail "unexpected item" } } }; @@ -421,30 +383,77 @@ fn merge_method_attrs( #[test] fn should_extract_iface_docs() { - let source = "#[doc = \"whatever\"] iface i { fn a(); }"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let doc = run(srv, doc); + let doc = test::mk_doc("#[doc = \"whatever\"] iface i { fn a(); }"); assert doc.topmod.ifaces()[0].desc == some("whatever"); } #[test] fn should_extract_iface_method_docs() { - let source = "iface i {\ - #[doc(\ - brief = \"brief\",\ - desc = \"desc\",\ - args(a = \"a\"),\ - return = \"return\",\ - failure = \"failure\")]\ - fn f(a: bool) -> bool;\ - }"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let doc = run(srv, doc); + let doc = test::mk_doc( + "iface i {\ + #[doc(\ + brief = \"brief\",\ + desc = \"desc\",\ + args(a = \"a\"),\ + return = \"return\",\ + failure = \"failure\")]\ + fn f(a: bool) -> bool;\ + }"); assert doc.topmod.ifaces()[0].methods[0].brief == some("brief"); assert doc.topmod.ifaces()[0].methods[0].desc == some("desc"); assert doc.topmod.ifaces()[0].methods[0].args[0].desc == some("a"); assert doc.topmod.ifaces()[0].methods[0].return.desc == some("return"); assert doc.topmod.ifaces()[0].methods[0].failure == some("failure"); } + + +fn fold_impl( + fold: fold::fold, + doc: doc::impldoc +) -> doc::impldoc { + let srv = fold.ctxt; + let doc = fold::default_seq_fold_impl(fold, doc); + let attrs = parse_item_attrs(srv, doc.id, attr_parser::parse_impl); + + { + brief: attrs.brief, + desc: attrs.desc, + methods: merge_method_attrs(srv, doc.id, doc.methods) + with doc + } +} + +#[test] +fn should_extract_impl_docs() { + let doc = test::mk_doc( + "#[doc = \"whatever\"] impl i for int { fn a() { } }"); + assert doc.topmod.impls()[0].desc == some("whatever"); +} + +#[test] +fn should_extract_impl_method_docs() { + let doc = test::mk_doc( + "impl i for int {\ + #[doc(\ + brief = \"brief\",\ + desc = \"desc\",\ + args(a = \"a\"),\ + return = \"return\",\ + failure = \"failure\")]\ + fn f(a: bool) -> bool { }\ + }"); + assert doc.topmod.impls()[0].methods[0].brief == some("brief"); + assert doc.topmod.impls()[0].methods[0].desc == some("desc"); + assert doc.topmod.impls()[0].methods[0].args[0].desc == some("a"); + assert doc.topmod.impls()[0].methods[0].return.desc == some("return"); + assert doc.topmod.impls()[0].methods[0].failure == some("failure"); +} + +#[cfg(test)] +mod test { + fn mk_doc(source: str) -> doc::cratedoc { + let srv = astsrv::mk_srv_from_str(source); + let doc = extract::from_srv(srv, ""); + run(srv, doc) + } +} \ No newline at end of file diff --git a/src/rustdoc/demo.rs b/src/rustdoc/demo.rs index 924c7d73ee64..4feae4106a5f 100644 --- a/src/rustdoc/demo.rs +++ b/src/rustdoc/demo.rs @@ -167,4 +167,15 @@ iface the_shunned_house { failure = "Will fail if bodies are removed from premises" )] fn construct() -> bool; +} + +#[doc = "Whatever"] +impl of the_shunned_house for omnomnomy { + #[doc(args(_unkempt_yard = "Whatever"))] + fn dingy_house(_unkempt_yard: int) { + } + + fn construct() -> bool { + fail; + } } \ No newline at end of file diff --git a/src/rustdoc/desc_pass.rs b/src/rustdoc/desc_pass.rs index c2ebde8b1a04..317c1f70a437 100644 --- a/src/rustdoc/desc_pass.rs +++ b/src/rustdoc/desc_pass.rs @@ -21,7 +21,8 @@ fn run( fold_fn: fold_fn, fold_enum: fold_enum, fold_res: fold_res, - fold_iface: fold_iface + fold_iface: fold_iface, + fold_impl: fold_impl with *fold::default_seq_fold(op) }); fold.fold_crate(fold, doc) @@ -104,154 +105,181 @@ fn fold_iface(fold: fold::fold, doc: doc::ifacedoc) -> doc::ifacedoc { { brief: maybe_apply_op(fold.ctxt, doc.brief), desc: maybe_apply_op(fold.ctxt, doc.desc), - methods: vec::map(doc.methods) {|doc| - { - brief: maybe_apply_op(fold.ctxt, doc.brief), - desc: maybe_apply_op(fold.ctxt, doc.desc), - args: vec::map(doc.args) {|doc| - { - desc: maybe_apply_op(fold.ctxt, doc.desc) - with doc - } - }, - return: { - desc: maybe_apply_op(fold.ctxt, doc.return.desc) - with doc.return - }, - failure: maybe_apply_op(fold.ctxt, doc.failure) - with doc - } + methods: apply_to_methods(fold.ctxt, doc.methods) + with doc + } +} + +fn apply_to_methods(op: op, docs: [doc::methoddoc]) -> [doc::methoddoc] { + vec::map(docs) {|doc| + { + brief: maybe_apply_op(op, doc.brief), + desc: maybe_apply_op(op, doc.desc), + args: vec::map(doc.args) {|doc| + { + desc: maybe_apply_op(op, doc.desc) + with doc + } + }, + return: { + desc: maybe_apply_op(op, doc.return.desc) + with doc.return + }, + failure: maybe_apply_op(op, doc.failure) + with doc } + } +} + +fn fold_impl(fold: fold::fold, doc: doc::impldoc) -> doc::impldoc { + { + brief: maybe_apply_op(fold.ctxt, doc.brief), + desc: maybe_apply_op(fold.ctxt, doc.desc), + methods: apply_to_methods(fold.ctxt, doc.methods) with doc } } #[test] fn should_execute_op_on_enum_brief() { - let source = "#[doc(brief = \" a \")] enum a { b }"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let doc = attr_pass::mk_pass()(srv, doc); - let doc = mk_pass(str::trim)(srv, doc); + let doc = test::mk_doc("#[doc(brief = \" a \")] enum a { b }"); assert doc.topmod.enums()[0].brief == some("a"); } #[test] fn should_execute_op_on_enum_desc() { - let source = "#[doc(desc = \" a \")] enum a { b }"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let doc = attr_pass::mk_pass()(srv, doc); - let doc = mk_pass(str::trim)(srv, doc); + let doc = test::mk_doc("#[doc(desc = \" a \")] enum a { b }"); assert doc.topmod.enums()[0].desc == some("a"); } #[test] fn should_execute_op_on_variant_desc() { - let source = "enum a { #[doc = \" a \"] b }"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let doc = attr_pass::mk_pass()(srv, doc); - let doc = mk_pass(str::trim)(srv, doc); + let doc = test::mk_doc("enum a { #[doc = \" a \"] b }"); assert doc.topmod.enums()[0].variants[0].desc == some("a"); } #[test] fn should_execute_op_on_resource_brief() { - let source = "#[doc(brief = \" a \")] resource r(a: bool) { }"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let doc = attr_pass::mk_pass()(srv, doc); - let doc = mk_pass(str::trim)(srv, doc); + let doc = test::mk_doc("#[doc(brief = \" a \")] resource r(a: bool) { }"); assert doc.topmod.resources()[0].brief == some("a"); } #[test] fn should_execute_op_on_resource_desc() { - let source = "#[doc(desc = \" a \")] resource r(a: bool) { }"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let doc = attr_pass::mk_pass()(srv, doc); - let doc = mk_pass(str::trim)(srv, doc); + let doc = test::mk_doc("#[doc(desc = \" a \")] resource r(a: bool) { }"); assert doc.topmod.resources()[0].desc == some("a"); } #[test] fn should_execute_op_on_resource_args() { - let source = "#[doc(args(a = \" a \"))] resource r(a: bool) { }"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let doc = attr_pass::mk_pass()(srv, doc); - let doc = mk_pass(str::trim)(srv, doc); + let doc = test::mk_doc( + "#[doc(args(a = \" a \"))] resource r(a: bool) { }"); assert doc.topmod.resources()[0].args[0].desc == some("a"); } #[test] fn should_execute_op_on_iface_brief() { - let source = "#[doc(brief = \" a \")] iface i { fn a(); }"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let doc = attr_pass::mk_pass()(srv, doc); - let doc = mk_pass(str::trim)(srv, doc); + let doc = test::mk_doc( + "#[doc(brief = \" a \")] iface i { fn a(); }"); assert doc.topmod.ifaces()[0].brief == some("a"); } #[test] fn should_execute_op_on_iface_desc() { - let source = "#[doc(desc = \" a \")] iface i { fn a(); }"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let doc = attr_pass::mk_pass()(srv, doc); - let doc = mk_pass(str::trim)(srv, doc); + let doc = test::mk_doc( + "#[doc(desc = \" a \")] iface i { fn a(); }"); assert doc.topmod.ifaces()[0].desc == some("a"); } #[test] fn should_execute_op_on_iface_method_brief() { - let source = "iface i { #[doc(brief = \" a \")] fn a(); }"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let doc = attr_pass::mk_pass()(srv, doc); - let doc = mk_pass(str::trim)(srv, doc); + let doc = test::mk_doc( + "iface i { #[doc(brief = \" a \")] fn a(); }"); assert doc.topmod.ifaces()[0].methods[0].brief == some("a"); } #[test] fn should_execute_op_on_iface_method_desc() { - let source = "iface i { #[doc(desc = \" a \")] fn a(); }"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let doc = attr_pass::mk_pass()(srv, doc); - let doc = mk_pass(str::trim)(srv, doc); + let doc = test::mk_doc( + "iface i { #[doc(desc = \" a \")] fn a(); }"); assert doc.topmod.ifaces()[0].methods[0].desc == some("a"); } #[test] fn should_execute_op_on_iface_method_args() { - let source = "iface i { #[doc(args(a = \" a \"))] fn a(a: bool); }"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let doc = attr_pass::mk_pass()(srv, doc); - let doc = mk_pass(str::trim)(srv, doc); + let doc = test::mk_doc( + "iface i { #[doc(args(a = \" a \"))] fn a(a: bool); }"); assert doc.topmod.ifaces()[0].methods[0].args[0].desc == some("a"); } #[test] fn should_execute_op_on_iface_method_return() { - let source = "iface i { #[doc(return = \" a \")] fn a() -> int; }"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let doc = attr_pass::mk_pass()(srv, doc); - let doc = mk_pass(str::trim)(srv, doc); + let doc = test::mk_doc( + "iface i { #[doc(return = \" a \")] fn a() -> int; }"); assert doc.topmod.ifaces()[0].methods[0].return.desc == some("a"); } #[test] fn should_execute_op_on_iface_method_failure_condition() { - let source = "iface i { #[doc(failure = \" a \")] fn a(); }"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let doc = attr_pass::mk_pass()(srv, doc); - let doc = mk_pass(str::trim)(srv, doc); + let doc = test::mk_doc("iface i { #[doc(failure = \" a \")] fn a(); }"); assert doc.topmod.ifaces()[0].methods[0].failure == some("a"); } + +#[test] +fn should_execute_op_on_impl_brief() { + let doc = test::mk_doc( + "#[doc(brief = \" a \")] impl i for int { fn a() { } }"); + assert doc.topmod.impls()[0].brief == some("a"); +} + +#[test] +fn should_execute_op_on_impl_desc() { + let doc = test::mk_doc( + "#[doc(desc = \" a \")] impl i for int { fn a() { } }"); + assert doc.topmod.impls()[0].desc == some("a"); +} + +#[test] +fn should_execute_op_on_impl_method_brief() { + let doc = test::mk_doc( + "impl i for int { #[doc(brief = \" a \")] fn a() { } }"); + assert doc.topmod.impls()[0].methods[0].brief == some("a"); +} + +#[test] +fn should_execute_op_on_impl_method_desc() { + let doc = test::mk_doc( + "impl i for int { #[doc(desc = \" a \")] fn a() { } }"); + assert doc.topmod.impls()[0].methods[0].desc == some("a"); +} + +#[test] +fn should_execute_op_on_impl_method_args() { + let doc = test::mk_doc( + "impl i for int { #[doc(args(a = \" a \"))] fn a(a: bool) { } }"); + assert doc.topmod.impls()[0].methods[0].args[0].desc == some("a"); +} + +#[test] +fn should_execute_op_on_impl_method_return() { + let doc = test::mk_doc( + "impl i for int { #[doc(return = \" a \")] fn a() -> int { fail } }"); + assert doc.topmod.impls()[0].methods[0].return.desc == some("a"); +} + +#[test] +fn should_execute_op_on_impl_method_failure_condition() { + let doc = test::mk_doc( + "impl i for int { #[doc(failure = \" a \")] fn a() { } }"); + assert doc.topmod.impls()[0].methods[0].failure == some("a"); +} + +#[cfg(test)] +mod test { + fn mk_doc(source: str) -> doc::cratedoc { + let srv = astsrv::mk_srv_from_str(source); + let doc = extract::from_srv(srv, ""); + let doc = attr_pass::mk_pass()(srv, doc); + mk_pass(str::trim)(srv, doc) + } +} \ No newline at end of file diff --git a/src/rustdoc/desc_to_brief_pass.rs b/src/rustdoc/desc_to_brief_pass.rs index 2ab9a86db4ad..315138db3d32 100644 --- a/src/rustdoc/desc_to_brief_pass.rs +++ b/src/rustdoc/desc_to_brief_pass.rs @@ -23,7 +23,8 @@ fn run( fold_fn: fold_fn, fold_enum: fold_enum, fold_res: fold_res, - fold_iface: fold_iface + fold_iface: fold_iface, + fold_impl: fold_impl with *fold::default_seq_fold(()) }); fold.fold_crate(fold, doc) @@ -104,83 +105,102 @@ fn fold_iface(fold: fold::fold<()>, doc: doc::ifacedoc) -> doc::ifacedoc { } } +fn fold_impl(fold: fold::fold<()>, doc: doc::impldoc) -> doc::impldoc { + let doc =fold::default_seq_fold_impl(fold, doc); + let (brief, desc) = modify(doc.brief, doc.desc); + + { + brief: brief, + desc: desc, + methods: vec::map(doc.methods) {|doc| + let (brief, desc) = modify(doc.brief, doc.desc); + + { + brief: brief, + desc: desc + with doc + } + } + with doc + } +} + #[test] fn should_promote_mod_desc() { - let source = "#[doc(desc = \"desc\")] mod m { }"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let doc = attr_pass::mk_pass()(srv, doc); - let doc = run(srv, doc); + let doc = test::mk_doc("#[doc(desc = \"desc\")] mod m { }"); assert doc.topmod.mods()[0].brief == some("desc"); assert doc.topmod.mods()[0].desc == none; } #[test] fn should_promote_const_desc() { - let source = "#[doc(desc = \"desc\")] const a: bool = true;"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let doc = attr_pass::mk_pass()(srv, doc); - let doc = run(srv, doc); + let doc = test::mk_doc("#[doc(desc = \"desc\")] const a: bool = true;"); assert doc.topmod.consts()[0].brief == some("desc"); assert doc.topmod.consts()[0].desc == none; } #[test] fn should_promote_fn_desc() { - let source = "#[doc(desc = \"desc\")] fn a() { }"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let doc = attr_pass::mk_pass()(srv, doc); - let doc = run(srv, doc); + let doc = test::mk_doc("#[doc(desc = \"desc\")] fn a() { }"); assert doc.topmod.fns()[0].brief == some("desc"); assert doc.topmod.fns()[0].desc == none; } #[test] fn should_promote_enum_desc() { - let source = "#[doc(desc = \"desc\")] enum a { b }"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let doc = attr_pass::mk_pass()(srv, doc); - let doc = run(srv, doc); + let doc = test::mk_doc("#[doc(desc = \"desc\")] enum a { b }"); assert doc.topmod.enums()[0].brief == some("desc"); assert doc.topmod.enums()[0].desc == none; } #[test] fn should_promote_resource_desc() { - let source = "#[doc(desc = \"desc\")] resource r(a: bool) { }"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let doc = attr_pass::mk_pass()(srv, doc); - let doc = run(srv, doc); + let doc = test::mk_doc( + "#[doc(desc = \"desc\")] resource r(a: bool) { }"); assert doc.topmod.resources()[0].brief == some("desc"); assert doc.topmod.resources()[0].desc == none; } #[test] fn should_promote_iface_desc() { - let source = "#[doc(desc = \"desc\")] iface i { fn a(); }"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let doc = attr_pass::mk_pass()(srv, doc); - let doc = run(srv, doc); + let doc = test::mk_doc("#[doc(desc = \"desc\")] iface i { fn a(); }"); assert doc.topmod.ifaces()[0].brief == some("desc"); assert doc.topmod.ifaces()[0].desc == none; } #[test] fn should_promote_iface_method_desc() { - let source = "iface i { #[doc(desc = \"desc\")] fn a(); }"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let doc = attr_pass::mk_pass()(srv, doc); - let doc = run(srv, doc); + let doc = test::mk_doc("iface i { #[doc(desc = \"desc\")] fn a(); }"); assert doc.topmod.ifaces()[0].methods[0].brief == some("desc"); assert doc.topmod.ifaces()[0].methods[0].desc == none; } +#[test] +fn should_promote_impl_desc() { + let doc = test::mk_doc( + "#[doc(desc = \"desc\")] impl i for int { fn a() { } }"); + assert doc.topmod.impls()[0].brief == some("desc"); + assert doc.topmod.impls()[0].desc == none; +} + +#[test] +fn should_promote_impl_method_desc() { + let doc = test::mk_doc( + "impl i for int { #[doc(desc = \"desc\")] fn a() { } }"); + assert doc.topmod.impls()[0].methods[0].brief == some("desc"); + assert doc.topmod.impls()[0].methods[0].desc == none; +} + +#[cfg(test)] +mod test { + fn mk_doc(source: str) -> doc::cratedoc { + let srv = astsrv::mk_srv_from_str(source); + let doc = extract::from_srv(srv, ""); + let doc = attr_pass::mk_pass()(srv, doc); + run(srv, doc) + } +} + fn modify( brief: option, desc: option diff --git a/src/rustdoc/doc.rs b/src/rustdoc/doc.rs index 13c618c685b2..9370ffb6c514 100644 --- a/src/rustdoc/doc.rs +++ b/src/rustdoc/doc.rs @@ -12,7 +12,8 @@ enum itemtag { fntag(fndoc), enumtag(enumdoc), restag(resdoc), - ifacetag(ifacedoc) + ifacetag(ifacedoc), + impltag(impldoc) } type moddoc = { @@ -96,6 +97,16 @@ type methoddoc = { sig: option }; +type impldoc = { + id: ast_id, + name: str, + brief: option, + desc: option, + iface_ty: option, + self_ty: option, + methods: [methoddoc] +}; + #[doc = "Some helper methods on moddoc, mostly for testing"] impl util for moddoc { @@ -152,6 +163,15 @@ impl util for moddoc { } } } + + fn impls() -> [impldoc] { + vec::filter_map(*self.items) {|itemtag| + alt itemtag { + impltag(impldoc) { some(impldoc) } + _ { none } + } + } + } } #[doc = "Helper methods on itemtag"] @@ -164,6 +184,7 @@ impl util for itemtag { doc::enumtag({name, _}) { name } doc::restag({name, _}) { name } doc::ifacetag({name, _}) { name } + doc::impltag({name, _}) { name } } } } diff --git a/src/rustdoc/extract.rs b/src/rustdoc/extract.rs index 64e179c78c03..a36536fd3e8d 100644 --- a/src/rustdoc/extract.rs +++ b/src/rustdoc/extract.rs @@ -75,6 +75,11 @@ fn moddoc_from_mod( ifacedoc_from_iface(methods, item.ident, item.id) )) } + ast::item_impl(_, _, _, methods) { + some(doc::impltag( + impldoc_from_impl(methods, item.ident, item.id) + )) + } _ { none } @@ -140,9 +145,7 @@ fn constdoc_from_const( #[test] fn should_extract_const_name_and_id() { - let source = "const a: int = 0;"; - let ast = parse::from_str(source); - let doc = extract(ast, ""); + let doc = test::mk_doc("const a: int = 0;"); assert doc.topmod.consts()[0].id != 0; assert doc.topmod.consts()[0].name == "a"; } @@ -177,18 +180,14 @@ fn variantdoc_from_variant(variant: ast::variant) -> doc::variantdoc { #[test] fn should_extract_enums() { - let source = "enum e { v }"; - let ast = parse::from_str(source); - let doc = extract(ast, ""); + let doc = test::mk_doc("enum e { v }"); assert doc.topmod.enums()[0].id != 0; assert doc.topmod.enums()[0].name == "e"; } #[test] fn should_extract_enum_variants() { - let source = "enum e { v }"; - let ast = parse::from_str(source); - let doc = extract(ast, ""); + let doc = test::mk_doc("enum e { v }"); assert doc.topmod.enums()[0].variants[0].name == "v"; } @@ -209,18 +208,14 @@ fn resdoc_from_resource( #[test] fn should_extract_resources() { - let source = "resource r(b: bool) { }"; - let ast = parse::from_str(source); - let doc = extract(ast, ""); + let doc = test::mk_doc("resource r(b: bool) { }"); assert doc.topmod.resources()[0].id != 0; assert doc.topmod.resources()[0].name == "r"; } #[test] fn should_extract_resource_args() { - let source = "resource r(b: bool) { }"; - let ast = parse::from_str(source); - let doc = extract(ast, ""); + let doc = test::mk_doc("resource r(b: bool) { }"); assert doc.topmod.resources()[0].args[0].name == "b"; } @@ -253,45 +248,93 @@ fn ifacedoc_from_iface( #[test] fn should_extract_ifaces() { - let source = "iface i { fn f(); }"; - let ast = parse::from_str(source); - let doc = extract(ast, ""); + let doc = test::mk_doc("iface i { fn f(); }"); assert doc.topmod.ifaces()[0].name == "i"; } #[test] fn should_extract_iface_methods() { - let source = "iface i { fn f(); }"; - let ast = parse::from_str(source); - let doc = extract(ast, ""); + let doc = test::mk_doc("iface i { fn f(); }"); assert doc.topmod.ifaces()[0].methods[0].name == "f"; } #[test] fn should_extract_iface_method_args() { - let source = "iface i { fn f(a: bool); }"; - let ast = parse::from_str(source); - let doc = extract(ast, ""); + let doc = test::mk_doc("iface i { fn f(a: bool); }"); assert doc.topmod.ifaces()[0].methods[0].args[0].name == "a"; } +fn impldoc_from_impl( + methods: [@ast::method], + name: str, + id: ast::node_id +) -> doc::impldoc { + { + id: id, + name: name, + brief: none, + desc: none, + iface_ty: none, + self_ty: none, + methods: vec::map(methods) {|method| + { + name: method.ident, + brief: none, + desc: none, + args: argdocs_from_args(method.decl.inputs), + return: { + desc: none, + ty: none + }, + failure: none, + sig: none + } + } + } +} + +#[test] +fn should_extract_impls_with_names() { + let doc = test::mk_doc("impl i for int { fn a() { } }"); + assert doc.topmod.impls()[0].name == "i"; +} + +#[test] +fn should_extract_impls_without_names() { + let doc = test::mk_doc("impl of i for int { fn a() { } }"); + assert doc.topmod.impls()[0].name == "i"; +} + +#[test] +fn should_extract_impl_methods() { + let doc = test::mk_doc("impl i for int { fn f() { } }"); + assert doc.topmod.impls()[0].methods[0].name == "f"; +} + +#[test] +fn should_extract_impl_method_args() { + let doc = test::mk_doc("impl i for int { fn f(a: bool) { } }"); + assert doc.topmod.impls()[0].methods[0].args[0].name == "a"; +} + #[cfg(test)] -mod tests { +mod test { + + fn mk_doc(source: str) -> doc::cratedoc { + let ast = parse::from_str(source); + extract(ast, "") + } #[test] fn extract_empty_crate() { - let source = ""; // empty crate - let ast = parse::from_str(source); - let doc = extract(ast, ""); + let doc = mk_doc(""); assert vec::is_empty(doc.topmod.mods()); assert vec::is_empty(doc.topmod.fns()); } #[test] fn extract_mods() { - let source = "mod a { mod b { } mod c { } }"; - let ast = parse::from_str(source); - let doc = extract(ast, ""); + let doc = mk_doc("mod a { mod b { } mod c { } }"); assert doc.topmod.mods()[0].name == "a"; assert doc.topmod.mods()[0].mods()[0].name == "b"; assert doc.topmod.mods()[0].mods()[1].name == "c"; @@ -299,36 +342,28 @@ mod tests { #[test] fn extract_mods_deep() { - let source = "mod a { mod b { mod c { } } }"; - let ast = parse::from_str(source); - let doc = extract(ast, ""); + let doc = mk_doc("mod a { mod b { mod c { } } }"); assert doc.topmod.mods()[0].mods()[0].mods()[0].name == "c"; } #[test] fn extract_should_set_mod_ast_id() { - let source = "mod a { }"; - let ast = parse::from_str(source); - let doc = extract(ast, ""); + let doc = mk_doc("mod a { }"); assert doc.topmod.mods()[0].id != 0; } #[test] fn extract_fns() { - let source = + let doc = mk_doc( "fn a() { } \ - mod b { fn c() { } }"; - let ast = parse::from_str(source); - let doc = extract(ast, ""); + mod b { fn c() { } }"); assert doc.topmod.fns()[0].name == "a"; assert doc.topmod.mods()[0].fns()[0].name == "c"; } #[test] fn extract_should_set_fn_ast_id() { - let source = "fn a() { }"; - let ast = parse::from_str(source); - let doc = extract(ast, ""); + let doc = mk_doc("fn a() { }"); assert doc.topmod.fns()[0].id != 0; } diff --git a/src/rustdoc/fold.rs b/src/rustdoc/fold.rs index 6851299db87d..ba5283bd6ff4 100644 --- a/src/rustdoc/fold.rs +++ b/src/rustdoc/fold.rs @@ -11,6 +11,7 @@ export default_seq_fold_const; export default_seq_fold_enum; export default_seq_fold_res; export default_seq_fold_iface; +export default_seq_fold_impl; enum fold = t; @@ -21,6 +22,7 @@ type fold_const = fn~(fold: fold, doc: doc::constdoc) -> doc::constdoc; 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 t = { ctxt: T, @@ -30,7 +32,8 @@ type t = { fold_const: fold_const, fold_enum: fold_enum, fold_res: fold_res, - fold_iface: fold_iface + fold_iface: fold_iface, + fold_impl: fold_impl }; @@ -44,7 +47,8 @@ fn mk_fold( fold_const: fold_const, fold_enum: fold_enum, fold_res: fold_res, - fold_iface: fold_iface + fold_iface: fold_iface, + fold_impl: fold_impl ) -> fold { fold({ ctxt: ctxt, @@ -54,7 +58,8 @@ fn mk_fold( fold_const: fold_const, fold_enum: fold_enum, fold_res: fold_res, - fold_iface: fold_iface + fold_iface: fold_iface, + fold_impl: fold_impl }) } @@ -67,7 +72,8 @@ fn default_seq_fold(ctxt: T) -> fold { {|f, d| default_seq_fold_const(f, d)}, {|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_iface(f, d)}, + {|f, d| default_seq_fold_impl(f, d)} ) } @@ -105,6 +111,9 @@ fn default_seq_fold_mod( doc::ifacetag(ifacedoc) { doc::ifacetag(fold.fold_iface(fold, ifacedoc)) } + doc::impltag(impldoc) { + doc::impltag(fold.fold_impl(fold, impldoc)) + } } } with doc @@ -146,6 +155,13 @@ fn default_seq_fold_iface( doc } +fn default_seq_fold_impl( + _fold: fold, + doc: doc::impldoc +) -> doc::impldoc { + 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 0833b5c7e74d..4aab41e38ccc 100644 --- a/src/rustdoc/markdown_pass.rs +++ b/src/rustdoc/markdown_pass.rs @@ -138,6 +138,7 @@ fn write_mod_contents( doc::enumtag(enumdoc) { write_enum(ctxt, enumdoc) } doc::restag(resdoc) { write_res(ctxt, resdoc) } doc::ifacetag(ifacedoc) { write_iface(ctxt, ifacedoc) } + doc::impltag(impldoc) { write_impl(ctxt, impldoc) } } } } @@ -647,6 +648,101 @@ fn should_write_iface_method_failure_conditions() { assert str::contains(markdown, "Failure conditions: nuked"); } +fn write_impl(ctxt: ctxt, doc: doc::impldoc) { + assert option::is_some(doc.self_ty); + let self_ty = option::get(doc.self_ty); + alt doc.iface_ty { + some(iface_ty) { + write_header(ctxt, h2, + #fmt("Implementation `%s` of `%s` for `%s`", + doc.name, iface_ty, self_ty)); + } + none { + write_header(ctxt, h2, + #fmt("Implementation `%s` for `%s`", + doc.name, self_ty)); + } + } + write_brief(ctxt, doc.brief); + write_desc(ctxt, doc.desc); + write_methods(ctxt, doc.methods); +} + +#[test] +fn should_write_impl_header() { + let markdown = test::render("impl i for int { fn a() { } }"); + assert str::contains(markdown, "## Implementation `i` for `int`"); +} + +#[test] +fn should_write_impl_header_with_iface() { + let markdown = test::render("impl i of j for int { fn a() { } }"); + assert str::contains(markdown, "## Implementation `i` of `j` for `int`"); +} + +#[test] +fn should_write_impl_brief() { + let markdown = test::render( + "#[doc(brief = \"brief\")] impl i for int { fn a() { } }"); + assert str::contains(markdown, "brief"); +} + +#[test] +fn should_write_impl_desc() { + let markdown = test::render( + "#[doc(desc = \"desc\")] impl i for int { fn a() { } }"); + assert str::contains(markdown, "desc"); +} + +#[test] +fn should_write_impl_method_header() { + let markdown = test::render( + "impl i for int { fn a() { } }"); + assert str::contains(markdown, "### Method `a`"); +} + +#[test] +fn should_write_impl_method_signature() { + let markdown = test::render( + "impl i for int { fn a() { } }"); + assert str::contains(markdown, "\n fn a()"); +} + +#[test] +fn should_write_impl_method_argument_header() { + let markdown = test::render( + "impl a for int { fn a(b: int) { } }"); + assert str::contains(markdown, "\n\nArguments:\n\n"); +} + +#[test] +fn should_write_impl_method_arguments() { + let markdown = test::render( + "impl a for int { fn a(b: int) { } }"); + assert str::contains(markdown, "* `b`: `int`\n"); +} + +#[test] +fn should_not_write_impl_method_arguments_if_none() { + let markdown = test::render( + "impl a for int { fn a() { } }"); + assert !str::contains(markdown, "Arguments"); +} + +#[test] +fn should_write_impl_method_return_info() { + let markdown = test::render( + "impl a for int { fn a() -> int { } }"); + assert str::contains(markdown, "Returns `int`"); +} + +#[test] +fn should_write_impl_method_failure_conditions() { + let markdown = test::render( + "impl a for int { #[doc(failure = \"nuked\")] fn a() { } }"); + assert str::contains(markdown, "Failure conditions: nuked"); +} + #[cfg(test)] mod test { fn render(source: str) -> str { diff --git a/src/rustdoc/prune_undoc_pass.rs b/src/rustdoc/prune_undoc_pass.rs index a68477058c1f..5b197b9859a9 100644 --- a/src/rustdoc/prune_undoc_pass.rs +++ b/src/rustdoc/prune_undoc_pass.rs @@ -23,7 +23,8 @@ fn run( fold_const: fold_const, fold_enum: fold_enum, fold_res: fold_res, - fold_iface: fold_iface + fold_iface: fold_iface, + fold_impl: fold_impl with *fold::default_seq_fold(ctxt) }); fold.fold_crate(fold, doc) @@ -84,6 +85,14 @@ fn fold_mod( none } } + doc::impltag(impldoc) { + let doc = fold.fold_impl(fold, impldoc); + if fold.ctxt.have_docs { + some(doc::impltag(doc)) + } else { + none + } + } _ { some(itemtag) } } } @@ -138,21 +147,13 @@ fn prune_return(doc: doc::retdoc) -> doc::retdoc { #[test] fn should_elide_undocumented_arguments() { - let source = "#[doc = \"hey\"] fn a(b: int) { }"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let doc = attr_pass::mk_pass()(srv, doc); - let doc = run(srv, doc); + let doc = test::mk_doc("#[doc = \"hey\"] fn a(b: int) { }"); assert vec::is_empty(doc.topmod.fns()[0].args); } #[test] fn should_not_elide_fns_with_documented_arguments() { - let source = "#[doc(args(a = \"b\"))] fn a(a: int) { }"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let doc = attr_pass::mk_pass()(srv, doc); - let doc = run(srv, doc); + let doc = test::mk_doc("#[doc(args(a = \"b\"))] fn a(a: int) { }"); assert vec::is_not_empty(doc.topmod.fns()); } @@ -169,49 +170,31 @@ fn should_elide_undocumented_return_values() { #[test] fn should_not_elide_fns_with_documented_failure_conditions() { - let source = "#[doc(failure = \"yup\")] fn a() { }"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let doc = attr_pass::mk_pass()(srv, doc); - let doc = run(srv, doc); + let doc = test::mk_doc("#[doc(failure = \"yup\")] fn a() { }"); assert vec::is_not_empty(doc.topmod.fns()); } #[test] fn should_elide_undocumented_mods() { - let source = "mod a { }"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let doc = run(srv, doc); + let doc = test::mk_doc("mod a { }"); assert vec::is_empty(doc.topmod.mods()); } #[test] fn should_not_elide_undocument_mods_with_documented_mods() { - let source = "mod a { #[doc = \"b\"] mod b { } }"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let doc = attr_pass::mk_pass()(srv, doc); - let doc = run(srv, doc); + let doc = test::mk_doc("mod a { #[doc = \"b\"] mod b { } }"); assert vec::is_not_empty(doc.topmod.mods()); } #[test] fn should_not_elide_undocument_mods_with_documented_fns() { - let source = "mod a { #[doc = \"b\"] fn b() { } }"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let doc = attr_pass::mk_pass()(srv, doc); - let doc = run(srv, doc); + let doc = test::mk_doc("mod a { #[doc = \"b\"] fn b() { } }"); assert vec::is_not_empty(doc.topmod.mods()); } #[test] fn should_elide_undocumented_fns() { - let source = "fn a() { }"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let doc = run(srv, doc); + let doc = test::mk_doc("fn a() { }"); assert vec::is_empty(doc.topmod.fns()); } @@ -228,10 +211,7 @@ fn fold_const( #[test] fn should_elide_undocumented_consts() { - let source = "const a: bool = true;"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let doc = run(srv, doc); + let doc = test::mk_doc("const a: bool = true;"); assert vec::is_empty(doc.topmod.consts()); } @@ -255,31 +235,19 @@ fn fold_enum(fold: fold::fold, doc: doc::enumdoc) -> doc::enumdoc { #[test] fn should_elide_undocumented_enums() { - let source = "enum a { b }"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let doc = attr_pass::mk_pass()(srv, doc); - let doc = run(srv, doc); + let doc = test::mk_doc("enum a { b }"); assert vec::is_empty(doc.topmod.enums()); } #[test] fn should_elide_undocumented_variants() { - let source = "#[doc = \"a\"] enum a { b }"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let doc = attr_pass::mk_pass()(srv, doc); - let doc = run(srv, doc); + let doc = test::mk_doc("#[doc = \"a\"] enum a { b }"); assert vec::is_empty(doc.topmod.enums()[0].variants); } #[test] fn should_not_elide_enums_with_documented_variants() { - let source = "enum a { #[doc = \"a\"] b }"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let doc = attr_pass::mk_pass()(srv, doc); - let doc = run(srv, doc); + let doc = test::mk_doc("enum a { #[doc = \"a\"] b }"); assert vec::is_not_empty(doc.topmod.enums()); } @@ -303,32 +271,21 @@ fn fold_res(fold: fold::fold, doc: doc::resdoc) -> doc::resdoc { #[test] fn should_elide_undocumented_resources() { - let source = "resource r(a: bool) { }"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let doc = run(srv, doc); + let doc = test::mk_doc("resource r(a: bool) { }"); assert vec::is_empty(doc.topmod.resources()); } #[test] fn should_elide_undocumented_resource_args() { - let source = "#[doc = \"drunk\"]\ - resource r(a: bool) { }"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let doc = attr_pass::mk_pass()(srv, doc); - let doc = run(srv, doc); + let doc = test::mk_doc("#[doc = \"drunk\"]\ + resource r(a: bool) { }"); assert vec::is_empty(doc.topmod.resources()[0].args); } #[test] fn should_not_elide_resources_with_documented_args() { - let source = "#[doc(args(a = \"drunk\"))]\ - resource r(a: bool) { }"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let doc = attr_pass::mk_pass()(srv, doc); - let doc = run(srv, doc); + let doc = test::mk_doc("#[doc(args(a = \"drunk\"))]\ + resource r(a: bool) { }"); assert vec::is_not_empty(doc.topmod.resources()); } @@ -338,86 +295,133 @@ fn fold_iface( ) -> doc::ifacedoc { let doc = fold::default_seq_fold_iface(fold, doc); let doc = { - methods: vec::map(doc.methods) {|doc| - { - args: prune_args(doc.args), - return: prune_return(doc.return) - with doc - } - } + methods: prune_methods(doc.methods) with doc }; - let methods_have_docs = vec::foldl(false, doc.methods) {|accum, doc| + fold.ctxt.have_docs = + doc.brief != none + || doc.desc != none + || methods_have_docs(doc.methods); + ret doc; +} + +fn prune_methods(docs: [doc::methoddoc]) -> [doc::methoddoc] { + vec::map(docs) {|doc| + { + args: prune_args(doc.args), + return: prune_return(doc.return) + with doc + } + } +} + +fn methods_have_docs(docs: [doc::methoddoc]) -> bool { + vec::foldl(false, docs) {|accum, doc| accum || doc.brief != none || doc.desc != none || vec::is_not_empty(doc.args) || doc.return.desc != none || doc.failure != none - }; - fold.ctxt.have_docs = - doc.brief != none - || doc.desc != none - || methods_have_docs; - ret doc; + } } #[test] fn should_elide_undocumented_ifaces() { - let source = "iface i { fn a(); }"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let doc = attr_pass::mk_pass()(srv, doc); - let doc = run(srv, doc); + let doc = test::mk_doc("iface i { fn a(); }"); assert vec::is_empty(doc.topmod.ifaces()); } #[test] fn should_not_elide_documented_ifaces() { - let source = "#[doc = \"hey\"] iface i { fn a(); }"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let doc = attr_pass::mk_pass()(srv, doc); - let doc = run(srv, doc); + let doc = test::mk_doc("#[doc = \"hey\"] iface i { fn a(); }"); assert vec::is_not_empty(doc.topmod.ifaces()); } #[test] fn should_not_elide_ifaces_with_documented_methods() { - let source = "iface i { #[doc = \"hey\"] fn a(); }"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let doc = attr_pass::mk_pass()(srv, doc); - let doc = run(srv, doc); + let doc = test::mk_doc("iface i { #[doc = \"hey\"] fn a(); }"); assert vec::is_not_empty(doc.topmod.ifaces()); } #[test] -fn should_not_elide_undocumented_methods() { - let source = "#[doc = \"hey\"] iface i { fn a(); }"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let doc = attr_pass::mk_pass()(srv, doc); - let doc = run(srv, doc); +fn should_not_elide_undocumented_iface_methods() { + let doc = test::mk_doc("#[doc = \"hey\"] iface i { fn a(); }"); assert vec::is_not_empty(doc.topmod.ifaces()[0].methods); } #[test] -fn should_elide_undocumented_method_args() { - let source = "#[doc = \"hey\"] iface i { fn a(); }"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let doc = attr_pass::mk_pass()(srv, doc); - let doc = run(srv, doc); +fn should_elide_undocumented_iface_method_args() { + let doc = test::mk_doc("#[doc = \"hey\"] iface i { fn a(); }"); assert vec::is_empty(doc.topmod.ifaces()[0].methods[0].args); } #[test] -fn should_elide_undocumented_method_return_values() { - let source = "#[doc = \"hey\"] iface i { fn a() -> int; }"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let doc = attr_pass::mk_pass()(srv, doc); - let doc = run(srv, doc); +fn should_elide_undocumented_iface_method_return_values() { + let doc = test::mk_doc("#[doc = \"hey\"] iface i { fn a() -> int; }"); assert doc.topmod.ifaces()[0].methods[0].return.ty == none; -} \ No newline at end of file +} + +fn fold_impl( + fold: fold::fold, + doc: doc::impldoc +) -> doc::impldoc { + let doc = fold::default_seq_fold_impl(fold, doc); + let doc = { + methods: prune_methods(doc.methods) + with doc + }; + fold.ctxt.have_docs = + doc.brief != none + || doc.desc != none + || methods_have_docs(doc.methods); + ret doc; +} + +#[test] +fn should_elide_undocumented_impls() { + let doc = test::mk_doc("impl i for int { fn a() { } }"); + assert vec::is_empty(doc.topmod.impls()); +} + +#[test] +fn should_not_elide_documented_impls() { + let doc = test::mk_doc("#[doc = \"hey\"] impl i for int { fn a() { } }"); + assert vec::is_not_empty(doc.topmod.impls()); +} + +#[test] +fn should_not_elide_impls_with_documented_methods() { + let doc = test::mk_doc("impl i for int { #[doc = \"hey\"] fn a() { } }"); + assert vec::is_not_empty(doc.topmod.impls()); +} + +#[test] +fn should_not_elide_undocumented_impl_methods() { + let doc = test::mk_doc("#[doc = \"hey\"] impl i for int { fn a() { } }"); + assert vec::is_not_empty(doc.topmod.impls()[0].methods); +} + +#[test] +fn should_elide_undocumented_impl_method_args() { + let doc = test::mk_doc( + "#[doc = \"hey\"] impl i for int { fn a(b: bool) { } }"); + assert vec::is_empty(doc.topmod.impls()[0].methods[0].args); +} + +#[test] +fn should_elide_undocumented_impl_method_return_values() { + let doc = test::mk_doc( + "#[doc = \"hey\"] impl i for int { fn a() -> int { } }"); + assert doc.topmod.impls()[0].methods[0].return.ty == none; +} + +#[cfg(test)] +mod test { + fn mk_doc(source: str) -> doc::cratedoc { + let srv = astsrv::mk_srv_from_str(source); + let doc = extract::from_srv(srv, ""); + let doc = attr_pass::mk_pass()(srv, doc); + run(srv, doc) + } +} diff --git a/src/rustdoc/prune_unexported_pass.rs b/src/rustdoc/prune_unexported_pass.rs index 554124f6348d..94e7332e2ccd 100644 --- a/src/rustdoc/prune_unexported_pass.rs +++ b/src/rustdoc/prune_unexported_pass.rs @@ -132,119 +132,99 @@ fn is_exported_from_crate( #[test] fn should_prune_unexported_fns() { - let source = "mod b { export a; fn a() { } fn b() { } }"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let doc = run(srv, doc); + let doc = test::mk_doc("mod b { export a; fn a() { } fn b() { } }"); assert vec::len(doc.topmod.mods()[0].fns()) == 1u; } #[test] fn should_prune_unexported_fns_from_top_mod() { - let source = "export a; fn a() { } fn b() { }"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let doc = run(srv, doc); + let doc = test::mk_doc("export a; fn a() { } fn b() { }"); assert vec::len(doc.topmod.fns()) == 1u; } #[test] fn should_prune_unexported_modules() { - let source = "mod a { export a; mod a { } mod b { } }"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let doc = run(srv, doc); + let doc = test::mk_doc("mod a { export a; mod a { } mod b { } }"); assert vec::len(doc.topmod.mods()[0].mods()) == 1u; } #[test] fn should_prune_unexported_modules_from_top_mod() { - let source = "export a; mod a { } mod b { }"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let doc = run(srv, doc); + let doc = test::mk_doc("export a; mod a { } mod b { }"); assert vec::len(doc.topmod.mods()) == 1u; } #[test] fn should_prune_unexported_consts() { - let source = "mod a { export a; \ - const a: bool = true; \ - const b: bool = true; }"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let doc = run(srv, doc); + let doc = test::mk_doc( + "mod a { export a; \ + const a: bool = true; \ + const b: bool = true; }"); assert vec::len(doc.topmod.mods()[0].consts()) == 1u; } #[test] fn should_prune_unexported_consts_from_top_mod() { - let source = "export a; const a: bool = true; const b: bool = true;"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let doc = run(srv, doc); + let doc = test::mk_doc( + "export a; const a: bool = true; const b: bool = true;"); assert vec::len(doc.topmod.consts()) == 1u; } #[test] fn should_prune_unexported_enums_from_top_mod() { - let source = "export a; mod a { } enum b { c }"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let doc = run(srv, doc); + let doc = test::mk_doc("export a; mod a { } enum b { c }"); assert vec::len(doc.topmod.enums()) == 0u; } #[test] fn should_prune_unexported_enums() { - let source = "mod a { export a; mod a { } enum b { c } }"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let doc = run(srv, doc); + let doc = test::mk_doc("mod a { export a; mod a { } enum b { c } }"); assert vec::len(doc.topmod.mods()[0].enums()) == 0u; } #[test] fn should_prune_unexported_variants_from_top_mod() { - let source = "export b::{}; enum b { c }"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let doc = run(srv, doc); + let doc = test::mk_doc("export b::{}; enum b { c }"); assert vec::len(doc.topmod.enums()[0].variants) == 0u; } #[test] fn should_prune_unexported_variants() { - let source = "mod a { export b::{}; enum b { c } }"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let doc = run(srv, doc); + let doc = test::mk_doc("mod a { export b::{}; enum b { c } }"); assert vec::len(doc.topmod.mods()[0].enums()[0].variants) == 0u; } #[test] fn should_prune_unexported_resources_from_top_mod() { - let source = "export a; mod a { } resource r(a: bool) { }"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let doc = run(srv, doc); + let doc = test::mk_doc("export a; mod a { } resource r(a: bool) { }"); assert vec::is_empty(doc.topmod.resources()); } #[test] fn should_prune_unexported_resources() { - let source = "mod a { export a; mod a { } resource r(a: bool) { } }"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let doc = run(srv, doc); + let doc = test::mk_doc( + "mod a { export a; mod a { } resource r(a: bool) { } }"); assert vec::is_empty(doc.topmod.mods()[0].resources()); } #[test] fn should_prune_unexported_ifaces_from_top_mod() { - let source = "export a; mod a { } iface b { fn c(); }"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let doc = run(srv, doc); + let doc = test::mk_doc("export a; mod a { } iface b { fn c(); }"); assert vec::is_empty(doc.topmod.ifaces()); } + +#[test] +fn should_prune_unexported_impls_from_top_mod() { + let doc = test::mk_doc( + "export a; mod a { } impl b for int { fn c() { } }"); + assert vec::is_empty(doc.topmod.impls()) +} + +#[cfg(test)] +mod test { + fn mk_doc(source: str) -> doc::cratedoc { + let srv = astsrv::mk_srv_from_str(source); + let doc = extract::from_srv(srv, ""); + run(srv, doc) + } +} \ No newline at end of file diff --git a/src/rustdoc/trim_pass.rs b/src/rustdoc/trim_pass.rs index f315be73c59b..bec08afdbd2b 100644 --- a/src/rustdoc/trim_pass.rs +++ b/src/rustdoc/trim_pass.rs @@ -15,69 +15,55 @@ fn mk_pass() -> pass { #[test] fn should_trim_mod() { - let source = "#[doc(brief = \"\nbrief\n\", \ - desc = \"\ndesc\n\")] \ - mod m { }"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let doc = attr_pass::mk_pass()(srv, doc); - let doc = mk_pass()(srv, doc); + let doc = test::mk_doc("#[doc(brief = \"\nbrief\n\", \ + desc = \"\ndesc\n\")] \ + mod m { }"); assert doc.topmod.mods()[0].brief == some("brief"); assert doc.topmod.mods()[0].desc == some("desc"); } #[test] fn should_trim_const() { - let source = "#[doc(brief = \"\nbrief\n\", \ - desc = \"\ndesc\n\")] \ - const a: bool = true;"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let doc = attr_pass::mk_pass()(srv, doc); - let doc = mk_pass()(srv, doc); + let doc = test::mk_doc("#[doc(brief = \"\nbrief\n\", \ + desc = \"\ndesc\n\")] \ + const a: bool = true;"); assert doc.topmod.consts()[0].brief == some("brief"); assert doc.topmod.consts()[0].desc == some("desc"); } #[test] fn should_trim_fn() { - let source = "#[doc(brief = \"\nbrief\n\", \ - desc = \"\ndesc\n\")] \ - fn a() { }"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let doc = attr_pass::mk_pass()(srv, doc); - let doc = mk_pass()(srv, doc); + let doc = test::mk_doc("#[doc(brief = \"\nbrief\n\", \ + desc = \"\ndesc\n\")] \ + fn a() { }"); assert doc.topmod.fns()[0].brief == some("brief"); assert doc.topmod.fns()[0].desc == some("desc"); } #[test] fn should_trim_args() { - let source = "#[doc(args(a = \"\na\n\"))] fn a(a: int) { }"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let doc = attr_pass::mk_pass()(srv, doc); - let doc = mk_pass()(srv, doc); + let doc = test::mk_doc("#[doc(args(a = \"\na\n\"))] fn a(a: int) { }"); assert doc.topmod.fns()[0].args[0].desc == some("a"); } #[test] fn should_trim_ret() { - let source = "#[doc(return = \"\na\n\")] fn a() -> int { }"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let doc = attr_pass::mk_pass()(srv, doc); - let doc = mk_pass()(srv, doc); + let doc = test::mk_doc("#[doc(return = \"\na\n\")] fn a() -> int { }"); assert doc.topmod.fns()[0].return.desc == some("a"); } #[test] fn should_trim_failure_conditions() { - let source = "#[doc(failure = \"\na\n\")] fn a() -> int { }"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let doc = attr_pass::mk_pass()(srv, doc); - let doc = mk_pass()(srv, doc); + let doc = test::mk_doc("#[doc(failure = \"\na\n\")] fn a() -> int { }"); assert doc.topmod.fns()[0].failure == some("a"); } + +#[cfg(test)] +mod test { + fn mk_doc(source: str) -> doc::cratedoc { + let srv = astsrv::mk_srv_from_str(source); + let doc = extract::from_srv(srv, ""); + let doc = attr_pass::mk_pass()(srv, doc); + mk_pass()(srv, doc) + } +} \ No newline at end of file diff --git a/src/rustdoc/tystr_pass.rs b/src/rustdoc/tystr_pass.rs index ecf3049b156a..604e411dde07 100644 --- a/src/rustdoc/tystr_pass.rs +++ b/src/rustdoc/tystr_pass.rs @@ -20,7 +20,8 @@ fn run( fold_const: fold_const, fold_enum: fold_enum, fold_res: fold_res, - fold_iface: fold_iface + fold_iface: fold_iface, + fold_impl: fold_impl with *fold::default_seq_fold(srv) }); fold.fold_crate(fold, doc) @@ -59,10 +60,7 @@ fn get_fn_sig(srv: astsrv::srv, fn_id: doc::ast_id) -> option { #[test] fn should_add_fn_sig() { - let source = "fn a() -> int { }"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let doc = run(srv, doc); + let doc = test::mk_doc("fn a() -> int { }"); assert doc.topmod.fns()[0].sig == some("fn a() -> int"); } @@ -106,19 +104,13 @@ fn ret_ty_to_str(decl: ast::fn_decl) -> option { #[test] fn should_add_fn_ret_types() { - let source = "fn a() -> int { }"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let doc = run(srv, doc); + let doc = test::mk_doc("fn a() -> int { }"); assert doc.topmod.fns()[0].return.ty == some("int"); } #[test] fn should_not_add_nil_ret_type() { - let source = "fn a() { }"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let doc = run(srv, doc); + let doc = test::mk_doc("fn a() { }"); assert doc.topmod.fns()[0].return.ty == none; } @@ -164,10 +156,7 @@ fn decl_arg_tys(decl: ast::fn_decl) -> [(str, str)] { #[test] fn should_add_arg_types() { - let source = "fn a(b: int, c: bool) { }"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let doc = run(srv, doc); + let doc = test::mk_doc("fn a(b: int, c: bool) { }"); let fn_ = doc.topmod.fns()[0]; assert fn_.args[0].ty == some("int"); assert fn_.args[1].ty == some("bool"); @@ -198,10 +187,7 @@ fn fold_const( #[test] fn should_add_const_types() { - let source = "const a: bool = true;"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let doc = run(srv, doc); + let doc = test::mk_doc("const a: bool = true;"); assert doc.topmod.consts()[0].ty == some("bool"); } @@ -240,10 +226,7 @@ fn fold_enum( #[test] fn should_add_variant_sigs() { - let source = "enum a { b(int) }"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let doc = run(srv, doc); + let doc = test::mk_doc("enum a { b(int) }"); assert doc.topmod.enums()[0].variants[0].sig == some("b(int)"); } @@ -271,19 +254,13 @@ fn fold_res( #[test] fn should_add_resource_sigs() { - let source = "resource r(b: bool) { }"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let doc = run(srv, doc); + let doc = test::mk_doc("resource r(b: bool) { }"); assert doc.topmod.resources()[0].sig == some("resource r(b: bool)"); } #[test] fn should_add_resource_arg_tys() { - let source = "resource r(a: bool) { }"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let doc = run(srv, doc); + let doc = test::mk_doc("resource r(a: bool) { }"); assert doc.topmod.resources()[0].args[0].ty == some("bool"); } @@ -291,30 +268,35 @@ fn fold_iface( fold: fold::fold, doc: doc::ifacedoc ) -> doc::ifacedoc { - - let srv = fold.ctxt; - { - methods: vec::map(doc.methods) {|methoddoc| - { - args: merge_method_arg_tys( - srv, - doc.id, - methoddoc.args, - methoddoc.name), - return: merge_method_ret_ty( - srv, - doc.id, - methoddoc.return, - methoddoc.name), - sig: get_method_sig(srv, doc.id, methoddoc.name) - with methoddoc - } - } + methods: merge_methods(fold.ctxt, doc.id, doc.methods) with doc } } +fn merge_methods( + srv: astsrv::srv, + item_id: doc::ast_id, + docs: [doc::methoddoc] +) -> [doc::methoddoc] { + vec::map(docs) {|doc| + { + args: merge_method_arg_tys( + srv, + item_id, + doc.args, + doc.name), + return: merge_method_ret_ty( + srv, + item_id, + doc.return, + doc.name), + sig: get_method_sig(srv, item_id, doc.name) + with doc + } + } +} + fn merge_method_ret_ty( srv: astsrv::srv, item_id: doc::ast_id, @@ -351,7 +333,19 @@ fn get_method_ret_ty( _ { fail "get_method_ret_ty: undocumented invariant"; } } } - _ { fail "get_method_ret_ty: undocumented invariant"; } + ast_map::node_item(@{ + node: ast::item_impl(_, _, _, methods), _ + }) { + alt vec::find(methods) {|method| + method.ident == method_name + } { + some(method) { + ret_ty_to_str(method.decl) + } + _ { fail "get_method_ret_ty: undocumented invariant"; } + } + } + _ { fail } } } } @@ -372,10 +366,22 @@ fn get_method_sig( some(method) { some(pprust::fun_to_str(method.decl, method.ident, [])) } - _ { fail "get_method_ret_sig: undocumented invariant"; } + _ { fail "get_method_sig: undocumented invariant"; } } } - _ { fail "get_method_ret_sig: undocumented invariant"; } + ast_map::node_item(@{ + node: ast::item_impl(_, _, _, methods), _ + }) { + alt vec::find(methods) {|method| + method.ident == method_name + } { + some(method) { + some(pprust::fun_to_str(method.decl, method.ident, [])) + } + _ { fail "get_method_sig: undocumented invariant"; } + } + } + _ { fail "get_method_sig: undocumented invariant"; } } } } @@ -412,48 +418,130 @@ fn get_method_arg_tys( some(method) { decl_arg_tys(method.decl) } - _ { fail "get_method_arg_tys: undocumented invariant"; } + _ { fail "get_method_arg_tys: expected method"; } } } - _ { fail "get_method_arg_tys: undocumented invariant"; } + ast_map::node_item(@{ + node: ast::item_impl(_, _, _, methods), _ + }) { + alt vec::find(methods) {|method| + method.ident == method_name + } { + some(method) { + decl_arg_tys(method.decl) + } + _ { fail "get_method_arg_tys: expected method"; } + } + } + _ { fail } } } } #[test] fn should_add_iface_method_sigs() { - let source = "iface i { fn a() -> int; }"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let doc = run(srv, doc); + let doc = test::mk_doc("iface i { fn a() -> int; }"); assert doc.topmod.ifaces()[0].methods[0].sig == some("fn a() -> int"); } #[test] fn should_add_iface_method_ret_types() { - let source = "iface i { fn a() -> int; }"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let doc = run(srv, doc); + let doc = test::mk_doc("iface i { fn a() -> int; }"); assert doc.topmod.ifaces()[0].methods[0].return.ty == some("int"); } #[test] fn should_not_add_iface_method_nil_ret_type() { - let source = "iface i { fn a(); }"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let doc = run(srv, doc); + let doc = test::mk_doc("iface i { fn a(); }"); assert doc.topmod.ifaces()[0].methods[0].return.ty == none; } #[test] fn should_add_iface_method_arg_types() { - let source = "iface i { fn a(b: int, c: bool); }"; - let srv = astsrv::mk_srv_from_str(source); - let doc = extract::from_srv(srv, ""); - let doc = run(srv, doc); + let doc = test::mk_doc("iface i { fn a(b: int, c: bool); }"); let fn_ = doc.topmod.ifaces()[0].methods[0]; assert fn_.args[0].ty == some("int"); assert fn_.args[1].ty == some("bool"); } + +fn fold_impl( + fold: fold::fold, + doc: doc::impldoc +) -> doc::impldoc { + + let srv = fold.ctxt; + + let (iface_ty, self_ty) = astsrv::exec(srv) {|ctxt| + alt ctxt.ast_map.get(doc.id) { + ast_map::node_item(@{ + node: ast::item_impl(_, iface_ty, self_ty, _), _ + }) { + let iface_ty = option::map(iface_ty) {|iface_ty| + pprust::ty_to_str(iface_ty) + }; + (iface_ty, some(pprust::ty_to_str(self_ty))) + } + _ { fail "expected impl" } + } + }; + + { + iface_ty: iface_ty, + self_ty: self_ty, + methods: merge_methods(fold.ctxt, doc.id, doc.methods) + with doc + } +} + +#[test] +fn should_add_impl_iface_ty() { + let doc = test::mk_doc("impl i of j for int { fn a() { } }"); + assert doc.topmod.impls()[0].iface_ty == some("j"); +} + +#[test] +fn should_not_add_impl_iface_ty_if_none() { + let doc = test::mk_doc("impl i for int { fn a() { } }"); + assert doc.topmod.impls()[0].iface_ty == none; +} + +#[test] +fn should_add_impl_self_ty() { + let doc = test::mk_doc("impl i for int { fn a() { } }"); + assert doc.topmod.impls()[0].self_ty == some("int"); +} + +#[test] +fn should_add_impl_method_sigs() { + let doc = test::mk_doc("impl i for int { fn a() -> int { fail } }"); + assert doc.topmod.impls()[0].methods[0].sig == some("fn a() -> int"); +} + +#[test] +fn should_add_impl_method_ret_types() { + let doc = test::mk_doc("impl i for int { fn a() -> int { fail } }"); + assert doc.topmod.impls()[0].methods[0].return.ty == some("int"); +} + +#[test] +fn should_not_add_impl_method_nil_ret_type() { + let doc = test::mk_doc("impl i for int { fn a() { } }"); + assert doc.topmod.impls()[0].methods[0].return.ty == none; +} + +#[test] +fn should_add_impl_method_arg_types() { + let doc = test::mk_doc("impl i for int { fn a(b: int, c: bool) { } }"); + let fn_ = doc.topmod.impls()[0].methods[0]; + assert fn_.args[0].ty == some("int"); + assert fn_.args[1].ty == some("bool"); +} + +#[cfg(test)] +mod test { + fn mk_doc(source: str) -> doc::cratedoc { + let srv = astsrv::mk_srv_from_str(source); + let doc = extract::from_srv(srv, ""); + run(srv, doc) + } +} \ No newline at end of file