From 583880b0ff3a04712e66426d63b7474dc74c2165 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 5 May 2022 17:03:51 +0200 Subject: [PATCH] Move logic for making potentially remapped paths absolute into helper method. --- compiler/rustc_metadata/src/rmeta/encoder.rs | 93 ++++++-------------- compiler/rustc_span/src/source_map.rs | 79 +++++++++++++++++ 2 files changed, 108 insertions(+), 64 deletions(-) diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 39e6ddb316d..a382209e206 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -33,18 +33,14 @@ use rustc_serialize::{opaque, Encodable, Encoder}; use rustc_session::config::CrateType; use rustc_session::cstore::{ForeignModule, LinkagePreference, NativeLib}; +use rustc_span::hygiene::{ExpnIndex, HygieneEncodeContext, MacroKind}; use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::{ self, DebuggerVisualizerFile, ExternalSource, FileName, SourceFile, Span, SyntaxContext, }; -use rustc_span::{ - hygiene::{ExpnIndex, HygieneEncodeContext, MacroKind}, - RealFileName, -}; use rustc_target::abi::VariantIdx; use std::hash::Hash; use std::num::NonZeroUsize; -use std::path::Path; use tracing::{debug, trace}; pub(super) struct EncodeContext<'a, 'tcx> { @@ -490,6 +486,8 @@ fn encode_source_map(&mut self) -> Lazy<[rustc_span::SourceFile]> { // is done. let required_source_files = self.required_source_files.take().unwrap(); + let working_directory = &self.tcx.sess.opts.working_dir; + let adapted = all_source_files .iter() .enumerate() @@ -502,66 +500,33 @@ fn encode_source_map(&mut self) -> Lazy<[rustc_span::SourceFile]> { (!source_file.is_imported() || self.is_proc_macro) }) .map(|(_, source_file)| { - let mut adapted = match source_file.name { - FileName::Real(ref realname) => { - let mut adapted = (**source_file).clone(); - adapted.name = FileName::Real(match realname { - RealFileName::LocalPath(path_to_file) => { - // Prepend path of working directory onto potentially - // relative paths, because they could become relative - // to a wrong directory. - // We include `working_dir` as part of the crate hash, - // so it's okay for us to use it as part of the encoded - // metadata. - let working_dir = &self.tcx.sess.opts.working_dir; - match working_dir { - RealFileName::LocalPath(absolute) => { - // Although neither working_dir or the file name were subject - // to path remapping, the concatenation between the two may - // be. Hence we need to do a remapping here. - let joined = Path::new(absolute).join(path_to_file); - let (joined, remapped) = - source_map.path_mapping().map_prefix(joined); - if remapped { - RealFileName::Remapped { - local_path: None, - virtual_name: joined, - } - } else { - RealFileName::LocalPath(joined) - } - } - RealFileName::Remapped { local_path: _, virtual_name } => { - // If working_dir has been remapped, then we emit - // Remapped variant as the expanded path won't be valid - RealFileName::Remapped { - local_path: None, - virtual_name: Path::new(virtual_name) - .join(path_to_file), - } - } - } - } - RealFileName::Remapped { local_path: _, virtual_name } => { - RealFileName::Remapped { - // We do not want any local path to be exported into metadata - local_path: None, - virtual_name: virtual_name.clone(), - } - } - }); - adapted.name_hash = { - let mut hasher: StableHasher = StableHasher::new(); - adapted.name.hash(&mut hasher); - hasher.finish::() - }; - Lrc::new(adapted) - } + match source_file.name { + FileName::Real(ref original_file_name) => { + let adapted_file_name = + source_map.path_mapping().to_embeddable_absolute_path( + original_file_name.clone(), + working_directory, + ); + if adapted_file_name != *original_file_name { + let mut adapted: SourceFile = (**source_file).clone(); + adapted.name = FileName::Real(adapted_file_name); + adapted.name_hash = { + let mut hasher: StableHasher = StableHasher::new(); + adapted.name.hash(&mut hasher); + hasher.finish::() + }; + Lrc::new(adapted) + } else { + // Nothing to adapt + source_file.clone() + } + } // expanded code, not from a file _ => source_file.clone(), - }; - + } + }) + .map(|mut source_file| { // We're serializing this `SourceFile` into our crate metadata, // so mark it as coming from this crate. // This also ensures that we don't try to deserialize the @@ -569,9 +534,9 @@ fn encode_source_map(&mut self) -> Lazy<[rustc_span::SourceFile]> { // dependencies aren't loaded when we deserialize a proc-macro, // trying to remap the `CrateNum` would fail. if self.is_proc_macro { - Lrc::make_mut(&mut adapted).cnum = LOCAL_CRATE; + Lrc::make_mut(&mut source_file).cnum = LOCAL_CRATE; } - adapted + source_file }) .collect::>(); diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index 03e82dde967..44aa9f72809 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -1155,4 +1155,83 @@ fn map_filename_prefix(&self, file: &FileName) -> (FileName, bool) { other => (other.clone(), false), } } + + /// Expand a relative path to an absolute path with remapping taken into account. + /// Use this when absolute paths are required (e.g. debuginfo or crate metadata). + /// + /// The resulting `RealFileName` will have its `local_path` portion erased if + /// possible (i.e. if there's also a remapped path). + pub fn to_embeddable_absolute_path( + &self, + file_path: RealFileName, + working_directory: &RealFileName, + ) -> RealFileName { + match file_path { + // Anything that's already remapped we don't modify, except for erasing + // the `local_path` portion. + RealFileName::Remapped { local_path: _, virtual_name } => { + RealFileName::Remapped { + // We do not want any local path to be exported into metadata + local_path: None, + // We use the remapped name verbatim, even if it looks like a relative + // path. The assumption is that the user doesn't want us to further + // process paths that have gone through remapping. + virtual_name, + } + } + + RealFileName::LocalPath(unmapped_file_path) => { + // If no remapping has been applied yet, try to do so + let (new_path, was_remapped) = self.map_prefix(unmapped_file_path); + if was_remapped { + // It was remapped, so don't modify further + return RealFileName::Remapped { local_path: None, virtual_name: new_path }; + } + + if new_path.is_absolute() { + // No remapping has applied to this path and it is absolute, + // so the working directory cannot influence it either, so + // we are done. + return RealFileName::LocalPath(new_path); + } + + debug_assert!(new_path.is_relative()); + let unmapped_file_path_rel = new_path; + + match working_directory { + RealFileName::LocalPath(unmapped_working_dir_abs) => { + let file_path_abs = unmapped_working_dir_abs.join(unmapped_file_path_rel); + + // Although neither `working_directory` nor the file name were subject + // to path remapping, the concatenation between the two may be. Hence + // we need to do a remapping here. + let (file_path_abs, was_remapped) = self.map_prefix(file_path_abs); + if was_remapped { + RealFileName::Remapped { + // Erase the actual path + local_path: None, + virtual_name: file_path_abs, + } + } else { + // No kind of remapping applied to this path, so + // we leave it as it is. + RealFileName::LocalPath(file_path_abs) + } + } + RealFileName::Remapped { + local_path: _, + virtual_name: remapped_working_dir_abs, + } => { + // If working_directory has been remapped, then we emit + // Remapped variant as the expanded path won't be valid + RealFileName::Remapped { + local_path: None, + virtual_name: Path::new(remapped_working_dir_abs) + .join(unmapped_file_path_rel), + } + } + } + } + } + } }