From 30edd349edb5aad81a3eae18eb76c89165e15548 Mon Sep 17 00:00:00 2001 From: Dominic Date: Sun, 21 Feb 2021 18:06:50 +0100 Subject: [PATCH] improve ui on invalid types for endpoints --- derive/src/endpoint.rs | 14 +++++--- tests/ui/endpoint/invalid_body_ty.rs | 19 +++++++++++ tests/ui/endpoint/invalid_body_ty.stderr | 13 ++++++++ tests/ui/endpoint/invalid_params_ty.rs | 19 +++++++++++ tests/ui/endpoint/invalid_params_ty.stderr | 32 +++++++++++++++++++ tests/ui/endpoint/invalid_placeholders_ty.rs | 19 +++++++++++ .../endpoint/invalid_placeholders_ty.stderr | 32 +++++++++++++++++++ tests/ui/endpoint/invalid_return_type.rs | 16 ++++++++++ tests/ui/endpoint/invalid_return_type.stderr | 10 ++++++ 9 files changed, 169 insertions(+), 5 deletions(-) create mode 100644 tests/ui/endpoint/invalid_body_ty.rs create mode 100644 tests/ui/endpoint/invalid_body_ty.stderr create mode 100644 tests/ui/endpoint/invalid_params_ty.rs create mode 100644 tests/ui/endpoint/invalid_params_ty.stderr create mode 100644 tests/ui/endpoint/invalid_placeholders_ty.rs create mode 100644 tests/ui/endpoint/invalid_placeholders_ty.stderr create mode 100644 tests/ui/endpoint/invalid_return_type.rs create mode 100644 tests/ui/endpoint/invalid_return_type.stderr diff --git a/derive/src/endpoint.rs b/derive/src/endpoint.rs index 5078383..aac3757 100644 --- a/derive/src/endpoint.rs +++ b/derive/src/endpoint.rs @@ -2,7 +2,7 @@ use crate::util::{CollectToResult, ExpectLit, PathEndsWith}; use once_cell::sync::Lazy; use paste::paste; use proc_macro2::{Ident, Span, TokenStream}; -use quote::{format_ident, quote, ToTokens}; +use quote::{format_ident, quote, quote_spanned, ToTokens}; use regex::Regex; use std::str::FromStr; use syn::{ @@ -405,6 +405,7 @@ fn expand_endpoint_type(mut ty: EndpointType, attrs: AttributeArgs, fun: &ItemFn ReturnType::Default => (quote!(::gotham_restful::NoContent), true), ReturnType::Type(_, ty) => (quote!(#ty), false) }; + let output_typedef = quote_spanned!(output_ty.span() => type Output = #output_ty;); let arg_tys = args.iter().filter(|arg| arg.ty.is_method_arg()).collect::>(); let mut arg_ty_idx = 0; @@ -434,10 +435,13 @@ fn expand_endpoint_type(mut ty: EndpointType, attrs: AttributeArgs, fun: &ItemFn })?; let has_placeholders = ty.has_placeholders(); let placeholder_ty = ty.placeholders_ty(next_arg_ty(!has_placeholders.value)?); + let placeholder_typedef = quote_spanned!(placeholder_ty.span() => type Placeholders = #placeholder_ty;); let needs_params = ty.needs_params(); let params_ty = ty.params_ty(next_arg_ty(!needs_params.value)?); + let params_typedef = quote_spanned!(params_ty.span() => type Params = #params_ty;); let needs_body = ty.needs_body(); let body_ty = ty.body_ty(next_arg_ty(!needs_body.value)?); + let body_typedef = quote_spanned!(body_ty.span() => type Body = #body_ty;); if arg_ty_idx < arg_tys.len() { return Err(Error::new(fun_ident.span(), "Too many arguments")); @@ -537,22 +541,22 @@ fn expand_endpoint_type(mut ty: EndpointType, attrs: AttributeArgs, fun: &ItemFn { #uri }.into() } - type Output = #output_ty; + #output_typedef fn has_placeholders() -> bool { #has_placeholders } - type Placeholders = #placeholder_ty; + #placeholder_typedef fn needs_params() -> bool { #needs_params } - type Params = #params_ty; + #params_typedef fn needs_body() -> bool { #needs_body } - type Body = #body_ty; + #body_typedef fn handle<'a>( state: &'a mut ::gotham_restful::gotham::state::State, diff --git a/tests/ui/endpoint/invalid_body_ty.rs b/tests/ui/endpoint/invalid_body_ty.rs new file mode 100644 index 0000000..a3ab10d --- /dev/null +++ b/tests/ui/endpoint/invalid_body_ty.rs @@ -0,0 +1,19 @@ +#[macro_use] +extern crate gotham_restful; +use gotham_restful::gotham::hyper::Method; + +#[derive(Resource)] +#[resource(endpoint)] +struct FooResource; + +#[derive(Debug)] +struct FooBody { + foo: String +} + +#[endpoint(method = "Method::GET", uri = "", body = true)] +fn endpoint(_: FooBody) { + unimplemented!() +} + +fn main() {} diff --git a/tests/ui/endpoint/invalid_body_ty.stderr b/tests/ui/endpoint/invalid_body_ty.stderr new file mode 100644 index 0000000..e042ed3 --- /dev/null +++ b/tests/ui/endpoint/invalid_body_ty.stderr @@ -0,0 +1,13 @@ +error[E0277]: the trait bound `for<'de> FooBody: serde::de::Deserialize<'de>` is not satisfied + --> $DIR/invalid_body_ty.rs:15:16 + | +15 | fn endpoint(_: FooBody) { + | ^^^^^^^ the trait `for<'de> serde::de::Deserialize<'de>` is not implemented for `FooBody` + | + ::: $WORKSPACE/src/endpoint.rs + | + | type Body: RequestBody + Send; + | ----------- required by this bound in `gotham_restful::Endpoint::Body` + | + = note: required because of the requirements on the impl of `serde::de::DeserializeOwned` for `FooBody` + = note: required because of the requirements on the impl of `RequestBody` for `FooBody` diff --git a/tests/ui/endpoint/invalid_params_ty.rs b/tests/ui/endpoint/invalid_params_ty.rs new file mode 100644 index 0000000..e08ff91 --- /dev/null +++ b/tests/ui/endpoint/invalid_params_ty.rs @@ -0,0 +1,19 @@ +#[macro_use] +extern crate gotham_restful; +use gotham_restful::gotham::hyper::Method; + +#[derive(Resource)] +#[resource(endpoint)] +struct FooResource; + +#[derive(Debug)] +struct FooParams { + foo: String +} + +#[endpoint(method = "Method::GET", uri = "", params = true)] +fn endpoint(_: FooParams) { + unimplemented!() +} + +fn main() {} diff --git a/tests/ui/endpoint/invalid_params_ty.stderr b/tests/ui/endpoint/invalid_params_ty.stderr new file mode 100644 index 0000000..8f7cdb8 --- /dev/null +++ b/tests/ui/endpoint/invalid_params_ty.stderr @@ -0,0 +1,32 @@ +error[E0277]: the trait bound `for<'de> FooParams: serde::de::Deserialize<'de>` is not satisfied + --> $DIR/invalid_params_ty.rs:15:16 + | +15 | fn endpoint(_: FooParams) { + | ^^^^^^^^^ the trait `for<'de> serde::de::Deserialize<'de>` is not implemented for `FooParams` + | + ::: $WORKSPACE/src/endpoint.rs + | + | type Params: QueryStringExtractor + Sync; + | -------------------------- required by this bound in `gotham_restful::Endpoint::Params` + +error[E0277]: the trait bound `FooParams: StateData` is not satisfied + --> $DIR/invalid_params_ty.rs:15:16 + | +15 | fn endpoint(_: FooParams) { + | ^^^^^^^^^ the trait `StateData` is not implemented for `FooParams` + | + ::: $WORKSPACE/src/endpoint.rs + | + | type Params: QueryStringExtractor + Sync; + | -------------------------- required by this bound in `gotham_restful::Endpoint::Params` + +error[E0277]: the trait bound `FooParams: StaticResponseExtender` is not satisfied + --> $DIR/invalid_params_ty.rs:15:16 + | +15 | fn endpoint(_: FooParams) { + | ^^^^^^^^^ the trait `StaticResponseExtender` is not implemented for `FooParams` + | + ::: $WORKSPACE/src/endpoint.rs + | + | type Params: QueryStringExtractor + Sync; + | -------------------------- required by this bound in `gotham_restful::Endpoint::Params` diff --git a/tests/ui/endpoint/invalid_placeholders_ty.rs b/tests/ui/endpoint/invalid_placeholders_ty.rs new file mode 100644 index 0000000..3ca1d10 --- /dev/null +++ b/tests/ui/endpoint/invalid_placeholders_ty.rs @@ -0,0 +1,19 @@ +#[macro_use] +extern crate gotham_restful; +use gotham_restful::gotham::hyper::Method; + +#[derive(Resource)] +#[resource(endpoint)] +struct FooResource; + +#[derive(Debug)] +struct FooPlaceholders { + foo: String +} + +#[endpoint(method = "Method::GET", uri = ":foo")] +fn endpoint(_: FooPlaceholders) { + unimplemented!() +} + +fn main() {} diff --git a/tests/ui/endpoint/invalid_placeholders_ty.stderr b/tests/ui/endpoint/invalid_placeholders_ty.stderr new file mode 100644 index 0000000..6810ef5 --- /dev/null +++ b/tests/ui/endpoint/invalid_placeholders_ty.stderr @@ -0,0 +1,32 @@ +error[E0277]: the trait bound `for<'de> FooPlaceholders: serde::de::Deserialize<'de>` is not satisfied + --> $DIR/invalid_placeholders_ty.rs:15:16 + | +15 | fn endpoint(_: FooPlaceholders) { + | ^^^^^^^^^^^^^^^ the trait `for<'de> serde::de::Deserialize<'de>` is not implemented for `FooPlaceholders` + | + ::: $WORKSPACE/src/endpoint.rs + | + | type Placeholders: PathExtractor + Sync; + | ------------------- required by this bound in `gotham_restful::Endpoint::Placeholders` + +error[E0277]: the trait bound `FooPlaceholders: StateData` is not satisfied + --> $DIR/invalid_placeholders_ty.rs:15:16 + | +15 | fn endpoint(_: FooPlaceholders) { + | ^^^^^^^^^^^^^^^ the trait `StateData` is not implemented for `FooPlaceholders` + | + ::: $WORKSPACE/src/endpoint.rs + | + | type Placeholders: PathExtractor + Sync; + | ------------------- required by this bound in `gotham_restful::Endpoint::Placeholders` + +error[E0277]: the trait bound `FooPlaceholders: StaticResponseExtender` is not satisfied + --> $DIR/invalid_placeholders_ty.rs:15:16 + | +15 | fn endpoint(_: FooPlaceholders) { + | ^^^^^^^^^^^^^^^ the trait `StaticResponseExtender` is not implemented for `FooPlaceholders` + | + ::: $WORKSPACE/src/endpoint.rs + | + | type Placeholders: PathExtractor + Sync; + | ------------------- required by this bound in `gotham_restful::Endpoint::Placeholders` diff --git a/tests/ui/endpoint/invalid_return_type.rs b/tests/ui/endpoint/invalid_return_type.rs new file mode 100644 index 0000000..feeaf98 --- /dev/null +++ b/tests/ui/endpoint/invalid_return_type.rs @@ -0,0 +1,16 @@ +#[macro_use] +extern crate gotham_restful; +use gotham_restful::gotham::hyper::Method; + +#[derive(Resource)] +#[resource(endpoint)] +struct FooResource; + +struct FooResponse; + +#[endpoint(method = "Method::GET", uri = "")] +fn endpoint() -> FooResponse { + unimplemented!() +} + +fn main() {} diff --git a/tests/ui/endpoint/invalid_return_type.stderr b/tests/ui/endpoint/invalid_return_type.stderr new file mode 100644 index 0000000..1660b14 --- /dev/null +++ b/tests/ui/endpoint/invalid_return_type.stderr @@ -0,0 +1,10 @@ +error[E0277]: the trait bound `FooResponse: ResourceResult` is not satisfied + --> $DIR/invalid_return_type.rs:12:18 + | +12 | fn endpoint() -> FooResponse { + | ^^^^^^^^^^^ the trait `ResourceResult` is not implemented for `FooResponse` + | + ::: $WORKSPACE/src/endpoint.rs + | + | type Output: ResourceResult + Send; + | -------------- required by this bound in `gotham_restful::Endpoint::Output`