1#[cfg(not(feature = "parking_lot"))]
2use std::sync::Mutex;
3use std::{
4 borrow::Cow,
5 cmp, fmt,
6 hash::{Hash, Hasher},
7 ops::{Add, Sub},
8 path::PathBuf,
9 sync::atomic::AtomicU32,
10};
11
12#[cfg(feature = "parking_lot")]
13use parking_lot::Mutex;
14use serde::{Deserialize, Serialize};
15use url::Url;
16
17use self::hygiene::MarkData;
18pub use self::hygiene::{Mark, SyntaxContext};
19use crate::{cache::CacheCell, rustc_data_structures::stable_hasher::StableHasher, sync::Lrc};
20
21mod analyze_source_file;
22pub mod hygiene;
23
24#[derive(Clone, Copy, Hash, PartialEq, Eq, Ord, PartialOrd, Serialize, Deserialize)]
35#[cfg_attr(
36 any(feature = "rkyv-impl"),
37 derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
38)]
39#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
40#[cfg_attr(feature = "rkyv-impl", repr(C))]
41#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
42pub struct Span {
43 #[serde(rename = "start")]
44 #[cfg_attr(feature = "__rkyv", rkyv(omit_bounds))]
45 pub lo: BytePos,
46 #[serde(rename = "end")]
47 #[cfg_attr(feature = "__rkyv", rkyv(omit_bounds))]
48 pub hi: BytePos,
49}
50
51impl std::fmt::Debug for Span {
52 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
53 write!(f, "{}..{}", self.lo.0, self.hi.0,)
54 }
55}
56
57impl From<(BytePos, BytePos)> for Span {
58 #[inline]
59 fn from(sp: (BytePos, BytePos)) -> Self {
60 Span::new(sp.0, sp.1)
61 }
62}
63
64impl From<Span> for (BytePos, BytePos) {
65 #[inline]
66 fn from(sp: Span) -> Self {
67 (sp.lo, sp.hi)
68 }
69}
70
71#[cfg(feature = "arbitrary")]
72#[cfg_attr(docsrs, doc(cfg(feature = "arbitrary")))]
73impl<'a> arbitrary::Arbitrary<'a> for Span {
74 fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
75 let lo = u.arbitrary::<BytePos>()?;
76 let hi = u.arbitrary::<BytePos>()?;
77
78 Ok(Self::new(lo, hi))
79 }
80}
81
82pub const DUMMY_SP: Span = Span {
85 lo: BytePos::DUMMY,
86 hi: BytePos::DUMMY,
87};
88
89pub const PURE_SP: Span = Span {
91 lo: BytePos::PURE,
92 hi: BytePos::PURE,
93};
94
95pub const PLACEHOLDER_SP: Span = Span {
97 lo: BytePos::PLACEHOLDER,
98 hi: BytePos::PLACEHOLDER,
99};
100
101pub struct Globals {
102 hygiene_data: Mutex<hygiene::HygieneData>,
103 #[allow(unused)]
104 dummy_cnt: AtomicU32,
105 #[allow(unused)]
106 marks: Mutex<Vec<MarkData>>,
107}
108
109const DUMMY_RESERVE: u32 = u32::MAX - 2_u32.pow(16);
110
111impl Default for Globals {
112 fn default() -> Self {
113 Self::new()
114 }
115}
116
117impl Globals {
118 pub fn new() -> Globals {
119 Globals {
120 hygiene_data: Mutex::new(hygiene::HygieneData::new()),
121 marks: Mutex::new(vec![MarkData {
122 parent: Mark::root(),
123 }]),
124 dummy_cnt: AtomicU32::new(DUMMY_RESERVE),
125 }
126 }
127}
128
129better_scoped_tls::scoped_tls!(
130
131 pub static GLOBALS: Globals
156);
157
158#[cfg_attr(
159 any(feature = "rkyv-impl"),
160 derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
161)]
162#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
163#[cfg_attr(feature = "rkyv-impl", repr(u32))]
164#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Hash)]
165pub enum FileName {
166 Real(
167 #[cfg_attr(
168 any(feature = "rkyv-impl"),
169 rkyv(with = crate::source_map::EncodePathBuf)
170 )]
171 PathBuf,
172 ),
173 Macros(String),
176 QuoteExpansion,
178 Anon,
180 MacroExpansion,
182 ProcMacroSourceCode,
183 Url(#[cfg_attr(any(feature = "rkyv-impl"), rkyv(with = crate::source_map::EncodeUrl))] Url),
184 Internal(String),
185 Custom(String),
187}
188
189#[cfg(feature = "rkyv-impl")]
199#[derive(Debug, Clone, Copy)]
200#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
201#[cfg_attr(feature = "rkyv-impl", repr(C))]
202pub struct EncodePathBuf;
203
204#[cfg(feature = "rkyv-impl")]
205impl rkyv::with::ArchiveWith<PathBuf> for EncodePathBuf {
206 type Archived = rkyv::string::ArchivedString;
207 type Resolver = rkyv::string::StringResolver;
208
209 #[inline]
210 fn resolve_with(field: &PathBuf, resolver: Self::Resolver, out: rkyv::Place<Self::Archived>) {
211 rkyv::string::ArchivedString::resolve_from_str(field.to_str().unwrap(), resolver, out);
214 }
215}
216
217#[cfg(feature = "rkyv-impl")]
218impl<S> rkyv::with::SerializeWith<PathBuf, S> for EncodePathBuf
219where
220 S: ?Sized + rancor::Fallible + rkyv::ser::Writer,
221 S::Error: rancor::Source,
222{
223 #[inline]
224 fn serialize_with(field: &PathBuf, serializer: &mut S) -> Result<Self::Resolver, S::Error> {
225 let s = field.to_str().unwrap_or_default();
226 rkyv::string::ArchivedString::serialize_from_str(s, serializer)
227 }
228}
229
230#[cfg(feature = "rkyv-impl")]
231impl<D> rkyv::with::DeserializeWith<rkyv::string::ArchivedString, PathBuf, D> for EncodePathBuf
232where
233 D: ?Sized + rancor::Fallible,
234{
235 #[inline]
236 fn deserialize_with(
237 field: &rkyv::string::ArchivedString,
238 _: &mut D,
239 ) -> Result<PathBuf, D::Error> {
240 Ok(<PathBuf as std::str::FromStr>::from_str(field.as_str()).unwrap())
241 }
242}
243
244#[cfg(feature = "rkyv-impl")]
246#[derive(Debug, Clone, Copy)]
247#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
248#[cfg_attr(feature = "rkyv-impl", repr(C))]
249pub struct EncodeUrl;
250
251#[cfg(feature = "rkyv-impl")]
252impl rkyv::with::ArchiveWith<Url> for EncodeUrl {
253 type Archived = rkyv::string::ArchivedString;
254 type Resolver = rkyv::string::StringResolver;
255
256 #[inline]
257 fn resolve_with(field: &Url, resolver: Self::Resolver, out: rkyv::Place<Self::Archived>) {
258 rkyv::string::ArchivedString::resolve_from_str(field.as_str(), resolver, out);
259 }
260}
261
262#[cfg(feature = "rkyv-impl")]
263impl<S> rkyv::with::SerializeWith<Url, S> for EncodeUrl
264where
265 S: ?Sized + rancor::Fallible + rkyv::ser::Writer,
266 S::Error: rancor::Source,
267{
268 #[inline]
269 fn serialize_with(field: &Url, serializer: &mut S) -> Result<Self::Resolver, S::Error> {
270 let field = field.as_str();
271 rkyv::string::ArchivedString::serialize_from_str(field, serializer)
272 }
273}
274
275#[cfg(feature = "rkyv-impl")]
276impl<D> rkyv::with::DeserializeWith<rkyv::Archived<String>, Url, D> for EncodeUrl
277where
278 D: ?Sized + rancor::Fallible,
279{
280 #[inline]
281 fn deserialize_with(field: &rkyv::string::ArchivedString, _: &mut D) -> Result<Url, D::Error> {
282 Ok(Url::parse(field.as_str()).unwrap())
283 }
284}
285
286impl std::fmt::Display for FileName {
287 fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
288 match *self {
289 FileName::Real(ref path) => write!(fmt, "{}", path.display()),
290 FileName::Macros(ref name) => write!(fmt, "<{} macros>", name),
291 FileName::QuoteExpansion => write!(fmt, "<quote expansion>"),
292 FileName::MacroExpansion => write!(fmt, "<macro expansion>"),
293 FileName::Anon => write!(fmt, "<anon>"),
294 FileName::ProcMacroSourceCode => write!(fmt, "<proc-macro source code>"),
295 FileName::Url(ref u) => write!(fmt, "{}", u),
296 FileName::Custom(ref s) => {
297 write!(fmt, "{}", s)
298 }
299 FileName::Internal(ref s) => write!(fmt, "<{}>", s),
300 }
301 }
302}
303
304impl From<PathBuf> for FileName {
305 fn from(p: PathBuf) -> Self {
306 assert!(!p.to_string_lossy().ends_with('>'));
307 FileName::Real(p)
308 }
309}
310
311impl From<Url> for FileName {
312 fn from(url: Url) -> Self {
313 FileName::Url(url)
314 }
315}
316
317impl FileName {
318 pub fn is_real(&self) -> bool {
319 match *self {
320 FileName::Real(_) => true,
321 FileName::Macros(_)
322 | FileName::Anon
323 | FileName::MacroExpansion
324 | FileName::ProcMacroSourceCode
325 | FileName::Custom(_)
326 | FileName::QuoteExpansion
327 | FileName::Internal(_)
328 | FileName::Url(_) => false,
329 }
330 }
331
332 pub fn is_macros(&self) -> bool {
333 match *self {
334 FileName::Real(_)
335 | FileName::Anon
336 | FileName::MacroExpansion
337 | FileName::ProcMacroSourceCode
338 | FileName::Custom(_)
339 | FileName::QuoteExpansion
340 | FileName::Internal(_)
341 | FileName::Url(_) => false,
342 FileName::Macros(_) => true,
343 }
344 }
345}
346
347#[derive(Clone, Debug, Default, Hash, PartialEq, Eq)]
348#[cfg_attr(
349 feature = "diagnostic-serde",
350 derive(serde::Serialize, serde::Deserialize)
351)]
352#[cfg_attr(
353 any(feature = "rkyv-impl"),
354 derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
355)]
356#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
357#[cfg_attr(feature = "rkyv-impl", repr(C))]
358pub struct PrimarySpanLabel(pub Span, pub String);
359
360#[derive(Clone, Debug, Default, Hash, PartialEq, Eq)]
367#[cfg_attr(
368 feature = "diagnostic-serde",
369 derive(serde::Serialize, serde::Deserialize)
370)]
371#[cfg_attr(
372 any(feature = "rkyv-impl"),
373 derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
374)]
375#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
376#[cfg_attr(feature = "rkyv-impl", repr(C))]
377pub struct MultiSpan {
378 primary_spans: Vec<Span>,
379 span_labels: Vec<PrimarySpanLabel>,
380}
381
382extern "C" {
383 fn __span_dummy_with_cmt_proxy() -> u32;
384}
385
386impl Span {
387 #[inline]
388 pub fn lo(self) -> BytePos {
389 self.lo
390 }
391
392 #[inline]
393 pub fn new(mut lo: BytePos, mut hi: BytePos) -> Self {
394 if lo > hi {
395 std::mem::swap(&mut lo, &mut hi);
396 }
397
398 Span { lo, hi }
399 }
400
401 #[inline]
402 pub fn with_lo(&self, lo: BytePos) -> Span {
403 Span::new(lo, self.hi)
404 }
405
406 #[inline]
407 pub fn hi(self) -> BytePos {
408 self.hi
409 }
410
411 #[inline]
412 pub fn with_hi(&self, hi: BytePos) -> Span {
413 Span::new(self.lo, hi)
414 }
415
416 #[inline]
418 pub fn is_dummy(self) -> bool {
419 self.lo.0 == 0 && self.hi.0 == 0 || self.lo.0 >= DUMMY_RESERVE
420 }
421
422 #[inline]
423 pub fn is_pure(self) -> bool {
424 self.lo.is_pure()
425 }
426
427 #[inline]
428 pub fn is_placeholder(self) -> bool {
429 self.lo.is_placeholder()
430 }
431
432 #[inline]
434 pub fn is_dummy_ignoring_cmt(self) -> bool {
435 self.lo.0 == 0 && self.hi.0 == 0
436 }
437
438 #[inline]
441 pub fn shrink_to_lo(self) -> Span {
442 self.with_hi(self.lo)
443 }
444
445 #[inline]
447 pub fn shrink_to_hi(self) -> Span {
448 self.with_lo(self.hi)
449 }
450
451 pub fn substitute_dummy(self, other: Span) -> Span {
453 if self.is_dummy() {
454 other
455 } else {
456 self
457 }
458 }
459
460 pub fn contains(self, other: Span) -> bool {
462 self.lo <= other.lo && other.hi <= self.hi
463 }
464
465 pub fn source_equal(self, other: Span) -> bool {
470 self.lo == other.lo && self.hi == other.hi
471 }
472
473 pub fn trim_start(self, other: Span) -> Option<Span> {
475 if self.hi > other.hi {
476 Some(self.with_lo(cmp::max(self.lo, other.hi)))
477 } else {
478 None
479 }
480 }
481
482 pub fn to(self, end: Span) -> Span {
484 let span_data = self;
485 let end_data = end;
486 Span::new(
492 cmp::min(span_data.lo, end_data.lo),
493 cmp::max(span_data.hi, end_data.hi),
494 )
495 }
496
497 pub fn between(self, end: Span) -> Span {
499 let span = self;
500 Span::new(span.hi, end.lo)
501 }
502
503 pub fn until(self, end: Span) -> Span {
506 let span = self;
507 Span::new(span.lo, end.lo)
508 }
509
510 pub fn from_inner_byte_pos(self, start: usize, end: usize) -> Span {
511 let span = self;
512 Span::new(
513 span.lo + BytePos::from_usize(start),
514 span.lo + BytePos::from_usize(end),
515 )
516 }
517
518 pub fn dummy_with_cmt() -> Self {
521 #[cfg(all(feature = "__plugin_mode", target_arch = "wasm32"))]
522 {
523 let lo = BytePos(unsafe { __span_dummy_with_cmt_proxy() });
524
525 return Span { lo, hi: lo };
526 }
527
528 #[cfg(not(all(any(feature = "__plugin_mode"), target_arch = "wasm32")))]
529 return GLOBALS.with(|globals| {
530 let lo = BytePos(
531 globals
532 .dummy_cnt
533 .fetch_add(1, std::sync::atomic::Ordering::SeqCst),
534 );
535 Span { lo, hi: lo }
536 });
537 }
538}
539
540#[derive(Clone, Debug)]
541pub struct SpanLabel {
542 pub span: Span,
544
545 pub is_primary: bool,
548
549 pub label: Option<String>,
551}
552
553impl Default for Span {
554 fn default() -> Self {
555 DUMMY_SP
556 }
557}
558
559impl MultiSpan {
560 #[inline]
561 pub fn new() -> MultiSpan {
562 Self::default()
563 }
564
565 pub fn from_span(primary_span: Span) -> MultiSpan {
566 MultiSpan {
567 primary_spans: vec![primary_span],
568 span_labels: Vec::new(),
569 }
570 }
571
572 pub fn from_spans(vec: Vec<Span>) -> MultiSpan {
573 MultiSpan {
574 primary_spans: vec,
575 span_labels: Vec::new(),
576 }
577 }
578
579 pub fn push_span_label(&mut self, span: Span, label: String) {
580 self.span_labels.push(PrimarySpanLabel(span, label));
581 }
582
583 pub fn primary_span(&self) -> Option<Span> {
585 self.primary_spans.first().cloned()
586 }
587
588 pub fn primary_spans(&self) -> &[Span] {
590 &self.primary_spans
591 }
592
593 pub fn is_dummy(&self) -> bool {
596 let mut is_dummy = true;
597 for span in &self.primary_spans {
598 if !span.is_dummy() {
599 is_dummy = false;
600 }
601 }
602 is_dummy
603 }
604
605 pub fn replace(&mut self, before: Span, after: Span) -> bool {
609 let mut replacements_occurred = false;
610 for primary_span in &mut self.primary_spans {
611 if *primary_span == before {
612 *primary_span = after;
613 replacements_occurred = true;
614 }
615 }
616 for span_label in &mut self.span_labels {
617 if span_label.0 == before {
618 span_label.0 = after;
619 replacements_occurred = true;
620 }
621 }
622 replacements_occurred
623 }
624
625 pub fn span_labels(&self) -> Vec<SpanLabel> {
631 let is_primary = |span| self.primary_spans.contains(&span);
632
633 let mut span_labels = self
634 .span_labels
635 .iter()
636 .map(|&PrimarySpanLabel(span, ref label)| SpanLabel {
637 span,
638 is_primary: is_primary(span),
639 label: Some(label.clone()),
640 })
641 .collect::<Vec<_>>();
642
643 for &span in &self.primary_spans {
644 if !span_labels.iter().any(|sl| sl.span == span) {
645 span_labels.push(SpanLabel {
646 span,
647 is_primary: true,
648 label: None,
649 });
650 }
651 }
652
653 span_labels
654 }
655}
656
657impl From<Span> for MultiSpan {
658 fn from(span: Span) -> MultiSpan {
659 MultiSpan::from_span(span)
660 }
661}
662
663impl From<Vec<Span>> for MultiSpan {
664 fn from(spans: Vec<Span>) -> MultiSpan {
665 MultiSpan::from_spans(spans)
666 }
667}
668
669pub const NO_EXPANSION: SyntaxContext = SyntaxContext::empty();
670
671#[cfg_attr(
673 any(feature = "rkyv-impl"),
674 derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
675)]
676#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
677#[cfg_attr(feature = "rkyv-impl", repr(C))]
678#[derive(Copy, Clone, Eq, PartialEq, Debug)]
679pub struct MultiByteChar {
680 pub pos: BytePos,
682 pub bytes: u8,
684}
685
686impl MultiByteChar {
687 pub fn byte_to_char_diff(&self) -> u8 {
693 if self.bytes == 4 {
694 2
695 } else {
696 self.bytes - 1
697 }
698 }
699}
700
701#[cfg_attr(
703 any(feature = "rkyv-impl"),
704 derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
705)]
706#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
707#[cfg_attr(feature = "rkyv-impl", repr(u32))]
708#[derive(Copy, Clone, Eq, PartialEq, Debug)]
709pub enum NonNarrowChar {
710 ZeroWidth(BytePos),
712 Wide(BytePos, usize),
714 Tab(BytePos),
717}
718
719impl NonNarrowChar {
720 fn new(pos: BytePos, width: usize) -> Self {
721 match width {
722 0 => NonNarrowChar::ZeroWidth(pos),
723 4 => NonNarrowChar::Tab(pos),
724 w => NonNarrowChar::Wide(pos, w),
725 }
726 }
727
728 pub fn pos(self) -> BytePos {
730 match self {
731 NonNarrowChar::ZeroWidth(p) | NonNarrowChar::Wide(p, _) | NonNarrowChar::Tab(p) => p,
732 }
733 }
734
735 pub fn width(self) -> usize {
737 match self {
738 NonNarrowChar::ZeroWidth(_) => 0,
739 NonNarrowChar::Wide(_, width) => width,
740 NonNarrowChar::Tab(_) => 4,
741 }
742 }
743}
744
745impl Add<BytePos> for NonNarrowChar {
746 type Output = Self;
747
748 fn add(self, rhs: BytePos) -> Self {
749 match self {
750 NonNarrowChar::ZeroWidth(pos) => NonNarrowChar::ZeroWidth(pos + rhs),
751 NonNarrowChar::Wide(pos, width) => NonNarrowChar::Wide(pos + rhs, width),
752 NonNarrowChar::Tab(pos) => NonNarrowChar::Tab(pos + rhs),
753 }
754 }
755}
756
757impl Sub<BytePos> for NonNarrowChar {
758 type Output = Self;
759
760 fn sub(self, rhs: BytePos) -> Self {
761 match self {
762 NonNarrowChar::ZeroWidth(pos) => NonNarrowChar::ZeroWidth(pos - rhs),
763 NonNarrowChar::Wide(pos, width) => NonNarrowChar::Wide(pos - rhs, width),
764 NonNarrowChar::Tab(pos) => NonNarrowChar::Tab(pos - rhs),
765 }
766 }
767}
768
769#[doc(hidden)]
771#[cfg(feature = "rkyv-impl")]
772#[derive(Debug, Clone, Copy)]
773#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
774#[cfg_attr(feature = "rkyv-impl", repr(C))]
775pub struct EncodeArcString;
776
777#[cfg(feature = "rkyv-impl")]
778impl rkyv::with::ArchiveWith<Lrc<String>> for EncodeArcString {
779 type Archived = rkyv::Archived<String>;
780 type Resolver = rkyv::Resolver<String>;
781
782 fn resolve_with(
783 field: &Lrc<String>,
784 resolver: Self::Resolver,
785 out: rkyv::Place<Self::Archived>,
786 ) {
787 let s = field.to_string();
788 rkyv::Archive::resolve(&s, resolver, out);
789 }
790}
791
792#[cfg(feature = "rkyv-impl")]
793impl<S> rkyv::with::SerializeWith<Lrc<String>, S> for EncodeArcString
794where
795 S: ?Sized + rancor::Fallible + rkyv::ser::Writer,
796 S::Error: rancor::Source,
797{
798 fn serialize_with(field: &Lrc<String>, serializer: &mut S) -> Result<Self::Resolver, S::Error> {
799 rkyv::string::ArchivedString::serialize_from_str(field, serializer)
800 }
801}
802
803#[cfg(feature = "rkyv-impl")]
804impl<D> rkyv::with::DeserializeWith<rkyv::Archived<String>, Lrc<String>, D> for EncodeArcString
805where
806 D: ?Sized + rancor::Fallible,
807{
808 fn deserialize_with(
809 field: &rkyv::Archived<String>,
810 deserializer: &mut D,
811 ) -> Result<Lrc<String>, D::Error> {
812 use rkyv::Deserialize;
813
814 let s: String = field.deserialize(deserializer)?;
815
816 Ok(s.into())
817 }
818}
819
820#[cfg_attr(
822 any(feature = "rkyv-impl"),
823 derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
824)]
825#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
826#[cfg_attr(feature = "rkyv-impl", repr(C))]
827#[derive(Clone)]
828pub struct SourceFile {
829 pub name: Lrc<FileName>,
833 pub name_was_remapped: bool,
836 pub unmapped_path: Option<Lrc<FileName>>,
839 pub crate_of_origin: u32,
841 #[cfg_attr(any(feature = "rkyv-impl"), rkyv(with = EncodeArcString))]
843 pub src: Lrc<String>,
844 pub src_hash: u128,
846 pub start_pos: BytePos,
848 pub end_pos: BytePos,
850 pub name_hash: u128,
852
853 lazy: CacheCell<SourceFileAnalysis>,
854}
855
856#[cfg_attr(
857 any(feature = "rkyv-impl"),
858 derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
859)]
860#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
861#[cfg_attr(feature = "rkyv-impl", repr(C))]
862#[derive(Clone)]
863pub struct SourceFileAnalysis {
864 pub lines: Vec<BytePos>,
866 pub multibyte_chars: Vec<MultiByteChar>,
868 pub non_narrow_chars: Vec<NonNarrowChar>,
870}
871
872impl fmt::Debug for SourceFile {
873 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
874 write!(fmt, "SourceFile({})", self.name)
875 }
876}
877
878impl SourceFile {
879 pub fn new(
880 name: Lrc<FileName>,
881 name_was_remapped: bool,
882 unmapped_path: Lrc<FileName>,
883 mut src: String,
884 start_pos: BytePos,
885 ) -> SourceFile {
886 remove_bom(&mut src);
887
888 Self::new_from(
889 name,
890 name_was_remapped,
891 unmapped_path,
892 Lrc::new(src),
893 start_pos,
894 )
895 }
896
897 pub fn new_from(
899 name: Lrc<FileName>,
900 name_was_remapped: bool,
901 unmapped_path: Lrc<FileName>,
902 src: Lrc<String>,
903 start_pos: BytePos,
904 ) -> SourceFile {
905 debug_assert_ne!(
906 start_pos,
907 BytePos::DUMMY,
908 "BytePos::DUMMY is reserved and `SourceFile` should not use it"
909 );
910
911 let src_hash = {
912 let mut hasher: StableHasher = StableHasher::new();
913 hasher.write(src.as_bytes());
914 hasher.finish()
915 };
916 let name_hash = {
917 let mut hasher: StableHasher = StableHasher::new();
918 name.hash(&mut hasher);
919 hasher.finish()
920 };
921 let end_pos = start_pos.to_usize() + src.len();
922
923 SourceFile {
924 name,
925 name_was_remapped,
926 unmapped_path: Some(unmapped_path),
927 crate_of_origin: 0,
928 src,
929 src_hash,
930 start_pos,
931 end_pos: SmallPos::from_usize(end_pos),
932 name_hash,
933 lazy: CacheCell::new(),
934 }
935 }
936
937 pub fn line_begin_pos(&self, pos: BytePos) -> BytePos {
939 let line_index = self.lookup_line(pos).unwrap();
940 let analysis = self.analyze();
941 analysis.lines[line_index]
942 }
943
944 pub fn get_line(&self, line_number: usize) -> Option<Cow<'_, str>> {
947 fn get_until_newline(src: &str, begin: usize) -> &str {
948 let slice = &src[begin..];
952 match slice.find('\n') {
953 Some(e) => &slice[..e],
954 None => slice,
955 }
956 }
957
958 let begin = {
959 let analysis = self.analyze();
960 let line = analysis.lines.get(line_number)?;
961 let begin: BytePos = *line - self.start_pos;
962 begin.to_usize()
963 };
964
965 Some(Cow::from(get_until_newline(&self.src, begin)))
966 }
967
968 pub fn is_real_file(&self) -> bool {
969 self.name.is_real()
970 }
971
972 pub fn byte_length(&self) -> u32 {
973 self.end_pos.0 - self.start_pos.0
974 }
975
976 pub fn count_lines(&self) -> usize {
977 let analysis = self.analyze();
978 analysis.lines.len()
979 }
980
981 pub fn lookup_line(&self, pos: BytePos) -> Option<usize> {
986 let analysis = self.analyze();
987 if analysis.lines.is_empty() {
988 return None;
989 }
990
991 let line_index = lookup_line(&analysis.lines, pos);
992 assert!(line_index < analysis.lines.len() as isize);
993 if line_index >= 0 {
994 Some(line_index as usize)
995 } else {
996 None
997 }
998 }
999
1000 pub fn line_bounds(&self, line_index: usize) -> (BytePos, BytePos) {
1001 if self.start_pos == self.end_pos {
1002 return (self.start_pos, self.end_pos);
1003 }
1004
1005 let analysis = self.analyze();
1006
1007 assert!(line_index < analysis.lines.len());
1008 if line_index == (analysis.lines.len() - 1) {
1009 (analysis.lines[line_index], self.end_pos)
1010 } else {
1011 (analysis.lines[line_index], analysis.lines[line_index + 1])
1012 }
1013 }
1014
1015 #[inline]
1016 pub fn contains(&self, byte_pos: BytePos) -> bool {
1017 byte_pos >= self.start_pos && byte_pos <= self.end_pos
1018 }
1019
1020 pub fn analyze(&self) -> &SourceFileAnalysis {
1021 self.lazy.get_or_init(|| {
1022 let (lines, multibyte_chars, non_narrow_chars) =
1023 analyze_source_file::analyze_source_file(&self.src[..], self.start_pos);
1024 SourceFileAnalysis {
1025 lines,
1026 multibyte_chars,
1027 non_narrow_chars,
1028 }
1029 })
1030 }
1031}
1032
1033pub(super) fn remove_bom(src: &mut String) {
1035 if src.starts_with('\u{feff}') {
1036 src.drain(..3);
1037 }
1038}
1039
1040pub trait SmallPos {
1045 fn from_usize(n: usize) -> Self;
1046 fn to_usize(&self) -> usize;
1047 fn from_u32(n: u32) -> Self;
1048 fn to_u32(&self) -> u32;
1049}
1050
1051#[derive(
1064 Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize, Default,
1065)]
1066#[serde(transparent)]
1067#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1068#[cfg_attr(
1069 any(feature = "rkyv-impl"),
1070 derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
1071)]
1072#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
1073#[cfg_attr(feature = "rkyv-impl", repr(C))]
1074#[cfg_attr(feature = "shrink-to-fit", derive(shrink_to_fit::ShrinkToFit))]
1075pub struct BytePos(#[cfg_attr(feature = "__rkyv", rkyv(omit_bounds))] pub u32);
1076
1077impl BytePos {
1078 pub const DUMMY: Self = BytePos(0);
1080 const MIN_RESERVED: Self = BytePos(DUMMY_RESERVE);
1081 pub const PLACEHOLDER: Self = BytePos(u32::MAX - 2);
1084 pub const PURE: Self = BytePos(u32::MAX - 1);
1086 pub const SYNTHESIZED: Self = BytePos(u32::MAX);
1088
1089 pub const fn is_reserved_for_comments(self) -> bool {
1090 self.0 >= Self::MIN_RESERVED.0 && self.0 != u32::MAX
1091 }
1092
1093 pub const fn is_dummy(self) -> bool {
1096 self.0 == 0
1097 }
1098
1099 pub const fn is_pure(self) -> bool {
1100 self.0 == Self::PURE.0
1101 }
1102
1103 pub const fn is_placeholder(self) -> bool {
1104 self.0 == Self::PLACEHOLDER.0
1105 }
1106
1107 pub const fn can_have_comment(self) -> bool {
1110 self.0 != 0
1111 }
1112}
1113
1114#[cfg_attr(
1118 any(feature = "rkyv-impl"),
1119 derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
1120)]
1121#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
1122#[cfg_attr(feature = "rkyv-impl", repr(C))]
1123#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
1124pub struct CharPos(pub usize);
1125
1126impl SmallPos for BytePos {
1130 #[inline(always)]
1131 fn from_usize(n: usize) -> BytePos {
1132 BytePos(n as u32)
1133 }
1134
1135 #[inline(always)]
1136 fn to_usize(&self) -> usize {
1137 self.0 as usize
1138 }
1139
1140 #[inline(always)]
1141 fn from_u32(n: u32) -> BytePos {
1142 BytePos(n)
1143 }
1144
1145 #[inline(always)]
1146 fn to_u32(&self) -> u32 {
1147 self.0
1148 }
1149}
1150
1151impl Add for BytePos {
1152 type Output = BytePos;
1153
1154 #[inline(always)]
1155 fn add(self, rhs: BytePos) -> BytePos {
1156 BytePos((self.to_usize() + rhs.to_usize()) as u32)
1157 }
1158}
1159
1160impl Sub for BytePos {
1161 type Output = BytePos;
1162
1163 #[inline(always)]
1164 fn sub(self, rhs: BytePos) -> BytePos {
1165 BytePos((self.to_usize() - rhs.to_usize()) as u32)
1166 }
1167}
1168
1169impl SmallPos for CharPos {
1170 #[inline(always)]
1171 fn from_usize(n: usize) -> CharPos {
1172 CharPos(n)
1173 }
1174
1175 #[inline(always)]
1176 fn to_usize(&self) -> usize {
1177 self.0
1178 }
1179
1180 #[inline(always)]
1181 fn from_u32(n: u32) -> CharPos {
1182 CharPos(n as usize)
1183 }
1184
1185 #[inline(always)]
1186 fn to_u32(&self) -> u32 {
1187 self.0 as u32
1188 }
1189}
1190
1191impl Add for CharPos {
1192 type Output = CharPos;
1193
1194 #[inline(always)]
1195 fn add(self, rhs: CharPos) -> CharPos {
1196 CharPos(self.to_usize() + rhs.to_usize())
1197 }
1198}
1199
1200impl Sub for CharPos {
1201 type Output = CharPos;
1202
1203 #[inline(always)]
1204 fn sub(self, rhs: CharPos) -> CharPos {
1205 CharPos(self.to_usize() - rhs.to_usize())
1206 }
1207}
1208
1209#[derive(Debug, Clone)]
1220pub struct Loc {
1221 pub file: Lrc<SourceFile>,
1223 pub line: usize,
1225 pub col: CharPos,
1227 pub col_display: usize,
1229}
1230
1231#[cfg_attr(
1234 any(feature = "rkyv-impl"),
1235 derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize, Debug, Clone)
1236)]
1237#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
1238#[cfg_attr(feature = "rkyv-impl", repr(C))]
1239pub struct PartialLoc {
1240 pub source_file: Option<Lrc<SourceFile>>,
1241 pub line: usize,
1242 pub col: usize,
1243 pub col_display: usize,
1244}
1245
1246#[derive(Debug)]
1250pub struct LocWithOpt {
1251 pub filename: Lrc<FileName>,
1252 pub line: usize,
1253 pub col: CharPos,
1254 pub file: Option<Lrc<SourceFile>>,
1255}
1256
1257#[derive(Debug)]
1259pub struct SourceFileAndLine {
1260 pub sf: Lrc<SourceFile>,
1261 pub line: usize,
1262}
1263
1264#[cfg_attr(
1265 any(feature = "rkyv-impl"),
1266 derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
1267)]
1268#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
1269#[cfg_attr(feature = "rkyv-impl", repr(C))]
1270#[derive(Debug)]
1271pub struct SourceFileAndBytePos {
1272 pub sf: Lrc<SourceFile>,
1273 pub pos: BytePos,
1274}
1275
1276#[derive(Copy, Clone, Debug, PartialEq, Eq)]
1277#[cfg_attr(
1278 any(feature = "rkyv-impl"),
1279 derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
1280)]
1281#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
1282#[cfg_attr(feature = "rkyv-impl", repr(C))]
1283pub struct LineInfo {
1284 pub line_index: usize,
1286
1287 pub start_col: CharPos,
1289
1290 pub end_col: CharPos,
1292}
1293
1294#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
1296pub struct LineCol {
1297 pub line: u32,
1299
1300 pub col: u32,
1302}
1303
1304pub struct FileLines {
1311 pub file: Lrc<SourceFile>,
1312 pub lines: Vec<LineInfo>,
1313}
1314
1315#[cfg_attr(
1318 any(feature = "rkyv-impl"),
1319 derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize, Debug, Clone)
1320)]
1321#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
1322#[cfg_attr(feature = "rkyv-impl", repr(C))]
1323pub struct PartialFileLines {
1324 pub file: Option<Lrc<SourceFile>>,
1325 pub lines: Vec<LineInfo>,
1326}
1327
1328pub type FileLinesResult = Result<FileLines, Box<SpanLinesError>>;
1334#[cfg(feature = "__plugin")]
1335pub type PartialFileLinesResult = Result<PartialFileLines, Box<SpanLinesError>>;
1336
1337#[derive(Clone, PartialEq, Eq, Debug)]
1338#[cfg_attr(
1339 any(feature = "rkyv-impl"),
1340 derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
1341)]
1342#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
1343#[cfg_attr(feature = "rkyv-impl", repr(u32))]
1344pub enum SpanLinesError {
1345 IllFormedSpan(Span),
1346 DistinctSources(DistinctSources),
1347}
1348
1349#[derive(Clone, PartialEq, Eq, Debug)]
1350#[cfg_attr(
1351 any(feature = "rkyv-impl"),
1352 derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
1353)]
1354#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
1355#[cfg_attr(feature = "rkyv-impl", repr(u32))]
1356pub enum SpanSnippetError {
1357 DummyBytePos,
1358 IllFormedSpan(Span),
1359 DistinctSources(DistinctSources),
1360 MalformedForSourcemap(MalformedSourceMapPositions),
1361 SourceNotAvailable { filename: FileName },
1362 LookupFailed(SourceMapLookupError),
1363}
1364
1365#[derive(Clone, PartialEq, Eq, Debug)]
1370#[cfg_attr(
1371 any(feature = "rkyv-impl"),
1372 derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
1373)]
1374#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
1375#[cfg_attr(feature = "rkyv-impl", repr(u32))]
1376pub enum SourceMapLookupError {
1377 NoFileFor(BytePos),
1378}
1379
1380#[derive(Clone, PartialEq, Eq, Debug)]
1381#[cfg_attr(
1382 any(feature = "rkyv-impl"),
1383 derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
1384)]
1385#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
1386#[cfg_attr(feature = "rkyv-impl", repr(C))]
1387pub struct FilePos(pub Lrc<FileName>, pub BytePos);
1388
1389#[derive(Clone, PartialEq, Eq, Debug)]
1390#[cfg_attr(
1391 any(feature = "rkyv-impl"),
1392 derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
1393)]
1394#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
1395#[cfg_attr(feature = "rkyv-impl", repr(C))]
1396pub struct DistinctSources {
1397 pub begin: FilePos,
1398 pub end: FilePos,
1399}
1400
1401#[derive(Clone, PartialEq, Eq, Debug)]
1402#[cfg_attr(
1403 any(feature = "rkyv-impl"),
1404 derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
1405)]
1406#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
1407#[cfg_attr(feature = "rkyv-impl", repr(C))]
1408pub struct MalformedSourceMapPositions {
1409 pub name: Lrc<FileName>,
1410 pub source_len: usize,
1411 pub begin_pos: BytePos,
1412 pub end_pos: BytePos,
1413}
1414
1415fn lookup_line(lines: &[BytePos], pos: BytePos) -> isize {
1419 match lines.binary_search(&pos) {
1420 Ok(line) => line as isize,
1421 Err(line) => line as isize - 1,
1422 }
1423}
1424
1425impl From<SourceMapLookupError> for Box<SpanSnippetError> {
1426 #[cold]
1427 fn from(err: SourceMapLookupError) -> Self {
1428 Box::new(SpanSnippetError::LookupFailed(err))
1429 }
1430}
1431
1432#[cfg(test)]
1433mod tests {
1434 use super::{lookup_line, BytePos, Span};
1435
1436 #[test]
1437 fn test_lookup_line() {
1438 let lines = &[BytePos(3), BytePos(17), BytePos(28)];
1439
1440 assert_eq!(lookup_line(lines, BytePos(0)), -1);
1441 assert_eq!(lookup_line(lines, BytePos(3)), 0);
1442 assert_eq!(lookup_line(lines, BytePos(4)), 0);
1443
1444 assert_eq!(lookup_line(lines, BytePos(16)), 0);
1445 assert_eq!(lookup_line(lines, BytePos(17)), 1);
1446 assert_eq!(lookup_line(lines, BytePos(18)), 1);
1447
1448 assert_eq!(lookup_line(lines, BytePos(28)), 2);
1449 assert_eq!(lookup_line(lines, BytePos(29)), 2);
1450 }
1451
1452 #[test]
1453 fn size_of_span() {
1454 assert_eq!(std::mem::size_of::<Span>(), 8);
1455 }
1456}