mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH v2] rust: doctest: add source map script
@ 2026-09-03 19:21 Gary Guo
  0 siblings, 0 replies; only message in thread
From: Gary Guo @ 2026-09-03 19:21 UTC (permalink / raw)
  To: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
	Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
	Danilo Krummrich, Daniel Almeida, Tamir Duberstein,
	Alexandre Courbot, Onur Özkan, Brendan Higgins, David Gow,
	Rae Moar
  Cc: linux-kernel, rust-for-linux, linux-kselftest, kunit-dev

Quite often when updating abstractions there will be some documentation
that needs updating, but the build process is not very developer friendly
as it just gives out something like
"rust/doctests_kernel_generated.rs:12345:42" and it is a hassle to find
where the documentation actually is.

Add a script as rustc wrapper, which translates the error message by
appending a "(generated from original_file:original_line:col)" message to
the original source info emitted by rustc.

This is the result of an example diagnostics:

    error: test
        --> rust/doctests_kernel_generated.rs:4490:1 (generated from rust/kernel/build_assert.rs:96:1)
         |
    4490 | compile_error!("test");
         | ^^^^^^^^^^^^^^^^^^^^^^

Signed-off-by: Gary Guo <gary@garyguo.net>
---
Changes in v2:
- Fixed SPDX header.
- Detect tty with stderr instead of stdout.
- Match doctest anchors more loosely without hardcoding i32.
- Link to v1: https://patch.msgid.link/20260612160523.3083792-1-gary@kernel.org
---
 rust/Makefile                      |  6 ++++
 scripts/rustdoc_test_map_source.py | 73 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 79 insertions(+)

diff --git a/rust/Makefile b/rust/Makefile
index da1a7409d984..23f603d1356e 100644
--- a/rust/Makefile
+++ b/rust/Makefile
@@ -406,6 +406,12 @@ quiet_cmd_rustdoc_test_kernel = RUSTDOC TK $<
     $(objtree)/scripts/rustdoc_test_gen FORCE
 	+$(call if_changed,rustdoc_test_kernel)
 
+# When building rustdoc tests, instead of using the actual RUSTC_OR_CLIPPY, use a wrapper to build
+# so we can convert line number in diagnostics.
+ACTUAL_RUSTC := $(RUSTC_OR_CLIPPY)
+%/doctests_kernel_generated.o: private RUSTC_OR_CLIPPY = \
+	PYTHONDONTWRITEBYTECODE=1 ACTUAL_RUSTC=$(ACTUAL_RUSTC) $(PYTHON3) $(srctree)/scripts/rustdoc_test_map_source.py
+
 # We cannot use `-Zpanic-abort-tests` because some tests are dynamic,
 # so for the moment we skip `-Cpanic=abort`.
 quiet_cmd_rustc_test = $(RUSTC_OR_CLIPPY_QUIET) T  $<
diff --git a/scripts/rustdoc_test_map_source.py b/scripts/rustdoc_test_map_source.py
new file mode 100644
index 000000000000..673021bedf4c
--- /dev/null
+++ b/scripts/rustdoc_test_map_source.py
@@ -0,0 +1,73 @@
+# SPDX-License-Identifier: GPL-2.0
+
+import sys
+import re
+import os
+import subprocess
+
+LOCATION_REGEX = re.compile(r"\.location: (.*):(\d+)")
+ANCHOR_REGEX = re.compile(r"static __DOCTEST_ANCHOR: .+ = .* \+ (\d+) \+ (\d+);")
+SOURCE_INFO_REGEX = re.compile(r"(rust/[\w/.-]+\.rs):(\d+):(\d+)")
+
+
+def transform(file, line):
+    with open(file, "r") as f:
+        lines = f.readlines()
+
+    line_idx = line - 1
+
+    # Find the last location and anchor before the erroring line
+    real_path = None
+    orig_line = None
+    anchor_line = None
+
+    for i in range(line_idx, -1, -1):
+        if real_path is None:
+            match = LOCATION_REGEX.search(lines[i])
+            if match:
+                real_path = match.group(1)
+                orig_line = int(match.group(2))
+
+        if anchor_line is None:
+            match = ANCHOR_REGEX.search(lines[i])
+            if match:
+                anchor_line = i + int(match.group(1)) + int(match.group(2))
+
+        if real_path is not None and anchor_line is not None:
+            break
+
+    new_line = orig_line + (line_idx - anchor_line)
+    return real_path, new_line
+
+
+def main():
+    actual_rustc = os.environ.get("ACTUAL_RUSTC")
+    args = sys.argv[1:]
+
+    # We redirected Rust output so it is not TTY anymore.
+    # Add `--color=always` back to preserve the color behaviour.
+    if sys.stderr.isatty() and not any(arg.startswith("--color") for arg in args):
+        args.append("--color=always")
+
+    result = subprocess.run([actual_rustc] + args, stderr=subprocess.PIPE, text=True)
+
+    def replacer(match):
+        orig = match.group(0)
+        file = match.group(1)
+        line = int(match.group(2))
+        col = int(match.group(3))
+
+        if file != "rust/doctests_kernel_generated.rs":
+            return orig
+
+        new_file, new_line = transform(file, line)
+        return f"{orig} (generated from {new_file}:{new_line}:{col})"
+
+    if result.stderr:
+        sys.stderr.write(SOURCE_INFO_REGEX.sub(replacer, result.stderr))
+
+    sys.exit(result.returncode)
+
+
+if __name__ == "__main__":
+    main()

---
base-commit: cee9395acd8043be0644b25c34bfa86623f2b935
change-id: 20260903-rustdoc-sourcemap-160f904fe78f

Best regards,
--  
Gary Guo <gary@garyguo.net>


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2026-09-03 19:22 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-03 19:21 [PATCH v2] rust: doctest: add source map script Gary Guo

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®