Auto merge of #41508 - michaelwoerister:generic-path-remapping, r=alexcrichton

Implement a file-path remapping feature in support of debuginfo and reproducible builds

This PR adds the `-Zremap-path-prefix-from`/`-Zremap-path-prefix-to` commandline option pair and is a more general implementation of #41419. As opposed to the previous attempt, this implementation should enable reproducible builds regardless of the working directory of the compiler.

This implementation of the feature is more general in the sense that the re-mapping will affect *all* paths the compiler emits, including the ones in error messages.

r? @alexcrichton
This commit is contained in:
bors 2017-04-28 12:09:37 +00:00
commit 2971d491b9
37 changed files with 549 additions and 315 deletions

View File

@ -2,6 +2,7 @@
- [Compiler flags](compiler-flags.md)
- [linker_flavor](compiler-flags/linker-flavor.md)
- [remap_path_prefix](compiler-flags/remap-path-prefix.md)
- [Language features](language-features.md)
- [abi_msp430_interrupt](language-features/abi-msp430-interrupt.md)
- [abi_ptx](language-features/abi-ptx.md)

View File

@ -0,0 +1,37 @@
# `remap-path-prefix`
The tracking issue for this feature is: [#41555](https://github.com/rust-lang/rust/issues/41555)
------------------------
The `-Z remap-path-prefix-from`, `-Z remap-path-prefix-to` commandline option
pair allows to replace prefixes of any file paths the compiler emits in various
places. This is useful for bringing debuginfo paths into a well-known form and
for achieving reproducible builds independent of the directory the compiler was
executed in. All paths emitted by the compiler are affected, including those in
error messages.
In order to map all paths starting with `/home/foo/my-project/src` to
`/sources/my-project`, one would invoke the compiler as follows:
```text
rustc -Zremap-path-prefix-from="/home/foo/my-project/src" -Zremap-path-prefix-to="/sources/my-project"
```
Debuginfo for code from the file `/home/foo/my-project/src/foo/mod.rs`,
for example, would then point debuggers to `/sources/my-project/foo/mod.rs`
instead of the original file.
The options can be specified multiple times when multiple prefixes should be
mapped:
```text
rustc -Zremap-path-prefix-from="/home/foo/my-project/src" \
-Zremap-path-prefix-to="/sources/my-project" \
-Zremap-path-prefix-from="/home/foo/my-project/build-dir" \
-Zremap-path-prefix-to="/stable-build-dir"
```
When the options are given multiple times, the nth `-from` will be matched up
with the nth `-to` and they can appear anywhere on the commandline. Mappings
specified later on the line will take precedence over earlier ones.

View File

@ -296,7 +296,7 @@ fn main() {
syntax::errors::registry::Registry::new(&[]),
Rc::new(DummyCrateStore));
let filemap = session.parse_sess.codemap()
.new_filemap("<n/a>".to_string(), None, code);
.new_filemap("<n/a>".to_string(), code);
let mut lexer = lexer::StringReader::new(session.diagnostic(), filemap);
let cm = session.codemap();

View File

@ -25,6 +25,7 @@ use lint;
use middle::cstore;
use syntax::ast::{self, IntTy, UintTy};
use syntax::codemap::FilePathMapping;
use syntax::parse::token;
use syntax::parse;
use syntax::symbol::Symbol;
@ -492,6 +493,14 @@ impl Options {
self.incremental.is_none() ||
self.cg.codegen_units == 1
}
pub fn file_path_mapping(&self) -> FilePathMapping {
FilePathMapping::new(
self.debugging_opts.remap_path_prefix_from.iter().zip(
self.debugging_opts.remap_path_prefix_to.iter()
).map(|(src, dst)| (src.clone(), dst.clone())).collect()
)
}
}
// The type of entry function, so
@ -1012,6 +1021,10 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
"Set the optimization fuel quota for a crate."),
print_fuel: Option<String> = (None, parse_opt_string, [TRACKED],
"Make Rustc print the total optimization fuel used by a crate."),
remap_path_prefix_from: Vec<String> = (vec![], parse_string_push, [TRACKED],
"add a source pattern to the file path remapping config"),
remap_path_prefix_to: Vec<String> = (vec![], parse_string_push, [TRACKED],
"add a mapping target to the file path remapping config"),
}
pub fn default_lib_output() -> CrateType {
@ -1319,7 +1332,7 @@ pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
// Convert strings provided as --cfg [cfgspec] into a crate_cfg
pub fn parse_cfgspecs(cfgspecs: Vec<String> ) -> ast::CrateConfig {
cfgspecs.into_iter().map(|s| {
let sess = parse::ParseSess::new();
let sess = parse::ParseSess::new(FilePathMapping::empty());
let mut parser =
parse::new_parser_from_source_str(&sess, "cfgspec".to_string(), s.to_string());
@ -1430,6 +1443,23 @@ pub fn build_session_options_and_crate_config(matches: &getopts::Matches)
output_types.insert(OutputType::Exe, None);
}
let remap_path_prefix_sources = debugging_opts.remap_path_prefix_from.len();
let remap_path_prefix_targets = debugging_opts.remap_path_prefix_from.len();
if remap_path_prefix_targets < remap_path_prefix_sources {
for source in &debugging_opts.remap_path_prefix_from[remap_path_prefix_targets..] {
early_error(error_format,
&format!("option `-Zremap-path-prefix-from='{}'` does not have \
a corresponding `-Zremap-path-prefix-to`", source))
}
} else if remap_path_prefix_targets > remap_path_prefix_sources {
for target in &debugging_opts.remap_path_prefix_to[remap_path_prefix_sources..] {
early_error(error_format,
&format!("option `-Zremap-path-prefix-to='{}'` does not have \
a corresponding `-Zremap-path-prefix-from`", target))
}
}
let mut cg = build_codegen_options(matches, error_format);
// Issue #30063: if user requests llvm-related output to one

View File

@ -74,8 +74,10 @@ pub struct Session {
// The name of the root source file of the crate, in the local file system.
// The path is always expected to be absolute. `None` means that there is no
// source file.
pub local_crate_source_file: Option<PathBuf>,
pub working_dir: PathBuf,
pub local_crate_source_file: Option<String>,
// The directory the compiler has been executed in plus a flag indicating
// if the value stored here has been affected by path remapping.
pub working_dir: (String, bool),
pub lint_store: RefCell<lint::LintStore>,
pub lints: RefCell<lint::LintTable>,
/// Set of (LintId, span, message) tuples tracking lint (sub)diagnostics
@ -553,12 +555,14 @@ pub fn build_session(sopts: config::Options,
registry: errors::registry::Registry,
cstore: Rc<CrateStore>)
-> Session {
let file_path_mapping = sopts.file_path_mapping();
build_session_with_codemap(sopts,
dep_graph,
local_crate_source_file,
registry,
cstore,
Rc::new(codemap::CodeMap::new()),
Rc::new(codemap::CodeMap::new(file_path_mapping)),
None)
}
@ -622,7 +626,7 @@ pub fn build_session_(sopts: config::Options,
Ok(t) => t,
Err(e) => {
panic!(span_diagnostic.fatal(&format!("Error loading host specification: {}", e)));
}
}
};
let target_cfg = config::build_target_config(&sopts, &span_diagnostic);
let p_s = parse::ParseSess::with_span_handler(span_diagnostic, codemap);
@ -631,14 +635,12 @@ pub fn build_session_(sopts: config::Options,
None => Some(filesearch::get_or_default_sysroot())
};
let file_path_mapping = sopts.file_path_mapping();
// Make the path absolute, if necessary
let local_crate_source_file = local_crate_source_file.map(|path|
if path.is_absolute() {
path.clone()
} else {
env::current_dir().unwrap().join(&path)
}
);
let local_crate_source_file = local_crate_source_file.map(|path| {
file_path_mapping.map_prefix(path.to_string_lossy().into_owned()).0
});
let optimization_fuel_crate = sopts.debugging_opts.fuel.as_ref().map(|i| i.0.clone());
let optimization_fuel_limit = Cell::new(sopts.debugging_opts.fuel.as_ref()
@ -646,6 +648,9 @@ pub fn build_session_(sopts: config::Options,
let print_fuel_crate = sopts.debugging_opts.print_fuel.clone();
let print_fuel = Cell::new(0);
let working_dir = env::current_dir().unwrap().to_string_lossy().into_owned();
let working_dir = file_path_mapping.map_prefix(working_dir);
let sess = Session {
dep_graph: dep_graph.clone(),
target: target_cfg,
@ -660,7 +665,7 @@ pub fn build_session_(sopts: config::Options,
derive_registrar_fn: Cell::new(None),
default_sysroot: default_sysroot,
local_crate_source_file: local_crate_source_file,
working_dir: env::current_dir().unwrap(),
working_dir: working_dir,
lint_store: RefCell::new(lint::LintStore::new()),
lints: RefCell::new(lint::LintTable::new()),
one_time_diagnostics: RefCell::new(FxHashSet()),

View File

@ -206,7 +206,7 @@ pub fn run_compiler<'a>(args: &[String],
let cstore = Rc::new(CStore::new(&dep_graph));
let loader = file_loader.unwrap_or(box RealFileLoader);
let codemap = Rc::new(CodeMap::with_file_loader(loader));
let codemap = Rc::new(CodeMap::with_file_loader(loader, sopts.file_path_mapping()));
let mut sess = session::build_session_with_codemap(
sopts, &dep_graph, input_file_path, descriptions, cstore.clone(), codemap, emitter_dest,
);

View File

@ -31,7 +31,7 @@ use rustc::session::{self, config};
use std::rc::Rc;
use syntax::ast;
use syntax::abi::Abi;
use syntax::codemap::CodeMap;
use syntax::codemap::{CodeMap, FilePathMapping};
use errors;
use errors::emitter::Emitter;
use errors::{Level, DiagnosticBuilder};
@ -108,7 +108,7 @@ fn test_env<F>(source_string: &str,
&dep_graph,
None,
diagnostic_handler,
Rc::new(CodeMap::new()),
Rc::new(CodeMap::new(FilePathMapping::empty())),
cstore.clone());
rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
let input = config::Input::Str {

View File

@ -397,7 +397,7 @@ impl CrateStore for cstore::CStore {
let (name, def) = data.get_macro(id.index);
let source_name = format!("<{} macros>", name);
let filemap = sess.parse_sess.codemap().new_filemap(source_name, None, def.body);
let filemap = sess.parse_sess.codemap().new_filemap(source_name, def.body);
let local_span = Span { lo: filemap.start_pos, hi: filemap.end_pos, ctxt: NO_EXPANSION };
let body = filemap_to_stream(&sess.parse_sess, filemap);

View File

@ -1138,7 +1138,7 @@ impl<'a, 'tcx> CrateMetadata {
// We can't reuse an existing FileMap, so allocate a new one
// containing the information we need.
let syntax_pos::FileMap { name,
abs_path,
name_was_remapped,
start_pos,
end_pos,
lines,
@ -1162,7 +1162,7 @@ impl<'a, 'tcx> CrateMetadata {
}
let local_version = local_codemap.new_imported_filemap(name,
abs_path,
name_was_remapped,
source_length,
lines,
multibyte_chars);

View File

@ -30,6 +30,7 @@ use std::hash::Hash;
use std::intrinsics;
use std::io::prelude::*;
use std::io::Cursor;
use std::path::Path;
use std::rc::Rc;
use std::u32;
use syntax::ast::{self, CRATE_NODE_ID};
@ -1270,13 +1271,40 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
fn encode_codemap(&mut self) -> LazySeq<syntax_pos::FileMap> {
let codemap = self.tcx.sess.codemap();
let all_filemaps = codemap.files.borrow();
self.lazy_seq_ref(all_filemaps.iter()
let adapted = all_filemaps.iter()
.filter(|filemap| {
// No need to re-export imported filemaps, as any downstream
// crate will import them from their original source.
!filemap.is_imported()
})
.map(|filemap| &**filemap))
.map(|filemap| {
// When exporting FileMaps, we expand all paths to absolute
// paths because any relative paths are potentially relative to
// a wrong directory.
// However, if a path has been modified via
// `-Zremap-path-prefix` we assume the user has already set
// things up the way they want and don't touch the path values
// anymore.
let name = Path::new(&filemap.name);
let (ref working_dir, working_dir_was_remapped) = self.tcx.sess.working_dir;
if filemap.name_was_remapped ||
(name.is_relative() && working_dir_was_remapped) {
// This path of this FileMap has been modified by
// path-remapping, so we use it verbatim (and avoid cloning
// the whole map in the process).
filemap.clone()
} else {
let mut adapted = (**filemap).clone();
let abs_path = Path::new(working_dir).join(name)
.to_string_lossy()
.into_owned();
adapted.name = abs_path;
Rc::new(adapted)
}
})
.collect::<Vec<_>>();
self.lazy_seq_ref(adapted.iter().map(|fm| &**fm))
}
fn encode_def_path_table(&mut self) -> Lazy<DefPathTable> {

View File

@ -37,6 +37,7 @@ use rustc::ty::{self, TyCtxt, AssociatedItemContainer};
use std::collections::HashSet;
use std::collections::hash_map::DefaultHasher;
use std::hash::*;
use std::path::Path;
use syntax::ast::{self, NodeId, PatKind, Attribute, CRATE_NODE_ID};
use syntax::parse::token;
@ -128,6 +129,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
pub fn dump_crate_info(&mut self, name: &str, krate: &ast::Crate) {
let source_file = self.tcx.sess.local_crate_source_file.as_ref();
let crate_root = source_file.map(|source_file| {
let source_file = Path::new(source_file);
match source_file.file_name() {
Some(_) => source_file.parent().unwrap().display().to_string(),
None => source_file.display().to_string(),

View File

@ -8,12 +8,12 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use super::FunctionDebugContext;
use super::{FunctionDebugContext, FunctionDebugContextData};
use super::metadata::file_metadata;
use super::utils::{DIB, span_start};
use llvm;
use llvm::debuginfo::{DIScope, DISubprogram};
use llvm::debuginfo::DIScope;
use common::CrateContext;
use rustc::mir::{Mir, VisibilityScope};
@ -53,8 +53,8 @@ pub fn create_mir_scopes(ccx: &CrateContext, mir: &Mir, debug_context: &Function
};
let mut scopes = IndexVec::from_elem(null_scope, &mir.visibility_scopes);
let fn_metadata = match *debug_context {
FunctionDebugContext::RegularContext(ref data) => data.fn_metadata,
let debug_context = match *debug_context {
FunctionDebugContext::RegularContext(ref data) => data,
FunctionDebugContext::DebugInfoDisabled |
FunctionDebugContext::FunctionWithoutDebugInfo => {
return scopes;
@ -71,7 +71,7 @@ pub fn create_mir_scopes(ccx: &CrateContext, mir: &Mir, debug_context: &Function
// Instantiate all scopes.
for idx in 0..mir.visibility_scopes.len() {
let scope = VisibilityScope::new(idx);
make_mir_scope(ccx, &mir, &has_variables, fn_metadata, scope, &mut scopes);
make_mir_scope(ccx, &mir, &has_variables, debug_context, scope, &mut scopes);
}
scopes
@ -80,7 +80,7 @@ pub fn create_mir_scopes(ccx: &CrateContext, mir: &Mir, debug_context: &Function
fn make_mir_scope(ccx: &CrateContext,
mir: &Mir,
has_variables: &BitVector,
fn_metadata: DISubprogram,
debug_context: &FunctionDebugContextData,
scope: VisibilityScope,
scopes: &mut IndexVec<VisibilityScope, MirDebugScope>) {
if scopes[scope].is_valid() {
@ -89,13 +89,13 @@ fn make_mir_scope(ccx: &CrateContext,
let scope_data = &mir.visibility_scopes[scope];
let parent_scope = if let Some(parent) = scope_data.parent_scope {
make_mir_scope(ccx, mir, has_variables, fn_metadata, parent, scopes);
make_mir_scope(ccx, mir, has_variables, debug_context, parent, scopes);
scopes[parent]
} else {
// The root is the function itself.
let loc = span_start(ccx, mir.span);
scopes[scope] = MirDebugScope {
scope_metadata: fn_metadata,
scope_metadata: debug_context.fn_metadata,
file_start_pos: loc.file.start_pos,
file_end_pos: loc.file.end_pos,
};
@ -109,14 +109,17 @@ fn make_mir_scope(ccx: &CrateContext,
// However, we don't skip creating a nested scope if
// our parent is the root, because we might want to
// put arguments in the root and not have shadowing.
if parent_scope.scope_metadata != fn_metadata {
if parent_scope.scope_metadata != debug_context.fn_metadata {
scopes[scope] = parent_scope;
return;
}
}
let loc = span_start(ccx, scope_data.span);
let file_metadata = file_metadata(ccx, &loc.file.name, &loc.file.abs_path);
let file_metadata = file_metadata(ccx,
&loc.file.name,
debug_context.defining_crate);
let scope_metadata = unsafe {
llvm::LLVMRustDIBuilderCreateLexicalBlock(
DIB(ccx),

View File

@ -26,7 +26,7 @@ use llvm::debuginfo::{DIType, DIFile, DIScope, DIDescriptor,
DICompositeType, DILexicalBlock, DIFlags};
use rustc::hir::def::CtorKind;
use rustc::hir::def_id::{DefId, LOCAL_CRATE};
use rustc::hir::def_id::{DefId, CrateNum, LOCAL_CRATE};
use rustc::ty::fold::TypeVisitor;
use rustc::ty::subst::Substs;
use rustc::ty::util::TypeIdHasher;
@ -39,14 +39,12 @@ use rustc::ty::{self, AdtKind, Ty};
use rustc::ty::layout::{self, LayoutTyper};
use session::config;
use util::nodemap::FxHashMap;
use util::common::path2cstr;
use libc::{c_uint, c_longlong};
use std::ffi::CString;
use std::path::Path;
use std::ptr;
use syntax::ast;
use syntax::symbol::{Interner, InternedString};
use syntax::symbol::{Interner, InternedString, Symbol};
use syntax_pos::{self, Span};
@ -349,8 +347,7 @@ fn vec_slice_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
assert!(member_descriptions.len() == member_llvm_types.len());
let loc = span_start(cx, span);
let file_metadata = file_metadata(cx, &loc.file.name, &loc.file.abs_path);
let file_metadata = unknown_file_metadata(cx);
let metadata = composite_type_metadata(cx,
slice_llvm_type,
@ -659,44 +656,51 @@ pub fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
metadata
}
pub fn file_metadata(cx: &CrateContext, path: &str, full_path: &Option<String>) -> DIFile {
// FIXME (#9639): This needs to handle non-utf8 paths
let work_dir = cx.sess().working_dir.to_str().unwrap();
let file_name =
full_path.as_ref().map(|p| p.as_str()).unwrap_or_else(|| {
if path.starts_with(work_dir) {
&path[work_dir.len() + 1..path.len()]
} else {
path
}
});
pub fn file_metadata(cx: &CrateContext,
file_name: &str,
defining_crate: CrateNum) -> DIFile {
debug!("file_metadata: file_name: {}, defining_crate: {}",
file_name,
defining_crate);
file_metadata_(cx, path, file_name, &work_dir)
let directory = if defining_crate == LOCAL_CRATE {
&cx.sess().working_dir.0[..]
} else {
// If the path comes from an upstream crate we assume it has been made
// independent of the compiler's working directory one way or another.
""
};
file_metadata_raw(cx, file_name, directory)
}
pub fn unknown_file_metadata(cx: &CrateContext) -> DIFile {
// Regular filenames should not be empty, so we abuse an empty name as the
// key for the special unknown file metadata
file_metadata_(cx, "", "<unknown>", "")
file_metadata_raw(cx, "<unknown>", "")
}
fn file_metadata_(cx: &CrateContext, key: &str, file_name: &str, work_dir: &str) -> DIFile {
if let Some(file_metadata) = debug_context(cx).created_files.borrow().get(key) {
fn file_metadata_raw(cx: &CrateContext,
file_name: &str,
directory: &str)
-> DIFile {
let key = (Symbol::intern(file_name), Symbol::intern(directory));
if let Some(file_metadata) = debug_context(cx).created_files.borrow().get(&key) {
return *file_metadata;
}
debug!("file_metadata: file_name: {}, work_dir: {}", file_name, work_dir);
debug!("file_metadata: file_name: {}, directory: {}", file_name, directory);
let file_name = CString::new(file_name).unwrap();
let work_dir = CString::new(work_dir).unwrap();
let directory = CString::new(directory).unwrap();
let file_metadata = unsafe {
llvm::LLVMRustDIBuilderCreateFile(DIB(cx), file_name.as_ptr(),
work_dir.as_ptr())
llvm::LLVMRustDIBuilderCreateFile(DIB(cx),
file_name.as_ptr(),
directory.as_ptr())
};
let mut created_files = debug_context(cx).created_files.borrow_mut();
created_files.insert(key.to_string(), file_metadata);
created_files.insert(key, file_metadata);
file_metadata
}
@ -761,25 +765,10 @@ pub fn compile_unit_metadata(scc: &SharedCrateContext,
debug_context: &CrateDebugContext,
sess: &Session)
-> DIDescriptor {
let work_dir = &sess.working_dir;
let compile_unit_name = match sess.local_crate_source_file {
None => fallback_path(scc),
Some(ref abs_path) => {
if abs_path.is_relative() {
sess.warn("debuginfo: Invalid path to crate's local root source file!");
fallback_path(scc)
} else {
match abs_path.strip_prefix(work_dir) {
Ok(ref p) if p.is_relative() => {
if p.starts_with(Path::new("./")) {
path2cstr(p)
} else {
path2cstr(&Path::new(".").join(p))
}
}
_ => fallback_path(scc)
}
}
Some(ref path) => {
CString::new(&path[..]).unwrap()
}
};
@ -789,7 +778,8 @@ pub fn compile_unit_metadata(scc: &SharedCrateContext,
(option_env!("CFG_VERSION")).expect("CFG_VERSION"));
let compile_unit_name = compile_unit_name.as_ptr();
let work_dir = path2cstr(&work_dir);
let work_dir = CString::new(&sess.working_dir.0[..]).unwrap();
let producer = CString::new(producer).unwrap();
let flags = "\0";
let split_name = "\0";
@ -1760,7 +1750,7 @@ pub fn create_global_var_metadata(cx: &CrateContext,
let (file_metadata, line_number) = if span != syntax_pos::DUMMY_SP {
let loc = span_start(cx, span);
(file_metadata(cx, &loc.file.name, &loc.file.abs_path), loc.line as c_uint)
(file_metadata(cx, &loc.file.name, LOCAL_CRATE), loc.line as c_uint)
} else {
(unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER)
};
@ -1795,9 +1785,10 @@ pub fn create_global_var_metadata(cx: &CrateContext,
// Creates an "extension" of an existing DIScope into another file.
pub fn extend_scope_to_file(ccx: &CrateContext,
scope_metadata: DIScope,
file: &syntax_pos::FileMap)
file: &syntax_pos::FileMap,
defining_crate: CrateNum)
-> DILexicalBlock {
let file_metadata = file_metadata(ccx, &file.name, &file.abs_path);
let file_metadata = file_metadata(ccx, &file.name, defining_crate);
unsafe {
llvm::LLVMRustDIBuilderCreateLexicalBlockFile(
DIB(ccx),

View File

@ -23,7 +23,7 @@ use self::source_loc::InternalDebugLocation::{self, UnknownLocation};
use llvm;
use llvm::{ModuleRef, ContextRef, ValueRef};
use llvm::debuginfo::{DIFile, DIType, DIScope, DIBuilderRef, DISubprogram, DIArray, DIFlags};
use rustc::hir::def_id::DefId;
use rustc::hir::def_id::{DefId, CrateNum};
use rustc::ty::subst::Substs;
use abi::Abi;
@ -42,6 +42,7 @@ use std::ptr;
use syntax_pos::{self, Span, Pos};
use syntax::ast;
use syntax::symbol::Symbol;
use rustc::ty::layout;
pub mod gdb;
@ -67,7 +68,7 @@ const DW_TAG_arg_variable: c_uint = 0x101;
pub struct CrateDebugContext<'tcx> {
llcontext: ContextRef,
builder: DIBuilderRef,
created_files: RefCell<FxHashMap<String, DIFile>>,
created_files: RefCell<FxHashMap<(Symbol, Symbol), DIFile>>,
created_enum_disr_types: RefCell<FxHashMap<(DefId, layout::Integer), DIType>>,
type_map: RefCell<TypeMap<'tcx>>,
@ -103,7 +104,7 @@ pub enum FunctionDebugContext {
}
impl FunctionDebugContext {
fn get_ref<'a>(&'a self, span: Span) -> &'a FunctionDebugContextData {
pub fn get_ref<'a>(&'a self, span: Span) -> &'a FunctionDebugContextData {
match *self {
FunctionDebugContext::RegularContext(ref data) => data,
FunctionDebugContext::DebugInfoDisabled => {
@ -128,6 +129,7 @@ impl FunctionDebugContext {
pub struct FunctionDebugContextData {
fn_metadata: DISubprogram,
source_locations_enabled: Cell<bool>,
pub defining_crate: CrateNum,
}
pub enum VariableAccess<'a> {
@ -220,8 +222,9 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
return FunctionDebugContext::FunctionWithoutDebugInfo;
}
let def_id = instance.def_id();
let loc = span_start(cx, span);
let file_metadata = file_metadata(cx, &loc.file.name, &loc.file.abs_path);
let file_metadata = file_metadata(cx, &loc.file.name, def_id.krate);
let function_type_metadata = unsafe {
let fn_signature = get_function_signature(cx, sig);
@ -229,15 +232,15 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
};
// Find the enclosing function, in case this is a closure.
let def_key = cx.tcx().def_key(instance.def_id());
let def_key = cx.tcx().def_key(def_id);
let mut name = def_key.disambiguated_data.data.to_string();
let name_len = name.len();
let fn_def_id = cx.tcx().closure_base_def_id(instance.def_id());
let enclosing_fn_def_id = cx.tcx().closure_base_def_id(def_id);
// Get_template_parameters() will append a `<...>` clause to the function
// name if necessary.
let generics = cx.tcx().generics_of(fn_def_id);
let generics = cx.tcx().generics_of(enclosing_fn_def_id);
let substs = instance.substs.truncate_to(cx.tcx(), generics);
let template_parameters = get_template_parameters(cx,
&generics,
@ -289,6 +292,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
let fn_debug_context = FunctionDebugContextData {
fn_metadata: fn_metadata,
source_locations_enabled: Cell::new(false),
defining_crate: def_id.krate,
};
return FunctionDebugContext::RegularContext(fn_debug_context);
@ -438,8 +442,9 @@ pub fn declare_local<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
let cx = bcx.ccx;
let file = span_start(cx, span).file;
let filename = file.name.clone();
let file_metadata = file_metadata(cx, &filename[..], &file.abs_path);
let file_metadata = file_metadata(cx,
&file.name[..],
dbg_context.get_ref(span).defining_crate);
let loc = span_start(cx, span);
let type_metadata = type_metadata(cx, variable_type, span);

View File

@ -72,7 +72,7 @@ pub fn item_namespace(ccx: &CrateContext, def_id: DefId) -> DIScope {
let span = ccx.tcx().def_span(def_id);
let (file, line) = if span != DUMMY_SP {
let loc = span_start(ccx, span);
(file_metadata(ccx, &loc.file.name, &loc.file.abs_path), loc.line as c_uint)
(file_metadata(ccx, &loc.file.name, def_id.krate), loc.line as c_uint)
} else {
(unknown_file_metadata(ccx), UNKNOWN_LINE_NUMBER)
};

View File

@ -157,7 +157,11 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
if pos < self.scopes[scope_id].file_start_pos ||
pos >= self.scopes[scope_id].file_end_pos {
let cm = self.ccx.sess().codemap();
debuginfo::extend_scope_to_file(self.ccx, scope_metadata, &cm.lookup_char_pos(pos).file)
let defining_crate = self.debug_context.get_ref(DUMMY_SP).defining_crate;
debuginfo::extend_scope_to_file(self.ccx,
scope_metadata,
&cm.lookup_char_pos(pos).file,
defining_crate)
} else {
scope_metadata
}

View File

@ -129,7 +129,7 @@ pub fn run_core(search_paths: SearchPaths,
..config::basic_options().clone()
};
let codemap = Rc::new(codemap::CodeMap::new());
let codemap = Rc::new(codemap::CodeMap::new(sessopts.file_path_mapping()));
let diagnostic_handler = errors::Handler::with_tty_emitter(ColorConfig::Auto,
true,
false,

View File

@ -26,7 +26,7 @@ use std::fmt::Display;
use std::io;
use std::io::prelude::*;
use syntax::codemap::CodeMap;
use syntax::codemap::{CodeMap, FilePathMapping};
use syntax::parse::lexer::{self, TokenAndSpan};
use syntax::parse::token;
use syntax::parse;
@ -36,8 +36,8 @@ use syntax_pos::Span;
pub fn render_with_highlighting(src: &str, class: Option<&str>, id: Option<&str>,
extension: Option<&str>) -> String {
debug!("highlighting: ================\n{}\n==============", src);
let sess = parse::ParseSess::new();
let fm = sess.codemap().new_filemap("<stdin>".to_string(), None, src.to_string());
let sess = parse::ParseSess::new(FilePathMapping::empty());
let fm = sess.codemap().new_filemap("<stdin>".to_string(), src.to_string());
let mut out = Vec::new();
write_header(class, id, &mut out).unwrap();
@ -58,8 +58,8 @@ pub fn render_with_highlighting(src: &str, class: Option<&str>, id: Option<&str>
/// be inserted into an element. C.f., `render_with_highlighting` which includes
/// an enclosing `<pre>` block.
pub fn render_inner_with_highlighting(src: &str) -> io::Result<String> {
let sess = parse::ParseSess::new();
let fm = sess.codemap().new_filemap("<stdin>".to_string(), None, src.to_string());
let sess = parse::ParseSess::new(FilePathMapping::empty());
let fm = sess.codemap().new_filemap("<stdin>".to_string(), src.to_string());
let mut out = Vec::new();
let mut classifier = Classifier::new(lexer::StringReader::new(&sess, fm), sess.codemap());

View File

@ -74,7 +74,7 @@ pub fn run(input: &str,
..config::basic_options().clone()
};
let codemap = Rc::new(CodeMap::new());
let codemap = Rc::new(CodeMap::new(sessopts.file_path_mapping()));
let handler =
errors::Handler::with_tty_emitter(ColorConfig::Auto, true, false, Some(codemap.clone()));
@ -217,7 +217,7 @@ fn runtest(test: &str, cratename: &str, cfgs: Vec<String>, libs: SearchPaths,
}
}
let data = Arc::new(Mutex::new(Vec::new()));
let codemap = Rc::new(CodeMap::new());
let codemap = Rc::new(CodeMap::new(sessopts.file_path_mapping()));
let emitter = errors::emitter::EmitterWriter::new(box Sink(data.clone()),
Some(codemap.clone()));
let old = io::set_panic(Some(box Sink(data.clone())));

View File

@ -104,32 +104,42 @@ impl FileLoader for RealFileLoader {
pub struct CodeMap {
pub files: RefCell<Vec<Rc<FileMap>>>,
file_loader: Box<FileLoader>
file_loader: Box<FileLoader>,
// This is used to apply the file path remapping as specified via
// -Zremap-path-prefix to all FileMaps allocated within this CodeMap.
path_mapping: FilePathMapping,
}
impl CodeMap {
pub fn new() -> CodeMap {
pub fn new(path_mapping: FilePathMapping) -> CodeMap {
CodeMap {
files: RefCell::new(Vec::new()),
file_loader: Box::new(RealFileLoader)
file_loader: Box::new(RealFileLoader),
path_mapping: path_mapping,
}
}
pub fn with_file_loader(file_loader: Box<FileLoader>) -> CodeMap {
pub fn with_file_loader(file_loader: Box<FileLoader>,
path_mapping: FilePathMapping)
-> CodeMap {
CodeMap {
files: RefCell::new(Vec::new()),
file_loader: file_loader
file_loader: file_loader,
path_mapping: path_mapping,
}
}
pub fn path_mapping(&self) -> &FilePathMapping {
&self.path_mapping
}
pub fn file_exists(&self, path: &Path) -> bool {
self.file_loader.file_exists(path)
}
pub fn load_file(&self, path: &Path) -> io::Result<Rc<FileMap>> {
let src = self.file_loader.read_file(path)?;
let abs_path = self.file_loader.abs_path(path).map(|p| p.to_str().unwrap().to_string());
Ok(self.new_filemap(path.to_str().unwrap().to_string(), abs_path, src))
Ok(self.new_filemap(path.to_str().unwrap().to_string(), src))
}
fn next_start_pos(&self) -> usize {
@ -144,8 +154,7 @@ impl CodeMap {
/// Creates a new filemap without setting its line information. If you don't
/// intend to set the line information yourself, you should use new_filemap_and_lines.
pub fn new_filemap(&self, filename: FileName, abs_path: Option<FileName>,
mut src: String) -> Rc<FileMap> {
pub fn new_filemap(&self, filename: FileName, mut src: String) -> Rc<FileMap> {
let start_pos = self.next_start_pos();
let mut files = self.files.borrow_mut();
@ -156,9 +165,11 @@ impl CodeMap {
let end_pos = start_pos + src.len();
let (filename, was_remapped) = self.path_mapping.map_prefix(filename);
let filemap = Rc::new(FileMap {
name: filename,
abs_path: abs_path,
name_was_remapped: was_remapped,
src: Some(Rc::new(src)),
start_pos: Pos::from_usize(start_pos),
end_pos: Pos::from_usize(end_pos),
@ -172,11 +183,8 @@ impl CodeMap {
}
/// Creates a new filemap and sets its line information.
pub fn new_filemap_and_lines(&self, filename: &str, abs_path: Option<&str>,
src: &str) -> Rc<FileMap> {
let fm = self.new_filemap(filename.to_string(),
abs_path.map(|s| s.to_owned()),
src.to_owned());
pub fn new_filemap_and_lines(&self, filename: &str, src: &str) -> Rc<FileMap> {
let fm = self.new_filemap(filename.to_string(), src.to_owned());
let mut byte_pos: u32 = fm.start_pos.0;
for line in src.lines() {
// register the start of this line
@ -195,7 +203,7 @@ impl CodeMap {
/// information for things inlined from other crates.
pub fn new_imported_filemap(&self,
filename: FileName,
abs_path: Option<FileName>,
name_was_remapped: bool,
source_len: usize,
mut file_local_lines: Vec<BytePos>,
mut file_local_multibyte_chars: Vec<MultiByteChar>)
@ -216,7 +224,7 @@ impl CodeMap {
let filemap = Rc::new(FileMap {
name: filename,
abs_path: abs_path,
name_was_remapped: name_was_remapped,
src: None,
start_pos: start_pos,
end_pos: end_pos,
@ -550,6 +558,42 @@ impl CodeMapper for CodeMap {
}
}
#[derive(Clone)]
pub struct FilePathMapping {
mapping: Vec<(String, String)>,
}
impl FilePathMapping {
pub fn empty() -> FilePathMapping {
FilePathMapping {
mapping: vec![]
}
}
pub fn new(mapping: Vec<(String, String)>) -> FilePathMapping {
FilePathMapping {
mapping: mapping
}
}
/// Applies any path prefix substitution as defined by the mapping.
/// The return value is the remapped path and a boolean indicating whether
/// the path was affected by the mapping.
pub fn map_prefix(&self, path: String) -> (String, bool) {
// NOTE: We are iterating over the mapping entries from last to first
// because entries specified later on the command line should
// take precedence.
for &(ref from, ref to) in self.mapping.iter().rev() {
if path.starts_with(from) {
let mapped = path.replacen(from, to, 1);
return (mapped, true);
}
}
(path, false)
}
}
// _____________________________________________________________________________
// Tests
//
@ -561,9 +605,8 @@ mod tests {
#[test]
fn t1 () {
let cm = CodeMap::new();
let cm = CodeMap::new(FilePathMapping::empty());
let fm = cm.new_filemap("blork.rs".to_string(),
None,
"first line.\nsecond line".to_string());
fm.next_line(BytePos(0));
// Test we can get lines with partial line info.
@ -578,9 +621,8 @@ mod tests {
#[test]
#[should_panic]
fn t2 () {
let cm = CodeMap::new();
let cm = CodeMap::new(FilePathMapping::empty());
let fm = cm.new_filemap("blork.rs".to_string(),
None,
"first line.\nsecond line".to_string());
// TESTING *REALLY* BROKEN BEHAVIOR:
fm.next_line(BytePos(0));
@ -589,15 +631,12 @@ mod tests {
}
fn init_code_map() -> CodeMap {
let cm = CodeMap::new();
let cm = CodeMap::new(FilePathMapping::empty());
let fm1 = cm.new_filemap("blork.rs".to_string(),
None,
"first line.\nsecond line".to_string());
let fm2 = cm.new_filemap("empty.rs".to_string(),
None,
"".to_string());
let fm3 = cm.new_filemap("blork2.rs".to_string(),
None,
"first line.\nsecond line".to_string());
fm1.next_line(BytePos(0));
@ -656,14 +695,12 @@ mod tests {
}
fn init_code_map_mbc() -> CodeMap {
let cm = CodeMap::new();
let cm = CodeMap::new(FilePathMapping::empty());
// € is a three byte utf8 char.
let fm1 =
cm.new_filemap("blork.rs".to_string(),
None,
"fir€st €€€€ line.\nsecond line".to_string());
let fm2 = cm.new_filemap("blork2.rs".to_string(),
None,
"first line€€.\n€ second line".to_string());
fm1.next_line(BytePos(0));
@ -728,10 +765,10 @@ mod tests {
/// lines in the middle of a file.
#[test]
fn span_to_snippet_and_lines_spanning_multiple_lines() {
let cm = CodeMap::new();
let cm = CodeMap::new(FilePathMapping::empty());
let inputtext = "aaaaa\nbbbbBB\nCCC\nDDDDDddddd\neee\n";
let selection = " \n ~~\n~~~\n~~~~~ \n \n";
cm.new_filemap_and_lines("blork.rs", None, inputtext);
cm.new_filemap_and_lines("blork.rs", inputtext);
let span = span_from_selection(inputtext, selection);
// check that we are extracting the text we thought we were extracting
@ -770,11 +807,11 @@ mod tests {
/// Test failing to merge two spans on different lines
#[test]
fn span_merging_fail() {
let cm = CodeMap::new();
let cm = CodeMap::new(FilePathMapping::empty());
let inputtext = "bbbb BB\ncc CCC\n";
let selection1 = " ~~\n \n";
let selection2 = " \n ~~~\n";
cm.new_filemap_and_lines("blork.rs", None, inputtext);
cm.new_filemap_and_lines("blork.rs", inputtext);
let span1 = span_from_selection(inputtext, selection1);
let span2 = span_from_selection(inputtext, selection2);

View File

@ -783,7 +783,7 @@ fn stream_for_item(item: &Annotatable, parse_sess: &ParseSess) -> TokenStream {
fn string_to_stream(text: String, parse_sess: &ParseSess) -> TokenStream {
let filename = String::from("<macro expansion>");
filemap_to_stream(parse_sess, parse_sess.codemap().new_filemap(filename, None, text))
filemap_to_stream(parse_sess, parse_sess.codemap().new_filemap(filename, text))
}
impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {

View File

@ -142,7 +142,7 @@ pub fn expand_include_str(cx: &mut ExtCtxt, sp: Span, tts: &[tokenstream::TokenT
// Add this input file to the code map to make it available as
// dependency information
let filename = format!("{}", file.display());
cx.codemap().new_filemap_and_lines(&filename, None, &src);
cx.codemap().new_filemap_and_lines(&filename, &src);
base::MacEager::expr(cx.expr_str(sp, Symbol::intern(&src)))
}
@ -173,7 +173,7 @@ pub fn expand_include_bytes(cx: &mut ExtCtxt, sp: Span, tts: &[tokenstream::Toke
// Add this input file to the code map to make it available as
// dependency information, but don't enter it's contents
let filename = format!("{}", file.display());
cx.codemap().new_filemap_and_lines(&filename, None, "");
cx.codemap().new_filemap_and_lines(&filename, "");
base::MacEager::expr(cx.expr_lit(sp, ast::LitKind::ByteStr(Rc::new(bytes))))
}

View File

@ -19,7 +19,7 @@
// FIXME spec the JSON output properly.
use codemap::CodeMap;
use codemap::{CodeMap, FilePathMapping};
use syntax_pos::{self, MacroBacktrace, Span, SpanLabel, MultiSpan};
use errors::registry::Registry;
use errors::{DiagnosticBuilder, SubDiagnostic, RenderSpan, CodeSuggestion, CodeMapper};
@ -48,7 +48,8 @@ impl JsonEmitter {
}
pub fn basic() -> JsonEmitter {
JsonEmitter::stderr(None, Rc::new(CodeMap::new()))
let file_path_mapping = FilePathMapping::empty();
JsonEmitter::stderr(None, Rc::new(CodeMap::new(file_path_mapping)))
}
pub fn new(dst: Box<Write + Send>,

View File

@ -348,8 +348,8 @@ pub fn gather_comments_and_literals(sess: &ParseSess, path: String, srdr: &mut R
let mut src = Vec::new();
srdr.read_to_end(&mut src).unwrap();
let src = String::from_utf8(src).unwrap();
let cm = CodeMap::new();
let filemap = cm.new_filemap(path, None, src);
let cm = CodeMap::new(sess.codemap().path_mapping().clone());
let filemap = cm.new_filemap(path, src);
let mut rdr = lexer::StringReader::new_raw(sess, filemap);
let mut comments: Vec<Comment> = Vec::new();

View File

@ -10,7 +10,7 @@
use ast::{self, Ident};
use syntax_pos::{self, BytePos, CharPos, Pos, Span, NO_EXPANSION};
use codemap::CodeMap;
use codemap::{CodeMap, FilePathMapping};
use errors::{FatalError, DiagnosticBuilder};
use parse::{token, ParseSess};
use str::char_at;
@ -563,7 +563,7 @@ impl<'a> StringReader<'a> {
// I guess this is the only way to figure out if
// we're at the beginning of the file...
let cmap = CodeMap::new();
let cmap = CodeMap::new(FilePathMapping::empty());
cmap.files.borrow_mut().push(self.filemap.clone());
let loc = cmap.lookup_char_pos_adj(self.pos);
debug!("Skipping a shebang");
@ -1718,13 +1718,13 @@ mod tests {
sess: &'a ParseSess,
teststr: String)
-> StringReader<'a> {
let fm = cm.new_filemap("zebra.rs".to_string(), None, teststr);
let fm = cm.new_filemap("zebra.rs".to_string(), teststr);
StringReader::new(sess, fm)
}
#[test]
fn t1() {
let cm = Rc::new(CodeMap::new());
let cm = Rc::new(CodeMap::new(FilePathMapping::empty()));
let sh = mk_sess(cm.clone());
let mut string_reader = setup(&cm,
&sh,
@ -1776,7 +1776,7 @@ mod tests {
#[test]
fn doublecolonparsing() {
let cm = Rc::new(CodeMap::new());
let cm = Rc::new(CodeMap::new(FilePathMapping::empty()));
let sh = mk_sess(cm.clone());
check_tokenization(setup(&cm, &sh, "a b".to_string()),
vec![mk_ident("a"), token::Whitespace, mk_ident("b")]);
@ -1784,7 +1784,7 @@ mod tests {
#[test]
fn dcparsing_2() {
let cm = Rc::new(CodeMap::new());
let cm = Rc::new(CodeMap::new(FilePathMapping::empty()));
let sh = mk_sess(cm.clone());
check_tokenization(setup(&cm, &sh, "a::b".to_string()),
vec![mk_ident("a"), token::ModSep, mk_ident("b")]);
@ -1792,7 +1792,7 @@ mod tests {
#[test]
fn dcparsing_3() {
let cm = Rc::new(CodeMap::new());
let cm = Rc::new(CodeMap::new(FilePathMapping::empty()));
let sh = mk_sess(cm.clone());
check_tokenization(setup(&cm, &sh, "a ::b".to_string()),
vec![mk_ident("a"), token::Whitespace, token::ModSep, mk_ident("b")]);
@ -1800,7 +1800,7 @@ mod tests {
#[test]
fn dcparsing_4() {
let cm = Rc::new(CodeMap::new());
let cm = Rc::new(CodeMap::new(FilePathMapping::empty()));
let sh = mk_sess(cm.clone());
check_tokenization(setup(&cm, &sh, "a:: b".to_string()),
vec![mk_ident("a"), token::ModSep, token::Whitespace, mk_ident("b")]);
@ -1808,7 +1808,7 @@ mod tests {
#[test]
fn character_a() {
let cm = Rc::new(CodeMap::new());
let cm = Rc::new(CodeMap::new(FilePathMapping::empty()));
let sh = mk_sess(cm.clone());
assert_eq!(setup(&cm, &sh, "'a'".to_string()).next_token().tok,
token::Literal(token::Char(Symbol::intern("a")), None));
@ -1816,7 +1816,7 @@ mod tests {
#[test]
fn character_space() {
let cm = Rc::new(CodeMap::new());
let cm = Rc::new(CodeMap::new(FilePathMapping::empty()));
let sh = mk_sess(cm.clone());
assert_eq!(setup(&cm, &sh, "' '".to_string()).next_token().tok,
token::Literal(token::Char(Symbol::intern(" ")), None));
@ -1824,7 +1824,7 @@ mod tests {
#[test]
fn character_escaped() {
let cm = Rc::new(CodeMap::new());
let cm = Rc::new(CodeMap::new(FilePathMapping::empty()));
let sh = mk_sess(cm.clone());
assert_eq!(setup(&cm, &sh, "'\\n'".to_string()).next_token().tok,
token::Literal(token::Char(Symbol::intern("\\n")), None));
@ -1832,7 +1832,7 @@ mod tests {
#[test]
fn lifetime_name() {
let cm = Rc::new(CodeMap::new());
let cm = Rc::new(CodeMap::new(FilePathMapping::empty()));
let sh = mk_sess(cm.clone());
assert_eq!(setup(&cm, &sh, "'abc".to_string()).next_token().tok,
token::Lifetime(Ident::from_str("'abc")));
@ -1840,7 +1840,7 @@ mod tests {
#[test]
fn raw_string() {
let cm = Rc::new(CodeMap::new());
let cm = Rc::new(CodeMap::new(FilePathMapping::empty()));
let sh = mk_sess(cm.clone());
assert_eq!(setup(&cm, &sh, "r###\"\"#a\\b\x00c\"\"###".to_string())
.next_token()
@ -1850,7 +1850,7 @@ mod tests {
#[test]
fn literal_suffixes() {
let cm = Rc::new(CodeMap::new());
let cm = Rc::new(CodeMap::new(FilePathMapping::empty()));
let sh = mk_sess(cm.clone());
macro_rules! test {
($input: expr, $tok_type: ident, $tok_contents: expr) => {{
@ -1894,7 +1894,7 @@ mod tests {
#[test]
fn nested_block_comments() {
let cm = Rc::new(CodeMap::new());
let cm = Rc::new(CodeMap::new(FilePathMapping::empty()));
let sh = mk_sess(cm.clone());
let mut lexer = setup(&cm, &sh, "/* /* */ */'a'".to_string());
match lexer.next_token().tok {
@ -1907,7 +1907,7 @@ mod tests {
#[test]
fn crlf_comments() {
let cm = Rc::new(CodeMap::new());
let cm = Rc::new(CodeMap::new(FilePathMapping::empty()));
let sh = mk_sess(cm.clone());
let mut lexer = setup(&cm, &sh, "// test\r\n/// test\r\n".to_string());
let comment = lexer.next_token();

View File

@ -11,7 +11,7 @@
//! The main parser interface
use ast::{self, CrateConfig};
use codemap::CodeMap;
use codemap::{CodeMap, FilePathMapping};
use syntax_pos::{self, Span, FileMap, NO_EXPANSION};
use errors::{Handler, ColorConfig, DiagnosticBuilder};
use feature_gate::UnstableFeatures;
@ -53,8 +53,8 @@ pub struct ParseSess {
}
impl ParseSess {
pub fn new() -> Self {
let cm = Rc::new(CodeMap::new());
pub fn new(file_path_mapping: FilePathMapping) -> Self {
let cm = Rc::new(CodeMap::new(file_path_mapping));
let handler = Handler::with_tty_emitter(ColorConfig::Auto,
true,
false,
@ -143,13 +143,13 @@ pub fn parse_stmt_from_source_str<'a>(name: String, source: String, sess: &'a Pa
pub fn parse_stream_from_source_str<'a>(name: String, source: String, sess: &'a ParseSess)
-> TokenStream {
filemap_to_stream(sess, sess.codemap().new_filemap(name, None, source))
filemap_to_stream(sess, sess.codemap().new_filemap(name, source))
}
// Create a new parser from a source string
pub fn new_parser_from_source_str<'a>(sess: &'a ParseSess, name: String, source: String)
-> Parser<'a> {
filemap_to_parser(sess, sess.codemap().new_filemap(name, None, source))
filemap_to_parser(sess, sess.codemap().new_filemap(name, source))
}
/// Create a new parser, handling errors as appropriate
@ -828,7 +828,7 @@ mod tests {
}
#[test] fn parse_ident_pat () {
let sess = ParseSess::new();
let sess = ParseSess::new(FilePathMapping::empty());
let mut parser = string_to_parser(&sess, "b".to_string());
assert!(panictry!(parser.parse_pat())
== P(ast::Pat{
@ -998,7 +998,7 @@ mod tests {
}
#[test] fn crlf_doc_comments() {
let sess = ParseSess::new();
let sess = ParseSess::new(FilePathMapping::empty());
let name = "<source>".to_string();
let source = "/// doc comment\r\nfn foo() {}".to_string();
@ -1023,7 +1023,7 @@ mod tests {
#[test]
fn ttdelim_span() {
let sess = ParseSess::new();
let sess = ParseSess::new(FilePathMapping::empty());
let expr = parse::parse_expr_from_source_str("foo".to_string(),
"foo!( fn main() { body } )".to_string(), &sess).unwrap();

View File

@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use codemap::CodeMap;
use codemap::{CodeMap, FilePathMapping};
use errors::Handler;
use errors::emitter::EmitterWriter;
use std::io;
@ -47,8 +47,8 @@ impl<T: Write> Write for Shared<T> {
fn test_harness(file_text: &str, span_labels: Vec<SpanLabel>, expected_output: &str) {
let output = Arc::new(Mutex::new(Vec::new()));
let code_map = Rc::new(CodeMap::new());
code_map.new_filemap_and_lines("test.rs", None, &file_text);
let code_map = Rc::new(CodeMap::new(FilePathMapping::empty()));
code_map.new_filemap_and_lines("test.rs", &file_text);
let primary_span = make_span(&file_text, &span_labels[0].start, &span_labels[0].end);
let mut msp = MultiSpan::from_span(primary_span);

View File

@ -9,6 +9,7 @@
// except according to those terms.
use ast::{self, Ident};
use codemap::FilePathMapping;
use parse::{ParseSess, PResult, filemap_to_stream};
use parse::{lexer, new_parser_from_source_str};
use parse::parser::Parser;
@ -18,8 +19,8 @@ use std::iter::Peekable;
/// Map a string to tts, using a made-up filename:
pub fn string_to_stream(source_str: String) -> TokenStream {
let ps = ParseSess::new();
filemap_to_stream(&ps, ps.codemap().new_filemap("bogofile".to_string(), None, source_str))
let ps = ParseSess::new(FilePathMapping::empty());
filemap_to_stream(&ps, ps.codemap().new_filemap("bogofile".to_string(), source_str))
}
/// Map string to parser (via tts)
@ -38,7 +39,7 @@ fn with_error_checking_parse<'a, T, F>(s: String, ps: &'a ParseSess, f: F) -> T
/// Parse a string, return a crate.
pub fn string_to_crate (source_str : String) -> ast::Crate {
let ps = ParseSess::new();
let ps = ParseSess::new(FilePathMapping::empty());
with_error_checking_parse(source_str, &ps, |p| {
p.parse_crate_mod()
})
@ -46,7 +47,7 @@ pub fn string_to_crate (source_str : String) -> ast::Crate {
/// Parse a string, return an expr
pub fn string_to_expr (source_str : String) -> P<ast::Expr> {
let ps = ParseSess::new();
let ps = ParseSess::new(FilePathMapping::empty());
with_error_checking_parse(source_str, &ps, |p| {
p.parse_expr()
})
@ -54,7 +55,7 @@ pub fn string_to_expr (source_str : String) -> P<ast::Expr> {
/// Parse a string, return an item
pub fn string_to_item (source_str : String) -> Option<P<ast::Item>> {
let ps = ParseSess::new();
let ps = ParseSess::new(FilePathMapping::empty());
with_error_checking_parse(source_str, &ps, |p| {
p.parse_item()
})
@ -62,7 +63,7 @@ pub fn string_to_item (source_str : String) -> Option<P<ast::Item>> {
/// Parse a string, return a stmt
pub fn string_to_stmt(source_str : String) -> Option<ast::Stmt> {
let ps = ParseSess::new();
let ps = ParseSess::new(FilePathMapping::empty());
with_error_checking_parse(source_str, &ps, |p| {
p.parse_stmt()
})
@ -71,7 +72,7 @@ pub fn string_to_stmt(source_str : String) -> Option<ast::Stmt> {
/// Parse a string, return a pat. Uses "irrefutable"... which doesn't
/// (currently) affect parsing.
pub fn string_to_pat(source_str: String) -> P<ast::Pat> {
let ps = ParseSess::new();
let ps = ParseSess::new(FilePathMapping::empty());
with_error_checking_parse(source_str, &ps, |p| {
p.parse_pat()
})

View File

@ -369,13 +369,14 @@ pub struct MultiByteChar {
}
/// A single source in the CodeMap.
#[derive(Clone)]
pub struct FileMap {
/// The name of the file that the source came from, source that doesn't
/// originate from files has names between angle brackets by convention,
/// e.g. `<anon>`
pub name: FileName,
/// The absolute path of the file that the source came from.
pub abs_path: Option<FileName>,
/// True if the `name` field above has been modified by -Zremap-path-prefix
pub name_was_remapped: bool,
/// The complete source code
pub src: Option<Rc<String>>,
/// The start position of this source in the CodeMap
@ -392,7 +393,7 @@ impl Encodable for FileMap {
fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
s.emit_struct("FileMap", 6, |s| {
s.emit_struct_field("name", 0, |s| self.name.encode(s))?;
s.emit_struct_field("abs_path", 1, |s| self.abs_path.encode(s))?;
s.emit_struct_field("name_was_remapped", 1, |s| self.name_was_remapped.encode(s))?;
s.emit_struct_field("start_pos", 2, |s| self.start_pos.encode(s))?;
s.emit_struct_field("end_pos", 3, |s| self.end_pos.encode(s))?;
s.emit_struct_field("lines", 4, |s| {
@ -453,8 +454,8 @@ impl Decodable for FileMap {
d.read_struct("FileMap", 6, |d| {
let name: String = d.read_struct_field("name", 0, |d| Decodable::decode(d))?;
let abs_path: Option<String> =
d.read_struct_field("abs_path", 1, |d| Decodable::decode(d))?;
let name_was_remapped: bool =
d.read_struct_field("name_was_remapped", 1, |d| Decodable::decode(d))?;
let start_pos: BytePos = d.read_struct_field("start_pos", 2, |d| Decodable::decode(d))?;
let end_pos: BytePos = d.read_struct_field("end_pos", 3, |d| Decodable::decode(d))?;
let lines: Vec<BytePos> = d.read_struct_field("lines", 4, |d| {
@ -489,7 +490,7 @@ impl Decodable for FileMap {
d.read_struct_field("multibyte_chars", 5, |d| Decodable::decode(d))?;
Ok(FileMap {
name: name,
abs_path: abs_path,
name_was_remapped: name_was_remapped,
start_pos: start_pos,
end_pos: end_pos,
src: None,

View File

@ -0,0 +1,18 @@
// Copyright 2017 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.
// ignore-tidy-linelength
// compile-flags: -g -Zremap-path-prefix-from={{cwd}} -Zremap-path-prefix-to=/the/aux-cwd -Zremap-path-prefix-from={{src-base}}/remap_path_prefix/auxiliary -Zremap-path-prefix-to=/the/aux-src
#[inline]
pub fn some_aux_function() -> i32 {
1234
}

View File

@ -0,0 +1,31 @@
// Copyright 2017 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.
// ignore-windows
// ignore-tidy-linelength
// compile-flags: -g -C no-prepopulate-passes -Zremap-path-prefix-from={{cwd}} -Zremap-path-prefix-to=/the/cwd -Zremap-path-prefix-from={{src-base}} -Zremap-path-prefix-to=/the/src
// aux-build:remap_path_prefix_aux.rs
extern crate remap_path_prefix_aux;
// Here we check that the expansion of the file!() macro is mapped.
// CHECK: internal constant [34 x i8] c"/the/src/remap_path_prefix/main.rs"
pub static FILE_PATH: &'static str = file!();
fn main() {
remap_path_prefix_aux::some_aux_function();
}
// Here we check that local debuginfo is mapped correctly.
// CHECK: !DIFile(filename: "/the/src/remap_path_prefix/main.rs", directory: "/the/cwd")
// And here that debuginfo from other crates are expanded to absolute paths.
// CHECK: !DIFile(filename: "/the/aux-src/remap_path_prefix_aux.rs", directory: "")

View File

@ -16,12 +16,13 @@ extern crate syntax;
extern crate syntax_pos;
use syntax::ast;
use syntax::codemap::FilePathMapping;
use syntax::print::pprust;
use syntax::symbol::Symbol;
use syntax_pos::DUMMY_SP;
fn main() {
let ps = syntax::parse::ParseSess::new();
let ps = syntax::parse::ParseSess::new(FilePathMapping::empty());
let mut resolver = syntax::ext::base::DummyResolver;
let mut cx = syntax::ext::base::ExtCtxt::new(
&ps,

View File

@ -24,7 +24,7 @@ use syntax::symbol::Symbol;
use syntax_pos::DUMMY_SP;
fn main() {
let ps = syntax::parse::ParseSess::new();
let ps = syntax::parse::ParseSess::new(codemap::FilePathMapping::empty());
let mut resolver = syntax::ext::base::DummyResolver;
let mut cx = syntax::ext::base::ExtCtxt::new(
&ps,

View File

@ -17,6 +17,7 @@ extern crate syntax;
use syntax::ast::*;
use syntax::attr::*;
use syntax::ast;
use syntax::codemap::FilePathMapping;
use syntax::parse;
use syntax::parse::{ParseSess, PResult};
use syntax::parse::new_parser_from_source_str;
@ -78,7 +79,7 @@ fn str_compare<T, F: Fn(&T) -> String>(e: &str, expected: &[T], actual: &[T], f:
}
fn check_expr_attrs(es: &str, expected: &[&str]) {
let ps = ParseSess::new();
let ps = ParseSess::new(FilePathMapping::empty());
let e = expr(es, &ps).expect("parse error");
let actual = &e.attrs;
str_compare(es,
@ -88,7 +89,7 @@ fn check_expr_attrs(es: &str, expected: &[&str]) {
}
fn check_stmt_attrs(es: &str, expected: &[&str]) {
let ps = ParseSess::new();
let ps = ParseSess::new(FilePathMapping::empty());
let e = stmt(es, &ps).expect("parse error");
let actual = e.node.attrs();
str_compare(es,
@ -98,7 +99,7 @@ fn check_stmt_attrs(es: &str, expected: &[&str]) {
}
fn reject_expr_parse(es: &str) {
let ps = ParseSess::new();
let ps = ParseSess::new(FilePathMapping::empty());
match expr(es, &ps) {
Ok(_) => panic!("parser did not reject `{}`", es),
Err(mut e) => e.cancel(),
@ -106,7 +107,7 @@ fn reject_expr_parse(es: &str) {
}
fn reject_stmt_parse(es: &str) {
let ps = ParseSess::new();
let ps = ParseSess::new(FilePathMapping::empty());
match stmt(es, &ps) {
Ok(_) => panic!("parser did not reject `{}`", es),
Err(mut e) => e.cancel(),

View File

@ -15,12 +15,13 @@
extern crate syntax;
extern crate syntax_pos;
use syntax::codemap::FilePathMapping;
use syntax::print::pprust::*;
use syntax::symbol::Symbol;
use syntax_pos::DUMMY_SP;
fn main() {
let ps = syntax::parse::ParseSess::new();
let ps = syntax::parse::ParseSess::new(FilePathMapping::empty());
let mut resolver = syntax::ext::base::DummyResolver;
let mut cx = syntax::ext::base::ExtCtxt::new(
&ps,

View File

@ -40,23 +40,24 @@ impl EarlyProps {
None,
&mut |ln| {
props.ignore =
props.ignore || parse_name_directive(ln, "ignore-test") ||
parse_name_directive(ln, &ignore_target(config)) ||
parse_name_directive(ln, &ignore_architecture(config)) ||
parse_name_directive(ln, &ignore_stage(config)) ||
parse_name_directive(ln, &ignore_env(config)) ||
(config.mode == common::Pretty && parse_name_directive(ln, "ignore-pretty")) ||
props.ignore || config.parse_name_directive(ln, "ignore-test") ||
config.parse_name_directive(ln, &ignore_target(config)) ||
config.parse_name_directive(ln, &ignore_architecture(config)) ||
config.parse_name_directive(ln, &ignore_stage(config)) ||
config.parse_name_directive(ln, &ignore_env(config)) ||
(config.mode == common::Pretty &&
config.parse_name_directive(ln, "ignore-pretty")) ||
(config.target != config.host &&
parse_name_directive(ln, "ignore-cross-compile")) ||
config.parse_name_directive(ln, "ignore-cross-compile")) ||
ignore_gdb(config, ln) ||
ignore_lldb(config, ln) ||
ignore_llvm(config, ln);
if let Some(s) = parse_aux_build(ln) {
if let Some(s) = config.parse_aux_build(ln) {
props.aux.push(s);
}
props.should_fail = props.should_fail || parse_name_directive(ln, "should-fail");
props.should_fail = props.should_fail || config.parse_name_directive(ln, "should-fail");
});
return props;
@ -80,7 +81,7 @@ impl EarlyProps {
}
if !line.contains("ignore-gdb-version") &&
parse_name_directive(line, "ignore-gdb") {
config.parse_name_directive(line, "ignore-gdb") {
return true;
}
@ -143,7 +144,7 @@ impl EarlyProps {
return false;
}
if parse_name_directive(line, "ignore-lldb") {
if config.parse_name_directive(line, "ignore-lldb") {
return true;
}
@ -260,19 +261,23 @@ impl TestProps {
}
}
pub fn from_aux_file(&self, testfile: &Path, cfg: Option<&str>) -> Self {
pub fn from_aux_file(&self,
testfile: &Path,
cfg: Option<&str>,
config: &Config)
-> Self {
let mut props = TestProps::new();
// copy over select properties to the aux build:
props.incremental_dir = self.incremental_dir.clone();
props.load_from(testfile, cfg);
props.load_from(testfile, cfg, config);
props
}
pub fn from_file(testfile: &Path) -> Self {
pub fn from_file(testfile: &Path, config: &Config) -> Self {
let mut props = TestProps::new();
props.load_from(testfile, None);
props.load_from(testfile, None, config);
props
}
@ -280,85 +285,88 @@ impl TestProps {
/// tied to a particular revision `foo` (indicated by writing
/// `//[foo]`), then the property is ignored unless `cfg` is
/// `Some("foo")`.
pub fn load_from(&mut self, testfile: &Path, cfg: Option<&str>) {
pub fn load_from(&mut self,
testfile: &Path,
cfg: Option<&str>,
config: &Config) {
iter_header(testfile,
cfg,
&mut |ln| {
if let Some(ep) = parse_error_pattern(ln) {
if let Some(ep) = config.parse_error_pattern(ln) {
self.error_patterns.push(ep);
}
if let Some(flags) = parse_compile_flags(ln) {
if let Some(flags) = config.parse_compile_flags(ln) {
self.compile_flags.extend(flags.split_whitespace()
.map(|s| s.to_owned()));
}
if let Some(r) = parse_revisions(ln) {
if let Some(r) = config.parse_revisions(ln) {
self.revisions.extend(r);
}
if self.run_flags.is_none() {
self.run_flags = parse_run_flags(ln);
self.run_flags = config.parse_run_flags(ln);
}
if self.pp_exact.is_none() {
self.pp_exact = parse_pp_exact(ln, testfile);
self.pp_exact = config.parse_pp_exact(ln, testfile);
}
if !self.build_aux_docs {
self.build_aux_docs = parse_build_aux_docs(ln);
self.build_aux_docs = config.parse_build_aux_docs(ln);
}
if !self.force_host {
self.force_host = parse_force_host(ln);
self.force_host = config.parse_force_host(ln);
}
if !self.check_stdout {
self.check_stdout = parse_check_stdout(ln);
self.check_stdout = config.parse_check_stdout(ln);
}
if !self.no_prefer_dynamic {
self.no_prefer_dynamic = parse_no_prefer_dynamic(ln);
self.no_prefer_dynamic = config.parse_no_prefer_dynamic(ln);
}
if !self.pretty_expanded {
self.pretty_expanded = parse_pretty_expanded(ln);
self.pretty_expanded = config.parse_pretty_expanded(ln);
}
if let Some(m) = parse_pretty_mode(ln) {
if let Some(m) = config.parse_pretty_mode(ln) {
self.pretty_mode = m;
}
if !self.pretty_compare_only {
self.pretty_compare_only = parse_pretty_compare_only(ln);
self.pretty_compare_only = config.parse_pretty_compare_only(ln);
}
if let Some(ab) = parse_aux_build(ln) {
if let Some(ab) = config.parse_aux_build(ln) {
self.aux_builds.push(ab);
}
if let Some(ee) = parse_env(ln, "exec-env") {
if let Some(ee) = config.parse_env(ln, "exec-env") {
self.exec_env.push(ee);
}
if let Some(ee) = parse_env(ln, "rustc-env") {
if let Some(ee) = config.parse_env(ln, "rustc-env") {
self.rustc_env.push(ee);
}
if let Some(cl) = parse_check_line(ln) {
if let Some(cl) = config.parse_check_line(ln) {
self.check_lines.push(cl);
}
if let Some(of) = parse_forbid_output(ln) {
if let Some(of) = config.parse_forbid_output(ln) {
self.forbid_output.push(of);
}
if !self.must_compile_successfully {
self.must_compile_successfully = parse_must_compile_successfully(ln);
self.must_compile_successfully = config.parse_must_compile_successfully(ln);
}
if !self.check_test_line_numbers_match {
self.check_test_line_numbers_match = parse_check_test_line_numbers_match(ln);
self.check_test_line_numbers_match = config.parse_check_test_line_numbers_match(ln);
}
});
@ -410,117 +418,121 @@ fn iter_header(testfile: &Path, cfg: Option<&str>, it: &mut FnMut(&str)) {
return;
}
fn parse_error_pattern(line: &str) -> Option<String> {
parse_name_value_directive(line, "error-pattern")
}
impl Config {
fn parse_forbid_output(line: &str) -> Option<String> {
parse_name_value_directive(line, "forbid-output")
}
fn parse_error_pattern(&self, line: &str) -> Option<String> {
self.parse_name_value_directive(line, "error-pattern")
}
fn parse_aux_build(line: &str) -> Option<String> {
parse_name_value_directive(line, "aux-build")
}
fn parse_forbid_output(&self, line: &str) -> Option<String> {
self.parse_name_value_directive(line, "forbid-output")
}
fn parse_compile_flags(line: &str) -> Option<String> {
parse_name_value_directive(line, "compile-flags")
}
fn parse_aux_build(&self, line: &str) -> Option<String> {
self.parse_name_value_directive(line, "aux-build")
}
fn parse_revisions(line: &str) -> Option<Vec<String>> {
parse_name_value_directive(line, "revisions")
.map(|r| r.split_whitespace().map(|t| t.to_string()).collect())
}
fn parse_compile_flags(&self, line: &str) -> Option<String> {
self.parse_name_value_directive(line, "compile-flags")
}
fn parse_run_flags(line: &str) -> Option<String> {
parse_name_value_directive(line, "run-flags")
}
fn parse_revisions(&self, line: &str) -> Option<Vec<String>> {
self.parse_name_value_directive(line, "revisions")
.map(|r| r.split_whitespace().map(|t| t.to_string()).collect())
}
fn parse_check_line(line: &str) -> Option<String> {
parse_name_value_directive(line, "check")
}
fn parse_run_flags(&self, line: &str) -> Option<String> {
self.parse_name_value_directive(line, "run-flags")
}
fn parse_force_host(line: &str) -> bool {
parse_name_directive(line, "force-host")
}
fn parse_check_line(&self, line: &str) -> Option<String> {
self.parse_name_value_directive(line, "check")
}
fn parse_build_aux_docs(line: &str) -> bool {
parse_name_directive(line, "build-aux-docs")
}
fn parse_force_host(&self, line: &str) -> bool {
self.parse_name_directive(line, "force-host")
}
fn parse_check_stdout(line: &str) -> bool {
parse_name_directive(line, "check-stdout")
}
fn parse_build_aux_docs(&self, line: &str) -> bool {
self.parse_name_directive(line, "build-aux-docs")
}
fn parse_no_prefer_dynamic(line: &str) -> bool {
parse_name_directive(line, "no-prefer-dynamic")
}
fn parse_check_stdout(&self, line: &str) -> bool {
self.parse_name_directive(line, "check-stdout")
}
fn parse_pretty_expanded(line: &str) -> bool {
parse_name_directive(line, "pretty-expanded")
}
fn parse_no_prefer_dynamic(&self, line: &str) -> bool {
self.parse_name_directive(line, "no-prefer-dynamic")
}
fn parse_pretty_mode(line: &str) -> Option<String> {
parse_name_value_directive(line, "pretty-mode")
}
fn parse_pretty_expanded(&self, line: &str) -> bool {
self.parse_name_directive(line, "pretty-expanded")
}
fn parse_pretty_compare_only(line: &str) -> bool {
parse_name_directive(line, "pretty-compare-only")
}
fn parse_pretty_mode(&self, line: &str) -> Option<String> {
self.parse_name_value_directive(line, "pretty-mode")
}
fn parse_must_compile_successfully(line: &str) -> bool {
parse_name_directive(line, "must-compile-successfully")
}
fn parse_pretty_compare_only(&self, line: &str) -> bool {
self.parse_name_directive(line, "pretty-compare-only")
}
fn parse_check_test_line_numbers_match(line: &str) -> bool {
parse_name_directive(line, "check-test-line-numbers-match")
}
fn parse_must_compile_successfully(&self, line: &str) -> bool {
self.parse_name_directive(line, "must-compile-successfully")
}
fn parse_env(line: &str, name: &str) -> Option<(String, String)> {
parse_name_value_directive(line, name).map(|nv| {
// nv is either FOO or FOO=BAR
let mut strs: Vec<String> = nv.splitn(2, '=')
.map(str::to_owned)
.collect();
fn parse_check_test_line_numbers_match(&self, line: &str) -> bool {
self.parse_name_directive(line, "check-test-line-numbers-match")
}
match strs.len() {
1 => (strs.pop().unwrap(), "".to_owned()),
2 => {
let end = strs.pop().unwrap();
(strs.pop().unwrap(), end)
fn parse_env(&self, line: &str, name: &str) -> Option<(String, String)> {
self.parse_name_value_directive(line, name).map(|nv| {
// nv is either FOO or FOO=BAR
let mut strs: Vec<String> = nv.splitn(2, '=')
.map(str::to_owned)
.collect();
match strs.len() {
1 => (strs.pop().unwrap(), "".to_owned()),
2 => {
let end = strs.pop().unwrap();
(strs.pop().unwrap(), end)
}
n => panic!("Expected 1 or 2 strings, not {}", n),
}
n => panic!("Expected 1 or 2 strings, not {}", n),
}
})
}
})
}
fn parse_pp_exact(line: &str, testfile: &Path) -> Option<PathBuf> {
if let Some(s) = parse_name_value_directive(line, "pp-exact") {
Some(PathBuf::from(&s))
} else {
if parse_name_directive(line, "pp-exact") {
testfile.file_name().map(PathBuf::from)
fn parse_pp_exact(&self, line: &str, testfile: &Path) -> Option<PathBuf> {
if let Some(s) = self.parse_name_value_directive(line, "pp-exact") {
Some(PathBuf::from(&s))
} else {
if self.parse_name_directive(line, "pp-exact") {
testfile.file_name().map(PathBuf::from)
} else {
None
}
}
}
fn parse_name_directive(&self, line: &str, directive: &str) -> bool {
// This 'no-' rule is a quick hack to allow pretty-expanded and
// no-pretty-expanded to coexist
line.contains(directive) && !line.contains(&("no-".to_owned() + directive))
}
pub fn parse_name_value_directive(&self, line: &str, directive: &str) -> Option<String> {
let keycolon = format!("{}:", directive);
if let Some(colon) = line.find(&keycolon) {
let value = line[(colon + keycolon.len())..line.len()].to_owned();
debug!("{}: {}", directive, value);
Some(expand_variables(value, self))
} else {
None
}
}
}
fn parse_name_directive(line: &str, directive: &str) -> bool {
// This 'no-' rule is a quick hack to allow pretty-expanded and no-pretty-expanded to coexist
line.contains(directive) && !line.contains(&("no-".to_owned() + directive))
}
pub fn parse_name_value_directive(line: &str, directive: &str) -> Option<String> {
let keycolon = format!("{}:", directive);
if let Some(colon) = line.find(&keycolon) {
let value = line[(colon + keycolon.len())..line.len()].to_owned();
debug!("{}: {}", directive, value);
Some(value)
} else {
None
}
}
pub fn lldb_version_to_int(version_string: &str) -> isize {
let error_string = format!("Encountered LLDB version string with unexpected format: {}",
version_string);
@ -528,3 +540,24 @@ pub fn lldb_version_to_int(version_string: &str) -> isize {
let major: isize = version_string.parse().ok().expect(&error_string);
return major;
}
fn expand_variables(mut value: String, config: &Config) -> String {
const CWD: &'static str = "{{cwd}}";
const SRC_BASE: &'static str = "{{src-base}}";
const BUILD_BASE: &'static str = "{{build-base}}";
if value.contains(CWD) {
let cwd = env::current_dir().unwrap();
value = value.replace(CWD, &cwd.to_string_lossy());
}
if value.contains(SRC_BASE) {
value = value.replace(SRC_BASE, &config.src_base.to_string_lossy());
}
if value.contains(BUILD_BASE) {
value = value.replace(BUILD_BASE, &config.build_base.to_string_lossy());
}
value
}

View File

@ -16,7 +16,6 @@ use errors::{self, ErrorKind, Error};
use filetime::FileTime;
use json;
use header::TestProps;
use header;
use procsrv;
use test::TestPaths;
use uidiff;
@ -57,7 +56,7 @@ pub fn run(config: Config, testpaths: &TestPaths) {
print!("\n\n");
}
debug!("running {:?}", testpaths.file.display());
let base_props = TestProps::from_file(&testpaths.file);
let base_props = TestProps::from_file(&testpaths.file, &config);
let base_cx = TestCx { config: &config,
props: &base_props,
@ -70,7 +69,7 @@ pub fn run(config: Config, testpaths: &TestPaths) {
} else {
for revision in &base_props.revisions {
let mut revision_props = base_props.clone();
revision_props.load_from(&testpaths.file, Some(&revision));
revision_props.load_from(&testpaths.file, Some(&revision), &config);
let rev_cx = TestCx {
config: &config,
props: &revision_props,
@ -867,13 +866,13 @@ actual:\n\
}
for &(ref command_directive, ref check_directive) in &directives {
header::parse_name_value_directive(
self.config.parse_name_value_directive(
&line,
&command_directive).map(|cmd| {
commands.push(cmd)
});
header::parse_name_value_directive(
self.config.parse_name_value_directive(
&line,
&check_directive).map(|cmd| {
check_lines.push(cmd)
@ -1158,7 +1157,9 @@ actual:\n\
if self.props.build_aux_docs {
for rel_ab in &self.props.aux_builds {
let aux_testpaths = self.compute_aux_test_paths(rel_ab);
let aux_props = self.props.from_aux_file(&aux_testpaths.file, self.revision);
let aux_props = self.props.from_aux_file(&aux_testpaths.file,
self.revision,
self.config);
let aux_cx = TestCx {
config: self.config,
props: &aux_props,
@ -1279,7 +1280,9 @@ actual:\n\
for rel_ab in &self.props.aux_builds {
let aux_testpaths = self.compute_aux_test_paths(rel_ab);
let aux_props = self.props.from_aux_file(&aux_testpaths.file, self.revision);
let aux_props = self.props.from_aux_file(&aux_testpaths.file,
self.revision,
self.config);
let mut crate_type = if aux_props.no_prefer_dynamic {
Vec::new()
} else {