Skip to content

Commit

Permalink
Merge pull request #166 from dtolnay/location
Browse files Browse the repository at this point in the history
Expose span locations on stable
  • Loading branch information
dtolnay authored Jan 31, 2019
2 parents ad8e2e5 + 3b1f7d2 commit 2b01a3f
Show file tree
Hide file tree
Showing 8 changed files with 91 additions and 46 deletions.
2 changes: 2 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ matrix:
script:
- cargo test
- cargo test --no-default-features
- cargo test --features span-locations
- RUSTFLAGS='--cfg procmacro2_semver_exempt' cargo test
- RUSTFLAGS='--cfg procmacro2_semver_exempt' cargo test --no-default-features
- cargo update -Z minimal-versions && cargo build
Expand All @@ -25,6 +26,7 @@ before_script:
script:
- cargo test
- cargo test --no-default-features
- cargo test --features span-locations
- RUSTFLAGS='--cfg procmacro2_semver_exempt' cargo test
- RUSTFLAGS='--cfg procmacro2_semver_exempt' cargo test --no-default-features

Expand Down
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ quote = "0.6"
proc-macro = []
default = ["proc-macro"]

# Expose methods Span::start and Span::end which give the line/column location
# of a token.
span-locations = []

# This feature no longer means anything.
nightly = []

Expand Down
21 changes: 16 additions & 5 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@
// "super_unstable"
// Implement the semver exempt API in terms of the nightly-only proc_macro
// API. Enabled when using procmacro2_semver_exempt on a nightly compiler.
//
// "span_locations"
// Provide methods Span::start and Span::end which give the line/column
// location of a token. Enabled by procmacro2_semver_exempt or the
// "span-locations" Cargo cfg. This is behind a cfg because tracking
// location inside spans is a performance hit.

use std::env;
use std::process::Command;
Expand All @@ -50,17 +56,22 @@ fn main() {
println!("cargo:rustc-cfg=u128");
}

if !enable_use_proc_macro(&target) {
return;
}
println!("cargo:rustc-cfg=use_proc_macro");

let semver_exempt = cfg!(procmacro2_semver_exempt);
if semver_exempt {
// https://github.com/alexcrichton/proc-macro2/issues/147
println!("cargo:rustc-cfg=procmacro2_semver_exempt");
}

if semver_exempt || cfg!(feature = "span-locations") {
println!("cargo:rustc-cfg=span_locations");
}

if !enable_use_proc_macro(&target) {
return;
}

println!("cargo:rustc-cfg=use_proc_macro");

// Rust 1.29 stabilized the necessary APIs in the `proc_macro` crate
if version.nightly || version.minor >= 29 && !semver_exempt {
println!("cargo:rustc-cfg=wrap_proc_macro");
Expand Down
73 changes: 49 additions & 24 deletions src/fallback.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
#![cfg_attr(not(procmacro2_semver_exempt), allow(dead_code))]

#[cfg(procmacro2_semver_exempt)]
#[cfg(span_locations)]
use std::cell::RefCell;
#[cfg(procmacro2_semver_exempt)]
use std::cmp;
Expand Down Expand Up @@ -35,7 +33,7 @@ impl TokenStream {
}
}

#[cfg(procmacro2_semver_exempt)]
#[cfg(span_locations)]
fn get_cursor(src: &str) -> Cursor {
// Create a dummy file & add it to the codemap
CODEMAP.with(|cm| {
Expand All @@ -49,7 +47,7 @@ fn get_cursor(src: &str) -> Cursor {
})
}

#[cfg(not(procmacro2_semver_exempt))]
#[cfg(not(span_locations))]
fn get_cursor(src: &str) -> Cursor {
Cursor { rest: src }
}
Expand Down Expand Up @@ -225,27 +223,41 @@ pub struct LineColumn {
pub column: usize,
}

#[cfg(procmacro2_semver_exempt)]
#[cfg(span_locations)]
thread_local! {
static CODEMAP: RefCell<Codemap> = RefCell::new(Codemap {
// NOTE: We start with a single dummy file which all call_site() and
// def_site() spans reference.
files: vec![FileInfo {
name: "<unspecified>".to_owned(),
span: Span { lo: 0, hi: 0 },
lines: vec![0],
files: vec![{
#[cfg(procmacro2_semver_exempt)]
{
FileInfo {
name: "<unspecified>".to_owned(),
span: Span { lo: 0, hi: 0 },
lines: vec![0],
}
}

#[cfg(not(procmacro2_semver_exempt))]
{
FileInfo {
span: Span { lo: 0, hi: 0 },
lines: vec![0],
}
}
}],
});
}

#[cfg(procmacro2_semver_exempt)]
#[cfg(span_locations)]
struct FileInfo {
#[cfg(procmacro2_semver_exempt)]
name: String,
span: Span,
lines: Vec<usize>,
}

#[cfg(procmacro2_semver_exempt)]
#[cfg(span_locations)]
impl FileInfo {
fn offset_line_column(&self, offset: usize) -> LineColumn {
assert!(self.span_within(Span {
Expand All @@ -271,7 +283,7 @@ impl FileInfo {
}

/// Computesthe offsets of each line in the given source string.
#[cfg(procmacro2_semver_exempt)]
#[cfg(span_locations)]
fn lines_offsets(s: &str) -> Vec<usize> {
let mut lines = vec![0];
let mut prev = 0;
Expand All @@ -282,12 +294,12 @@ fn lines_offsets(s: &str) -> Vec<usize> {
lines
}

#[cfg(procmacro2_semver_exempt)]
#[cfg(span_locations)]
struct Codemap {
files: Vec<FileInfo>,
}

#[cfg(procmacro2_semver_exempt)]
#[cfg(span_locations)]
impl Codemap {
fn next_start_pos(&self) -> u32 {
// Add 1 so there's always space between files.
Expand All @@ -306,12 +318,20 @@ impl Codemap {
hi: lo + (src.len() as u32),
};

#[cfg(procmacro2_semver_exempt)]
self.files.push(FileInfo {
name: name.to_owned(),
span: span,
lines: lines,
});

#[cfg(not(procmacro2_semver_exempt))]
self.files.push(FileInfo {
span: span,
lines: lines,
});
let _ = name;

span
}

Expand All @@ -327,34 +347,37 @@ impl Codemap {

#[derive(Clone, Copy, PartialEq, Eq)]
pub struct Span {
#[cfg(procmacro2_semver_exempt)]
#[cfg(span_locations)]
lo: u32,
#[cfg(procmacro2_semver_exempt)]
#[cfg(span_locations)]
hi: u32,
}

impl Span {
#[cfg(not(procmacro2_semver_exempt))]
#[cfg(not(span_locations))]
pub fn call_site() -> Span {
Span {}
}

#[cfg(procmacro2_semver_exempt)]
#[cfg(span_locations)]
pub fn call_site() -> Span {
Span { lo: 0, hi: 0 }
}

#[cfg(procmacro2_semver_exempt)]
pub fn def_site() -> Span {
Span::call_site()
}

#[cfg(procmacro2_semver_exempt)]
pub fn resolved_at(&self, _other: Span) -> Span {
// Stable spans consist only of line/column information, so
// `resolved_at` and `located_at` only select which span the
// caller wants line/column information from.
*self
}

#[cfg(procmacro2_semver_exempt)]
pub fn located_at(&self, other: Span) -> Span {
other
}
Expand All @@ -370,7 +393,7 @@ impl Span {
})
}

#[cfg(procmacro2_semver_exempt)]
#[cfg(span_locations)]
pub fn start(&self) -> LineColumn {
CODEMAP.with(|cm| {
let cm = cm.borrow();
Expand All @@ -379,7 +402,7 @@ impl Span {
})
}

#[cfg(procmacro2_semver_exempt)]
#[cfg(span_locations)]
pub fn end(&self) -> LineColumn {
CODEMAP.with(|cm| {
let cm = cm.borrow();
Expand Down Expand Up @@ -448,10 +471,12 @@ impl Group {
self.span
}

#[cfg(procmacro2_semver_exempt)]
pub fn span_open(&self) -> Span {
self.span
}

#[cfg(procmacro2_semver_exempt)]
pub fn span_close(&self) -> Span {
self.span
}
Expand Down Expand Up @@ -788,16 +813,16 @@ fn token_stream(mut input: Cursor) -> PResult<TokenStream> {
Ok((input, TokenStream { inner: trees }))
}

#[cfg(not(procmacro2_semver_exempt))]
#[cfg(not(span_locations))]
fn spanned<'a, T>(
input: Cursor<'a>,
f: fn(Cursor<'a>) -> PResult<'a, T>,
) -> PResult<'a, (T, ::Span)> {
let (a, b) = f(skip_whitespace(input))?;
Ok((a, ((b, ::Span::_new_stable(Span {})))))
Ok((a, ((b, ::Span::_new_stable(Span::call_site())))))
}

#[cfg(procmacro2_semver_exempt)]
#[cfg(span_locations)]
fn spanned<'a, T>(
input: Cursor<'a>,
f: fn(Cursor<'a>) -> PResult<'a, T>,
Expand Down
16 changes: 7 additions & 9 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,8 @@

// Proc-macro2 types in rustdoc of other crates get linked to here.
#![doc(html_root_url = "https://docs.rs/proc-macro2/0.4.26")]
#![cfg_attr(
super_unstable,
feature(proc_macro_raw_ident, proc_macro_span, proc_macro_def_site)
)]
#![cfg_attr(nightly, feature(proc_macro_span))]
#![cfg_attr(super_unstable, feature(proc_macro_raw_ident, proc_macro_def_site))]

#[cfg(use_proc_macro)]
extern crate proc_macro;
Expand Down Expand Up @@ -302,7 +300,7 @@ impl fmt::Debug for SourceFile {
/// A line-column pair representing the start or end of a `Span`.
///
/// This type is semver exempt and not exposed by default.
#[cfg(procmacro2_semver_exempt)]
#[cfg(span_locations)]
pub struct LineColumn {
/// The 1-indexed line in the source file on which the span starts or ends
/// (inclusive).
Expand Down Expand Up @@ -401,8 +399,8 @@ impl Span {

/// Get the starting line/column in the source file for this span.
///
/// This method is semver exempt and not exposed by default.
#[cfg(procmacro2_semver_exempt)]
/// This method requires the `"span-locations"` feature to be enabled.
#[cfg(span_locations)]
pub fn start(&self) -> LineColumn {
let imp::LineColumn { line, column } = self.inner.start();
LineColumn {
Expand All @@ -413,8 +411,8 @@ impl Span {

/// Get the ending line/column in the source file for this span.
///
/// This method is semver exempt and not exposed by default.
#[cfg(procmacro2_semver_exempt)]
/// This method requires the `"span-locations"` feature to be enabled.
#[cfg(span_locations)]
pub fn end(&self) -> LineColumn {
let imp::LineColumn { line, column } = self.inner.end();
LineColumn {
Expand Down
6 changes: 3 additions & 3 deletions src/strnom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,18 @@ use fallback::LexError;
#[derive(Copy, Clone, Eq, PartialEq)]
pub struct Cursor<'a> {
pub rest: &'a str,
#[cfg(procmacro2_semver_exempt)]
#[cfg(span_locations)]
pub off: u32,
}

impl<'a> Cursor<'a> {
#[cfg(not(procmacro2_semver_exempt))]
#[cfg(not(span_locations))]
pub fn advance(&self, amt: usize) -> Cursor<'a> {
Cursor {
rest: &self.rest[amt..],
}
}
#[cfg(procmacro2_semver_exempt)]
#[cfg(span_locations)]
pub fn advance(&self, amt: usize) -> Cursor<'a> {
Cursor {
rest: &self.rest[amt..],
Expand Down
13 changes: 9 additions & 4 deletions src/wrapper.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
#![cfg_attr(not(super_unstable), allow(dead_code))]

use std::fmt;
use std::iter;
use std::panic::{self, PanicInfo};
Expand Down Expand Up @@ -413,6 +411,7 @@ impl fmt::Debug for SourceFile {
}
}

#[cfg(any(super_unstable, feature = "span-locations"))]
pub struct LineColumn {
pub line: usize,
pub column: usize,
Expand Down Expand Up @@ -475,27 +474,33 @@ impl Span {
}
}

#[cfg(super_unstable)]
#[cfg(any(super_unstable, feature = "span-locations"))]
pub fn start(&self) -> LineColumn {
match self {
#[cfg(nightly)]
Span::Compiler(s) => {
let proc_macro::LineColumn { line, column } = s.start();
LineColumn { line, column }
}
#[cfg(not(nightly))]
Span::Compiler(_) => LineColumn { line: 0, column: 0 },
Span::Fallback(s) => {
let fallback::LineColumn { line, column } = s.start();
LineColumn { line, column }
}
}
}

#[cfg(super_unstable)]
#[cfg(any(super_unstable, feature = "span-locations"))]
pub fn end(&self) -> LineColumn {
match self {
#[cfg(nightly)]
Span::Compiler(s) => {
let proc_macro::LineColumn { line, column } = s.end();
LineColumn { line, column }
}
#[cfg(not(nightly))]
Span::Compiler(_) => LineColumn { line: 0, column: 0 },
Span::Fallback(s) => {
let fallback::LineColumn { line, column } = s.end();
LineColumn { line, column }
Expand Down
Loading

0 comments on commit 2b01a3f

Please sign in to comment.