Skip to content

Commit ad87732

Browse files
authored
Rollup merge of #138104 - GuillaumeGomez:simplify-doctest-parsing, r=fmease
Greatly simplify doctest parsing and information extraction The original process was pretty terrible, as it tried to extract information such as attributes by performing matches over tokens like `#!`, which doesn't work very well considering you can have `# ! [`, which is valid. Also, it now does it in one pass: if the parser is happy, then we try to extract information, otherwise we return early. r? `@fmease`
2 parents 9597bf7 + 87d524b commit ad87732

File tree

10 files changed

+314
-375
lines changed

10 files changed

+314
-375
lines changed

src/librustdoc/doctest/make.rs

+191-355
Large diffs are not rendered by default.

src/librustdoc/doctest/tests.rs

+76-2
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,7 @@ fn make_test_crate_attrs() {
197197
assert_eq!(2+2, 4);";
198198
let expected = "#![allow(unused)]
199199
#![feature(sick_rad)]
200+
200201
fn main() {
201202
assert_eq!(2+2, 4);
202203
}"
@@ -228,8 +229,8 @@ fn make_test_fake_main() {
228229
let input = "//Ceci n'est pas une `fn main`
229230
assert_eq!(2+2, 4);";
230231
let expected = "#![allow(unused)]
231-
//Ceci n'est pas une `fn main`
232232
fn main() {
233+
//Ceci n'est pas une `fn main`
233234
assert_eq!(2+2, 4);
234235
}"
235236
.to_string();
@@ -259,8 +260,8 @@ fn make_test_issues_21299() {
259260
assert_eq!(2+2, 4);";
260261

261262
let expected = "#![allow(unused)]
262-
// fn main
263263
fn main() {
264+
// fn main
264265
assert_eq!(2+2, 4);
265266
}"
266267
.to_string();
@@ -401,3 +402,76 @@ fn check_split_args() {
401402
compare("a\n\t \rb", &["a", "b"]);
402403
compare("a\n\t1 \rb", &["a", "1", "b"]);
403404
}
405+
406+
#[test]
407+
fn comment_in_attrs() {
408+
// If there is an inline code comment after attributes, we need to ensure that
409+
// a backline will be added to prevent generating code "inside" it (and thus generating)
410+
// invalid code.
411+
let opts = default_global_opts("");
412+
let input = "\
413+
#![feature(rustdoc_internals)]
414+
#![allow(internal_features)]
415+
#![doc(rust_logo)]
416+
//! This crate has the Rust(tm) branding on it.";
417+
let expected = "\
418+
#![allow(unused)]
419+
#![feature(rustdoc_internals)]
420+
#![allow(internal_features)]
421+
#![doc(rust_logo)]
422+
//! This crate has the Rust(tm) branding on it.
423+
fn main() {
424+
425+
}"
426+
.to_string();
427+
let (output, len) = make_test(input, None, false, &opts, None);
428+
assert_eq!((output, len), (expected, 2));
429+
430+
// And same, if there is a `main` function provided by the user, we ensure that it's
431+
// correctly separated.
432+
let input = "\
433+
#![feature(rustdoc_internals)]
434+
#![allow(internal_features)]
435+
#![doc(rust_logo)]
436+
//! This crate has the Rust(tm) branding on it.
437+
fn main() {}";
438+
let expected = "\
439+
#![allow(unused)]
440+
#![feature(rustdoc_internals)]
441+
#![allow(internal_features)]
442+
#![doc(rust_logo)]
443+
//! This crate has the Rust(tm) branding on it.
444+
445+
fn main() {}"
446+
.to_string();
447+
let (output, len) = make_test(input, None, false, &opts, None);
448+
assert_eq!((output, len), (expected, 1));
449+
}
450+
451+
// This test ensures that the only attributes taken into account when we switch between
452+
// "crate level" content and the rest doesn't include inner attributes span, as it would
453+
// include part of the item and generate broken code.
454+
#[test]
455+
fn inner_attributes() {
456+
let opts = default_global_opts("");
457+
let input = r#"
458+
//! A doc comment that applies to the implicit anonymous module of this crate
459+
460+
pub mod outer_module {
461+
//!! - Still an inner line doc (but with a bang at the beginning)
462+
}
463+
"#;
464+
let expected = "#![allow(unused)]
465+
466+
//! A doc comment that applies to the implicit anonymous module of this crate
467+
468+
469+
fn main() {
470+
pub mod outer_module {
471+
//!! - Still an inner line doc (but with a bang at the beginning)
472+
}
473+
}"
474+
.to_string();
475+
let (output, len) = make_test(input, None, false, &opts, None);
476+
assert_eq!((output, len), (expected, 2));
477+
}

tests/coverage-run-rustdoc/doctest.coverage

+8-8
Original file line numberDiff line numberDiff line change
@@ -58,21 +58,21 @@ $DIR/doctest.rs:
5858
LL| |//!
5959
LL| |//! doctest with custom main:
6060
LL| |//! ```
61-
LL| 1|//! fn some_func() {
62-
LL| 1|//! println!("called some_func()");
63-
LL| 1|//! }
64-
LL| |//!
65-
LL| |//! #[derive(Debug)]
66-
LL| |//! struct SomeError;
61+
LL| |//! fn some_func() {
62+
LL| |//! println!("called some_func()");
63+
LL| |//! }
64+
LL| 1|//!
65+
LL| 1|//! #[derive(Debug)]
66+
LL| 1|//! struct SomeError;
6767
LL| |//!
6868
LL| |//! extern crate doctest_crate;
6969
LL| |//!
70-
LL| 1|//! fn doctest_main() -> Result<(), SomeError> {
70+
LL| |//! fn doctest_main() -> Result<(), SomeError> {
7171
LL| 1|//! some_func();
7272
LL| 1|//! doctest_crate::fn_run_in_doctests(2);
7373
LL| 1|//! Ok(())
7474
LL| 1|//! }
75-
LL| |//!
75+
LL| 1|//!
7676
LL| |//! // this `main` is not shown as covered, as it clashes with all the other
7777
LL| |//! // `main` functions that were automatically generated for doctests
7878
LL| |//! fn main() -> Result<(), SomeError> {

tests/run-make/rustdoc-error-lines/rmake.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@ fn main() {
88

99
let should_contain = &[
1010
"input.rs - foo (line 5)",
11-
"input.rs:7:15",
11+
"input.rs:8:15",
1212
"input.rs - bar (line 13)",
13-
"input.rs:15:15",
13+
"input.rs:16:15",
1414
"input.rs - bar (line 22)",
15-
"input.rs:24:15",
15+
"input.rs:25:15",
1616
];
1717
for text in should_contain {
1818
assert!(output.contains(text), "output doesn't contains {:?}", text);

tests/rustdoc-ui/doctest/display-output.stdout

+3-3
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ successes:
66

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

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

2727
warning: function `foo` is never used
28-
--> $DIR/display-output.rs:13:4
28+
--> $DIR/display-output.rs:14:4
2929
|
3030
LL | fn foo(x: &dyn std::fmt::Display) {}
3131
| ^^^
+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//@ check-pass
2+
//@ compile-flags:--test --test-args=--test-threads=1
3+
//@ normalize-stdout: "tests/rustdoc-ui/doctest" -> "$$DIR"
4+
//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME"
5+
6+
// This test ensures that crate imports are placed outside of the `main` function
7+
// so they work all the time (even in 2015 edition).
8+
9+
/// ```rust
10+
/// #![feature(test)]
11+
///
12+
/// extern crate test;
13+
/// use test::Bencher;
14+
///
15+
/// #[bench]
16+
/// fn bench_xor_1000_ints(b: &mut Bencher) {
17+
/// b.iter(|| {
18+
/// (0..1000).fold(0, |old, new| old ^ new);
19+
/// });
20+
/// }
21+
/// ```
22+
///
23+
pub fn foo() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
2+
running 1 test
3+
test $DIR/extern-crate.rs - foo (line 9) ... ok
4+
5+
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
6+
+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +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)"}]}
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":null,"name":"$DIR/extract-doctests.rs - (line 13)"}]}

tests/rustdoc-ui/remap-path-prefix-invalid-doctest.stdout

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@ test remapped_path/remap-path-prefix-invalid-doctest.rs - SomeStruct (line 10) .
55
failures:
66

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

1414
error: aborting due to 1 previous error
1515

tests/rustdoc/playground.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,4 @@
2424
2525
//@ 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"]' ""
2626
//@ 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"]' ""
27-
//@ 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"]' ""
27+
//@ 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"]' ""

0 commit comments

Comments
 (0)