Auto merge of #115507 - cjgillot:relative-source-file, r=oli-obk

Use relative positions inside a SourceFile.

This allows to remove the normalization of start positions for hashing, and simplify allocation of global address space.

cc `@Zoxc`
This commit is contained in:
bors 2023-09-05 21:03:56 +00:00
commit a991861ec9
20 changed files with 260 additions and 369 deletions

View File

@ -82,12 +82,9 @@ impl DebugContext {
match tcx.sess.source_map().lookup_line(span.lo()) {
Ok(SourceFileAndLine { sf: file, line }) => {
let line_pos = file.lines(|lines| lines[line]);
let col = file.relative_position(span.lo()) - line_pos;
(
file,
u64::try_from(line).unwrap() + 1,
u64::from((span.lo() - line_pos).to_u32()) + 1,
)
(file, u64::try_from(line).unwrap() + 1, u64::from(col.to_u32()) + 1)
}
Err(file) => (file, 0, 0),
}

View File

@ -68,7 +68,7 @@ fn make_mir_scope<'ll, 'tcx>(
let file = cx.sess().source_map().lookup_source_file(mir.span.lo());
debug_context.scopes[scope] = DebugScope {
file_start_pos: file.start_pos,
file_end_pos: file.end_pos,
file_end_pos: file.end_position(),
..debug_context.scopes[scope]
};
instantiated.insert(scope);
@ -120,7 +120,7 @@ fn make_mir_scope<'ll, 'tcx>(
dbg_scope,
inlined_at: inlined_at.or(parent_scope.inlined_at),
file_start_pos: loc.file.start_pos,
file_end_pos: loc.file.end_pos,
file_end_pos: loc.file.end_position(),
};
instantiated.insert(scope);
}

View File

@ -267,7 +267,7 @@ impl CodegenCx<'_, '_> {
// Use 1-based indexing.
let line = (line + 1) as u32;
let col = (pos - line_pos).to_u32() + 1;
let col = (file.relative_position(pos) - line_pos).to_u32() + 1;
(file, line, col)
}

View File

@ -1501,11 +1501,12 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
// We can't reuse an existing SourceFile, so allocate a new one
// containing the information we need.
let original_end_pos = source_file_to_import.end_position();
let rustc_span::SourceFile {
mut name,
src_hash,
start_pos,
end_pos,
start_pos: original_start_pos,
source_len,
lines,
multibyte_chars,
non_narrow_chars,
@ -1547,35 +1548,32 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
// on `try_to_translate_virtual_to_real`).
try_to_translate_virtual_to_real(&mut name);
let source_length = (end_pos - start_pos).to_usize();
let local_version = sess.source_map().new_imported_source_file(
name,
src_hash,
name_hash,
source_length,
source_len.to_u32(),
self.cnum,
lines,
multibyte_chars,
non_narrow_chars,
normalized_pos,
start_pos,
source_file_index,
);
debug!(
"CrateMetaData::imported_source_files alloc \
source_file {:?} original (start_pos {:?} end_pos {:?}) \
translated (start_pos {:?} end_pos {:?})",
source_file {:?} original (start_pos {:?} source_len {:?}) \
translated (start_pos {:?} source_len {:?})",
local_version.name,
start_pos,
end_pos,
original_start_pos,
source_len,
local_version.start_pos,
local_version.end_pos
local_version.source_len
);
ImportedSourceFile {
original_start_pos: start_pos,
original_end_pos: end_pos,
original_start_pos,
original_end_pos,
translated_source_file: local_version,
}
})

View File

@ -22,7 +22,7 @@ use rustc_span::hygiene::{
ExpnId, HygieneDecodeContext, HygieneEncodeContext, SyntaxContext, SyntaxContextData,
};
use rustc_span::source_map::{SourceMap, StableSourceFileId};
use rustc_span::{BytePos, ExpnData, ExpnHash, Pos, SourceFile, Span};
use rustc_span::{BytePos, ExpnData, ExpnHash, Pos, RelativeBytePos, SourceFile, Span};
use rustc_span::{CachingSourceMapView, Symbol};
use std::collections::hash_map::Entry;
use std::io;
@ -688,11 +688,12 @@ impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for Span {
let file_lo_index = SourceFileIndex::decode(decoder);
let line_lo = usize::decode(decoder);
let col_lo = BytePos::decode(decoder);
let col_lo = RelativeBytePos::decode(decoder);
let len = BytePos::decode(decoder);
let file_lo = decoder.file_index_to_file(file_lo_index);
let lo = file_lo.lines(|lines| lines[line_lo - 1] + col_lo);
let lo = file_lo.absolute_position(lo);
let hi = lo + len;
Span::new(lo, hi, ctxt, parent)

View File

@ -28,7 +28,7 @@ use rustc_middle::mir::{
use rustc_middle::ty::TyCtxt;
use rustc_span::def_id::DefId;
use rustc_span::source_map::SourceMap;
use rustc_span::{CharPos, ExpnKind, Pos, SourceFile, Span, Symbol};
use rustc_span::{ExpnKind, SourceFile, Span, Symbol};
/// A simple error message wrapper for `coverage::Error`s.
#[derive(Debug)]
@ -314,8 +314,7 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
};
graphviz_data.add_bcb_coverage_span_with_counter(bcb, &covspan, &counter_kind);
let code_region =
make_code_region(source_map, file_name, &self.source_file, span, body_span);
let code_region = make_code_region(source_map, file_name, span, body_span);
inject_statement(
self.mir_body,
@ -510,40 +509,36 @@ fn inject_intermediate_expression(mir_body: &mut mir::Body<'_>, expression: Cove
fn make_code_region(
source_map: &SourceMap,
file_name: Symbol,
source_file: &Lrc<SourceFile>,
span: Span,
body_span: Span,
) -> CodeRegion {
debug!(
"Called make_code_region(file_name={}, source_file={:?}, span={}, body_span={})",
"Called make_code_region(file_name={}, span={}, body_span={})",
file_name,
source_file,
source_map.span_to_diagnostic_string(span),
source_map.span_to_diagnostic_string(body_span)
);
let (start_line, mut start_col) = source_file.lookup_file_pos(span.lo());
let (end_line, end_col) = if span.hi() == span.lo() {
let (end_line, mut end_col) = (start_line, start_col);
let (file, mut start_line, mut start_col, mut end_line, mut end_col) =
source_map.span_to_location_info(span);
if span.hi() == span.lo() {
// Extend an empty span by one character so the region will be counted.
let CharPos(char_pos) = start_col;
if span.hi() == body_span.hi() {
start_col = CharPos(char_pos.saturating_sub(1));
start_col = start_col.saturating_sub(1);
} else {
end_col = CharPos(char_pos + 1);
end_col = start_col + 1;
}
(end_line, end_col)
} else {
source_file.lookup_file_pos(span.hi())
};
let start_line = source_map.doctest_offset_line(&source_file.name, start_line);
let end_line = source_map.doctest_offset_line(&source_file.name, end_line);
if let Some(file) = file {
start_line = source_map.doctest_offset_line(&file.name, start_line);
end_line = source_map.doctest_offset_line(&file.name, end_line);
}
CodeRegion {
file_name,
start_line: start_line as u32,
start_col: start_col.to_u32() + 1,
start_col: start_col as u32,
end_line: end_line as u32,
end_col: end_col.to_u32() + 1,
end_col: end_col as u32,
}
}

View File

@ -132,7 +132,7 @@ fn maybe_source_file_to_parser(
sess: &ParseSess,
source_file: Lrc<SourceFile>,
) -> Result<Parser<'_>, Vec<Diagnostic>> {
let end_pos = source_file.end_pos;
let end_pos = source_file.end_position();
let stream = maybe_file_to_stream(sess, source_file, None)?;
let mut parser = stream_to_parser(sess, stream, None);
if parser.token == token::Eof {

View File

@ -5,7 +5,7 @@ use crate::ich::StableHashingContext;
use rustc_ast as ast;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_span::{BytePos, NormalizedPos, SourceFile};
use rustc_span::SourceFile;
use std::assert_matches::assert_matches;
use smallvec::SmallVec;
@ -67,8 +67,8 @@ impl<'a> HashStable<StableHashingContext<'a>> for SourceFile {
src: _,
ref src_hash,
external_src: _,
start_pos,
end_pos: _,
start_pos: _,
source_len: _,
lines: _,
ref multibyte_chars,
ref non_narrow_chars,
@ -85,56 +85,30 @@ impl<'a> HashStable<StableHashingContext<'a>> for SourceFile {
// We only hash the relative position within this source_file
lines.len().hash_stable(hcx, hasher);
for &line in lines.iter() {
stable_byte_pos(line, start_pos).hash_stable(hcx, hasher);
line.hash_stable(hcx, hasher);
}
});
// We only hash the relative position within this source_file
multibyte_chars.len().hash_stable(hcx, hasher);
for &char_pos in multibyte_chars.iter() {
stable_multibyte_char(char_pos, start_pos).hash_stable(hcx, hasher);
char_pos.hash_stable(hcx, hasher);
}
non_narrow_chars.len().hash_stable(hcx, hasher);
for &char_pos in non_narrow_chars.iter() {
stable_non_narrow_char(char_pos, start_pos).hash_stable(hcx, hasher);
char_pos.hash_stable(hcx, hasher);
}
normalized_pos.len().hash_stable(hcx, hasher);
for &char_pos in normalized_pos.iter() {
stable_normalized_pos(char_pos, start_pos).hash_stable(hcx, hasher);
char_pos.hash_stable(hcx, hasher);
}
cnum.hash_stable(hcx, hasher);
}
}
fn stable_byte_pos(pos: BytePos, source_file_start: BytePos) -> u32 {
pos.0 - source_file_start.0
}
fn stable_multibyte_char(mbc: rustc_span::MultiByteChar, source_file_start: BytePos) -> (u32, u32) {
let rustc_span::MultiByteChar { pos, bytes } = mbc;
(pos.0 - source_file_start.0, bytes as u32)
}
fn stable_non_narrow_char(
swc: rustc_span::NonNarrowChar,
source_file_start: BytePos,
) -> (u32, u32) {
let pos = swc.pos();
let width = swc.width();
(pos.0 - source_file_start.0, width as u32)
}
fn stable_normalized_pos(np: NormalizedPos, source_file_start: BytePos) -> (u32, u32) {
let NormalizedPos { pos, diff } = np;
(pos.0 - source_file_start.0, diff)
}
impl<'tcx> HashStable<StableHashingContext<'tcx>> for rustc_feature::Features {
fn hash_stable(&self, hcx: &mut StableHashingContext<'tcx>, hasher: &mut StableHasher) {
// Unfortunately we cannot exhaustively list fields here, since the

View File

@ -11,26 +11,19 @@ mod tests;
/// is detected at runtime.
pub fn analyze_source_file(
src: &str,
source_file_start_pos: BytePos,
) -> (Vec<BytePos>, Vec<MultiByteChar>, Vec<NonNarrowChar>) {
let mut lines = vec![source_file_start_pos];
) -> (Vec<RelativeBytePos>, Vec<MultiByteChar>, Vec<NonNarrowChar>) {
let mut lines = vec![RelativeBytePos::from_u32(0)];
let mut multi_byte_chars = vec![];
let mut non_narrow_chars = vec![];
// Calls the right implementation, depending on hardware support available.
analyze_source_file_dispatch(
src,
source_file_start_pos,
&mut lines,
&mut multi_byte_chars,
&mut non_narrow_chars,
);
analyze_source_file_dispatch(src, &mut lines, &mut multi_byte_chars, &mut non_narrow_chars);
// The code above optimistically registers a new line *after* each \n
// it encounters. If that point is already outside the source_file, remove
// it again.
if let Some(&last_line_start) = lines.last() {
let source_file_end = source_file_start_pos + BytePos::from_usize(src.len());
let source_file_end = RelativeBytePos::from_usize(src.len());
assert!(source_file_end >= last_line_start);
if last_line_start == source_file_end {
lines.pop();
@ -43,14 +36,12 @@ pub fn analyze_source_file(
cfg_if::cfg_if! {
if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {
fn analyze_source_file_dispatch(src: &str,
source_file_start_pos: BytePos,
lines: &mut Vec<BytePos>,
lines: &mut Vec<RelativeBytePos>,
multi_byte_chars: &mut Vec<MultiByteChar>,
non_narrow_chars: &mut Vec<NonNarrowChar>) {
if is_x86_feature_detected!("sse2") {
unsafe {
analyze_source_file_sse2(src,
source_file_start_pos,
lines,
multi_byte_chars,
non_narrow_chars);
@ -58,7 +49,7 @@ cfg_if::cfg_if! {
} else {
analyze_source_file_generic(src,
src.len(),
source_file_start_pos,
RelativeBytePos::from_u32(0),
lines,
multi_byte_chars,
non_narrow_chars);
@ -72,8 +63,7 @@ cfg_if::cfg_if! {
/// SSE2 intrinsics to quickly find all newlines.
#[target_feature(enable = "sse2")]
unsafe fn analyze_source_file_sse2(src: &str,
output_offset: BytePos,
lines: &mut Vec<BytePos>,
lines: &mut Vec<RelativeBytePos>,
multi_byte_chars: &mut Vec<MultiByteChar>,
non_narrow_chars: &mut Vec<NonNarrowChar>) {
#[cfg(target_arch = "x86")]
@ -129,8 +119,7 @@ cfg_if::cfg_if! {
if control_char_mask == newlines_mask {
// All control characters are newlines, record them
let mut newlines_mask = 0xFFFF0000 | newlines_mask as u32;
let output_offset = output_offset +
BytePos::from_usize(chunk_index * CHUNK_SIZE + 1);
let output_offset = RelativeBytePos::from_usize(chunk_index * CHUNK_SIZE + 1);
loop {
let index = newlines_mask.trailing_zeros();
@ -140,7 +129,7 @@ cfg_if::cfg_if! {
break
}
lines.push(BytePos(index) + output_offset);
lines.push(RelativeBytePos(index) + output_offset);
// Clear the bit, so we can find the next one.
newlines_mask &= (!1) << index;
@ -165,7 +154,7 @@ cfg_if::cfg_if! {
intra_chunk_offset = analyze_source_file_generic(
&src[scan_start .. ],
CHUNK_SIZE - intra_chunk_offset,
BytePos::from_usize(scan_start) + output_offset,
RelativeBytePos::from_usize(scan_start),
lines,
multi_byte_chars,
non_narrow_chars
@ -177,7 +166,7 @@ cfg_if::cfg_if! {
if tail_start < src.len() {
analyze_source_file_generic(&src[tail_start ..],
src.len() - tail_start,
output_offset + BytePos::from_usize(tail_start),
RelativeBytePos::from_usize(tail_start),
lines,
multi_byte_chars,
non_narrow_chars);
@ -187,13 +176,12 @@ cfg_if::cfg_if! {
// The target (or compiler version) does not support SSE2 ...
fn analyze_source_file_dispatch(src: &str,
source_file_start_pos: BytePos,
lines: &mut Vec<BytePos>,
lines: &mut Vec<RelativeBytePos>,
multi_byte_chars: &mut Vec<MultiByteChar>,
non_narrow_chars: &mut Vec<NonNarrowChar>) {
analyze_source_file_generic(src,
src.len(),
source_file_start_pos,
RelativeBytePos::from_u32(0),
lines,
multi_byte_chars,
non_narrow_chars);
@ -207,8 +195,8 @@ cfg_if::cfg_if! {
fn analyze_source_file_generic(
src: &str,
scan_len: usize,
output_offset: BytePos,
lines: &mut Vec<BytePos>,
output_offset: RelativeBytePos,
lines: &mut Vec<RelativeBytePos>,
multi_byte_chars: &mut Vec<MultiByteChar>,
non_narrow_chars: &mut Vec<NonNarrowChar>,
) -> usize {
@ -230,11 +218,11 @@ fn analyze_source_file_generic(
// This is an ASCII control character, it could be one of the cases
// that are interesting to us.
let pos = BytePos::from_usize(i) + output_offset;
let pos = RelativeBytePos::from_usize(i) + output_offset;
match byte {
b'\n' => {
lines.push(pos + BytePos(1));
lines.push(pos + RelativeBytePos(1));
}
b'\t' => {
non_narrow_chars.push(NonNarrowChar::Tab(pos));
@ -250,7 +238,7 @@ fn analyze_source_file_generic(
let c = src[i..].chars().next().unwrap();
char_len = c.len_utf8();
let pos = BytePos::from_usize(i) + output_offset;
let pos = RelativeBytePos::from_usize(i) + output_offset;
if char_len > 1 {
assert!((2..=4).contains(&char_len));

View File

@ -3,29 +3,28 @@ use super::*;
macro_rules! test {
(case: $test_name:ident,
text: $text:expr,
source_file_start_pos: $source_file_start_pos:expr,
lines: $lines:expr,
multi_byte_chars: $multi_byte_chars:expr,
non_narrow_chars: $non_narrow_chars:expr,) => {
#[test]
fn $test_name() {
let (lines, multi_byte_chars, non_narrow_chars) =
analyze_source_file($text, BytePos($source_file_start_pos));
let (lines, multi_byte_chars, non_narrow_chars) = analyze_source_file($text);
let expected_lines: Vec<BytePos> = $lines.into_iter().map(BytePos).collect();
let expected_lines: Vec<RelativeBytePos> =
$lines.into_iter().map(RelativeBytePos).collect();
assert_eq!(lines, expected_lines);
let expected_mbcs: Vec<MultiByteChar> = $multi_byte_chars
.into_iter()
.map(|(pos, bytes)| MultiByteChar { pos: BytePos(pos), bytes })
.map(|(pos, bytes)| MultiByteChar { pos: RelativeBytePos(pos), bytes })
.collect();
assert_eq!(multi_byte_chars, expected_mbcs);
let expected_nncs: Vec<NonNarrowChar> = $non_narrow_chars
.into_iter()
.map(|(pos, width)| NonNarrowChar::new(BytePos(pos), width))
.map(|(pos, width)| NonNarrowChar::new(RelativeBytePos(pos), width))
.collect();
assert_eq!(non_narrow_chars, expected_nncs);
@ -36,7 +35,6 @@ macro_rules! test {
test!(
case: empty_text,
text: "",
source_file_start_pos: 0,
lines: vec![],
multi_byte_chars: vec![],
non_narrow_chars: vec![],
@ -45,7 +43,6 @@ test!(
test!(
case: newlines_short,
text: "a\nc",
source_file_start_pos: 0,
lines: vec![0, 2],
multi_byte_chars: vec![],
non_narrow_chars: vec![],
@ -54,7 +51,6 @@ test!(
test!(
case: newlines_long,
text: "012345678\nabcdef012345678\na",
source_file_start_pos: 0,
lines: vec![0, 10, 26],
multi_byte_chars: vec![],
non_narrow_chars: vec![],
@ -63,7 +59,6 @@ test!(
test!(
case: newline_and_multi_byte_char_in_same_chunk,
text: "01234β789\nbcdef0123456789abcdef",
source_file_start_pos: 0,
lines: vec![0, 11],
multi_byte_chars: vec![(5, 2)],
non_narrow_chars: vec![],
@ -72,7 +67,6 @@ test!(
test!(
case: newline_and_control_char_in_same_chunk,
text: "01234\u{07}6789\nbcdef0123456789abcdef",
source_file_start_pos: 0,
lines: vec![0, 11],
multi_byte_chars: vec![],
non_narrow_chars: vec![(5, 0)],
@ -81,7 +75,6 @@ test!(
test!(
case: multi_byte_char_short,
text: "aβc",
source_file_start_pos: 0,
lines: vec![0],
multi_byte_chars: vec![(1, 2)],
non_narrow_chars: vec![],
@ -90,7 +83,6 @@ test!(
test!(
case: multi_byte_char_long,
text: "0123456789abcΔf012345β",
source_file_start_pos: 0,
lines: vec![0],
multi_byte_chars: vec![(13, 2), (22, 2)],
non_narrow_chars: vec![],
@ -99,7 +91,6 @@ test!(
test!(
case: multi_byte_char_across_chunk_boundary,
text: "0123456789abcdeΔ123456789abcdef01234",
source_file_start_pos: 0,
lines: vec![0],
multi_byte_chars: vec![(15, 2)],
non_narrow_chars: vec![],
@ -108,7 +99,6 @@ test!(
test!(
case: multi_byte_char_across_chunk_boundary_tail,
text: "0123456789abcdeΔ....",
source_file_start_pos: 0,
lines: vec![0],
multi_byte_chars: vec![(15, 2)],
non_narrow_chars: vec![],
@ -117,7 +107,6 @@ test!(
test!(
case: non_narrow_short,
text: "0\t2",
source_file_start_pos: 0,
lines: vec![0],
multi_byte_chars: vec![],
non_narrow_chars: vec![(1, 4)],
@ -126,7 +115,6 @@ test!(
test!(
case: non_narrow_long,
text: "01\t3456789abcdef01234567\u{07}9",
source_file_start_pos: 0,
lines: vec![0],
multi_byte_chars: vec![],
non_narrow_chars: vec![(2, 4), (24, 0)],
@ -135,8 +123,7 @@ test!(
test!(
case: output_offset_all,
text: "01\t345\n789abcΔf01234567\u{07}9\nbcΔf",
source_file_start_pos: 1000,
lines: vec![0 + 1000, 7 + 1000, 27 + 1000],
multi_byte_chars: vec![(13 + 1000, 2), (29 + 1000, 2)],
non_narrow_chars: vec![(2 + 1000, 4), (24 + 1000, 0)],
lines: vec![0, 7, 27],
multi_byte_chars: vec![(13, 2), (29, 2)],
non_narrow_chars: vec![(2, 4), (24, 0)],
);

View File

@ -1,5 +1,5 @@
use crate::source_map::SourceMap;
use crate::{BytePos, SourceFile, SpanData};
use crate::{BytePos, Pos, RelativeBytePos, SourceFile, SpanData};
use rustc_data_structures::sync::Lrc;
use std::ops::Range;
@ -37,6 +37,7 @@ impl CacheEntry {
self.file_index = file_idx;
}
let pos = self.file.relative_position(pos);
let line_index = self.file.lookup_line(pos).unwrap();
let line_bounds = self.file.line_bounds(line_index);
self.line_number = line_index + 1;
@ -79,7 +80,7 @@ impl<'sm> CachingSourceMapView<'sm> {
pub fn byte_pos_to_line_and_col(
&mut self,
pos: BytePos,
) -> Option<(Lrc<SourceFile>, usize, BytePos)> {
) -> Option<(Lrc<SourceFile>, usize, RelativeBytePos)> {
self.time_stamp += 1;
// Check if the position is in one of the cached lines
@ -88,11 +89,8 @@ impl<'sm> CachingSourceMapView<'sm> {
let cache_entry = &mut self.line_cache[cache_idx as usize];
cache_entry.touch(self.time_stamp);
return Some((
cache_entry.file.clone(),
cache_entry.line_number,
pos - cache_entry.line.start,
));
let col = RelativeBytePos(pos.to_u32() - cache_entry.line.start.to_u32());
return Some((cache_entry.file.clone(), cache_entry.line_number, col));
}
// No cache hit ...
@ -108,7 +106,8 @@ impl<'sm> CachingSourceMapView<'sm> {
let cache_entry = &mut self.line_cache[oldest];
cache_entry.update(new_file_and_idx, pos, self.time_stamp);
Some((cache_entry.file.clone(), cache_entry.line_number, pos - cache_entry.line.start))
let col = RelativeBytePos(pos.to_u32() - cache_entry.line.start.to_u32());
Some((cache_entry.file.clone(), cache_entry.line_number, col))
}
pub fn span_data_to_lines_and_cols(

View File

@ -1107,27 +1107,27 @@ impl fmt::Debug for SpanData {
}
/// Identifies an offset of a multi-byte character in a `SourceFile`.
#[derive(Copy, Clone, Encodable, Decodable, Eq, PartialEq, Debug)]
#[derive(Copy, Clone, Encodable, Decodable, Eq, PartialEq, Debug, HashStable_Generic)]
pub struct MultiByteChar {
/// The absolute offset of the character in the `SourceMap`.
pub pos: BytePos,
/// The relative offset of the character in the `SourceFile`.
pub pos: RelativeBytePos,
/// The number of bytes, `>= 2`.
pub bytes: u8,
}
/// Identifies an offset of a non-narrow character in a `SourceFile`.
#[derive(Copy, Clone, Encodable, Decodable, Eq, PartialEq, Debug)]
#[derive(Copy, Clone, Encodable, Decodable, Eq, PartialEq, Debug, HashStable_Generic)]
pub enum NonNarrowChar {
/// Represents a zero-width character.
ZeroWidth(BytePos),
ZeroWidth(RelativeBytePos),
/// Represents a wide (full-width) character.
Wide(BytePos),
Wide(RelativeBytePos),
/// Represents a tab character, represented visually with a width of 4 characters.
Tab(BytePos),
Tab(RelativeBytePos),
}
impl NonNarrowChar {
fn new(pos: BytePos, width: usize) -> Self {
fn new(pos: RelativeBytePos, width: usize) -> Self {
match width {
0 => NonNarrowChar::ZeroWidth(pos),
2 => NonNarrowChar::Wide(pos),
@ -1136,8 +1136,8 @@ impl NonNarrowChar {
}
}
/// Returns the absolute offset of the character in the `SourceMap`.
pub fn pos(&self) -> BytePos {
/// Returns the relative offset of the character in the `SourceFile`.
pub fn pos(&self) -> RelativeBytePos {
match *self {
NonNarrowChar::ZeroWidth(p) | NonNarrowChar::Wide(p) | NonNarrowChar::Tab(p) => p,
}
@ -1153,10 +1153,10 @@ impl NonNarrowChar {
}
}
impl Add<BytePos> for NonNarrowChar {
impl Add<RelativeBytePos> for NonNarrowChar {
type Output = Self;
fn add(self, rhs: BytePos) -> Self {
fn add(self, rhs: RelativeBytePos) -> Self {
match self {
NonNarrowChar::ZeroWidth(pos) => NonNarrowChar::ZeroWidth(pos + rhs),
NonNarrowChar::Wide(pos) => NonNarrowChar::Wide(pos + rhs),
@ -1165,10 +1165,10 @@ impl Add<BytePos> for NonNarrowChar {
}
}
impl Sub<BytePos> for NonNarrowChar {
impl Sub<RelativeBytePos> for NonNarrowChar {
type Output = Self;
fn sub(self, rhs: BytePos) -> Self {
fn sub(self, rhs: RelativeBytePos) -> Self {
match self {
NonNarrowChar::ZeroWidth(pos) => NonNarrowChar::ZeroWidth(pos - rhs),
NonNarrowChar::Wide(pos) => NonNarrowChar::Wide(pos - rhs),
@ -1178,10 +1178,10 @@ impl Sub<BytePos> for NonNarrowChar {
}
/// Identifies an offset of a character that was normalized away from `SourceFile`.
#[derive(Copy, Clone, Encodable, Decodable, Eq, PartialEq, Debug)]
#[derive(Copy, Clone, Encodable, Decodable, Eq, PartialEq, Debug, HashStable_Generic)]
pub struct NormalizedPos {
/// The absolute offset of the character in the `SourceMap`.
pub pos: BytePos,
/// The relative offset of the character in the `SourceFile`.
pub pos: RelativeBytePos,
/// The difference between original and normalized string at position.
pub diff: u32,
}
@ -1293,7 +1293,7 @@ impl SourceFileHash {
#[derive(Clone)]
pub enum SourceFileLines {
/// The source file lines, in decoded (random-access) form.
Lines(Vec<BytePos>),
Lines(Vec<RelativeBytePos>),
/// The source file lines, in undecoded difference list form.
Diffs(SourceFileDiffs),
@ -1314,11 +1314,6 @@ impl SourceFileLines {
/// small crates where very little of `std`'s metadata is used.
#[derive(Clone)]
pub struct SourceFileDiffs {
/// Position of the first line. Note that this is always encoded as a
/// `BytePos` because it is often much larger than any of the
/// differences.
line_start: BytePos,
/// Always 1, 2, or 4. Always as small as possible, while being big
/// enough to hold the length of the longest line in the source file.
/// The 1 case is by far the most common.
@ -1351,8 +1346,8 @@ pub struct SourceFile {
pub external_src: Lock<ExternalSource>,
/// The start position of this source in the `SourceMap`.
pub start_pos: BytePos,
/// The end position of this source in the `SourceMap`.
pub end_pos: BytePos,
/// The byte length of this source.
pub source_len: RelativeBytePos,
/// Locations of lines beginnings in the source code.
pub lines: Lock<SourceFileLines>,
/// Locations of multi-byte characters in the source code.
@ -1375,7 +1370,7 @@ impl Clone for SourceFile {
src_hash: self.src_hash,
external_src: Lock::new(self.external_src.borrow().clone()),
start_pos: self.start_pos,
end_pos: self.end_pos,
source_len: self.source_len,
lines: Lock::new(self.lines.borrow().clone()),
multibyte_chars: self.multibyte_chars.clone(),
non_narrow_chars: self.non_narrow_chars.clone(),
@ -1390,8 +1385,8 @@ impl<S: Encoder> Encodable<S> for SourceFile {
fn encode(&self, s: &mut S) {
self.name.encode(s);
self.src_hash.encode(s);
self.start_pos.encode(s);
self.end_pos.encode(s);
// Do not encode `start_pos` as it's global state for this session.
self.source_len.encode(s);
// We are always in `Lines` form by the time we reach here.
assert!(self.lines.borrow().is_lines());
@ -1422,7 +1417,7 @@ impl<S: Encoder> Encodable<S> for SourceFile {
s.emit_u8(bytes_per_diff as u8);
// Encode the first element.
lines[0].encode(s);
assert_eq!(lines[0], RelativeBytePos(0));
// Encode the difference list.
let diff_iter = lines.array_windows().map(|&[fst, snd]| snd - fst);
@ -1465,26 +1460,17 @@ impl<D: Decoder> Decodable<D> for SourceFile {
fn decode(d: &mut D) -> SourceFile {
let name: FileName = Decodable::decode(d);
let src_hash: SourceFileHash = Decodable::decode(d);
let start_pos: BytePos = Decodable::decode(d);
let end_pos: BytePos = Decodable::decode(d);
let source_len: RelativeBytePos = Decodable::decode(d);
let lines = {
let num_lines: u32 = Decodable::decode(d);
if num_lines > 0 {
// Read the number of bytes used per diff.
let bytes_per_diff = d.read_u8() as usize;
// Read the first element.
let line_start: BytePos = Decodable::decode(d);
// Read the difference list.
let num_diffs = num_lines as usize - 1;
let raw_diffs = d.read_raw_bytes(bytes_per_diff * num_diffs).to_vec();
SourceFileLines::Diffs(SourceFileDiffs {
line_start,
bytes_per_diff,
num_diffs,
raw_diffs,
})
SourceFileLines::Diffs(SourceFileDiffs { bytes_per_diff, num_diffs, raw_diffs })
} else {
SourceFileLines::Lines(vec![])
}
@ -1496,8 +1482,8 @@ impl<D: Decoder> Decodable<D> for SourceFile {
let cnum: CrateNum = Decodable::decode(d);
SourceFile {
name,
start_pos,
end_pos,
start_pos: BytePos::from_u32(0),
source_len,
src: None,
src_hash,
// Unused - the metadata decoder will construct
@ -1523,63 +1509,58 @@ impl SourceFile {
pub fn new(
name: FileName,
mut src: String,
start_pos: BytePos,
hash_kind: SourceFileHashAlgorithm,
) -> Self {
) -> Result<Self, OffsetOverflowError> {
// Compute the file hash before any normalization.
let src_hash = SourceFileHash::new(hash_kind, &src);
let normalized_pos = normalize_src(&mut src, start_pos);
let normalized_pos = normalize_src(&mut src);
let name_hash = {
let mut hasher: StableHasher = StableHasher::new();
name.hash(&mut hasher);
hasher.finish()
};
let end_pos = start_pos.to_usize() + src.len();
assert!(end_pos <= u32::MAX as usize);
let source_len = src.len();
let source_len = u32::try_from(source_len).map_err(|_| OffsetOverflowError)?;
let (lines, multibyte_chars, non_narrow_chars) =
analyze_source_file::analyze_source_file(&src, start_pos);
analyze_source_file::analyze_source_file(&src);
SourceFile {
Ok(SourceFile {
name,
src: Some(Lrc::new(src)),
src_hash,
external_src: Lock::new(ExternalSource::Unneeded),
start_pos,
end_pos: Pos::from_usize(end_pos),
start_pos: BytePos::from_u32(0),
source_len: RelativeBytePos::from_u32(source_len),
lines: Lock::new(SourceFileLines::Lines(lines)),
multibyte_chars,
non_narrow_chars,
normalized_pos,
name_hash,
cnum: LOCAL_CRATE,
}
})
}
pub fn lines<F, R>(&self, f: F) -> R
where
F: FnOnce(&[BytePos]) -> R,
F: FnOnce(&[RelativeBytePos]) -> R,
{
let mut guard = self.lines.borrow_mut();
match &*guard {
SourceFileLines::Lines(lines) => f(lines),
SourceFileLines::Diffs(SourceFileDiffs {
mut line_start,
bytes_per_diff,
num_diffs,
raw_diffs,
}) => {
SourceFileLines::Diffs(SourceFileDiffs { bytes_per_diff, num_diffs, raw_diffs }) => {
// Convert from "diffs" form to "lines" form.
let num_lines = num_diffs + 1;
let mut lines = Vec::with_capacity(num_lines);
let mut line_start = RelativeBytePos(0);
lines.push(line_start);
assert_eq!(*num_diffs, raw_diffs.len() / bytes_per_diff);
match bytes_per_diff {
1 => {
lines.extend(raw_diffs.into_iter().map(|&diff| {
line_start = line_start + BytePos(diff as u32);
line_start = line_start + RelativeBytePos(diff as u32);
line_start
}));
}
@ -1588,7 +1569,7 @@ impl SourceFile {
let pos = bytes_per_diff * i;
let bytes = [raw_diffs[pos], raw_diffs[pos + 1]];
let diff = u16::from_le_bytes(bytes);
line_start = line_start + BytePos(diff as u32);
line_start = line_start + RelativeBytePos(diff as u32);
line_start
}));
}
@ -1602,7 +1583,7 @@ impl SourceFile {
raw_diffs[pos + 3],
];
let diff = u32::from_le_bytes(bytes);
line_start = line_start + BytePos(diff);
line_start = line_start + RelativeBytePos(diff);
line_start
}));
}
@ -1617,8 +1598,10 @@ impl SourceFile {
/// Returns the `BytePos` of the beginning of the current line.
pub fn line_begin_pos(&self, pos: BytePos) -> BytePos {
let pos = self.relative_position(pos);
let line_index = self.lookup_line(pos).unwrap();
self.lines(|lines| lines[line_index])
let line_start_pos = self.lines(|lines| lines[line_index]);
self.absolute_position(line_start_pos)
}
/// Add externally loaded source.
@ -1643,7 +1626,7 @@ impl SourceFile {
if let Some(mut src) = src {
// The src_hash needs to be computed on the pre-normalized src.
if self.src_hash.matches(&src) {
normalize_src(&mut src, BytePos::from_usize(0));
normalize_src(&mut src);
*src_kind = ExternalSourceKind::Present(Lrc::new(src));
return true;
}
@ -1676,8 +1659,7 @@ impl SourceFile {
let begin = {
let line = self.lines(|lines| lines.get(line_number).copied())?;
let begin: BytePos = line - self.start_pos;
begin.to_usize()
line.to_usize()
};
if let Some(ref src) = self.src {
@ -1703,25 +1685,41 @@ impl SourceFile {
self.lines(|lines| lines.len())
}
#[inline]
pub fn absolute_position(&self, pos: RelativeBytePos) -> BytePos {
BytePos::from_u32(pos.to_u32() + self.start_pos.to_u32())
}
#[inline]
pub fn relative_position(&self, pos: BytePos) -> RelativeBytePos {
RelativeBytePos::from_u32(pos.to_u32() - self.start_pos.to_u32())
}
#[inline]
pub fn end_position(&self) -> BytePos {
self.absolute_position(self.source_len)
}
/// Finds the line containing the given position. The return value is the
/// index into the `lines` array of this `SourceFile`, not the 1-based line
/// number. If the source_file is empty or the position is located before the
/// first line, `None` is returned.
pub fn lookup_line(&self, pos: BytePos) -> Option<usize> {
pub fn lookup_line(&self, pos: RelativeBytePos) -> Option<usize> {
self.lines(|lines| lines.partition_point(|x| x <= &pos).checked_sub(1))
}
pub fn line_bounds(&self, line_index: usize) -> Range<BytePos> {
if self.is_empty() {
return self.start_pos..self.end_pos;
return self.start_pos..self.start_pos;
}
self.lines(|lines| {
assert!(line_index < lines.len());
if line_index == (lines.len() - 1) {
lines[line_index]..self.end_pos
self.absolute_position(lines[line_index])..self.end_position()
} else {
lines[line_index]..lines[line_index + 1]
self.absolute_position(lines[line_index])
..self.absolute_position(lines[line_index + 1])
}
})
}
@ -1732,17 +1730,19 @@ impl SourceFile {
/// returns true still contain one byte position according to this function.
#[inline]
pub fn contains(&self, byte_pos: BytePos) -> bool {
byte_pos >= self.start_pos && byte_pos <= self.end_pos
byte_pos >= self.start_pos && byte_pos <= self.end_position()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.start_pos == self.end_pos
self.source_len.to_u32() == 0
}
/// Calculates the original byte position relative to the start of the file
/// based on the given byte position.
pub fn original_relative_byte_pos(&self, pos: BytePos) -> BytePos {
pub fn original_relative_byte_pos(&self, pos: BytePos) -> RelativeBytePos {
let pos = self.relative_position(pos);
// Diff before any records is 0. Otherwise use the previously recorded
// diff as that applies to the following characters until a new diff
// is recorded.
@ -1752,7 +1752,7 @@ impl SourceFile {
Err(i) => self.normalized_pos[i - 1].diff,
};
BytePos::from_u32(pos.0 - self.start_pos.0 + diff)
RelativeBytePos::from_u32(pos.0 + diff)
}
/// Calculates a normalized byte position from a byte offset relative to the
@ -1777,8 +1777,8 @@ impl SourceFile {
BytePos::from_u32(self.start_pos.0 + offset - diff)
}
/// Converts an absolute `BytePos` to a `CharPos` relative to the `SourceFile`.
pub fn bytepos_to_file_charpos(&self, bpos: BytePos) -> CharPos {
/// Converts an relative `RelativeBytePos` to a `CharPos` relative to the `SourceFile`.
fn bytepos_to_file_charpos(&self, bpos: RelativeBytePos) -> CharPos {
// The number of extra bytes due to multibyte chars in the `SourceFile`.
let mut total_extra_bytes = 0;
@ -1796,13 +1796,13 @@ impl SourceFile {
}
}
assert!(self.start_pos.to_u32() + total_extra_bytes <= bpos.to_u32());
CharPos(bpos.to_usize() - self.start_pos.to_usize() - total_extra_bytes as usize)
assert!(total_extra_bytes <= bpos.to_u32());
CharPos(bpos.to_usize() - total_extra_bytes as usize)
}
/// Looks up the file's (1-based) line number and (0-based `CharPos`) column offset, for a
/// given `BytePos`.
pub fn lookup_file_pos(&self, pos: BytePos) -> (usize, CharPos) {
/// given `RelativeBytePos`.
fn lookup_file_pos(&self, pos: RelativeBytePos) -> (usize, CharPos) {
let chpos = self.bytepos_to_file_charpos(pos);
match self.lookup_line(pos) {
Some(a) => {
@ -1823,6 +1823,7 @@ impl SourceFile {
/// Looks up the file's (1-based) line number, (0-based `CharPos`) column offset, and (0-based)
/// column offset when displayed, for a given `BytePos`.
pub fn lookup_file_pos_with_col_display(&self, pos: BytePos) -> (usize, CharPos, usize) {
let pos = self.relative_position(pos);
let (line, col_or_chpos) = self.lookup_file_pos(pos);
if line > 0 {
let col = col_or_chpos;
@ -1861,16 +1862,10 @@ impl SourceFile {
}
/// Normalizes the source code and records the normalizations.
fn normalize_src(src: &mut String, start_pos: BytePos) -> Vec<NormalizedPos> {
fn normalize_src(src: &mut String) -> Vec<NormalizedPos> {
let mut normalized_pos = vec![];
remove_bom(src, &mut normalized_pos);
normalize_newlines(src, &mut normalized_pos);
// Offset all the positions by start_pos to match the final file positions.
for np in &mut normalized_pos {
np.pos.0 += start_pos.0;
}
normalized_pos
}
@ -1878,7 +1873,7 @@ fn normalize_src(src: &mut String, start_pos: BytePos) -> Vec<NormalizedPos> {
fn remove_bom(src: &mut String, normalized_pos: &mut Vec<NormalizedPos>) {
if src.starts_with('\u{feff}') {
src.drain(..3);
normalized_pos.push(NormalizedPos { pos: BytePos(0), diff: 3 });
normalized_pos.push(NormalizedPos { pos: RelativeBytePos(0), diff: 3 });
}
}
@ -1913,7 +1908,7 @@ fn normalize_newlines(src: &mut String, normalized_pos: &mut Vec<NormalizedPos>)
cursor += idx - gap_len;
gap_len += 1;
normalized_pos.push(NormalizedPos {
pos: BytePos::from_usize(cursor + 1),
pos: RelativeBytePos::from_usize(cursor + 1),
diff: original_gap + gap_len as u32,
});
}
@ -2015,6 +2010,10 @@ impl_pos! {
#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
pub struct BytePos(pub u32);
/// A byte offset relative to file beginning.
#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
pub struct RelativeBytePos(pub u32);
/// A character offset.
///
/// Because of multibyte UTF-8 characters, a byte offset
@ -2036,6 +2035,24 @@ impl<D: Decoder> Decodable<D> for BytePos {
}
}
impl<H: HashStableContext> HashStable<H> for RelativeBytePos {
fn hash_stable(&self, hcx: &mut H, hasher: &mut StableHasher) {
self.0.hash_stable(hcx, hasher);
}
}
impl<S: Encoder> Encodable<S> for RelativeBytePos {
fn encode(&self, s: &mut S) {
s.emit_u32(self.0);
}
}
impl<D: Decoder> Decodable<D> for RelativeBytePos {
fn decode(d: &mut D) -> RelativeBytePos {
RelativeBytePos(d.read_u32())
}
}
// _____________________________________________________________________________
// Loc, SourceFileAndLine, SourceFileAndBytePos
//

View File

@ -14,13 +14,10 @@ pub use crate::*;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::stable_hasher::{Hash128, Hash64, StableHasher};
use rustc_data_structures::sync::{
AtomicU32, IntoDynSyncSend, Lrc, MappedReadGuard, ReadGuard, RwLock,
};
use rustc_data_structures::sync::{IntoDynSyncSend, Lrc, MappedReadGuard, ReadGuard, RwLock};
use std::cmp;
use std::hash::Hash;
use std::path::{self, Path, PathBuf};
use std::sync::atomic::Ordering;
use std::fs;
use std::io;
@ -187,9 +184,6 @@ pub(super) struct SourceMapFiles {
}
pub struct SourceMap {
/// The address space below this value is currently used by the files in the source map.
used_address_space: AtomicU32,
files: RwLock<SourceMapFiles>,
file_loader: IntoDynSyncSend<Box<dyn FileLoader + Sync + Send>>,
// This is used to apply the file path remapping as specified via
@ -215,7 +209,6 @@ impl SourceMap {
hash_kind: SourceFileHashAlgorithm,
) -> SourceMap {
SourceMap {
used_address_space: AtomicU32::new(0),
files: Default::default(),
file_loader: IntoDynSyncSend(file_loader),
path_mapping,
@ -267,26 +260,26 @@ impl SourceMap {
self.files.borrow().stable_id_to_source_file.get(&stable_id).cloned()
}
fn allocate_address_space(&self, size: usize) -> Result<usize, OffsetOverflowError> {
let size = u32::try_from(size).map_err(|_| OffsetOverflowError)?;
fn register_source_file(
&self,
file_id: StableSourceFileId,
mut file: SourceFile,
) -> Result<Lrc<SourceFile>, OffsetOverflowError> {
let mut files = self.files.borrow_mut();
loop {
let current = self.used_address_space.load(Ordering::Relaxed);
let next = current
.checked_add(size)
// Add one so there is some space between files. This lets us distinguish
// positions in the `SourceMap`, even in the presence of zero-length files.
.and_then(|next| next.checked_add(1))
.ok_or(OffsetOverflowError)?;
file.start_pos = BytePos(if let Some(last_file) = files.source_files.last() {
// Add one so there is some space between files. This lets us distinguish
// positions in the `SourceMap`, even in the presence of zero-length files.
last_file.end_position().0.checked_add(1).ok_or(OffsetOverflowError)?
} else {
0
});
if self
.used_address_space
.compare_exchange(current, next, Ordering::Relaxed, Ordering::Relaxed)
.is_ok()
{
return Ok(usize::try_from(current).unwrap());
}
}
let file = Lrc::new(file);
files.source_files.push(file.clone());
files.stable_id_to_source_file.insert(file_id, file.clone());
Ok(file)
}
/// Creates a new `SourceFile`.
@ -310,32 +303,18 @@ impl SourceMap {
let (filename, _) = self.path_mapping.map_filename_prefix(&filename);
let file_id = StableSourceFileId::new_from_name(&filename, LOCAL_CRATE);
let lrc_sf = match self.source_file_by_stable_id(file_id) {
Some(lrc_sf) => lrc_sf,
match self.source_file_by_stable_id(file_id) {
Some(lrc_sf) => Ok(lrc_sf),
None => {
let start_pos = self.allocate_address_space(src.len())?;
let source_file = Lrc::new(SourceFile::new(
filename,
src,
Pos::from_usize(start_pos),
self.hash_kind,
));
let source_file = SourceFile::new(filename, src, self.hash_kind)?;
// Let's make sure the file_id we generated above actually matches
// the ID we generate for the SourceFile we just created.
debug_assert_eq!(StableSourceFileId::new(&source_file), file_id);
let mut files = self.files.borrow_mut();
files.source_files.push(source_file.clone());
files.stable_id_to_source_file.insert(file_id, source_file.clone());
source_file
self.register_source_file(file_id, source_file)
}
};
Ok(lrc_sf)
}
}
/// Allocates a new `SourceFile` representing a source file from an external
@ -347,53 +326,17 @@ impl SourceMap {
filename: FileName,
src_hash: SourceFileHash,
name_hash: Hash128,
source_len: usize,
source_len: u32,
cnum: CrateNum,
file_local_lines: Lock<SourceFileLines>,
mut file_local_multibyte_chars: Vec<MultiByteChar>,
mut file_local_non_narrow_chars: Vec<NonNarrowChar>,
mut file_local_normalized_pos: Vec<NormalizedPos>,
original_start_pos: BytePos,
multibyte_chars: Vec<MultiByteChar>,
non_narrow_chars: Vec<NonNarrowChar>,
normalized_pos: Vec<NormalizedPos>,
metadata_index: u32,
) -> Lrc<SourceFile> {
let start_pos = self
.allocate_address_space(source_len)
.expect("not enough address space for imported source file");
let source_len = RelativeBytePos::from_u32(source_len);
let end_pos = Pos::from_usize(start_pos + source_len);
let start_pos = Pos::from_usize(start_pos);
// Translate these positions into the new global frame of reference,
// now that the offset of the SourceFile is known.
//
// These are all unsigned values. `original_start_pos` may be larger or
// smaller than `start_pos`, but `pos` is always larger than both.
// Therefore, `(pos - original_start_pos) + start_pos` won't overflow
// but `start_pos - original_start_pos` might. So we use the former
// form rather than pre-computing the offset into a local variable. The
// compiler backend can optimize away the repeated computations in a
// way that won't trigger overflow checks.
match &mut *file_local_lines.borrow_mut() {
SourceFileLines::Lines(lines) => {
for pos in lines {
*pos = (*pos - original_start_pos) + start_pos;
}
}
SourceFileLines::Diffs(SourceFileDiffs { line_start, .. }) => {
*line_start = (*line_start - original_start_pos) + start_pos;
}
}
for mbc in &mut file_local_multibyte_chars {
mbc.pos = (mbc.pos - original_start_pos) + start_pos;
}
for swc in &mut file_local_non_narrow_chars {
*swc = (*swc - original_start_pos) + start_pos;
}
for nc in &mut file_local_normalized_pos {
nc.pos = (nc.pos - original_start_pos) + start_pos;
}
let source_file = Lrc::new(SourceFile {
let source_file = SourceFile {
name: filename,
src: None,
src_hash,
@ -401,24 +344,19 @@ impl SourceMap {
kind: ExternalSourceKind::AbsentOk,
metadata_index,
}),
start_pos,
end_pos,
start_pos: BytePos(0),
source_len,
lines: file_local_lines,
multibyte_chars: file_local_multibyte_chars,
non_narrow_chars: file_local_non_narrow_chars,
normalized_pos: file_local_normalized_pos,
multibyte_chars,
non_narrow_chars,
normalized_pos,
name_hash,
cnum,
});
};
let mut files = self.files.borrow_mut();
files.source_files.push(source_file.clone());
files
.stable_id_to_source_file
.insert(StableSourceFileId::new(&source_file), source_file.clone());
source_file
let file_id = StableSourceFileId::new(&source_file);
self.register_source_file(file_id, source_file)
.expect("not enough address space for imported source file")
}
/// If there is a doctest offset, applies it to the line.
@ -452,6 +390,7 @@ impl SourceMap {
pub fn lookup_line(&self, pos: BytePos) -> Result<SourceFileAndLine, Lrc<SourceFile>> {
let f = self.lookup_source_file(pos);
let pos = f.relative_position(pos);
match f.lookup_line(pos) {
Some(line) => Ok(SourceFileAndLine { sf: f, line }),
None => Err(f),
@ -547,7 +486,9 @@ impl SourceMap {
return true;
}
let f = (*self.files.borrow().source_files)[lo].clone();
f.lookup_line(sp.lo()) != f.lookup_line(sp.hi())
let lo = f.relative_position(sp.lo());
let hi = f.relative_position(sp.hi());
f.lookup_line(lo) != f.lookup_line(hi)
}
#[instrument(skip(self), level = "trace")]
@ -627,7 +568,7 @@ impl SourceMap {
let start_index = local_begin.pos.to_usize();
let end_index = local_end.pos.to_usize();
let source_len = (local_begin.sf.end_pos - local_begin.sf.start_pos).to_usize();
let source_len = local_begin.sf.source_len.to_usize();
if start_index > end_index || end_index > source_len {
return Err(SpanSnippetError::MalformedForSourcemap(MalformedSourceMapPositions {
@ -1034,7 +975,7 @@ impl SourceMap {
return 1;
}
let source_len = (local_begin.sf.end_pos - local_begin.sf.start_pos).to_usize();
let source_len = local_begin.sf.source_len.to_usize();
debug!("source_len=`{:?}`", source_len);
// Ensure indexes are also not malformed.
if start_index > end_index || end_index > source_len - 1 {

View File

@ -50,6 +50,7 @@ impl SourceMap {
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];
let bpos = sf.relative_position(bpos);
sf.bytepos_to_file_charpos(bpos)
}
}
@ -230,8 +231,7 @@ fn t10() {
let SourceFile {
name,
src_hash,
start_pos,
end_pos,
source_len,
lines,
multibyte_chars,
non_narrow_chars,
@ -244,13 +244,12 @@ fn t10() {
name,
src_hash,
name_hash,
(end_pos - start_pos).to_usize(),
source_len.to_u32(),
CrateNum::new(0),
lines,
multibyte_chars,
non_narrow_chars,
normalized_pos,
start_pos,
0,
);

View File

@ -3,24 +3,23 @@ use super::*;
#[test]
fn test_lookup_line() {
let source = "abcdefghijklm\nabcdefghij\n...".to_owned();
let sf = SourceFile::new(
FileName::Anon(Hash64::ZERO),
source,
BytePos(3),
SourceFileHashAlgorithm::Sha256,
);
sf.lines(|lines| assert_eq!(lines, &[BytePos(3), BytePos(17), BytePos(28)]));
let mut sf =
SourceFile::new(FileName::Anon(Hash64::ZERO), source, SourceFileHashAlgorithm::Sha256)
.unwrap();
sf.start_pos = BytePos(3);
sf.lines(|lines| {
assert_eq!(lines, &[RelativeBytePos(0), RelativeBytePos(14), RelativeBytePos(25)])
});
assert_eq!(sf.lookup_line(BytePos(0)), None);
assert_eq!(sf.lookup_line(BytePos(3)), Some(0));
assert_eq!(sf.lookup_line(BytePos(4)), Some(0));
assert_eq!(sf.lookup_line(RelativeBytePos(0)), Some(0));
assert_eq!(sf.lookup_line(RelativeBytePos(1)), Some(0));
assert_eq!(sf.lookup_line(BytePos(16)), Some(0));
assert_eq!(sf.lookup_line(BytePos(17)), Some(1));
assert_eq!(sf.lookup_line(BytePos(18)), Some(1));
assert_eq!(sf.lookup_line(RelativeBytePos(13)), Some(0));
assert_eq!(sf.lookup_line(RelativeBytePos(14)), Some(1));
assert_eq!(sf.lookup_line(RelativeBytePos(15)), Some(1));
assert_eq!(sf.lookup_line(BytePos(28)), Some(2));
assert_eq!(sf.lookup_line(BytePos(29)), Some(2));
assert_eq!(sf.lookup_line(RelativeBytePos(25)), Some(2));
assert_eq!(sf.lookup_line(RelativeBytePos(26)), Some(2));
}
#[test]

View File

@ -134,7 +134,7 @@ impl DocVisitor for SourceCollector<'_, '_> {
let filename = span.filename(sess);
let span = span.inner();
let pos = sess.source_map().lookup_source_file(span.lo());
let file_span = span.with_lo(pos.start_pos).with_hi(pos.end_pos);
let file_span = span.with_lo(pos.start_pos).with_hi(pos.end_position());
// If it turns out that we couldn't read this file, then we probably
// can't read any of the files (generating html output from json or
// something like that), so just don't include sources for the

View File

@ -73,7 +73,7 @@ pub(crate) struct SyntaxRange {
impl SyntaxRange {
fn new(span: rustc_span::Span, file: &SourceFile) -> Option<Self> {
let get_pos = |bytepos: BytePos| file.original_relative_byte_pos(bytepos).0;
let get_line = |bytepos: BytePos| file.lookup_line(bytepos);
let get_line = |bytepos: BytePos| file.lookup_line(file.relative_position(bytepos));
Some(SyntaxRange {
byte_span: (get_pos(span.lo()), get_pos(span.hi())),

View File

@ -12,7 +12,7 @@ use rustc_lexer::{tokenize, TokenKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::{BytePos, Pos, Span, SyntaxContext};
use rustc_span::{BytePos, Pos, RelativeBytePos, Span, SyntaxContext};
declare_clippy_lint! {
/// ### What it does
@ -514,7 +514,7 @@ fn item_has_safety_comment(cx: &LateContext<'_>, item: &hir::Item<'_>) -> HasSaf
match text_has_safety_comment(
src,
&lines[comment_start_line.line + 1..=unsafe_line.line],
unsafe_line.sf.start_pos.to_usize(),
unsafe_line.sf.start_pos,
) {
Some(b) => HasSafetyComment::Yes(b),
None => HasSafetyComment::No,
@ -558,7 +558,7 @@ fn stmt_has_safety_comment(cx: &LateContext<'_>, span: Span, hir_id: HirId) -> H
match text_has_safety_comment(
src,
&lines[comment_start_line.line + 1..=unsafe_line.line],
unsafe_line.sf.start_pos.to_usize(),
unsafe_line.sf.start_pos,
) {
Some(b) => HasSafetyComment::Yes(b),
None => HasSafetyComment::No,
@ -619,7 +619,7 @@ fn span_from_macro_expansion_has_safety_comment(cx: &LateContext<'_>, span: Span
match text_has_safety_comment(
src,
&lines[macro_line.line + 1..=unsafe_line.line],
unsafe_line.sf.start_pos.to_usize(),
unsafe_line.sf.start_pos,
) {
Some(b) => HasSafetyComment::Yes(b),
None => HasSafetyComment::No,
@ -675,7 +675,7 @@ fn span_in_body_has_safety_comment(cx: &LateContext<'_>, span: Span) -> bool {
body_line.line < unsafe_line.line && text_has_safety_comment(
src,
&lines[body_line.line + 1..=unsafe_line.line],
unsafe_line.sf.start_pos.to_usize(),
unsafe_line.sf.start_pos,
).is_some()
})
} else {
@ -688,13 +688,13 @@ fn span_in_body_has_safety_comment(cx: &LateContext<'_>, span: Span) -> bool {
}
/// Checks if the given text has a safety comment for the immediately proceeding line.
fn text_has_safety_comment(src: &str, line_starts: &[BytePos], offset: usize) -> Option<BytePos> {
fn text_has_safety_comment(src: &str, line_starts: &[RelativeBytePos], start_pos: BytePos) -> Option<BytePos> {
let mut lines = line_starts
.array_windows::<2>()
.rev()
.map_while(|[start, end]| {
let start = start.to_usize() - offset;
let end = end.to_usize() - offset;
let start = start.to_usize();
let end = end.to_usize();
let text = src.get(start..end)?;
let trimmed = text.trim_start();
Some((start + (text.len() - trimmed.len()), trimmed))
@ -709,9 +709,7 @@ fn text_has_safety_comment(src: &str, line_starts: &[BytePos], offset: usize) ->
let (mut line, mut line_start) = (line, line_start);
loop {
if line.to_ascii_uppercase().contains("SAFETY:") {
return Some(BytePos(
u32::try_from(line_start).unwrap() + u32::try_from(offset).unwrap(),
));
return Some(start_pos + BytePos(u32::try_from(line_start).unwrap()));
}
match lines.next() {
Some((s, x)) if x.starts_with("//") => (line, line_start) = (x, s),
@ -724,15 +722,13 @@ fn text_has_safety_comment(src: &str, line_starts: &[BytePos], offset: usize) ->
let (mut line_start, mut line) = (line_start, line);
loop {
if line.starts_with("/*") {
let src = &src[line_start..line_starts.last().unwrap().to_usize() - offset];
let src = &src[line_start..line_starts.last().unwrap().to_usize()];
let mut tokens = tokenize(src);
return (src[..tokens.next().unwrap().len as usize]
.to_ascii_uppercase()
.contains("SAFETY:")
&& tokens.all(|t| t.kind == TokenKind::Whitespace))
.then_some(BytePos(
u32::try_from(line_start).unwrap() + u32::try_from(offset).unwrap(),
));
.then_some(start_pos + BytePos(u32::try_from(line_start).unwrap()));
}
match lines.next() {
Some(x) => (line_start, line) = x,

View File

@ -8,7 +8,7 @@ use rustc_hir::{BlockCheckMode, Expr, ExprKind, UnsafeSource};
use rustc_lint::{LateContext, LintContext};
use rustc_session::Session;
use rustc_span::source_map::{original_sp, SourceMap};
use rustc_span::{hygiene, BytePos, Pos, SourceFile, Span, SpanData, SyntaxContext, DUMMY_SP};
use rustc_span::{hygiene, BytePos, SourceFileAndLine, Pos, SourceFile, Span, SpanData, SyntaxContext, DUMMY_SP};
use std::borrow::Cow;
use std::ops::Range;
@ -117,9 +117,9 @@ fn first_char_in_first_line<T: LintContext>(cx: &T, span: Span) -> Option<BytePo
/// ```
fn line_span<T: LintContext>(cx: &T, span: Span) -> Span {
let span = original_sp(span, DUMMY_SP);
let source_map_and_line = cx.sess().source_map().lookup_line(span.lo()).unwrap();
let line_no = source_map_and_line.line;
let line_start = source_map_and_line.sf.lines(|lines| lines[line_no]);
let SourceFileAndLine { sf, line } = cx.sess().source_map().lookup_line(span.lo()).unwrap();
let line_start = sf.lines(|lines| lines[line]);
let line_start = sf.absolute_position(line_start);
span.with_lo(line_start)
}

View File

@ -268,7 +268,7 @@ impl ParseSess {
let source_file = self.parse_sess.source_map().lookup_char_pos(span.lo()).file;
SnippetProvider::new(
source_file.start_pos,
source_file.end_pos,
source_file.end_position(),
Lrc::clone(source_file.src.as_ref().unwrap()),
)
}