Skip to main content

rustc_span/
source_map.rs

1//! Types for tracking pieces of source code within a crate.
2//!
3//! The [`SourceMap`] tracks all the source code used within a single crate, mapping
4//! from integer byte positions to the original source code location. Each bit
5//! of source parsed during crate parsing (typically files, in-memory strings,
6//! or various bits of macro expansion) cover a continuous range of bytes in the
7//! `SourceMap` and are represented by [`SourceFile`]s. Byte positions are stored in
8//! [`Span`] and used pervasively in the compiler. They are absolute positions
9//! within the `SourceMap`, which upon request can be converted to line and column
10//! information, source code snippets, etc.
11
12use 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
25/// Returns the span itself if it doesn't come from a macro expansion,
26/// otherwise return the call site span up to the `enclosing_sp` by
27/// following the `expn_data` chain.
28pub 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    /// A `MonotonicVec` is a `Vec` which can only be grown.
49    /// Once inserted, an element can never be removed or swapped,
50    /// guaranteeing that any indices into a `MonotonicVec` are stable
51    // This is declared in its own module to ensure that the private
52    // field is inaccessible
53    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
76// _____________________________________________________________________________
77// SourceFile, MultiByteChar, FileName, FileLines
78//
79
80/// An abstraction over the fs operations used by the Parser.
81pub trait FileLoader {
82    /// Query the existence of a file.
83    fn file_exists(&self, path: &Path) -> bool;
84
85    /// Read the contents of a UTF-8 file into memory.
86    /// This function must return a String because we normalize
87    /// source files, which may require resizing.
88    fn read_file(&self, path: &Path) -> io::Result<String>;
89
90    /// Read the contents of a potentially non-UTF-8 file into memory.
91    /// We don't normalize binary files, so we can start in an Arc.
92    fn read_binary_file(&self, path: &Path) -> io::Result<Arc<[u8]>>;
93
94    /// Current working directory
95    fn current_directory(&self) -> io::Result<PathBuf>;
96}
97
98/// A FileLoader that uses std::fs to load real files.
99pub 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        // SAFETY: If the read_buf_exact call returns Ok(()), then we have
136        // read len bytes and initialized the buffer.
137        let bytes = unsafe { bytes.assume_init() };
138
139        // At this point, we've read all the bytes that filesystem metadata reported exist.
140        // But we are not guaranteed to be at the end of the file, because we did not attempt to do
141        // a read with a non-zero-sized buffer and get Ok(0).
142        // So we do small read to a fixed-size buffer. If the read returns no bytes then we're
143        // already done, and we just return the Arc we built above.
144        // If the read returns bytes however, we just fall back to reading into a Vec then turning
145        // that into an Arc, losing our nice peak memory behavior. This fallback code path should
146        // be rarely exercised.
147
148        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// _____________________________________________________________________________
168// SourceMap
169//
170
171#[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
177impl std::fmt::Debug for SourceMapFiles {
178    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
179        let SourceMapFiles { source_files, stable_id_to_source_file: _ } = self;
180
181        f.debug_list()
182            .entries(
183                source_files.iter().map(|f| f.name.prefer_remapped_unconditionally().to_string()),
184            )
185            .finish()
186    }
187}
188
189/// Used to construct a `SourceMap` with `SourceMap::with_inputs`.
190pub struct SourceMapInputs {
191    pub file_loader: Box<dyn FileLoader + Send + Sync>,
192    pub path_mapping: FilePathMapping,
193    pub hash_kind: SourceFileHashAlgorithm,
194    pub checksum_hash_kind: Option<SourceFileHashAlgorithm>,
195}
196
197pub struct SourceMap {
198    files: RwLock<SourceMapFiles>,
199    file_loader: IntoDynSyncSend<Box<dyn FileLoader + Sync + Send>>,
200
201    // This is used to apply the file path remapping as specified via
202    // `--remap-path-prefix` to all `SourceFile`s allocated within this `SourceMap`.
203    path_mapping: FilePathMapping,
204
205    /// Current working directory
206    working_dir: RealFileName,
207
208    /// The algorithm used for hashing the contents of each source file.
209    hash_kind: SourceFileHashAlgorithm,
210
211    /// Similar to `hash_kind`, however this algorithm is used for checksums to determine if a crate is fresh.
212    /// `cargo` is the primary user of these.
213    ///
214    /// If this is equal to `hash_kind` then the checksum won't be computed twice.
215    checksum_hash_kind: Option<SourceFileHashAlgorithm>,
216}
217
218impl std::fmt::Debug for SourceMap {
219    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
220        let SourceMap {
221            files,
222            file_loader,
223            path_mapping,
224            working_dir,
225            hash_kind,
226            checksum_hash_kind,
227        } = self;
228
229        f.debug_struct("SourceMap")
230            .field("files", files)
231            .field("file_loader", &format_args!("<file_loader@{0:p}>", file_loader)format_args!("<file_loader@{file_loader:p}>"))
232            .field("path_mapping", path_mapping)
233            .field("working_dir", working_dir)
234            .field("hash_kind", hash_kind)
235            .field("checksum_hash_kind", checksum_hash_kind)
236            .finish()
237    }
238}
239
240impl SourceMap {
241    pub fn new(path_mapping: FilePathMapping) -> SourceMap {
242        Self::with_inputs(SourceMapInputs {
243            file_loader: Box::new(RealFileLoader),
244            path_mapping,
245            hash_kind: SourceFileHashAlgorithm::Md5,
246            checksum_hash_kind: None,
247        })
248    }
249
250    pub fn with_inputs(
251        SourceMapInputs { file_loader, path_mapping, hash_kind, checksum_hash_kind }: SourceMapInputs,
252    ) -> SourceMap {
253        let cwd = file_loader
254            .current_directory()
255            .expect("expecting a current working directory to exist");
256        let working_dir = path_mapping.to_real_filename(&RealFileName::empty(), &cwd);
257        {
    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:257",
                        "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(257u32),
                        ::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);
258        SourceMap {
259            files: Default::default(),
260            working_dir,
261            file_loader: IntoDynSyncSend(file_loader),
262            path_mapping,
263            hash_kind,
264            checksum_hash_kind,
265        }
266    }
267
268    pub fn path_mapping(&self) -> &FilePathMapping {
269        &self.path_mapping
270    }
271
272    pub fn working_dir(&self) -> &RealFileName {
273        &self.working_dir
274    }
275
276    pub fn file_exists(&self, path: &Path) -> bool {
277        self.file_loader.file_exists(path)
278    }
279
280    pub fn load_file(&self, path: &Path) -> io::Result<Arc<SourceFile>> {
281        let src = self.file_loader.read_file(path)?;
282        let filename = FileName::Real(self.path_mapping.to_real_filename(&self.working_dir, path));
283        Ok(self.new_source_file(filename, src))
284    }
285
286    /// Loads source file as a binary blob.
287    ///
288    /// Unlike `load_file`, guarantees that no normalization like BOM-removal
289    /// takes place.
290    pub fn load_binary_file(&self, path: &Path) -> io::Result<(Arc<[u8]>, Span)> {
291        let bytes = self.file_loader.read_binary_file(path)?;
292
293        // We need to add file to the `SourceMap`, so that it is present
294        // in dep-info. There's also an edge case that file might be both
295        // loaded as a binary via `include_bytes!` and as proper `SourceFile`
296        // via `mod`, so we try to use real file contents and not just an
297        // empty string.
298        let text = std::str::from_utf8(&bytes).unwrap_or("").to_string();
299        let filename = FileName::Real(self.path_mapping.to_real_filename(&self.working_dir, path));
300        let file = self.new_source_file(filename, text);
301        Ok((
302            bytes,
303            Span::new(
304                file.start_pos,
305                BytePos(file.start_pos.0 + file.normalized_source_len.0),
306                SyntaxContext::root(),
307                None,
308            ),
309        ))
310    }
311
312    // By returning a `MonotonicVec`, we ensure that consumers cannot invalidate
313    // any existing indices pointing into `files`.
314    pub fn files(&self) -> MappedReadGuard<'_, monotonic::MonotonicVec<Arc<SourceFile>>> {
315        ReadGuard::map(self.files.borrow(), |files| &files.source_files)
316    }
317
318    pub fn source_file_by_stable_id(
319        &self,
320        stable_id: StableSourceFileId,
321    ) -> Option<Arc<SourceFile>> {
322        self.files.borrow().stable_id_to_source_file.get(&stable_id).cloned()
323    }
324
325    fn register_source_file(
326        &self,
327        file_id: StableSourceFileId,
328        mut file: SourceFile,
329    ) -> Result<Arc<SourceFile>, OffsetOverflowError> {
330        let mut files = self.files.borrow_mut();
331
332        file.start_pos = BytePos(if let Some(last_file) = files.source_files.last() {
333            // Add one so there is some space between files. This lets us distinguish
334            // positions in the `SourceMap`, even in the presence of zero-length files.
335            last_file.end_position().0.checked_add(1).ok_or(OffsetOverflowError)?
336        } else {
337            0
338        });
339
340        let file = Arc::new(file);
341        files.source_files.push(Arc::clone(&file));
342        files.stable_id_to_source_file.insert(file_id, Arc::clone(&file));
343
344        Ok(file)
345    }
346
347    /// Creates a new `SourceFile`.
348    /// If a file already exists in the `SourceMap` with the same ID, that file is returned
349    /// unmodified.
350    pub fn new_source_file(&self, filename: FileName, src: String) -> Arc<SourceFile> {
351        self.try_new_source_file(filename, src).unwrap_or_else(|OffsetOverflowError| {
352            {
    ::std::io::_eprint(format_args!("fatal error: rustc does not support text files larger than {0} bytes\n",
            SourceFile::MAX_FILE_SIZE));
};eprintln!(
353                "fatal error: rustc does not support text files larger than {} bytes",
354                SourceFile::MAX_FILE_SIZE
355            );
356            crate::fatal_error::FatalError.raise()
357        })
358    }
359
360    fn try_new_source_file(
361        &self,
362        filename: FileName,
363        src: String,
364    ) -> Result<Arc<SourceFile>, OffsetOverflowError> {
365        // Note that filename may not be a valid path, eg it may be `<anon>` etc,
366        // but this is okay because the directory determined by `path.pop()` will
367        // be empty, so the working directory will be used.
368
369        let stable_id = StableSourceFileId::from_filename_in_current_crate(&filename);
370        match self.source_file_by_stable_id(stable_id) {
371            Some(lrc_sf) => Ok(lrc_sf),
372            None => {
373                let source_file =
374                    SourceFile::new(filename, src, self.hash_kind, self.checksum_hash_kind)?;
375
376                // Let's make sure the file_id we generated above actually matches
377                // the ID we generate for the SourceFile we just created.
378                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);
379
380                self.register_source_file(stable_id, source_file)
381            }
382        }
383    }
384
385    /// Allocates a new `SourceFile` representing a source file from an external
386    /// crate. The source code of such an "imported `SourceFile`" is not available,
387    /// but we still know enough to generate accurate debuginfo location
388    /// information for things inlined from other crates.
389    pub fn new_imported_source_file(
390        &self,
391        filename: FileName,
392        src_hash: SourceFileHash,
393        checksum_hash: Option<SourceFileHash>,
394        stable_id: StableSourceFileId,
395        normalized_source_len: u32,
396        unnormalized_source_len: u32,
397        cnum: CrateNum,
398        file_local_lines: FreezeLock<SourceFileLines>,
399        multibyte_chars: Vec<MultiByteChar>,
400        normalized_pos: Vec<NormalizedPos>,
401        metadata_index: u32,
402    ) -> Arc<SourceFile> {
403        let normalized_source_len = RelativeBytePos::from_u32(normalized_source_len);
404
405        let source_file = SourceFile {
406            name: filename,
407            src: None,
408            src_hash,
409            checksum_hash,
410            external_src: FreezeLock::new(ExternalSource::Foreign {
411                kind: ExternalSourceKind::AbsentOk,
412                metadata_index,
413            }),
414            start_pos: BytePos(0),
415            normalized_source_len,
416            unnormalized_source_len,
417            lines: file_local_lines,
418            multibyte_chars,
419            normalized_pos,
420            stable_id,
421            cnum,
422        };
423
424        self.register_source_file(stable_id, source_file)
425            .expect("not enough address space for imported source file")
426    }
427
428    /// If there is a doctest offset, applies it to the line.
429    pub fn doctest_offset_line(&self, file: &FileName, orig: usize) -> usize {
430        match file {
431            FileName::DocTest(_, offset) => {
432                if *offset < 0 {
433                    orig - (-(*offset)) as usize
434                } else {
435                    orig + *offset as usize
436                }
437            }
438            _ => orig,
439        }
440    }
441
442    /// Return the SourceFile that contains the given `BytePos`
443    pub fn lookup_source_file(&self, pos: BytePos) -> Arc<SourceFile> {
444        let idx = self.lookup_source_file_idx(pos);
445        Arc::clone(&(*self.files.borrow().source_files)[idx])
446    }
447
448    /// Looks up source information about a `BytePos`.
449    pub fn lookup_char_pos(&self, pos: BytePos) -> Loc {
450        let sf = self.lookup_source_file(pos);
451        let (line, col, col_display) = sf.lookup_file_pos_with_col_display(pos);
452        Loc { file: sf, line, col, col_display }
453    }
454
455    /// If the corresponding `SourceFile` is empty, does not return a line number.
456    pub fn lookup_line(&self, pos: BytePos) -> Result<SourceFileAndLine, Arc<SourceFile>> {
457        let f = self.lookup_source_file(pos);
458
459        let pos = f.relative_position(pos);
460        match f.lookup_line(pos) {
461            Some(line) => Ok(SourceFileAndLine { sf: f, line }),
462            None => Err(f),
463        }
464    }
465
466    pub fn span_to_string(&self, sp: Span, display_scope: RemapPathScopeComponents) -> String {
467        self.span_to_string_ext(sp, display_scope, false)
468    }
469
470    pub fn span_to_short_string(
471        &self,
472        sp: Span,
473        display_scope: RemapPathScopeComponents,
474    ) -> String {
475        self.span_to_string_ext(sp, display_scope, true)
476    }
477
478    fn span_to_string_ext(
479        &self,
480        sp: Span,
481        display_scope: RemapPathScopeComponents,
482        short: bool,
483    ) -> String {
484        let (source_file, lo_line, lo_col, hi_line, hi_col) = self.span_to_location_info(sp);
485
486        let file_name = match source_file {
487            Some(sf) => {
488                if short { sf.name.short() } else { sf.name.display(display_scope) }.to_string()
489            }
490            None => return "no-location".to_string(),
491        };
492
493        ::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!(
494            "{file_name}:{lo_line}:{lo_col}{}",
495            if short { String::new() } else { format!(": {hi_line}:{hi_col}") }
496        )
497    }
498
499    pub fn span_to_location_info(
500        &self,
501        sp: Span,
502    ) -> (Option<Arc<SourceFile>>, usize, usize, usize, usize) {
503        if self.files.borrow().source_files.is_empty() || sp.is_dummy() {
504            return (None, 0, 0, 0, 0);
505        }
506
507        let lo = self.lookup_char_pos(sp.lo());
508        let hi = self.lookup_char_pos(sp.hi());
509        (Some(lo.file), lo.line, lo.col.to_usize() + 1, hi.line, hi.col.to_usize() + 1)
510    }
511
512    /// Format the span location to be printed in diagnostics. Must not be emitted
513    /// to build artifacts as this may leak local file paths. Use span_to_embeddable_string
514    /// for string suitable for embedding.
515    pub fn span_to_diagnostic_string(&self, sp: Span) -> String {
516        self.span_to_string(sp, RemapPathScopeComponents::DIAGNOSTICS)
517    }
518
519    pub fn span_to_filename(&self, sp: Span) -> FileName {
520        self.lookup_char_pos(sp.lo()).file.name.clone()
521    }
522
523    pub fn filename_for_diagnostics<'a>(&self, filename: &'a FileName) -> FileNameDisplay<'a> {
524        filename.display(RemapPathScopeComponents::DIAGNOSTICS)
525    }
526
527    pub fn is_multiline(&self, sp: Span) -> bool {
528        let lo = self.lookup_source_file_idx(sp.lo());
529        let hi = self.lookup_source_file_idx(sp.hi());
530        if lo != hi {
531            return true;
532        }
533        let f = Arc::clone(&(*self.files.borrow().source_files)[lo]);
534        let lo = f.relative_position(sp.lo());
535        let hi = f.relative_position(sp.hi());
536        f.lookup_line(lo) != f.lookup_line(hi)
537    }
538
539    #[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(539u32),
                                    ::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:542",
                                    "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(542u32),
                                    ::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:544",
                                    "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(544u32),
                                    ::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")]
540    pub fn is_valid_span(&self, sp: Span) -> Result<(Loc, Loc), SpanLinesError> {
541        let lo = self.lookup_char_pos(sp.lo());
542        trace!(?lo);
543        let hi = self.lookup_char_pos(sp.hi());
544        trace!(?hi);
545        if lo.file.start_pos != hi.file.start_pos {
546            return Err(SpanLinesError::DistinctSources(Box::new(DistinctSources {
547                begin: (lo.file.name.clone(), lo.file.start_pos),
548                end: (hi.file.name.clone(), hi.file.start_pos),
549            })));
550        }
551        Ok((lo, hi))
552    }
553
554    pub fn is_line_before_span_empty(&self, sp: Span) -> bool {
555        match self.span_to_prev_source(sp) {
556            Ok(s) => s.rsplit_once('\n').unwrap_or(("", &s)).1.trim_start().is_empty(),
557            Err(_) => false,
558        }
559    }
560
561    pub fn span_to_lines(&self, sp: Span) -> FileLinesResult {
562        {
    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:562",
                        "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(562u32),
                        ::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);
563        let (lo, hi) = self.is_valid_span(sp)?;
564        if !(hi.line >= lo.line) {
    ::core::panicking::panic("assertion failed: hi.line >= lo.line")
};assert!(hi.line >= lo.line);
565
566        if sp.is_dummy() {
567            return Ok(FileLines { file: lo.file, lines: Vec::new() });
568        }
569
570        let mut lines = Vec::with_capacity(hi.line - lo.line + 1);
571
572        // The span starts partway through the first line,
573        // but after that it starts from offset 0.
574        let mut start_col = lo.col;
575
576        // For every line but the last, it extends from `start_col`
577        // and to the end of the line. Be careful because the line
578        // numbers in Loc are 1-based, so we subtract 1 to get 0-based
579        // lines.
580        //
581        // FIXME: now that we handle DUMMY_SP up above, we should consider
582        // asserting that the line numbers here are all indeed 1-based.
583        let hi_line = hi.line.saturating_sub(1);
584        for line_index in lo.line.saturating_sub(1)..hi_line {
585            let line_len = lo.file.get_line(line_index).map_or(0, |s| s.chars().count());
586            lines.push(LineInfo { line_index, start_col, end_col: CharPos::from_usize(line_len) });
587            start_col = CharPos::from_usize(0);
588        }
589
590        // For the last line, it extends from `start_col` to `hi.col`:
591        lines.push(LineInfo { line_index: hi_line, start_col, end_col: hi.col });
592
593        Ok(FileLines { file: lo.file, lines })
594    }
595
596    /// Extracts the source surrounding the given `Span` using the `extract_source` function. The
597    /// extract function takes three arguments: a string slice containing the source, an index in
598    /// the slice for the beginning of the span and an index in the slice for the end of the span.
599    pub fn span_to_source<F, T>(&self, sp: Span, extract_source: F) -> Result<T, SpanSnippetError>
600    where
601        F: Fn(&str, usize, usize) -> Result<T, SpanSnippetError>,
602    {
603        let local_begin = self.lookup_byte_offset(sp.lo());
604        let local_end = self.lookup_byte_offset(sp.hi());
605
606        if local_begin.sf.start_pos != local_end.sf.start_pos {
607            Err(SpanSnippetError::DistinctSources(Box::new(DistinctSources {
608                begin: (local_begin.sf.name.clone(), local_begin.sf.start_pos),
609                end: (local_end.sf.name.clone(), local_end.sf.start_pos),
610            })))
611        } else {
612            self.ensure_source_file_source_present(&local_begin.sf);
613
614            let start_index = local_begin.pos.to_usize();
615            let end_index = local_end.pos.to_usize();
616            let source_len = local_begin.sf.normalized_source_len.to_usize();
617
618            if start_index > end_index || end_index > source_len {
619                return Err(SpanSnippetError::MalformedForSourcemap(MalformedSourceMapPositions {
620                    name: local_begin.sf.name.clone(),
621                    source_len,
622                    begin_pos: local_begin.pos,
623                    end_pos: local_end.pos,
624                }));
625            }
626
627            if let Some(ref src) = local_begin.sf.src {
628                extract_source(src, start_index, end_index)
629            } else if let Some(src) = local_begin.sf.external_src.read().get_source() {
630                extract_source(src, start_index, end_index)
631            } else {
632                Err(SpanSnippetError::SourceNotAvailable { filename: local_begin.sf.name.clone() })
633            }
634        }
635    }
636
637    pub fn is_span_accessible(&self, sp: Span) -> bool {
638        self.span_to_source(sp, |src, start_index, end_index| {
639            Ok(src.get(start_index..end_index).is_some())
640        })
641        .is_ok_and(|is_accessible| is_accessible)
642    }
643
644    /// Returns the source snippet as `String` corresponding to the given `Span`.
645    pub fn span_to_snippet(&self, sp: Span) -> Result<String, SpanSnippetError> {
646        self.span_to_source(sp, |src, start_index, end_index| {
647            src.get(start_index..end_index)
648                .map(|s| s.to_string())
649                .ok_or(SpanSnippetError::IllFormedSpan(sp))
650        })
651    }
652
653    pub fn span_to_margin(&self, sp: Span) -> Option<usize> {
654        Some(self.indentation_before(sp)?.len())
655    }
656
657    pub fn indentation_before(&self, sp: Span) -> Option<String> {
658        self.span_to_source(sp, |src, start_index, _| {
659            let before = &src[..start_index];
660            let last_line = before.rsplit_once('\n').map_or(before, |(_, last)| last);
661            Ok(last_line
662                .split_once(|c: char| !c.is_whitespace())
663                .map_or(last_line, |(indent, _)| indent)
664                .to_string())
665        })
666        .ok()
667    }
668
669    /// Returns the source snippet as `String` before the given `Span`.
670    pub fn span_to_prev_source(&self, sp: Span) -> Result<String, SpanSnippetError> {
671        self.span_to_source(sp, |src, start_index, _| {
672            src.get(..start_index).map(|s| s.to_string()).ok_or(SpanSnippetError::IllFormedSpan(sp))
673        })
674    }
675
676    /// Extends the given `Span` to just after the previous occurrence of `c`. Return the same span
677    /// if no character could be found or if an error occurred while retrieving the code snippet.
678    pub fn span_extend_to_prev_char(&self, sp: Span, c: char, accept_newlines: bool) -> Span {
679        if let Ok(prev_source) = self.span_to_prev_source(sp) {
680            let prev_source = prev_source.rsplit(c).next().unwrap_or("");
681            if !prev_source.is_empty() && (accept_newlines || !prev_source.contains('\n')) {
682                return sp.with_lo(BytePos(sp.lo().0 - prev_source.len() as u32));
683            }
684        }
685
686        sp
687    }
688
689    /// Extends the given `Span` to just before the previous occurrence of `c`. Return the same span
690    /// if an error occurred while retrieving the code snippet.
691    pub fn span_extend_to_prev_char_before(
692        &self,
693        sp: Span,
694        c: char,
695        accept_newlines: bool,
696    ) -> Span {
697        if let Ok(prev_source) = self.span_to_prev_source(sp) {
698            let prev_source = prev_source.rsplit(c).next().unwrap_or("");
699            if accept_newlines || !prev_source.contains('\n') {
700                return sp.with_lo(BytePos(sp.lo().0 - prev_source.len() as u32 - 1_u32));
701            }
702        }
703
704        sp
705    }
706
707    /// Extends the given `Span` to just after the previous occurrence of `pat` when surrounded by
708    /// whitespace. Returns None if the pattern could not be found or if an error occurred while
709    /// retrieving the code snippet.
710    pub fn span_extend_to_prev_str(
711        &self,
712        sp: Span,
713        pat: &str,
714        accept_newlines: bool,
715        include_whitespace: bool,
716    ) -> Option<Span> {
717        // assure that the pattern is delimited, to avoid the following
718        //     fn my_fn()
719        //           ^^^^ returned span without the check
720        //     ---------- correct span
721        let prev_source = self.span_to_prev_source(sp).ok()?;
722        for ws in &[" ", "\t", "\n"] {
723            let pat = pat.to_owned() + ws;
724            if let Some(pat_pos) = prev_source.rfind(&pat) {
725                let just_after_pat_pos = pat_pos + pat.len() - 1;
726                let just_after_pat_plus_ws = if include_whitespace {
727                    just_after_pat_pos
728                        + prev_source[just_after_pat_pos..]
729                            .find(|c: char| !c.is_whitespace())
730                            .unwrap_or(0)
731                } else {
732                    just_after_pat_pos
733                };
734                let len = prev_source.len() - just_after_pat_plus_ws;
735                let prev_source = &prev_source[just_after_pat_plus_ws..];
736                if accept_newlines || !prev_source.trim_start().contains('\n') {
737                    return Some(sp.with_lo(BytePos(sp.lo().0 - len as u32)));
738                }
739            }
740        }
741
742        None
743    }
744
745    /// Returns the source snippet as `String` after the given `Span`.
746    pub fn span_to_next_source(&self, sp: Span) -> Result<String, SpanSnippetError> {
747        self.span_to_source(sp, |src, _, end_index| {
748            src.get(end_index..).map(|s| s.to_string()).ok_or(SpanSnippetError::IllFormedSpan(sp))
749        })
750    }
751
752    /// Extends the given `Span` while the next character matches the predicate
753    pub fn span_extend_while(
754        &self,
755        span: Span,
756        f: impl Fn(char) -> bool,
757    ) -> Result<Span, SpanSnippetError> {
758        self.span_to_source(span, |s, _start, end| {
759            let n = s[end..].char_indices().find(|&(_, c)| !f(c)).map_or(s.len() - end, |(i, _)| i);
760            Ok(span.with_hi(span.hi() + BytePos(n as u32)))
761        })
762    }
763
764    /// Extends the span to include any trailing whitespace, or returns the original
765    /// span if a `SpanSnippetError` was encountered.
766    pub fn span_extend_while_whitespace(&self, span: Span) -> Span {
767        self.span_extend_while(span, char::is_whitespace).unwrap_or(span)
768    }
769
770    /// Extends the given `Span` to previous character while the previous character matches the predicate
771    pub fn span_extend_prev_while(
772        &self,
773        span: Span,
774        f: impl Fn(char) -> bool,
775    ) -> Result<Span, SpanSnippetError> {
776        self.span_to_source(span, |s, start, _end| {
777            let n = s[..start]
778                .char_indices()
779                .rfind(|&(_, c)| !f(c))
780                .map_or(start, |(i, c)| start - i - c.len_utf8());
781            Ok(span.with_lo(span.lo() - BytePos(n as u32)))
782        })
783    }
784
785    /// Extends the given `Span` to just before the next occurrence of `c`.
786    pub fn span_extend_to_next_char(&self, sp: Span, c: char, accept_newlines: bool) -> Span {
787        if let Ok(next_source) = self.span_to_next_source(sp) {
788            let next_source = next_source.split(c).next().unwrap_or("");
789            if !next_source.is_empty() && (accept_newlines || !next_source.contains('\n')) {
790                return sp.with_hi(BytePos(sp.hi().0 + next_source.len() as u32));
791            }
792        }
793
794        sp
795    }
796
797    /// Extends the given `Span` to contain the entire line it is on.
798    pub fn span_extend_to_line(&self, sp: Span) -> Span {
799        self.span_extend_to_prev_char(self.span_extend_to_next_char(sp, '\n', true), '\n', true)
800    }
801
802    /// Given a `Span`, tries to get a shorter span ending before the first occurrence of `char`
803    /// `c`.
804    pub fn span_until_char(&self, sp: Span, c: char) -> Span {
805        match self.span_to_snippet(sp) {
806            Ok(snippet) => {
807                let snippet = snippet.split(c).next().unwrap_or("").trim_end();
808                if !snippet.is_empty() && !snippet.contains('\n') {
809                    sp.with_hi(BytePos(sp.lo().0 + snippet.len() as u32))
810                } else {
811                    sp
812                }
813            }
814            _ => sp,
815        }
816    }
817
818    /// Given a 'Span', tries to tell if it's wrapped by "<>" or "()"
819    /// the algorithm searches if the next character is '>' or ')' after skipping white space
820    /// then searches the previous character to match '<' or '(' after skipping white space
821    /// return true if wrapped by '<>' or '()'
822    pub fn span_wrapped_by_angle_or_parentheses(&self, span: Span) -> bool {
823        self.span_to_source(span, |src, start_index, end_index| {
824            if src.get(start_index..end_index).is_none() {
825                return Ok(false);
826            }
827            // test the right side to match '>' after skipping white space
828            let end_src = &src[end_index..];
829            let mut i = 0;
830            let mut found_right_parentheses = false;
831            let mut found_right_angle = false;
832            while let Some(cc) = end_src.chars().nth(i) {
833                if cc == ' ' {
834                    i = i + 1;
835                } else if cc == '>' {
836                    // found > in the right;
837                    found_right_angle = true;
838                    break;
839                } else if cc == ')' {
840                    found_right_parentheses = true;
841                    break;
842                } else {
843                    // failed to find '>' return false immediately
844                    return Ok(false);
845                }
846            }
847            // test the left side to match '<' after skipping white space
848            i = start_index;
849            let start_src = &src[0..start_index];
850            while let Some(cc) = start_src.chars().nth(i) {
851                if cc == ' ' {
852                    if i == 0 {
853                        return Ok(false);
854                    }
855                    i = i - 1;
856                } else if cc == '<' {
857                    // found < in the left
858                    if !found_right_angle {
859                        // skip something like "(< )>"
860                        return Ok(false);
861                    }
862                    break;
863                } else if cc == '(' {
864                    if !found_right_parentheses {
865                        // skip something like "<(>)"
866                        return Ok(false);
867                    }
868                    break;
869                } else {
870                    // failed to find '<' return false immediately
871                    return Ok(false);
872                }
873            }
874            Ok(true)
875        })
876        .is_ok_and(|is_accessible| is_accessible)
877    }
878
879    /// Given a `Span`, tries to get a shorter span ending just after the first occurrence of `char`
880    /// `c`.
881    pub fn span_through_char(&self, sp: Span, c: char) -> Span {
882        if let Ok(snippet) = self.span_to_snippet(sp)
883            && let Some(offset) = snippet.find(c)
884        {
885            return sp.with_hi(BytePos(sp.lo().0 + (offset + c.len_utf8()) as u32));
886        }
887        sp
888    }
889
890    /// Given a `Span`, gets a new `Span` covering the first token and all its trailing whitespace
891    /// or the original `Span`.
892    ///
893    /// If `sp` points to `"let mut x"`, then a span pointing at `"let "` will be returned.
894    pub fn span_until_non_whitespace(&self, sp: Span) -> Span {
895        let mut whitespace_found = false;
896
897        self.span_take_while(sp, |c| {
898            if !whitespace_found && c.is_whitespace() {
899                whitespace_found = true;
900            }
901
902            !whitespace_found || c.is_whitespace()
903        })
904    }
905
906    /// Given a `Span`, gets a new `Span` covering the first token without its trailing whitespace
907    /// or the original `Span` in case of error.
908    ///
909    /// If `sp` points to `"let mut x"`, then a span pointing at `"let"` will be returned.
910    pub fn span_until_whitespace(&self, sp: Span) -> Span {
911        self.span_take_while(sp, |c| !c.is_whitespace())
912    }
913
914    /// Given a `Span`, gets a shorter one until `predicate` yields `false`.
915    pub fn span_take_while<P>(&self, sp: Span, predicate: P) -> Span
916    where
917        P: for<'r> FnMut(&'r char) -> bool,
918    {
919        if let Ok(snippet) = self.span_to_snippet(sp) {
920            let offset = snippet.chars().take_while(predicate).map(|c| c.len_utf8()).sum::<usize>();
921
922            sp.with_hi(BytePos(sp.lo().0 + (offset as u32)))
923        } else {
924            sp
925        }
926    }
927
928    /// Given a `Span`, return a span ending in the closest `{`. This is useful when you have a
929    /// `Span` enclosing a whole item but we need to point at only the head (usually the first
930    /// line) of that item.
931    ///
932    /// *Only suitable for diagnostics.*
933    pub fn guess_head_span(&self, sp: Span) -> Span {
934        // FIXME: extend the AST items to have a head span, or replace callers with pointing at
935        // the item's ident when appropriate.
936        self.span_until_char(sp, '{')
937    }
938
939    /// Returns a new span representing just the first character of the given span.
940    pub fn start_point(&self, sp: Span) -> Span {
941        let width = {
942            let sp = sp.data();
943            let local_begin = self.lookup_byte_offset(sp.lo);
944            let start_index = local_begin.pos.to_usize();
945            let src = local_begin.sf.external_src.read();
946
947            let snippet = if let Some(ref src) = local_begin.sf.src {
948                Some(&src[start_index..])
949            } else {
950                src.get_source().map(|src| &src[start_index..])
951            };
952
953            match snippet {
954                None => 1,
955                Some(snippet) => match snippet.chars().next() {
956                    None => 1,
957                    Some(c) => c.len_utf8(),
958                },
959            }
960        };
961
962        sp.with_hi(BytePos(sp.lo().0 + width as u32))
963    }
964
965    /// Returns a new span representing just the last character of this span.
966    pub fn end_point(&self, sp: Span) -> Span {
967        let sp = sp.data();
968        let pos = sp.hi.0;
969
970        let width = self.find_width_of_character_at_span(sp, false);
971        let corrected_end_position = pos.checked_sub(width).unwrap_or(pos);
972
973        let end_point = BytePos(cmp::max(corrected_end_position, sp.lo.0));
974        sp.with_lo(end_point)
975    }
976
977    /// Returns a new span representing the next character after the end-point of this span.
978    /// Special cases:
979    /// - if span is a dummy one, returns the same span
980    /// - if next_point reached the end of source, return a span exceeding the end of source,
981    ///   which means sm.span_to_snippet(next_point) will get `Err`
982    /// - respect multi-byte characters
983    pub fn next_point(&self, sp: Span) -> Span {
984        if sp.is_dummy() {
985            return sp;
986        }
987
988        let sp = sp.data();
989        let start_of_next_point = sp.hi.0;
990        let width = self.find_width_of_character_at_span(sp, true);
991        // If the width is 1, then the next span should only contain the next char besides current ending.
992        // However, in the case of a multibyte character, where the width != 1, the next span should
993        // span multiple bytes to include the whole character.
994        let end_of_next_point =
995            start_of_next_point.checked_add(width).unwrap_or(start_of_next_point);
996
997        let end_of_next_point = BytePos(cmp::max(start_of_next_point + 1, end_of_next_point));
998        Span::new(BytePos(start_of_next_point), end_of_next_point, sp.ctxt, None)
999    }
1000
1001    /// Check whether span is followed by some specified target string, ignoring whitespace.
1002    /// *Only suitable for diagnostics.*
1003    pub fn span_followed_by(&self, span: Span, target: &str) -> Option<Span> {
1004        let span = self.span_extend_while_whitespace(span);
1005        self.span_to_next_source(span).ok()?.strip_prefix(target).map(|_| {
1006            Span::new(span.hi(), span.hi() + BytePos(target.len() as u32), span.ctxt(), None)
1007        })
1008    }
1009
1010    /// Finds the width of the character, either before or after the end of provided span,
1011    /// depending on the `forwards` parameter.
1012    #[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(1012u32),
                                    ::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:1015",
                                        "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(1015u32),
                                        ::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:1021",
                                    "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(1021u32),
                                    ::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:1024",
                                        "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(1024u32),
                                        ::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:1030",
                                    "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(1030u32),
                                    ::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:1035",
                                        "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(1035u32),
                                        ::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:1040",
                                    "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(1040u32),
                                    ::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:1043",
                                        "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(1043u32),
                                        ::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))]
1013    fn find_width_of_character_at_span(&self, sp: SpanData, forwards: bool) -> u32 {
1014        if sp.lo == sp.hi && !forwards {
1015            debug!("early return empty span");
1016            return 1;
1017        }
1018
1019        let local_begin = self.lookup_byte_offset(sp.lo);
1020        let local_end = self.lookup_byte_offset(sp.hi);
1021        debug!("local_begin=`{:?}`, local_end=`{:?}`", local_begin, local_end);
1022
1023        if local_begin.sf.start_pos != local_end.sf.start_pos {
1024            debug!("begin and end are in different files");
1025            return 1;
1026        }
1027
1028        let start_index = local_begin.pos.to_usize();
1029        let end_index = local_end.pos.to_usize();
1030        debug!("start_index=`{:?}`, end_index=`{:?}`", start_index, end_index);
1031
1032        // Disregard indexes that are at the start or end of their spans, they can't fit bigger
1033        // characters.
1034        if (!forwards && end_index == usize::MIN) || (forwards && start_index == usize::MAX) {
1035            debug!("start or end of span, cannot be multibyte");
1036            return 1;
1037        }
1038
1039        let source_len = local_begin.sf.normalized_source_len.to_usize();
1040        debug!("source_len=`{:?}`", source_len);
1041        // Ensure indexes are also not malformed.
1042        if start_index > end_index || end_index > source_len - 1 {
1043            debug!("source indexes are malformed");
1044            return 1;
1045        }
1046
1047        let src = local_begin.sf.external_src.read();
1048
1049        let snippet = if let Some(src) = &local_begin.sf.src {
1050            src
1051        } else if let Some(src) = src.get_source() {
1052            src
1053        } else {
1054            return 1;
1055        };
1056
1057        if forwards {
1058            (snippet.ceil_char_boundary(end_index + 1) - end_index) as u32
1059        } else {
1060            (end_index - snippet.floor_char_boundary(end_index - 1)) as u32
1061        }
1062    }
1063
1064    pub fn get_source_file(&self, filename: &FileName) -> Option<Arc<SourceFile>> {
1065        for sf in self.files.borrow().source_files.iter() {
1066            if *filename == sf.name {
1067                return Some(Arc::clone(&sf));
1068            }
1069        }
1070        None
1071    }
1072
1073    /// For a global `BytePos`, computes the local offset within the containing `SourceFile`.
1074    pub fn lookup_byte_offset(&self, bpos: BytePos) -> SourceFileAndBytePos {
1075        let idx = self.lookup_source_file_idx(bpos);
1076        let sf = Arc::clone(&(*self.files.borrow().source_files)[idx]);
1077        let offset = bpos - sf.start_pos;
1078        SourceFileAndBytePos { sf, pos: offset }
1079    }
1080
1081    /// Returns the index of the [`SourceFile`] (in `self.files`) that contains `pos`.
1082    /// This index is guaranteed to be valid for the lifetime of this `SourceMap`,
1083    /// since `source_files` is a `MonotonicVec`
1084    pub fn lookup_source_file_idx(&self, pos: BytePos) -> usize {
1085        self.files.borrow().source_files.partition_point(|x| x.start_pos <= pos) - 1
1086    }
1087
1088    pub fn count_lines(&self) -> usize {
1089        self.files().iter().fold(0, |a, f| a + f.count_lines())
1090    }
1091
1092    pub fn ensure_source_file_source_present(&self, source_file: &SourceFile) -> bool {
1093        source_file.add_external_src(|| {
1094            let FileName::Real(ref name) = source_file.name else {
1095                return None;
1096            };
1097
1098            let local_path: Cow<'_, Path> = match name.local_path() {
1099                Some(local) => local.into(),
1100                None => {
1101                    // The compiler produces better error messages if the sources of dependencies
1102                    // are available. Attempt to undo any path mapping so we can find remapped
1103                    // dependencies.
1104                    //
1105                    // We can only use the heuristic because `add_external_src` checks the file
1106                    // content hash.
1107                    let maybe_remapped_path = name.path(RemapPathScopeComponents::DIAGNOSTICS);
1108                    self.path_mapping
1109                        .reverse_map_prefix_heuristically(maybe_remapped_path)
1110                        .map(Cow::from)
1111                        .unwrap_or(maybe_remapped_path.into())
1112                }
1113            };
1114
1115            self.file_loader.read_file(&local_path).ok()
1116        })
1117    }
1118
1119    pub fn is_imported(&self, sp: Span) -> bool {
1120        let source_file_index = self.lookup_source_file_idx(sp.lo());
1121        let source_file = &self.files()[source_file_index];
1122        source_file.is_imported()
1123    }
1124
1125    /// Gets the span of a statement. If the statement is a macro expansion, the
1126    /// span in the context of the block span is found. The trailing semicolon is included
1127    /// on a best-effort basis.
1128    pub fn stmt_span(&self, stmt_span: Span, block_span: Span) -> Span {
1129        if !stmt_span.from_expansion() {
1130            return stmt_span;
1131        }
1132        let mac_call = original_sp(stmt_span, block_span);
1133        self.mac_call_stmt_semi_span(mac_call).map_or(mac_call, |s| mac_call.with_hi(s.hi()))
1134    }
1135
1136    /// Tries to find the span of the semicolon of a macro call statement.
1137    /// The input must be the *call site* span of a statement from macro expansion.
1138    /// ```ignore (illustrative)
1139    /// //       v output
1140    ///    mac!();
1141    /// // ^^^^^^ input
1142    /// ```
1143    pub fn mac_call_stmt_semi_span(&self, mac_call: Span) -> Option<Span> {
1144        let span = self.span_extend_while_whitespace(mac_call);
1145        let span = self.next_point(span);
1146        if self.span_to_snippet(span).as_deref() == Ok(";") { Some(span) } else { None }
1147    }
1148}
1149
1150pub fn get_source_map() -> Option<Arc<SourceMap>> {
1151    with_session_globals(|session_globals| session_globals.source_map.clone())
1152}
1153
1154#[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, #[automatically_derived]
impl ::core::fmt::Debug for FilePathMapping {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field2_finish(f,
            "FilePathMapping", "mapping", &self.mapping,
            "filename_remapping_scopes", &&self.filename_remapping_scopes)
    }
}Debug)]
1155pub struct FilePathMapping {
1156    mapping: Vec<(PathBuf, PathBuf)>,
1157    filename_remapping_scopes: RemapPathScopeComponents,
1158}
1159
1160impl FilePathMapping {
1161    pub fn empty() -> FilePathMapping {
1162        FilePathMapping::new(Vec::new(), RemapPathScopeComponents::empty())
1163    }
1164
1165    pub fn new(
1166        mapping: Vec<(PathBuf, PathBuf)>,
1167        filename_remapping_scopes: RemapPathScopeComponents,
1168    ) -> FilePathMapping {
1169        FilePathMapping { mapping, filename_remapping_scopes }
1170    }
1171
1172    /// Applies any path prefix substitution as defined by the mapping.
1173    /// The return value is the remapped path and a boolean indicating whether
1174    /// the path was affected by the mapping.
1175    fn map_prefix<'a>(&'a self, path: impl Into<Cow<'a, Path>>) -> (Cow<'a, Path>, bool) {
1176        let path = path.into();
1177        if path.as_os_str().is_empty() {
1178            // Exit early if the path is empty and therefore there's nothing to remap.
1179            // This is mostly to reduce spam for `RUSTC_LOG=[remap_path_prefix]`.
1180            return (path, false);
1181        }
1182
1183        return remap_path_prefix(&self.mapping, path);
1184
1185        x;#[instrument(level = "debug", skip(mapping), ret)]
1186        fn remap_path_prefix<'a>(
1187            mapping: &'a [(PathBuf, PathBuf)],
1188            path: Cow<'a, Path>,
1189        ) -> (Cow<'a, Path>, bool) {
1190            // NOTE: We are iterating over the mapping entries from last to first
1191            //       because entries specified later on the command line should
1192            //       take precedence.
1193            for (from, to) in mapping.iter().rev() {
1194                debug!("Trying to apply {from:?} => {to:?}");
1195
1196                if let Ok(rest) = path.strip_prefix(from) {
1197                    let remapped = if rest.as_os_str().is_empty() {
1198                        // This is subtle, joining an empty path onto e.g. `foo/bar` will
1199                        // result in `foo/bar/`, that is, there'll be an additional directory
1200                        // separator at the end. This can lead to duplicated directory separators
1201                        // in remapped paths down the line.
1202                        // So, if we have an exact match, we just return that without a call
1203                        // to `Path::join()`.
1204                        to.into()
1205                    } else {
1206                        to.join(rest).into()
1207                    };
1208                    debug!("Match - remapped");
1209
1210                    return (remapped, true);
1211                } else {
1212                    debug!("No match - prefix {from:?} does not match");
1213                }
1214            }
1215
1216            debug!("not remapped");
1217            (path, false)
1218        }
1219    }
1220
1221    /// Applies any path prefix substitution as defined by the mapping.
1222    ///
1223    /// The returned filename contains the a remapped path representing the remapped
1224    /// part if any remapping was performed.
1225    pub fn to_real_filename<'a>(
1226        &self,
1227        working_directory: &RealFileName,
1228        local_path: impl Into<Cow<'a, Path>>,
1229    ) -> RealFileName {
1230        let local_path = local_path.into();
1231
1232        let (remapped_path, mut was_remapped) = self.map_prefix(&*local_path);
1233        {
    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:1233",
                        "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(1233u32),
                        ::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);
1234
1235        // Always populate the local part, even if we just remapped it and the scopes are
1236        // total, so that places that load the file from disk still have access to it.
1237        let local = InnerRealFileName {
1238            name: local_path.to_path_buf(),
1239            working_directory: working_directory
1240                .local_path()
1241                .expect("working directory should be local")
1242                .to_path_buf(),
1243            embeddable_name: if local_path.is_absolute() {
1244                local_path.to_path_buf()
1245            } else {
1246                working_directory
1247                    .local_path()
1248                    .expect("working directory should be local")
1249                    .to_path_buf()
1250                    .join(&local_path)
1251            },
1252        };
1253
1254        RealFileName {
1255            maybe_remapped: InnerRealFileName {
1256                working_directory: working_directory.maybe_remapped.name.clone(),
1257                embeddable_name: if remapped_path.is_absolute() || was_remapped {
1258                    // The current directory may have been remapped so we take that
1259                    // into account, otherwise we'll forget to include the scopes
1260                    was_remapped = was_remapped || working_directory.was_remapped();
1261
1262                    remapped_path.to_path_buf()
1263                } else {
1264                    // Create an absolute path and remap it as well.
1265                    let (abs_path, abs_was_remapped) = self.map_prefix(
1266                        working_directory.maybe_remapped.name.clone().join(&remapped_path),
1267                    );
1268
1269                    // If either the embeddable name or the working directory was
1270                    // remapped, then the filename was remapped
1271                    was_remapped = abs_was_remapped || working_directory.was_remapped();
1272
1273                    abs_path.to_path_buf()
1274                },
1275                name: remapped_path.to_path_buf(),
1276            },
1277            local: Some(local),
1278            scopes: if was_remapped {
1279                self.filename_remapping_scopes
1280            } else {
1281                RemapPathScopeComponents::empty()
1282            },
1283        }
1284    }
1285
1286    /// Attempts to (heuristically) reverse a prefix mapping.
1287    ///
1288    /// Returns [`Some`] if there is exactly one mapping where the "to" part is
1289    /// a prefix of `path` and has at least one non-empty
1290    /// [`Normal`](path::Component::Normal) component. The component
1291    /// restriction exists to avoid reverse mapping overly generic paths like
1292    /// `/` or `.`).
1293    ///
1294    /// This is a heuristic and not guaranteed to return the actual original
1295    /// path! Do not rely on the result unless you have other means to verify
1296    /// that the mapping is correct (e.g. by checking the file content hash).
1297    x;#[instrument(level = "debug", skip(self), ret)]
1298    fn reverse_map_prefix_heuristically(&self, path: &Path) -> Option<PathBuf> {
1299        let mut found = None;
1300
1301        for (from, to) in self.mapping.iter() {
1302            let has_normal_component = to.components().any(|c| match c {
1303                path::Component::Normal(s) => !s.is_empty(),
1304                _ => false,
1305            });
1306
1307            if !has_normal_component {
1308                continue;
1309            }
1310
1311            let Ok(rest) = path.strip_prefix(to) else {
1312                continue;
1313            };
1314
1315            if found.is_some() {
1316                return None;
1317            }
1318
1319            found = Some(from.join(rest));
1320        }
1321
1322        found
1323    }
1324}