]> git.lizzy.rs Git - rust.git/commitdiff
Add line number and filename in error message
authorGuillaume Gomez <guillaume1.gomez@gmail.com>
Sun, 2 Oct 2016 00:11:45 +0000 (02:11 +0200)
committerGuillaume Gomez <guillaume1.gomez@gmail.com>
Fri, 3 Feb 2017 10:08:19 +0000 (11:08 +0100)
src/librustdoc/markdown.rs
src/librustdoc/test.rs

index 369e18948ad5b44dbd18e4ad1c0ff8bd8a31b456..50f748deb0b9e840a4d7d407bd6773e9fa1d9081 100644 (file)
@@ -154,7 +154,7 @@ pub fn test(input: &str, cfgs: Vec<String>, libs: SearchPaths, externs: Externs,
     let mut opts = TestOptions::default();
     opts.no_crate_inject = true;
     let mut collector = Collector::new(input.to_string(), cfgs, libs, externs,
-                                       true, opts, maybe_sysroot);
+                                       true, opts, maybe_sysroot, &input_str, "input".to_string());
     find_testable_code(&input_str, &mut collector);
     test_args.insert(0, "rustdoctest".to_string());
     testing::test_main(&test_args, collector.tests);
index 00327007dd00d94a40731e271416e98134cfe1ed..a772a52da727ac32f403b6761daa72a656a79da8 100644 (file)
@@ -8,8 +8,10 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use std::collections::HashMap;
 use std::env;
 use std::ffi::OsString;
+use std::fs::File;
 use std::io::prelude::*;
 use std::io;
 use std::path::PathBuf;
@@ -96,13 +98,24 @@ pub fn run(input: &str,
         link::find_crate_name(None, &hir_forest.krate().attrs, &input)
     });
     let opts = scrape_test_config(hir_forest.krate());
+    let filename = input_path.to_str().unwrap_or("").to_owned();
+    let mut f = match File::open(input_path) {
+        Ok(f) => f,
+        _ => return 1,
+    };
+    let mut file_content = String::new();
+    if let Err(_) = f.read_to_string(&mut file_content) {
+        return 1;
+    }
     let mut collector = Collector::new(crate_name,
                                        cfgs,
                                        libs,
                                        externs,
                                        false,
                                        opts,
-                                       maybe_sysroot);
+                                       maybe_sysroot,
+                                       &file_content,
+                                       filename);
 
     {
         let dep_graph = DepGraph::new(false);
@@ -162,11 +175,12 @@ fn runtest(test: &str, cratename: &str, cfgs: Vec<String>, libs: SearchPaths,
            should_panic: bool, no_run: bool, as_test_harness: bool,
            compile_fail: bool, mut error_codes: Vec<String>, opts: &TestOptions,
            maybe_sysroot: Option<PathBuf>,
-           original: &str) {
+           original: &str, line_number: u32, filename: &str) {
     // the test harness wants its own `main` & top level functions, so
     // never wrap the test in `fn main() { ... }`
     let new_test = maketest(test, Some(cratename), as_test_harness, opts);
-    let test = format!("```{}\n{}\n```\n", original, test);
+    let test = format!("Error on {}:{}\n\n```{}\n{}\n```\n",
+                       filename, line_number, original, test);
     let input = config::Input::Str {
         name: driver::anon_src(),
         input: new_test.to_owned(),
@@ -389,11 +403,27 @@ pub struct Collector {
     cratename: String,
     opts: TestOptions,
     maybe_sysroot: Option<PathBuf>,
+    code_blocks: HashMap<String, Vec<u32>>,
+    filename: String,
 }
 
 impl Collector {
     pub fn new(cratename: String, cfgs: Vec<String>, libs: SearchPaths, externs: Externs,
-               use_headers: bool, opts: TestOptions, maybe_sysroot: Option<PathBuf>) -> Collector {
+               use_headers: bool, opts: TestOptions, maybe_sysroot: Option<PathBuf>,
+               file_content: &str, filename: String) -> Collector {
+        let mut line_number = 1;
+        let mut block_lines = HashMap::new();
+        for (pos, block) in file_content.split("```").enumerate() {
+            if (pos & 1) != 0 {
+                let key = format!("{}", block.replace("/// ", "").replace("//!", ""));
+                if !block_lines.contains_key(&key) {
+                    block_lines.insert(key.clone(), Vec::new());
+                }
+                block_lines.get_mut(&key).unwrap().push(line_number);
+            }
+            line_number += block.lines().count() as u32 - 1;
+        }
+
         Collector {
             tests: Vec::new(),
             names: Vec::new(),
@@ -406,7 +436,22 @@ pub fn new(cratename: String, cfgs: Vec<String>, libs: SearchPaths, externs: Ext
             cratename: cratename,
             opts: opts,
             maybe_sysroot: maybe_sysroot,
+            code_blocks: block_lines,
+            filename: filename,
+        }
+    }
+
+    fn get_line_from_key(&mut self, key: &String) -> u32 {
+        let (line, need_removal) = if let Some(l) = self.code_blocks.get_mut(key) {
+            let need_removal = l.len() > 1;
+            (l.pop().unwrap_or(1), need_removal)
+        } else {
+            return 1;
+        };
+        if need_removal {
+            self.code_blocks.remove(key);
         }
+        line
     }
 
     pub fn add_test(&mut self, test: String,
@@ -427,6 +472,8 @@ pub fn add_test(&mut self, test: String,
         let opts = self.opts.clone();
         let maybe_sysroot = self.maybe_sysroot.clone();
         debug!("Creating test {}: {}", name, test);
+        let line_number = self.get_line_from_key(&format!("{}\n{}\n", original, test));
+        let filename = self.filename.clone();
         self.tests.push(testing::TestDescAndFn {
             desc: testing::TestDesc {
                 name: testing::DynTestName(name),
@@ -453,7 +500,9 @@ pub fn add_test(&mut self, test: String,
                                 error_codes,
                                 &opts,
                                 maybe_sysroot,
-                                &original)
+                                &original,
+                                line_number,
+                                &filename)
                     })
                 } {
                     Ok(()) => (),