Skip to content

unused_async doesn't work if an async fn without await has attribute #13199

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

Closed
hlf20010508 opened this issue Aug 1, 2024 · 2 comments
Closed
Labels
C-bug Category: Clippy is not doing the correct thing I-false-negative Issue: The lint should have been triggered on code, but wasn't

Comments

@hlf20010508
Copy link

Summary

I wrote a proc_macro_attribute, only added some trace to the code block, and the unused_async doesn't work anymore.

I tried to work around it in dylint, copied the code of unused_async.

If I remove condition !span.from_expansion() and use call_site for macro span, it worked.

let mut span = span;

if let Some(info) = span.macro_backtrace().next() {
    span = info.call_site
}

self.unused_async_fns.push(UnusedAsyncFn {
    await_in_async_block: visitor.await_in_async_block,
    fn_span: span,
    def_id,
});

Is there anything more should be considered for macros that I don't know?

Lint Name

unused_async

Reproducer

Attribute:

use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, ItemFn};

#[proc_macro_attribute]
pub fn add_trace(_args: TokenStream, item: TokenStream) -> TokenStream {
    let input = parse_macro_input!(item as ItemFn);

    let fn_attrs = &input.attrs;
    let fn_visibility = &input.vis;
    let fn_is_async = input.sig.asyncness.is_some();
    let fn_name = &input.sig.ident;
    let fn_generics = &input.sig.generics;
    let fn_inputs = &input.sig.inputs;
    let fn_output = &input.sig.output;
    let fn_where_clause = &input.sig.generics.where_clause;
    let fn_block = &input.block;

    let fn_name_str = &fn_name.to_string();

    let expanded = if fn_is_async {
        quote! {
            #(#fn_attrs)*
            #fn_visibility async fn #fn_name #fn_generics(#fn_inputs) #fn_output #fn_where_clause {
                let func_path = module_path!().to_string() + "::" + #fn_name_str;
                tracing::trace!("->|{}", func_path);
                let result = #fn_block;
                tracing::trace!("<-|{}", func_path);
                result
            }
        }
    } else {
        quote! {
            #(#fn_attrs)*
            #fn_visibility fn #fn_name #fn_generics(#fn_inputs) #fn_output #fn_where_clause {
                let func_path = module_path!().to_string() + "::" + #fn_name_str;
                tracing::trace!("->|{}", func_path);
                let result = #fn_block;
                tracing::trace!("<-|{}", func_path);
                result
            }
        }
    };

    TokenStream::from(expanded)
}

Fn:

#[add_trace]
pub async fn test() {
    println!("test");
}

Version

rustc 1.80.0-nightly (c987ad527 2024-05-01)
@hlf20010508 hlf20010508 added C-bug Category: Clippy is not doing the correct thing I-false-negative Issue: The lint should have been triggered on code, but wasn't labels Aug 1, 2024
@hlf20010508
Copy link
Author

I also found that it doesn't work for

pub async fn test() {
    async {
        println!("test");
    }
    .await;
}

@Alexendoo
Copy link
Member

The produced function can be detected as not from a macro expansion by preserving the token spans, e.g.

use proc_macro::TokenStream;
use quote::{quote, ToTokens};
use syn::{parse_macro_input, ItemFn};

#[proc_macro_attribute]
pub fn add_trace(_args: TokenStream, item: TokenStream) -> TokenStream {
    let input = parse_macro_input!(item as ItemFn);

    let mut tokens = input.sig.to_token_stream();
    input.block.brace_token.surround(&mut tokens, |tokens| {
        let fn_name = input.sig.ident.to_string();
        let fn_block = &input.block;
        tokens.extend(quote! {
            let func_path = module_path!().to_string() + "::" + #fn_name;
            tracing::trace!("->|{}", func_path);
            let result = #fn_block;
            tracing::trace!("<-|{}", func_path);
            result
        });
    });

    tokens.into()
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-bug Category: Clippy is not doing the correct thing I-false-negative Issue: The lint should have been triggered on code, but wasn't
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants