about summary refs log tree commit diff
diff options
context:
space:
mode:
authorGuillaume Gomez <guillaume1.gomez@gmail.com>2025-08-23 01:38:57 +0200
committerGuillaume Gomez <guillaume1.gomez@gmail.com>2025-08-23 10:57:14 +0200
commitf5fddc776ca450c08fe8fc3ecbe5e2c969055d01 (patch)
tree7b214b983f660f37b740a3c8941dce395816eddd
parent0e9b126695847418a681b96b87b5976fb069394a (diff)
downloadrust-f5fddc776ca450c08fe8fc3ecbe5e2c969055d01.tar.gz
rust-f5fddc776ca450c08fe8fc3ecbe5e2c969055d01.zip
Improve code and add test with macro coming from another file from the same crate
-rw-r--r--src/librustdoc/html/highlight.rs22
-rw-r--r--src/librustdoc/html/macro_expansion.rs8
-rw-r--r--src/librustdoc/html/mod.rs2
-rw-r--r--src/librustdoc/lib.rs26
-rw-r--r--tests/rustdoc-gui/macro-expansion.goml103
-rw-r--r--tests/rustdoc-gui/src/macro_expansion/lib.rs5
-rw-r--r--tests/rustdoc-gui/src/macro_expansion/other.rs6
7 files changed, 92 insertions, 80 deletions
diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs
index 583c178fa11..feafb41dc99 100644
--- a/src/librustdoc/html/highlight.rs
+++ b/src/librustdoc/html/highlight.rs
@@ -298,21 +298,17 @@ fn empty_line_number(out: &mut impl Write, _: u32, extra: &'static str) {
     out.write_str(extra).unwrap();
 }
 
-fn get_next_expansion<'a>(
-    expanded_codes: Option<&'a Vec<ExpandedCode>>,
+fn get_next_expansion(
+    expanded_codes: &[ExpandedCode],
     line: u32,
     span: Span,
-) -> Option<&'a ExpandedCode> {
-    if let Some(expanded_codes) = expanded_codes {
-        expanded_codes.iter().find(|code| code.start_line == line && code.span.lo() > span.lo())
-    } else {
-        None
-    }
+) -> Option<&ExpandedCode> {
+    expanded_codes.iter().find(|code| code.start_line == line && code.span.lo() > span.lo())
 }
 
 fn get_expansion<'a, W: Write>(
     token_handler: &mut TokenHandler<'_, '_, W>,
-    expanded_codes: Option<&'a Vec<ExpandedCode>>,
+    expanded_codes: &'a [ExpandedCode],
     line: u32,
     span: Span,
 ) -> Option<&'a ExpandedCode> {
@@ -356,7 +352,7 @@ fn start_expansion(out: &mut Vec<(Cow<'_, str>, Option<Class>)>, expanded_code:
 
 fn end_expansion<'a, W: Write>(
     token_handler: &mut TokenHandler<'_, '_, W>,
-    expanded_codes: Option<&'a Vec<ExpandedCode>>,
+    expanded_codes: &'a [ExpandedCode],
     expansion_start_tags: &[(&'static str, Class)],
     line: u32,
     span: Span,
@@ -467,8 +463,8 @@ pub(super) fn write_code(
         let expanded_codes = c.context.shared.expanded_codes.get(&c.file_span.lo())?;
         Some((expanded_codes, c.file_span))
     }) {
-        Some((expanded_codes, file_span)) => (Some(expanded_codes), file_span),
-        None => (None, DUMMY_SP),
+        Some((expanded_codes, file_span)) => (expanded_codes.as_slice(), file_span),
+        None => (&[] as &[ExpandedCode], DUMMY_SP),
     };
     let mut current_expansion = get_expansion(&mut token_handler, expanded_codes, line, file_span);
     token_handler.write_pending_elems(None);
@@ -1257,7 +1253,7 @@ fn string<W: Write>(
     if let Some(Class::Backline(line)) = klass {
         write_line_number_callback(out, line, "\n");
     } else if let Some(Class::Expansion) = klass {
-        // Nothing to escape here so we get the text to write it directly.
+        // This has already been escaped so we get the text to write it directly.
         out.write_str(text.0).unwrap();
     } else if let Some(closing_tag) =
         string_without_closing_tag(out, text, klass, href_context, open_tag)
diff --git a/src/librustdoc/html/macro_expansion.rs b/src/librustdoc/html/macro_expansion.rs
index d76663a3d1a..9098e92a5cd 100644
--- a/src/librustdoc/html/macro_expansion.rs
+++ b/src/librustdoc/html/macro_expansion.rs
@@ -45,16 +45,16 @@ pub(crate) struct ExpandedCode {
 struct ExpandedCodeInfo {
     /// Callsite of the macro.
     span: Span,
-    /// Expanded macro source code.
+    /// Expanded macro source code (HTML escaped).
     code: String,
-    /// Expanded span
+    /// Span of macro-generated code.
     expanded_span: Span,
 }
 
 /// HIR visitor which retrieves expanded macro.
 ///
 /// Once done, the `expanded_codes` will be transformed into a vec of [`ExpandedCode`]
-/// which contains more information needed when running the source code highlighter.
+/// which contains the information needed when running the source code highlighter.
 pub(crate) struct ExpandedCodeVisitor<'ast> {
     expanded_codes: Vec<ExpandedCodeInfo>,
     source_map: &'ast SourceMap,
@@ -71,7 +71,7 @@ impl<'ast> ExpandedCodeVisitor<'ast> {
         {
             let info = &mut self.expanded_codes[index];
             if new_span.contains(info.expanded_span) {
-                // We replace the item.
+                // New macro expansion recursively contains the old one, so replace it.
                 info.span = callsite_span;
                 info.expanded_span = new_span;
                 info.code = f();
diff --git a/src/librustdoc/html/mod.rs b/src/librustdoc/html/mod.rs
index 170449fc033..d42f4782845 100644
--- a/src/librustdoc/html/mod.rs
+++ b/src/librustdoc/html/mod.rs
@@ -3,8 +3,8 @@ pub(crate) mod format;
 pub(crate) mod highlight;
 pub(crate) mod layout;
 mod length_limit;
-// used by the error-index generator, so it needs to be public
 pub(crate) mod macro_expansion;
+// used by the error-index generator, so it needs to be public
 pub mod markdown;
 pub(crate) mod render;
 pub(crate) mod sources;
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index fe56fdb2271..d891d1fba25 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -665,6 +665,14 @@ fn opts() -> Vec<RustcOptGroup> {
             "disable the minification of CSS/JS files (perma-unstable, do not use with cached files)",
             "",
         ),
+        opt(
+            Unstable,
+            Flag,
+            "",
+            "generate-macro-expansion",
+            "Add possibility to expand macros in the HTML source code pages",
+            "",
+        ),
         // deprecated / removed options
         opt(
             Stable,
@@ -706,14 +714,6 @@ fn opts() -> Vec<RustcOptGroup> {
             "removed, see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information",
             "[rust]",
         ),
-        opt(
-            Unstable,
-            Flag,
-            "",
-            "generate-macro-expansion",
-            "Add possibility to expand macros in the HTML source code pages",
-            "",
-        ),
     ]
 }
 
@@ -958,15 +958,7 @@ fn main_args(early_dcx: &mut EarlyDiagCtxt, at_args: &[String]) {
                     )
                 }),
                 config::OutputFormat::Json => sess.time("render_json", || {
-                    run_renderer(
-                        krate,
-                        render_opts,
-                        cache,
-                        tcx,
-                        |krate, render_opts, cache, tcx| {
-                            json::JsonRenderer::init(krate, render_opts, cache, tcx)
-                        },
-                    )
+                    run_renderer(krate, render_opts, cache, tcx, json::JsonRenderer::init)
                 }),
                 // Already handled above with doctest runners.
                 config::OutputFormat::Doctest => unreachable!(),
diff --git a/tests/rustdoc-gui/macro-expansion.goml b/tests/rustdoc-gui/macro-expansion.goml
index 5e9a3049405..b87d0e4870a 100644
--- a/tests/rustdoc-gui/macro-expansion.goml
+++ b/tests/rustdoc-gui/macro-expansion.goml
@@ -28,86 +28,99 @@ define-function: (
 )
 
 // First we check the derive macro expansion at line 33.
-call-function: ("check-expansion", {"line": 33, "original_content": "Debug"})
+call-function: ("check-expansion", {"line": 35, "original_content": "Debug"})
 // Then we check the `bar` macro expansion at line 41.
-call-function: ("check-expansion", {"line": 41, "original_content": "bar!(y)"})
+call-function: ("check-expansion", {"line": 43, "original_content": "bar!(y)"})
 // Then we check the `println` macro expansion at line 42-44.
-call-function: ("check-expansion", {"line": 42, "original_content": 'println!("
-43    {y}
-44    ")'})
+call-function: ("check-expansion", {"line": 44, "original_content": 'println!("
+45    {y}
+46    ")'})
 
 // Then finally we check when there are two macro calls on a same line.
-assert-count: ("#expand-50 ~ .original", 2)
-assert-count: ("#expand-50 ~ .expanded", 2)
+assert-count: ("#expand-52 ~ .original", 2)
+assert-count: ("#expand-52 ~ .expanded", 2)
 
 store-value: (repeat_o, '/following-sibling::*[@class="original"]')
 store-value: (repeat_e, '/following-sibling::*[@class="expanded"]')
-assert-text: ('//*[@id="expand-50"]' + |repeat_o|, "stringify!(foo)")
-assert-text: ('//*[@id="expand-50"]' + |repeat_o| + |repeat_o|, "stringify!(bar)")
-assert-text: ('//*[@id="expand-50"]' + |repeat_e|, '"foo"')
-assert-text: ('//*[@id="expand-50"]' + |repeat_e| + |repeat_e|, '"bar"')
+store-value: (expand_id, "expand-52")
+assert-text: ('//*[@id="' + |expand_id| + '"]' + |repeat_o|, "stringify!(foo)")
+assert-text: ('//*[@id="' + |expand_id| + '"]' + |repeat_o| + |repeat_o|, "stringify!(bar)")
+assert-text: ('//*[@id="' + |expand_id| + '"]' + |repeat_e|, '"foo"')
+assert-text: ('//*[@id="' + |expand_id| + '"]' + |repeat_e| + |repeat_e|, '"bar"')
 
 // The "original" content should be expanded.
-assert-css: ('//*[@id="expand-50"]' + |repeat_o|, {"display": "inline"})
-assert-css: ('//*[@id="expand-50"]' + |repeat_o| + |repeat_o|, {"display": "inline"})
+assert-css: ('//*[@id="' + |expand_id| + '"]' + |repeat_o|, {"display": "inline"})
+assert-css: ('//*[@id="' + |expand_id| + '"]' + |repeat_o| + |repeat_o|, {"display": "inline"})
 // The expanded macro should be hidden.
-assert-css: ('//*[@id="expand-50"]' + |repeat_e|, {"display": "none"})
-assert-css: ('//*[@id="expand-50"]' + |repeat_e| + |repeat_e|, {"display": "none"})
+assert-css: ('//*[@id="' + |expand_id| + '"]' + |repeat_e|, {"display": "none"})
+assert-css: ('//*[@id="' + |expand_id| + '"]' + |repeat_e| + |repeat_e|, {"display": "none"})
 
 // We "expand" the macro (because the line starts with a string, the label is not at the "top
 // level" of the `<code>`, so we need to use a different selector).
-click: "#expand-50"
+click: "#" + |expand_id|
 // The "original" content is hidden.
-assert-css: ('//*[@id="expand-50"]' + |repeat_o|, {"display": "none"})
-assert-css: ('//*[@id="expand-50"]' + |repeat_o| + |repeat_o|, {"display": "none"})
+assert-css: ('//*[@id="' + |expand_id| + '"]' + |repeat_o|, {"display": "none"})
+assert-css: ('//*[@id="' + |expand_id| + '"]' + |repeat_o| + |repeat_o|, {"display": "none"})
 // The expanded macro is visible.
-assert-css: ('//*[@id="expand-50"]' + |repeat_e|, {"display": "inline"})
-assert-css: ('//*[@id="expand-50"]' + |repeat_e| + |repeat_e|, {"display": "inline"})
+assert-css: ('//*[@id="' + |expand_id| + '"]' + |repeat_e|, {"display": "inline"})
+assert-css: ('//*[@id="' + |expand_id| + '"]' + |repeat_e| + |repeat_e|, {"display": "inline"})
 
 // We collapse the macro.
-click: "#expand-50"
+click: "#" + |expand_id|
 // The "original" content is expanded.
-assert-css: ('//*[@id="expand-50"]' + |repeat_o|, {"display": "inline"})
-assert-css: ('//*[@id="expand-50"]' + |repeat_o| + |repeat_o|, {"display": "inline"})
+assert-css: ('//*[@id="' + |expand_id| + '"]' + |repeat_o|, {"display": "inline"})
+assert-css: ('//*[@id="' + |expand_id| + '"]' + |repeat_o| + |repeat_o|, {"display": "inline"})
 // The expanded macro is hidden.
-assert-css: ('//*[@id="expand-50"]' + |repeat_e|, {"display": "none"})
-assert-css: ('//*[@id="expand-50"]' + |repeat_e| + |repeat_e|, {"display": "none"})
+assert-css: ('//*[@id="' + |expand_id| + '"]' + |repeat_e|, {"display": "none"})
+assert-css: ('//*[@id="' + |expand_id| + '"]' + |repeat_e| + |repeat_e|, {"display": "none"})
 
-// Checking the line 46 `println` which needs to be handled differently because the line number is
+// Checking the line 48 `println` which needs to be handled differently because the line number is
 // inside a "comment" span.
-assert-text: ("#expand-46 ~ .original", 'println!("
-47    {y}
-48    ")')
+store-value: (expand_id, "expand-48")
+assert-text: ("#" + |expand_id| + " ~ .original", 'println!("
+49    {y}
+50    ")')
 // The "original" content should be expanded.
-assert-css: ("#expand-46 ~ .original", {"display": "inline"})
+assert-css: ("#" + |expand_id| + " ~ .original", {"display": "inline"})
 // The expanded macro should be hidden.
-assert-css: ("#expand-46 ~ .expanded", {"display": "none"})
+assert-css: ("#" + |expand_id| + " ~ .expanded", {"display": "none"})
 
 // We "expand" the macro.
-click: "#expand-46"
+click: "#" + |expand_id|
 // The "original" content is hidden.
-assert-css: ("#expand-46 ~ .original", {"display": "none"})
+assert-css: ("#" + |expand_id| + " ~ .original", {"display": "none"})
 // The expanded macro is visible.
-assert-css: ("#expand-46 ~ .expanded", {"display": "inline"})
+assert-css: ("#" + |expand_id| + " ~ .expanded", {"display": "inline"})
 
 // We collapse the macro.
-click: "#expand-46"
+click: "#" + |expand_id|
 // The "original" content is expanded.
-assert-css: ("#expand-46 ~ .original", {"display": "inline"})
+assert-css: ("#" + |expand_id| + " ~ .original", {"display": "inline"})
 // The expanded macro is hidden.
-assert-css: ("#expand-46 ~ .expanded", {"display": "none"})
+assert-css: ("#" + |expand_id| + " ~ .expanded", {"display": "none"})
 
 // Ensure that the toggles are focusable and can be interacted with keyboard.
-focus: "//a[@id='27']"
+focus: "//a[@id='29']"
 press-key: "Tab"
-assert: "#expand-27:focus"
-assert-css: ("#expand-27 ~ .expanded", {"display": "none"})
-assert-css: ("#expand-27 ~ .original", {"display": "inline"})
+store-value: (expand_id, "expand-29")
+assert: "#" + |expand_id| + ":focus"
+assert-css: ("#" + |expand_id| +" ~ .expanded", {"display": "none"})
+assert-css: ("#" + |expand_id| +" ~ .original", {"display": "inline"})
 // We now expand the macro.
 press-key: "Space"
-assert-css: ("#expand-27 ~ .expanded", {"display": "inline"})
-assert-css: ("#expand-27 ~ .original", {"display": "none"})
+assert-css: ("#" + |expand_id| + " ~ .expanded", {"display": "inline"})
+assert-css: ("#" + |expand_id| + " ~ .original", {"display": "none"})
 // We collapse the macro.
 press-key: "Space"
-assert-css: ("#expand-27 ~ .expanded", {"display": "none"})
-assert-css: ("#expand-27 ~ .original", {"display": "inline"})
+assert-css: ("#" + |expand_id| + " ~ .expanded", {"display": "none"})
+assert-css: ("#" + |expand_id| + " ~ .original", {"display": "inline"})
+
+// Now we check a macro coming from another file.
+store-value: (expand_id, "expand-55")
+// We "expand" the macro.
+click: "#" + |expand_id|
+// The "original" content is hidden.
+assert-css: ("#" + |expand_id| + " ~ .original", {"display": "none"})
+// The expanded macro is visible.
+assert-css: ("#" + |expand_id| + " ~ .expanded", {"display": "inline"})
+assert-text: ("#" + |expand_id| + " ~ .expanded", "{ y += 2; };")
diff --git a/tests/rustdoc-gui/src/macro_expansion/lib.rs b/tests/rustdoc-gui/src/macro_expansion/lib.rs
index 7926e0143d8..62a92d5d15e 100644
--- a/tests/rustdoc-gui/src/macro_expansion/lib.rs
+++ b/tests/rustdoc-gui/src/macro_expansion/lib.rs
@@ -1,6 +1,8 @@
 // Test crate used to check the `--generate-macro-expansion` option.
 //@ compile-flags: -Zunstable-options --generate-macro-expansion --generate-link-to-definition
 
+mod other;
+
 #[macro_export]
 macro_rules! bar {
     ($x:ident) => {{
@@ -48,4 +50,7 @@ fn foo() {
     ");
     let s = y_f("\
 bla", stringify!(foo), stringify!(bar));
+
+    // Macro from another file.
+    other_macro!(y);
 }
diff --git a/tests/rustdoc-gui/src/macro_expansion/other.rs b/tests/rustdoc-gui/src/macro_expansion/other.rs
new file mode 100644
index 00000000000..8661b01be38
--- /dev/null
+++ b/tests/rustdoc-gui/src/macro_expansion/other.rs
@@ -0,0 +1,6 @@
+#[macro_export]
+macro_rules! other_macro {
+    ($x:ident) => {{
+        $x += 2;
+    }}
+}