Use upstream 'Literal::subspan()'.

This commit is contained in:
Sergio Benitez 2018-11-23 19:15:13 -06:00
parent ed4055925d
commit 543b07a4ba
6 changed files with 53 additions and 56 deletions

View File

@ -8,8 +8,8 @@ use yansi::Color::{Red, Yellow, Blue};
use version_check::{supports_features, is_min_version, is_min_date};
// Specifies the minimum nightly version needed to compile Rocket.
const MIN_DATE: &'static str = "2018-10-05";
const MIN_VERSION: &'static str = "1.31.0-nightly";
const MIN_DATE: &'static str = "2018-11-23";
const MIN_VERSION: &'static str = "1.32.0-nightly";
fn main() {
let ok_channel = supports_features();

View File

@ -3,7 +3,7 @@ use proc_macro2::TokenStream as TokenStream2;
use devise::{syn, Spanned, SpanWrapped, Result, FromMeta, ext::TypeExt};
use indexmap::IndexSet;
use proc_macro_ext::{Diagnostics, SpanExt};
use proc_macro_ext::{Diagnostics, StringLit};
use syn_ext::{syn_to_diag, IdentExt};
use self::syn::{Attribute, parse::Parser};
@ -426,7 +426,10 @@ fn incomplete_route(
) -> Result<TokenStream> {
let method_str = method.to_string().to_lowercase();
// FIXME(proc_macro): there should be a way to get this `Span`.
let method_span = Span::call_site().subspan(2..2 + method_str.len()).unwrap();
let method_span = StringLit::new(format!("#[{}]", method), Span::call_site())
.subspan(2..2 + method_str.len())
.unwrap_or(Span::call_site());
let method_ident = syn::Ident::new(&method_str, method_span.into());
let function: syn::ItemFn = syn::parse(input).map_err(syn_to_diag)

View File

@ -4,7 +4,7 @@ use devise::syn;
use proc_macro::{Span, Diagnostic};
use http::route::RouteSegment;
use proc_macro_ext::{SpanExt, Diagnostics, PResult, DResult};
use proc_macro_ext::{Diagnostics, StringLit, PResult, DResult};
crate use http::route::{Error, Kind, Source};
@ -52,15 +52,16 @@ impl Hash for Segment {
fn subspan(needle: &str, haystack: &str, span: Span) -> Option<Span> {
let index = needle.as_ptr() as usize - haystack.as_ptr() as usize;
span.subspan(index..index + needle.len())
StringLit::new(haystack, span).subspan(index..index + needle.len())
}
fn trailspan(needle: &str, haystack: &str, span: Span) -> Option<Span> {
let index = needle.as_ptr() as usize - haystack.as_ptr() as usize;
let lit = StringLit::new(haystack, span);
if needle.as_ptr() as usize > haystack.as_ptr() as usize {
span.subspan((index - 1)..)
lit.subspan((index - 1)..)
} else {
span.subspan(index..)
lit.subspan(index..)
}
}

View File

@ -4,7 +4,7 @@ use devise::{FromMeta, MetaItem, Result, ext::Split2};
use http::{self, ext::IntoOwned};
use attribute::segments::{parse_segments, parse_segment, Segment, Kind, Source};
use proc_macro_ext::SpanExt;
use proc_macro_ext::StringLit;
#[derive(Debug)]
crate struct ContentType(crate http::ContentType);
@ -27,6 +27,12 @@ crate struct DataSegment(crate Segment);
#[derive(Clone, Debug)]
crate struct Optional<T>(crate Option<T>);
impl FromMeta for StringLit {
fn from_meta(meta: MetaItem) -> Result<Self> {
Ok(StringLit::new(String::from_meta(meta)?, meta.value_span()))
}
}
#[derive(Debug)]
crate struct RoutePath {
crate origin: Origin,
@ -159,14 +165,13 @@ impl ToTokens for Method {
impl FromMeta for Origin {
fn from_meta(meta: MetaItem) -> Result<Self> {
let string = String::from_meta(meta)?;
let span = meta.value_span();
let string = StringLit::from_meta(meta)?;
let uri = http::uri::Origin::parse_route(&string)
.map_err(|e| {
let span = e.index()
.map(|i| span.subspan(i + 1..).expect("origin"))
.unwrap_or(span);
.map(|i| string.subspan(i + 1..).expect("origin"))
.unwrap_or(string.span());
span.error(format!("invalid path URI: {}", e))
.help("expected path in origin form: \"/path/<param>\"")
@ -174,7 +179,7 @@ impl FromMeta for Origin {
if !uri.is_normalized() {
let normalized = uri.to_normalized();
return Err(span.error("paths cannot contain empty segments")
return Err(string.span().error("paths cannot contain empty segments")
.note(format!("expected '{}', found '{}'", normalized, uri)));
}
@ -184,9 +189,8 @@ impl FromMeta for Origin {
impl FromMeta for Segment {
fn from_meta(meta: MetaItem) -> Result<Self> {
let string = String::from_meta(meta)?;
let span = meta.value_span()
.subspan(1..(string.len() + 1))
let string = StringLit::from_meta(meta)?;
let span = string.subspan(1..(string.len() + 1))
.expect("segment");
let segment = parse_segment(&string, span)?;
@ -210,15 +214,15 @@ impl FromMeta for DataSegment {
impl FromMeta for RoutePath {
fn from_meta(meta: MetaItem) -> Result<Self> {
let (origin, span) = (Origin::from_meta(meta)?, meta.value_span());
let path_span = span.subspan(1..origin.0.path().len() + 1).expect("path");
let (origin, string) = (Origin::from_meta(meta)?, StringLit::from_meta(meta)?);
let path_span = string.subspan(1..origin.0.path().len() + 1).expect("path");
let path = parse_segments(origin.0.path(), '/', Source::Path, path_span);
let query = origin.0.query()
.map(|q| {
let len_to_q = 1 + origin.0.path().len() + 1;
let end_of_q = len_to_q + q.len();
let query_span = span.subspan(len_to_q..end_of_q).expect("query");
let query_span = string.subspan(len_to_q..end_of_q).expect("query");
if q.starts_with('&') || q.contains("&&") || q.ends_with('&') {
// TODO: Show a help message with what's expected.
Err(query_span.error("query cannot contain empty segments").into())

View File

@ -60,7 +60,7 @@
//! ```
#[macro_use] extern crate quote;
#[macro_use] extern crate devise;
extern crate devise;
extern crate proc_macro;
extern crate rocket_http as http;
extern crate indexmap;

View File

@ -1,6 +1,6 @@
use std::ops::{Bound, RangeBounds};
use proc_macro::{Span, Diagnostic, /* MultiSpan */};
use proc_macro::{Span, Diagnostic, Literal};
use syntax_pos::{Span as InnerSpan, Pos, BytePos};
pub type PResult<T> = ::std::result::Result<T, Diagnostic>;
@ -62,42 +62,31 @@ impl From<Vec<Diagnostic>> for Diagnostics {
}
}
pub trait SpanExt {
fn subspan<R: RangeBounds<usize>>(self, range: R) -> Option<Span>;
}
use std::ops::Deref;
impl SpanExt for Span {
/// Create a `subspan` from `start` to `end`.
fn subspan<R: RangeBounds<usize>>(self, range: R) -> Option<Span> {
let inner: InnerSpan = unsafe { ::std::mem::transmute(self) };
let length = inner.hi().to_usize() - inner.lo().to_usize();
pub struct StringLit(crate String, crate Literal);
let start = match range.start_bound() {
Bound::Included(&lo) => lo,
Bound::Excluded(&lo) => lo + 1,
Bound::Unbounded => 0,
};
impl Deref for StringLit {
type Target = str;
let end = match range.end_bound() {
Bound::Included(&hi) => hi + 1,
Bound::Excluded(&hi) => hi,
Bound::Unbounded => length,
};
// Bounds check the values, preventing addition overflow and OOB spans.
if start > u32::max_value() as usize
|| end > u32::max_value() as usize
|| (u32::max_value() - start as u32) < inner.lo().to_u32()
|| (u32::max_value() - end as u32) < inner.lo().to_u32()
|| start >= end
|| end > length
{
return None;
}
let new_lo = inner.lo() + BytePos(start as u32);
let new_hi = inner.lo() + BytePos(end as u32);
let new_inner = inner.with_lo(new_lo).with_hi(new_hi);
Some(unsafe { ::std::mem::transmute(new_inner) })
fn deref(&self) -> &str {
&self.0
}
}
impl StringLit {
pub fn new<S: Into<String>>(string: S, span: Span) -> Self {
let string = string.into();
let mut lit = Literal::string(&string);
lit.set_span(span);
StringLit(string, lit)
}
pub fn span(&self) -> Span {
self.1.span()
}
pub fn subspan<R: RangeBounds<usize>>(&self, range: R) -> Option<Span> {
self.1.subspan(range)
}
}