about summary refs log tree commit diff
diff options
context:
space:
mode:
authorGuillaume Gomez <guillaume1.gomez@gmail.com>2025-01-27 17:51:01 +0100
committerGuillaume Gomez <guillaume1.gomez@gmail.com>2025-01-29 13:57:27 +0100
commit43bf52989a86b7eaa4ebac68dcac9ca627f5cf54 (patch)
treedacba82cd82eff2ae6085c998dc0893dd935c280
parent7fa2094cb1bfccc37fa93baf8a45eb6ca24d43c4 (diff)
downloadrust-43bf52989a86b7eaa4ebac68dcac9ca627f5cf54.tar.gz
rust-43bf52989a86b7eaa4ebac68dcac9ca627f5cf54.zip
Move extracted doctest code and types into its own file
-rw-r--r--src/librustdoc/doctest.rs50
-rw-r--r--src/librustdoc/doctest/extracted.rs132
-rw-r--r--src/librustdoc/html/markdown.rs16
-rw-r--r--tests/rustdoc-ui/extract-doctests.stdout2
4 files changed, 139 insertions, 61 deletions
diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs
index 48fe41c8b46..46d0776699a 100644
--- a/src/librustdoc/doctest.rs
+++ b/src/librustdoc/doctest.rs
@@ -1,3 +1,4 @@
+mod extracted;
 mod make;
 mod markdown;
 mod runner;
@@ -26,7 +27,6 @@ use rustc_span::FileName;
 use rustc_span::edition::Edition;
 use rustc_span::symbol::sym;
 use rustc_target::spec::{Target, TargetTuple};
-use serde::{Serialize, Serializer};
 use tempfile::{Builder as TempFileBuilder, TempDir};
 use tracing::debug;
 
@@ -134,14 +134,6 @@ fn get_doctest_dir() -> io::Result<TempDir> {
     TempFileBuilder::new().prefix("rustdoctest").tempdir()
 }
 
-#[derive(Serialize)]
-struct ExtractedDoctest {
-    /// `None` if the code syntax is invalid.
-    doctest_code: Option<String>,
-    #[serde(flatten)] // We make all `ScrapedDocTest` fields at the same level as `doctest_code`.
-    scraped_test: ScrapedDocTest,
-}
-
 pub(crate) fn run(dcx: DiagCtxtHandle<'_>, input: Input, options: RustdocOptions) {
     let invalid_codeblock_attributes_name = crate::lint::INVALID_CODEBLOCK_ATTRIBUTES.name;
 
@@ -243,34 +235,12 @@ pub(crate) fn run(dcx: DiagCtxtHandle<'_>, input: Input, options: RustdocOptions
             );
             let tests = hir_collector.collect_crate();
             if extract_doctests {
-                let extracted = tests
-                    .into_iter()
-                    .map(|scraped_test| {
-                        let edition = scraped_test.edition(&options);
-                        let doctest = DocTestBuilder::new(
-                            &scraped_test.text,
-                            Some(&opts.crate_name),
-                            edition,
-                            false,
-                            None,
-                            Some(&scraped_test.langstr),
-                        );
-                        let (full_test_code, size) = doctest.generate_unique_doctest(
-                            &scraped_test.text,
-                            scraped_test.langstr.test_harness,
-                            &opts,
-                            Some(&opts.crate_name),
-                        );
-                        ExtractedDoctest {
-                            doctest_code: if size != 0 { Some(full_test_code) } else { None },
-                            scraped_test,
-                        }
-                    })
-                    .collect::<Vec<_>>();
+                let mut collector = extracted::ExtractedDocTests::new();
+                tests.into_iter().for_each(|t| collector.add_test(t, &opts, &options));
 
                 let stdout = std::io::stdout();
                 let mut stdout = stdout.lock();
-                if let Err(error) = serde_json::ser::to_writer(&mut stdout, &extracted) {
+                if let Err(error) = serde_json::ser::to_writer(&mut stdout, &collector) {
                     eprintln!();
                     Err(format!("Failed to generate JSON output for doctests: {error:?}"))
                 } else {
@@ -805,14 +775,6 @@ impl IndividualTestOptions {
     }
 }
 
-fn filename_to_string<S: Serializer>(
-    filename: &FileName,
-    serializer: S,
-) -> Result<S::Ok, S::Error> {
-    let filename = filename.prefer_remapped_unconditionaly().to_string();
-    serializer.serialize_str(&filename)
-}
-
 /// A doctest scraped from the code, ready to be turned into a runnable test.
 ///
 /// The pipeline goes: [`clean`] AST -> `ScrapedDoctest` -> `RunnableDoctest`.
@@ -822,14 +784,10 @@ fn filename_to_string<S: Serializer>(
 /// [`clean`]: crate::clean
 /// [`run_merged_tests`]: crate::doctest::runner::DocTestRunner::run_merged_tests
 /// [`generate_unique_doctest`]: crate::doctest::make::DocTestBuilder::generate_unique_doctest
-#[derive(Serialize)]
 pub(crate) struct ScrapedDocTest {
-    #[serde(serialize_with = "filename_to_string")]
     filename: FileName,
     line: usize,
-    #[serde(rename = "doctest_attributes")]
     langstr: LangString,
-    #[serde(rename = "original_code")]
     text: String,
     name: String,
 }
diff --git a/src/librustdoc/doctest/extracted.rs b/src/librustdoc/doctest/extracted.rs
new file mode 100644
index 00000000000..b45cc907635
--- /dev/null
+++ b/src/librustdoc/doctest/extracted.rs
@@ -0,0 +1,132 @@
+use serde::Serialize;
+
+use super::{DocTestBuilder, ScrapedDocTest};
+use crate::config::Options as RustdocOptions;
+use crate::html::markdown;
+
+const FORMAT_VERSION: u32 = 1;
+
+#[derive(Serialize)]
+pub(crate) struct ExtractedDocTests {
+    #[allow(non_snake_case)]
+    format_version: u32,
+    doctests: Vec<ExtractedDocTest>,
+}
+
+impl ExtractedDocTests {
+    pub(crate) fn new() -> Self {
+        Self { format_version: FORMAT_VERSION, doctests: Vec::new() }
+    }
+
+    pub(crate) fn add_test(
+        &mut self,
+        scraped_test: ScrapedDocTest,
+        opts: &super::GlobalTestOptions,
+        options: &RustdocOptions,
+    ) {
+        let edition = scraped_test.edition(&options);
+
+        let ScrapedDocTest { filename, line, langstr, text, name } = scraped_test;
+
+        let doctest = DocTestBuilder::new(
+            &text,
+            Some(&opts.crate_name),
+            edition,
+            false,
+            None,
+            Some(&langstr),
+        );
+        let (full_test_code, size) = doctest.generate_unique_doctest(
+            &text,
+            langstr.test_harness,
+            &opts,
+            Some(&opts.crate_name),
+        );
+        self.doctests.push(ExtractedDocTest {
+            file: filename.prefer_remapped_unconditionaly().to_string(),
+            line,
+            doctest_attributes: langstr.into(),
+            doctest_code: if size != 0 { Some(full_test_code) } else { None },
+            original_code: text,
+            name,
+        });
+    }
+}
+
+#[derive(Serialize)]
+pub(crate) struct ExtractedDocTest {
+    file: String,
+    line: usize,
+    doctest_attributes: LangString,
+    original_code: String,
+    /// `None` if the code syntax is invalid.
+    doctest_code: Option<String>,
+    name: String,
+}
+
+#[derive(Serialize)]
+pub(crate) enum Ignore {
+    All,
+    None,
+    Some(Vec<String>),
+}
+
+impl From<markdown::Ignore> for Ignore {
+    fn from(original: markdown::Ignore) -> Self {
+        match original {
+            markdown::Ignore::All => Self::All,
+            markdown::Ignore::None => Self::None,
+            markdown::Ignore::Some(values) => Self::Some(values),
+        }
+    }
+}
+
+#[derive(Serialize)]
+struct LangString {
+    pub(crate) original: String,
+    pub(crate) should_panic: bool,
+    pub(crate) no_run: bool,
+    pub(crate) ignore: Ignore,
+    pub(crate) rust: bool,
+    pub(crate) test_harness: bool,
+    pub(crate) compile_fail: bool,
+    pub(crate) standalone_crate: bool,
+    pub(crate) error_codes: Vec<String>,
+    pub(crate) edition: Option<String>,
+    pub(crate) added_css_classes: Vec<String>,
+    pub(crate) unknown: Vec<String>,
+}
+
+impl From<markdown::LangString> for LangString {
+    fn from(original: markdown::LangString) -> Self {
+        let markdown::LangString {
+            original,
+            should_panic,
+            no_run,
+            ignore,
+            rust,
+            test_harness,
+            compile_fail,
+            standalone_crate,
+            error_codes,
+            edition,
+            added_classes,
+            unknown,
+        } = original;
+
+        Self {
+            original,
+            should_panic,
+            no_run,
+            ignore: ignore.into(),
+            rust,
+            test_harness,
+            compile_fail,
+            standalone_crate,
+            error_codes,
+            edition: edition.map(|edition| edition.to_string()),
+            added_css_classes: added_classes,
+            unknown,
+        }
+    }
+}
diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index 7b4ed7a4d47..7e835585b73 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -46,7 +46,6 @@ pub(crate) use rustc_resolve::rustdoc::main_body_opts;
 use rustc_resolve::rustdoc::may_be_doc_link;
 use rustc_span::edition::Edition;
 use rustc_span::{Span, Symbol};
-use serde::{Serialize, Serializer};
 use tracing::{debug, trace};
 
 use crate::clean::RenderedLink;
@@ -821,17 +820,7 @@ impl<'tcx> ExtraInfo<'tcx> {
     }
 }
 
-fn edition_to_string<S: Serializer>(
-    edition: &Option<Edition>,
-    serializer: S,
-) -> Result<S::Ok, S::Error> {
-    match edition {
-        Some(edition) => serializer.serialize_some(&edition.to_string()),
-        None => serializer.serialize_none(),
-    }
-}
-
-#[derive(Eq, PartialEq, Clone, Debug, Serialize)]
+#[derive(Eq, PartialEq, Clone, Debug)]
 pub(crate) struct LangString {
     pub(crate) original: String,
     pub(crate) should_panic: bool,
@@ -842,13 +831,12 @@ pub(crate) struct LangString {
     pub(crate) compile_fail: bool,
     pub(crate) standalone_crate: bool,
     pub(crate) error_codes: Vec<String>,
-    #[serde(serialize_with = "edition_to_string")]
     pub(crate) edition: Option<Edition>,
     pub(crate) added_classes: Vec<String>,
     pub(crate) unknown: Vec<String>,
 }
 
-#[derive(Eq, PartialEq, Clone, Debug, Serialize)]
+#[derive(Eq, PartialEq, Clone, Debug)]
 pub(crate) enum Ignore {
     All,
     None,
diff --git a/tests/rustdoc-ui/extract-doctests.stdout b/tests/rustdoc-ui/extract-doctests.stdout
index 9d42af30449..fa8604cae94 100644
--- a/tests/rustdoc-ui/extract-doctests.stdout
+++ b/tests/rustdoc-ui/extract-doctests.stdout
@@ -1 +1 @@
-[{"doctest_code":"#![allow(unused)]\nfn main() {\nlet x = 12;\nlet y = 14;\n}","filename":"$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_classes":[],"unknown":[]},"original_code":"let x = 12;\nlet y = 14;","name":"$DIR/extract-doctests.rs - (line 8)"},{"doctest_code":"#![allow(unused)]\nfn main() {\nlet\n}","filename":"$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_classes":[],"unknown":[]},"original_code":"let","name":"$DIR/extract-doctests.rs - (line 13)"}]
\ No newline at end of file
+{"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)"}]}
\ No newline at end of file