Improve 'FromForm' derive error spans.

This commit is contained in:
Sergio Benitez 2021-03-03 23:13:09 -08:00
parent 398a044eb0
commit 7628546ca2
8 changed files with 132 additions and 14 deletions

View File

@ -19,7 +19,7 @@ proc-macro = true
[dependencies]
quote = "1.0"
devise = { git = "https://github.com/SergioBenitez/Devise.git", rev = "bd221a4" }
devise = { git = "https://github.com/SergioBenitez/Devise.git", rev = "3ebe83" }
[dev-dependencies]
rocket = { version = "0.5.0-dev", path = "../../core/lib" }

View File

@ -18,7 +18,7 @@ proc-macro = true
indexmap = "1.0"
quote = "1.0"
rocket_http = { version = "0.5.0-dev", path = "../http/" }
devise = { git = "https://github.com/SergioBenitez/Devise.git", rev = "bd221a4" }
devise = { git = "https://github.com/SergioBenitez/Devise.git", rev = "3ebe83" }
unicode-xid = "0.2"
glob = "0.3"

View File

@ -328,7 +328,7 @@ fn incomplete_route(
let attribute = Attribute {
method: SpanWrapped {
full_span: method_span, span: method_span, value: Method(method)
full_span: method_span, key_span: None, span: method_span, value: Method(method)
},
uri: method_attribute.uri,
data: method_attribute.data,

View File

@ -3,8 +3,8 @@ use devise::{*, ext::{TypeExt, SpanDiagnosticExt}};
use syn::visit_mut::VisitMut;
use syn::visit::Visit;
use crate::exports::*;
use crate::proc_macro2::{Span, TokenStream, TokenTree};
use crate::syn_ext::IdentExt;
use crate::name::Name;
pub struct FormField {
@ -15,7 +15,7 @@ pub struct FormField {
#[derive(FromMeta)]
pub struct FieldAttr {
pub name: Option<FormField>,
pub validate: Option<syn::Expr>,
pub validate: Option<SpanWrapped<syn::Expr>>,
}
impl FieldAttr {
@ -89,6 +89,7 @@ impl FieldExt for Field<'_> {
fn name_view(&self) -> Result<syn::Expr> {
let field_name = self.field_name()?;
define_spanned_export!(self.span() => _form);
let name_view = quote_spanned! { self.span() =>
#_form::NameBuf::from((__c.__parent, #field_name))
};
@ -201,7 +202,7 @@ pub fn validators<'v>(
parent: &'v syn::Ident, // field ident (if local) or form ident (if !local)
local: bool,
) -> Result<impl Iterator<Item = syn::Expr> + 'v> {
Ok(FieldAttr::from_attrs(FieldAttr::NAME, &field.attrs)?
let exprs = FieldAttr::from_attrs(FieldAttr::NAME, &field.attrs)?
.into_iter()
.filter_map(|a| a.validate)
.map(move |expr| {
@ -219,9 +220,21 @@ pub fn validators<'v>(
})
.filter(move |(_, is_local)| *is_local == local)
.map(move |(mut expr, _)| {
let field = field.ident();
let mut v = ValidationMutator { parent, local, field, visited: false };
let field_span = field.ident().span()
.join(field.ty.span())
.unwrap_or(field.ty.span());
let field_ident = field.ident().clone().with_span(field_span);
let mut v = ValidationMutator { parent, local, field: &field_ident, visited: false };
v.visit_expr_mut(&mut expr);
expr
}))
let span = expr.key_span.unwrap_or(field_span);
define_spanned_export!(span => _form);
syn::parse2(quote_spanned!(span => {
let __result: #_form::Result<'_, ()> = #expr;
__result
})).unwrap()
});
Ok(exprs)
}

View File

@ -336,3 +336,44 @@ note: error occurred while deriving `FromForm`
136 | #[derive(FromForm)]
| ^^^^^^^^
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0425]: cannot find function `unknown` in this scope
--> $DIR/from_form.rs:150:24
|
150 | #[field(validate = unknown())]
| ^^^^^^^ not found in this scope
error[E0308]: mismatched types
--> $DIR/from_form.rs:144:24
|
144 | #[field(validate = 123)]
| -------- ^^^ expected enum `Result`, found integer
| |
| expected due to this
|
= note: expected enum `Result<(), Errors<'_>>`
found type `{integer}`
error[E0308]: mismatched types
--> $DIR/from_form.rs:157:5
|
157 | first: String,
| ^^^^^^^^^^^^^ expected enum `TempFile`, found struct `std::string::String`
|
= note: expected reference `&TempFile<'_>`
found reference `&std::string::String`
error[E0308]: mismatched types
--> $DIR/from_form.rs:163:5
|
163 | first: String,
| ^^^^^^^^^^^^^ expected enum `TempFile`, found struct `std::string::String`
|
= note: expected reference `&TempFile<'_>`
found reference `&std::string::String`
error[E0308]: mismatched types
--> $DIR/from_form.rs:162:28
|
162 | #[field(validate = ext("hello"))]
| ^^^^^^^ expected struct `ContentType`, found `&str`

View File

@ -359,3 +359,44 @@ error: [note] error occurred while deriving `FromForm`
| ^^^^^^^^
|
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0425]: cannot find function `unknown` in this scope
--> $DIR/from_form.rs:150:24
|
150 | #[field(validate = unknown())]
| ^^^^^^^ not found in this scope
error[E0308]: mismatched types
--> $DIR/from_form.rs:144:24
|
144 | #[field(validate = 123)]
| -------- ^^^ expected enum `std::result::Result`, found integer
| |
| expected due to this
|
= note: expected enum `std::result::Result<(), Errors<'_>>`
found type `{integer}`
error[E0308]: mismatched types
--> $DIR/from_form.rs:157:12
|
157 | first: String,
| ^^^^^^ expected enum `TempFile`, found struct `std::string::String`
|
= note: expected reference `&TempFile<'_>`
found reference `&std::string::String`
error[E0308]: mismatched types
--> $DIR/from_form.rs:163:12
|
163 | first: String,
| ^^^^^^ expected enum `TempFile`, found struct `std::string::String`
|
= note: expected reference `&TempFile<'_>`
found reference `&std::string::String`
error[E0308]: mismatched types
--> $DIR/from_form.rs:162:28
|
162 | #[field(validate = ext("hello"))]
| ^^^^^^^ expected struct `ContentType`, found `&str`

View File

@ -139,4 +139,28 @@ struct BadName3 {
field: String,
}
#[derive(FromForm)]
struct Validate0 {
#[field(validate = 123)]
first: String,
}
#[derive(FromForm)]
struct Validate1 {
#[field(validate = unknown())]
first: String,
}
#[derive(FromForm)]
struct Validate2 {
#[field(validate = ext(rocket::http::ContentType::HTML))]
first: String,
}
#[derive(FromForm)]
struct Validate3 {
#[field(validate = ext("hello"))]
first: String,
}
fn main() { }

View File

@ -1,6 +1,6 @@
#[macro_use]extern crate rocket;
use rocket::http::Status;
use rocket::http::{Status, ContentType};
use rocket::form::{Form, Contextual, FromForm, FromFormField, Context};
use rocket::data::TempFile;
@ -39,7 +39,7 @@ struct Submission<'v> {
date: time::Date,
#[field(validate = len(1..=250))]
r#abstract: &'v str,
#[field(validate = ext("pdf"))]
#[field(validate = ext(ContentType::PDF))]
file: TempFile<'v>,
#[field(validate = len(1..))]
category: Vec<Category>,
@ -52,8 +52,7 @@ struct Account<'v> {
#[field(validate = len(1..))]
name: &'v str,
password: Password<'v>,
#[field(validate = contains('@'))]
#[field(validate = omits(self.password.first))]
#[field(validate = contains('@').or_else(msg!("invalid email address")))]
email: &'v str,
}