diff --git a/actix-web-codegen/src/route.rs b/actix-web-codegen/src/route.rs index adb484c76..38217b8a0 100644 --- a/actix-web-codegen/src/route.rs +++ b/actix-web-codegen/src/route.rs @@ -427,23 +427,31 @@ pub(crate) fn with_methods(input: TokenStream) -> TokenStream { ast.attrs = others.into_iter().map(Result::unwrap_err).collect(); - let methods = match methods - .into_iter() - .map(Result::unwrap) - .map(|(method, attr)| { - attr.parse_meta().and_then(|args| { - if let Meta::List(args) = args { - Args::new(args.nested.into_iter().collect(), Some(method)) - } else { - Err(syn::Error::new_spanned(attr, "Invalid input for macro")) - } + let methods = + match methods + .into_iter() + .map(Result::unwrap) + .map(|(method, attr)| { + attr.parse_meta().and_then(|args| { + if let Meta::List(args) = args { + Args::new(args.nested.into_iter().collect(), Some(method)) + } else { + Err(syn::Error::new_spanned(attr, "Invalid input for macro")) + } + }) }) - }) - .collect() - { - Ok(methods) => methods, - Err(err) => return input_and_compile_error(input, err), - }; + .collect::, _>>() + { + Ok(methods) if methods.is_empty() => return input_and_compile_error( + input, + syn::Error::new( + Span::call_site(), + "The #[routes] macro requires at least one `#[(..)]` attribute.", + ), + ), + Ok(methods) => methods, + Err(err) => return input_and_compile_error(input, err), + }; match Route::multiple(methods, ast) { Ok(route) => route.into_token_stream().into(), diff --git a/actix-web-codegen/tests/trybuild.rs b/actix-web-codegen/tests/trybuild.rs index 17ece57da..f690d9570 100644 --- a/actix-web-codegen/tests/trybuild.rs +++ b/actix-web-codegen/tests/trybuild.rs @@ -13,6 +13,7 @@ fn compile_macros() { t.compile_fail("tests/trybuild/route-malformed-path-fail.rs"); t.pass("tests/trybuild/routes-ok.rs"); + t.compile_fail("tests/trybuild/routes-missing-method-fail.rs"); t.pass("tests/trybuild/docstring-ok.rs"); diff --git a/actix-web-codegen/tests/trybuild/routes-missing-method-fail.rs b/actix-web-codegen/tests/trybuild/routes-missing-method-fail.rs new file mode 100644 index 000000000..f0271ef44 --- /dev/null +++ b/actix-web-codegen/tests/trybuild/routes-missing-method-fail.rs @@ -0,0 +1,13 @@ +use actix_web_codegen::*; + +#[routes] +async fn index() -> String { + "Hello World!".to_owned() +} + +#[actix_web::main] +async fn main() { + use actix_web::App; + + let srv = actix_test::start(|| App::new().service(index)); +} diff --git a/actix-web-codegen/tests/trybuild/routes-missing-method-fail.stderr b/actix-web-codegen/tests/trybuild/routes-missing-method-fail.stderr new file mode 100644 index 000000000..c7de4047f --- /dev/null +++ b/actix-web-codegen/tests/trybuild/routes-missing-method-fail.stderr @@ -0,0 +1,13 @@ +error: The #[routes] macro requires at least one `#[(..)]` attribute. + --> tests/trybuild/routes-missing-method-fail.rs:3:1 + | +3 | #[routes] + | ^^^^^^^^^ + | + = note: this error originates in the attribute macro `routes` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `fn() -> impl std::future::Future {index}: HttpServiceFactory` is not satisfied + --> tests/trybuild/routes-missing-method-fail.rs:12:55 + | +12 | let srv = actix_test::start(|| App::new().service(index)); + | ^^^^^ the trait `HttpServiceFactory` is not implemented for `fn() -> impl std::future::Future {index}`