]> git.lizzy.rs Git - rust.git/commitdiff
Remap instrument-coverage line numbers in doctests
authorArpad Borsos <arpad.borsos@googlemail.com>
Sun, 6 Dec 2020 12:57:37 +0000 (13:57 +0100)
committerArpad Borsos <arpad.borsos@googlemail.com>
Sat, 19 Dec 2020 12:22:24 +0000 (13:22 +0100)
This uses the `SourceMap::doctest_offset_line` method to re-map line
numbers from doctests. Remapping columns is not yet done.

Part of issue #79417.

15 files changed:
compiler/rustc_mir/src/transform/coverage/mod.rs
compiler/rustc_span/src/lib.rs
src/librustdoc/doctest.rs
src/librustdoc/doctest/tests.rs
src/librustdoc/html/markdown.rs
src/test/run-make-fulldeps/coverage-reports/Makefile
src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.doctest.txt [new file with mode: 0644]
src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt
src/test/run-make-fulldeps/coverage-reports/normalize_paths.py [new file with mode: 0644]
src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.doctest/doctest.main.-------.InstrumentCoverage.0.html [new file with mode: 0644]
src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.doctest_crate/doctest_crate.fn_run_in_doctests.-------.InstrumentCoverage.0.html [new file with mode: 0644]
src/test/run-make-fulldeps/coverage/compiletest-ignore-dir
src/test/run-make-fulldeps/coverage/coverage_tools.mk
src/test/run-make-fulldeps/coverage/doctest.rs [new file with mode: 0644]
src/test/run-make-fulldeps/coverage/lib/doctest_crate.rs [new file with mode: 0644]

index 4590d37c182e405d292f3d8fa545b827846b0322..93133e9b7f06364b52f3b549b7714fae78d858ea 100644 (file)
@@ -30,6 +30,7 @@
 };
 use rustc_middle::ty::TyCtxt;
 use rustc_span::def_id::DefId;
+use rustc_span::source_map::SourceMap;
 use rustc_span::{CharPos, Pos, SourceFile, Span, Symbol};
 
 /// A simple error message wrapper for `coverage::Error`s.
@@ -311,7 +312,7 @@ fn inject_coverage_span_counters(
                 self.mir_body,
                 counter_kind,
                 self.bcb_leader_bb(bcb),
-                Some(make_code_region(file_name, &self.source_file, span, body_span)),
+                Some(make_code_region(source_map, file_name, &self.source_file, span, body_span)),
             );
         }
     }
@@ -489,6 +490,7 @@ fn inject_intermediate_expression(mir_body: &mut mir::Body<'tcx>, expression: Co
 
 /// Convert the Span into its file name, start line and column, and end line and column
 fn make_code_region(
+    source_map: &SourceMap,
     file_name: Symbol,
     source_file: &Lrc<SourceFile>,
     span: Span,
@@ -508,6 +510,8 @@ fn make_code_region(
     } else {
         source_file.lookup_file_pos(span.hi())
     };
+    let start_line = source_map.doctest_offset_line(&source_file.name, start_line);
+    let end_line = source_map.doctest_offset_line(&source_file.name, end_line);
     CodeRegion {
         file_name,
         start_line: start_line as u32,
index f63a73acbf4ba164c5130eaaa41e9e015f3be718..fbef4d06709ec39bf88c79a408d4ace139b41c01 100644 (file)
@@ -182,7 +182,7 @@ fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         use FileName::*;
         match *self {
             Real(RealFileName::Named(ref path)) => write!(fmt, "{}", path.display()),
-            // FIXME: might be nice to display both compoments of Devirtualized.
+            // FIXME: might be nice to display both components of Devirtualized.
             // But for now (to backport fix for issue #70924), best to not
             // perturb diagnostics so its obvious test suite still works.
             Real(RealFileName::Devirtualized { ref local_path, virtual_name: _ }) => {
index 37fe13c32ce745dfee79c88fb44610377b5bb538..a08ded926402f0627029640e59f4bf6bb2456913 100644 (file)
@@ -247,9 +247,10 @@ fn run_test(
     edition: Edition,
     outdir: DirState,
     path: PathBuf,
+    test_id: &str,
 ) -> Result<(), TestFailure> {
     let (test, line_offset, supports_color) =
-        make_test(test, Some(cratename), as_test_harness, opts, edition);
+        make_test(test, Some(cratename), as_test_harness, opts, edition, Some(test_id));
 
     let output_file = outdir.path().join("rust_out");
 
@@ -387,6 +388,7 @@ fn drop(&mut self) {
     dont_insert_main: bool,
     opts: &TestOptions,
     edition: Edition,
+    test_id: Option<&str>,
 ) -> (String, usize, bool) {
     let (crate_attrs, everything_else, crates) = partition_source(s);
     let everything_else = everything_else.trim();
@@ -542,16 +544,40 @@ fn drop(&mut self) {
         prog.push_str(everything_else);
     } else {
         let returns_result = everything_else.trim_end().ends_with("(())");
+        // Give each doctest main function a unique name.
+        // This is for example needed for the tooling around `-Z instrument-coverage`.
+        let inner_fn_name = if let Some(test_id) = test_id {
+            format!("_doctest_main_{}", test_id)
+        } else {
+            "_inner".into()
+        };
         let (main_pre, main_post) = if returns_result {
             (
-                "fn main() { fn _inner() -> Result<(), impl core::fmt::Debug> {",
-                "}\n_inner().unwrap() }",
+                format!(
+                    "fn main() {{ fn {}() -> Result<(), impl core::fmt::Debug> {{\n",
+                    inner_fn_name
+                ),
+                format!("\n}}; {}().unwrap() }}", inner_fn_name),
+            )
+        } else if test_id.is_some() {
+            (
+                format!("fn main() {{ fn {}() {{\n", inner_fn_name),
+                format!("\n}}; {}() }}", inner_fn_name),
             )
         } else {
-            ("fn main() {\n", "\n}")
+            ("fn main() {\n".into(), "\n}".into())
         };
-        prog.extend([main_pre, everything_else, main_post].iter().cloned());
+        // Note on newlines: We insert a line/newline *before*, and *after*
+        // the doctest and adjust the `line_offset` accordingly.
+        // In the case of `-Z instrument-coverage`, this means that the generated
+        // inner `main` function spans from the doctest opening codeblock to the
+        // closing one. For example
+        // /// ``` <- start of the inner main
+        // /// <- code under doctest
+        // /// ``` <- end of the inner main
         line_offset += 1;
+
+        prog.extend([&main_pre, everything_else, &main_post].iter().cloned());
     }
 
     debug!("final doctest:\n{}", prog);
@@ -749,28 +775,24 @@ fn add_test(&mut self, test: String, config: LangString, line: usize) {
             _ => PathBuf::from(r"doctest.rs"),
         };
 
+        // For example `module/file.rs` would become `module_file_rs`
+        let file = filename
+            .to_string()
+            .chars()
+            .map(|c| if c.is_ascii_alphanumeric() { c } else { '_' })
+            .collect::<String>();
+        let test_id = format!(
+            "{file}_{line}_{number}",
+            file = file,
+            line = line,
+            number = {
+                // Increases the current test number, if this file already
+                // exists or it creates a new entry with a test number of 0.
+                self.visited_tests.entry((file.clone(), line)).and_modify(|v| *v += 1).or_insert(0)
+            },
+        );
         let outdir = if let Some(mut path) = options.persist_doctests.clone() {
-            // For example `module/file.rs` would become `module_file_rs`
-            let folder_name = filename
-                .to_string()
-                .chars()
-                .map(|c| if c == '\\' || c == '/' || c == '.' { '_' } else { c })
-                .collect::<String>();
-
-            path.push(format!(
-                "{krate}_{file}_{line}_{number}",
-                krate = cratename,
-                file = folder_name,
-                line = line,
-                number = {
-                    // Increases the current test number, if this file already
-                    // exists or it creates a new entry with a test number of 0.
-                    self.visited_tests
-                        .entry((folder_name.clone(), line))
-                        .and_modify(|v| *v += 1)
-                        .or_insert(0)
-                },
-            ));
+            path.push(&test_id);
 
             std::fs::create_dir_all(&path)
                 .expect("Couldn't create directory for doctest executables");
@@ -817,6 +839,7 @@ fn add_test(&mut self, test: String, config: LangString, line: usize) {
                     edition,
                     outdir,
                     path,
+                    &test_id,
                 );
 
                 if let Err(err) = res {
index a024e9c72a43e01969a2523dfca486cc115a7b67..7c0df673c1b9eb5ff472557921353ebdafa7e1a6 100644 (file)
@@ -11,7 +11,7 @@ fn main() {
 assert_eq!(2+2, 4);
 }"
     .to_string();
-    let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION);
+    let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION, None);
     assert_eq!((output, len), (expected, 2));
 }
 
@@ -26,7 +26,7 @@ fn main() {
 assert_eq!(2+2, 4);
 }"
     .to_string();
-    let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION);
+    let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION, None);
     assert_eq!((output, len), (expected, 2));
 }
 
@@ -44,7 +44,7 @@ fn main() {
 assert_eq!(2+2, 4);
 }"
     .to_string();
-    let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION);
+    let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION, None);
     assert_eq!((output, len), (expected, 3));
 }
 
@@ -61,7 +61,7 @@ fn main() {
 assert_eq!(2+2, 4);
 }"
     .to_string();
-    let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION);
+    let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION, None);
     assert_eq!((output, len), (expected, 2));
 }
 
@@ -79,7 +79,7 @@ fn main() {
 assert_eq!(2+2, 4);
 }"
     .to_string();
-    let (output, len, _) = make_test(input, Some("std"), false, &opts, DEFAULT_EDITION);
+    let (output, len, _) = make_test(input, Some("std"), false, &opts, DEFAULT_EDITION, None);
     assert_eq!((output, len), (expected, 2));
 }
 
@@ -98,7 +98,7 @@ fn main() {
 assert_eq!(2+2, 4);
 }"
     .to_string();
-    let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION);
+    let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION, None);
     assert_eq!((output, len), (expected, 2));
 }
 
@@ -115,7 +115,7 @@ fn main() {
 assert_eq!(2+2, 4);
 }"
     .to_string();
-    let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION);
+    let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION, None);
     assert_eq!((output, len), (expected, 2));
 }
 
@@ -134,7 +134,7 @@ fn main() {
 assert_eq!(2+2, 4);
 }"
     .to_string();
-    let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION);
+    let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION, None);
     assert_eq!((output, len), (expected, 3));
 
     // Adding more will also bump the returned line offset.
@@ -147,7 +147,7 @@ fn main() {
 assert_eq!(2+2, 4);
 }"
     .to_string();
-    let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION);
+    let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION, None);
     assert_eq!((output, len), (expected, 4));
 }
 
@@ -164,7 +164,7 @@ fn main() {
 assert_eq!(2+2, 4);
 }"
     .to_string();
-    let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION);
+    let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION, None);
     assert_eq!((output, len), (expected, 2));
 }
 
@@ -180,7 +180,7 @@ fn main() {
     assert_eq!(2+2, 4);
 }"
     .to_string();
-    let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION);
+    let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION, None);
     assert_eq!((output, len), (expected, 1));
 }
 
@@ -196,7 +196,7 @@ fn main() {
 assert_eq!(2+2, 4);
 }"
     .to_string();
-    let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION);
+    let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION, None);
     assert_eq!((output, len), (expected, 2));
 }
 
@@ -210,7 +210,7 @@ fn make_test_dont_insert_main() {
 //Ceci n'est pas une `fn main`
 assert_eq!(2+2, 4);"
         .to_string();
-    let (output, len, _) = make_test(input, None, true, &opts, DEFAULT_EDITION);
+    let (output, len, _) = make_test(input, None, true, &opts, DEFAULT_EDITION, None);
     assert_eq!((output, len), (expected, 1));
 }
 
@@ -224,7 +224,7 @@ fn make_test_display_warnings() {
 assert_eq!(2+2, 4);
 }"
     .to_string();
-    let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION);
+    let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION, None);
     assert_eq!((output, len), (expected, 1));
 }
 
@@ -242,7 +242,7 @@ fn main() {
 }"
     .to_string();
 
-    let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION);
+    let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION, None);
     assert_eq!((output, len), (expected, 2));
 
     let input = "extern crate hella_qwop;
@@ -256,7 +256,7 @@ fn main() {
 }"
     .to_string();
 
-    let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION);
+    let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION, None);
     assert_eq!((output, len), (expected, 3));
 }
 
@@ -274,6 +274,41 @@ fn main() {}
 }"
     .to_string();
 
-    let (output, len, _) = make_test(input, Some("my_crate"), false, &opts, DEFAULT_EDITION);
+    let (output, len, _) = make_test(input, Some("my_crate"), false, &opts, DEFAULT_EDITION, None);
     assert_eq!((output, len), (expected, 1));
 }
+
+#[test]
+fn make_test_returns_result() {
+    // creates an inner function and unwraps it
+    let opts = TestOptions::default();
+    let input = "use std::io;
+let mut input = String::new();
+io::stdin().read_line(&mut input)?;
+Ok::<(), io:Error>(())";
+    let expected = "#![allow(unused)]
+fn main() { fn _inner() -> Result<(), impl core::fmt::Debug> {
+use std::io;
+let mut input = String::new();
+io::stdin().read_line(&mut input)?;
+Ok::<(), io:Error>(())
+}; _inner().unwrap() }"
+        .to_string();
+    let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION, None);
+    assert_eq!((output, len), (expected, 2));
+}
+
+#[test]
+fn make_test_named_wrapper() {
+    // creates an inner function with a specific name
+    let opts = TestOptions::default();
+    let input = "assert_eq!(2+2, 4);";
+    let expected = "#![allow(unused)]
+fn main() { fn _doctest_main_some_unique_name() {
+assert_eq!(2+2, 4);
+}; _doctest_main_some_unique_name() }"
+        .to_string();
+    let (output, len, _) =
+        make_test(input, None, false, &opts, DEFAULT_EDITION, Some("some_unique_name"));
+    assert_eq!((output, len), (expected, 2));
+}
index 22096203d4ce63855857d297bf173bb4299c6daa..f911a2ce3fc7888bb63e1cdcd1cec27b6a757cf5 100644 (file)
@@ -248,7 +248,7 @@ fn next(&mut self) -> Option<Self::Item> {
                 .join("\n");
             let krate = krate.as_ref().map(|s| &**s);
             let (test, _, _) =
-                doctest::make_test(&test, krate, false, &Default::default(), edition);
+                doctest::make_test(&test, krate, false, &Default::default(), edition, None);
             let channel = if test.contains("#![feature(") { "&amp;version=nightly" } else { "" };
 
             let edition_string = format!("&amp;edition={}", edition);
index 5c24f909130c0745645bd6c1df2ec8f292cb07eb..c4700b317efa03b7286bf2ecf4a78e2838228f2f 100644 (file)
@@ -98,7 +98,7 @@ endif
        # Run it in order to generate some profiling data,
        # with `LLVM_PROFILE_FILE=<profdata_file>` environment variable set to
        # output the coverage stats for this run.
-       LLVM_PROFILE_FILE="$(TMPDIR)"/$@.profraw \
+       LLVM_PROFILE_FILE="$(TMPDIR)"/$@-%p.profraw \
                        $(call RUN,$@) || \
                        ( \
                                status=$$?; \
@@ -108,9 +108,16 @@ endif
                                ) \
                        )
 
+       # Run it through rustdoc as well to cover doctests
+       LLVM_PROFILE_FILE="$(TMPDIR)"/$@-%p.profraw \
+                       $(RUSTDOC) --crate-name workaround_for_79771 --test $(SOURCEDIR)/$@.rs \
+                       $$( grep -q '^\/\/ require-rust-edition-2018' $(SOURCEDIR)/$@.rs && echo "--edition=2018" ) \
+                       -L "$(TMPDIR)" -Zinstrument-coverage \
+                       -Z unstable-options --persist-doctests=$(TMPDIR)/rustdoc-$@
+
        # Postprocess the profiling data so it can be used by the llvm-cov tool
        "$(LLVM_BIN_DIR)"/llvm-profdata merge --sparse \
-                       "$(TMPDIR)"/$@.profraw \
+                       "$(TMPDIR)"/$@-*.profraw \
                        -o "$(TMPDIR)"/$@.profdata
 
        # Generate a coverage report using `llvm-cov show`.
@@ -121,8 +128,15 @@ endif
                        --show-line-counts-or-regions \
                        --instr-profile="$(TMPDIR)"/$@.profdata \
                        $(call BIN,"$(TMPDIR)"/$@) \
-               > "$(TMPDIR)"/actual_show_coverage.$@.txt \
-               2> "$(TMPDIR)"/show_coverage_stderr.$@.txt || \
+                       $$( \
+                               for file in $(TMPDIR)/rustdoc-$@/*/rust_out; \
+                               do \
+                               [[ -x $$file ]] && printf "%s %s " -object $$file; \
+                               done \
+                       ) \
+               2> "$(TMPDIR)"/show_coverage_stderr.$@.txt \
+               | "$(PYTHON)" $(BASEDIR)/normalize_paths.py \
+               > "$(TMPDIR)"/actual_show_coverage.$@.txt || \
        ( status=$$? ; \
                >&2 cat "$(TMPDIR)"/show_coverage_stderr.$@.txt ; \
                exit $$status \
diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.doctest.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.doctest.txt
new file mode 100644 (file)
index 0000000..e1731c7
--- /dev/null
@@ -0,0 +1,79 @@
+../coverage/doctest.rs:
+    1|       |//! This test ensures that code from doctests is properly re-mapped.
+    2|       |//! See <https://github.com/rust-lang/rust/issues/79417> for more info.
+    3|       |//!
+    4|       |//! Just some random code:
+    5|      1|//! ```
+    6|      1|//! if true {
+    7|       |//!     // this is executed!
+    8|      1|//!     assert_eq!(1, 1);
+    9|       |//! } else {
+   10|       |//!     // this is not!
+   11|       |//!     assert_eq!(1, 2);
+   12|       |//! }
+   13|      1|//! ```
+   14|       |//!
+   15|       |//! doctest testing external code:
+   16|       |//! ```
+   17|      1|//! extern crate doctest_crate;
+   18|      1|//! doctest_crate::fn_run_in_doctests(1);
+   19|      1|//! ```
+   20|       |//!
+   21|       |//! doctest returning a result:
+   22|      1|//! ```
+   23|      1|//! #[derive(Debug)]
+   24|      1|//! struct SomeError;
+   25|      1|//! let mut res = Err(SomeError);
+   26|      1|//! if res.is_ok() {
+   27|      0|//!   res?;
+   28|      1|//! } else {
+   29|      1|//!   res = Ok(0);
+   30|      1|//! }
+   31|       |//! // need to be explicit because rustdoc cant infer the return type
+   32|      1|//! Ok::<(), SomeError>(())
+   33|      1|//! ```
+   34|       |//!
+   35|       |//! doctest with custom main:
+   36|       |//! ```
+   37|       |//! #[derive(Debug)]
+   38|       |//! struct SomeError;
+   39|       |//!
+   40|       |//! extern crate doctest_crate;
+   41|       |//!
+   42|      1|//! fn doctest_main() -> Result<(), SomeError> {
+   43|      1|//!     doctest_crate::fn_run_in_doctests(2);
+   44|      1|//!     Ok(())
+   45|      1|//! }
+   46|       |//!
+   47|       |//! // this `main` is not shown as covered, as it clashes with all the other
+   48|       |//! // `main` functions that were automatically generated for doctests
+   49|       |//! fn main() -> Result<(), SomeError> {
+   50|       |//!     doctest_main()
+   51|       |//! }
+   52|       |//! ```
+   53|       |
+   54|       |/// doctest attached to fn testing external code:
+   55|       |/// ```
+   56|      1|/// extern crate doctest_crate;
+   57|      1|/// doctest_crate::fn_run_in_doctests(3);
+   58|      1|/// ```
+   59|       |///
+   60|      1|fn main() {
+   61|      1|    if true {
+   62|      1|        assert_eq!(1, 1);
+   63|       |    } else {
+   64|       |        assert_eq!(1, 2);
+   65|       |    }
+   66|      1|}
+
+../coverage/lib/doctest_crate.rs:
+    1|       |/// A function run only from within doctests
+    2|      3|pub fn fn_run_in_doctests(conditional: usize) {
+    3|      3|    match conditional {
+    4|      1|        1 => assert_eq!(1, 1), // this is run,
+    5|      1|        2 => assert_eq!(1, 1), // this,
+    6|      1|        3 => assert_eq!(1, 1), // and this too
+    7|      0|        _ => assert_eq!(1, 2), // however this is not
+    8|       |    }
+    9|      3|}
+
index e14e733fff6d4cbe55f76924985cb802434c4a49..4c03e950af029de06d229074b246fca1d69326f6 100644 (file)
    18|      2|    println!("used_only_from_bin_crate_generic_function with {:?}", arg);
    19|      2|}
   ------------------
-  | used_crate::used_only_from_bin_crate_generic_function::<&str>:
+  | used_crate::used_only_from_bin_crate_generic_function::<&alloc::vec::Vec<i32>>:
   |   17|      1|pub fn used_only_from_bin_crate_generic_function<T: Debug>(arg: T) {
   |   18|      1|    println!("used_only_from_bin_crate_generic_function with {:?}", arg);
   |   19|      1|}
   ------------------
-  | used_crate::used_only_from_bin_crate_generic_function::<&alloc::vec::Vec<i32>>:
+  | used_crate::used_only_from_bin_crate_generic_function::<&str>:
   |   17|      1|pub fn used_only_from_bin_crate_generic_function<T: Debug>(arg: T) {
   |   18|      1|    println!("used_only_from_bin_crate_generic_function with {:?}", arg);
   |   19|      1|}
diff --git a/src/test/run-make-fulldeps/coverage-reports/normalize_paths.py b/src/test/run-make-fulldeps/coverage-reports/normalize_paths.py
new file mode 100644 (file)
index 0000000..05fb412
--- /dev/null
@@ -0,0 +1,10 @@
+#!/usr/bin/env python
+
+import sys
+
+# Normalize file paths in output
+for line in sys.stdin:
+    if line.startswith("..") and line.rstrip().endswith(".rs:"):
+        print(line.replace("\\", "/"), end='')
+    else:
+        print(line, end='')
diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.doctest/doctest.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.doctest/doctest.main.-------.InstrumentCoverage.0.html
new file mode 100644 (file)
index 0000000..8d07455
--- /dev/null
@@ -0,0 +1,127 @@
+<!DOCTYPE html>
+<!--
+
+Preview this file as rendered HTML from the github source at:
+https://htmlpreview.github.io/?https://github.com/rust-lang/rust/blob/master/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.doctest/doctest.main.-------.InstrumentCoverage.0.html
+
+For revisions in Pull Requests (PR):
+  * Replace "rust-lang" with the github PR author
+  * Replace "master" with the PR branch name
+
+-->
+<html>
+<head>
+<title>doctest.main - Coverage Spans</title>
+<style>
+    .line {
+        counter-increment: line;
+    }
+    .line:before {
+        content: counter(line) ": ";
+        font-family: Menlo, Monaco, monospace;
+        font-style: italic;
+        width: 3.8em;
+        display: inline-block;
+        text-align: right;
+        filter: opacity(50%);
+        -webkit-user-select: none;
+    }
+    .code {
+        color: #dddddd;
+        background-color: #222222;
+        font-family: Menlo, Monaco, monospace;
+        line-height: 1.4em;
+        border-bottom: 2px solid #222222;
+        white-space: pre;
+        display: inline-block;
+    }
+    .odd {
+        background-color: #55bbff;
+        color: #223311;
+    }
+    .even {
+        background-color: #ee7756;
+        color: #551133;
+    }
+    .code {
+        --index: calc(var(--layer) - 1);
+        padding-top: calc(var(--index) * 0.15em);
+        filter:
+            hue-rotate(calc(var(--index) * 25deg))
+            saturate(calc(100% - (var(--index) * 2%)))
+            brightness(calc(100% - (var(--index) * 1.5%)));
+    }
+    .annotation {
+        color: #4444ff;
+        font-family: monospace;
+        font-style: italic;
+        display: none;
+        -webkit-user-select: none;
+    }
+    body:active .annotation {
+        /* requires holding mouse down anywhere on the page */
+        display: inline-block;
+    }
+    span:hover .annotation {
+        /* requires hover over a span ONLY on its first line */
+        display: inline-block;
+    }
+</style>
+</head>
+<body>
+<div class="code" style="counter-reset: line 59"><span class="line"><span><span class="code even" style="--layer: 1"><span class="annotation">@0⦊</span>fn main() <span class="annotation">⦉@0</span></span></span><span class="code" style="--layer: 0">{</span></span>
+<span class="line"><span class="code" style="--layer: 0">    if </span><span><span class="code even" style="--layer: 1" title="61:8-61:12: @0[1]: _1 = const true
+61:8-61:12: @0[2]: FakeRead(ForMatchedPlace, _1)"><span class="annotation">@0⦊</span>true<span class="annotation">⦉@0</span></span></span><span class="code" style="--layer: 0"> {</span></span>
+<span class="line"><span class="code" style="--layer: 0">        </span><span><span class="code odd" style="--layer: 1" title="62:9-62:26: @5[0]: _2 = const ()"><span class="annotation">@5⦊</span></span></span><span class="code even" style="--layer: 2" title="62:9-62:26: @6[5]: _75 = const main::promoted[3]
+62:9-62:26: @6[6]: _18 = &amp;(*_75)
+62:9-62:26: @6[7]: _17 = &amp;(*_18)
+62:9-62:26: @6[8]: _16 = move _17 as &amp;[&amp;str] (Pointer(Unsize))
+62:9-62:26: @6[17]: _26 = &amp;(*_8)
+62:9-62:26: @6[18]: _25 = &amp;_26
+62:9-62:26: @6[21]: _28 = &amp;(*_9)
+62:9-62:26: @6[22]: _27 = &amp;_28
+62:9-62:26: @6[23]: _24 = (move _25, move _27)
+62:9-62:26: @6[26]: FakeRead(ForMatchedPlace, _24)
+62:9-62:26: @6[28]: _29 = (_24.0: &amp;&amp;i32)
+62:9-62:26: @6[30]: _30 = (_24.1: &amp;&amp;i32)
+62:9-62:26: @6[33]: _32 = &amp;(*_29)
+62:9-62:26: @6[35]: _33 = &lt;&amp;i32 as Debug&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r &amp;i32, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+62:9-62:26: @6.Call: _31 = ArgumentV1::new::&lt;&amp;i32&gt;(move _32, move _33) -&gt; [return: bb7, unwind: bb17]
+62:9-62:26: @7[4]: _35 = &amp;(*_30)
+62:9-62:26: @7[6]: _36 = &lt;&amp;i32 as Debug&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r &amp;i32, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+62:9-62:26: @7.Call: _34 = ArgumentV1::new::&lt;&amp;i32&gt;(move _35, move _36) -&gt; [return: bb8, unwind: bb17]
+62:9-62:26: @8[2]: _23 = [move _31, move _34]
+62:9-62:26: @8[7]: _22 = &amp;_23
+62:9-62:26: @8[8]: _21 = &amp;(*_22)
+62:9-62:26: @8[9]: _20 = move _21 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+62:9-62:26: @8.Call: _15 = Arguments::new_v1(move _16, move _20) -&gt; [return: bb9, unwind: bb17]
+62:9-62:26: @9.Call: core::panicking::panic_fmt(move _15) -&gt; bb17"><span class="annotation">@4,6,7,8,9⦊</span>assert_eq!(1, 1);<span class="annotation">⦉@4,6,7,8,9</span></span><span><span class="code odd" style="--layer: 1" title="62:9-62:26: @5[0]: _2 = const ()"><span class="annotation">⦉@5</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    } else {</span></span>
+<span class="line"><span class="code" style="--layer: 0">        </span><span><span class="code even" style="--layer: 1" title="64:9-64:26: @11[0]: _37 = const ()"><span class="annotation">@11⦊</span></span></span><span class="code even" style="--layer: 2" title="64:9-64:26: @12[5]: _72 = const main::promoted[0]
+64:9-64:26: @12[6]: _53 = &amp;(*_72)
+64:9-64:26: @12[7]: _52 = &amp;(*_53)
+64:9-64:26: @12[8]: _51 = move _52 as &amp;[&amp;str] (Pointer(Unsize))
+64:9-64:26: @12[17]: _61 = &amp;(*_43)
+64:9-64:26: @12[18]: _60 = &amp;_61
+64:9-64:26: @12[21]: _63 = &amp;(*_44)
+64:9-64:26: @12[22]: _62 = &amp;_63
+64:9-64:26: @12[23]: _59 = (move _60, move _62)
+64:9-64:26: @12[26]: FakeRead(ForMatchedPlace, _59)
+64:9-64:26: @12[28]: _64 = (_59.0: &amp;&amp;i32)
+64:9-64:26: @12[30]: _65 = (_59.1: &amp;&amp;i32)
+64:9-64:26: @12[33]: _67 = &amp;(*_64)
+64:9-64:26: @12[35]: _68 = &lt;&amp;i32 as Debug&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r &amp;i32, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+64:9-64:26: @12.Call: _66 = ArgumentV1::new::&lt;&amp;i32&gt;(move _67, move _68) -&gt; [return: bb13, unwind: bb17]
+64:9-64:26: @13[4]: _70 = &amp;(*_65)
+64:9-64:26: @13[6]: _71 = &lt;&amp;i32 as Debug&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r &amp;i32, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+64:9-64:26: @13.Call: _69 = ArgumentV1::new::&lt;&amp;i32&gt;(move _70, move _71) -&gt; [return: bb14, unwind: bb17]
+64:9-64:26: @14[2]: _58 = [move _66, move _69]
+64:9-64:26: @14[7]: _57 = &amp;_58
+64:9-64:26: @14[8]: _56 = &amp;(*_57)
+64:9-64:26: @14[9]: _55 = move _56 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+64:9-64:26: @14.Call: _50 = Arguments::new_v1(move _51, move _55) -&gt; [return: bb15, unwind: bb17]
+64:9-64:26: @15.Call: core::panicking::panic_fmt(move _50) -&gt; bb17"><span class="annotation">@10,12,13,14,15⦊</span>assert_eq!(1, 2);<span class="annotation">⦉@10,12,13,14,15</span></span><span><span class="code even" style="--layer: 1" title="64:9-64:26: @11[0]: _37 = const ()"><span class="annotation">⦉@11</span></span></span><span class="code" style="--layer: 0"></span></span>
+<span class="line"><span class="code" style="--layer: 0">    }</span></span>
+<span class="line"><span class="code" style="--layer: 0">}</span><span><span class="code odd" style="--layer: 1" title="66:2-66:2: @16.Return: return"><span class="annotation">@16⦊</span>‸<span class="annotation">⦉@16</span></span></span></span></div>
+</body>
+</html>
diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.doctest_crate/doctest_crate.fn_run_in_doctests.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.doctest_crate/doctest_crate.fn_run_in_doctests.-------.InstrumentCoverage.0.html
new file mode 100644 (file)
index 0000000..ae119d9
--- /dev/null
@@ -0,0 +1,173 @@
+<!DOCTYPE html>
+<!--
+
+Preview this file as rendered HTML from the github source at:
+https://htmlpreview.github.io/?https://github.com/rust-lang/rust/blob/master/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.doctest_crate/doctest_crate.fn_run_in_doctests.-------.InstrumentCoverage.0.html
+
+For revisions in Pull Requests (PR):
+  * Replace "rust-lang" with the github PR author
+  * Replace "master" with the PR branch name
+
+-->
+<html>
+<head>
+<title>doctest_crate.fn_run_in_doctests - Coverage Spans</title>
+<style>
+    .line {
+        counter-increment: line;
+    }
+    .line:before {
+        content: counter(line) ": ";
+        font-family: Menlo, Monaco, monospace;
+        font-style: italic;
+        width: 3.8em;
+        display: inline-block;
+        text-align: right;
+        filter: opacity(50%);
+        -webkit-user-select: none;
+    }
+    .code {
+        color: #dddddd;
+        background-color: #222222;
+        font-family: Menlo, Monaco, monospace;
+        line-height: 1.4em;
+        border-bottom: 2px solid #222222;
+        white-space: pre;
+        display: inline-block;
+    }
+    .odd {
+        background-color: #55bbff;
+        color: #223311;
+    }
+    .even {
+        background-color: #ee7756;
+        color: #551133;
+    }
+    .code {
+        --index: calc(var(--layer) - 1);
+        padding-top: calc(var(--index) * 0.15em);
+        filter:
+            hue-rotate(calc(var(--index) * 25deg))
+            saturate(calc(100% - (var(--index) * 2%)))
+            brightness(calc(100% - (var(--index) * 1.5%)));
+    }
+    .annotation {
+        color: #4444ff;
+        font-family: monospace;
+        font-style: italic;
+        display: none;
+        -webkit-user-select: none;
+    }
+    body:active .annotation {
+        /* requires holding mouse down anywhere on the page */
+        display: inline-block;
+    }
+    span:hover .annotation {
+        /* requires hover over a span ONLY on its first line */
+        display: inline-block;
+    }
+</style>
+</head>
+<body>
+<div class="code" style="counter-reset: line 1"><span class="line"><span><span class="code even" style="--layer: 1"><span class="annotation">@0⦊</span>pub fn fn_run_in_doctests(conditional: usize) <span class="annotation">⦉@0</span></span></span><span class="code" style="--layer: 0">{</span></span>
+<span class="line"><span class="code" style="--layer: 0">    match </span><span><span class="code even" style="--layer: 1" title="3:11-3:22: @0[0]: FakeRead(ForMatchedPlace, _1)"><span class="annotation">@0⦊</span>conditional<span class="annotation">⦉@0</span></span></span><span class="code" style="--layer: 0"> {</span></span>
+<span class="line"><span class="code" style="--layer: 0">        1 =&gt; </span><span><span class="code odd" style="--layer: 1" title="4:14-4:30: @7[0]: _0 = const ()"><span class="annotation">@7⦊</span></span></span><span class="code even" style="--layer: 2" title="4:14-4:30: @8[5]: _138 = const fn_run_in_doctests::promoted[0]
+4:14-4:30: @8[6]: _17 = &amp;(*_138)
+4:14-4:30: @8[7]: _16 = &amp;(*_17)
+4:14-4:30: @8[8]: _15 = move _16 as &amp;[&amp;str] (Pointer(Unsize))
+4:14-4:30: @8[17]: _25 = &amp;(*_7)
+4:14-4:30: @8[18]: _24 = &amp;_25
+4:14-4:30: @8[21]: _27 = &amp;(*_8)
+4:14-4:30: @8[22]: _26 = &amp;_27
+4:14-4:30: @8[23]: _23 = (move _24, move _26)
+4:14-4:30: @8[26]: FakeRead(ForMatchedPlace, _23)
+4:14-4:30: @8[28]: _28 = (_23.0: &amp;&amp;i32)
+4:14-4:30: @8[30]: _29 = (_23.1: &amp;&amp;i32)
+4:14-4:30: @8[33]: _31 = &amp;(*_28)
+4:14-4:30: @8[35]: _32 = &lt;&amp;i32 as Debug&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r &amp;i32, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+4:14-4:30: @8.Call: _30 = ArgumentV1::new::&lt;&amp;i32&gt;(move _31, move _32) -&gt; [return: bb9, unwind: bb33]
+4:14-4:30: @9[4]: _34 = &amp;(*_29)
+4:14-4:30: @9[6]: _35 = &lt;&amp;i32 as Debug&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r &amp;i32, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+4:14-4:30: @9.Call: _33 = ArgumentV1::new::&lt;&amp;i32&gt;(move _34, move _35) -&gt; [return: bb10, unwind: bb33]
+4:14-4:30: @10[2]: _22 = [move _30, move _33]
+4:14-4:30: @10[7]: _21 = &amp;_22
+4:14-4:30: @10[8]: _20 = &amp;(*_21)
+4:14-4:30: @10[9]: _19 = move _20 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+4:14-4:30: @10.Call: _14 = Arguments::new_v1(move _15, move _19) -&gt; [return: bb11, unwind: bb33]
+4:14-4:30: @11.Call: core::panicking::panic_fmt(move _14) -&gt; bb33"><span class="annotation">@6,8,9,10,11⦊</span>assert_eq!(1, 1)<span class="annotation">⦉@6,8,9,10,11</span></span><span><span class="code odd" style="--layer: 1" title="4:14-4:30: @7[0]: _0 = const ()"><span class="annotation">⦉@7</span></span></span><span class="code" style="--layer: 0">, // this is run,</span></span>
+<span class="line"><span class="code" style="--layer: 0">        2 =&gt; </span><span><span class="code even" style="--layer: 1" title="5:14-5:30: @14[0]: _0 = const ()"><span class="annotation">@14⦊</span></span></span><span class="code even" style="--layer: 2" title="5:14-5:30: @15[5]: _141 = const fn_run_in_doctests::promoted[3]
+5:14-5:30: @15[6]: _51 = &amp;(*_141)
+5:14-5:30: @15[7]: _50 = &amp;(*_51)
+5:14-5:30: @15[8]: _49 = move _50 as &amp;[&amp;str] (Pointer(Unsize))
+5:14-5:30: @15[17]: _59 = &amp;(*_41)
+5:14-5:30: @15[18]: _58 = &amp;_59
+5:14-5:30: @15[21]: _61 = &amp;(*_42)
+5:14-5:30: @15[22]: _60 = &amp;_61
+5:14-5:30: @15[23]: _57 = (move _58, move _60)
+5:14-5:30: @15[26]: FakeRead(ForMatchedPlace, _57)
+5:14-5:30: @15[28]: _62 = (_57.0: &amp;&amp;i32)
+5:14-5:30: @15[30]: _63 = (_57.1: &amp;&amp;i32)
+5:14-5:30: @15[33]: _65 = &amp;(*_62)
+5:14-5:30: @15[35]: _66 = &lt;&amp;i32 as Debug&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r &amp;i32, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+5:14-5:30: @15.Call: _64 = ArgumentV1::new::&lt;&amp;i32&gt;(move _65, move _66) -&gt; [return: bb16, unwind: bb33]
+5:14-5:30: @16[4]: _68 = &amp;(*_63)
+5:14-5:30: @16[6]: _69 = &lt;&amp;i32 as Debug&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r &amp;i32, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+5:14-5:30: @16.Call: _67 = ArgumentV1::new::&lt;&amp;i32&gt;(move _68, move _69) -&gt; [return: bb17, unwind: bb33]
+5:14-5:30: @17[2]: _56 = [move _64, move _67]
+5:14-5:30: @17[7]: _55 = &amp;_56
+5:14-5:30: @17[8]: _54 = &amp;(*_55)
+5:14-5:30: @17[9]: _53 = move _54 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+5:14-5:30: @17.Call: _48 = Arguments::new_v1(move _49, move _53) -&gt; [return: bb18, unwind: bb33]
+5:14-5:30: @18.Call: core::panicking::panic_fmt(move _48) -&gt; bb33"><span class="annotation">@13,15,16,17,18⦊</span>assert_eq!(1, 1)<span class="annotation">⦉@13,15,16,17,18</span></span><span><span class="code even" style="--layer: 1" title="5:14-5:30: @14[0]: _0 = const ()"><span class="annotation">⦉@14</span></span></span><span class="code" style="--layer: 0">, // this,</span></span>
+<span class="line"><span class="code" style="--layer: 0">        3 =&gt; </span><span><span class="code odd" style="--layer: 1" title="6:14-6:30: @21[0]: _0 = const ()"><span class="annotation">@21⦊</span></span></span><span class="code even" style="--layer: 2" title="6:14-6:30: @22[5]: _144 = const fn_run_in_doctests::promoted[6]
+6:14-6:30: @22[6]: _85 = &amp;(*_144)
+6:14-6:30: @22[7]: _84 = &amp;(*_85)
+6:14-6:30: @22[8]: _83 = move _84 as &amp;[&amp;str] (Pointer(Unsize))
+6:14-6:30: @22[17]: _93 = &amp;(*_75)
+6:14-6:30: @22[18]: _92 = &amp;_93
+6:14-6:30: @22[21]: _95 = &amp;(*_76)
+6:14-6:30: @22[22]: _94 = &amp;_95
+6:14-6:30: @22[23]: _91 = (move _92, move _94)
+6:14-6:30: @22[26]: FakeRead(ForMatchedPlace, _91)
+6:14-6:30: @22[28]: _96 = (_91.0: &amp;&amp;i32)
+6:14-6:30: @22[30]: _97 = (_91.1: &amp;&amp;i32)
+6:14-6:30: @22[33]: _99 = &amp;(*_96)
+6:14-6:30: @22[35]: _100 = &lt;&amp;i32 as Debug&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r &amp;i32, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+6:14-6:30: @22.Call: _98 = ArgumentV1::new::&lt;&amp;i32&gt;(move _99, move _100) -&gt; [return: bb23, unwind: bb33]
+6:14-6:30: @23[4]: _102 = &amp;(*_97)
+6:14-6:30: @23[6]: _103 = &lt;&amp;i32 as Debug&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r &amp;i32, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+6:14-6:30: @23.Call: _101 = ArgumentV1::new::&lt;&amp;i32&gt;(move _102, move _103) -&gt; [return: bb24, unwind: bb33]
+6:14-6:30: @24[2]: _90 = [move _98, move _101]
+6:14-6:30: @24[7]: _89 = &amp;_90
+6:14-6:30: @24[8]: _88 = &amp;(*_89)
+6:14-6:30: @24[9]: _87 = move _88 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+6:14-6:30: @24.Call: _82 = Arguments::new_v1(move _83, move _87) -&gt; [return: bb25, unwind: bb33]
+6:14-6:30: @25.Call: core::panicking::panic_fmt(move _82) -&gt; bb33"><span class="annotation">@20,22,23,24,25⦊</span>assert_eq!(1, 1)<span class="annotation">⦉@20,22,23,24,25</span></span><span><span class="code odd" style="--layer: 1" title="6:14-6:30: @21[0]: _0 = const ()"><span class="annotation">⦉@21</span></span></span><span class="code" style="--layer: 0">, // and this too</span></span>
+<span class="line"><span class="code" style="--layer: 0">        _ =&gt; </span><span><span class="code even" style="--layer: 1" title="7:14-7:30: @27[0]: _0 = const ()"><span class="annotation">@27⦊</span></span></span><span class="code even" style="--layer: 2" title="7:14-7:30: @28[5]: _147 = const fn_run_in_doctests::promoted[9]
+7:14-7:30: @28[6]: _119 = &amp;(*_147)
+7:14-7:30: @28[7]: _118 = &amp;(*_119)
+7:14-7:30: @28[8]: _117 = move _118 as &amp;[&amp;str] (Pointer(Unsize))
+7:14-7:30: @28[17]: _127 = &amp;(*_109)
+7:14-7:30: @28[18]: _126 = &amp;_127
+7:14-7:30: @28[21]: _129 = &amp;(*_110)
+7:14-7:30: @28[22]: _128 = &amp;_129
+7:14-7:30: @28[23]: _125 = (move _126, move _128)
+7:14-7:30: @28[26]: FakeRead(ForMatchedPlace, _125)
+7:14-7:30: @28[28]: _130 = (_125.0: &amp;&amp;i32)
+7:14-7:30: @28[30]: _131 = (_125.1: &amp;&amp;i32)
+7:14-7:30: @28[33]: _133 = &amp;(*_130)
+7:14-7:30: @28[35]: _134 = &lt;&amp;i32 as Debug&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r &amp;i32, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+7:14-7:30: @28.Call: _132 = ArgumentV1::new::&lt;&amp;i32&gt;(move _133, move _134) -&gt; [return: bb29, unwind: bb33]
+7:14-7:30: @29[4]: _136 = &amp;(*_131)
+7:14-7:30: @29[6]: _137 = &lt;&amp;i32 as Debug&gt;::fmt as for&lt;&#39;r, &#39;s, &#39;t0&gt; fn(&amp;&#39;r &amp;i32, &amp;&#39;s mut std::fmt::Formatter&lt;&#39;t0&gt;) -&gt; std::result::Result&lt;(), std::fmt::Error&gt; (Pointer(ReifyFnPointer))
+7:14-7:30: @29.Call: _135 = ArgumentV1::new::&lt;&amp;i32&gt;(move _136, move _137) -&gt; [return: bb30, unwind: bb33]
+7:14-7:30: @30[2]: _124 = [move _132, move _135]
+7:14-7:30: @30[7]: _123 = &amp;_124
+7:14-7:30: @30[8]: _122 = &amp;(*_123)
+7:14-7:30: @30[9]: _121 = move _122 as &amp;[std::fmt::ArgumentV1] (Pointer(Unsize))
+7:14-7:30: @30.Call: _116 = Arguments::new_v1(move _117, move _121) -&gt; [return: bb31, unwind: bb33]
+7:14-7:30: @31.Call: core::panicking::panic_fmt(move _116) -&gt; bb33"><span class="annotation">@26,28,29,30,31⦊</span>assert_eq!(1, 2)<span class="annotation">⦉@26,28,29,30,31</span></span><span><span class="code even" style="--layer: 1" title="7:14-7:30: @27[0]: _0 = const ()"><span class="annotation">⦉@27</span></span></span><span class="code" style="--layer: 0">, // however this is not</span></span>
+<span class="line"><span class="code" style="--layer: 0">    }</span></span>
+<span class="line"><span class="code" style="--layer: 0">}</span><span><span class="code odd" style="--layer: 1" title="9:2-9:2: @32.Return: return"><span class="annotation">@32⦊</span>‸<span class="annotation">⦉@32</span></span></span></span></div>
+</body>
+</html>
index abf8df8fdc9e621132970f7cbde7608ac1d42916..d1824d189e38248b8d51973a80a103bae265bcbc 100644 (file)
@@ -1,3 +1,3 @@
-# Directory "instrument-coverage" supports the tests at prefix ../instrument-coverage-*
+# Directory "coverage" supports the tests at prefix ../coverage-*
 
-# Use ./x.py [options] test src/test/run-make-fulldeps/instrument-coverage to run all related tests.
+# Use ./x.py [options] test src/test/run-make-fulldeps/coverage to run all related tests.
index 7dc485cd94d66dc03f96cb76ce32fb7bbf328c17..4d340d4b1dadddb324f3b349ea0acb37207a68b2 100644 (file)
@@ -1,7 +1,7 @@
-# Common Makefile include for Rust `run-make-fulldeps/instrument-coverage-* tests. Include this
+# Common Makefile include for Rust `run-make-fulldeps/coverage-* tests. Include this
 # file with the line:
 #
-# -include ../instrument-coverage/coverage_tools.mk
+# -include ../coverage/coverage_tools.mk
 
 -include ../tools.mk
 
diff --git a/src/test/run-make-fulldeps/coverage/doctest.rs b/src/test/run-make-fulldeps/coverage/doctest.rs
new file mode 100644 (file)
index 0000000..e41d669
--- /dev/null
@@ -0,0 +1,66 @@
+//! This test ensures that code from doctests is properly re-mapped.
+//! See <https://github.com/rust-lang/rust/issues/79417> for more info.
+//!
+//! Just some random code:
+//! ```
+//! if true {
+//!     // this is executed!
+//!     assert_eq!(1, 1);
+//! } else {
+//!     // this is not!
+//!     assert_eq!(1, 2);
+//! }
+//! ```
+//!
+//! doctest testing external code:
+//! ```
+//! extern crate doctest_crate;
+//! doctest_crate::fn_run_in_doctests(1);
+//! ```
+//!
+//! doctest returning a result:
+//! ```
+//! #[derive(Debug)]
+//! struct SomeError;
+//! let mut res = Err(SomeError);
+//! if res.is_ok() {
+//!   res?;
+//! } else {
+//!   res = Ok(0);
+//! }
+//! // need to be explicit because rustdoc cant infer the return type
+//! Ok::<(), SomeError>(())
+//! ```
+//!
+//! doctest with custom main:
+//! ```
+//! #[derive(Debug)]
+//! struct SomeError;
+//!
+//! extern crate doctest_crate;
+//!
+//! fn doctest_main() -> Result<(), SomeError> {
+//!     doctest_crate::fn_run_in_doctests(2);
+//!     Ok(())
+//! }
+//!
+//! // this `main` is not shown as covered, as it clashes with all the other
+//! // `main` functions that were automatically generated for doctests
+//! fn main() -> Result<(), SomeError> {
+//!     doctest_main()
+//! }
+//! ```
+
+/// doctest attached to fn testing external code:
+/// ```
+/// extern crate doctest_crate;
+/// doctest_crate::fn_run_in_doctests(3);
+/// ```
+///
+fn main() {
+    if true {
+        assert_eq!(1, 1);
+    } else {
+        assert_eq!(1, 2);
+    }
+}
diff --git a/src/test/run-make-fulldeps/coverage/lib/doctest_crate.rs b/src/test/run-make-fulldeps/coverage/lib/doctest_crate.rs
new file mode 100644 (file)
index 0000000..c321014
--- /dev/null
@@ -0,0 +1,9 @@
+/// A function run only from within doctests
+pub fn fn_run_in_doctests(conditional: usize) {
+    match conditional {
+        1 => assert_eq!(1, 1), // this is run,
+        2 => assert_eq!(1, 1), // this,
+        3 => assert_eq!(1, 1), // and this too
+        _ => assert_eq!(1, 2), // however this is not
+    }
+}