1use std::fs::File;
13use std::io::{self, BorrowedBuf, Read};
14use std::{fs, path};
15
16use rustc_data_structures::sync::{IntoDynSyncSend, MappedReadGuard, ReadGuard, RwLock};
17use rustc_data_structures::unhash::UnhashMap;
18use tracing::{debug, instrument, trace};
19
20use crate::*;
21
22#[cfg(test)]
23mod tests;
24
25pub fn original_sp(sp: Span, enclosing_sp: Span) -> Span {
29 let ctxt = sp.ctxt();
30 if ctxt.is_root() {
31 return sp;
32 }
33
34 let enclosing_ctxt = enclosing_sp.ctxt();
35 let expn_data1 = ctxt.outer_expn_data();
36 if !enclosing_ctxt.is_root()
37 && expn_data1.call_site == enclosing_ctxt.outer_expn_data().call_site
38 {
39 sp
40 } else {
41 original_sp(expn_data1.call_site, enclosing_sp)
42 }
43}
44
45mod monotonic {
46 use std::ops::{Deref, DerefMut};
47
48 pub struct MonotonicVec<T>(Vec<T>);
54 impl<T> MonotonicVec<T> {
55 pub(super) fn push(&mut self, val: T) {
56 self.0.push(val);
57 }
58 }
59
60 impl<T> Default for MonotonicVec<T> {
61 fn default() -> Self {
62 MonotonicVec(::alloc::vec::Vec::new()vec![])
63 }
64 }
65
66 impl<T> Deref for MonotonicVec<T> {
67 type Target = Vec<T>;
68 fn deref(&self) -> &Self::Target {
69 &self.0
70 }
71 }
72
73 impl<T> !DerefMut for MonotonicVec<T> {}
74}
75
76pub trait FileLoader {
82 fn file_exists(&self, path: &Path) -> bool;
84
85 fn read_file(&self, path: &Path) -> io::Result<String>;
89
90 fn read_binary_file(&self, path: &Path) -> io::Result<Arc<[u8]>>;
93
94 fn current_directory(&self) -> io::Result<PathBuf>;
96}
97
98pub struct RealFileLoader;
100
101impl FileLoader for RealFileLoader {
102 fn file_exists(&self, path: &Path) -> bool {
103 path.exists()
104 }
105
106 fn read_file(&self, path: &Path) -> io::Result<String> {
107 let mut file = File::open(path)?;
108 let size = file.metadata().map(|metadata| metadata.len()).ok().unwrap_or(0);
109
110 if size > SourceFile::MAX_FILE_SIZE.into() {
111 return Err(io::Error::other(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("text files larger than {0} bytes are unsupported",
SourceFile::MAX_FILE_SIZE))
})format!(
112 "text files larger than {} bytes are unsupported",
113 SourceFile::MAX_FILE_SIZE
114 )));
115 }
116 let mut contents = String::new();
117 file.read_to_string(&mut contents)?;
118 Ok(contents)
119 }
120
121 fn read_binary_file(&self, path: &Path) -> io::Result<Arc<[u8]>> {
122 let mut file = fs::File::open(path)?;
123 let len = file.metadata()?.len();
124
125 let mut bytes = Arc::new_uninit_slice(len as usize);
126 let mut buf = BorrowedBuf::from(Arc::get_mut(&mut bytes).unwrap());
127 match file.read_buf_exact(buf.unfilled()) {
128 Ok(()) => {}
129 Err(e) if e.kind() == io::ErrorKind::UnexpectedEof => {
130 drop(bytes);
131 return fs::read(path).map(Vec::into);
132 }
133 Err(e) => return Err(e),
134 }
135 let bytes = unsafe { bytes.assume_init() };
138
139 let mut probe = [0u8; 32];
149 let n = loop {
150 match file.read(&mut probe) {
151 Ok(0) => return Ok(bytes),
152 Err(e) if e.kind() == io::ErrorKind::Interrupted => continue,
153 Err(e) => return Err(e),
154 Ok(n) => break n,
155 }
156 };
157 let mut bytes: Vec<u8> = bytes.iter().copied().chain(probe[..n].iter().copied()).collect();
158 file.read_to_end(&mut bytes)?;
159 Ok(bytes.into())
160 }
161
162 fn current_directory(&self) -> io::Result<PathBuf> {
163 std::env::current_dir()
164 }
165}
166
167#[derive(#[automatically_derived]
impl ::core::default::Default for SourceMapFiles {
#[inline]
fn default() -> SourceMapFiles {
SourceMapFiles {
source_files: ::core::default::Default::default(),
stable_id_to_source_file: ::core::default::Default::default(),
}
}
}Default)]
172struct SourceMapFiles {
173 source_files: monotonic::MonotonicVec<Arc<SourceFile>>,
174 stable_id_to_source_file: UnhashMap<StableSourceFileId, Arc<SourceFile>>,
175}
176
177pub struct SourceMapInputs {
179 pub file_loader: Box<dyn FileLoader + Send + Sync>,
180 pub path_mapping: FilePathMapping,
181 pub hash_kind: SourceFileHashAlgorithm,
182 pub checksum_hash_kind: Option<SourceFileHashAlgorithm>,
183}
184
185pub struct SourceMap {
186 files: RwLock<SourceMapFiles>,
187 file_loader: IntoDynSyncSend<Box<dyn FileLoader + Sync + Send>>,
188
189 path_mapping: FilePathMapping,
192
193 working_dir: RealFileName,
195
196 hash_kind: SourceFileHashAlgorithm,
198
199 checksum_hash_kind: Option<SourceFileHashAlgorithm>,
204}
205
206impl SourceMap {
207 pub fn new(path_mapping: FilePathMapping) -> SourceMap {
208 Self::with_inputs(SourceMapInputs {
209 file_loader: Box::new(RealFileLoader),
210 path_mapping,
211 hash_kind: SourceFileHashAlgorithm::Md5,
212 checksum_hash_kind: None,
213 })
214 }
215
216 pub fn with_inputs(
217 SourceMapInputs { file_loader, path_mapping, hash_kind, checksum_hash_kind }: SourceMapInputs,
218 ) -> SourceMap {
219 let cwd = file_loader
220 .current_directory()
221 .expect("expecting a current working directory to exist");
222 let working_dir = path_mapping.to_real_filename(&RealFileName::empty(), &cwd);
223 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_span/src/source_map.rs:223",
"rustc_span::source_map", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_span/src/source_map.rs"),
::tracing_core::__macro_support::Option::Some(223u32),
::tracing_core::__macro_support::Option::Some("rustc_span::source_map"),
::tracing_core::field::FieldSet::new(&[{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("working_dir")
}> =
::tracing::__macro_support::FieldName::new("working_dir");
NAME.as_str()
}], ::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&working_dir)
as &dyn ::tracing::field::Value))])
});
} else { ; }
};debug!(?working_dir);
224 SourceMap {
225 files: Default::default(),
226 working_dir,
227 file_loader: IntoDynSyncSend(file_loader),
228 path_mapping,
229 hash_kind,
230 checksum_hash_kind,
231 }
232 }
233
234 pub fn path_mapping(&self) -> &FilePathMapping {
235 &self.path_mapping
236 }
237
238 pub fn working_dir(&self) -> &RealFileName {
239 &self.working_dir
240 }
241
242 pub fn file_exists(&self, path: &Path) -> bool {
243 self.file_loader.file_exists(path)
244 }
245
246 pub fn load_file(&self, path: &Path) -> io::Result<Arc<SourceFile>> {
247 let src = self.file_loader.read_file(path)?;
248 let filename = FileName::Real(self.path_mapping.to_real_filename(&self.working_dir, path));
249 Ok(self.new_source_file(filename, src))
250 }
251
252 pub fn load_binary_file(&self, path: &Path) -> io::Result<(Arc<[u8]>, Span)> {
257 let bytes = self.file_loader.read_binary_file(path)?;
258
259 let text = std::str::from_utf8(&bytes).unwrap_or("").to_string();
265 let filename = FileName::Real(self.path_mapping.to_real_filename(&self.working_dir, path));
266 let file = self.new_source_file(filename, text);
267 Ok((
268 bytes,
269 Span::new(
270 file.start_pos,
271 BytePos(file.start_pos.0 + file.normalized_source_len.0),
272 SyntaxContext::root(),
273 None,
274 ),
275 ))
276 }
277
278 pub fn files(&self) -> MappedReadGuard<'_, monotonic::MonotonicVec<Arc<SourceFile>>> {
281 ReadGuard::map(self.files.borrow(), |files| &files.source_files)
282 }
283
284 pub fn source_file_by_stable_id(
285 &self,
286 stable_id: StableSourceFileId,
287 ) -> Option<Arc<SourceFile>> {
288 self.files.borrow().stable_id_to_source_file.get(&stable_id).cloned()
289 }
290
291 fn register_source_file(
292 &self,
293 file_id: StableSourceFileId,
294 mut file: SourceFile,
295 ) -> Result<Arc<SourceFile>, OffsetOverflowError> {
296 let mut files = self.files.borrow_mut();
297
298 file.start_pos = BytePos(if let Some(last_file) = files.source_files.last() {
299 last_file.end_position().0.checked_add(1).ok_or(OffsetOverflowError)?
302 } else {
303 0
304 });
305
306 let file = Arc::new(file);
307 files.source_files.push(Arc::clone(&file));
308 files.stable_id_to_source_file.insert(file_id, Arc::clone(&file));
309
310 Ok(file)
311 }
312
313 pub fn new_source_file(&self, filename: FileName, src: String) -> Arc<SourceFile> {
317 self.try_new_source_file(filename, src).unwrap_or_else(|OffsetOverflowError| {
318 {
::std::io::_eprint(format_args!("fatal error: rustc does not support text files larger than {0} bytes\n",
SourceFile::MAX_FILE_SIZE));
};eprintln!(
319 "fatal error: rustc does not support text files larger than {} bytes",
320 SourceFile::MAX_FILE_SIZE
321 );
322 crate::fatal_error::FatalError.raise()
323 })
324 }
325
326 fn try_new_source_file(
327 &self,
328 filename: FileName,
329 src: String,
330 ) -> Result<Arc<SourceFile>, OffsetOverflowError> {
331 let stable_id = StableSourceFileId::from_filename_in_current_crate(&filename);
336 match self.source_file_by_stable_id(stable_id) {
337 Some(lrc_sf) => Ok(lrc_sf),
338 None => {
339 let source_file =
340 SourceFile::new(filename, src, self.hash_kind, self.checksum_hash_kind)?;
341
342 if true {
{
match (&source_file.stable_id, &stable_id) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
}
};
};debug_assert_eq!(source_file.stable_id, stable_id);
345
346 self.register_source_file(stable_id, source_file)
347 }
348 }
349 }
350
351 pub fn new_imported_source_file(
356 &self,
357 filename: FileName,
358 src_hash: SourceFileHash,
359 checksum_hash: Option<SourceFileHash>,
360 stable_id: StableSourceFileId,
361 normalized_source_len: u32,
362 unnormalized_source_len: u32,
363 cnum: CrateNum,
364 file_local_lines: FreezeLock<SourceFileLines>,
365 multibyte_chars: Vec<MultiByteChar>,
366 normalized_pos: Vec<NormalizedPos>,
367 metadata_index: u32,
368 ) -> Arc<SourceFile> {
369 let normalized_source_len = RelativeBytePos::from_u32(normalized_source_len);
370
371 let source_file = SourceFile {
372 name: filename,
373 src: None,
374 src_hash,
375 checksum_hash,
376 external_src: FreezeLock::new(ExternalSource::Foreign {
377 kind: ExternalSourceKind::AbsentOk,
378 metadata_index,
379 }),
380 start_pos: BytePos(0),
381 normalized_source_len,
382 unnormalized_source_len,
383 lines: file_local_lines,
384 multibyte_chars,
385 normalized_pos,
386 stable_id,
387 cnum,
388 };
389
390 self.register_source_file(stable_id, source_file)
391 .expect("not enough address space for imported source file")
392 }
393
394 pub fn doctest_offset_line(&self, file: &FileName, orig: usize) -> usize {
396 match file {
397 FileName::DocTest(_, offset) => {
398 if *offset < 0 {
399 orig - (-(*offset)) as usize
400 } else {
401 orig + *offset as usize
402 }
403 }
404 _ => orig,
405 }
406 }
407
408 pub fn lookup_source_file(&self, pos: BytePos) -> Arc<SourceFile> {
410 let idx = self.lookup_source_file_idx(pos);
411 Arc::clone(&(*self.files.borrow().source_files)[idx])
412 }
413
414 pub fn lookup_char_pos(&self, pos: BytePos) -> Loc {
416 let sf = self.lookup_source_file(pos);
417 let (line, col, col_display) = sf.lookup_file_pos_with_col_display(pos);
418 Loc { file: sf, line, col, col_display }
419 }
420
421 pub fn lookup_line(&self, pos: BytePos) -> Result<SourceFileAndLine, Arc<SourceFile>> {
423 let f = self.lookup_source_file(pos);
424
425 let pos = f.relative_position(pos);
426 match f.lookup_line(pos) {
427 Some(line) => Ok(SourceFileAndLine { sf: f, line }),
428 None => Err(f),
429 }
430 }
431
432 pub fn span_to_string(&self, sp: Span, display_scope: RemapPathScopeComponents) -> String {
433 self.span_to_string_ext(sp, display_scope, false)
434 }
435
436 pub fn span_to_short_string(
437 &self,
438 sp: Span,
439 display_scope: RemapPathScopeComponents,
440 ) -> String {
441 self.span_to_string_ext(sp, display_scope, true)
442 }
443
444 fn span_to_string_ext(
445 &self,
446 sp: Span,
447 display_scope: RemapPathScopeComponents,
448 short: bool,
449 ) -> String {
450 let (source_file, lo_line, lo_col, hi_line, hi_col) = self.span_to_location_info(sp);
451
452 let file_name = match source_file {
453 Some(sf) => {
454 if short { sf.name.short() } else { sf.name.display(display_scope) }.to_string()
455 }
456 None => return "no-location".to_string(),
457 };
458
459 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{1}:{2}:{3}{0}",
if short {
String::new()
} else {
::alloc::__export::must_use({
::alloc::fmt::format(format_args!(": {0}:{1}", hi_line,
hi_col))
})
}, file_name, lo_line, lo_col))
})format!(
460 "{file_name}:{lo_line}:{lo_col}{}",
461 if short { String::new() } else { format!(": {hi_line}:{hi_col}") }
462 )
463 }
464
465 pub fn span_to_location_info(
466 &self,
467 sp: Span,
468 ) -> (Option<Arc<SourceFile>>, usize, usize, usize, usize) {
469 if self.files.borrow().source_files.is_empty() || sp.is_dummy() {
470 return (None, 0, 0, 0, 0);
471 }
472
473 let lo = self.lookup_char_pos(sp.lo());
474 let hi = self.lookup_char_pos(sp.hi());
475 (Some(lo.file), lo.line, lo.col.to_usize() + 1, hi.line, hi.col.to_usize() + 1)
476 }
477
478 pub fn span_to_diagnostic_string(&self, sp: Span) -> String {
482 self.span_to_string(sp, RemapPathScopeComponents::DIAGNOSTICS)
483 }
484
485 pub fn span_to_filename(&self, sp: Span) -> FileName {
486 self.lookup_char_pos(sp.lo()).file.name.clone()
487 }
488
489 pub fn filename_for_diagnostics<'a>(&self, filename: &'a FileName) -> FileNameDisplay<'a> {
490 filename.display(RemapPathScopeComponents::DIAGNOSTICS)
491 }
492
493 pub fn is_multiline(&self, sp: Span) -> bool {
494 let lo = self.lookup_source_file_idx(sp.lo());
495 let hi = self.lookup_source_file_idx(sp.hi());
496 if lo != hi {
497 return true;
498 }
499 let f = Arc::clone(&(*self.files.borrow().source_files)[lo]);
500 let lo = f.relative_position(sp.lo());
501 let hi = f.relative_position(sp.hi());
502 f.lookup_line(lo) != f.lookup_line(hi)
503 }
504
505 #[allow(clippy :: suspicious_else_formatting)]
{
let __tracing_attr_span;
let __tracing_attr_guard;
if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::TRACE <=
::tracing::level_filters::LevelFilter::current() ||
{ false } {
__tracing_attr_span =
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("is_valid_span",
"rustc_span::source_map", ::tracing::Level::TRACE,
::tracing_core::__macro_support::Option::Some("compiler/rustc_span/src/source_map.rs"),
::tracing_core::__macro_support::Option::Some(505u32),
::tracing_core::__macro_support::Option::Some("rustc_span::source_map"),
::tracing_core::field::FieldSet::new(&[{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("sp")
}> =
::tracing::__macro_support::FieldName::new("sp");
NAME.as_str()
}], ::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::SPAN)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let mut interest = ::tracing::subscriber::Interest::never();
if ::tracing::Level::TRACE <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::TRACE <=
::tracing::level_filters::LevelFilter::current() &&
{ interest = __CALLSITE.interest(); !interest.is_never() }
&&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest) {
let meta = __CALLSITE.metadata();
::tracing::Span::new(meta,
&{
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
meta.fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&sp)
as &dyn ::tracing::field::Value))])
})
} else {
let span =
::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
{};
span
}
};
__tracing_attr_guard = __tracing_attr_span.enter();
}
#[warn(clippy :: suspicious_else_formatting)]
{
#[allow(unknown_lints, unreachable_code, clippy ::
diverging_sub_expression, clippy :: empty_loop, clippy ::
let_unit_value, clippy :: let_with_type_underscore, clippy ::
needless_return, clippy :: unreachable)]
if false {
let __tracing_attr_fake_return:
Result<(Loc, Loc), SpanLinesError> = loop {};
return __tracing_attr_fake_return;
}
{
let lo = self.lookup_char_pos(sp.lo());
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_span/src/source_map.rs:508",
"rustc_span::source_map", ::tracing::Level::TRACE,
::tracing_core::__macro_support::Option::Some("compiler/rustc_span/src/source_map.rs"),
::tracing_core::__macro_support::Option::Some(508u32),
::tracing_core::__macro_support::Option::Some("rustc_span::source_map"),
::tracing_core::field::FieldSet::new(&[{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("lo")
}> =
::tracing::__macro_support::FieldName::new("lo");
NAME.as_str()
}], ::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::TRACE <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::TRACE <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&lo)
as &dyn ::tracing::field::Value))])
});
} else { ; }
};
let hi = self.lookup_char_pos(sp.hi());
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_span/src/source_map.rs:510",
"rustc_span::source_map", ::tracing::Level::TRACE,
::tracing_core::__macro_support::Option::Some("compiler/rustc_span/src/source_map.rs"),
::tracing_core::__macro_support::Option::Some(510u32),
::tracing_core::__macro_support::Option::Some("rustc_span::source_map"),
::tracing_core::field::FieldSet::new(&[{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("hi")
}> =
::tracing::__macro_support::FieldName::new("hi");
NAME.as_str()
}], ::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::TRACE <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::TRACE <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&hi)
as &dyn ::tracing::field::Value))])
});
} else { ; }
};
if lo.file.start_pos != hi.file.start_pos {
return Err(SpanLinesError::DistinctSources(Box::new(DistinctSources {
begin: (lo.file.name.clone(), lo.file.start_pos),
end: (hi.file.name.clone(), hi.file.start_pos),
})));
}
Ok((lo, hi))
}
}
}#[instrument(skip(self), level = "trace")]
506 pub fn is_valid_span(&self, sp: Span) -> Result<(Loc, Loc), SpanLinesError> {
507 let lo = self.lookup_char_pos(sp.lo());
508 trace!(?lo);
509 let hi = self.lookup_char_pos(sp.hi());
510 trace!(?hi);
511 if lo.file.start_pos != hi.file.start_pos {
512 return Err(SpanLinesError::DistinctSources(Box::new(DistinctSources {
513 begin: (lo.file.name.clone(), lo.file.start_pos),
514 end: (hi.file.name.clone(), hi.file.start_pos),
515 })));
516 }
517 Ok((lo, hi))
518 }
519
520 pub fn is_line_before_span_empty(&self, sp: Span) -> bool {
521 match self.span_to_prev_source(sp) {
522 Ok(s) => s.rsplit_once('\n').unwrap_or(("", &s)).1.trim_start().is_empty(),
523 Err(_) => false,
524 }
525 }
526
527 pub fn span_to_lines(&self, sp: Span) -> FileLinesResult {
528 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_span/src/source_map.rs:528",
"rustc_span::source_map", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_span/src/source_map.rs"),
::tracing_core::__macro_support::Option::Some(528u32),
::tracing_core::__macro_support::Option::Some("rustc_span::source_map"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("span_to_lines(sp={0:?})",
sp) as &dyn ::tracing::field::Value))])
});
} else { ; }
};debug!("span_to_lines(sp={:?})", sp);
529 let (lo, hi) = self.is_valid_span(sp)?;
530 if !(hi.line >= lo.line) {
::core::panicking::panic("assertion failed: hi.line >= lo.line")
};assert!(hi.line >= lo.line);
531
532 if sp.is_dummy() {
533 return Ok(FileLines { file: lo.file, lines: Vec::new() });
534 }
535
536 let mut lines = Vec::with_capacity(hi.line - lo.line + 1);
537
538 let mut start_col = lo.col;
541
542 let hi_line = hi.line.saturating_sub(1);
550 for line_index in lo.line.saturating_sub(1)..hi_line {
551 let line_len = lo.file.get_line(line_index).map_or(0, |s| s.chars().count());
552 lines.push(LineInfo { line_index, start_col, end_col: CharPos::from_usize(line_len) });
553 start_col = CharPos::from_usize(0);
554 }
555
556 lines.push(LineInfo { line_index: hi_line, start_col, end_col: hi.col });
558
559 Ok(FileLines { file: lo.file, lines })
560 }
561
562 pub fn span_to_source<F, T>(&self, sp: Span, extract_source: F) -> Result<T, SpanSnippetError>
566 where
567 F: Fn(&str, usize, usize) -> Result<T, SpanSnippetError>,
568 {
569 let local_begin = self.lookup_byte_offset(sp.lo());
570 let local_end = self.lookup_byte_offset(sp.hi());
571
572 if local_begin.sf.start_pos != local_end.sf.start_pos {
573 Err(SpanSnippetError::DistinctSources(Box::new(DistinctSources {
574 begin: (local_begin.sf.name.clone(), local_begin.sf.start_pos),
575 end: (local_end.sf.name.clone(), local_end.sf.start_pos),
576 })))
577 } else {
578 self.ensure_source_file_source_present(&local_begin.sf);
579
580 let start_index = local_begin.pos.to_usize();
581 let end_index = local_end.pos.to_usize();
582 let source_len = local_begin.sf.normalized_source_len.to_usize();
583
584 if start_index > end_index || end_index > source_len {
585 return Err(SpanSnippetError::MalformedForSourcemap(MalformedSourceMapPositions {
586 name: local_begin.sf.name.clone(),
587 source_len,
588 begin_pos: local_begin.pos,
589 end_pos: local_end.pos,
590 }));
591 }
592
593 if let Some(ref src) = local_begin.sf.src {
594 extract_source(src, start_index, end_index)
595 } else if let Some(src) = local_begin.sf.external_src.read().get_source() {
596 extract_source(src, start_index, end_index)
597 } else {
598 Err(SpanSnippetError::SourceNotAvailable { filename: local_begin.sf.name.clone() })
599 }
600 }
601 }
602
603 pub fn is_span_accessible(&self, sp: Span) -> bool {
604 self.span_to_source(sp, |src, start_index, end_index| {
605 Ok(src.get(start_index..end_index).is_some())
606 })
607 .is_ok_and(|is_accessible| is_accessible)
608 }
609
610 pub fn span_to_snippet(&self, sp: Span) -> Result<String, SpanSnippetError> {
612 self.span_to_source(sp, |src, start_index, end_index| {
613 src.get(start_index..end_index)
614 .map(|s| s.to_string())
615 .ok_or(SpanSnippetError::IllFormedSpan(sp))
616 })
617 }
618
619 pub fn span_to_margin(&self, sp: Span) -> Option<usize> {
620 Some(self.indentation_before(sp)?.len())
621 }
622
623 pub fn indentation_before(&self, sp: Span) -> Option<String> {
624 self.span_to_source(sp, |src, start_index, _| {
625 let before = &src[..start_index];
626 let last_line = before.rsplit_once('\n').map_or(before, |(_, last)| last);
627 Ok(last_line
628 .split_once(|c: char| !c.is_whitespace())
629 .map_or(last_line, |(indent, _)| indent)
630 .to_string())
631 })
632 .ok()
633 }
634
635 pub fn span_to_prev_source(&self, sp: Span) -> Result<String, SpanSnippetError> {
637 self.span_to_source(sp, |src, start_index, _| {
638 src.get(..start_index).map(|s| s.to_string()).ok_or(SpanSnippetError::IllFormedSpan(sp))
639 })
640 }
641
642 pub fn span_extend_to_prev_char(&self, sp: Span, c: char, accept_newlines: bool) -> Span {
645 if let Ok(prev_source) = self.span_to_prev_source(sp) {
646 let prev_source = prev_source.rsplit(c).next().unwrap_or("");
647 if !prev_source.is_empty() && (accept_newlines || !prev_source.contains('\n')) {
648 return sp.with_lo(BytePos(sp.lo().0 - prev_source.len() as u32));
649 }
650 }
651
652 sp
653 }
654
655 pub fn span_extend_to_prev_char_before(
658 &self,
659 sp: Span,
660 c: char,
661 accept_newlines: bool,
662 ) -> Span {
663 if let Ok(prev_source) = self.span_to_prev_source(sp) {
664 let prev_source = prev_source.rsplit(c).next().unwrap_or("");
665 if accept_newlines || !prev_source.contains('\n') {
666 return sp.with_lo(BytePos(sp.lo().0 - prev_source.len() as u32 - 1_u32));
667 }
668 }
669
670 sp
671 }
672
673 pub fn span_extend_to_prev_str(
677 &self,
678 sp: Span,
679 pat: &str,
680 accept_newlines: bool,
681 include_whitespace: bool,
682 ) -> Option<Span> {
683 let prev_source = self.span_to_prev_source(sp).ok()?;
688 for ws in &[" ", "\t", "\n"] {
689 let pat = pat.to_owned() + ws;
690 if let Some(pat_pos) = prev_source.rfind(&pat) {
691 let just_after_pat_pos = pat_pos + pat.len() - 1;
692 let just_after_pat_plus_ws = if include_whitespace {
693 just_after_pat_pos
694 + prev_source[just_after_pat_pos..]
695 .find(|c: char| !c.is_whitespace())
696 .unwrap_or(0)
697 } else {
698 just_after_pat_pos
699 };
700 let len = prev_source.len() - just_after_pat_plus_ws;
701 let prev_source = &prev_source[just_after_pat_plus_ws..];
702 if accept_newlines || !prev_source.trim_start().contains('\n') {
703 return Some(sp.with_lo(BytePos(sp.lo().0 - len as u32)));
704 }
705 }
706 }
707
708 None
709 }
710
711 pub fn span_to_next_source(&self, sp: Span) -> Result<String, SpanSnippetError> {
713 self.span_to_source(sp, |src, _, end_index| {
714 src.get(end_index..).map(|s| s.to_string()).ok_or(SpanSnippetError::IllFormedSpan(sp))
715 })
716 }
717
718 pub fn span_extend_while(
720 &self,
721 span: Span,
722 f: impl Fn(char) -> bool,
723 ) -> Result<Span, SpanSnippetError> {
724 self.span_to_source(span, |s, _start, end| {
725 let n = s[end..].char_indices().find(|&(_, c)| !f(c)).map_or(s.len() - end, |(i, _)| i);
726 Ok(span.with_hi(span.hi() + BytePos(n as u32)))
727 })
728 }
729
730 pub fn span_extend_while_whitespace(&self, span: Span) -> Span {
733 self.span_extend_while(span, char::is_whitespace).unwrap_or(span)
734 }
735
736 pub fn span_extend_prev_while(
738 &self,
739 span: Span,
740 f: impl Fn(char) -> bool,
741 ) -> Result<Span, SpanSnippetError> {
742 self.span_to_source(span, |s, start, _end| {
743 let n = s[..start]
744 .char_indices()
745 .rfind(|&(_, c)| !f(c))
746 .map_or(start, |(i, c)| start - i - c.len_utf8());
747 Ok(span.with_lo(span.lo() - BytePos(n as u32)))
748 })
749 }
750
751 pub fn span_extend_to_next_char(&self, sp: Span, c: char, accept_newlines: bool) -> Span {
753 if let Ok(next_source) = self.span_to_next_source(sp) {
754 let next_source = next_source.split(c).next().unwrap_or("");
755 if !next_source.is_empty() && (accept_newlines || !next_source.contains('\n')) {
756 return sp.with_hi(BytePos(sp.hi().0 + next_source.len() as u32));
757 }
758 }
759
760 sp
761 }
762
763 pub fn span_extend_to_line(&self, sp: Span) -> Span {
765 self.span_extend_to_prev_char(self.span_extend_to_next_char(sp, '\n', true), '\n', true)
766 }
767
768 pub fn span_until_char(&self, sp: Span, c: char) -> Span {
771 match self.span_to_snippet(sp) {
772 Ok(snippet) => {
773 let snippet = snippet.split(c).next().unwrap_or("").trim_end();
774 if !snippet.is_empty() && !snippet.contains('\n') {
775 sp.with_hi(BytePos(sp.lo().0 + snippet.len() as u32))
776 } else {
777 sp
778 }
779 }
780 _ => sp,
781 }
782 }
783
784 pub fn span_wrapped_by_angle_or_parentheses(&self, span: Span) -> bool {
789 self.span_to_source(span, |src, start_index, end_index| {
790 if src.get(start_index..end_index).is_none() {
791 return Ok(false);
792 }
793 let end_src = &src[end_index..];
795 let mut i = 0;
796 let mut found_right_parentheses = false;
797 let mut found_right_angle = false;
798 while let Some(cc) = end_src.chars().nth(i) {
799 if cc == ' ' {
800 i = i + 1;
801 } else if cc == '>' {
802 found_right_angle = true;
804 break;
805 } else if cc == ')' {
806 found_right_parentheses = true;
807 break;
808 } else {
809 return Ok(false);
811 }
812 }
813 i = start_index;
815 let start_src = &src[0..start_index];
816 while let Some(cc) = start_src.chars().nth(i) {
817 if cc == ' ' {
818 if i == 0 {
819 return Ok(false);
820 }
821 i = i - 1;
822 } else if cc == '<' {
823 if !found_right_angle {
825 return Ok(false);
827 }
828 break;
829 } else if cc == '(' {
830 if !found_right_parentheses {
831 return Ok(false);
833 }
834 break;
835 } else {
836 return Ok(false);
838 }
839 }
840 Ok(true)
841 })
842 .is_ok_and(|is_accessible| is_accessible)
843 }
844
845 pub fn span_through_char(&self, sp: Span, c: char) -> Span {
848 if let Ok(snippet) = self.span_to_snippet(sp)
849 && let Some(offset) = snippet.find(c)
850 {
851 return sp.with_hi(BytePos(sp.lo().0 + (offset + c.len_utf8()) as u32));
852 }
853 sp
854 }
855
856 pub fn span_until_non_whitespace(&self, sp: Span) -> Span {
861 let mut whitespace_found = false;
862
863 self.span_take_while(sp, |c| {
864 if !whitespace_found && c.is_whitespace() {
865 whitespace_found = true;
866 }
867
868 !whitespace_found || c.is_whitespace()
869 })
870 }
871
872 pub fn span_until_whitespace(&self, sp: Span) -> Span {
877 self.span_take_while(sp, |c| !c.is_whitespace())
878 }
879
880 pub fn span_take_while<P>(&self, sp: Span, predicate: P) -> Span
882 where
883 P: for<'r> FnMut(&'r char) -> bool,
884 {
885 if let Ok(snippet) = self.span_to_snippet(sp) {
886 let offset = snippet.chars().take_while(predicate).map(|c| c.len_utf8()).sum::<usize>();
887
888 sp.with_hi(BytePos(sp.lo().0 + (offset as u32)))
889 } else {
890 sp
891 }
892 }
893
894 pub fn guess_head_span(&self, sp: Span) -> Span {
900 self.span_until_char(sp, '{')
903 }
904
905 pub fn start_point(&self, sp: Span) -> Span {
907 let width = {
908 let sp = sp.data();
909 let local_begin = self.lookup_byte_offset(sp.lo);
910 let start_index = local_begin.pos.to_usize();
911 let src = local_begin.sf.external_src.read();
912
913 let snippet = if let Some(ref src) = local_begin.sf.src {
914 Some(&src[start_index..])
915 } else {
916 src.get_source().map(|src| &src[start_index..])
917 };
918
919 match snippet {
920 None => 1,
921 Some(snippet) => match snippet.chars().next() {
922 None => 1,
923 Some(c) => c.len_utf8(),
924 },
925 }
926 };
927
928 sp.with_hi(BytePos(sp.lo().0 + width as u32))
929 }
930
931 pub fn end_point(&self, sp: Span) -> Span {
933 let sp = sp.data();
934 let pos = sp.hi.0;
935
936 let width = self.find_width_of_character_at_span(sp, false);
937 let corrected_end_position = pos.checked_sub(width).unwrap_or(pos);
938
939 let end_point = BytePos(cmp::max(corrected_end_position, sp.lo.0));
940 sp.with_lo(end_point)
941 }
942
943 pub fn next_point(&self, sp: Span) -> Span {
950 if sp.is_dummy() {
951 return sp;
952 }
953
954 let sp = sp.data();
955 let start_of_next_point = sp.hi.0;
956 let width = self.find_width_of_character_at_span(sp, true);
957 let end_of_next_point =
961 start_of_next_point.checked_add(width).unwrap_or(start_of_next_point);
962
963 let end_of_next_point = BytePos(cmp::max(start_of_next_point + 1, end_of_next_point));
964 Span::new(BytePos(start_of_next_point), end_of_next_point, sp.ctxt, None)
965 }
966
967 pub fn span_followed_by(&self, span: Span, target: &str) -> Option<Span> {
970 let span = self.span_extend_while_whitespace(span);
971 self.span_to_next_source(span).ok()?.strip_prefix(target).map(|_| {
972 Span::new(span.hi(), span.hi() + BytePos(target.len() as u32), span.ctxt(), None)
973 })
974 }
975
976 #[allow(clippy :: suspicious_else_formatting)]
{
let __tracing_attr_span;
let __tracing_attr_guard;
if ::tracing::Level::INFO <= ::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::INFO <=
::tracing::level_filters::LevelFilter::current() ||
{ false } {
__tracing_attr_span =
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("find_width_of_character_at_span",
"rustc_span::source_map", ::tracing::Level::INFO,
::tracing_core::__macro_support::Option::Some("compiler/rustc_span/src/source_map.rs"),
::tracing_core::__macro_support::Option::Some(978u32),
::tracing_core::__macro_support::Option::Some("rustc_span::source_map"),
::tracing_core::field::FieldSet::new(&[{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("forwards")
}> =
::tracing::__macro_support::FieldName::new("forwards");
NAME.as_str()
}], ::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::SPAN)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let mut interest = ::tracing::subscriber::Interest::never();
if ::tracing::Level::INFO <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::INFO <=
::tracing::level_filters::LevelFilter::current() &&
{ interest = __CALLSITE.interest(); !interest.is_never() }
&&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest) {
let meta = __CALLSITE.metadata();
::tracing::Span::new(meta,
&{
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
meta.fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&forwards
as &dyn ::tracing::field::Value))])
})
} else {
let span =
::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
{};
span
}
};
__tracing_attr_guard = __tracing_attr_span.enter();
}
#[warn(clippy :: suspicious_else_formatting)]
{
#[allow(unknown_lints, unreachable_code, clippy ::
diverging_sub_expression, clippy :: empty_loop, clippy ::
let_unit_value, clippy :: let_with_type_underscore, clippy ::
needless_return, clippy :: unreachable)]
if false {
let __tracing_attr_fake_return: u32 = loop {};
return __tracing_attr_fake_return;
}
{
if sp.lo == sp.hi && !forwards {
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_span/src/source_map.rs:981",
"rustc_span::source_map", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_span/src/source_map.rs"),
::tracing_core::__macro_support::Option::Some(981u32),
::tracing_core::__macro_support::Option::Some("rustc_span::source_map"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("early return empty span")
as &dyn ::tracing::field::Value))])
});
} else { ; }
};
return 1;
}
let local_begin = self.lookup_byte_offset(sp.lo);
let local_end = self.lookup_byte_offset(sp.hi);
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_span/src/source_map.rs:987",
"rustc_span::source_map", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_span/src/source_map.rs"),
::tracing_core::__macro_support::Option::Some(987u32),
::tracing_core::__macro_support::Option::Some("rustc_span::source_map"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("local_begin=`{0:?}`, local_end=`{1:?}`",
local_begin, local_end) as &dyn ::tracing::field::Value))])
});
} else { ; }
};
if local_begin.sf.start_pos != local_end.sf.start_pos {
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_span/src/source_map.rs:990",
"rustc_span::source_map", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_span/src/source_map.rs"),
::tracing_core::__macro_support::Option::Some(990u32),
::tracing_core::__macro_support::Option::Some("rustc_span::source_map"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("begin and end are in different files")
as &dyn ::tracing::field::Value))])
});
} else { ; }
};
return 1;
}
let start_index = local_begin.pos.to_usize();
let end_index = local_end.pos.to_usize();
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_span/src/source_map.rs:996",
"rustc_span::source_map", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_span/src/source_map.rs"),
::tracing_core::__macro_support::Option::Some(996u32),
::tracing_core::__macro_support::Option::Some("rustc_span::source_map"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("start_index=`{0:?}`, end_index=`{1:?}`",
start_index, end_index) as &dyn ::tracing::field::Value))])
});
} else { ; }
};
if (!forwards && end_index == usize::MIN) ||
(forwards && start_index == usize::MAX) {
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_span/src/source_map.rs:1001",
"rustc_span::source_map", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_span/src/source_map.rs"),
::tracing_core::__macro_support::Option::Some(1001u32),
::tracing_core::__macro_support::Option::Some("rustc_span::source_map"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("start or end of span, cannot be multibyte")
as &dyn ::tracing::field::Value))])
});
} else { ; }
};
return 1;
}
let source_len = local_begin.sf.normalized_source_len.to_usize();
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_span/src/source_map.rs:1006",
"rustc_span::source_map", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_span/src/source_map.rs"),
::tracing_core::__macro_support::Option::Some(1006u32),
::tracing_core::__macro_support::Option::Some("rustc_span::source_map"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("source_len=`{0:?}`",
source_len) as &dyn ::tracing::field::Value))])
});
} else { ; }
};
if start_index > end_index || end_index > source_len - 1 {
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_span/src/source_map.rs:1009",
"rustc_span::source_map", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_span/src/source_map.rs"),
::tracing_core::__macro_support::Option::Some(1009u32),
::tracing_core::__macro_support::Option::Some("rustc_span::source_map"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("source indexes are malformed")
as &dyn ::tracing::field::Value))])
});
} else { ; }
};
return 1;
}
let src = local_begin.sf.external_src.read();
let snippet =
if let Some(src) = &local_begin.sf.src {
src
} else if let Some(src) = src.get_source() {
src
} else { return 1; };
if forwards {
(snippet.ceil_char_boundary(end_index + 1) - end_index) as u32
} else {
(end_index - snippet.floor_char_boundary(end_index - 1)) as
u32
}
}
}
}#[instrument(skip(self, sp))]
979 fn find_width_of_character_at_span(&self, sp: SpanData, forwards: bool) -> u32 {
980 if sp.lo == sp.hi && !forwards {
981 debug!("early return empty span");
982 return 1;
983 }
984
985 let local_begin = self.lookup_byte_offset(sp.lo);
986 let local_end = self.lookup_byte_offset(sp.hi);
987 debug!("local_begin=`{:?}`, local_end=`{:?}`", local_begin, local_end);
988
989 if local_begin.sf.start_pos != local_end.sf.start_pos {
990 debug!("begin and end are in different files");
991 return 1;
992 }
993
994 let start_index = local_begin.pos.to_usize();
995 let end_index = local_end.pos.to_usize();
996 debug!("start_index=`{:?}`, end_index=`{:?}`", start_index, end_index);
997
998 if (!forwards && end_index == usize::MIN) || (forwards && start_index == usize::MAX) {
1001 debug!("start or end of span, cannot be multibyte");
1002 return 1;
1003 }
1004
1005 let source_len = local_begin.sf.normalized_source_len.to_usize();
1006 debug!("source_len=`{:?}`", source_len);
1007 if start_index > end_index || end_index > source_len - 1 {
1009 debug!("source indexes are malformed");
1010 return 1;
1011 }
1012
1013 let src = local_begin.sf.external_src.read();
1014
1015 let snippet = if let Some(src) = &local_begin.sf.src {
1016 src
1017 } else if let Some(src) = src.get_source() {
1018 src
1019 } else {
1020 return 1;
1021 };
1022
1023 if forwards {
1024 (snippet.ceil_char_boundary(end_index + 1) - end_index) as u32
1025 } else {
1026 (end_index - snippet.floor_char_boundary(end_index - 1)) as u32
1027 }
1028 }
1029
1030 pub fn get_source_file(&self, filename: &FileName) -> Option<Arc<SourceFile>> {
1031 for sf in self.files.borrow().source_files.iter() {
1032 if *filename == sf.name {
1033 return Some(Arc::clone(&sf));
1034 }
1035 }
1036 None
1037 }
1038
1039 pub fn lookup_byte_offset(&self, bpos: BytePos) -> SourceFileAndBytePos {
1041 let idx = self.lookup_source_file_idx(bpos);
1042 let sf = Arc::clone(&(*self.files.borrow().source_files)[idx]);
1043 let offset = bpos - sf.start_pos;
1044 SourceFileAndBytePos { sf, pos: offset }
1045 }
1046
1047 pub fn lookup_source_file_idx(&self, pos: BytePos) -> usize {
1051 self.files.borrow().source_files.partition_point(|x| x.start_pos <= pos) - 1
1052 }
1053
1054 pub fn count_lines(&self) -> usize {
1055 self.files().iter().fold(0, |a, f| a + f.count_lines())
1056 }
1057
1058 pub fn ensure_source_file_source_present(&self, source_file: &SourceFile) -> bool {
1059 source_file.add_external_src(|| {
1060 let FileName::Real(ref name) = source_file.name else {
1061 return None;
1062 };
1063
1064 let local_path: Cow<'_, Path> = match name.local_path() {
1065 Some(local) => local.into(),
1066 None => {
1067 let maybe_remapped_path = name.path(RemapPathScopeComponents::DIAGNOSTICS);
1074 self.path_mapping
1075 .reverse_map_prefix_heuristically(maybe_remapped_path)
1076 .map(Cow::from)
1077 .unwrap_or(maybe_remapped_path.into())
1078 }
1079 };
1080
1081 self.file_loader.read_file(&local_path).ok()
1082 })
1083 }
1084
1085 pub fn is_imported(&self, sp: Span) -> bool {
1086 let source_file_index = self.lookup_source_file_idx(sp.lo());
1087 let source_file = &self.files()[source_file_index];
1088 source_file.is_imported()
1089 }
1090
1091 pub fn stmt_span(&self, stmt_span: Span, block_span: Span) -> Span {
1095 if !stmt_span.from_expansion() {
1096 return stmt_span;
1097 }
1098 let mac_call = original_sp(stmt_span, block_span);
1099 self.mac_call_stmt_semi_span(mac_call).map_or(mac_call, |s| mac_call.with_hi(s.hi()))
1100 }
1101
1102 pub fn mac_call_stmt_semi_span(&self, mac_call: Span) -> Option<Span> {
1110 let span = self.span_extend_while_whitespace(mac_call);
1111 let span = self.next_point(span);
1112 if self.span_to_snippet(span).as_deref() == Ok(";") { Some(span) } else { None }
1113 }
1114}
1115
1116pub fn get_source_map() -> Option<Arc<SourceMap>> {
1117 with_session_globals(|session_globals| session_globals.source_map.clone())
1118}
1119
1120#[derive(#[automatically_derived]
impl ::core::clone::Clone for FilePathMapping {
#[inline]
fn clone(&self) -> FilePathMapping {
FilePathMapping {
mapping: ::core::clone::Clone::clone(&self.mapping),
filename_remapping_scopes: ::core::clone::Clone::clone(&self.filename_remapping_scopes),
}
}
}Clone)]
1121pub struct FilePathMapping {
1122 mapping: Vec<(PathBuf, PathBuf)>,
1123 filename_remapping_scopes: RemapPathScopeComponents,
1124}
1125
1126impl FilePathMapping {
1127 pub fn empty() -> FilePathMapping {
1128 FilePathMapping::new(Vec::new(), RemapPathScopeComponents::empty())
1129 }
1130
1131 pub fn new(
1132 mapping: Vec<(PathBuf, PathBuf)>,
1133 filename_remapping_scopes: RemapPathScopeComponents,
1134 ) -> FilePathMapping {
1135 FilePathMapping { mapping, filename_remapping_scopes }
1136 }
1137
1138 fn map_prefix<'a>(&'a self, path: impl Into<Cow<'a, Path>>) -> (Cow<'a, Path>, bool) {
1142 let path = path.into();
1143 if path.as_os_str().is_empty() {
1144 return (path, false);
1147 }
1148
1149 return remap_path_prefix(&self.mapping, path);
1150
1151 x;#[instrument(level = "debug", skip(mapping), ret)]
1152 fn remap_path_prefix<'a>(
1153 mapping: &'a [(PathBuf, PathBuf)],
1154 path: Cow<'a, Path>,
1155 ) -> (Cow<'a, Path>, bool) {
1156 for (from, to) in mapping.iter().rev() {
1160 debug!("Trying to apply {from:?} => {to:?}");
1161
1162 if let Ok(rest) = path.strip_prefix(from) {
1163 let remapped = if rest.as_os_str().is_empty() {
1164 to.into()
1171 } else {
1172 to.join(rest).into()
1173 };
1174 debug!("Match - remapped");
1175
1176 return (remapped, true);
1177 } else {
1178 debug!("No match - prefix {from:?} does not match");
1179 }
1180 }
1181
1182 debug!("not remapped");
1183 (path, false)
1184 }
1185 }
1186
1187 pub fn to_real_filename<'a>(
1192 &self,
1193 working_directory: &RealFileName,
1194 local_path: impl Into<Cow<'a, Path>>,
1195 ) -> RealFileName {
1196 let local_path = local_path.into();
1197
1198 let (remapped_path, mut was_remapped) = self.map_prefix(&*local_path);
1199 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_span/src/source_map.rs:1199",
"rustc_span::source_map", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_span/src/source_map.rs"),
::tracing_core::__macro_support::Option::Some(1199u32),
::tracing_core::__macro_support::Option::Some("rustc_span::source_map"),
::tracing_core::field::FieldSet::new(&[{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("local_path")
}> =
::tracing::__macro_support::FieldName::new("local_path");
NAME.as_str()
},
{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("remapped_path")
}> =
::tracing::__macro_support::FieldName::new("remapped_path");
NAME.as_str()
},
{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("was_remapped")
}> =
::tracing::__macro_support::FieldName::new("was_remapped");
NAME.as_str()
},
{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("self.filename_remapping_scopes")
}> =
::tracing::__macro_support::FieldName::new("self.filename_remapping_scopes");
NAME.as_str()
}], ::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&local_path)
as &dyn ::tracing::field::Value)),
(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&remapped_path)
as &dyn ::tracing::field::Value)),
(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&was_remapped)
as &dyn ::tracing::field::Value)),
(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&self.filename_remapping_scopes)
as &dyn ::tracing::field::Value))])
});
} else { ; }
};debug!(?local_path, ?remapped_path, ?was_remapped, ?self.filename_remapping_scopes);
1200
1201 let local = InnerRealFileName {
1204 name: local_path.to_path_buf(),
1205 working_directory: working_directory
1206 .local_path()
1207 .expect("working directory should be local")
1208 .to_path_buf(),
1209 embeddable_name: if local_path.is_absolute() {
1210 local_path.to_path_buf()
1211 } else {
1212 working_directory
1213 .local_path()
1214 .expect("working directory should be local")
1215 .to_path_buf()
1216 .join(&local_path)
1217 },
1218 };
1219
1220 RealFileName {
1221 maybe_remapped: InnerRealFileName {
1222 working_directory: working_directory.maybe_remapped.name.clone(),
1223 embeddable_name: if remapped_path.is_absolute() || was_remapped {
1224 was_remapped = was_remapped || working_directory.was_remapped();
1227
1228 remapped_path.to_path_buf()
1229 } else {
1230 let (abs_path, abs_was_remapped) = self.map_prefix(
1232 working_directory.maybe_remapped.name.clone().join(&remapped_path),
1233 );
1234
1235 was_remapped = abs_was_remapped || working_directory.was_remapped();
1238
1239 abs_path.to_path_buf()
1240 },
1241 name: remapped_path.to_path_buf(),
1242 },
1243 local: Some(local),
1244 scopes: if was_remapped {
1245 self.filename_remapping_scopes
1246 } else {
1247 RemapPathScopeComponents::empty()
1248 },
1249 }
1250 }
1251
1252 x;#[instrument(level = "debug", skip(self), ret)]
1264 fn reverse_map_prefix_heuristically(&self, path: &Path) -> Option<PathBuf> {
1265 let mut found = None;
1266
1267 for (from, to) in self.mapping.iter() {
1268 let has_normal_component = to.components().any(|c| match c {
1269 path::Component::Normal(s) => !s.is_empty(),
1270 _ => false,
1271 });
1272
1273 if !has_normal_component {
1274 continue;
1275 }
1276
1277 let Ok(rest) = path.strip_prefix(to) else {
1278 continue;
1279 };
1280
1281 if found.is_some() {
1282 return None;
1283 }
1284
1285 found = Some(from.join(rest));
1286 }
1287
1288 found
1289 }
1290}