mirror of https://github.com/rwf2/Rocket.git
Always produce a valid, if conservative, subspan.
This commit is contained in:
parent
b9c3a5c64b
commit
c86f4312fb
|
@ -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());
|
||||
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in New Issue