Skip to content

Use correct line offsets for doctests #47274

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jan 14, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/librustc_errors/emitter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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);
}
Expand Down
1 change: 1 addition & 0 deletions src/librustc_errors/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
4 changes: 2 additions & 2 deletions src/librustdoc/html/markdown.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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"
Expand Down
21 changes: 15 additions & 6 deletions src/librustdoc/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,15 +176,16 @@ 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,
maybe_sysroot: Option<PathBuf>,
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 {
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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() {
Expand All @@ -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
Expand All @@ -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;
}
}
}
Expand All @@ -379,14 +386,15 @@ 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}");
}

info!("final test program: {}", prog);

prog
(prog, line_offset)
}

// FIXME(aburka): use a real parser to deal with multiline attributes
Expand Down Expand Up @@ -543,6 +551,7 @@ impl Collector {
run_test(&test,
&cratename,
&filename,
line,
cfgs,
libs,
externs,
Expand Down
36 changes: 35 additions & 1 deletion src/libsyntax/codemap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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 {
Expand All @@ -151,6 +164,7 @@ impl CodeMap {
file_loader,
path_mapping,
stable_id_to_filemap: RefCell::new(FxHashMap()),
doctest_offset: None,
}
}

Expand All @@ -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>>> {
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -681,6 +712,9 @@ impl CodeMapper for CodeMap {
}
)
}
fn doctest_offset_line(&self, line: usize) -> usize {
self.doctest_offset_line(line)
}
}

#[derive(Clone)]
Expand Down
8 changes: 8 additions & 0 deletions src/test/run-make/rustdoc-error-lines/Makefile
Original file line number Diff line number Diff line change
@@ -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
21 changes: 21 additions & 0 deletions src/test/run-make/rustdoc-error-lines/input.rs
Original file line number Diff line number Diff line change
@@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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() {

}