diff --git a/build/probe.rs b/build/probe.rs index 5afa13a..2c4947a 100644 --- a/build/probe.rs +++ b/build/probe.rs @@ -6,9 +6,13 @@ extern crate proc_macro; -use core::ops::RangeBounds; +use core::ops::{Range, RangeBounds}; use proc_macro::{Literal, Span}; +pub fn byte_range(this: &Span) -> Range { + this.byte_range() +} + pub fn join(this: &Span, other: Span) -> Option { this.join(other) } diff --git a/src/fallback.rs b/src/fallback.rs index f26d156..16bf645 100644 --- a/src/fallback.rs +++ b/src/fallback.rs @@ -11,6 +11,8 @@ use core::cell::RefCell; use core::cmp; use core::fmt::{self, Debug, Display, Write}; use core::mem::ManuallyDrop; +#[cfg(span_locations)] +use core::ops::Range; use core::ops::RangeBounds; use core::ptr; use core::str::FromStr; @@ -372,7 +374,7 @@ impl FileInfo { span.lo >= self.span.lo && span.hi <= self.span.hi } - fn source_text(&mut self, span: Span) -> String { + fn byte_range(&mut self, span: Span) -> Range { let lo_char = (span.lo - self.span.lo) as usize; // Look up offset of the largest already-computed char index that is @@ -401,11 +403,15 @@ impl FileInfo { let trunc_lo = &self.source_text[lo_byte..]; let char_len = (span.hi - span.lo) as usize; - let source_text = match trunc_lo.char_indices().nth(char_len) { - Some((offset, _ch)) => &trunc_lo[..offset], - None => trunc_lo, - }; - source_text.to_owned() + lo_byte..match trunc_lo.char_indices().nth(char_len) { + Some((offset, _ch)) => lo_byte + offset, + None => self.source_text.len(), + } + } + + fn source_text(&mut self, span: Span) -> String { + let byte_range = self.byte_range(span); + self.source_text[byte_range].to_owned() } } @@ -547,6 +553,21 @@ impl Span { }) } + #[cfg(span_locations)] + pub fn byte_range(&self) -> Range { + #[cfg(fuzzing)] + return 0..0; + + #[cfg(not(fuzzing))] + { + if self.is_call_site() { + 0..0 + } else { + SOURCE_MAP.with(|sm| sm.borrow_mut().fileinfo_mut(*self).byte_range(*self)) + } + } + } + #[cfg(span_locations)] pub fn start(&self) -> LineColumn { #[cfg(fuzzing)] diff --git a/src/lib.rs b/src/lib.rs index 5fd229a..648afde 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -164,6 +164,8 @@ use crate::marker::{ProcMacroAutoTraits, MARKER}; use core::cmp::Ordering; use core::fmt::{self, Debug, Display}; use core::hash::{Hash, Hasher}; +#[cfg(span_locations)] +use core::ops::Range; use core::ops::RangeBounds; use core::str::FromStr; use std::error::Error; @@ -472,6 +474,21 @@ impl Span { SourceFile::_new(self.inner.source_file()) } + /// Returns the span's byte position range in the source file. + /// + /// This method requires the `"span-locations"` feature to be enabled. + /// + /// When executing in a procedural macro context, the returned range is only + /// accurate if compiled with a nightly toolchain. The stable toolchain does + /// not have this information available. When executing outside of a + /// procedural macro, such as main.rs or build.rs, the byte range is always + /// accurate regardless of toolchain. + #[cfg(span_locations)] + #[cfg_attr(doc_cfg, doc(cfg(feature = "span-locations")))] + pub fn byte_range(&self) -> Range { + self.inner.byte_range() + } + /// Get the starting line/column in the source file for this span. /// /// This method requires the `"span-locations"` feature to be enabled. diff --git a/src/wrapper.rs b/src/wrapper.rs index 5169dca..a71043a 100644 --- a/src/wrapper.rs +++ b/src/wrapper.rs @@ -3,6 +3,8 @@ use crate::detection::inside_proc_macro; use crate::location::LineColumn; use crate::{fallback, Delimiter, Punct, Spacing, TokenTree}; use core::fmt::{self, Debug, Display}; +#[cfg(span_locations)] +use core::ops::Range; use core::ops::RangeBounds; use core::str::FromStr; use std::panic; @@ -460,6 +462,17 @@ impl Span { } } + #[cfg(span_locations)] + pub fn byte_range(&self) -> Range { + match self { + #[cfg(proc_macro_span)] + Span::Compiler(s) => s.byte_range(), + #[cfg(not(proc_macro_span))] + Span::Compiler(_) => 0..0, + Span::Fallback(s) => s.byte_range(), + } + } + #[cfg(span_locations)] pub fn start(&self) -> LineColumn { match self {