Skip to content

Commit 88054d0

Browse files
committed
Support user format-like macros
Add support for `#[clippy::format_args]` attribute that can be attached to any macro to indicate that it functions the same as the built-in format macros like `format!`, `println!` and `write!`
1 parent a01975b commit 88054d0

File tree

5 files changed

+35
-5
lines changed

5 files changed

+35
-5
lines changed

clippy_utils/src/attrs.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ pub const BUILTIN_ATTRIBUTES: &[(&str, DeprecationStatus)] = &[
2828
("dump", DeprecationStatus::None),
2929
("msrv", DeprecationStatus::None),
3030
("has_significant_drop", DeprecationStatus::None),
31+
("format_args", DeprecationStatus::None),
3132
];
3233

3334
pub struct LimitStack {

clippy_utils/src/macros.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
#![allow(clippy::similar_names)] // `expr` and `expn`
22

3+
use crate::get_unique_attr;
34
use crate::visitors::{Descend, for_each_expr_without_closures};
45

56
use arrayvec::ArrayVec;
67
use rustc_ast::{FormatArgs, FormatArgument, FormatPlaceholder};
78
use rustc_data_structures::fx::FxHashMap;
89
use rustc_data_structures::sync::{Lrc, OnceLock};
910
use rustc_hir::{self as hir, Expr, ExprKind, HirId, Node, QPath};
10-
use rustc_lint::LateContext;
11+
use rustc_lint::{LateContext, LintContext};
1112
use rustc_span::def_id::DefId;
1213
use rustc_span::hygiene::{self, MacroKind, SyntaxContext};
1314
use rustc_span::{BytePos, ExpnData, ExpnId, ExpnKind, Span, SpanData, Symbol, sym};
@@ -36,7 +37,9 @@ pub fn is_format_macro(cx: &LateContext<'_>, macro_def_id: DefId) -> bool {
3637
if let Some(name) = cx.tcx.get_diagnostic_name(macro_def_id) {
3738
FORMAT_MACRO_DIAG_ITEMS.contains(&name)
3839
} else {
39-
false
40+
// Allow users to tag any macro as being format!-like
41+
// TODO: consider deleting FORMAT_MACRO_DIAG_ITEMS and using just this method
42+
get_unique_attr(cx.sess(), cx.tcx.get_attrs_unchecked(macro_def_id), "format_args").is_some()
4043
}
4144
}
4245

tests/ui/uninlined_format_args.fixed

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,7 @@ macro_rules! my_concat {
212212
}
213213
}
214214

215+
#[clippy::format_args]
215216
macro_rules! my_good_macro {
216217
($fmt:literal $(, $e:expr)* $(,)?) => {
217218
println!($fmt $(, $e)*)
@@ -255,8 +256,8 @@ fn tester2() {
255256
my_println2_args!(true, "{}", local_i32);
256257
my_println2!(true, "{}", local_i32);
257258
my_concat!("{}", local_i32);
258-
my_good_macro!("{}", local_i32);
259-
my_good_macro!("{}", local_i32,);
259+
my_good_macro!("{local_i32}");
260+
my_good_macro!("{local_i32}",);
260261

261262
// FIXME: Broken false positives, currently unhandled
262263
my_bad_macro!("{}", local_i32);

tests/ui/uninlined_format_args.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,7 @@ macro_rules! my_concat {
217217
}
218218
}
219219

220+
#[clippy::format_args]
220221
macro_rules! my_good_macro {
221222
($fmt:literal $(, $e:expr)* $(,)?) => {
222223
println!($fmt $(, $e)*)

tests/ui/uninlined_format_args.stderr

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -845,5 +845,29 @@ LL - println!("expand='{}'", local_i32);
845845
LL + println!("expand='{local_i32}'");
846846
|
847847

848-
error: aborting due to 71 previous errors
848+
error: variables can be used directly in the `format!` string
849+
--> tests/ui/uninlined_format_args.rs:264:5
850+
|
851+
LL | my_good_macro!("{}", local_i32);
852+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
853+
|
854+
help: change this to
855+
|
856+
LL - my_good_macro!("{}", local_i32);
857+
LL + my_good_macro!("{local_i32}");
858+
|
859+
860+
error: variables can be used directly in the `format!` string
861+
--> tests/ui/uninlined_format_args.rs:265:5
862+
|
863+
LL | my_good_macro!("{}", local_i32,);
864+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
865+
|
866+
help: change this to
867+
|
868+
LL - my_good_macro!("{}", local_i32,);
869+
LL + my_good_macro!("{local_i32}",);
870+
|
871+
872+
error: aborting due to 73 previous errors
849873

0 commit comments

Comments
 (0)