Skip to content

Commit 47528bf

Browse files
ifxfrancoislucagladiator
authored andcommitted
Add support to generate documentation for tests
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.
1 parent f6648f2 commit 47528bf

File tree

18 files changed

+145
-19
lines changed

18 files changed

+145
-19
lines changed

src/doc/rustdoc/src/unstable-features.md

+31
Original file line numberDiff line numberDiff line change
@@ -627,3 +627,34 @@ add the `--scrape-tests` flag.
627627

628628
This flag enables the generation of links in the source code pages which allow the reader
629629
to jump to a type definition.
630+
631+
### `--document-tests`: show test items
632+
633+
Using this flag looks like this:
634+
635+
```bash
636+
$ rustdoc src/lib.rs -Z unstable-options --cfg test --document-private-items --document-tests
637+
```
638+
639+
By default, `rustdoc` does not document test items.
640+
641+
```rust
642+
/// by default this test function would not be documented
643+
#[test]
644+
fn test_in_module() {
645+
assert_eq!(2, 1 + 1);
646+
}
647+
/// by default this test module would not be documented
648+
#[cfg(test)]
649+
mod tests {
650+
/// by default this test function would not be documented
651+
#[test]
652+
fn test_in_a_test_module() {
653+
assert_eq!(2, 1 + 1);
654+
}
655+
}
656+
```
657+
658+
Note:
659+
* `--cfg test` must be set because tests are guarded by #[cfg(test)].
660+
* `--document-private-items` is typically required because it is standard practice to keep test items private. By enabling this option, you ensure that private items, including tests, are documented as needed while maintaining their non-public status.

src/librustdoc/clean/mod.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -1022,7 +1022,11 @@ fn clean_fn_or_proc_macro<'tcx>(
10221022
None => {
10231023
let mut func = clean_function(cx, sig, generics, FunctionArgs::Body(body_id));
10241024
clean_fn_decl_legacy_const_generics(&mut func, attrs);
1025-
FunctionItem(func)
1025+
if cx.cache.document_tests && cx.cache.tests.contains(&item.owner_id.to_def_id()) {
1026+
TestItem(func)
1027+
} else {
1028+
FunctionItem(func)
1029+
}
10261030
}
10271031
}
10281032
}

src/librustdoc/clean/types.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -674,7 +674,10 @@ impl Item {
674674
asyncness: hir::IsAsync::NotAsync,
675675
}
676676
}
677-
ItemKind::FunctionItem(_) | ItemKind::MethodItem(_, _) | ItemKind::TyMethodItem(_) => {
677+
ItemKind::FunctionItem(_)
678+
| ItemKind::MethodItem(_, _)
679+
| ItemKind::TyMethodItem(_)
680+
| ItemKind::TestItem(_) => {
678681
let def_id = self.def_id().unwrap();
679682
build_fn_header(def_id, tcx, tcx.asyncness(def_id))
680683
}
@@ -841,6 +844,7 @@ pub(crate) enum ItemKind {
841844
UnionItem(Union),
842845
EnumItem(Enum),
843846
FunctionItem(Box<Function>),
847+
TestItem(Box<Function>),
844848
ModuleItem(Module),
845849
TypeAliasItem(Box<TypeAlias>),
846850
StaticItem(Static),
@@ -899,6 +903,7 @@ impl ItemKind {
899903
ExternCrateItem { .. }
900904
| ImportItem(_)
901905
| FunctionItem(_)
906+
| TestItem(_)
902907
| TypeAliasItem(_)
903908
| StaticItem(_)
904909
| ConstantItem(_)

src/librustdoc/clean/types/tests.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ fn should_not_trim() {
7171
fn is_same_generic() {
7272
use crate::clean::types::{PrimitiveType, Type};
7373
use crate::formats::cache::Cache;
74-
let cache = Cache::new(false, false);
74+
let cache = Cache::new(false, false, false);
7575
let generic = Type::Generic(rustc_span::symbol::sym::Any);
7676
let unit = Type::Primitive(PrimitiveType::Unit);
7777
assert!(!generic.is_doc_subtype_of(&unit, &cache));

src/librustdoc/config.rs

+4
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,8 @@ pub(crate) struct RenderOptions {
275275
pub(crate) document_private: bool,
276276
/// Document items that have `doc(hidden)`.
277277
pub(crate) document_hidden: bool,
278+
/// Document tests.
279+
pub(crate) document_tests: bool,
278280
/// If `true`, generate a JSON file in the crate folder instead of HTML redirection files.
279281
pub(crate) generate_redirect_map: bool,
280282
/// Show the memory layout of types in the docs.
@@ -772,6 +774,7 @@ impl Options {
772774
}
773775

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

@@ -840,6 +843,7 @@ impl Options {
840843
markdown_playground_url,
841844
document_private,
842845
document_hidden,
846+
document_tests,
843847
generate_redirect_map,
844848
show_type_layout,
845849
unstable_features,

src/librustdoc/core.rs

+8-3
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ pub(crate) fn create_config(
198198
remap_path_prefix,
199199
..
200200
}: RustdocOptions,
201-
RenderOptions { document_private, .. }: &RenderOptions,
201+
RenderOptions { document_private, document_tests, .. }: &RenderOptions,
202202
using_internal_features: Arc<AtomicBool>,
203203
) -> rustc_interface::Config {
204204
// Add the doc cfg into the doc build.
@@ -227,7 +227,8 @@ pub(crate) fn create_config(
227227
if proc_macro_crate { vec![CrateType::ProcMacro] } else { vec![CrateType::Rlib] };
228228
let resolve_doc_links =
229229
if *document_private { ResolveDocLinks::All } else { ResolveDocLinks::Exported };
230-
let test = scrape_examples_options.map(|opts| opts.scrape_tests).unwrap_or(false);
230+
let test = scrape_examples_options.map(|opts| opts.scrape_tests).unwrap_or(false)
231+
|| (cfgs.iter().any(|cfg| cfg == "test") && *document_tests);
231232
// plays with error output here!
232233
let sessopts = config::Options {
233234
maybe_sysroot,
@@ -341,7 +342,11 @@ pub(crate) fn run_global_ctxt(
341342
impl_trait_bounds: Default::default(),
342343
generated_synthetics: Default::default(),
343344
auto_traits,
344-
cache: Cache::new(render_options.document_private, render_options.document_hidden),
345+
cache: Cache::new(
346+
render_options.document_private,
347+
render_options.document_hidden,
348+
render_options.document_tests,
349+
),
345350
inlined: FxHashSet::default(),
346351
output_format,
347352
render_options,

src/librustdoc/fold.rs

+1
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ pub(crate) trait DocFolder: Sized {
7979
ExternCrateItem { src: _ }
8080
| ImportItem(_)
8181
| FunctionItem(_)
82+
| TestItem(_)
8283
| StaticItem(_)
8384
| ConstantItem(..)
8485
| TraitAliasItem(_)

src/librustdoc/formats/cache.rs

+8-2
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,11 @@ pub(crate) struct Cache {
9191
/// Whether to document hidden items.
9292
/// This is stored in `Cache` so it doesn't need to be passed through all rustdoc functions.
9393
pub(crate) document_hidden: bool,
94+
/// Whether to document tests.
95+
/// This is stored in `Cache` so it doesn't need to be passed through all rustdoc functions.
96+
pub(crate) document_tests: bool,
97+
/// DefIds of all functions which are tests.
98+
pub(crate) tests: FxHashSet<DefId>,
9499

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

144149
impl Cache {
145-
pub(crate) fn new(document_private: bool, document_hidden: bool) -> Self {
146-
Cache { document_private, document_hidden, ..Cache::default() }
150+
pub(crate) fn new(document_private: bool, document_hidden: bool, document_tests: bool) -> Self {
151+
Cache { document_private, document_hidden, document_tests, ..Cache::default() }
147152
}
148153

149154
/// Populates the `Cache` with more data. The returned `Crate` will be missing some data that was
@@ -295,6 +300,7 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
295300
| clean::TraitItem(..)
296301
| clean::TraitAliasItem(..)
297302
| clean::FunctionItem(..)
303+
| clean::TestItem(..)
298304
| clean::ModuleItem(..)
299305
| clean::ForeignFunctionItem(..)
300306
| clean::ForeignStaticItem(..)

src/librustdoc/formats/item_type.rs

+3
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ pub(crate) enum ItemType {
5757
TraitAlias = 25,
5858
// This number is reserved for use in JavaScript
5959
// Generic = 26,
60+
Test = 27,
6061
}
6162

6263
impl Serialize for ItemType {
@@ -83,6 +84,7 @@ impl<'a> From<&'a clean::Item> for ItemType {
8384
clean::UnionItem(..) => ItemType::Union,
8485
clean::EnumItem(..) => ItemType::Enum,
8586
clean::FunctionItem(..) => ItemType::Function,
87+
clean::TestItem(..) => ItemType::Test,
8688
clean::TypeAliasItem(..) => ItemType::TypeAlias,
8789
clean::StaticItem(..) => ItemType::Static,
8890
clean::ConstantItem(..) => ItemType::Constant,
@@ -176,6 +178,7 @@ impl ItemType {
176178
ItemType::Union => "union",
177179
ItemType::Enum => "enum",
178180
ItemType::Function => "fn",
181+
ItemType::Test => "test",
179182
ItemType::TypeAlias => "type",
180183
ItemType::Static => "static",
181184
ItemType::Trait => "trait",

src/librustdoc/html/render/mod.rs

+15
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,7 @@ struct AllTypes {
341341
attribute_macros: FxIndexSet<ItemEntry>,
342342
derive_macros: FxIndexSet<ItemEntry>,
343343
trait_aliases: FxIndexSet<ItemEntry>,
344+
tests: FxIndexSet<ItemEntry>,
344345
}
345346

346347
impl AllTypes {
@@ -360,6 +361,7 @@ impl AllTypes {
360361
attribute_macros: new_set(100),
361362
derive_macros: new_set(100),
362363
trait_aliases: new_set(100),
364+
tests: new_set(100),
363365
}
364366
}
365367

@@ -385,6 +387,7 @@ impl AllTypes {
385387
}
386388
ItemType::ProcDerive => self.derive_macros.insert(ItemEntry::new(new_url, name)),
387389
ItemType::TraitAlias => self.trait_aliases.insert(ItemEntry::new(new_url, name)),
390+
ItemType::Test => self.tests.insert(ItemEntry::new(new_url, name)),
388391
_ => true,
389392
};
390393
}
@@ -414,6 +417,9 @@ impl AllTypes {
414417
if !self.functions.is_empty() {
415418
sections.insert(ItemSection::Functions);
416419
}
420+
if !self.tests.is_empty() {
421+
sections.insert(ItemSection::Tests);
422+
}
417423
if !self.type_aliases.is_empty() {
418424
sections.insert(ItemSection::TypeAliases);
419425
}
@@ -432,6 +438,9 @@ impl AllTypes {
432438
if !self.trait_aliases.is_empty() {
433439
sections.insert(ItemSection::TraitAliases);
434440
}
441+
if !self.tests.is_empty() {
442+
sections.insert(ItemSection::Tests);
443+
}
435444

436445
sections
437446
}
@@ -468,6 +477,7 @@ impl AllTypes {
468477
print_entries(f, &self.attribute_macros, ItemSection::AttributeMacros);
469478
print_entries(f, &self.derive_macros, ItemSection::DeriveMacros);
470479
print_entries(f, &self.functions, ItemSection::Functions);
480+
print_entries(f, &self.tests, ItemSection::Tests);
471481
print_entries(f, &self.type_aliases, ItemSection::TypeAliases);
472482
print_entries(f, &self.trait_aliases, ItemSection::TraitAliases);
473483
print_entries(f, &self.statics, ItemSection::Statics);
@@ -2227,6 +2237,7 @@ pub(crate) enum ItemSection {
22272237
Statics,
22282238
Traits,
22292239
Functions,
2240+
Tests,
22302241
TypeAliases,
22312242
Unions,
22322243
Implementations,
@@ -2259,6 +2270,7 @@ impl ItemSection {
22592270
Statics,
22602271
Traits,
22612272
Functions,
2273+
Tests,
22622274
TypeAliases,
22632275
Unions,
22642276
Implementations,
@@ -2284,6 +2296,7 @@ impl ItemSection {
22842296
Self::Unions => "unions",
22852297
Self::Enums => "enums",
22862298
Self::Functions => "functions",
2299+
Self::Tests => "tests",
22872300
Self::TypeAliases => "types",
22882301
Self::Statics => "statics",
22892302
Self::Constants => "constants",
@@ -2313,6 +2326,7 @@ impl ItemSection {
23132326
Self::Unions => "Unions",
23142327
Self::Enums => "Enums",
23152328
Self::Functions => "Functions",
2329+
Self::Tests => "Tests",
23162330
Self::TypeAliases => "Type Aliases",
23172331
Self::Statics => "Statics",
23182332
Self::Constants => "Constants",
@@ -2343,6 +2357,7 @@ fn item_ty_to_section(ty: ItemType) -> ItemSection {
23432357
ItemType::Union => ItemSection::Unions,
23442358
ItemType::Enum => ItemSection::Enums,
23452359
ItemType::Function => ItemSection::Functions,
2360+
ItemType::Test => ItemSection::Tests,
23462361
ItemType::TypeAlias => ItemSection::TypeAliases,
23472362
ItemType::Static => ItemSection::Statics,
23482363
ItemType::Constant => ItemSection::Constants,

src/librustdoc/html/render/print_item.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,7 @@ pub(super) fn print_item(cx: &mut Context<'_>, item: &clean::Item, buf: &mut Buf
187187
}
188188
}
189189
clean::FunctionItem(..) | clean::ForeignFunctionItem(..) => "Function ",
190+
clean::TestItem(..) => "Test ",
190191
clean::TraitItem(..) => "Trait ",
191192
clean::StructItem(..) => "Struct ",
192193
clean::UnionItem(..) => "Union ",
@@ -254,9 +255,9 @@ pub(super) fn print_item(cx: &mut Context<'_>, item: &clean::Item, buf: &mut Buf
254255

255256
match &item.kind {
256257
clean::ModuleItem(ref m) => item_module(buf, cx, item, &m.items),
257-
clean::FunctionItem(ref f) | clean::ForeignFunctionItem(ref f, _) => {
258-
item_function(buf, cx, item, f)
259-
}
258+
clean::FunctionItem(ref f)
259+
| clean::ForeignFunctionItem(ref f, _)
260+
| clean::TestItem(ref f) => item_function(buf, cx, item, f),
260261
clean::TraitItem(ref t) => item_trait(buf, cx, item, t),
261262
clean::StructItem(ref s) => item_struct(buf, cx, item, s),
262263
clean::UnionItem(ref s) => item_union(buf, cx, item, s),
@@ -332,6 +333,7 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items:
332333
ItemType::Static => 8,
333334
ItemType::Trait => 9,
334335
ItemType::Function => 10,
336+
ItemType::Test => 11,
335337
ItemType::TypeAlias => 12,
336338
ItemType::Union => 13,
337339
_ => 14 + ty as u8,

src/librustdoc/html/static/js/main.js

+1
Original file line numberDiff line numberDiff line change
@@ -581,6 +581,7 @@ function preLoadCss(cssUrl) {
581581
block("static", "static", "Statics");
582582
block("trait", "traits", "Traits");
583583
block("fn", "functions", "Functions");
584+
block("test", "tests", "Tests");
584585
block("type", "types", "Type Aliases");
585586
block("union", "unions", "Unions");
586587
// No point, because these items don't appear in modules

src/librustdoc/json/conversions.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,9 @@ fn from_clean_item(item: clean::Item, renderer: &JsonRenderer<'_>) -> ItemEnum {
312312
StructFieldItem(f) => ItemEnum::StructField(f.into_json(renderer)),
313313
EnumItem(e) => ItemEnum::Enum(e.into_json(renderer)),
314314
VariantItem(v) => ItemEnum::Variant(v.into_json(renderer)),
315-
FunctionItem(f) => ItemEnum::Function(from_function(f, true, header.unwrap(), renderer)),
315+
FunctionItem(f) | TestItem(f) => {
316+
ItemEnum::Function(from_function(f, true, header.unwrap(), renderer))
317+
}
316318
ForeignFunctionItem(f, _) => {
317319
ItemEnum::Function(from_function(f, false, header.unwrap(), renderer))
318320
}
@@ -866,7 +868,7 @@ impl FromClean<ItemType> for ItemKind {
866868
Struct => ItemKind::Struct,
867869
Union => ItemKind::Union,
868870
Enum => ItemKind::Enum,
869-
Function | TyMethod | Method => ItemKind::Function,
871+
Function | Test | TyMethod | Method => ItemKind::Function,
870872
TypeAlias => ItemKind::TypeAlias,
871873
Static => ItemKind::Static,
872874
Constant => ItemKind::Constant,

src/librustdoc/lib.rs

+3
Original file line numberDiff line numberDiff line change
@@ -596,6 +596,9 @@ fn opts() -> Vec<RustcOptGroup> {
596596
unstable("scrape-tests", |o| {
597597
o.optflag("", "scrape-tests", "Include test code when scraping examples")
598598
}),
599+
unstable("document-tests", |o| {
600+
o.optflagmulti("", "document-tests", "Generate documentation for tests")
601+
}),
599602
unstable("with-examples", |o| {
600603
o.optmulti(
601604
"",

src/librustdoc/passes/stripper.rs

+1
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ impl<'a, 'tcx> DocFolder for Stripper<'a, 'tcx> {
5757
| clean::EnumItem(..)
5858
| clean::TraitItem(..)
5959
| clean::FunctionItem(..)
60+
| clean::TestItem(..)
6061
| clean::VariantItem(..)
6162
| clean::ForeignFunctionItem(..)
6263
| clean::ForeignStaticItem(..)

src/librustdoc/visit.rs

+1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ pub(crate) trait DocVisitor<'a>: Sized {
3131
ExternCrateItem { src: _ }
3232
| ImportItem(_)
3333
| FunctionItem(_)
34+
| TestItem(_)
3435
| TypeAliasItem(_)
3536
| StaticItem(_)
3637
| ConstantItem(..)

0 commit comments

Comments
 (0)