1
0
mirror of https://github.com/fafhrd91/actix-net synced 2024-11-27 16:52:58 +01:00

make runtime macros more IDE friendly (#391)

This commit is contained in:
Rob Ede 2021-10-14 10:54:39 +01:00 committed by GitHub
parent 5c555a9408
commit 4ff8a2cf68
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 109 additions and 6 deletions

View File

@ -1,6 +1,10 @@
# Changes # Changes
## Unreleased - 2021-xx-xx ## Unreleased - 2021-xx-xx
* Improve error recovery potential when macro input is invalid. [#391]
* Allow custom `System`s on test macro. [#391]
[#391]: https://github.com/actix/actix-net/pull/391
## 0.2.1 - 2021-02-02 ## 0.2.1 - 2021-02-02

View File

@ -28,7 +28,12 @@ use quote::quote;
#[proc_macro_attribute] #[proc_macro_attribute]
#[cfg(not(test))] // Work around for rust-lang/rust#62127 #[cfg(not(test))] // Work around for rust-lang/rust#62127
pub fn main(args: TokenStream, item: TokenStream) -> TokenStream { pub fn main(args: TokenStream, item: TokenStream) -> TokenStream {
let mut input = syn::parse_macro_input!(item as syn::ItemFn); let mut input = match syn::parse::<syn::ItemFn>(item.clone()) {
Ok(input) => input,
// on parse err, make IDEs happy; see fn docs
Err(err) => return input_and_compile_error(item, err),
};
let args = syn::parse_macro_input!(args as syn::AttributeArgs); let args = syn::parse_macro_input!(args as syn::AttributeArgs);
let attrs = &input.attrs; let attrs = &input.attrs;
@ -101,8 +106,15 @@ pub fn main(args: TokenStream, item: TokenStream) -> TokenStream {
/// } /// }
/// ``` /// ```
#[proc_macro_attribute] #[proc_macro_attribute]
pub fn test(_: TokenStream, item: TokenStream) -> TokenStream { pub fn test(args: TokenStream, item: TokenStream) -> TokenStream {
let mut input = syn::parse_macro_input!(item as syn::ItemFn); let mut input = match syn::parse::<syn::ItemFn>(item.clone()) {
Ok(input) => input,
// on parse err, make IDEs happy; see fn docs
Err(err) => return input_and_compile_error(item, err),
};
let args = syn::parse_macro_input!(args as syn::AttributeArgs);
let attrs = &input.attrs; let attrs = &input.attrs;
let vis = &input.vis; let vis = &input.vis;
let sig = &mut input.sig; let sig = &mut input.sig;
@ -132,13 +144,59 @@ pub fn test(_: TokenStream, item: TokenStream) -> TokenStream {
quote!(#[test]) quote!(#[test])
}; };
let mut system = syn::parse_str::<syn::Path>("::actix_rt::System").unwrap();
for arg in &args {
match arg {
syn::NestedMeta::Meta(syn::Meta::NameValue(syn::MetaNameValue {
lit: syn::Lit::Str(lit),
path,
..
})) => match path
.get_ident()
.map(|i| i.to_string().to_lowercase())
.as_deref()
{
Some("system") => match lit.parse() {
Ok(path) => system = path,
Err(_) => {
return syn::Error::new_spanned(lit, "Expected path")
.to_compile_error()
.into();
}
},
_ => {
return syn::Error::new_spanned(arg, "Unknown attribute specified")
.to_compile_error()
.into();
}
},
_ => {
return syn::Error::new_spanned(arg, "Unknown attribute specified")
.to_compile_error()
.into();
}
}
}
(quote! { (quote! {
#missing_test_attr #missing_test_attr
#(#attrs)* #(#attrs)*
#vis #sig { #vis #sig {
actix_rt::System::new() <#system>::new().block_on(async { #body })
.block_on(async { #body })
} }
}) })
.into() .into()
} }
/// Converts the error to a token stream and appends it to the original input.
///
/// Returning the original input in addition to the error is good for IDEs which can gracefully
/// recover and show more precise errors within the macro body.
///
/// See <https://github.com/rust-analyzer/rust-analyzer/issues/10468> for more info.
fn input_and_compile_error(mut item: TokenStream, err: syn::Error) -> TokenStream {
let compile_err = TokenStream::from(err.to_compile_error());
item.extend(compile_err);
return item;
}

View File

@ -11,4 +11,7 @@ fn compile_macros() {
t.pass("tests/trybuild/test-01-basic.rs"); t.pass("tests/trybuild/test-01-basic.rs");
t.pass("tests/trybuild/test-02-keep-attrs.rs"); t.pass("tests/trybuild/test-02-keep-attrs.rs");
t.compile_fail("tests/trybuild/test-03-only-async.rs"); t.compile_fail("tests/trybuild/test-03-only-async.rs");
t.pass("tests/trybuild/test-04-system-path.rs");
t.compile_fail("tests/trybuild/test-05-system-expect-path.rs");
t.compile_fail("tests/trybuild/test-06-unknown-attr.rs");
} }

View File

@ -0,0 +1,10 @@
mod system {
pub use actix_rt::System as MySystem;
}
#[actix_rt::test(system = "system::MySystem")]
async fn my_test() {
futures_util::future::ready(()).await
}
fn main() {}

View File

@ -0,0 +1,4 @@
#[actix_rt::test(system = "!@#*&")]
async fn my_test() {}
fn main() {}

View File

@ -0,0 +1,5 @@
error: Expected path
--> $DIR/test-05-system-expect-path.rs:1:27
|
1 | #[actix_rt::test(system = "!@#*&")]
| ^^^^^^^

View File

@ -0,0 +1,7 @@
#[actix_rt::test(foo = "bar")]
async fn my_test_1() {}
#[actix_rt::test(bar::baz)]
async fn my_test_2() {}
fn main() {}

View File

@ -0,0 +1,11 @@
error: Unknown attribute specified
--> $DIR/test-06-unknown-attr.rs:1:18
|
1 | #[actix_rt::test(foo = "bar")]
| ^^^^^^^^^^^
error: Unknown attribute specified
--> $DIR/test-06-unknown-attr.rs:4:18
|
4 | #[actix_rt::test(bar::baz)]
| ^^^^^^^^

View File

@ -24,4 +24,5 @@ serde = { version = "1.0", optional = true }
[dev-dependencies] [dev-dependencies]
serde_json = "1.0" serde_json = "1.0"
ahash = { version = "0.7", default-features = false } # TODO: remove when ahash MSRV is restored
ahash = { version = "=0.7.4", default-features = false }