Skip to content

Commit d4cf95c

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 5545959 commit d4cf95c

File tree

19 files changed

+142
-18
lines changed

19 files changed

+142
-18
lines changed

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

+31
Original file line numberDiff line numberDiff line change
@@ -741,3 +741,34 @@ will be split as follows:
741741
"you today?",
742742
]
743743
```
744+
745+
### `--document-tests`: show test items
746+
747+
Using this flag looks like this:
748+
749+
```bash
750+
$ rustdoc src/lib.rs -Z unstable-options --cfg test --document-private-items --document-tests
751+
```
752+
753+
By default, `rustdoc` does not document test items.
754+
755+
```rust
756+
/// by default this test function would not be documented
757+
#[test]
758+
fn test_in_module() {
759+
assert_eq!(2, 1 + 1);
760+
}
761+
/// by default this test module would not be documented
762+
#[cfg(test)]
763+
mod tests {
764+
/// by default this test function would not be documented
765+
#[test]
766+
fn test_in_a_test_module() {
767+
assert_eq!(2, 1 + 1);
768+
}
769+
}
770+
```
771+
772+
Note:
773+
* `--cfg test` must be set because tests are guarded by #[cfg(test)].
774+
* `--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
@@ -1032,7 +1032,11 @@ fn clean_fn_or_proc_macro<'tcx>(
10321032
None => {
10331033
let mut func = clean_function(cx, sig, generics, FunctionArgs::Body(body_id));
10341034
clean_fn_decl_legacy_const_generics(&mut func, attrs);
1035-
FunctionItem(func)
1035+
if cx.cache.document_tests && cx.cache.tests.contains(&item.owner_id.to_def_id()) {
1036+
TestItem(func)
1037+
} else {
1038+
FunctionItem(func)
1039+
}
10361040
}
10371041
}
10381042
}

src/librustdoc/clean/types.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -707,7 +707,8 @@ impl Item {
707707
}
708708
ItemKind::FunctionItem(_)
709709
| ItemKind::MethodItem(_, _)
710-
| ItemKind::RequiredMethodItem(_) => {
710+
| ItemKind::RequiredMethodItem(_)
711+
| ItemKind::TestItem(_) => {
711712
let def_id = self.def_id().unwrap();
712713
build_fn_header(def_id, tcx, tcx.asyncness(def_id))
713714
}
@@ -881,6 +882,7 @@ pub(crate) enum ItemKind {
881882
UnionItem(Union),
882883
EnumItem(Enum),
883884
FunctionItem(Box<Function>),
885+
TestItem(Box<Function>),
884886
ModuleItem(Module),
885887
TypeAliasItem(Box<TypeAlias>),
886888
StaticItem(Static),
@@ -941,6 +943,7 @@ impl ItemKind {
941943
ExternCrateItem { .. }
942944
| ImportItem(_)
943945
| FunctionItem(_)
946+
| TestItem(_)
944947
| TypeAliasItem(_)
945948
| StaticItem(_)
946949
| 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
@@ -278,6 +278,8 @@ pub(crate) struct RenderOptions {
278278
pub(crate) document_private: bool,
279279
/// Document items that have `doc(hidden)`.
280280
pub(crate) document_hidden: bool,
281+
/// Document tests.
282+
pub(crate) document_tests: bool,
281283
/// If `true`, generate a JSON file in the crate folder instead of HTML redirection files.
282284
pub(crate) generate_redirect_map: bool,
283285
/// Show the memory layout of types in the docs.
@@ -777,6 +779,7 @@ impl Options {
777779
}
778780

779781
let scrape_examples_options = ScrapeExamplesOptions::new(matches, dcx);
782+
let document_tests = matches.opt_present("document-tests");
780783
let with_examples = matches.opt_strs("with-examples");
781784
let call_locations = crate::scrape_examples::load_call_locations(with_examples, dcx);
782785
let doctest_compilation_args = matches.opt_strs("doctest-compilation-args");
@@ -850,6 +853,7 @@ impl Options {
850853
markdown_playground_url,
851854
document_private,
852855
document_hidden,
856+
document_tests,
853857
generate_redirect_map,
854858
show_type_layout,
855859
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
) -> rustc_interface::Config {
225225
// Add the doc cfg into the doc build.
226226
cfgs.push("doc".to_string());
@@ -248,7 +248,8 @@ pub(crate) fn create_config(
248248
if proc_macro_crate { vec![CrateType::ProcMacro] } else { vec![CrateType::Rlib] };
249249
let resolve_doc_links =
250250
if *document_private { ResolveDocLinks::All } else { ResolveDocLinks::Exported };
251-
let test = scrape_examples_options.map(|opts| opts.scrape_tests).unwrap_or(false);
251+
let test = scrape_examples_options.map(|opts| opts.scrape_tests).unwrap_or(false)
252+
|| (cfgs.iter().any(|cfg| cfg == "test") && *document_tests);
252253
// plays with error output here!
253254
let sessopts = config::Options {
254255
maybe_sysroot,
@@ -360,7 +361,11 @@ pub(crate) fn run_global_ctxt(
360361
impl_trait_bounds: Default::default(),
361362
generated_synthetics: Default::default(),
362363
auto_traits,
363-
cache: Cache::new(render_options.document_private, render_options.document_hidden),
364+
cache: Cache::new(
365+
render_options.document_private,
366+
render_options.document_hidden,
367+
render_options.document_tests,
368+
),
364369
inlined: FxHashSet::default(),
365370
output_format,
366371
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
@@ -92,6 +92,11 @@ pub(crate) struct Cache {
9292
/// Whether to document hidden items.
9393
/// This is stored in `Cache` so it doesn't need to be passed through all rustdoc functions.
9494
pub(crate) document_hidden: bool,
95+
/// Whether to document tests.
96+
/// This is stored in `Cache` so it doesn't need to be passed through all rustdoc functions.
97+
pub(crate) document_tests: bool,
98+
/// DefIds of all functions which are tests.
99+
pub(crate) tests: FxHashSet<DefId>,
95100

96101
/// Crates marked with [`#[doc(masked)]`][doc_masked].
97102
///
@@ -144,8 +149,8 @@ struct CacheBuilder<'a, 'tcx> {
144149
}
145150

146151
impl Cache {
147-
pub(crate) fn new(document_private: bool, document_hidden: bool) -> Self {
148-
Cache { document_private, document_hidden, ..Cache::default() }
152+
pub(crate) fn new(document_private: bool, document_hidden: bool, document_tests: bool) -> Self {
153+
Cache { document_private, document_hidden, document_tests, ..Cache::default() }
149154
}
150155

151156
/// Populates the `Cache` with more data. The returned `Crate` will be missing some data that was
@@ -302,6 +307,7 @@ impl DocFolder for CacheBuilder<'_, '_> {
302307
| clean::TraitItem(..)
303308
| clean::TraitAliasItem(..)
304309
| clean::FunctionItem(..)
310+
| clean::TestItem(..)
305311
| clean::ModuleItem(..)
306312
| clean::ForeignFunctionItem(..)
307313
| 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
@@ -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);
@@ -2267,6 +2277,7 @@ pub(crate) enum ItemSection {
22672277
Statics,
22682278
Traits,
22692279
Functions,
2280+
Tests,
22702281
TypeAliases,
22712282
Unions,
22722283
Implementations,
@@ -2299,6 +2310,7 @@ impl ItemSection {
22992310
Statics,
23002311
Traits,
23012312
Functions,
2313+
Tests,
23022314
TypeAliases,
23032315
Unions,
23042316
Implementations,
@@ -2324,6 +2336,7 @@ impl ItemSection {
23242336
Self::Unions => "unions",
23252337
Self::Enums => "enums",
23262338
Self::Functions => "functions",
2339+
Self::Tests => "tests",
23272340
Self::TypeAliases => "types",
23282341
Self::Statics => "statics",
23292342
Self::Constants => "constants",
@@ -2353,6 +2366,7 @@ impl ItemSection {
23532366
Self::Unions => "Unions",
23542367
Self::Enums => "Enums",
23552368
Self::Functions => "Functions",
2369+
Self::Tests => "Tests",
23562370
Self::TypeAliases => "Type Aliases",
23572371
Self::Statics => "Statics",
23582372
Self::Constants => "Constants",
@@ -2383,6 +2397,7 @@ fn item_ty_to_section(ty: ItemType) -> ItemSection {
23832397
ItemType::Union => ItemSection::Unions,
23842398
ItemType::Enum => ItemSection::Enums,
23852399
ItemType::Function => ItemSection::Functions,
2400+
ItemType::Test => ItemSection::Tests,
23862401
ItemType::TypeAlias => ItemSection::TypeAliases,
23872402
ItemType::Static => ItemSection::Statics,
23882403
ItemType::Constant => ItemSection::Constants,

src/librustdoc/html/render/print_item.rs

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

251252
match &item.kind {
252253
clean::ModuleItem(ref m) => item_module(buf, cx, item, &m.items),
253-
clean::FunctionItem(ref f) | clean::ForeignFunctionItem(ref f, _) => {
254-
item_function(buf, cx, item, f)
255-
}
254+
clean::FunctionItem(ref f)
255+
| clean::ForeignFunctionItem(ref f, _)
256+
| clean::TestItem(ref f) => item_function(buf, cx, item, f),
256257
clean::TraitItem(ref t) => item_trait(buf, cx, item, t),
257258
clean::StructItem(ref s) => item_struct(buf, cx, item, s),
258259
clean::UnionItem(ref s) => item_union(buf, cx, item, s),
@@ -329,6 +330,7 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl
329330
ItemType::Static => 8,
330331
ItemType::Trait => 9,
331332
ItemType::Function => 10,
333+
ItemType::Test => 11,
332334
ItemType::TypeAlias => 12,
333335
ItemType::Union => 13,
334336
_ => 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
}
@@ -870,7 +872,7 @@ impl FromClean<ItemType> for ItemKind {
870872
Struct => ItemKind::Struct,
871873
Union => ItemKind::Union,
872874
Enum => ItemKind::Enum,
873-
Function | TyMethod | Method => ItemKind::Function,
875+
Function | Test | TyMethod | Method => ItemKind::Function,
874876
TypeAlias => ItemKind::TypeAlias,
875877
Static => ItemKind::Static,
876878
Constant => ItemKind::Constant,

src/librustdoc/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -699,6 +699,7 @@ fn opts() -> Vec<RustcOptGroup> {
699699
"removed, see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information",
700700
"[rust]",
701701
),
702+
opt(Unstable, FlagMulti, "", "document-tests", "Generate documentation for tests", ""),
702703
]
703704
}
704705

src/librustdoc/passes/propagate_stability.rs

+1
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ impl DocFolder for StabilityPropagator<'_, '_> {
6565
| ItemKind::UnionItem(..)
6666
| ItemKind::EnumItem(..)
6767
| ItemKind::FunctionItem(..)
68+
| ItemKind::TestItem(..)
6869
| ItemKind::ModuleItem(..)
6970
| ItemKind::TypeAliasItem(..)
7071
| 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)