From 730679685ebad64e94b50961bb6c8c2e385529e4 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Mon, 8 Jan 2018 20:17:23 +0530 Subject: [PATCH 1/2] Use correct line offsets for doctests (fixes #45868) --- src/librustc_errors/emitter.rs | 4 ++-- src/librustc_errors/lib.rs | 1 + src/librustdoc/html/markdown.rs | 4 ++-- src/librustdoc/test.rs | 21 +++++++++++++------ src/libsyntax/codemap.rs | 36 ++++++++++++++++++++++++++++++++- 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; fn call_span_if_macro(&self, sp: Span) -> Span; fn ensure_filemap_source_present(&self, file_map: Rc) -> 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>> Iterator for CodeBlocks<'a, I> { .map(|l| map_line(l).for_code()) .collect::>().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(") { "&version=nightly" @@ -607,7 +607,7 @@ pub fn render(w: &mut fmt::Formatter, .map(|l| map_line(l).for_code()) .collect::>().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(") { "&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, libs: SearchPaths, +fn run_test(test: &str, cratename: &str, filename: &FileName, line: usize, + cfgs: Vec, libs: SearchPaths, externs: Externs, should_panic: bool, no_run: bool, as_test_harness: bool, compile_fail: bool, mut error_codes: Vec, opts: &TestOptions, @@ -184,7 +185,7 @@ fn run_test(test: &str, cratename: &str, filename: &FileName, cfgs: Vec, linker: Option) { // 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, } } 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, } } +/// 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>>, + /// 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, 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> { 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>> { @@ -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)] From 44b659ac2d7563198ce3ae39a4bfcecc6954fe21 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Wed, 10 Jan 2018 10:34:14 +0530 Subject: [PATCH 2/2] Add test for #45868 --- .../run-make/rustdoc-error-lines/Makefile | 8 +++++++ .../run-make/rustdoc-error-lines/input.rs | 21 +++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 src/test/run-make/rustdoc-error-lines/Makefile create mode 100644 src/test/run-make/rustdoc-error-lines/input.rs diff --git a/src/test/run-make/rustdoc-error-lines/Makefile b/src/test/run-make/rustdoc-error-lines/Makefile new file mode 100644 index 00000000000..0019e5ee794 --- /dev/null +++ b/src/test/run-make/rustdoc-error-lines/Makefile @@ -0,0 +1,8 @@ +-include ../tools.mk + +# Test that hir-tree output doens't crash and includes +# the string constant we would expect to see. + +all: + $(RUSTDOC) --test input.rs > $(TMPDIR)/output || true + $(CGREP) 'input.rs:17:15' < $(TMPDIR)/output diff --git a/src/test/run-make/rustdoc-error-lines/input.rs b/src/test/run-make/rustdoc-error-lines/input.rs new file mode 100644 index 00000000000..6dc7060bc48 --- /dev/null +++ b/src/test/run-make/rustdoc-error-lines/input.rs @@ -0,0 +1,21 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test for #45868 + +// random #![feature] to ensure that crate attrs +// do not offset things +/// ```rust +/// #![feature(nll)] +/// let x: char = 1; +/// ``` +pub fn foo() { + +}