[rustdoc] Add `--output-format=doctest` command-line flag by GuillaumeGomez · Pull Request #134531 · rust-lang/rust

@rustbot rustbot added S-waiting-on-review

Status: Awaiting review from the assignee but also interested parties.

T-rustdoc

Relevant to the rustdoc team, which will review and decide on the PR/issue.

labels

Dec 19, 2024

@ojeda ojeda mentioned this pull request

Dec 19, 2024

48 tasks

notriddle

@rustbot rustbot added S-waiting-on-author

Status: This is awaiting some action (such as code changes or more information) from the author.

and removed S-waiting-on-review

Status: Awaiting review from the assignee but also interested parties.

labels

Dec 20, 2024

aDotInTheVoid

@GuillaumeGomez

@bors bors added S-waiting-on-bors

Status: Waiting on bors to run and complete tests. Bors will change the label on completion.

and removed S-waiting-on-author

Status: This is awaiting some action (such as code changes or more information) from the author.

labels

Jan 31, 2025

bors added a commit to rust-lang-ci/rust that referenced this pull request

Jan 31, 2025

bors added a commit to rust-lang-ci/rust that referenced this pull request

Jan 31, 2025

rust-timer added a commit to rust-lang-ci/rust that referenced this pull request

Jan 31, 2025
Rollup merge of rust-lang#134531 - GuillaumeGomez:extract-doctests, r=notriddle,aDotInTheVoid

[rustdoc] Add `--extract-doctests` command-line flag

Part of rust-lang#134529.

It was discussed with the Rust-for-Linux project recently that they needed a way to extract doctests so they can modify them and then run them more easily (look for "a way to extract doctests" [here](Rust-for-Linux/linux#2)).

For now, I output most of `ScrapedDoctest` fields in JSON format with `serde_json`. So it outputs the following information:

 * filename
 * line
 * langstr
 * text

cc `@ojeda`
r? `@notriddle`

@aDotInTheVoid aDotInTheVoid changed the title [rustdoc] Add --extract-doctests command-line flag [rustdoc] Add --output-format=doctest command-line flag

Feb 1, 2025

jhpratt added a commit to jhpratt/rust that referenced this pull request

Feb 4, 2025

fmease added a commit to fmease/rust that referenced this pull request

Feb 5, 2025

rust-timer added a commit to rust-lang-ci/rust that referenced this pull request

Feb 5, 2025

intel-lab-lkp pushed a commit to intel-lab-lkp/linux that referenced this pull request

Feb 28, 2025
…e doctest handling.

Thanks for the detailed answer!

I added the missing "Signed-of-by" in the commit message.

I added some more context in the commit message, hopefully I didn't
miss anything.

> We currently support versions 1.78+, so we will need to do these
> things conditionally. I can help with that, so don't worry too much
> about it for the moment (e.g. we have `rustc-option` and other helpers
> to pick the right flags given a version etc.).

I'll definitely need some help here. I'm not sure current stable already
has this change so until then, we'll need a beta/nightly version to run
these tests.

> Hmm... I was hoping we could do something on the `rustdoc` side to
> remove these hacks altogether since we are going to have a "proper
> flag" for it, i.e. to avoid relying on the particular "format" of the
> tests somehow.

I opened rust-lang/rust#137807 to resolve
this problem.

> > +    let doctest_code = doctest_code.replace(
> > +        "} _inner().unwrap() }",
> > +        "} let test_return_value = _inner(); assert!(test_return_value.is_ok()); }",
> >      );
> > +    std::fs::write(path, doctest_code.as_bytes()).unwrap();
> > +}
>
> Same for this.

For this one I'll need to check first if it can be done "safely" (ie,
so unexpected side
effect).

> > +    } else {
> > +        panic!("missing `format_version` field");
> > +    }
>
> `expect` maybe?

I don't think `expect` would work in any of the cases in this file.
What I suggest
is to add methods on `JsonValue` in a future patch which would allow to reduce
code in this file (and call `expect` too).

> These two bits could go in a first patch, I think, though it isn't a big deal.

You're absolutely right, removing them and sending a separate patch.

Here is the updated patch:

The goal of this patch is to remove the use of 2 unstable rustdoc features
(`--no-run` and `--test-builder`) and replace it with a stable feature:
`--output-format=doctest`, which was added in
rust-lang/rust#134531.

Before this patch, the code was using very hacky methods in order to retrieve
doctests, modify them as needed and then concatenate all of them in one file.

Now, with this new flag, it instead asks rustdoc to provide the doctests
code with their associated information such as file path and line number.

Signed-off-by: Guillaume Gomez <guillaume1.gomez@gmail.com>

jhpratt added a commit to jhpratt/rust that referenced this pull request

Jun 14, 2025
…r=aDotInTheVoid

[rustdoc] Give more information into extracted doctest information

Follow-up of rust-lang#134531.

This update fragment the doctest code into its sub-parts to give more control to the end users on how they want to use it.

The new JSON looks like this:

```json
{
  "format_version":2,
  "doctests":[
    {
      "file":"$DIR/extract-doctests-result.rs",
      "line":8,
      "doctest_attributes":{
        "original":"",
        "should_panic":false,
        "no_run":false,
        "ignore":"None",
        "rust":true,
        "test_harness":false,
        "compile_fail":false,
        "standalone_crate":false,
        "error_codes":[],
        "edition":null,
        "added_css_classes":[],
        "unknown":[]
      },
      "original_code":"let x = 12;\nOk(())",
      "doctest_code":{
        "crate_level":"#![allow(unused)]\n",
        "code":"let x = 12;\nOk(())",
        "wrapper":{
          "before":"fn main() { fn _inner() -> core::result::Result<(), impl core::fmt::Debug> {\n",
          "after":"\n} _inner().unwrap() }",
          "returns_result":true
        }
      },
      "name":"$DIR/extract-doctests-result.rs - (line 8)"
    }
  ]
}
```

for this doctest:

```rust
let x = 12;
Ok(())
```

With this, I think it matches what you need `@ojeda?` If so, once merged I'll update the patch I sent to RfL.

r? `@aDotInTheVoid`

matthiaskrgr added a commit to matthiaskrgr/rust that referenced this pull request

Jun 14, 2025
…r=aDotInTheVoid

[rustdoc] Give more information into extracted doctest information

Follow-up of rust-lang#134531.

This update fragment the doctest code into its sub-parts to give more control to the end users on how they want to use it.

The new JSON looks like this:

```json
{
  "format_version":2,
  "doctests":[
    {
      "file":"$DIR/extract-doctests-result.rs",
      "line":8,
      "doctest_attributes":{
        "original":"",
        "should_panic":false,
        "no_run":false,
        "ignore":"None",
        "rust":true,
        "test_harness":false,
        "compile_fail":false,
        "standalone_crate":false,
        "error_codes":[],
        "edition":null,
        "added_css_classes":[],
        "unknown":[]
      },
      "original_code":"let x = 12;\nOk(())",
      "doctest_code":{
        "crate_level":"#![allow(unused)]\n",
        "code":"let x = 12;\nOk(())",
        "wrapper":{
          "before":"fn main() { fn _inner() -> core::result::Result<(), impl core::fmt::Debug> {\n",
          "after":"\n} _inner().unwrap() }",
          "returns_result":true
        }
      },
      "name":"$DIR/extract-doctests-result.rs - (line 8)"
    }
  ]
}
```

for this doctest:

```rust
let x = 12;
Ok(())
```

With this, I think it matches what you need ``@ojeda?`` If so, once merged I'll update the patch I sent to RfL.

r? ``@aDotInTheVoid``

rust-timer added a commit that referenced this pull request

Jun 14, 2025
Rollup merge of #141399 - GuillaumeGomez:extracted-doctest, r=aDotInTheVoid

[rustdoc] Give more information into extracted doctest information

Follow-up of #134531.

This update fragment the doctest code into its sub-parts to give more control to the end users on how they want to use it.

The new JSON looks like this:

```json
{
  "format_version":2,
  "doctests":[
    {
      "file":"$DIR/extract-doctests-result.rs",
      "line":8,
      "doctest_attributes":{
        "original":"",
        "should_panic":false,
        "no_run":false,
        "ignore":"None",
        "rust":true,
        "test_harness":false,
        "compile_fail":false,
        "standalone_crate":false,
        "error_codes":[],
        "edition":null,
        "added_css_classes":[],
        "unknown":[]
      },
      "original_code":"let x = 12;\nOk(())",
      "doctest_code":{
        "crate_level":"#![allow(unused)]\n",
        "code":"let x = 12;\nOk(())",
        "wrapper":{
          "before":"fn main() { fn _inner() -> core::result::Result<(), impl core::fmt::Debug> {\n",
          "after":"\n} _inner().unwrap() }",
          "returns_result":true
        }
      },
      "name":"$DIR/extract-doctests-result.rs - (line 8)"
    }
  ]
}
```

for this doctest:

```rust
let x = 12;
Ok(())
```

With this, I think it matches what you need ``@ojeda?`` If so, once merged I'll update the patch I sent to RfL.

r? ``@aDotInTheVoid``

RalfJung pushed a commit to RalfJung/miri that referenced this pull request

Jun 15, 2025
…heVoid

[rustdoc] Give more information into extracted doctest information

Follow-up of rust-lang/rust#134531.

This update fragment the doctest code into its sub-parts to give more control to the end users on how they want to use it.

The new JSON looks like this:

```json
{
  "format_version":2,
  "doctests":[
    {
      "file":"$DIR/extract-doctests-result.rs",
      "line":8,
      "doctest_attributes":{
        "original":"",
        "should_panic":false,
        "no_run":false,
        "ignore":"None",
        "rust":true,
        "test_harness":false,
        "compile_fail":false,
        "standalone_crate":false,
        "error_codes":[],
        "edition":null,
        "added_css_classes":[],
        "unknown":[]
      },
      "original_code":"let x = 12;\nOk(())",
      "doctest_code":{
        "crate_level":"#![allow(unused)]\n",
        "code":"let x = 12;\nOk(())",
        "wrapper":{
          "before":"fn main() { fn _inner() -> core::result::Result<(), impl core::fmt::Debug> {\n",
          "after":"\n} _inner().unwrap() }",
          "returns_result":true
        }
      },
      "name":"$DIR/extract-doctests-result.rs - (line 8)"
    }
  ]
}
```

for this doctest:

```rust
let x = 12;
Ok(())
```

With this, I think it matches what you need ``@ojeda?`` If so, once merged I'll update the patch I sent to RfL.

r? ``@aDotInTheVoid``

github-actions bot pushed a commit to rust-lang/rustc-dev-guide that referenced this pull request

Jun 16, 2025
…heVoid

[rustdoc] Give more information into extracted doctest information

Follow-up of rust-lang/rust#134531.

This update fragment the doctest code into its sub-parts to give more control to the end users on how they want to use it.

The new JSON looks like this:

```json
{
  "format_version":2,
  "doctests":[
    {
      "file":"$DIR/extract-doctests-result.rs",
      "line":8,
      "doctest_attributes":{
        "original":"",
        "should_panic":false,
        "no_run":false,
        "ignore":"None",
        "rust":true,
        "test_harness":false,
        "compile_fail":false,
        "standalone_crate":false,
        "error_codes":[],
        "edition":null,
        "added_css_classes":[],
        "unknown":[]
      },
      "original_code":"let x = 12;\nOk(())",
      "doctest_code":{
        "crate_level":"#![allow(unused)]\n",
        "code":"let x = 12;\nOk(())",
        "wrapper":{
          "before":"fn main() { fn _inner() -> core::result::Result<(), impl core::fmt::Debug> {\n",
          "after":"\n} _inner().unwrap() }",
          "returns_result":true
        }
      },
      "name":"$DIR/extract-doctests-result.rs - (line 8)"
    }
  ]
}
```

for this doctest:

```rust
let x = 12;
Ok(())
```

With this, I think it matches what you need ``@ojeda?`` If so, once merged I'll update the patch I sent to RfL.

r? ``@aDotInTheVoid``

intel-lab-lkp pushed a commit to intel-lab-lkp/linux that referenced this pull request

Jun 17, 2025
…e doctest handling

The goal of this patch is to remove the use of 2 unstable
rustdoc features (`--no-run` and `--test-builder`) and replace it with a
stable feature: `--output-format=doctest`, which was added in
rust-lang/rust#134531.

Before this patch, the code was using very hacky methods in order to retrieve
doctests, modify them as needed and then concatenate all of them in one file.

Now, with this new flag, it instead asks rustdoc to provide the doctests
code with their associated information such as file path and line number.

Signed-off-by: Guillaume Gomez <guillaume1.gomez@gmail.com>

github-actions bot pushed a commit to rust-lang/compiler-builtins that referenced this pull request

Jul 12, 2025
…heVoid

[rustdoc] Give more information into extracted doctest information

Follow-up of rust-lang/rust#134531.

This update fragment the doctest code into its sub-parts to give more control to the end users on how they want to use it.

The new JSON looks like this:

```json
{
  "format_version":2,
  "doctests":[
    {
      "file":"$DIR/extract-doctests-result.rs",
      "line":8,
      "doctest_attributes":{
        "original":"",
        "should_panic":false,
        "no_run":false,
        "ignore":"None",
        "rust":true,
        "test_harness":false,
        "compile_fail":false,
        "standalone_crate":false,
        "error_codes":[],
        "edition":null,
        "added_css_classes":[],
        "unknown":[]
      },
      "original_code":"let x = 12;\nOk(())",
      "doctest_code":{
        "crate_level":"#![allow(unused)]\n",
        "code":"let x = 12;\nOk(())",
        "wrapper":{
          "before":"fn main() { fn _inner() -> core::result::Result<(), impl core::fmt::Debug> {\n",
          "after":"\n} _inner().unwrap() }",
          "returns_result":true
        }
      },
      "name":"$DIR/extract-doctests-result.rs - (line 8)"
    }
  ]
}
```

for this doctest:

```rust
let x = 12;
Ok(())
```

With this, I think it matches what you need ``@ojeda?`` If so, once merged I'll update the patch I sent to RfL.

r? ``@aDotInTheVoid``