Skip to content

Commit d12b7b5

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 81d8edc commit d12b7b5

File tree

19 files changed

+142
-16
lines changed

19 files changed

+142
-16
lines changed

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

+31
Original file line numberDiff line numberDiff line change
@@ -830,3 +830,34 @@ will be split as follows:
830830
"you today?",
831831
]
832832
```
833+
834+
### `--document-tests`: show test items
835+
836+
Using this flag looks like this:
837+
838+
```bash
839+
$ rustdoc src/lib.rs -Z unstable-options --cfg test --document-private-items --document-tests
840+
```
841+
842+
By default, `rustdoc` does not document test items.
843+
844+
```rust
845+
/// by default this test function would not be documented
846+
#[test]
847+
fn test_in_module() {
848+
assert_eq!(2, 1 + 1);
849+
}
850+
/// by default this test module would not be documented
851+
#[cfg(test)]
852+
mod tests {
853+
/// by default this test function would not be documented
854+
#[test]
855+
fn test_in_a_test_module() {
856+
assert_eq!(2, 1 + 1);
857+
}
858+
}
859+
```
860+
861+
Note:
862+
* `--cfg test` must be set because tests are guarded by #[cfg(test)].
863+
* `--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
@@ -1040,7 +1040,11 @@ fn clean_fn_or_proc_macro<'tcx>(
10401040
None => {
10411041
let mut func = clean_function(cx, sig, generics, FunctionArgs::Body(body_id));
10421042
clean_fn_decl_legacy_const_generics(&mut func, attrs);
1043-
FunctionItem(func)
1043+
if cx.cache.document_tests && cx.cache.tests.contains(&item.owner_id.to_def_id()) {
1044+
TestItem(func)
1045+
} else {
1046+
FunctionItem(func)
1047+
}
10441048
}
10451049
}
10461050
}

src/librustdoc/clean/types.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -697,7 +697,8 @@ impl Item {
697697
}
698698
ItemKind::FunctionItem(_)
699699
| ItemKind::MethodItem(_, _)
700-
| ItemKind::RequiredMethodItem(_) => {
700+
| ItemKind::RequiredMethodItem(_)
701+
| ItemKind::TestItem(_) => {
701702
let def_id = self.def_id().unwrap();
702703
build_fn_header(def_id, tcx, tcx.asyncness(def_id))
703704
}
@@ -871,6 +872,7 @@ pub(crate) enum ItemKind {
871872
UnionItem(Union),
872873
EnumItem(Enum),
873874
FunctionItem(Box<Function>),
875+
TestItem(Box<Function>),
874876
ModuleItem(Module),
875877
TypeAliasItem(Box<TypeAlias>),
876878
StaticItem(Static),
@@ -931,6 +933,7 @@ impl ItemKind {
931933
ExternCrateItem { .. }
932934
| ImportItem(_)
933935
| FunctionItem(_)
936+
| TestItem(_)
934937
| TypeAliasItem(_)
935938
| StaticItem(_)
936939
| 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
@@ -280,6 +280,8 @@ pub(crate) struct RenderOptions {
280280
pub(crate) document_private: bool,
281281
/// Document items that have `doc(hidden)`.
282282
pub(crate) document_hidden: bool,
283+
/// Document tests.
284+
pub(crate) document_tests: bool,
283285
/// If `true`, generate a JSON file in the crate folder instead of HTML redirection files.
284286
pub(crate) generate_redirect_map: bool,
285287
/// Show the memory layout of types in the docs.
@@ -792,6 +794,7 @@ impl Options {
792794
}
793795

794796
let scrape_examples_options = ScrapeExamplesOptions::new(matches, dcx);
797+
let document_tests = matches.opt_present("document-tests");
795798
let with_examples = matches.opt_strs("with-examples");
796799
let call_locations = crate::scrape_examples::load_call_locations(with_examples, dcx);
797800
let doctest_compilation_args = matches.opt_strs("doctest-compilation-args");
@@ -865,6 +868,7 @@ impl Options {
865868
markdown_playground_url,
866869
document_private,
867870
document_hidden,
871+
document_tests,
868872
generate_redirect_map,
869873
show_type_layout,
870874
unstable_features,

src/librustdoc/core.rs

+8-3
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ pub(crate) fn create_config(
219219
remap_path_prefix,
220220
..
221221
}: RustdocOptions,
222-
RenderOptions { document_private, .. }: &RenderOptions,
222+
RenderOptions { document_private, document_tests, .. }: &RenderOptions,
223223
) -> rustc_interface::Config {
224224
// Add the doc cfg into the doc build.
225225
cfgs.push("doc".to_string());
@@ -247,7 +247,8 @@ pub(crate) fn create_config(
247247
if proc_macro_crate { vec![CrateType::ProcMacro] } else { vec![CrateType::Rlib] };
248248
let resolve_doc_links =
249249
if *document_private { ResolveDocLinks::All } else { ResolveDocLinks::Exported };
250-
let test = scrape_examples_options.map(|opts| opts.scrape_tests).unwrap_or(false);
250+
let test = scrape_examples_options.map(|opts| opts.scrape_tests).unwrap_or(false)
251+
|| (cfgs.iter().any(|cfg| cfg == "test") && *document_tests);
251252
// plays with error output here!
252253
let sessopts = config::Options {
253254
maybe_sysroot,
@@ -358,7 +359,11 @@ pub(crate) fn run_global_ctxt(
358359
impl_trait_bounds: Default::default(),
359360
generated_synthetics: Default::default(),
360361
auto_traits,
361-
cache: Cache::new(render_options.document_private, render_options.document_hidden),
362+
cache: Cache::new(
363+
render_options.document_private,
364+
render_options.document_hidden,
365+
render_options.document_tests,
366+
),
362367
inlined: FxHashSet::default(),
363368
output_format,
364369
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
@@ -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
}
@@ -471,6 +480,7 @@ impl AllTypes {
471480
print_entries(f, &self.attribute_macros, ItemSection::AttributeMacros);
472481
print_entries(f, &self.derive_macros, ItemSection::DeriveMacros);
473482
print_entries(f, &self.functions, ItemSection::Functions);
483+
print_entries(f, &self.tests, ItemSection::Tests);
474484
print_entries(f, &self.type_aliases, ItemSection::TypeAliases);
475485
print_entries(f, &self.trait_aliases, ItemSection::TraitAliases);
476486
print_entries(f, &self.statics, ItemSection::Statics);
@@ -2385,6 +2395,7 @@ pub(crate) enum ItemSection {
23852395
Statics,
23862396
Traits,
23872397
Functions,
2398+
Tests,
23882399
TypeAliases,
23892400
Unions,
23902401
Implementations,
@@ -2417,6 +2428,7 @@ impl ItemSection {
24172428
Statics,
24182429
Traits,
24192430
Functions,
2431+
Tests,
24202432
TypeAliases,
24212433
Unions,
24222434
Implementations,
@@ -2442,6 +2454,7 @@ impl ItemSection {
24422454
Self::Unions => "unions",
24432455
Self::Enums => "enums",
24442456
Self::Functions => "functions",
2457+
Self::Tests => "tests",
24452458
Self::TypeAliases => "types",
24462459
Self::Statics => "statics",
24472460
Self::Constants => "constants",
@@ -2471,6 +2484,7 @@ impl ItemSection {
24712484
Self::Unions => "Unions",
24722485
Self::Enums => "Enums",
24732486
Self::Functions => "Functions",
2487+
Self::Tests => "Tests",
24742488
Self::TypeAliases => "Type Aliases",
24752489
Self::Statics => "Statics",
24762490
Self::Constants => "Constants",
@@ -2501,6 +2515,7 @@ fn item_ty_to_section(ty: ItemType) -> ItemSection {
25012515
ItemType::Union => ItemSection::Unions,
25022516
ItemType::Enum => ItemSection::Enums,
25032517
ItemType::Function => ItemSection::Functions,
2518+
ItemType::Test => ItemSection::Tests,
25042519
ItemType::TypeAlias => ItemSection::TypeAliases,
25052520
ItemType::Static => ItemSection::Statics,
25062521
ItemType::Constant => ItemSection::Constants,

src/librustdoc/html/render/print_item.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@ pub(super) fn print_item<'a, 'tcx>(
178178
}
179179
}
180180
clean::FunctionItem(..) | clean::ForeignFunctionItem(..) => "Function ",
181+
clean::TestItem(..) => "Test ",
181182
clean::TraitItem(..) => "Trait ",
182183
clean::StructItem(..) => "Struct ",
183184
clean::UnionItem(..) => "Union ",
@@ -244,7 +245,9 @@ pub(super) fn print_item<'a, 'tcx>(
244245
clean::ModuleItem(ref m) => {
245246
write!(buf, "{}", item_module(cx, item, &m.items))
246247
}
247-
clean::FunctionItem(ref f) | clean::ForeignFunctionItem(ref f, _) => {
248+
clean::FunctionItem(ref f)
249+
| clean::ForeignFunctionItem(ref f, _)
250+
| clean::TestItem(ref f) => {
248251
write!(buf, "{}", item_function(cx, item, f))
249252
}
250253
clean::TraitItem(ref t) => write!(buf, "{}", item_trait(cx, item, t)),
@@ -346,6 +349,7 @@ fn item_module<'a, 'tcx>(
346349
ItemType::Static => 8,
347350
ItemType::Trait => 9,
348351
ItemType::Function => 10,
352+
ItemType::Test => 11,
349353
ItemType::TypeAlias => 12,
350354
ItemType::Union => 13,
351355
_ => 14 + ty as u8,

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

+1
Original file line numberDiff line numberDiff line change
@@ -656,6 +656,7 @@ function preLoadCss(cssUrl) {
656656
block("static", "static", "Statics");
657657
block("trait", "traits", "Traits");
658658
block("fn", "functions", "Functions");
659+
block("test", "tests", "Tests");
659660
block("type", "types", "Type Aliases");
660661
block("union", "unions", "Unions");
661662
// 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
@@ -77,6 +77,7 @@ impl DocFolder for StabilityPropagator<'_, '_> {
7777
| ItemKind::UnionItem(..)
7878
| ItemKind::EnumItem(..)
7979
| ItemKind::FunctionItem(..)
80+
| ItemKind::TestItem(..)
8081
| ItemKind::ModuleItem(..)
8182
| ItemKind::TypeAliasItem(..)
8283
| 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)