Skip to content

Commit 0c5af12

Browse files
9999yearshds
authored andcommitted
Let dead_code lint work on #[instrument]ed functions (#3108)
Closes #1366
1 parent 5366628 commit 0c5af12

File tree

8 files changed

+99
-47
lines changed

8 files changed

+99
-47
lines changed

tracing-attributes/src/expand.rs

Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use std::iter;
22

33
use proc_macro2::TokenStream;
4+
use quote::TokenStreamExt;
45
use quote::{quote, quote_spanned, ToTokens};
56
use syn::visit_mut::VisitMut;
67
use syn::{
@@ -29,6 +30,7 @@ pub(crate) fn gen_function<'a, B: ToTokens + 'a>(
2930
inner_attrs,
3031
vis,
3132
sig,
33+
brace_token,
3234
block,
3335
} = input;
3436

@@ -44,9 +46,12 @@ pub(crate) fn gen_function<'a, B: ToTokens + 'a>(
4446
syn::Generics {
4547
params: gen_params,
4648
where_clause,
47-
..
49+
lt_token,
50+
gt_token,
4851
},
49-
..
52+
fn_token,
53+
paren_token,
54+
variadic,
5055
} = sig;
5156

5257
let warnings = args.warnings();
@@ -65,9 +70,14 @@ pub(crate) fn gen_function<'a, B: ToTokens + 'a>(
6570
// exactly that way for it to do its magic.
6671
let fake_return_edge = quote_spanned! {return_span=>
6772
#[allow(
68-
unknown_lints, unreachable_code, clippy::diverging_sub_expression,
69-
clippy::let_unit_value, clippy::unreachable, clippy::let_with_type_underscore,
70-
clippy::empty_loop
73+
unknown_lints,
74+
unreachable_code,
75+
clippy::diverging_sub_expression,
76+
clippy::empty_loop,
77+
clippy::let_unit_value,
78+
clippy::let_with_type_underscore,
79+
clippy::needless_return,
80+
clippy::unreachable
7181
)]
7282
if false {
7383
let __tracing_attr_fake_return: #return_type = loop {};
@@ -90,16 +100,27 @@ pub(crate) fn gen_function<'a, B: ToTokens + 'a>(
90100
self_type,
91101
);
92102

93-
quote!(
103+
let mut result = quote!(
94104
#(#outer_attrs) *
95-
#vis #constness #asyncness #unsafety #abi fn #ident<#gen_params>(#params) #output
96-
#where_clause
97-
{
98-
#(#inner_attrs) *
99-
#warnings
100-
#body
101-
}
102-
)
105+
#vis #constness #asyncness #unsafety #abi #fn_token #ident
106+
#lt_token #gen_params #gt_token
107+
);
108+
109+
paren_token.surround(&mut result, |tokens| {
110+
params.to_tokens(tokens);
111+
variadic.to_tokens(tokens);
112+
});
113+
114+
output.to_tokens(&mut result);
115+
where_clause.to_tokens(&mut result);
116+
117+
brace_token.surround(&mut result, |tokens| {
118+
tokens.append_all(inner_attrs);
119+
warnings.to_tokens(tokens);
120+
body.to_tokens(tokens);
121+
});
122+
123+
result
103124
}
104125

105126
/// Instrument a block

tracing-attributes/src/lib.rs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,10 @@
8383
extern crate proc_macro;
8484

8585
use proc_macro2::TokenStream;
86+
use quote::TokenStreamExt;
8687
use quote::{quote, ToTokens};
8788
use syn::parse::{Parse, ParseStream};
89+
use syn::token::Brace;
8890
use syn::{Attribute, ItemFn, Signature, Visibility};
8991

9092
mod attr;
@@ -628,6 +630,7 @@ struct MaybeItemFn {
628630
inner_attrs: Vec<Attribute>,
629631
vis: Visibility,
630632
sig: Signature,
633+
brace_token: Brace,
631634
block: TokenStream,
632635
}
633636

@@ -638,6 +641,7 @@ impl MaybeItemFn {
638641
inner_attrs: &self.inner_attrs,
639642
vis: &self.vis,
640643
sig: &self.sig,
644+
brace_token: &self.brace_token,
641645
block: &self.block,
642646
}
643647
}
@@ -651,12 +655,15 @@ impl Parse for MaybeItemFn {
651655
let vis: Visibility = input.parse()?;
652656
let sig: Signature = input.parse()?;
653657
let inner_attrs = input.call(Attribute::parse_inner)?;
654-
let block: TokenStream = input.parse()?;
658+
let block;
659+
let brace_token = syn::braced!(block in input);
660+
let block: TokenStream = block.call(|buffer| buffer.parse())?;
655661
Ok(Self {
656662
outer_attrs,
657663
inner_attrs,
658664
vis,
659665
sig,
666+
brace_token,
660667
block,
661668
})
662669
}
@@ -674,12 +681,15 @@ impl From<ItemFn> for MaybeItemFn {
674681
let (outer_attrs, inner_attrs) = attrs
675682
.into_iter()
676683
.partition(|attr| attr.style == syn::AttrStyle::Outer);
684+
let mut block_tokens = TokenStream::new();
685+
block_tokens.append_all(block.stmts);
677686
Self {
678687
outer_attrs,
679688
inner_attrs,
680689
vis,
681690
sig,
682-
block: block.to_token_stream(),
691+
brace_token: block.brace_token,
692+
block: block_tokens,
683693
}
684694
}
685695
}
@@ -692,5 +702,6 @@ struct MaybeItemFnRef<'a, B: ToTokens> {
692702
inner_attrs: &'a Vec<Attribute>,
693703
vis: &'a Visibility,
694704
sig: &'a Signature,
705+
brace_token: &'a Brace,
695706
block: &'a B,
696707
}

tracing-attributes/tests/async_fn.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,17 @@ async fn test_ret_impl_trait_err(n: i32) -> Result<impl Iterator<Item = i32>, &'
3030
}
3131

3232
#[instrument]
33+
#[allow(dead_code)]
3334
async fn test_async_fn_empty() {}
3435

3536
#[instrument]
37+
#[allow(dead_code)]
3638
async unsafe fn test_async_unsafe_fn_empty() {}
3739

3840
// Reproduces a compile error when an instrumented function body contains inner
3941
// attributes (https://github.com/tokio-rs/tracing/issues/2294).
4042
#[deny(unused_variables)]
43+
#[allow(dead_code, clippy::mixed_attributes_style)]
4144
#[instrument]
4245
async fn repro_async_2294() {
4346
#![allow(unused_variables)]
@@ -50,6 +53,7 @@ async fn repro_async_2294() {
5053
// with the rustfmt-generated formatting, the lint will not be triggered!
5154
#[rustfmt::skip]
5255
#[deny(clippy::suspicious_else_formatting)]
56+
#[allow(dead_code)]
5357
async fn repro_1613(var: bool) {
5458
println!(
5559
"{}",
@@ -61,6 +65,7 @@ async fn repro_1613(var: bool) {
6165
// and https://github.com/rust-lang/rust-clippy/issues/7760
6266
#[instrument]
6367
#[deny(clippy::suspicious_else_formatting)]
68+
#[allow(dead_code)]
6469
async fn repro_1613_2() {
6570
// hello world
6671
// else

tracing-attributes/tests/dead_code.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
use tracing_attributes::instrument;
2+
3+
#[deny(unfulfilled_lint_expectations)]
4+
#[expect(dead_code)]
5+
#[instrument]
6+
fn unused() {}
7+
8+
#[expect(dead_code)]
9+
#[instrument]
10+
async fn unused_async() {}

tracing-attributes/tests/err.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ fn err() -> Result<u8, TryFromIntError> {
1515
}
1616

1717
#[instrument(err)]
18+
#[allow(dead_code)]
1819
fn err_suspicious_else() -> Result<u8, TryFromIntError> {
1920
{}
2021
u8::try_from(1234)

tracing-attributes/tests/instrument.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use tracing_mock::*;
66
// Reproduces a compile error when an instrumented function body contains inner
77
// attributes (https://github.com/tokio-rs/tracing/issues/2294).
88
#[deny(unused_variables)]
9+
#[allow(dead_code, clippy::mixed_attributes_style)]
910
#[instrument]
1011
fn repro_2294() {
1112
#![allow(unused_variables)]
@@ -331,6 +332,7 @@ fn user_tracing_module() {
331332

332333
// Reproduces https://github.com/tokio-rs/tracing/issues/3119
333334
#[instrument(fields(f = Empty))]
335+
#[allow(dead_code)]
334336
fn my_fn() {
335337
assert_eq!("test", tracing::my_other_fn());
336338
}

tracing-attributes/tests/ui/async_instrument.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ async fn simple_mismatch() -> String {
1010
""
1111
}
1212

13-
// FIXME: this span is still pretty poor
1413
#[tracing::instrument]
1514
async fn opaque_unsatisfied() -> impl std::fmt::Display {
1615
("",)

tracing-attributes/tests/ui/async_instrument.stderr

Lines changed: 33 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -25,77 +25,80 @@ note: return type inferred to be `String` here
2525
| ^^^^^^
2626

2727
error[E0277]: `(&str,)` doesn't implement `std::fmt::Display`
28-
--> tests/ui/async_instrument.rs:14:1
28+
--> tests/ui/async_instrument.rs:14:57
2929
|
30-
14 | #[tracing::instrument]
31-
| ^^^^^^^^^^^^^^^^^^^^^^
32-
| |
33-
| `(&str,)` cannot be formatted with the default formatter
34-
| return type was inferred to be `(&str,)` here
30+
14 | async fn opaque_unsatisfied() -> impl std::fmt::Display {
31+
| _________________________________________________________-
32+
15 | | ("",)
33+
16 | | }
34+
| | ^
35+
| | |
36+
| |_`(&str,)` cannot be formatted with the default formatter
37+
| return type was inferred to be `(&str,)` here
3538
|
3639
= help: the trait `std::fmt::Display` is not implemented for `(&str,)`
3740
= note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
38-
= note: this error originates in the attribute macro `tracing::instrument` (in Nightly builds, run with -Z macro-backtrace for more info)
3941

4042
error[E0277]: `(&str,)` doesn't implement `std::fmt::Display`
41-
--> tests/ui/async_instrument.rs:15:34
43+
--> tests/ui/async_instrument.rs:14:34
4244
|
43-
15 | async fn opaque_unsatisfied() -> impl std::fmt::Display {
45+
14 | async fn opaque_unsatisfied() -> impl std::fmt::Display {
4446
| ^^^^^^^^^^^^^^^^^^^^^^ `(&str,)` cannot be formatted with the default formatter
4547
|
4648
= help: the trait `std::fmt::Display` is not implemented for `(&str,)`
4749
= note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
4850

4951
error[E0308]: mismatched types
50-
--> tests/ui/async_instrument.rs:23:5
52+
--> tests/ui/async_instrument.rs:22:5
5153
|
52-
23 | ""
54+
22 | ""
5355
| ^^ expected `Wrapper<_>`, found `&str`
5456
|
5557
= note: expected struct `Wrapper<_>`
5658
found reference `&'static str`
5759
note: return type inferred to be `Wrapper<_>` here
58-
--> tests/ui/async_instrument.rs:22:36
60+
--> tests/ui/async_instrument.rs:21:36
5961
|
60-
22 | async fn mismatch_with_opaque() -> Wrapper<impl std::fmt::Display> {
62+
21 | async fn mismatch_with_opaque() -> Wrapper<impl std::fmt::Display> {
6163
| ^^^^^^^
6264
help: try wrapping the expression in `Wrapper`
6365
|
64-
23 | Wrapper("")
66+
22 | Wrapper("")
6567
| ++++++++ +
6668

6769
error[E0308]: mismatched types
68-
--> tests/ui/async_instrument.rs:29:16
70+
--> tests/ui/async_instrument.rs:28:16
6971
|
70-
29 | return "";
72+
28 | return "";
7173
| ^^ expected `()`, found `&str`
7274
|
7375
note: return type inferred to be `()` here
74-
--> tests/ui/async_instrument.rs:27:10
76+
--> tests/ui/async_instrument.rs:26:10
7577
|
76-
27 | async fn early_return_unit() {
78+
26 | async fn early_return_unit() {
7779
| ^^^^^^^^^^^^^^^^^
7880

7981
error[E0308]: mismatched types
80-
--> tests/ui/async_instrument.rs:36:16
82+
--> tests/ui/async_instrument.rs:35:16
8183
|
82-
36 | return "";
84+
35 | return "";
8385
| ^^- help: try using a conversion method: `.to_string()`
8486
| |
8587
| expected `String`, found `&str`
8688
|
8789
note: return type inferred to be `String` here
88-
--> tests/ui/async_instrument.rs:34:28
90+
--> tests/ui/async_instrument.rs:33:28
8991
|
90-
34 | async fn early_return() -> String {
92+
33 | async fn early_return() -> String {
9193
| ^^^^^^
9294

9395
error[E0308]: mismatched types
94-
--> tests/ui/async_instrument.rs:42:35
95-
|
96-
42 | async fn extra_semicolon() -> i32 {
97-
| ___________________________________^
98-
43 | | 1;
99-
| | - help: remove this semicolon to return this value
100-
44 | | }
101-
| |_^ expected `i32`, found `()`
96+
--> tests/ui/async_instrument.rs:40:1
97+
|
98+
40 | #[tracing::instrument]
99+
| ^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `()`
100+
41 | async fn extra_semicolon() -> i32 {
101+
42 | 1;
102+
| - help: remove this semicolon to return this value
103+
|
104+
= note: this error originates in the attribute macro `tracing::instrument` (in Nightly builds, run with -Z macro-backtrace for more info)

0 commit comments

Comments
 (0)