commit c86f4312fb273c0380fb76a97bfb7fc227800542
parent b9c3a5c64bf20b1b83bfb709d117970156b0fc00
Author: Oliver Scherer <github35764891676564198441@oli-obk.de>
Date: Tue, 22 Jan 2019 11:03:37 +0100
Always produce a valid, if conservative, subspan.
Diffstat:
5 files changed, 32 insertions(+), 16 deletions(-)
diff --git a/core/codegen/src/attribute/route.rs b/core/codegen/src/attribute/route.rs
@@ -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());
diff --git a/core/codegen/src/attribute/segments.rs b/core/codegen/src/attribute/segments.rs
@@ -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));
}
}
diff --git a/core/codegen/src/http_codegen.rs b/core/codegen/src/http_codegen.rs
@@ -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())
diff --git a/core/codegen/src/proc_macro_ext.rs b/core/codegen/src/proc_macro_ext.rs
@@ -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())
}
}
diff --git a/core/codegen/tests/expansion.rs b/core/codegen/tests/expansion.rs
@@ -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 {