Coverage Report

Created: 2025-10-13 06:07

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/proc-macro2-1.0.101/src/extra.rs
Line
Count
Source
1
//! Items which do not have a correspondence to any API in the proc_macro crate,
2
//! but are necessary to include in proc-macro2.
3
4
use crate::fallback;
5
use crate::imp;
6
use crate::marker::{ProcMacroAutoTraits, MARKER};
7
use crate::Span;
8
use core::fmt::{self, Debug};
9
10
/// Invalidate any `proc_macro2::Span` that exist on the current thread.
11
///
12
/// The implementation of `Span` uses thread-local data structures and this
13
/// function clears them. Calling any method on a `Span` on the current thread
14
/// created prior to the invalidation will return incorrect values or crash.
15
///
16
/// This function is useful for programs that process more than 2<sup>32</sup>
17
/// bytes of Rust source code on the same thread. Just like rustc, proc-macro2
18
/// uses 32-bit source locations, and these wrap around when the total source
19
/// code processed by the same thread exceeds 2<sup>32</sup> bytes (4
20
/// gigabytes). After a wraparound, `Span` methods such as `source_text()` can
21
/// return wrong data.
22
///
23
/// # Example
24
///
25
/// As of late 2023, there is 200 GB of Rust code published on crates.io.
26
/// Looking at just the newest version of every crate, it is 16 GB of code. So a
27
/// workload that involves parsing it all would overflow a 32-bit source
28
/// location unless spans are being invalidated.
29
///
30
/// ```
31
/// use flate2::read::GzDecoder;
32
/// use std::ffi::OsStr;
33
/// use std::io::{BufReader, Read};
34
/// use std::str::FromStr;
35
/// use tar::Archive;
36
///
37
/// rayon::scope(|s| {
38
///     for krate in every_version_of_every_crate() {
39
///         s.spawn(move |_| {
40
///             proc_macro2::extra::invalidate_current_thread_spans();
41
///
42
///             let reader = BufReader::new(krate);
43
///             let tar = GzDecoder::new(reader);
44
///             let mut archive = Archive::new(tar);
45
///             for entry in archive.entries().unwrap() {
46
///                 let mut entry = entry.unwrap();
47
///                 let path = entry.path().unwrap();
48
///                 if path.extension() != Some(OsStr::new("rs")) {
49
///                     continue;
50
///                 }
51
///                 let mut content = String::new();
52
///                 entry.read_to_string(&mut content).unwrap();
53
///                 match proc_macro2::TokenStream::from_str(&content) {
54
///                     Ok(tokens) => {/* ... */},
55
///                     Err(_) => continue,
56
///                 }
57
///             }
58
///         });
59
///     }
60
/// });
61
/// #
62
/// # fn every_version_of_every_crate() -> Vec<std::fs::File> {
63
/// #     Vec::new()
64
/// # }
65
/// ```
66
///
67
/// # Panics
68
///
69
/// This function is not applicable to and will panic if called from a
70
/// procedural macro.
71
#[cfg(span_locations)]
72
#[cfg_attr(docsrs, doc(cfg(feature = "span-locations")))]
73
pub fn invalidate_current_thread_spans() {
74
    crate::imp::invalidate_current_thread_spans();
75
}
76
77
/// An object that holds a [`Group`]'s `span_open()` and `span_close()` together
78
/// in a more compact representation than holding those 2 spans individually.
79
///
80
/// [`Group`]: crate::Group
81
#[derive(Copy, Clone)]
82
pub struct DelimSpan {
83
    inner: DelimSpanEnum,
84
    _marker: ProcMacroAutoTraits,
85
}
86
87
#[derive(Copy, Clone)]
88
enum DelimSpanEnum {
89
    #[cfg(wrap_proc_macro)]
90
    Compiler {
91
        join: proc_macro::Span,
92
        open: proc_macro::Span,
93
        close: proc_macro::Span,
94
    },
95
    Fallback(fallback::Span),
96
}
97
98
impl DelimSpan {
99
0
    pub(crate) fn new(group: &imp::Group) -> Self {
100
        #[cfg(wrap_proc_macro)]
101
0
        let inner = match group {
102
0
            imp::Group::Compiler(group) => DelimSpanEnum::Compiler {
103
0
                join: group.span(),
104
0
                open: group.span_open(),
105
0
                close: group.span_close(),
106
0
            },
107
0
            imp::Group::Fallback(group) => DelimSpanEnum::Fallback(group.span()),
108
        };
109
110
        #[cfg(not(wrap_proc_macro))]
111
        let inner = DelimSpanEnum::Fallback(group.span());
112
113
0
        DelimSpan {
114
0
            inner,
115
0
            _marker: MARKER,
116
0
        }
117
0
    }
118
119
    /// Returns a span covering the entire delimited group.
120
0
    pub fn join(&self) -> Span {
121
0
        match &self.inner {
122
            #[cfg(wrap_proc_macro)]
123
0
            DelimSpanEnum::Compiler { join, .. } => Span::_new(imp::Span::Compiler(*join)),
124
0
            DelimSpanEnum::Fallback(span) => Span::_new_fallback(*span),
125
        }
126
0
    }
127
128
    /// Returns a span for the opening punctuation of the group only.
129
0
    pub fn open(&self) -> Span {
130
0
        match &self.inner {
131
            #[cfg(wrap_proc_macro)]
132
0
            DelimSpanEnum::Compiler { open, .. } => Span::_new(imp::Span::Compiler(*open)),
133
0
            DelimSpanEnum::Fallback(span) => Span::_new_fallback(span.first_byte()),
134
        }
135
0
    }
136
137
    /// Returns a span for the closing punctuation of the group only.
138
0
    pub fn close(&self) -> Span {
139
0
        match &self.inner {
140
            #[cfg(wrap_proc_macro)]
141
0
            DelimSpanEnum::Compiler { close, .. } => Span::_new(imp::Span::Compiler(*close)),
142
0
            DelimSpanEnum::Fallback(span) => Span::_new_fallback(span.last_byte()),
143
        }
144
0
    }
145
}
146
147
impl Debug for DelimSpan {
148
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
149
0
        Debug::fmt(&self.join(), f)
150
0
    }
151
}