Always produce a valid, if conservative, subspan.

This commit is contained in:
Oliver Scherer 2019-01-22 11:03:37 +01:00 committed by Sergio Benitez
parent b9c3a5c64b
commit c86f4312fb
5 changed files with 32 additions and 16 deletions

View File

@ -428,8 +428,7 @@ fn incomplete_route(
let method_str = method.to_string().to_lowercase();
// FIXME(proc_macro): there should be a way to get this `Span`.
let method_span = StringLit::new(format!("#[{}]", method), Span::call_site())
.subspan(2..2 + method_str.len())
.unwrap_or(Span::call_site());
.subspan(2..2 + method_str.len());
let method_ident = syn::Ident::new(&method_str, method_span.into());

View File

@ -57,12 +57,12 @@ impl Hash for Segment {
}
}
fn subspan(needle: &str, haystack: &str, span: Span) -> Option<Span> {
fn subspan(needle: &str, haystack: &str, span: Span) -> Span {
let index = needle.as_ptr() as usize - haystack.as_ptr() as usize;
StringLit::new(haystack, span).subspan(index..index + needle.len())
}
fn trailspan(needle: &str, haystack: &str, span: Span) -> Option<Span> {
fn trailspan(needle: &str, haystack: &str, span: Span) -> 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 {
@ -78,7 +78,7 @@ fn into_diagnostic(
span: Span, // The `Span` of `Source`.
error: &Error, // The error.
) -> Diagnostic {
let seg_span = subspan(segment, source, span).expect("seg_span");
let seg_span = subspan(segment, source, span);
match error {
Error::Empty => {
seg_span.error("parameter names cannot be empty")
@ -106,8 +106,8 @@ fn into_diagnostic(
.help("reserved characters include: '%', '+', '&', etc.")
}
Error::Trailing(multi) => {
let multi_span = subspan(multi, source, span).expect("mutli_span");
trailspan(segment, source, span).expect("trailspan")
let multi_span = subspan(multi, source, span);
trailspan(segment, source, span)
.error("unexpected trailing text after a '..' param")
.help("a multi-segment param must be the final component")
.span_note(multi_span, "multi-segment param is here")
@ -140,7 +140,7 @@ crate fn parse_segments<P: UriPart>(
break;
}
} else if let Ok(segment) = result {
let seg_span = subspan(&segment.string, string, span).expect("seg");
let seg_span = subspan(&segment.string, string, span);
segments.push(Segment::from(segment, seg_span));
}
}

View File

@ -172,7 +172,7 @@ impl FromMeta for Origin {
let uri = http::uri::Origin::parse_route(&string)
.map_err(|e| {
let span = e.index()
.map(|i| string.subspan(i + 1..).expect("origin"))
.map(|i| string.subspan(i + 1..))
.unwrap_or(string.span());
span.error(format!("invalid path URI: {}", e))
@ -192,8 +192,7 @@ impl FromMeta for Origin {
impl FromMeta for DataSegment {
fn from_meta(meta: MetaItem) -> Result<Self> {
let string = StringLit::from_meta(meta)?;
let span = string.subspan(1..(string.len() + 1))
.expect("segment");
let span = string.subspan(1..(string.len() + 1));
let segment = parse_data_segment(&string, span)?;
if segment.kind != Kind::Single {
@ -208,14 +207,14 @@ impl FromMeta for DataSegment {
impl FromMeta for RoutePath {
fn from_meta(meta: MetaItem) -> Result<Self> {
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_span = string.subspan(1..origin.0.path().len() + 1);
let path = parse_segments::<Path>(origin.0.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 = string.subspan(len_to_q..end_of_q).expect("query");
let query_span = string.subspan(len_to_q..end_of_q);
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

@ -85,7 +85,9 @@ impl StringLit {
self.1.span()
}
pub fn subspan<R: RangeBounds<usize>>(&self, range: R) -> Option<Span> {
self.1.subspan(range)
/// Attempt to obtain a subspan, or, failing that, produce the full span.
/// This will create suboptimal diagnostics, but better than failing to build entirely.
pub fn subspan<R: RangeBounds<usize>>(&self, range: R) -> Span {
self.1.subspan(range).unwrap_or_else(|| self.span())
}
}

View File

@ -20,9 +20,22 @@ macro_rules! make_handler {
make_handler!();
macro_rules! foo {
($addr:expr, $name:ident) => {
#[get($addr)]
fn hi($name: String) -> String {
$name
}
};
}
// regression test for `#[get] panicking if used inside a macro
foo!("/hello/<name>", name);
#[test]
fn test_reexpansion() {
let rocket = rocket::ignite().mount("/", routes![easy, hard]);
let rocket = rocket::ignite().mount("/", routes![easy, hard, hi]);
let client = Client::new(rocket).unwrap();
let mut response = client.get("/easy/327").dispatch();
@ -30,6 +43,9 @@ fn test_reexpansion() {
let mut response = client.get("/hard/72").dispatch();
assert_eq!(response.body_string().unwrap(), "hard id: 72");
let mut response = client.get("/hello/fish").dispatch();
assert_eq!(response.body_string().unwrap(), "fish");
}
macro_rules! index {