Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

macros: append generated test attribute so others are aware of it #6497

Merged
merged 11 commits into from
May 5, 2024
20 changes: 20 additions & 0 deletions tests-build/tests/fail/macros_invalid_input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,24 @@ async fn test_crate_not_path_invalid() {}
#[test]
async fn test_has_second_test_attr() {}

#[tokio::test]
#[::core::prelude::v1::test]
async fn test_has_second_test_attr_v1() {}

#[tokio::test]
#[core::prelude::rust_2015::test]
async fn test_has_second_test_attr_rust_2015() {}

#[tokio::test]
#[::std::prelude::rust_2018::test]
async fn test_has_second_test_attr_rust_2018() {}

#[tokio::test]
#[std::prelude::rust_2021::test]
async fn test_has_second_test_attr_rust_2021() {}

#[tokio::test]
#[tokio::test]
async fn test_has_generated_second_test_attr() {}

fn main() {}
38 changes: 29 additions & 9 deletions tests-build/tests/fail/macros_invalid_input.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -76,20 +76,40 @@ error: Failed to parse value of `crate` as path: "456"
41 | #[tokio::test(crate = "456")]
| ^^^^^

error: second test attribute is supplied
error: second test attribute is supplied, consider removing or changing the order of your test attributes
--> $DIR/macros_invalid_input.rs:45:1
|
45 | #[test]
| ^^^^^^^

error: duplicated attribute
--> $DIR/macros_invalid_input.rs:45:1
error: second test attribute is supplied, consider removing or changing the order of your test attributes
--> $DIR/macros_invalid_input.rs:49:1
|
45 | #[test]
| ^^^^^^^
49 | #[::core::prelude::v1::test]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: second test attribute is supplied, consider removing or changing the order of your test attributes
--> $DIR/macros_invalid_input.rs:53:1
|
53 | #[core::prelude::rust_2015::test]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: second test attribute is supplied, consider removing or changing the order of your test attributes
--> $DIR/macros_invalid_input.rs:57:1
|
57 | #[::std::prelude::rust_2018::test]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: second test attribute is supplied, consider removing or changing the order of your test attributes
--> $DIR/macros_invalid_input.rs:61:1
|
61 | #[std::prelude::rust_2021::test]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: second test attribute is supplied, consider removing or changing the order of your test attributes
--> $DIR/macros_invalid_input.rs:64:1
|
note: the lint level is defined here
--> $DIR/macros_invalid_input.rs:1:9
64 | #[tokio::test]
| ^^^^^^^^^^^^^^
|
1 | #![deny(duplicate_macro_attributes)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: this error originates in the attribute macro `tokio::test` (in Nightly builds, run with -Z macro-backtrace for more info)
44 changes: 37 additions & 7 deletions tokio-macros/src/entry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,7 @@ fn parse_knobs(mut input: ItemFn, is_test: bool, config: FinalConfig) -> TokenSt
rt = quote_spanned! {last_stmt_start_span=> #rt.start_paused(#v) };
}

let header = if is_test {
let generated_attrs = if is_test {
quote! {
#[::core::prelude::v1::test]
}
Expand Down Expand Up @@ -410,7 +410,7 @@ fn parse_knobs(mut input: ItemFn, is_test: bool, config: FinalConfig) -> TokenSt
}
};

input.into_tokens(header, body, last_block)
input.into_tokens(generated_attrs, body, last_block)
}

fn token_stream_with_error(mut tokens: TokenStream, error: syn::Error) -> TokenStream {
Expand Down Expand Up @@ -442,6 +442,35 @@ pub(crate) fn main(args: TokenStream, item: TokenStream, rt_multi_thread: bool)
}
}

// Check whether given attribute is a test attribute of forms:
// * `#[test]`
// * `#[core::prelude::*::test]` or `#[::core::prelude::*::test]`
// * `#[std::prelude::*::test]` or `#[::std::prelude::*::test]`
fn is_test_attribute(attr: &Attribute) -> bool {
let path = match &attr.meta {
syn::Meta::Path(path) => path,
_ => return false,
};
let candidates = [
["core", "prelude", "*", "test"],
["std", "prelude", "*", "test"],
];
if path.leading_colon.is_none()
&& path.segments.len() == 1
&& path.segments[0].arguments.is_none()
&& path.segments[0].ident == "test"
{
return true;
} else if path.segments.len() != candidates[0].len() {
return false;
}
candidates.into_iter().any(|segments| {
path.segments.iter().zip(segments).all(|(segment, path)| {
segment.arguments.is_none() && (path == "*" || segment.ident == path)
})
})
}

pub(crate) fn test(args: TokenStream, item: TokenStream, rt_multi_thread: bool) -> TokenStream {
// If any of the steps for this macro fail, we still want to expand to an item that is as close
// to the expected output as possible. This helps out IDEs such that completions and other
Expand All @@ -450,8 +479,8 @@ pub(crate) fn test(args: TokenStream, item: TokenStream, rt_multi_thread: bool)
Ok(it) => it,
Err(e) => return token_stream_with_error(item, e),
};
let config = if let Some(attr) = input.attrs().find(|attr| attr.meta.path().is_ident("test")) {
let msg = "second test attribute is supplied";
let config = if let Some(attr) = input.attrs().find(|attr| is_test_attribute(attr)) {
let msg = "second test attribute is supplied, consider removing or changing the order of your test attributes";
Err(syn::Error::new_spanned(attr, msg))
} else {
AttributeArgs::parse_terminated
Expand Down Expand Up @@ -492,13 +521,11 @@ impl ItemFn {
/// Convert our local function item into a token stream.
fn into_tokens(
self,
header: proc_macro2::TokenStream,
generated_attrs: proc_macro2::TokenStream,
body: proc_macro2::TokenStream,
last_block: proc_macro2::TokenStream,
) -> TokenStream {
let mut tokens = proc_macro2::TokenStream::new();
header.to_tokens(&mut tokens);

// Outer attributes are simply streamed as-is.
for attr in self.outer_attrs {
attr.to_tokens(&mut tokens);
Expand All @@ -512,6 +539,9 @@ impl ItemFn {
attr.to_tokens(&mut tokens);
}

// Add generated macros at the end, so macros processed later are aware of them.
generated_attrs.to_tokens(&mut tokens);
Darksonn marked this conversation as resolved.
Show resolved Hide resolved

self.vis.to_tokens(&mut tokens);
self.sig.to_tokens(&mut tokens);

Expand Down