Skip to content

Commit c94e982

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 8a1f803 commit c94e982

File tree

19 files changed

+142
-19
lines changed

19 files changed

+142
-19
lines changed

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

+31
Original file line numberDiff line numberDiff line change
@@ -664,3 +664,34 @@ Similar to cargo `build.rustc-wrapper` option, this flag takes a `rustc` wrapper
664664
The first argument to the program will be the test builder program.
665665

666666
This flag can be passed multiple times to nest wrappers.
667+
668+
### `--document-tests`: show test items
669+
670+
Using this flag looks like this:
671+
672+
```bash
673+
$ rustdoc src/lib.rs -Z unstable-options --cfg test --document-private-items --document-tests
674+
```
675+
676+
By default, `rustdoc` does not document test items.
677+
678+
```rust
679+
/// by default this test function would not be documented
680+
#[test]
681+
fn test_in_module() {
682+
assert_eq!(2, 1 + 1);
683+
}
684+
/// by default this test module would not be documented
685+
#[cfg(test)]
686+
mod tests {
687+
/// by default this test function would not be documented
688+
#[test]
689+
fn test_in_a_test_module() {
690+
assert_eq!(2, 1 + 1);
691+
}
692+
}
693+
```
694+
695+
Note:
696+
* `--cfg test` must be set because tests are guarded by #[cfg(test)].
697+
* `--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
@@ -1028,7 +1028,11 @@ fn clean_fn_or_proc_macro<'tcx>(
10281028
None => {
10291029
let mut func = clean_function(cx, sig, generics, FunctionArgs::Body(body_id));
10301030
clean_fn_decl_legacy_const_generics(&mut func, attrs);
1031-
FunctionItem(func)
1031+
if cx.cache.document_tests && cx.cache.tests.contains(&item.owner_id.to_def_id()) {
1032+
TestItem(func)
1033+
} else {
1034+
FunctionItem(func)
1035+
}
10321036
}
10331037
}
10341038
}

src/librustdoc/clean/types.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -671,7 +671,8 @@ impl Item {
671671
}
672672
ItemKind::FunctionItem(_)
673673
| ItemKind::MethodItem(_, _)
674-
| ItemKind::RequiredMethodItem(_) => {
674+
| ItemKind::RequiredMethodItem(_)
675+
| ItemKind::TestItem(_) => {
675676
let def_id = self.def_id().unwrap();
676677
build_fn_header(def_id, tcx, tcx.asyncness(def_id))
677678
}
@@ -845,6 +846,7 @@ pub(crate) enum ItemKind {
845846
UnionItem(Union),
846847
EnumItem(Enum),
847848
FunctionItem(Box<Function>),
849+
TestItem(Box<Function>),
848850
ModuleItem(Module),
849851
TypeAliasItem(Box<TypeAlias>),
850852
StaticItem(Static),
@@ -905,6 +907,7 @@ impl ItemKind {
905907
ExternCrateItem { .. }
906908
| ImportItem(_)
907909
| FunctionItem(_)
910+
| TestItem(_)
908911
| TypeAliasItem(_)
909912
| StaticItem(_)
910913
| 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
@@ -220,7 +220,7 @@ pub(crate) fn create_config(
220220
remap_path_prefix,
221221
..
222222
}: RustdocOptions,
223-
RenderOptions { document_private, .. }: &RenderOptions,
223+
RenderOptions { document_private, document_tests, .. }: &RenderOptions,
224224
using_internal_features: Arc<AtomicBool>,
225225
) -> rustc_interface::Config {
226226
// Add the doc cfg into the doc build.
@@ -249,7 +249,8 @@ pub(crate) fn create_config(
249249
if proc_macro_crate { vec![CrateType::ProcMacro] } else { vec![CrateType::Rlib] };
250250
let resolve_doc_links =
251251
if *document_private { ResolveDocLinks::All } else { ResolveDocLinks::Exported };
252-
let test = scrape_examples_options.map(|opts| opts.scrape_tests).unwrap_or(false);
252+
let test = scrape_examples_options.map(|opts| opts.scrape_tests).unwrap_or(false)
253+
|| (cfgs.iter().any(|cfg| cfg == "test") && *document_tests);
253254
// plays with error output here!
254255
let sessopts = config::Options {
255256
maybe_sysroot,
@@ -361,7 +362,11 @@ pub(crate) fn run_global_ctxt(
361362
impl_trait_bounds: Default::default(),
362363
generated_synthetics: Default::default(),
363364
auto_traits,
364-
cache: Cache::new(render_options.document_private, render_options.document_hidden),
365+
cache: Cache::new(
366+
render_options.document_private,
367+
render_options.document_hidden,
368+
render_options.document_tests,
369+
),
365370
inlined: FxHashSet::default(),
366371
output_format,
367372
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 DocFolder for CacheBuilder<'_, '_> {
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,
@@ -178,6 +180,7 @@ impl ItemType {
178180
ItemType::Union => "union",
179181
ItemType::Enum => "enum",
180182
ItemType::Function => "fn",
183+
ItemType::Test => "test",
181184
ItemType::TypeAlias => "type",
182185
ItemType::Static => "static",
183186
ItemType::Trait => "trait",

src/librustdoc/html/render/mod.rs

+15
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,7 @@ struct AllTypes {
342342
attribute_macros: FxIndexSet<ItemEntry>,
343343
derive_macros: FxIndexSet<ItemEntry>,
344344
trait_aliases: FxIndexSet<ItemEntry>,
345+
tests: FxIndexSet<ItemEntry>,
345346
}
346347

347348
impl AllTypes {
@@ -361,6 +362,7 @@ impl AllTypes {
361362
attribute_macros: new_set(100),
362363
derive_macros: new_set(100),
363364
trait_aliases: new_set(100),
365+
tests: new_set(100),
364366
}
365367
}
366368

@@ -386,6 +388,7 @@ impl AllTypes {
386388
}
387389
ItemType::ProcDerive => self.derive_macros.insert(ItemEntry::new(new_url, name)),
388390
ItemType::TraitAlias => self.trait_aliases.insert(ItemEntry::new(new_url, name)),
391+
ItemType::Test => self.tests.insert(ItemEntry::new(new_url, name)),
389392
_ => true,
390393
};
391394
}
@@ -415,6 +418,9 @@ impl AllTypes {
415418
if !self.functions.is_empty() {
416419
sections.insert(ItemSection::Functions);
417420
}
421+
if !self.tests.is_empty() {
422+
sections.insert(ItemSection::Tests);
423+
}
418424
if !self.type_aliases.is_empty() {
419425
sections.insert(ItemSection::TypeAliases);
420426
}
@@ -433,6 +439,9 @@ impl AllTypes {
433439
if !self.trait_aliases.is_empty() {
434440
sections.insert(ItemSection::TraitAliases);
435441
}
442+
if !self.tests.is_empty() {
443+
sections.insert(ItemSection::Tests);
444+
}
436445

437446
sections
438447
}
@@ -469,6 +478,7 @@ impl AllTypes {
469478
print_entries(f, &self.attribute_macros, ItemSection::AttributeMacros);
470479
print_entries(f, &self.derive_macros, ItemSection::DeriveMacros);
471480
print_entries(f, &self.functions, ItemSection::Functions);
481+
print_entries(f, &self.tests, ItemSection::Tests);
472482
print_entries(f, &self.type_aliases, ItemSection::TypeAliases);
473483
print_entries(f, &self.trait_aliases, ItemSection::TraitAliases);
474484
print_entries(f, &self.statics, ItemSection::Statics);
@@ -2268,6 +2278,7 @@ pub(crate) enum ItemSection {
22682278
Statics,
22692279
Traits,
22702280
Functions,
2281+
Tests,
22712282
TypeAliases,
22722283
Unions,
22732284
Implementations,
@@ -2300,6 +2311,7 @@ impl ItemSection {
23002311
Statics,
23012312
Traits,
23022313
Functions,
2314+
Tests,
23032315
TypeAliases,
23042316
Unions,
23052317
Implementations,
@@ -2325,6 +2337,7 @@ impl ItemSection {
23252337
Self::Unions => "unions",
23262338
Self::Enums => "enums",
23272339
Self::Functions => "functions",
2340+
Self::Tests => "tests",
23282341
Self::TypeAliases => "types",
23292342
Self::Statics => "statics",
23302343
Self::Constants => "constants",
@@ -2354,6 +2367,7 @@ impl ItemSection {
23542367
Self::Unions => "Unions",
23552368
Self::Enums => "Enums",
23562369
Self::Functions => "Functions",
2370+
Self::Tests => "Tests",
23572371
Self::TypeAliases => "Type Aliases",
23582372
Self::Statics => "Statics",
23592373
Self::Constants => "Constants",
@@ -2384,6 +2398,7 @@ fn item_ty_to_section(ty: ItemType) -> ItemSection {
23842398
ItemType::Union => ItemSection::Unions,
23852399
ItemType::Enum => ItemSection::Enums,
23862400
ItemType::Function => ItemSection::Functions,
2401+
ItemType::Test => ItemSection::Tests,
23872402
ItemType::TypeAlias => ItemSection::TypeAliases,
23882403
ItemType::Static => ItemSection::Statics,
23892404
ItemType::Constant => ItemSection::Constants,

src/librustdoc/html/render/print_item.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,7 @@ pub(super) fn print_item(cx: &Context<'_>, item: &clean::Item, buf: &mut Buffer)
184184
}
185185
}
186186
clean::FunctionItem(..) | clean::ForeignFunctionItem(..) => "Function ",
187+
clean::TestItem(..) => "Test ",
187188
clean::TraitItem(..) => "Trait ",
188189
clean::StructItem(..) => "Struct ",
189190
clean::UnionItem(..) => "Union ",
@@ -251,9 +252,9 @@ pub(super) fn print_item(cx: &Context<'_>, item: &clean::Item, buf: &mut Buffer)
251252

252253
match &item.kind {
253254
clean::ModuleItem(ref m) => item_module(buf, cx, item, &m.items),
254-
clean::FunctionItem(ref f) | clean::ForeignFunctionItem(ref f, _) => {
255-
item_function(buf, cx, item, f)
256-
}
255+
clean::FunctionItem(ref f)
256+
| clean::ForeignFunctionItem(ref f, _)
257+
| clean::TestItem(ref f) => item_function(buf, cx, item, f),
257258
clean::TraitItem(ref t) => item_trait(buf, cx, item, t),
258259
clean::StructItem(ref s) => item_struct(buf, cx, item, s),
259260
clean::UnionItem(ref s) => item_union(buf, cx, item, s),
@@ -330,6 +331,7 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl
330331
ItemType::Static => 8,
331332
ItemType::Trait => 9,
332333
ItemType::Function => 10,
334+
ItemType::Test => 11,
333335
ItemType::TypeAlias => 12,
334336
ItemType::Union => 13,
335337
_ => 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
}
@@ -869,7 +871,7 @@ impl FromClean<ItemType> for ItemKind {
869871
Struct => ItemKind::Struct,
870872
Union => ItemKind::Union,
871873
Enum => ItemKind::Enum,
872-
Function | TyMethod | Method => ItemKind::Function,
874+
Function | Test | TyMethod | Method => ItemKind::Function,
873875
TypeAlias => ItemKind::TypeAlias,
874876
Static => ItemKind::Static,
875877
Constant => ItemKind::Constant,

src/librustdoc/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -685,6 +685,7 @@ fn opts() -> Vec<RustcOptGroup> {
685685
"[rust]",
686686
),
687687
opt(Unstable, Flag, "", "html-no-source", "Disable HTML source code pages generation", ""),
688+
opt(Unstable, FlagMulti, "", "document-tests", "Generate documentation for tests", ""),
688689
]
689690
}
690691

src/librustdoc/passes/propagate_stability.rs

+1
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ impl DocFolder for StabilityPropagator<'_, '_> {
4646
| ItemKind::UnionItem(..)
4747
| ItemKind::EnumItem(..)
4848
| ItemKind::FunctionItem(..)
49+
| ItemKind::TestItem(..)
4950
| ItemKind::ModuleItem(..)
5051
| ItemKind::TypeAliasItem(..)
5152
| ItemKind::StaticItem(..)

src/librustdoc/passes/stripper.rs

+1
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ impl DocFolder for Stripper<'_, '_> {
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)