Skip to content

proc_macro::Span::len and subspan #53930

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 80 additions & 1 deletion src/libproc_macro/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ mod diagnostic;
pub use diagnostic::{Diagnostic, Level};

use std::{ascii, fmt, iter};
use std::ops::{Bound, RangeBounds};
use std::path::PathBuf;
use rustc_data_structures::sync::Lrc;
use std::str::FromStr;
Expand All @@ -64,7 +65,7 @@ use syntax::errors::DiagnosticBuilder;
use syntax::parse::{self, token};
use syntax::symbol::Symbol;
use syntax::tokenstream::{self, DelimSpan};
use syntax_pos::{Pos, FileName};
use syntax_pos::{BytePos, Pos, FileName};

/// The main type provided by this crate, representing an abstract stream of
/// tokens, or, more specifically, a sequence of token trees.
Expand Down Expand Up @@ -348,6 +349,84 @@ impl Span {
}
}

/// Number of bytes of source code covered by this span.
///
/// In other words, the number of bytes from the first byte associated with
/// this span to the byte after the last byte associated with this span.
///
/// # Example
///
/// In the following line of source code, the span associated with the
/// parenthesis token would have a `len` of 6 bytes.
///
/// ```text
/// pub fn len(self) -> usize {
/// ^^^^^^
/// ```
#[unstable(feature = "proc_macro_span", issue = "38356")]
pub fn len(self) -> usize {
self.0.hi().to_usize() - self.0.lo().to_usize()
}

/// Produces a span for some range of the bytes represented by this span.
///
/// # Examples
///
/// In the following line of source code the span of the parenthesis token
/// is shown. We could call `span.subspan(..1)` on this span to receive a
/// span referring to just the first byte, the opening parenthesis.
///
/// ```text
/// pub fn subspan<R: RangeBounds<usize>>(self, range: R) -> Span {
/// ^^^^^^^^^^^^^^^^
/// ```
///
/// In this line the indicated span would be obtained by
/// `span.subspan(9..12)` on the span of the full string literal token.
///
/// ```text
/// println!("{a} {b} {c}", a=1, b=2);
/// ^^^
/// ```
///
/// # Panics
///
/// Panics if the start of the resulting span would be greater than its end,
/// or if the upper bound of the range is out of bounds considering the
/// length of this span.
///
/// In the case of a half-open range like `lo..hi` this means we require `lo
/// <= hi` and `hi <= span.len()`.
#[unstable(feature = "proc_macro_span", issue = "38356")]
pub fn subspan<R: RangeBounds<usize>>(self, range: R) -> Span {
let len = self.len();
let hi = match range.end_bound() {
Bound::Included(&hi) => {
assert!(hi < len);
hi + 1
}
Bound::Excluded(&hi) => {
assert!(hi <= len);
hi
}
Bound::Unbounded => len,
};
let lo = match range.start_bound() {
Bound::Included(&lo) => {
assert!(lo <= hi);
lo
}
Bound::Excluded(&lo) => {
assert!(lo < hi);
lo + 1
}
Bound::Unbounded => 0,
};
let lo = BytePos::from_usize(self.0.lo().to_usize() + lo);
let hi = BytePos::from_usize(self.0.lo().to_usize() + hi);
Span(self.0.with_lo(lo).with_hi(hi))
}

/// Create a new span encompassing `self` and `other`.
///
/// Returns `None` if `self` and `other` are from different files.
Expand Down