Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Greatly simplify doctest parsing and information extraction #138104

Merged
merged 12 commits into from
Mar 28, 2025
Merged
546 changes: 191 additions & 355 deletions src/librustdoc/doctest/make.rs

Large diffs are not rendered by default.

78 changes: 76 additions & 2 deletions src/librustdoc/doctest/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ fn make_test_crate_attrs() {
assert_eq!(2+2, 4);";
let expected = "#![allow(unused)]
#![feature(sick_rad)]

fn main() {
assert_eq!(2+2, 4);
}"
Expand Down Expand Up @@ -228,8 +229,8 @@ fn make_test_fake_main() {
let input = "//Ceci n'est pas une `fn main`
assert_eq!(2+2, 4);";
let expected = "#![allow(unused)]
//Ceci n'est pas une `fn main`
fn main() {
//Ceci n'est pas une `fn main`
assert_eq!(2+2, 4);
}"
.to_string();
Expand Down Expand Up @@ -259,8 +260,8 @@ fn make_test_issues_21299() {
assert_eq!(2+2, 4);";

let expected = "#![allow(unused)]
// fn main
fn main() {
// fn main
assert_eq!(2+2, 4);
}"
.to_string();
Expand Down Expand Up @@ -401,3 +402,76 @@ fn check_split_args() {
compare("a\n\t \rb", &["a", "b"]);
compare("a\n\t1 \rb", &["a", "1", "b"]);
}

#[test]
fn comment_in_attrs() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wait, what has this test to do with comments? There are no comments, only an inner doc comment – which also isn't "in [an] attr"

// If there is an inline code comment after attributes, we need to ensure that
// a backline will be added to prevent generating code "inside" it (and thus generating)
// invalid code.
let opts = default_global_opts("");
let input = "\
#![feature(rustdoc_internals)]
#![allow(internal_features)]
#![doc(rust_logo)]
//! This crate has the Rust(tm) branding on it.";
let expected = "\
#![allow(unused)]
#![feature(rustdoc_internals)]
#![allow(internal_features)]
#![doc(rust_logo)]
//! This crate has the Rust(tm) branding on it.
fn main() {

}"
.to_string();
let (output, len) = make_test(input, None, false, &opts, None);
assert_eq!((output, len), (expected, 2));

// And same, if there is a `main` function provided by the user, we ensure that it's
// correctly separated.
let input = "\
#![feature(rustdoc_internals)]
#![allow(internal_features)]
#![doc(rust_logo)]
//! This crate has the Rust(tm) branding on it.
fn main() {}";
let expected = "\
#![allow(unused)]
#![feature(rustdoc_internals)]
#![allow(internal_features)]
#![doc(rust_logo)]
//! This crate has the Rust(tm) branding on it.

fn main() {}"
.to_string();
let (output, len) = make_test(input, None, false, &opts, None);
assert_eq!((output, len), (expected, 1));
}

// This test ensures that the only attributes taken into account when we switch between
// "crate level" content and the rest doesn't include inner attributes span, as it would
// include part of the item and generate broken code.
#[test]
fn inner_attributes() {
let opts = default_global_opts("");
let input = r#"
//! A doc comment that applies to the implicit anonymous module of this crate

pub mod outer_module {
//!! - Still an inner line doc (but with a bang at the beginning)
}
"#;
let expected = "#![allow(unused)]

//! A doc comment that applies to the implicit anonymous module of this crate


fn main() {
pub mod outer_module {
//!! - Still an inner line doc (but with a bang at the beginning)
}
}"
.to_string();
let (output, len) = make_test(input, None, false, &opts, None);
assert_eq!((output, len), (expected, 2));
}
16 changes: 8 additions & 8 deletions tests/coverage-run-rustdoc/doctest.coverage
Original file line number Diff line number Diff line change
Expand Up @@ -58,21 +58,21 @@ $DIR/doctest.rs:
LL| |//!
LL| |//! doctest with custom main:
LL| |//! ```
LL| 1|//! fn some_func() {
LL| 1|//! println!("called some_func()");
LL| 1|//! }
LL| |//!
LL| |//! #[derive(Debug)]
LL| |//! struct SomeError;
LL| |//! fn some_func() {
LL| |//! println!("called some_func()");
LL| |//! }
LL| 1|//!
LL| 1|//! #[derive(Debug)]
LL| 1|//! struct SomeError;
LL| |//!
LL| |//! extern crate doctest_crate;
LL| |//!
LL| 1|//! fn doctest_main() -> Result<(), SomeError> {
LL| |//! fn doctest_main() -> Result<(), SomeError> {
LL| 1|//! some_func();
LL| 1|//! doctest_crate::fn_run_in_doctests(2);
LL| 1|//! Ok(())
LL| 1|//! }
LL| |//!
LL| 1|//!
LL| |//! // this `main` is not shown as covered, as it clashes with all the other
LL| |//! // `main` functions that were automatically generated for doctests
LL| |//! fn main() -> Result<(), SomeError> {
Expand Down
6 changes: 3 additions & 3 deletions tests/run-make/rustdoc-error-lines/rmake.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ fn main() {

let should_contain = &[
"input.rs - foo (line 5)",
"input.rs:7:15",
"input.rs:8:15",
"input.rs - bar (line 13)",
"input.rs:15:15",
"input.rs:16:15",
"input.rs - bar (line 22)",
"input.rs:24:15",
"input.rs:25:15",
];
for text in should_contain {
assert!(output.contains(text), "output doesn't contains {:?}", text);
Expand Down
6 changes: 3 additions & 3 deletions tests/rustdoc-ui/doctest/display-output.stdout
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ successes:

---- $DIR/display-output.rs - foo (line 9) stdout ----
warning: unused variable: `x`
--> $DIR/display-output.rs:11:5
--> $DIR/display-output.rs:12:5
|
LL | let x = 12;
| ^ help: if this is intentional, prefix it with an underscore: `_x`
Expand All @@ -19,13 +19,13 @@ LL | #![warn(unused)]
= note: `#[warn(unused_variables)]` implied by `#[warn(unused)]`

warning: unused variable: `x`
--> $DIR/display-output.rs:13:8
--> $DIR/display-output.rs:14:8
|
LL | fn foo(x: &dyn std::fmt::Display) {}
| ^ help: if this is intentional, prefix it with an underscore: `_x`

warning: function `foo` is never used
--> $DIR/display-output.rs:13:4
--> $DIR/display-output.rs:14:4
|
LL | fn foo(x: &dyn std::fmt::Display) {}
| ^^^
Expand Down
23 changes: 23 additions & 0 deletions tests/rustdoc-ui/doctest/extern-crate.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//@ check-pass
//@ compile-flags:--test --test-args=--test-threads=1
//@ normalize-stdout: "tests/rustdoc-ui/doctest" -> "$$DIR"
//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME"

// This test ensures that crate imports are placed outside of the `main` function
// so they work all the time (even in 2015 edition).

/// ```rust
/// #![feature(test)]
///
/// extern crate test;
/// use test::Bencher;
///
/// #[bench]
/// fn bench_xor_1000_ints(b: &mut Bencher) {
/// b.iter(|| {
/// (0..1000).fold(0, |old, new| old ^ new);
/// });
/// }
/// ```
///
pub fn foo() {}
6 changes: 6 additions & 0 deletions tests/rustdoc-ui/doctest/extern-crate.stdout
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@

running 1 test
test $DIR/extern-crate.rs - foo (line 9) ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME

2 changes: 1 addition & 1 deletion tests/rustdoc-ui/extract-doctests.stdout
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"format_version":1,"doctests":[{"file":"$DIR/extract-doctests.rs","line":8,"doctest_attributes":{"original":"ignore (checking attributes)","should_panic":false,"no_run":false,"ignore":"All","rust":true,"test_harness":false,"compile_fail":false,"standalone_crate":false,"error_codes":[],"edition":null,"added_css_classes":[],"unknown":[]},"original_code":"let x = 12;\nlet y = 14;","doctest_code":"#![allow(unused)]\nfn main() {\nlet x = 12;\nlet y = 14;\n}","name":"$DIR/extract-doctests.rs - (line 8)"},{"file":"$DIR/extract-doctests.rs","line":13,"doctest_attributes":{"original":"edition2018,compile_fail","should_panic":false,"no_run":true,"ignore":"None","rust":true,"test_harness":false,"compile_fail":true,"standalone_crate":false,"error_codes":[],"edition":"2018","added_css_classes":[],"unknown":[]},"original_code":"let","doctest_code":"#![allow(unused)]\nfn main() {\nlet\n}","name":"$DIR/extract-doctests.rs - (line 13)"}]}
{"format_version":1,"doctests":[{"file":"$DIR/extract-doctests.rs","line":8,"doctest_attributes":{"original":"ignore (checking attributes)","should_panic":false,"no_run":false,"ignore":"All","rust":true,"test_harness":false,"compile_fail":false,"standalone_crate":false,"error_codes":[],"edition":null,"added_css_classes":[],"unknown":[]},"original_code":"let x = 12;\nlet y = 14;","doctest_code":"#![allow(unused)]\nfn main() {\nlet x = 12;\nlet y = 14;\n}","name":"$DIR/extract-doctests.rs - (line 8)"},{"file":"$DIR/extract-doctests.rs","line":13,"doctest_attributes":{"original":"edition2018,compile_fail","should_panic":false,"no_run":true,"ignore":"None","rust":true,"test_harness":false,"compile_fail":true,"standalone_crate":false,"error_codes":[],"edition":"2018","added_css_classes":[],"unknown":[]},"original_code":"let","doctest_code":null,"name":"$DIR/extract-doctests.rs - (line 13)"}]}
4 changes: 2 additions & 2 deletions tests/rustdoc-ui/remap-path-prefix-invalid-doctest.stdout
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ test remapped_path/remap-path-prefix-invalid-doctest.rs - SomeStruct (line 10) .
failures:

---- remapped_path/remap-path-prefix-invalid-doctest.rs - SomeStruct (line 10) stdout ----
error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `is`
error: expected one of `!` or `::`, found `is`
--> remapped_path/remap-path-prefix-invalid-doctest.rs:11:6
|
LL | this is not real code
| ^^ expected one of 8 possible tokens
| ^^ expected one of `!` or `::`

error: aborting due to 1 previous error

Expand Down
2 changes: 1 addition & 1 deletion tests/rustdoc/playground.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,4 @@

//@ matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0Afn+main()+%7B%0A++++println!(%22Hello,+world!%22);%0A%7D&edition=2015"]' ""
//@ matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0Afn+main()+%7B%0A++++println!(%22Hello,+world!%22);%0A%7D&edition=2015"]' ""
//@ matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0A%23!%5Bfeature(something)%5D%0A%0Afn+main()+%7B%0A++++println!(%22Hello,+world!%22);%0A%7D&version=nightly&edition=2015"]' ""
//@ matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0A%23!%5Bfeature(something)%5D%0A%0A%0Afn+main()+%7B%0A++++println!(%22Hello,+world!%22);%0A%7D&version=nightly&edition=2015"]' ""
Loading