use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::stable_hasher::StableHasher;
use rustc_data_structures::sync::{AtomicU32, Lrc, MappedReadGuard, ReadGuard, RwLock};
-use std::cmp;
-use std::convert::TryFrom;
use std::hash::Hash;
use std::path::{Path, PathBuf};
use std::sync::atomic::Ordering;
+use std::{clone::Clone, cmp};
+use std::{convert::TryFrom, unreachable};
use std::fs;
use std::io;
// StableSourceFileId, perhaps built atop source_file.name_hash.
impl StableSourceFileId {
pub fn new(source_file: &SourceFile) -> StableSourceFileId {
- StableSourceFileId::new_from_pieces(
- &source_file.name,
- source_file.name_was_remapped,
- source_file.unmapped_path.as_ref(),
- )
+ StableSourceFileId::new_from_name(&source_file.name)
}
- fn new_from_pieces(
- name: &FileName,
- name_was_remapped: bool,
- unmapped_path: Option<&FileName>,
- ) -> StableSourceFileId {
+ fn new_from_name(name: &FileName) -> StableSourceFileId {
let mut hasher = StableHasher::new();
- if let FileName::Real(real_name) = name {
- // rust-lang/rust#70924: Use the stable (virtualized) name when
- // available. (We do not want artifacts from transient file system
- // paths for libstd to leak into our build artifacts.)
- real_name.stable_name().hash(&mut hasher)
- } else {
- name.hash(&mut hasher);
- }
- name_was_remapped.hash(&mut hasher);
- unmapped_path.hash(&mut hasher);
+ name.hash(&mut hasher);
StableSourceFileId(hasher.finish())
}
fn try_new_source_file(
&self,
- mut filename: FileName,
+ filename: FileName,
src: String,
) -> Result<Lrc<SourceFile>, OffsetOverflowError> {
- // The path is used to determine the directory for loading submodules and
- // include files, so it must be before remapping.
// Note that filename may not be a valid path, eg it may be `<anon>` etc,
// but this is okay because the directory determined by `path.pop()` will
// be empty, so the working directory will be used.
- let unmapped_path = filename.clone();
-
- let was_remapped;
- if let FileName::Real(real_filename) = &mut filename {
- match real_filename {
- RealFileName::Named(path_to_be_remapped)
- | RealFileName::Devirtualized {
- local_path: path_to_be_remapped,
- virtual_name: _,
- } => {
- let mapped = self.path_mapping.map_prefix(path_to_be_remapped.clone());
- was_remapped = mapped.1;
- *path_to_be_remapped = mapped.0;
- }
- }
- } else {
- was_remapped = false;
- }
+ let (filename, _) = self.path_mapping.map_filename_prefix(&filename);
- let file_id =
- StableSourceFileId::new_from_pieces(&filename, was_remapped, Some(&unmapped_path));
+ let file_id = StableSourceFileId::new_from_name(&filename);
let lrc_sf = match self.source_file_by_stable_id(file_id) {
Some(lrc_sf) => lrc_sf,
let source_file = Lrc::new(SourceFile::new(
filename,
- was_remapped,
- unmapped_path,
src,
Pos::from_usize(start_pos),
self.hash_kind,
pub fn new_imported_source_file(
&self,
filename: FileName,
- name_was_remapped: bool,
src_hash: SourceFileHash,
name_hash: u128,
source_len: usize,
let source_file = Lrc::new(SourceFile {
name: filename,
- name_was_remapped,
- unmapped_path: None,
src: None,
src_hash,
external_src: Lock::new(ExternalSource::Foreign {
source_file
}
- pub fn mk_substr_filename(&self, sp: Span) -> String {
- let pos = self.lookup_char_pos(sp.lo());
- format!("<{}:{}:{}>", pos.file.name, pos.line, pos.col.to_usize() + 1)
- }
-
// If there is a doctest offset, applies it to the line.
pub fn doctest_offset_line(&self, file: &FileName, orig: usize) -> usize {
match file {
}
}
- /// Returns `Some(span)`, a union of the LHS and RHS span. The LHS must precede the RHS. If
- /// there are gaps between LHS and RHS, the resulting union will cross these gaps.
- /// For this to work,
- ///
- /// * the syntax contexts of both spans much match,
- /// * the LHS span needs to end on the same line the RHS span begins,
- /// * the LHS span must start at or before the RHS span.
- pub fn merge_spans(&self, sp_lhs: Span, sp_rhs: Span) -> Option<Span> {
- // Ensure we're at the same expansion ID.
- if sp_lhs.ctxt() != sp_rhs.ctxt() {
- return None;
- }
-
- let lhs_end = match self.lookup_line(sp_lhs.hi()) {
- Ok(x) => x,
- Err(_) => return None,
- };
- let rhs_begin = match self.lookup_line(sp_rhs.lo()) {
- Ok(x) => x,
- Err(_) => return None,
- };
-
- // If we must cross lines to merge, don't merge.
- if lhs_end.line != rhs_begin.line {
- return None;
- }
-
- // Ensure these follow the expected order and that we don't overlap.
- if (sp_lhs.lo() <= sp_rhs.lo()) && (sp_lhs.hi() <= sp_rhs.lo()) {
- Some(sp_lhs.to(sp_rhs))
- } else {
- None
- }
- }
-
pub fn span_to_string(&self, sp: Span) -> String {
if self.files.borrow().source_files.is_empty() && sp.is_dummy() {
return "no-location".to_string();
let hi = self.lookup_char_pos(sp.hi());
format!(
"{}:{}:{}: {}:{}",
- lo.file.name,
+ lo.file.name.prefer_remapped(),
lo.line,
lo.col.to_usize() + 1,
hi.line,
self.lookup_char_pos(sp.lo()).file.name.clone()
}
- pub fn span_to_unmapped_path(&self, sp: Span) -> FileName {
- self.lookup_char_pos(sp.lo())
- .file
- .unmapped_path
- .clone()
- .expect("`SourceMap::span_to_unmapped_path` called for imported `SourceFile`?")
- }
-
pub fn is_multiline(&self, sp: Span) -> bool {
let lo = self.lookup_char_pos(sp.lo());
let hi = self.lookup_char_pos(sp.hi());
SourceFileAndBytePos { sf, pos: offset }
}
- /// Converts an absolute `BytePos` to a `CharPos` relative to the `SourceFile`.
- pub fn bytepos_to_file_charpos(&self, bpos: BytePos) -> CharPos {
- let idx = self.lookup_source_file_idx(bpos);
- let sf = &(*self.files.borrow().source_files)[idx];
- sf.bytepos_to_file_charpos(bpos)
- }
-
// Returns the index of the `SourceFile` (in `self.files`) that contains `pos`.
// This index is guaranteed to be valid for the lifetime of this `SourceMap`,
// since `source_files` is a `MonotonicVec`
}
pub fn ensure_source_file_source_present(&self, source_file: Lrc<SourceFile>) -> bool {
source_file.add_external_src(|| match source_file.name {
- FileName::Real(ref name) => self.file_loader.read_file(name.local_path()).ok(),
+ FileName::Real(ref name) => {
+ if let Some(local_path) = name.local_path() {
+ self.file_loader.read_file(local_path).ok()
+ } else {
+ None
+ }
+ }
_ => None,
})
}
fn map_filename_prefix(&self, file: &FileName) -> (FileName, bool) {
match file {
FileName::Real(realfile) => {
- let path = realfile.local_path();
- let (path, mapped) = self.map_prefix(path.to_path_buf());
- (FileName::Real(RealFileName::Named(path)), mapped)
+ if let RealFileName::LocalPath(local_path) = realfile {
+ let (mapped_path, mapped) = self.map_prefix(local_path.to_path_buf());
+ let realfile = if mapped {
+ RealFileName::Remapped {
+ local_path: Some(local_path.clone()),
+ virtual_name: mapped_path,
+ }
+ } else {
+ realfile.clone()
+ };
+ (FileName::Real(realfile), mapped)
+ } else {
+ unreachable!("attempted to remap an already remapped filename");
+ }
}
other => (other.clone(), false),
}