about summary refs log tree commit diff
diff options
context:
space:
mode:
authorManish Goregaokar <manishsmail@gmail.com>2018-01-08 20:17:23 +0530
committerManish Goregaokar <manishsmail@gmail.com>2018-01-10 10:10:34 +0530
commit730679685ebad64e94b50961bb6c8c2e385529e4 (patch)
tree8e0f4529205efb84263d8b6fd7f0e1f5ce0ddf02
parent1b193de98af5b8c6e2b50908ea64323b9095a1a4 (diff)
downloadrust-730679685ebad64e94b50961bb6c8c2e385529e4.tar.gz
rust-730679685ebad64e94b50961bb6c8c2e385529e4.zip
Use correct line offsets for doctests (fixes #45868)
-rw-r--r--src/librustc_errors/emitter.rs4
-rw-r--r--src/librustc_errors/lib.rs1
-rw-r--r--src/librustdoc/html/markdown.rs4
-rw-r--r--src/librustdoc/test.rs21
-rw-r--r--src/libsyntax/codemap.rs36
5 files changed, 55 insertions, 11 deletions
diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs
index af556c576c0..1c3d4af9e18 100644
--- a/src/librustc_errors/emitter.rs
+++ b/src/librustc_errors/emitter.rs
@@ -990,7 +990,7 @@ impl EmitterWriter {
                     buffer.append(buffer_msg_line_offset,
                                   &format!("{}:{}:{}",
                                            loc.file.name,
-                                           loc.line,
+                                           cm.doctest_offset_line(loc.line),
                                            loc.col.0 + 1),
                                   Style::LineAndColumn);
                     for _ in 0..max_line_num_len {
@@ -1000,7 +1000,7 @@ impl EmitterWriter {
                     buffer.prepend(0,
                                    &format!("{}:{}:{} - ",
                                             loc.file.name,
-                                            loc.line,
+                                            cm.doctest_offset_line(loc.line),
                                             loc.col.0 + 1),
                                    Style::LineAndColumn);
                 }
diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs
index c4db39fae86..f2f387ee190 100644
--- a/src/librustc_errors/lib.rs
+++ b/src/librustc_errors/lib.rs
@@ -103,6 +103,7 @@ pub trait CodeMapper {
     fn merge_spans(&self, sp_lhs: Span, sp_rhs: Span) -> Option<Span>;
     fn call_span_if_macro(&self, sp: Span) -> Span;
     fn ensure_filemap_source_present(&self, file_map: Rc<FileMap>) -> bool;
+    fn doctest_offset_line(&self, line: usize) -> usize;
 }
 
 impl CodeSuggestion {
diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index f7a67b1b9c7..e66add20376 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -196,7 +196,7 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'a, I> {
                     .map(|l| map_line(l).for_code())
                     .collect::<Vec<&str>>().join("\n");
                 let krate = krate.as_ref().map(|s| &**s);
-                let test = test::make_test(&test, krate, false,
+                let (test, _) = test::make_test(&test, krate, false,
                                            &Default::default());
                 let channel = if test.contains("#![feature(") {
                     "&amp;version=nightly"
@@ -607,7 +607,7 @@ pub fn render(w: &mut fmt::Formatter,
                         .map(|l| map_line(l).for_code())
                         .collect::<Vec<&str>>().join("\n");
                     let krate = krate.as_ref().map(|s| &**s);
-                    let test = test::make_test(&test, krate, false,
+                    let (test, _) = test::make_test(&test, krate, false,
                                                &Default::default());
                     let channel = if test.contains("#![feature(") {
                         "&amp;version=nightly"
diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs
index 8e861f10dd8..5432f5cb6e1 100644
--- a/src/librustdoc/test.rs
+++ b/src/librustdoc/test.rs
@@ -176,7 +176,8 @@ fn scrape_test_config(krate: &::rustc::hir::Crate) -> TestOptions {
     opts
 }
 
-fn run_test(test: &str, cratename: &str, filename: &FileName, cfgs: Vec<String>, libs: SearchPaths,
+fn run_test(test: &str, cratename: &str, filename: &FileName, line: usize,
+            cfgs: Vec<String>, libs: SearchPaths,
             externs: Externs,
             should_panic: bool, no_run: bool, as_test_harness: bool,
             compile_fail: bool, mut error_codes: Vec<String>, opts: &TestOptions,
@@ -184,7 +185,7 @@ fn run_test(test: &str, cratename: &str, filename: &FileName, cfgs: Vec<String>,
             linker: Option<PathBuf>) {
     // the test harness wants its own `main` & top level functions, so
     // never wrap the test in `fn main() { ... }`
-    let test = make_test(test, Some(cratename), as_test_harness, opts);
+    let (test, line_offset) = make_test(test, Some(cratename), as_test_harness, opts);
     // FIXME(#44940): if doctests ever support path remapping, then this filename
     // needs to be the result of CodeMap::span_to_unmapped_path
     let input = config::Input::Str {
@@ -234,7 +235,9 @@ fn run_test(test: &str, cratename: &str, filename: &FileName, cfgs: Vec<String>,
         }
     }
     let data = Arc::new(Mutex::new(Vec::new()));
-    let codemap = Rc::new(CodeMap::new(sessopts.file_path_mapping()));
+    let codemap = Rc::new(CodeMap::new_doctest(
+        sessopts.file_path_mapping(), filename.clone(), line as isize - line_offset as isize
+    ));
     let emitter = errors::emitter::EmitterWriter::new(box Sink(data.clone()),
                                                       Some(codemap.clone()),
                                                       false);
@@ -326,13 +329,14 @@ fn run_test(test: &str, cratename: &str, filename: &FileName, cfgs: Vec<String>,
     }
 }
 
+/// Makes the test file. Also returns the number of lines before the code begins
 pub fn make_test(s: &str,
                  cratename: Option<&str>,
                  dont_insert_main: bool,
                  opts: &TestOptions)
-                 -> String {
+                 -> (String, usize) {
     let (crate_attrs, everything_else) = partition_source(s);
-
+    let mut line_offset = 0;
     let mut prog = String::new();
 
     if opts.attrs.is_empty() {
@@ -341,11 +345,13 @@ pub fn make_test(s: &str,
         // commonly used to make tests fail in case they trigger warnings, so having this there in
         // that case may cause some tests to pass when they shouldn't have.
         prog.push_str("#![allow(unused)]\n");
+        line_offset += 1;
     }
 
     // Next, any attributes that came from the crate root via #![doc(test(attr(...)))].
     for attr in &opts.attrs {
         prog.push_str(&format!("#![{}]\n", attr));
+        line_offset += 1;
     }
 
     // Now push any outer attributes from the example, assuming they
@@ -358,6 +364,7 @@ pub fn make_test(s: &str,
         if let Some(cratename) = cratename {
             if s.contains(cratename) {
                 prog.push_str(&format!("extern crate {};\n", cratename));
+                line_offset += 1;
             }
         }
     }
@@ -379,6 +386,7 @@ pub fn make_test(s: &str,
         prog.push_str(&everything_else);
     } else {
         prog.push_str("fn main() {\n");
+        line_offset += 1;
         prog.push_str(&everything_else);
         prog = prog.trim().into();
         prog.push_str("\n}");
@@ -386,7 +394,7 @@ pub fn make_test(s: &str,
 
     info!("final test program: {}", prog);
 
-    prog
+    (prog, line_offset)
 }
 
 // FIXME(aburka): use a real parser to deal with multiline attributes
@@ -543,6 +551,7 @@ impl Collector {
                         run_test(&test,
                                  &cratename,
                                  &filename,
+                                 line,
                                  cfgs,
                                  libs,
                                  externs,
diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs
index 129defd2093..a58a61c3636 100644
--- a/src/libsyntax/codemap.rs
+++ b/src/libsyntax/codemap.rs
@@ -131,6 +131,9 @@ pub struct CodeMap {
     // -Zremap-path-prefix to all FileMaps allocated within this CodeMap.
     path_mapping: FilePathMapping,
     stable_id_to_filemap: RefCell<FxHashMap<StableFilemapId, Rc<FileMap>>>,
+    /// In case we are in a doctest, replace all file names with the PathBuf,
+    /// and add the given offsets to the line info
+    doctest_offset: Option<(FileName, isize)>,
 }
 
 impl CodeMap {
@@ -140,9 +143,19 @@ impl CodeMap {
             file_loader: Box::new(RealFileLoader),
             path_mapping,
             stable_id_to_filemap: RefCell::new(FxHashMap()),
+            doctest_offset: None,
         }
     }
 
+    pub fn new_doctest(path_mapping: FilePathMapping,
+                       file: FileName, line: isize) -> CodeMap {
+        CodeMap {
+            doctest_offset: Some((file, line)),
+            ..CodeMap::new(path_mapping)
+        }
+
+    }
+
     pub fn with_file_loader(file_loader: Box<FileLoader>,
                             path_mapping: FilePathMapping)
                             -> CodeMap {
@@ -151,6 +164,7 @@ impl CodeMap {
             file_loader,
             path_mapping,
             stable_id_to_filemap: RefCell::new(FxHashMap()),
+            doctest_offset: None,
         }
     }
 
@@ -164,7 +178,12 @@ impl CodeMap {
 
     pub fn load_file(&self, path: &Path) -> io::Result<Rc<FileMap>> {
         let src = self.file_loader.read_file(path)?;
-        Ok(self.new_filemap(path.to_owned().into(), src))
+        let filename = if let Some((ref name, _)) = self.doctest_offset {
+            name.clone()
+        } else {
+            path.to_owned().into()
+        };
+        Ok(self.new_filemap(filename, src))
     }
 
     pub fn files(&self) -> Ref<Vec<Rc<FileMap>>> {
@@ -303,6 +322,18 @@ impl CodeMap {
                  pos.col.to_usize() + 1)).to_string()
     }
 
+    // If there is a doctest_offset, apply it to the line
+    pub fn doctest_offset_line(&self, mut orig: usize) -> usize {
+        if let Some((_, line)) = self.doctest_offset {
+            if line >= 0 {
+                orig = orig + line as usize;
+            } else {
+                orig = orig - (-line) as usize;
+            }
+        }
+        orig
+    }
+
     /// Lookup source information about a BytePos
     pub fn lookup_char_pos(&self, pos: BytePos) -> Loc {
         let chpos = self.bytepos_to_file_charpos(pos);
@@ -681,6 +712,9 @@ impl CodeMapper for CodeMap {
             }
         )
     }
+    fn doctest_offset_line(&self, line: usize) -> usize {
+        self.doctest_offset_line(line)
+    }
 }
 
 #[derive(Clone)]