Skip to content

Commit

Permalink
Add support to generate documentation for tests
Browse files Browse the repository at this point in the history
The new option --document-tests is unstable and documented as such.
In order to use it is needed to add `--cfg test` and in case the tests
are not marked public to add `--document-private-items`.
The implementation hide the auto generate main test function and
constants.
  • Loading branch information
ifxfrancois committed Sep 19, 2024
1 parent 21aa500 commit 289da1d
Show file tree
Hide file tree
Showing 16 changed files with 135 additions and 18 deletions.
27 changes: 27 additions & 0 deletions src/doc/rustdoc/src/unstable-features.md
Original file line number Diff line number Diff line change
Expand Up @@ -627,3 +627,30 @@ add the `--scrape-tests` flag.

This flag enables the generation of links in the source code pages which allow the reader
to jump to a type definition.

### `--document-tests`: show test items

Using this flag looks like this:

```bash
$ rustdoc src/lib.rs -Z unstable-options --cfg test --document-tests
```

By default, `rustdoc` does not documents test items.

```rust
#[test]
pub fn test() {} // this item is a test and will not be documented even though it is public
#[cfg(test)]
pub mod tests { // this is a test module and will not be documented even though it is public
pub fn unreacheable() {} // this item is public and not a test, but unreacheable, so it will not be documented
}
```

The option `--document-private-items` may be needed as it is not common practice to make tests public.

```bash
$ rustdoc src/lib.rs -Z unstable-options --cfg test --document-tests --document-private-items
```

`--document-tests` documents tests items.
6 changes: 5 additions & 1 deletion src/librustdoc/clean/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1022,7 +1022,11 @@ fn clean_fn_or_proc_macro<'tcx>(
None => {
let mut func = clean_function(cx, sig, generics, FunctionArgs::Body(body_id));
clean_fn_decl_legacy_const_generics(&mut func, attrs);
FunctionItem(func)
if cx.cache.document_tests && cx.cache.tests.contains(&item.owner_id.to_def_id()) {
TestItem(func)
} else {
FunctionItem(func)
}
}
}
}
Expand Down
7 changes: 6 additions & 1 deletion src/librustdoc/clean/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -673,7 +673,10 @@ impl Item {
asyncness: hir::IsAsync::NotAsync,
}
}
ItemKind::FunctionItem(_) | ItemKind::MethodItem(_, _) | ItemKind::TyMethodItem(_) => {
ItemKind::FunctionItem(_)
| ItemKind::MethodItem(_, _)
| ItemKind::TyMethodItem(_)
| ItemKind::TestItem(_) => {
let def_id = self.def_id().unwrap();
build_fn_header(def_id, tcx, tcx.asyncness(def_id))
}
Expand Down Expand Up @@ -840,6 +843,7 @@ pub(crate) enum ItemKind {
UnionItem(Union),
EnumItem(Enum),
FunctionItem(Box<Function>),
TestItem(Box<Function>),
ModuleItem(Module),
TypeAliasItem(Box<TypeAlias>),
StaticItem(Static),
Expand Down Expand Up @@ -898,6 +902,7 @@ impl ItemKind {
ExternCrateItem { .. }
| ImportItem(_)
| FunctionItem(_)
| TestItem(_)
| TypeAliasItem(_)
| StaticItem(_)
| ConstantItem(_)
Expand Down
4 changes: 4 additions & 0 deletions src/librustdoc/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,8 @@ pub(crate) struct RenderOptions {
pub(crate) document_private: bool,
/// Document items that have `doc(hidden)`.
pub(crate) document_hidden: bool,
/// Document tests.
pub(crate) document_tests: bool,
/// If `true`, generate a JSON file in the crate folder instead of HTML redirection files.
pub(crate) generate_redirect_map: bool,
/// Show the memory layout of types in the docs.
Expand Down Expand Up @@ -772,6 +774,7 @@ impl Options {
}

let scrape_examples_options = ScrapeExamplesOptions::new(matches, dcx);
let document_tests = matches.opt_present("document-tests");
let with_examples = matches.opt_strs("with-examples");
let call_locations = crate::scrape_examples::load_call_locations(with_examples, dcx);

Expand Down Expand Up @@ -840,6 +843,7 @@ impl Options {
markdown_playground_url,
document_private,
document_hidden,
document_tests,
generate_redirect_map,
show_type_layout,
unstable_features,
Expand Down
11 changes: 8 additions & 3 deletions src/librustdoc/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ pub(crate) fn create_config(
remap_path_prefix,
..
}: RustdocOptions,
RenderOptions { document_private, .. }: &RenderOptions,
RenderOptions { document_private, document_tests, .. }: &RenderOptions,
using_internal_features: Arc<AtomicBool>,
) -> rustc_interface::Config {
// Add the doc cfg into the doc build.
Expand Down Expand Up @@ -227,7 +227,8 @@ pub(crate) fn create_config(
if proc_macro_crate { vec![CrateType::ProcMacro] } else { vec![CrateType::Rlib] };
let resolve_doc_links =
if *document_private { ResolveDocLinks::All } else { ResolveDocLinks::Exported };
let test = scrape_examples_options.map(|opts| opts.scrape_tests).unwrap_or(false);
let test = scrape_examples_options.map(|opts| opts.scrape_tests).unwrap_or(false)
|| (cfgs.iter().any(|cfg| cfg == "test") && *document_tests);
// plays with error output here!
let sessopts = config::Options {
maybe_sysroot,
Expand Down Expand Up @@ -341,7 +342,11 @@ pub(crate) fn run_global_ctxt(
impl_trait_bounds: Default::default(),
generated_synthetics: Default::default(),
auto_traits,
cache: Cache::new(render_options.document_private, render_options.document_hidden),
cache: Cache::new(
render_options.document_private,
render_options.document_hidden,
render_options.document_tests,
),
inlined: FxHashSet::default(),
output_format,
render_options,
Expand Down
1 change: 1 addition & 0 deletions src/librustdoc/fold.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ pub(crate) trait DocFolder: Sized {
ExternCrateItem { src: _ }
| ImportItem(_)
| FunctionItem(_)
| TestItem(_)
| StaticItem(_)
| ConstantItem(..)
| TraitAliasItem(_)
Expand Down
10 changes: 8 additions & 2 deletions src/librustdoc/formats/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,11 @@ pub(crate) struct Cache {
/// Whether to document hidden items.
/// This is stored in `Cache` so it doesn't need to be passed through all rustdoc functions.
pub(crate) document_hidden: bool,
/// Whether to document tests.
/// This is stored in `Cache` so it doesn't need to be passed through all rustdoc functions.
pub(crate) document_tests: bool,
/// DefIds of all functions which are tests.
pub(crate) tests: FxHashSet<DefId>,

/// Crates marked with [`#[doc(masked)]`][doc_masked].
///
Expand Down Expand Up @@ -142,8 +147,8 @@ struct CacheBuilder<'a, 'tcx> {
}

impl Cache {
pub(crate) fn new(document_private: bool, document_hidden: bool) -> Self {
Cache { document_private, document_hidden, ..Cache::default() }
pub(crate) fn new(document_private: bool, document_hidden: bool, document_tests: bool) -> Self {
Cache { document_private, document_hidden, document_tests, ..Cache::default() }
}

/// Populates the `Cache` with more data. The returned `Crate` will be missing some data that was
Expand Down Expand Up @@ -295,6 +300,7 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
| clean::TraitItem(..)
| clean::TraitAliasItem(..)
| clean::FunctionItem(..)
| clean::TestItem(..)
| clean::ModuleItem(..)
| clean::ForeignFunctionItem(..)
| clean::ForeignStaticItem(..)
Expand Down
3 changes: 3 additions & 0 deletions src/librustdoc/formats/item_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ pub(crate) enum ItemType {
TraitAlias = 25,
// This number is reserved for use in JavaScript
// Generic = 26,
Test = 27,
}

impl Serialize for ItemType {
Expand All @@ -83,6 +84,7 @@ impl<'a> From<&'a clean::Item> for ItemType {
clean::UnionItem(..) => ItemType::Union,
clean::EnumItem(..) => ItemType::Enum,
clean::FunctionItem(..) => ItemType::Function,
clean::TestItem(..) => ItemType::Test,
clean::TypeAliasItem(..) => ItemType::TypeAlias,
clean::StaticItem(..) => ItemType::Static,
clean::ConstantItem(..) => ItemType::Constant,
Expand Down Expand Up @@ -176,6 +178,7 @@ impl ItemType {
ItemType::Union => "union",
ItemType::Enum => "enum",
ItemType::Function => "fn",
ItemType::Test => "test",
ItemType::TypeAlias => "type",
ItemType::Static => "static",
ItemType::Trait => "trait",
Expand Down
12 changes: 12 additions & 0 deletions src/librustdoc/html/render/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,7 @@ struct AllTypes {
attribute_macros: FxHashSet<ItemEntry>,
derive_macros: FxHashSet<ItemEntry>,
trait_aliases: FxHashSet<ItemEntry>,
tests: FxHashSet<ItemEntry>,
}

impl AllTypes {
Expand All @@ -360,6 +361,7 @@ impl AllTypes {
attribute_macros: new_set(100),
derive_macros: new_set(100),
trait_aliases: new_set(100),
tests: new_set(100),
}
}

Expand All @@ -385,6 +387,7 @@ impl AllTypes {
}
ItemType::ProcDerive => self.derive_macros.insert(ItemEntry::new(new_url, name)),
ItemType::TraitAlias => self.trait_aliases.insert(ItemEntry::new(new_url, name)),
ItemType::Test => self.tests.insert(ItemEntry::new(new_url, name)),
_ => true,
};
}
Expand Down Expand Up @@ -432,6 +435,9 @@ impl AllTypes {
if !self.trait_aliases.is_empty() {
sections.insert(ItemSection::TraitAliases);
}
if !self.tests.is_empty() {
sections.insert(ItemSection::Tests);
}

sections
}
Expand Down Expand Up @@ -468,6 +474,7 @@ impl AllTypes {
print_entries(f, &self.attribute_macros, ItemSection::AttributeMacros);
print_entries(f, &self.derive_macros, ItemSection::DeriveMacros);
print_entries(f, &self.functions, ItemSection::Functions);
print_entries(f, &self.tests, ItemSection::Tests);
print_entries(f, &self.type_aliases, ItemSection::TypeAliases);
print_entries(f, &self.trait_aliases, ItemSection::TraitAliases);
print_entries(f, &self.statics, ItemSection::Statics);
Expand Down Expand Up @@ -2227,6 +2234,7 @@ pub(crate) enum ItemSection {
Statics,
Traits,
Functions,
Tests,
TypeAliases,
Unions,
Implementations,
Expand Down Expand Up @@ -2259,6 +2267,7 @@ impl ItemSection {
Statics,
Traits,
Functions,
Tests,
TypeAliases,
Unions,
Implementations,
Expand All @@ -2284,6 +2293,7 @@ impl ItemSection {
Self::Unions => "unions",
Self::Enums => "enums",
Self::Functions => "functions",
Self::Tests => "tests",
Self::TypeAliases => "types",
Self::Statics => "statics",
Self::Constants => "constants",
Expand Down Expand Up @@ -2313,6 +2323,7 @@ impl ItemSection {
Self::Unions => "Unions",
Self::Enums => "Enums",
Self::Functions => "Functions",
Self::Tests => "Tests",
Self::TypeAliases => "Type Aliases",
Self::Statics => "Statics",
Self::Constants => "Constants",
Expand Down Expand Up @@ -2343,6 +2354,7 @@ fn item_ty_to_section(ty: ItemType) -> ItemSection {
ItemType::Union => ItemSection::Unions,
ItemType::Enum => ItemSection::Enums,
ItemType::Function => ItemSection::Functions,
ItemType::Test => ItemSection::Tests,
ItemType::TypeAlias => ItemSection::TypeAliases,
ItemType::Static => ItemSection::Statics,
ItemType::Constant => ItemSection::Constants,
Expand Down
8 changes: 5 additions & 3 deletions src/librustdoc/html/render/print_item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ pub(super) fn print_item(cx: &mut Context<'_>, item: &clean::Item, buf: &mut Buf
}
}
clean::FunctionItem(..) | clean::ForeignFunctionItem(..) => "Function ",
clean::TestItem(..) => "Test ",
clean::TraitItem(..) => "Trait ",
clean::StructItem(..) => "Struct ",
clean::UnionItem(..) => "Union ",
Expand Down Expand Up @@ -254,9 +255,9 @@ pub(super) fn print_item(cx: &mut Context<'_>, item: &clean::Item, buf: &mut Buf

match &item.kind {
clean::ModuleItem(ref m) => item_module(buf, cx, item, &m.items),
clean::FunctionItem(ref f) | clean::ForeignFunctionItem(ref f, _) => {
item_function(buf, cx, item, f)
}
clean::FunctionItem(ref f)
| clean::ForeignFunctionItem(ref f, _)
| clean::TestItem(ref f) => item_function(buf, cx, item, f),
clean::TraitItem(ref t) => item_trait(buf, cx, item, t),
clean::StructItem(ref s) => item_struct(buf, cx, item, s),
clean::UnionItem(ref s) => item_union(buf, cx, item, s),
Expand Down Expand Up @@ -332,6 +333,7 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items:
ItemType::Static => 8,
ItemType::Trait => 9,
ItemType::Function => 10,
ItemType::Test => 11,
ItemType::TypeAlias => 12,
ItemType::Union => 13,
_ => 14 + ty as u8,
Expand Down
1 change: 1 addition & 0 deletions src/librustdoc/html/static/js/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -581,6 +581,7 @@ function preLoadCss(cssUrl) {
block("static", "static", "Statics");
block("trait", "traits", "Traits");
block("fn", "functions", "Functions");
block("test", "tests", "Tests");
block("type", "types", "Type Aliases");
block("union", "unions", "Unions");
// No point, because these items don't appear in modules
Expand Down
6 changes: 4 additions & 2 deletions src/librustdoc/json/conversions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,9 @@ fn from_clean_item(item: clean::Item, tcx: TyCtxt<'_>) -> ItemEnum {
StructFieldItem(f) => ItemEnum::StructField(f.into_tcx(tcx)),
EnumItem(e) => ItemEnum::Enum(e.into_tcx(tcx)),
VariantItem(v) => ItemEnum::Variant(v.into_tcx(tcx)),
FunctionItem(f) => ItemEnum::Function(from_function(f, true, header.unwrap(), tcx)),
FunctionItem(f) | TestItem(f) => {
ItemEnum::Function(from_function(f, true, header.unwrap(), tcx))
}
ForeignFunctionItem(f, _) => {
ItemEnum::Function(from_function(f, false, header.unwrap(), tcx))
}
Expand Down Expand Up @@ -858,7 +860,7 @@ impl FromWithTcx<ItemType> for ItemKind {
Struct => ItemKind::Struct,
Union => ItemKind::Union,
Enum => ItemKind::Enum,
Function | TyMethod | Method => ItemKind::Function,
Function | Test | TyMethod | Method => ItemKind::Function,
TypeAlias => ItemKind::TypeAlias,
Static => ItemKind::Static,
Constant => ItemKind::Constant,
Expand Down
3 changes: 3 additions & 0 deletions src/librustdoc/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -597,6 +597,9 @@ fn opts() -> Vec<RustcOptGroup> {
unstable("scrape-tests", |o| {
o.optflag("", "scrape-tests", "Include test code when scraping examples")
}),
unstable("document-tests", |o| {
o.optflagmulti("", "document-tests", "Generate documentation for tests")
}),
unstable("with-examples", |o| {
o.optmulti(
"",
Expand Down
1 change: 1 addition & 0 deletions src/librustdoc/passes/stripper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ impl<'a, 'tcx> DocFolder for Stripper<'a, 'tcx> {
| clean::EnumItem(..)
| clean::TraitItem(..)
| clean::FunctionItem(..)
| clean::TestItem(..)
| clean::VariantItem(..)
| clean::ForeignFunctionItem(..)
| clean::ForeignStaticItem(..)
Expand Down
1 change: 1 addition & 0 deletions src/librustdoc/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ pub(crate) trait DocVisitor<'a>: Sized {
ExternCrateItem { src: _ }
| ImportItem(_)
| FunctionItem(_)
| TestItem(_)
| TypeAliasItem(_)
| StaticItem(_)
| ConstantItem(..)
Expand Down
Loading

0 comments on commit 289da1d

Please sign in to comment.