| //@aux-build:proc_macros.rs | |
| #![warn(clippy::uninlined_format_args)] | |
| #![allow(named_arguments_used_positionally, unused)] | |
| #![allow( | |
| clippy::eq_op, | |
| clippy::format_in_format_args, | |
| clippy::print_literal, | |
| clippy::unnecessary_literal_unwrap | |
| )] | |
| extern crate proc_macros; | |
| use proc_macros::with_span; | |
| macro_rules! no_param_str { | |
| () => { | |
| "{}" | |
| }; | |
| } | |
| macro_rules! my_println { | |
| ($($args:tt),*) => {{ | |
| println!($($args),*) | |
| }}; | |
| } | |
| macro_rules! my_println_args { | |
| ($($args:tt),*) => {{ | |
| println!("foo: {}", format_args!($($args),*)) | |
| }}; | |
| } | |
| fn tester(fn_arg: i32) { | |
| let local_i32 = 1; | |
| let local_f64 = 2.0; | |
| let local_opt: Option<i32> = Some(3); | |
| let width = 4; | |
| let prec = 5; | |
| let val = 6; | |
| // make sure this file hasn't been corrupted with tabs converted to spaces | |
| // let _ = ' '; // <- this is a single tab character | |
| let _: &[u8; 3] = b" "; // <- <tab><space><tab> | |
| println!("val='{local_i32}'"); | |
| //~^ uninlined_format_args | |
| println!("val='{local_i32}'"); // 3 spaces | |
| // | |
| //~^^ uninlined_format_args | |
| println!("val='{local_i32}'"); // tab | |
| // | |
| //~^^ uninlined_format_args | |
| println!("val='{local_i32}'"); // space+tab | |
| // | |
| //~^^ uninlined_format_args | |
| println!("val='{local_i32}'"); // tab+space | |
| // | |
| //~^^ uninlined_format_args | |
| println!( | |
| //~^ uninlined_format_args | |
| "val='{local_i32}'" | |
| ); | |
| println!("{local_i32}"); | |
| //~^ uninlined_format_args | |
| println!("{fn_arg}"); | |
| //~^ uninlined_format_args | |
| println!("{local_i32:?}"); | |
| //~^ uninlined_format_args | |
| println!("{local_i32:#?}"); | |
| //~^ uninlined_format_args | |
| println!("{local_i32:4}"); | |
| //~^ uninlined_format_args | |
| println!("{local_i32:04}"); | |
| //~^ uninlined_format_args | |
| println!("{local_i32:<3}"); | |
| //~^ uninlined_format_args | |
| println!("{local_i32:#010x}"); | |
| //~^ uninlined_format_args | |
| println!("{local_f64:.1}"); | |
| //~^ uninlined_format_args | |
| println!("Hello {} is {:.*}", "x", local_i32, local_f64); | |
| println!("Hello {} is {:.*}", local_i32, 5, local_f64); | |
| println!("Hello {} is {2:.*}", local_i32, 5, local_f64); | |
| println!("{local_i32} {local_f64}"); | |
| //~^ uninlined_format_args | |
| println!("{}, {}", local_i32, local_opt.unwrap()); | |
| println!("{val}"); | |
| //~^ uninlined_format_args | |
| println!("{val}"); | |
| //~^ uninlined_format_args | |
| println!("{} {1}", local_i32, 42); | |
| println!("val='{local_i32}'"); | |
| //~^ uninlined_format_args | |
| println!("val='{local_i32}'"); | |
| //~^ uninlined_format_args | |
| println!("val='{local_i32}'"); | |
| //~^ uninlined_format_args | |
| println!("val='{fn_arg}'"); | |
| //~^ uninlined_format_args | |
| println!("{local_i32}"); | |
| //~^ uninlined_format_args | |
| println!("{local_i32:?}"); | |
| //~^ uninlined_format_args | |
| println!("{local_i32:#?}"); | |
| //~^ uninlined_format_args | |
| println!("{local_i32:04}"); | |
| //~^ uninlined_format_args | |
| println!("{local_i32:<3}"); | |
| //~^ uninlined_format_args | |
| println!("{local_i32:#010x}"); | |
| //~^ uninlined_format_args | |
| println!("{local_f64:.1}"); | |
| //~^ uninlined_format_args | |
| println!("{local_i32} {local_i32}"); | |
| //~^ uninlined_format_args | |
| println!("{local_f64} {local_i32} {local_i32} {local_f64}"); | |
| //~^ uninlined_format_args | |
| println!("{local_i32} {local_f64}"); | |
| //~^ uninlined_format_args | |
| println!("{local_f64} {local_i32}"); | |
| //~^ uninlined_format_args | |
| println!("{local_f64} {local_i32} {local_f64} {local_i32}"); | |
| //~^ uninlined_format_args | |
| println!("{1} {0}", "str", local_i32); | |
| println!("{local_i32}"); | |
| //~^ uninlined_format_args | |
| println!("{local_i32:width$}"); | |
| //~^ uninlined_format_args | |
| println!("{local_i32:width$}"); | |
| //~^ uninlined_format_args | |
| println!("{local_i32:.prec$}"); | |
| //~^ uninlined_format_args | |
| println!("{local_i32:.prec$}"); | |
| //~^ uninlined_format_args | |
| println!("{val:val$}"); | |
| //~^ uninlined_format_args | |
| println!("{val:val$}"); | |
| //~^ uninlined_format_args | |
| println!("{val:val$.val$}"); | |
| //~^ uninlined_format_args | |
| println!("{val:val$.val$}"); | |
| //~^ uninlined_format_args | |
| println!("{val:val$.val$}"); | |
| //~^ uninlined_format_args | |
| println!("{val:val$.val$}"); | |
| //~^ uninlined_format_args | |
| println!("{val:val$.val$}"); | |
| //~^ uninlined_format_args | |
| println!("{val:val$.val$}"); | |
| //~^ uninlined_format_args | |
| println!("{val:val$.val$}"); | |
| //~^ uninlined_format_args | |
| println!("{val:val$.val$}"); | |
| //~^ uninlined_format_args | |
| println!("{width:width$}"); | |
| //~^ uninlined_format_args | |
| println!("{local_i32:width$}"); | |
| //~^ uninlined_format_args | |
| println!("{width:width$}"); | |
| //~^ uninlined_format_args | |
| println!("{local_i32:width$}"); | |
| //~^ uninlined_format_args | |
| println!("{prec:.prec$}"); | |
| //~^ uninlined_format_args | |
| println!("{local_i32:.prec$}"); | |
| //~^ uninlined_format_args | |
| println!("{prec:.prec$}"); | |
| //~^ uninlined_format_args | |
| println!("{local_i32:.prec$}"); | |
| //~^ uninlined_format_args | |
| println!("{width:width$.prec$}"); | |
| //~^ uninlined_format_args | |
| println!("{width:width$.prec$}"); | |
| //~^ uninlined_format_args | |
| println!("{local_f64:width$.prec$}"); | |
| //~^ uninlined_format_args | |
| println!("{local_f64:width$.prec$} {local_f64} {width} {prec}"); | |
| //~^ uninlined_format_args | |
| println!( | |
| //~^ uninlined_format_args | |
| "{local_i32:width$.prec$} {local_i32:prec$.width$} {width:local_i32$.prec$} {width:prec$.local_i32$} {prec:local_i32$.width$} {prec:width$.local_i32$}", | |
| ); | |
| println!( | |
| "{0:1$.2$} {0:2$.1$} {1:0$.2$} {1:2$.0$} {2:0$.1$} {2:1$.0$} {3}", | |
| local_i32, | |
| width, | |
| prec, | |
| 1 + 2 | |
| ); | |
| println!("Width = {local_i32}, value with width = {local_f64:local_i32$}"); | |
| //~^ uninlined_format_args | |
| println!("{local_i32:width$.prec$}"); | |
| //~^ uninlined_format_args | |
| println!("{width:width$.prec$}"); | |
| //~^ uninlined_format_args | |
| println!("{}", format!("{}", local_i32)); | |
| my_println!("{}", local_i32); | |
| my_println_args!("{}", local_i32); | |
| // these should NOT be modified by the lint | |
| println!(concat!("nope ", "{}"), local_i32); | |
| println!("val='{local_i32}'"); | |
| println!("val='{local_i32 }'"); | |
| println!("val='{local_i32 }'"); // with tab | |
| println!("val='{local_i32\n}'"); | |
| println!("{}", usize::MAX); | |
| println!("{}", local_opt.unwrap()); | |
| println!( | |
| "val='{local_i32 | |
| }'" | |
| ); | |
| println!(no_param_str!(), local_i32); | |
| println!( | |
| //~^ uninlined_format_args | |
| "{val}", | |
| ); | |
| println!("{val}"); | |
| //~^ uninlined_format_args | |
| println!(with_span!("{0} {1}" "{1} {0}"), local_i32, local_f64); | |
| println!("{}", with_span!(span val)); | |
| if local_i32 > 0 { | |
| panic!("p1 {local_i32}"); | |
| //~^ uninlined_format_args | |
| } | |
| if local_i32 > 0 { | |
| panic!("p2 {local_i32}"); | |
| //~^ uninlined_format_args | |
| } | |
| if local_i32 > 0 { | |
| panic!("p3 {local_i32}"); | |
| //~^ uninlined_format_args | |
| } | |
| if local_i32 > 0 { | |
| panic!("p4 {local_i32}"); | |
| } | |
| } | |
| fn main() {} | |
| #[clippy::msrv = "1.57"] | |
| fn _under_msrv() { | |
| let local_i32 = 1; | |
| println!("don't expand='{}'", local_i32); | |
| } | |
| #[clippy::msrv = "1.58"] | |
| fn _meets_msrv() { | |
| let local_i32 = 1; | |
| println!("expand='{local_i32}'"); | |
| //~^ uninlined_format_args | |
| } | |
| fn _do_not_fire() { | |
| println!("{:?}", None::<()>); | |
| } | |
| macro_rules! _internal { | |
| ($($args:tt)*) => { | |
| println!("{}", format_args!($($args)*)) | |
| }; | |
| } | |
| macro_rules! my_println2 { | |
| ($target:expr, $($args:tt)+) => {{ | |
| if $target { | |
| _internal!($($args)+) | |
| } | |
| }}; | |
| } | |
| macro_rules! my_println2_args { | |
| ($target:expr, $($args:tt)+) => {{ | |
| if $target { | |
| _internal!("foo: {}", format_args!($($args)+)) | |
| } | |
| }}; | |
| } | |
| macro_rules! my_concat { | |
| ($fmt:literal $(, $e:expr)*) => { | |
| println!(concat!("ERROR: ", $fmt), $($e,)*) | |
| } | |
| } | |
| macro_rules! my_good_macro { | |
| ($fmt:literal $(, $e:expr)* $(,)?) => { | |
| println!($fmt $(, $e)*) | |
| } | |
| } | |
| macro_rules! my_bad_macro { | |
| ($fmt:literal, $($e:expr),*) => { | |
| println!($fmt, $($e,)*) | |
| } | |
| } | |
| macro_rules! my_bad_macro2 { | |
| ($fmt:literal) => { | |
| let s = $fmt.clone(); | |
| println!("{}", s); | |
| }; | |
| ($fmt:literal, $($e:expr)+) => { | |
| println!($fmt, $($e,)*) | |
| }; | |
| } | |
| // This abomination was suggested by @Alexendoo, may the Rust gods have mercy on their soul... | |
| // https://github.com/rust-lang/rust-clippy/pull/9948#issuecomment-1327965962 | |
| macro_rules! used_twice { | |
| ( | |
| large = $large:literal, | |
| small = $small:literal, | |
| $val:expr, | |
| ) => { | |
| if $val < 5 { | |
| println!($small, $val); | |
| } else { | |
| println!($large, $val); | |
| } | |
| }; | |
| } | |
| fn tester2() { | |
| let local_i32 = 1; | |
| my_println2_args!(true, "{}", local_i32); | |
| my_println2!(true, "{}", local_i32); | |
| my_concat!("{}", local_i32); | |
| my_good_macro!("{}", local_i32); | |
| my_good_macro!("{}", local_i32,); | |
| my_bad_macro!("{}", local_i32); | |
| my_bad_macro2!("{}", local_i32); | |
| used_twice! { | |
| large = "large value: {}", | |
| small = "small value: {}", | |
| local_i32, | |
| }; | |
| } | |
| #[clippy::format_args] | |
| macro_rules! usr_println { | |
| ($target:expr, $($args:tt)*) => {{ | |
| if $target { | |
| println!($($args)*) | |
| } | |
| }}; | |
| } | |
| fn user_format() { | |
| let local_i32 = 1; | |
| let local_f64 = 2.0; | |
| usr_println!(true, "val='{local_i32}'"); | |
| //~^ uninlined_format_args | |
| usr_println!(true, "{local_i32}"); | |
| //~^ uninlined_format_args | |
| usr_println!(true, "{local_i32:#010x}"); | |
| //~^ uninlined_format_args | |
| usr_println!(true, "{local_f64:.1}"); | |
| //~^ uninlined_format_args | |
| } | |
| // issue #16411: false negative when #[clippy::format_args] macro uses nested format_args | |
| // without binding the inner args first | |
| #[clippy::format_args] | |
| macro_rules! nested_format_args { | |
| ($($arg:tt)*) => {{ | |
| // Wraps the user args in another format_args call | |
| ::core::format_args!("{}\n", ::core::format_args!($($arg)*)) | |
| }}; | |
| } | |
| fn nested_format_args_user() { | |
| let local_i32 = 1; | |
| let local_f64 = 2.0; | |
| // false negative: should warn but currently doesn't because the inner format_args | |
| // is not processed when it's used as an argument to another format_args | |
| nested_format_args!("{}", local_i32); | |
| nested_format_args!("val='{}'", local_i32); | |
| nested_format_args!("{:.1}", local_f64); | |
| } |