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
177/// Used to construct a `SourceMap` with `SourceMap::with_inputs`.
178pub struct SourceMapInputs {
179    pub file_loader: Box<dyn FileLoader + Send + Sync>,
180    pub path_mapping: FilePathMapping,
181    pub hash_kind: SourceFileHashAlgorithm,
182    pub checksum_hash_kind: Option<SourceFileHashAlgorithm>,
183}
184
185pub struct SourceMap {
186    files: RwLock<SourceMapFiles>,
187    file_loader: IntoDynSyncSend<Box<dyn FileLoader + Sync + Send>>,
188
189    // This is used to apply the file path remapping as specified via
190    // `--remap-path-prefix` to all `SourceFile`s allocated within this `SourceMap`.
191    path_mapping: FilePathMapping,
192
193    /// Current working directory
194    working_dir: RealFileName,
195
196    /// The algorithm used for hashing the contents of each source file.
197    hash_kind: SourceFileHashAlgorithm,
198
199    /// Similar to `hash_kind`, however this algorithm is used for checksums to determine if a crate is fresh.
200    /// `cargo` is the primary user of these.
201    ///
202    /// If this is equal to `hash_kind` then the checksum won't be computed twice.
203    checksum_hash_kind: Option<SourceFileHashAlgorithm>,
204}
205
206impl SourceMap {
207    pub fn new(path_mapping: FilePathMapping) -> SourceMap {
208        Self::with_inputs(SourceMapInputs {
209            file_loader: Box::new(RealFileLoader),
210            path_mapping,
211            hash_kind: SourceFileHashAlgorithm::Md5,
212            checksum_hash_kind: None,
213        })
214    }
215
216    pub fn with_inputs(
217        SourceMapInputs { file_loader, path_mapping, hash_kind, checksum_hash_kind }: SourceMapInputs,
218    ) -> SourceMap {
219        let cwd = file_loader
220            .current_directory()
221            .expect("expecting a current working directory to exist");
222        let working_dir = path_mapping.to_real_filename(&RealFileName::empty(), &cwd);
223        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_span/src/source_map.rs:223",
                        "rustc_span::source_map", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_span/src/source_map.rs"),
                        ::tracing_core::__macro_support::Option::Some(223u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_span::source_map"),
                        ::tracing_core::field::FieldSet::new(&["working_dir"],
                            ::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};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&debug(&working_dir)
                                            as &dyn Value))])
            });
    } else { ; }
};debug!(?working_dir);
224        SourceMap {
225            files: Default::default(),
226            working_dir,
227            file_loader: IntoDynSyncSend(file_loader),
228            path_mapping,
229            hash_kind,
230            checksum_hash_kind,
231        }
232    }
233
234    pub fn path_mapping(&self) -> &FilePathMapping {
235        &self.path_mapping
236    }
237
238    pub fn working_dir(&self) -> &RealFileName {
239        &self.working_dir
240    }
241
242    pub fn file_exists(&self, path: &Path) -> bool {
243        self.file_loader.file_exists(path)
244    }
245
246    pub fn load_file(&self, path: &Path) -> io::Result<Arc<SourceFile>> {
247        let src = self.file_loader.read_file(path)?;
248        let filename = FileName::Real(self.path_mapping.to_real_filename(&self.working_dir, path));
249        Ok(self.new_source_file(filename, src))
250    }
251
252    /// Loads source file as a binary blob.
253    ///
254    /// Unlike `load_file`, guarantees that no normalization like BOM-removal
255    /// takes place.
256    pub fn load_binary_file(&self, path: &Path) -> io::Result<(Arc<[u8]>, Span)> {
257        let bytes = self.file_loader.read_binary_file(path)?;
258
259        // We need to add file to the `SourceMap`, so that it is present
260        // in dep-info. There's also an edge case that file might be both
261        // loaded as a binary via `include_bytes!` and as proper `SourceFile`
262        // via `mod`, so we try to use real file contents and not just an
263        // empty string.
264        let text = std::str::from_utf8(&bytes).unwrap_or("").to_string();
265        let filename = FileName::Real(self.path_mapping.to_real_filename(&self.working_dir, path));
266        let file = self.new_source_file(filename, text);
267        Ok((
268            bytes,
269            Span::new(
270                file.start_pos,
271                BytePos(file.start_pos.0 + file.normalized_source_len.0),
272                SyntaxContext::root(),
273                None,
274            ),
275        ))
276    }
277
278    // By returning a `MonotonicVec`, we ensure that consumers cannot invalidate
279    // any existing indices pointing into `files`.
280    pub fn files(&self) -> MappedReadGuard<'_, monotonic::MonotonicVec<Arc<SourceFile>>> {
281        ReadGuard::map(self.files.borrow(), |files| &files.source_files)
282    }
283
284    pub fn source_file_by_stable_id(
285        &self,
286        stable_id: StableSourceFileId,
287    ) -> Option<Arc<SourceFile>> {
288        self.files.borrow().stable_id_to_source_file.get(&stable_id).cloned()
289    }
290
291    fn register_source_file(
292        &self,
293        file_id: StableSourceFileId,
294        mut file: SourceFile,
295    ) -> Result<Arc<SourceFile>, OffsetOverflowError> {
296        let mut files = self.files.borrow_mut();
297
298        file.start_pos = BytePos(if let Some(last_file) = files.source_files.last() {
299            // Add one so there is some space between files. This lets us distinguish
300            // positions in the `SourceMap`, even in the presence of zero-length files.
301            last_file.end_position().0.checked_add(1).ok_or(OffsetOverflowError)?
302        } else {
303            0
304        });
305
306        let file = Arc::new(file);
307        files.source_files.push(Arc::clone(&file));
308        files.stable_id_to_source_file.insert(file_id, Arc::clone(&file));
309
310        Ok(file)
311    }
312
313    /// Creates a new `SourceFile`.
314    /// If a file already exists in the `SourceMap` with the same ID, that file is returned
315    /// unmodified.
316    pub fn new_source_file(&self, filename: FileName, src: String) -> Arc<SourceFile> {
317        self.try_new_source_file(filename, src).unwrap_or_else(|OffsetOverflowError| {
318            {
    ::std::io::_eprint(format_args!("fatal error: rustc does not support text files larger than {0} bytes\n",
            SourceFile::MAX_FILE_SIZE));
};eprintln!(
319                "fatal error: rustc does not support text files larger than {} bytes",
320                SourceFile::MAX_FILE_SIZE
321            );
322            crate::fatal_error::FatalError.raise()
323        })
324    }
325
326    fn try_new_source_file(
327        &self,
328        filename: FileName,
329        src: String,
330    ) -> Result<Arc<SourceFile>, OffsetOverflowError> {
331        // Note that filename may not be a valid path, eg it may be `<anon>` etc,
332        // but this is okay because the directory determined by `path.pop()` will
333        // be empty, so the working directory will be used.
334
335        let stable_id = StableSourceFileId::from_filename_in_current_crate(&filename);
336        match self.source_file_by_stable_id(stable_id) {
337            Some(lrc_sf) => Ok(lrc_sf),
338            None => {
339                let source_file =
340                    SourceFile::new(filename, src, self.hash_kind, self.checksum_hash_kind)?;
341
342                // Let's make sure the file_id we generated above actually matches
343                // the ID we generate for the SourceFile we just created.
344                if true {
    match (&source_file.stable_id, &stable_id) {
        (left_val, right_val) => {
            if !(*left_val == *right_val) {
                let kind = ::core::panicking::AssertKind::Eq;
                ::core::panicking::assert_failed(kind, &*left_val,
                    &*right_val, ::core::option::Option::None);
            }
        }
    };
};debug_assert_eq!(source_file.stable_id, stable_id);
345
346                self.register_source_file(stable_id, source_file)
347            }
348        }
349    }
350
351    /// Allocates a new `SourceFile` representing a source file from an external
352    /// crate. The source code of such an "imported `SourceFile`" is not available,
353    /// but we still know enough to generate accurate debuginfo location
354    /// information for things inlined from other crates.
355    pub fn new_imported_source_file(
356        &self,
357        filename: FileName,
358        src_hash: SourceFileHash,
359        checksum_hash: Option<SourceFileHash>,
360        stable_id: StableSourceFileId,
361        normalized_source_len: u32,
362        unnormalized_source_len: u32,
363        cnum: CrateNum,
364        file_local_lines: FreezeLock<SourceFileLines>,
365        multibyte_chars: Vec<MultiByteChar>,
366        normalized_pos: Vec<NormalizedPos>,
367        metadata_index: u32,
368    ) -> Arc<SourceFile> {
369        let normalized_source_len = RelativeBytePos::from_u32(normalized_source_len);
370
371        let source_file = SourceFile {
372            name: filename,
373            src: None,
374            src_hash,
375            checksum_hash,
376            external_src: FreezeLock::new(ExternalSource::Foreign {
377                kind: ExternalSourceKind::AbsentOk,
378                metadata_index,
379            }),
380            start_pos: BytePos(0),
381            normalized_source_len,
382            unnormalized_source_len,
383            lines: file_local_lines,
384            multibyte_chars,
385            normalized_pos,
386            stable_id,
387            cnum,
388        };
389
390        self.register_source_file(stable_id, source_file)
391            .expect("not enough address space for imported source file")
392    }
393
394    /// If there is a doctest offset, applies it to the line.
395    pub fn doctest_offset_line(&self, file: &FileName, orig: usize) -> usize {
396        match file {
397            FileName::DocTest(_, offset) => {
398                if *offset < 0 {
399                    orig - (-(*offset)) as usize
400                } else {
401                    orig + *offset as usize
402                }
403            }
404            _ => orig,
405        }
406    }
407
408    /// Return the SourceFile that contains the given `BytePos`
409    pub fn lookup_source_file(&self, pos: BytePos) -> Arc<SourceFile> {
410        let idx = self.lookup_source_file_idx(pos);
411        Arc::clone(&(*self.files.borrow().source_files)[idx])
412    }
413
414    /// Looks up source information about a `BytePos`.
415    pub fn lookup_char_pos(&self, pos: BytePos) -> Loc {
416        let sf = self.lookup_source_file(pos);
417        let (line, col, col_display) = sf.lookup_file_pos_with_col_display(pos);
418        Loc { file: sf, line, col, col_display }
419    }
420
421    /// If the corresponding `SourceFile` is empty, does not return a line number.
422    pub fn lookup_line(&self, pos: BytePos) -> Result<SourceFileAndLine, Arc<SourceFile>> {
423        let f = self.lookup_source_file(pos);
424
425        let pos = f.relative_position(pos);
426        match f.lookup_line(pos) {
427            Some(line) => Ok(SourceFileAndLine { sf: f, line }),
428            None => Err(f),
429        }
430    }
431
432    pub fn span_to_string(&self, sp: Span, display_scope: RemapPathScopeComponents) -> String {
433        self.span_to_string_ext(sp, display_scope, false)
434    }
435
436    pub fn span_to_short_string(
437        &self,
438        sp: Span,
439        display_scope: RemapPathScopeComponents,
440    ) -> String {
441        self.span_to_string_ext(sp, display_scope, true)
442    }
443
444    fn span_to_string_ext(
445        &self,
446        sp: Span,
447        display_scope: RemapPathScopeComponents,
448        short: bool,
449    ) -> String {
450        let (source_file, lo_line, lo_col, hi_line, hi_col) = self.span_to_location_info(sp);
451
452        let file_name = match source_file {
453            Some(sf) => {
454                if short { sf.name.short() } else { sf.name.display(display_scope) }.to_string()
455            }
456            None => return "no-location".to_string(),
457        };
458
459        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{1}:{2}:{3}{0}",
                if short {
                    String::new()
                } else {
                    ::alloc::__export::must_use({
                            ::alloc::fmt::format(format_args!(": {0}:{1}", hi_line,
                                    hi_col))
                        })
                }, file_name, lo_line, lo_col))
    })format!(
460            "{file_name}:{lo_line}:{lo_col}{}",
461            if short { String::new() } else { format!(": {hi_line}:{hi_col}") }
462        )
463    }
464
465    pub fn span_to_location_info(
466        &self,
467        sp: Span,
468    ) -> (Option<Arc<SourceFile>>, usize, usize, usize, usize) {
469        if self.files.borrow().source_files.is_empty() || sp.is_dummy() {
470            return (None, 0, 0, 0, 0);
471        }
472
473        let lo = self.lookup_char_pos(sp.lo());
474        let hi = self.lookup_char_pos(sp.hi());
475        (Some(lo.file), lo.line, lo.col.to_usize() + 1, hi.line, hi.col.to_usize() + 1)
476    }
477
478    /// Format the span location to be printed in diagnostics. Must not be emitted
479    /// to build artifacts as this may leak local file paths. Use span_to_embeddable_string
480    /// for string suitable for embedding.
481    pub fn span_to_diagnostic_string(&self, sp: Span) -> String {
482        self.span_to_string(sp, RemapPathScopeComponents::DIAGNOSTICS)
483    }
484
485    pub fn span_to_filename(&self, sp: Span) -> FileName {
486        self.lookup_char_pos(sp.lo()).file.name.clone()
487    }
488
489    pub fn filename_for_diagnostics<'a>(&self, filename: &'a FileName) -> FileNameDisplay<'a> {
490        filename.display(RemapPathScopeComponents::DIAGNOSTICS)
491    }
492
493    pub fn is_multiline(&self, sp: Span) -> bool {
494        let lo = self.lookup_source_file_idx(sp.lo());
495        let hi = self.lookup_source_file_idx(sp.hi());
496        if lo != hi {
497            return true;
498        }
499        let f = Arc::clone(&(*self.files.borrow().source_files)[lo]);
500        let lo = f.relative_position(sp.lo());
501        let hi = f.relative_position(sp.hi());
502        f.lookup_line(lo) != f.lookup_line(hi)
503    }
504
505    #[allow(clippy :: suspicious_else_formatting)]
{
    let __tracing_attr_span;
    let __tracing_attr_guard;
    if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::TRACE <=
                    ::tracing::level_filters::LevelFilter::current() ||
            { false } {
        __tracing_attr_span =
            {
                use ::tracing::__macro_support::Callsite as _;
                static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                    {
                        static META: ::tracing::Metadata<'static> =
                            {
                                ::tracing_core::metadata::Metadata::new("is_valid_span",
                                    "rustc_span::source_map", ::tracing::Level::TRACE,
                                    ::tracing_core::__macro_support::Option::Some("compiler/rustc_span/src/source_map.rs"),
                                    ::tracing_core::__macro_support::Option::Some(505u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_span::source_map"),
                                    ::tracing_core::field::FieldSet::new(&["sp"],
                                        ::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};
                                let mut iter = meta.fields().iter();
                                meta.fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                    ::tracing::__macro_support::Option::Some(&::tracing::field::debug(&sp)
                                                            as &dyn Value))])
                            })
                } else {
                    let span =
                        ::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
                    {};
                    span
                }
            };
        __tracing_attr_guard = __tracing_attr_span.enter();
    }

    #[warn(clippy :: suspicious_else_formatting)]
    {

        #[allow(unknown_lints, unreachable_code, clippy ::
        diverging_sub_expression, clippy :: empty_loop, clippy ::
        let_unit_value, clippy :: let_with_type_underscore, clippy ::
        needless_return, clippy :: unreachable)]
        if false {
            let __tracing_attr_fake_return:
                    Result<(Loc, Loc), SpanLinesError> = loop {};
            return __tracing_attr_fake_return;
        }
        {
            let lo = self.lookup_char_pos(sp.lo());
            {
                use ::tracing::__macro_support::Callsite as _;
                static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                    {
                        static META: ::tracing::Metadata<'static> =
                            {
                                ::tracing_core::metadata::Metadata::new("event compiler/rustc_span/src/source_map.rs:508",
                                    "rustc_span::source_map", ::tracing::Level::TRACE,
                                    ::tracing_core::__macro_support::Option::Some("compiler/rustc_span/src/source_map.rs"),
                                    ::tracing_core::__macro_support::Option::Some(508u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_span::source_map"),
                                    ::tracing_core::field::FieldSet::new(&["lo"],
                                        ::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};
                            let mut iter = __CALLSITE.metadata().fields().iter();
                            __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                ::tracing::__macro_support::Option::Some(&debug(&lo) as
                                                        &dyn Value))])
                        });
                } else { ; }
            };
            let hi = self.lookup_char_pos(sp.hi());
            {
                use ::tracing::__macro_support::Callsite as _;
                static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                    {
                        static META: ::tracing::Metadata<'static> =
                            {
                                ::tracing_core::metadata::Metadata::new("event compiler/rustc_span/src/source_map.rs:510",
                                    "rustc_span::source_map", ::tracing::Level::TRACE,
                                    ::tracing_core::__macro_support::Option::Some("compiler/rustc_span/src/source_map.rs"),
                                    ::tracing_core::__macro_support::Option::Some(510u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_span::source_map"),
                                    ::tracing_core::field::FieldSet::new(&["hi"],
                                        ::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};
                            let mut iter = __CALLSITE.metadata().fields().iter();
                            __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                ::tracing::__macro_support::Option::Some(&debug(&hi) as
                                                        &dyn Value))])
                        });
                } else { ; }
            };
            if lo.file.start_pos != hi.file.start_pos {
                return Err(SpanLinesError::DistinctSources(Box::new(DistinctSources {
                                    begin: (lo.file.name.clone(), lo.file.start_pos),
                                    end: (hi.file.name.clone(), hi.file.start_pos),
                                })));
            }
            Ok((lo, hi))
        }
    }
}#[instrument(skip(self), level = "trace")]
506    pub fn is_valid_span(&self, sp: Span) -> Result<(Loc, Loc), SpanLinesError> {
507        let lo = self.lookup_char_pos(sp.lo());
508        trace!(?lo);
509        let hi = self.lookup_char_pos(sp.hi());
510        trace!(?hi);
511        if lo.file.start_pos != hi.file.start_pos {
512            return Err(SpanLinesError::DistinctSources(Box::new(DistinctSources {
513                begin: (lo.file.name.clone(), lo.file.start_pos),
514                end: (hi.file.name.clone(), hi.file.start_pos),
515            })));
516        }
517        Ok((lo, hi))
518    }
519
520    pub fn is_line_before_span_empty(&self, sp: Span) -> bool {
521        match self.span_to_prev_source(sp) {
522            Ok(s) => s.rsplit_once('\n').unwrap_or(("", &s)).1.trim_start().is_empty(),
523            Err(_) => false,
524        }
525    }
526
527    pub fn span_to_lines(&self, sp: Span) -> FileLinesResult {
528        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_span/src/source_map.rs:528",
                        "rustc_span::source_map", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_span/src/source_map.rs"),
                        ::tracing_core::__macro_support::Option::Some(528u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_span::source_map"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("span_to_lines(sp={0:?})",
                                                    sp) as &dyn Value))])
            });
    } else { ; }
};debug!("span_to_lines(sp={:?})", sp);
529        let (lo, hi) = self.is_valid_span(sp)?;
530        if !(hi.line >= lo.line) {
    ::core::panicking::panic("assertion failed: hi.line >= lo.line")
};assert!(hi.line >= lo.line);
531
532        if sp.is_dummy() {
533            return Ok(FileLines { file: lo.file, lines: Vec::new() });
534        }
535
536        let mut lines = Vec::with_capacity(hi.line - lo.line + 1);
537
538        // The span starts partway through the first line,
539        // but after that it starts from offset 0.
540        let mut start_col = lo.col;
541
542        // For every line but the last, it extends from `start_col`
543        // and to the end of the line. Be careful because the line
544        // numbers in Loc are 1-based, so we subtract 1 to get 0-based
545        // lines.
546        //
547        // FIXME: now that we handle DUMMY_SP up above, we should consider
548        // asserting that the line numbers here are all indeed 1-based.
549        let hi_line = hi.line.saturating_sub(1);
550        for line_index in lo.line.saturating_sub(1)..hi_line {
551            let line_len = lo.file.get_line(line_index).map_or(0, |s| s.chars().count());
552            lines.push(LineInfo { line_index, start_col, end_col: CharPos::from_usize(line_len) });
553            start_col = CharPos::from_usize(0);
554        }
555
556        // For the last line, it extends from `start_col` to `hi.col`:
557        lines.push(LineInfo { line_index: hi_line, start_col, end_col: hi.col });
558
559        Ok(FileLines { file: lo.file, lines })
560    }
561
562    /// Extracts the source surrounding the given `Span` using the `extract_source` function. The
563    /// extract function takes three arguments: a string slice containing the source, an index in
564    /// the slice for the beginning of the span and an index in the slice for the end of the span.
565    pub fn span_to_source<F, T>(&self, sp: Span, extract_source: F) -> Result<T, SpanSnippetError>
566    where
567        F: Fn(&str, usize, usize) -> Result<T, SpanSnippetError>,
568    {
569        let local_begin = self.lookup_byte_offset(sp.lo());
570        let local_end = self.lookup_byte_offset(sp.hi());
571
572        if local_begin.sf.start_pos != local_end.sf.start_pos {
573            Err(SpanSnippetError::DistinctSources(Box::new(DistinctSources {
574                begin: (local_begin.sf.name.clone(), local_begin.sf.start_pos),
575                end: (local_end.sf.name.clone(), local_end.sf.start_pos),
576            })))
577        } else {
578            self.ensure_source_file_source_present(&local_begin.sf);
579
580            let start_index = local_begin.pos.to_usize();
581            let end_index = local_end.pos.to_usize();
582            let source_len = local_begin.sf.normalized_source_len.to_usize();
583
584            if start_index > end_index || end_index > source_len {
585                return Err(SpanSnippetError::MalformedForSourcemap(MalformedSourceMapPositions {
586                    name: local_begin.sf.name.clone(),
587                    source_len,
588                    begin_pos: local_begin.pos,
589                    end_pos: local_end.pos,
590                }));
591            }
592
593            if let Some(ref src) = local_begin.sf.src {
594                extract_source(src, start_index, end_index)
595            } else if let Some(src) = local_begin.sf.external_src.read().get_source() {
596                extract_source(src, start_index, end_index)
597            } else {
598                Err(SpanSnippetError::SourceNotAvailable { filename: local_begin.sf.name.clone() })
599            }
600        }
601    }
602
603    pub fn is_span_accessible(&self, sp: Span) -> bool {
604        self.span_to_source(sp, |src, start_index, end_index| {
605            Ok(src.get(start_index..end_index).is_some())
606        })
607        .is_ok_and(|is_accessible| is_accessible)
608    }
609
610    /// Returns the source snippet as `String` corresponding to the given `Span`.
611    pub fn span_to_snippet(&self, sp: Span) -> Result<String, SpanSnippetError> {
612        self.span_to_source(sp, |src, start_index, end_index| {
613            src.get(start_index..end_index)
614                .map(|s| s.to_string())
615                .ok_or(SpanSnippetError::IllFormedSpan(sp))
616        })
617    }
618
619    pub fn span_to_margin(&self, sp: Span) -> Option<usize> {
620        Some(self.indentation_before(sp)?.len())
621    }
622
623    pub fn indentation_before(&self, sp: Span) -> Option<String> {
624        self.span_to_source(sp, |src, start_index, _| {
625            let before = &src[..start_index];
626            let last_line = before.rsplit_once('\n').map_or(before, |(_, last)| last);
627            Ok(last_line
628                .split_once(|c: char| !c.is_whitespace())
629                .map_or(last_line, |(indent, _)| indent)
630                .to_string())
631        })
632        .ok()
633    }
634
635    /// Returns the source snippet as `String` before the given `Span`.
636    pub fn span_to_prev_source(&self, sp: Span) -> Result<String, SpanSnippetError> {
637        self.span_to_source(sp, |src, start_index, _| {
638            src.get(..start_index).map(|s| s.to_string()).ok_or(SpanSnippetError::IllFormedSpan(sp))
639        })
640    }
641
642    /// Extends the given `Span` to just after the previous occurrence of `c`. Return the same span
643    /// if no character could be found or if an error occurred while retrieving the code snippet.
644    pub fn span_extend_to_prev_char(&self, sp: Span, c: char, accept_newlines: bool) -> Span {
645        if let Ok(prev_source) = self.span_to_prev_source(sp) {
646            let prev_source = prev_source.rsplit(c).next().unwrap_or("");
647            if !prev_source.is_empty() && (accept_newlines || !prev_source.contains('\n')) {
648                return sp.with_lo(BytePos(sp.lo().0 - prev_source.len() as u32));
649            }
650        }
651
652        sp
653    }
654
655    /// Extends the given `Span` to just before the previous occurrence of `c`. Return the same span
656    /// if an error occurred while retrieving the code snippet.
657    pub fn span_extend_to_prev_char_before(
658        &self,
659        sp: Span,
660        c: char,
661        accept_newlines: bool,
662    ) -> Span {
663        if let Ok(prev_source) = self.span_to_prev_source(sp) {
664            let prev_source = prev_source.rsplit(c).next().unwrap_or("");
665            if accept_newlines || !prev_source.contains('\n') {
666                return sp.with_lo(BytePos(sp.lo().0 - prev_source.len() as u32 - 1_u32));
667            }
668        }
669
670        sp
671    }
672
673    /// Extends the given `Span` to just after the previous occurrence of `pat` when surrounded by
674    /// whitespace. Returns None if the pattern could not be found or if an error occurred while
675    /// retrieving the code snippet.
676    pub fn span_extend_to_prev_str(
677        &self,
678        sp: Span,
679        pat: &str,
680        accept_newlines: bool,
681        include_whitespace: bool,
682    ) -> Option<Span> {
683        // assure that the pattern is delimited, to avoid the following
684        //     fn my_fn()
685        //           ^^^^ returned span without the check
686        //     ---------- correct span
687        let prev_source = self.span_to_prev_source(sp).ok()?;
688        for ws in &[" ", "\t", "\n"] {
689            let pat = pat.to_owned() + ws;
690            if let Some(pat_pos) = prev_source.rfind(&pat) {
691                let just_after_pat_pos = pat_pos + pat.len() - 1;
692                let just_after_pat_plus_ws = if include_whitespace {
693                    just_after_pat_pos
694                        + prev_source[just_after_pat_pos..]
695                            .find(|c: char| !c.is_whitespace())
696                            .unwrap_or(0)
697                } else {
698                    just_after_pat_pos
699                };
700                let len = prev_source.len() - just_after_pat_plus_ws;
701                let prev_source = &prev_source[just_after_pat_plus_ws..];
702                if accept_newlines || !prev_source.trim_start().contains('\n') {
703                    return Some(sp.with_lo(BytePos(sp.lo().0 - len as u32)));
704                }
705            }
706        }
707
708        None
709    }
710
711    /// Returns the source snippet as `String` after the given `Span`.
712    pub fn span_to_next_source(&self, sp: Span) -> Result<String, SpanSnippetError> {
713        self.span_to_source(sp, |src, _, end_index| {
714            src.get(end_index..).map(|s| s.to_string()).ok_or(SpanSnippetError::IllFormedSpan(sp))
715        })
716    }
717
718    /// Extends the given `Span` while the next character matches the predicate
719    pub fn span_extend_while(
720        &self,
721        span: Span,
722        f: impl Fn(char) -> bool,
723    ) -> Result<Span, SpanSnippetError> {
724        self.span_to_source(span, |s, _start, end| {
725            let n = s[end..].char_indices().find(|&(_, c)| !f(c)).map_or(s.len() - end, |(i, _)| i);
726            Ok(span.with_hi(span.hi() + BytePos(n as u32)))
727        })
728    }
729
730    /// Extends the span to include any trailing whitespace, or returns the original
731    /// span if a `SpanSnippetError` was encountered.
732    pub fn span_extend_while_whitespace(&self, span: Span) -> Span {
733        self.span_extend_while(span, char::is_whitespace).unwrap_or(span)
734    }
735
736    /// Extends the given `Span` to previous character while the previous character matches the predicate
737    pub fn span_extend_prev_while(
738        &self,
739        span: Span,
740        f: impl Fn(char) -> bool,
741    ) -> Result<Span, SpanSnippetError> {
742        self.span_to_source(span, |s, start, _end| {
743            let n = s[..start]
744                .char_indices()
745                .rfind(|&(_, c)| !f(c))
746                .map_or(start, |(i, _)| start - i - 1);
747            Ok(span.with_lo(span.lo() - BytePos(n as u32)))
748        })
749    }
750
751    /// Extends the given `Span` to just before the next occurrence of `c`.
752    pub fn span_extend_to_next_char(&self, sp: Span, c: char, accept_newlines: bool) -> Span {
753        if let Ok(next_source) = self.span_to_next_source(sp) {
754            let next_source = next_source.split(c).next().unwrap_or("");
755            if !next_source.is_empty() && (accept_newlines || !next_source.contains('\n')) {
756                return sp.with_hi(BytePos(sp.hi().0 + next_source.len() as u32));
757            }
758        }
759
760        sp
761    }
762
763    /// Extends the given `Span` to contain the entire line it is on.
764    pub fn span_extend_to_line(&self, sp: Span) -> Span {
765        self.span_extend_to_prev_char(self.span_extend_to_next_char(sp, '\n', true), '\n', true)
766    }
767
768    /// Given a `Span`, tries to get a shorter span ending before the first occurrence of `char`
769    /// `c`.
770    pub fn span_until_char(&self, sp: Span, c: char) -> Span {
771        match self.span_to_snippet(sp) {
772            Ok(snippet) => {
773                let snippet = snippet.split(c).next().unwrap_or("").trim_end();
774                if !snippet.is_empty() && !snippet.contains('\n') {
775                    sp.with_hi(BytePos(sp.lo().0 + snippet.len() as u32))
776                } else {
777                    sp
778                }
779            }
780            _ => sp,
781        }
782    }
783
784    /// Given a 'Span', tries to tell if it's wrapped by "<>" or "()"
785    /// the algorithm searches if the next character is '>' or ')' after skipping white space
786    /// then searches the previous character to match '<' or '(' after skipping white space
787    /// return true if wrapped by '<>' or '()'
788    pub fn span_wrapped_by_angle_or_parentheses(&self, span: Span) -> bool {
789        self.span_to_source(span, |src, start_index, end_index| {
790            if src.get(start_index..end_index).is_none() {
791                return Ok(false);
792            }
793            // test the right side to match '>' after skipping white space
794            let end_src = &src[end_index..];
795            let mut i = 0;
796            let mut found_right_parentheses = false;
797            let mut found_right_angle = false;
798            while let Some(cc) = end_src.chars().nth(i) {
799                if cc == ' ' {
800                    i = i + 1;
801                } else if cc == '>' {
802                    // found > in the right;
803                    found_right_angle = true;
804                    break;
805                } else if cc == ')' {
806                    found_right_parentheses = true;
807                    break;
808                } else {
809                    // failed to find '>' return false immediately
810                    return Ok(false);
811                }
812            }
813            // test the left side to match '<' after skipping white space
814            i = start_index;
815            let start_src = &src[0..start_index];
816            while let Some(cc) = start_src.chars().nth(i) {
817                if cc == ' ' {
818                    if i == 0 {
819                        return Ok(false);
820                    }
821                    i = i - 1;
822                } else if cc == '<' {
823                    // found < in the left
824                    if !found_right_angle {
825                        // skip something like "(< )>"
826                        return Ok(false);
827                    }
828                    break;
829                } else if cc == '(' {
830                    if !found_right_parentheses {
831                        // skip something like "<(>)"
832                        return Ok(false);
833                    }
834                    break;
835                } else {
836                    // failed to find '<' return false immediately
837                    return Ok(false);
838                }
839            }
840            Ok(true)
841        })
842        .is_ok_and(|is_accessible| is_accessible)
843    }
844
845    /// Given a `Span`, tries to get a shorter span ending just after the first occurrence of `char`
846    /// `c`.
847    pub fn span_through_char(&self, sp: Span, c: char) -> Span {
848        if let Ok(snippet) = self.span_to_snippet(sp)
849            && let Some(offset) = snippet.find(c)
850        {
851            return sp.with_hi(BytePos(sp.lo().0 + (offset + c.len_utf8()) as u32));
852        }
853        sp
854    }
855
856    /// Given a `Span`, gets a new `Span` covering the first token and all its trailing whitespace
857    /// or the original `Span`.
858    ///
859    /// If `sp` points to `"let mut x"`, then a span pointing at `"let "` will be returned.
860    pub fn span_until_non_whitespace(&self, sp: Span) -> Span {
861        let mut whitespace_found = false;
862
863        self.span_take_while(sp, |c| {
864            if !whitespace_found && c.is_whitespace() {
865                whitespace_found = true;
866            }
867
868            !whitespace_found || c.is_whitespace()
869        })
870    }
871
872    /// Given a `Span`, gets a new `Span` covering the first token without its trailing whitespace
873    /// or the original `Span` in case of error.
874    ///
875    /// If `sp` points to `"let mut x"`, then a span pointing at `"let"` will be returned.
876    pub fn span_until_whitespace(&self, sp: Span) -> Span {
877        self.span_take_while(sp, |c| !c.is_whitespace())
878    }
879
880    /// Given a `Span`, gets a shorter one until `predicate` yields `false`.
881    pub fn span_take_while<P>(&self, sp: Span, predicate: P) -> Span
882    where
883        P: for<'r> FnMut(&'r char) -> bool,
884    {
885        if let Ok(snippet) = self.span_to_snippet(sp) {
886            let offset = snippet.chars().take_while(predicate).map(|c| c.len_utf8()).sum::<usize>();
887
888            sp.with_hi(BytePos(sp.lo().0 + (offset as u32)))
889        } else {
890            sp
891        }
892    }
893
894    /// Given a `Span`, return a span ending in the closest `{`. This is useful when you have a
895    /// `Span` enclosing a whole item but we need to point at only the head (usually the first
896    /// line) of that item.
897    ///
898    /// *Only suitable for diagnostics.*
899    pub fn guess_head_span(&self, sp: Span) -> Span {
900        // FIXME: extend the AST items to have a head span, or replace callers with pointing at
901        // the item's ident when appropriate.
902        self.span_until_char(sp, '{')
903    }
904
905    /// Returns a new span representing just the first character of the given span.
906    pub fn start_point(&self, sp: Span) -> Span {
907        let width = {
908            let sp = sp.data();
909            let local_begin = self.lookup_byte_offset(sp.lo);
910            let start_index = local_begin.pos.to_usize();
911            let src = local_begin.sf.external_src.read();
912
913            let snippet = if let Some(ref src) = local_begin.sf.src {
914                Some(&src[start_index..])
915            } else {
916                src.get_source().map(|src| &src[start_index..])
917            };
918
919            match snippet {
920                None => 1,
921                Some(snippet) => match snippet.chars().next() {
922                    None => 1,
923                    Some(c) => c.len_utf8(),
924                },
925            }
926        };
927
928        sp.with_hi(BytePos(sp.lo().0 + width as u32))
929    }
930
931    /// Returns a new span representing just the last character of this span.
932    pub fn end_point(&self, sp: Span) -> Span {
933        let sp = sp.data();
934        let pos = sp.hi.0;
935
936        let width = self.find_width_of_character_at_span(sp, false);
937        let corrected_end_position = pos.checked_sub(width).unwrap_or(pos);
938
939        let end_point = BytePos(cmp::max(corrected_end_position, sp.lo.0));
940        sp.with_lo(end_point)
941    }
942
943    /// Returns a new span representing the next character after the end-point of this span.
944    /// Special cases:
945    /// - if span is a dummy one, returns the same span
946    /// - if next_point reached the end of source, return a span exceeding the end of source,
947    ///   which means sm.span_to_snippet(next_point) will get `Err`
948    /// - respect multi-byte characters
949    pub fn next_point(&self, sp: Span) -> Span {
950        if sp.is_dummy() {
951            return sp;
952        }
953
954        let sp = sp.data();
955        let start_of_next_point = sp.hi.0;
956        let width = self.find_width_of_character_at_span(sp, true);
957        // If the width is 1, then the next span should only contain the next char besides current ending.
958        // However, in the case of a multibyte character, where the width != 1, the next span should
959        // span multiple bytes to include the whole character.
960        let end_of_next_point =
961            start_of_next_point.checked_add(width).unwrap_or(start_of_next_point);
962
963        let end_of_next_point = BytePos(cmp::max(start_of_next_point + 1, end_of_next_point));
964        Span::new(BytePos(start_of_next_point), end_of_next_point, sp.ctxt, None)
965    }
966
967    /// Check whether span is followed by some specified expected string in limit scope
968    pub fn span_look_ahead(&self, span: Span, expect: &str, limit: Option<usize>) -> Option<Span> {
969        let mut sp = span;
970        for _ in 0..limit.unwrap_or(100_usize) {
971            sp = self.next_point(sp);
972            if let Ok(ref snippet) = self.span_to_snippet(sp) {
973                if snippet == expect {
974                    return Some(sp);
975                }
976                if snippet.chars().any(|c| !c.is_whitespace()) {
977                    break;
978                }
979            }
980        }
981        None
982    }
983
984    /// Finds the width of the character, either before or after the end of provided span,
985    /// depending on the `forwards` parameter.
986    #[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(986u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_span::source_map"),
                                    ::tracing_core::field::FieldSet::new(&["forwards"],
                                        ::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};
                                let mut iter = meta.fields().iter();
                                meta.fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                    ::tracing::__macro_support::Option::Some(&forwards as
                                                            &dyn 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:989",
                                        "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(989u32),
                                        ::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};
                                let mut iter = __CALLSITE.metadata().fields().iter();
                                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                    ::tracing::__macro_support::Option::Some(&format_args!("early return empty span")
                                                            as &dyn 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:995",
                                    "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(995u32),
                                    ::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};
                            let mut iter = __CALLSITE.metadata().fields().iter();
                            __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                ::tracing::__macro_support::Option::Some(&format_args!("local_begin=`{0:?}`, local_end=`{1:?}`",
                                                                local_begin, local_end) as &dyn 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:998",
                                        "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(998u32),
                                        ::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};
                                let mut iter = __CALLSITE.metadata().fields().iter();
                                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                    ::tracing::__macro_support::Option::Some(&format_args!("begin and end are in different files")
                                                            as &dyn 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:1004",
                                    "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(1004u32),
                                    ::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};
                            let mut iter = __CALLSITE.metadata().fields().iter();
                            __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                ::tracing::__macro_support::Option::Some(&format_args!("start_index=`{0:?}`, end_index=`{1:?}`",
                                                                start_index, end_index) as &dyn 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:1009",
                                        "rustc_span::source_map", ::tracing::Level::DEBUG,
                                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_span/src/source_map.rs"),
                                        ::tracing_core::__macro_support::Option::Some(1009u32),
                                        ::tracing_core::__macro_support::Option::Some("rustc_span::source_map"),
                                        ::tracing_core::field::FieldSet::new(&["message"],
                                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                        ::tracing::metadata::Kind::EVENT)
                                };
                            ::tracing::callsite::DefaultCallsite::new(&META)
                        };
                    let enabled =
                        ::tracing::Level::DEBUG <=
                                    ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                ::tracing::Level::DEBUG <=
                                    ::tracing::level_filters::LevelFilter::current() &&
                            {
                                let interest = __CALLSITE.interest();
                                !interest.is_never() &&
                                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                                        interest)
                            };
                    if enabled {
                        (|value_set: ::tracing::field::ValueSet|
                                    {
                                        let meta = __CALLSITE.metadata();
                                        ::tracing::Event::dispatch(meta, &value_set);
                                        ;
                                    })({
                                #[allow(unused_imports)]
                                use ::tracing::field::{debug, display, Value};
                                let mut iter = __CALLSITE.metadata().fields().iter();
                                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                    ::tracing::__macro_support::Option::Some(&format_args!("start or end of span, cannot be multibyte")
                                                            as &dyn 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:1014",
                                    "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(1014u32),
                                    ::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};
                            let mut iter = __CALLSITE.metadata().fields().iter();
                            __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                ::tracing::__macro_support::Option::Some(&format_args!("source_len=`{0:?}`",
                                                                source_len) as &dyn 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:1017",
                                        "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(1017u32),
                                        ::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};
                                let mut iter = __CALLSITE.metadata().fields().iter();
                                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                    ::tracing::__macro_support::Option::Some(&format_args!("source indexes are malformed")
                                                            as &dyn 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))]
987    fn find_width_of_character_at_span(&self, sp: SpanData, forwards: bool) -> u32 {
988        if sp.lo == sp.hi && !forwards {
989            debug!("early return empty span");
990            return 1;
991        }
992
993        let local_begin = self.lookup_byte_offset(sp.lo);
994        let local_end = self.lookup_byte_offset(sp.hi);
995        debug!("local_begin=`{:?}`, local_end=`{:?}`", local_begin, local_end);
996
997        if local_begin.sf.start_pos != local_end.sf.start_pos {
998            debug!("begin and end are in different files");
999            return 1;
1000        }
1001
1002        let start_index = local_begin.pos.to_usize();
1003        let end_index = local_end.pos.to_usize();
1004        debug!("start_index=`{:?}`, end_index=`{:?}`", start_index, end_index);
1005
1006        // Disregard indexes that are at the start or end of their spans, they can't fit bigger
1007        // characters.
1008        if (!forwards && end_index == usize::MIN) || (forwards && start_index == usize::MAX) {
1009            debug!("start or end of span, cannot be multibyte");
1010            return 1;
1011        }
1012
1013        let source_len = local_begin.sf.normalized_source_len.to_usize();
1014        debug!("source_len=`{:?}`", source_len);
1015        // Ensure indexes are also not malformed.
1016        if start_index > end_index || end_index > source_len - 1 {
1017            debug!("source indexes are malformed");
1018            return 1;
1019        }
1020
1021        let src = local_begin.sf.external_src.read();
1022
1023        let snippet = if let Some(src) = &local_begin.sf.src {
1024            src
1025        } else if let Some(src) = src.get_source() {
1026            src
1027        } else {
1028            return 1;
1029        };
1030
1031        if forwards {
1032            (snippet.ceil_char_boundary(end_index + 1) - end_index) as u32
1033        } else {
1034            (end_index - snippet.floor_char_boundary(end_index - 1)) as u32
1035        }
1036    }
1037
1038    pub fn get_source_file(&self, filename: &FileName) -> Option<Arc<SourceFile>> {
1039        for sf in self.files.borrow().source_files.iter() {
1040            if *filename == sf.name {
1041                return Some(Arc::clone(&sf));
1042            }
1043        }
1044        None
1045    }
1046
1047    /// For a global `BytePos`, computes the local offset within the containing `SourceFile`.
1048    pub fn lookup_byte_offset(&self, bpos: BytePos) -> SourceFileAndBytePos {
1049        let idx = self.lookup_source_file_idx(bpos);
1050        let sf = Arc::clone(&(*self.files.borrow().source_files)[idx]);
1051        let offset = bpos - sf.start_pos;
1052        SourceFileAndBytePos { sf, pos: offset }
1053    }
1054
1055    /// Returns the index of the [`SourceFile`] (in `self.files`) that contains `pos`.
1056    /// This index is guaranteed to be valid for the lifetime of this `SourceMap`,
1057    /// since `source_files` is a `MonotonicVec`
1058    pub fn lookup_source_file_idx(&self, pos: BytePos) -> usize {
1059        self.files.borrow().source_files.partition_point(|x| x.start_pos <= pos) - 1
1060    }
1061
1062    pub fn count_lines(&self) -> usize {
1063        self.files().iter().fold(0, |a, f| a + f.count_lines())
1064    }
1065
1066    pub fn ensure_source_file_source_present(&self, source_file: &SourceFile) -> bool {
1067        source_file.add_external_src(|| {
1068            let FileName::Real(ref name) = source_file.name else {
1069                return None;
1070            };
1071
1072            let local_path: Cow<'_, Path> = match name.local_path() {
1073                Some(local) => local.into(),
1074                None => {
1075                    // The compiler produces better error messages if the sources of dependencies
1076                    // are available. Attempt to undo any path mapping so we can find remapped
1077                    // dependencies.
1078                    //
1079                    // We can only use the heuristic because `add_external_src` checks the file
1080                    // content hash.
1081                    let maybe_remapped_path = name.path(RemapPathScopeComponents::DIAGNOSTICS);
1082                    self.path_mapping
1083                        .reverse_map_prefix_heuristically(maybe_remapped_path)
1084                        .map(Cow::from)
1085                        .unwrap_or(maybe_remapped_path.into())
1086                }
1087            };
1088
1089            self.file_loader.read_file(&local_path).ok()
1090        })
1091    }
1092
1093    pub fn is_imported(&self, sp: Span) -> bool {
1094        let source_file_index = self.lookup_source_file_idx(sp.lo());
1095        let source_file = &self.files()[source_file_index];
1096        source_file.is_imported()
1097    }
1098
1099    /// Gets the span of a statement. If the statement is a macro expansion, the
1100    /// span in the context of the block span is found. The trailing semicolon is included
1101    /// on a best-effort basis.
1102    pub fn stmt_span(&self, stmt_span: Span, block_span: Span) -> Span {
1103        if !stmt_span.from_expansion() {
1104            return stmt_span;
1105        }
1106        let mac_call = original_sp(stmt_span, block_span);
1107        self.mac_call_stmt_semi_span(mac_call).map_or(mac_call, |s| mac_call.with_hi(s.hi()))
1108    }
1109
1110    /// Tries to find the span of the semicolon of a macro call statement.
1111    /// The input must be the *call site* span of a statement from macro expansion.
1112    /// ```ignore (illustrative)
1113    /// //       v output
1114    ///    mac!();
1115    /// // ^^^^^^ input
1116    /// ```
1117    pub fn mac_call_stmt_semi_span(&self, mac_call: Span) -> Option<Span> {
1118        let span = self.span_extend_while_whitespace(mac_call);
1119        let span = self.next_point(span);
1120        if self.span_to_snippet(span).as_deref() == Ok(";") { Some(span) } else { None }
1121    }
1122}
1123
1124pub fn get_source_map() -> Option<Arc<SourceMap>> {
1125    with_session_globals(|session_globals| session_globals.source_map.clone())
1126}
1127
1128#[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)]
1129pub struct FilePathMapping {
1130    mapping: Vec<(PathBuf, PathBuf)>,
1131    filename_remapping_scopes: RemapPathScopeComponents,
1132}
1133
1134impl FilePathMapping {
1135    pub fn empty() -> FilePathMapping {
1136        FilePathMapping::new(Vec::new(), RemapPathScopeComponents::empty())
1137    }
1138
1139    pub fn new(
1140        mapping: Vec<(PathBuf, PathBuf)>,
1141        filename_remapping_scopes: RemapPathScopeComponents,
1142    ) -> FilePathMapping {
1143        FilePathMapping { mapping, filename_remapping_scopes }
1144    }
1145
1146    /// Applies any path prefix substitution as defined by the mapping.
1147    /// The return value is the remapped path and a boolean indicating whether
1148    /// the path was affected by the mapping.
1149    fn map_prefix<'a>(&'a self, path: impl Into<Cow<'a, Path>>) -> (Cow<'a, Path>, bool) {
1150        let path = path.into();
1151        if path.as_os_str().is_empty() {
1152            // Exit early if the path is empty and therefore there's nothing to remap.
1153            // This is mostly to reduce spam for `RUSTC_LOG=[remap_path_prefix]`.
1154            return (path, false);
1155        }
1156
1157        return remap_path_prefix(&self.mapping, path);
1158
1159        x;#[instrument(level = "debug", skip(mapping), ret)]
1160        fn remap_path_prefix<'a>(
1161            mapping: &'a [(PathBuf, PathBuf)],
1162            path: Cow<'a, Path>,
1163        ) -> (Cow<'a, Path>, bool) {
1164            // NOTE: We are iterating over the mapping entries from last to first
1165            //       because entries specified later on the command line should
1166            //       take precedence.
1167            for (from, to) in mapping.iter().rev() {
1168                debug!("Trying to apply {from:?} => {to:?}");
1169
1170                if let Ok(rest) = path.strip_prefix(from) {
1171                    let remapped = if rest.as_os_str().is_empty() {
1172                        // This is subtle, joining an empty path onto e.g. `foo/bar` will
1173                        // result in `foo/bar/`, that is, there'll be an additional directory
1174                        // separator at the end. This can lead to duplicated directory separators
1175                        // in remapped paths down the line.
1176                        // So, if we have an exact match, we just return that without a call
1177                        // to `Path::join()`.
1178                        to.into()
1179                    } else {
1180                        to.join(rest).into()
1181                    };
1182                    debug!("Match - remapped");
1183
1184                    return (remapped, true);
1185                } else {
1186                    debug!("No match - prefix {from:?} does not match");
1187                }
1188            }
1189
1190            debug!("not remapped");
1191            (path, false)
1192        }
1193    }
1194
1195    /// Applies any path prefix substitution as defined by the mapping.
1196    ///
1197    /// The returned filename contains the a remapped path representing the remapped
1198    /// part if any remapping was performed.
1199    pub fn to_real_filename<'a>(
1200        &self,
1201        working_directory: &RealFileName,
1202        local_path: impl Into<Cow<'a, Path>>,
1203    ) -> RealFileName {
1204        let local_path = local_path.into();
1205
1206        let (remapped_path, mut was_remapped) = self.map_prefix(&*local_path);
1207        {
    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:1207",
                        "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(1207u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_span::source_map"),
                        ::tracing_core::field::FieldSet::new(&["local_path",
                                        "remapped_path", "was_remapped",
                                        "self.filename_remapping_scopes"],
                            ::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};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&debug(&local_path)
                                            as &dyn Value)),
                                (&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&debug(&remapped_path)
                                            as &dyn Value)),
                                (&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&debug(&was_remapped)
                                            as &dyn Value)),
                                (&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&debug(&self.filename_remapping_scopes)
                                            as &dyn Value))])
            });
    } else { ; }
};debug!(?local_path, ?remapped_path, ?was_remapped, ?self.filename_remapping_scopes);
1208
1209        // Always populate the local part, even if we just remapped it and the scopes are
1210        // total, so that places that load the file from disk still have access to it.
1211        let local = InnerRealFileName {
1212            name: local_path.to_path_buf(),
1213            working_directory: working_directory
1214                .local_path()
1215                .expect("working directory should be local")
1216                .to_path_buf(),
1217            embeddable_name: if local_path.is_absolute() {
1218                local_path.to_path_buf()
1219            } else {
1220                working_directory
1221                    .local_path()
1222                    .expect("working directory should be local")
1223                    .to_path_buf()
1224                    .join(&local_path)
1225            },
1226        };
1227
1228        RealFileName {
1229            maybe_remapped: InnerRealFileName {
1230                working_directory: working_directory.maybe_remapped.name.clone(),
1231                embeddable_name: if remapped_path.is_absolute() || was_remapped {
1232                    // The current directory may have been remapped so we take that
1233                    // into account, otherwise we'll forget to include the scopes
1234                    was_remapped = was_remapped || working_directory.was_remapped();
1235
1236                    remapped_path.to_path_buf()
1237                } else {
1238                    // Create an absolute path and remap it as well.
1239                    let (abs_path, abs_was_remapped) = self.map_prefix(
1240                        working_directory.maybe_remapped.name.clone().join(&remapped_path),
1241                    );
1242
1243                    // If either the embeddable name or the working directory was
1244                    // remapped, then the filename was remapped
1245                    was_remapped = abs_was_remapped || working_directory.was_remapped();
1246
1247                    abs_path.to_path_buf()
1248                },
1249                name: remapped_path.to_path_buf(),
1250            },
1251            local: Some(local),
1252            scopes: if was_remapped {
1253                self.filename_remapping_scopes
1254            } else {
1255                RemapPathScopeComponents::empty()
1256            },
1257        }
1258    }
1259
1260    /// Attempts to (heuristically) reverse a prefix mapping.
1261    ///
1262    /// Returns [`Some`] if there is exactly one mapping where the "to" part is
1263    /// a prefix of `path` and has at least one non-empty
1264    /// [`Normal`](path::Component::Normal) component. The component
1265    /// restriction exists to avoid reverse mapping overly generic paths like
1266    /// `/` or `.`).
1267    ///
1268    /// This is a heuristic and not guaranteed to return the actual original
1269    /// path! Do not rely on the result unless you have other means to verify
1270    /// that the mapping is correct (e.g. by checking the file content hash).
1271    x;#[instrument(level = "debug", skip(self), ret)]
1272    fn reverse_map_prefix_heuristically(&self, path: &Path) -> Option<PathBuf> {
1273        let mut found = None;
1274
1275        for (from, to) in self.mapping.iter() {
1276            let has_normal_component = to.components().any(|c| match c {
1277                path::Component::Normal(s) => !s.is_empty(),
1278                _ => false,
1279            });
1280
1281            if !has_normal_component {
1282                continue;
1283            }
1284
1285            let Ok(rest) = path.strip_prefix(to) else {
1286                continue;
1287            };
1288
1289            if found.is_some() {
1290                return None;
1291            }
1292
1293            found = Some(from.join(rest));
1294        }
1295
1296        found
1297    }
1298}