Add useless_borrows_in_formatting lint

Detect format macros where an argument
is passed with an explicit `&` even though the formatter already takes
references, e.g. `println!("{}", &s)` when `s: &str`.

Some original micro-benchmarks showed ~6% performance improvement when redundant refs are removed.

- Lint runs for both Display (`{}`) and Debug (`{:?}`) placeholders when
  the inner type is Sized and implements the corresponding trait.
- Applies to the main value argument and to width/precision arguments
  (e.g. `format!("{0:1$.2$}", &v1, &v2, &v3)`).
- Suggests removing the redundant `&` with MachineApplicable fix.
- Skip when the argument comes from expansion or a proc macro.
This commit is contained in:
Yuri Astrakhan
2026-02-06 04:39:03 -05:00
parent 5800532ce0
commit aaa5bd244e
11 changed files with 618 additions and 33 deletions
+1
View File
@@ -7393,6 +7393,7 @@ Released 2018-09-13
[`used_underscore_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#used_underscore_items
[`useless_asref`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_asref
[`useless_attribute`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_attribute
[`useless_borrows_in_formatting`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_borrows_in_formatting
[`useless_concat`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_concat
[`useless_conversion`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_conversion
[`useless_format`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_format
+1
View File
@@ -176,6 +176,7 @@
crate::format_args::UNNECESSARY_DEBUG_FORMATTING_INFO,
crate::format_args::UNNECESSARY_TRAILING_COMMA_INFO,
crate::format_args::UNUSED_FORMAT_SPECS_INFO,
crate::format_args::USELESS_BORROWS_IN_FORMATTING_INFO,
crate::format_impl::PRINT_IN_FORMAT_IMPL_INFO,
crate::format_impl::RECURSIVE_FORMAT_IMPL_INFO,
crate::format_push_string::FORMAT_PUSH_STRING_INFO,
+82 -4
View File
@@ -10,13 +10,13 @@
};
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::res::MaybeDef;
use clippy_utils::source::{SpanRangeExt, snippet};
use clippy_utils::source::{SpanRangeExt, snippet, snippet_opt};
use clippy_utils::ty::implements_trait;
use clippy_utils::{is_from_proc_macro, is_in_test, sym, trait_ref_of_method};
use clippy_utils::{is_from_proc_macro, is_in_test, peel_hir_expr_while, sym, trait_ref_of_method};
use itertools::Itertools;
use rustc_ast::{
FormatArgPosition, FormatArgPositionKind, FormatArgsPiece, FormatArgumentKind, FormatCount, FormatOptions,
FormatPlaceholder, FormatTrait,
BorrowKind, FormatArgPosition, FormatArgPositionKind, FormatArgsPiece, FormatArgumentKind, FormatCount,
FormatOptions, FormatPlaceholder, FormatTrait,
};
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::Applicability;
@@ -257,6 +257,34 @@
"use of a format specifier that has no effect"
}
declare_clippy_lint! {
/// ### What it does
/// Detects format!-style macros (e.g. `format!`, `println!`, `write!`) where an argument
/// is passed with an explicit `&` but the value is already a reference, resulting in a
/// double reference (e.g. `&&T`).
///
/// ### Why is this bad?
/// The extra `&` is redundant and can make the code less clear. Format macros take
/// references to the arguments internally, so passing `&x` when `x` is already a
/// reference produces a double reference. The compiler is currently unable to
/// optimize double references, which results in about 6% degradation per call.
///
/// ### Example
/// ```no_run
/// let s: &str = "hello";
/// println!("{}", &s);
/// ```
/// Use instead:
/// ```no_run
/// let s: &str = "hello";
/// println!("{}", s);
/// ```
#[clippy::version = "1.97.0"]
pub USELESS_BORROWS_IN_FORMATTING,
perf,
"redundant reference in format args causes double reference"
}
impl_lint_pass!(FormatArgs<'_> => [
FORMAT_IN_FORMAT_ARGS,
POINTER_FORMAT,
@@ -265,6 +293,7 @@
UNNECESSARY_DEBUG_FORMATTING,
UNNECESSARY_TRAILING_COMMA,
UNUSED_FORMAT_SPECS,
USELESS_BORROWS_IN_FORMATTING,
]);
#[expect(clippy::struct_field_names)]
@@ -363,6 +392,18 @@ fn check_templates(&mut self) {
&& let Some(arg_expr) = find_format_arg_expr(self.expr, arg)
{
self.check_unused_format_specifier(placeholder, arg_expr);
self.check_useless_borrows_in_formatting(placeholder, arg_expr);
// Check width and precision arguments the same way as the value
for opt in [&placeholder.format_options.width, &placeholder.format_options.precision] {
if let Some(FormatCount::Argument(position)) = opt.as_ref()
&& let Ok(pos_index) = position.index
&& let Some(pos_arg) = self.format_args.arguments.all_args().get(pos_index)
&& let Some(pos_arg_expr) = find_format_arg_expr(self.expr, pos_arg)
{
self.check_useless_borrows_in_formatting(placeholder, pos_arg_expr);
}
}
if placeholder.format_trait == FormatTrait::Display
&& placeholder.format_options == FormatOptions::default()
@@ -392,6 +433,43 @@ fn check_templates(&mut self) {
}
}
fn check_useless_borrows_in_formatting(&self, placeholder: &FormatPlaceholder, arg_expr: &Expr<'tcx>) {
if !arg_expr.span.from_expansion()
&& !is_from_proc_macro(self.cx, arg_expr)
&& let Some(fmt_trait) = match placeholder.format_trait {
FormatTrait::Display => self.cx.tcx.get_diagnostic_item(sym::Display),
FormatTrait::Debug => self.cx.tcx.get_diagnostic_item(sym::Debug),
_ => None,
}
&& let Some(sized_trait) = self.cx.tcx.lang_items().sized_trait()
&& let peeled_expr = peel_hir_expr_while(arg_expr, |e| {
// Need to handle `&&&T` to `&T` when a single ref is still required
if let ExprKind::AddrOf(BorrowKind::Ref, _, e) = e.kind
&& let ty = self.cx.typeck_results().expr_ty(e)
&& implements_trait(self.cx, ty, sized_trait, &[])
&& implements_trait(self.cx, ty, fmt_trait, &[])
{
Some(e)
} else {
None
}
})
&& !std::ptr::eq(arg_expr, peeled_expr)
&& let Some(peeled_snippet) = snippet_opt(self.cx, peeled_expr.span)
{
let name = self.cx.tcx.item_name(self.macro_call.def_id);
span_lint_and_sugg(
self.cx,
USELESS_BORROWS_IN_FORMATTING,
arg_expr.span,
format!("redundant reference in `{name}!` argument"),
"remove the redundant `&`",
peeled_snippet,
Applicability::MachineApplicable,
);
}
}
fn check_unused_format_specifier(&self, placeholder: &FormatPlaceholder, arg: &Expr<'_>) {
let options = &placeholder.format_options;
+4 -3
View File
@@ -3,14 +3,15 @@
#![allow(unused_variables, unused_must_use)]
#![allow(
clippy::borrow_deref_ref,
suspicious_double_ref_op,
noop_method_call,
clippy::deref_addrof,
clippy::explicit_auto_deref,
clippy::needless_borrow,
clippy::no_effect,
clippy::useless_borrows_in_formatting,
clippy::uninlined_format_args,
clippy::unnecessary_literal_unwrap,
clippy::deref_addrof
noop_method_call,
suspicious_double_ref_op
)]
use std::ops::{Deref, DerefMut};
+4 -3
View File
@@ -3,14 +3,15 @@
#![allow(unused_variables, unused_must_use)]
#![allow(
clippy::borrow_deref_ref,
suspicious_double_ref_op,
noop_method_call,
clippy::deref_addrof,
clippy::explicit_auto_deref,
clippy::needless_borrow,
clippy::no_effect,
clippy::useless_borrows_in_formatting,
clippy::uninlined_format_args,
clippy::unnecessary_literal_unwrap,
clippy::deref_addrof
noop_method_call,
suspicious_double_ref_op
)]
use std::ops::{Deref, DerefMut};
+13 -13
View File
@@ -1,5 +1,5 @@
error: explicit `deref` method call
--> tests/ui/explicit_deref_methods.rs:58:19
--> tests/ui/explicit_deref_methods.rs:59:19
|
LL | let b: &str = a.deref();
| ^^^^^^^^^ help: try: `&*a`
@@ -8,73 +8,73 @@ LL | let b: &str = a.deref();
= help: to override `-D warnings` add `#[allow(clippy::explicit_deref_methods)]`
error: explicit `deref_mut` method call
--> tests/ui/explicit_deref_methods.rs:61:23
--> tests/ui/explicit_deref_methods.rs:62:23
|
LL | let b: &mut str = a.deref_mut();
| ^^^^^^^^^^^^^ help: try: `&mut **a`
error: explicit `deref` method call
--> tests/ui/explicit_deref_methods.rs:65:39
--> tests/ui/explicit_deref_methods.rs:66:39
|
LL | let b: String = format!("{}, {}", a.deref(), a.deref());
| ^^^^^^^^^ help: try: `&*a`
error: explicit `deref` method call
--> tests/ui/explicit_deref_methods.rs:65:50
--> tests/ui/explicit_deref_methods.rs:66:50
|
LL | let b: String = format!("{}, {}", a.deref(), a.deref());
| ^^^^^^^^^ help: try: `&*a`
error: explicit `deref` method call
--> tests/ui/explicit_deref_methods.rs:69:20
--> tests/ui/explicit_deref_methods.rs:70:20
|
LL | println!("{}", a.deref());
| ^^^^^^^^^ help: try: `&*a`
error: explicit `deref` method call
--> tests/ui/explicit_deref_methods.rs:73:11
--> tests/ui/explicit_deref_methods.rs:74:11
|
LL | match a.deref() {
| ^^^^^^^^^ help: try: `&*a`
error: explicit `deref` method call
--> tests/ui/explicit_deref_methods.rs:78:28
--> tests/ui/explicit_deref_methods.rs:79:28
|
LL | let b: String = concat(a.deref());
| ^^^^^^^^^ help: try: `&*a`
error: explicit `deref` method call
--> tests/ui/explicit_deref_methods.rs:81:13
--> tests/ui/explicit_deref_methods.rs:82:13
|
LL | let b = just_return(a).deref();
| ^^^^^^^^^^^^^^^^^^^^^^ help: try: `just_return(a)`
error: explicit `deref` method call
--> tests/ui/explicit_deref_methods.rs:84:28
--> tests/ui/explicit_deref_methods.rs:85:28
|
LL | let b: String = concat(just_return(a).deref());
| ^^^^^^^^^^^^^^^^^^^^^^ help: try: `just_return(a)`
error: explicit `deref` method call
--> tests/ui/explicit_deref_methods.rs:124:31
--> tests/ui/explicit_deref_methods.rs:125:31
|
LL | let b: &str = expr_deref!(a.deref());
| ^^^^^^^^^ help: try: `&*a`
error: explicit `deref` method call
--> tests/ui/explicit_deref_methods.rs:154:14
--> tests/ui/explicit_deref_methods.rs:155:14
|
LL | let _ = &Deref::deref(&"foo");
| ^^^^^^^^^^^^^^^^^^^^ help: try: `*&"foo"`
error: explicit `deref_mut` method call
--> tests/ui/explicit_deref_methods.rs:156:14
--> tests/ui/explicit_deref_methods.rs:157:14
|
LL | let _ = &DerefMut::deref_mut(&mut x);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut **&mut x`
error: explicit `deref_mut` method call
--> tests/ui/explicit_deref_methods.rs:157:14
--> tests/ui/explicit_deref_methods.rs:158:14
|
LL | let _ = &DerefMut::deref_mut((&mut &mut x).deref_mut());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut ***(&mut &mut x)`
+1
View File
@@ -3,6 +3,7 @@
clippy::borrow_deref_ref,
clippy::deref_addrof,
clippy::inherent_to_string_shadow_display,
clippy::useless_borrows_in_formatting,
clippy::to_string_in_format_args,
clippy::uninlined_format_args
)]
+10 -10
View File
@@ -1,5 +1,5 @@
error: using `self.to_string` in `fmt::Display` implementation will cause infinite recursion
--> tests/ui/recursive_format_impl.rs:31:25
--> tests/ui/recursive_format_impl.rs:32:25
|
LL | write!(f, "{}", self.to_string())
| ^^^^^^^^^^^^^^^^
@@ -8,55 +8,55 @@ LL | write!(f, "{}", self.to_string())
= help: to override `-D warnings` add `#[allow(clippy::recursive_format_impl)]`
error: using `self` as `Display` in `impl Display` will cause infinite recursion
--> tests/ui/recursive_format_impl.rs:76:9
--> tests/ui/recursive_format_impl.rs:77:9
|
LL | write!(f, "{}", self)
| ^^^^^^^^^^^^^^^^^^^^^
error: using `self` as `Display` in `impl Display` will cause infinite recursion
--> tests/ui/recursive_format_impl.rs:86:9
--> tests/ui/recursive_format_impl.rs:87:9
|
LL | write!(f, "{}", &self)
| ^^^^^^^^^^^^^^^^^^^^^^
error: using `self` as `Debug` in `impl Debug` will cause infinite recursion
--> tests/ui/recursive_format_impl.rs:93:9
--> tests/ui/recursive_format_impl.rs:94:9
|
LL | write!(f, "{:?}", &self)
| ^^^^^^^^^^^^^^^^^^^^^^^^
error: using `self` as `Display` in `impl Display` will cause infinite recursion
--> tests/ui/recursive_format_impl.rs:103:9
--> tests/ui/recursive_format_impl.rs:104:9
|
LL | write!(f, "{}", &&&self)
| ^^^^^^^^^^^^^^^^^^^^^^^^
error: using `self` as `Display` in `impl Display` will cause infinite recursion
--> tests/ui/recursive_format_impl.rs:178:9
--> tests/ui/recursive_format_impl.rs:179:9
|
LL | write!(f, "{}", &*self)
| ^^^^^^^^^^^^^^^^^^^^^^^
error: using `self` as `Debug` in `impl Debug` will cause infinite recursion
--> tests/ui/recursive_format_impl.rs:185:9
--> tests/ui/recursive_format_impl.rs:186:9
|
LL | write!(f, "{:?}", &*self)
| ^^^^^^^^^^^^^^^^^^^^^^^^^
error: using `self` as `Display` in `impl Display` will cause infinite recursion
--> tests/ui/recursive_format_impl.rs:202:9
--> tests/ui/recursive_format_impl.rs:203:9
|
LL | write!(f, "{}", *self)
| ^^^^^^^^^^^^^^^^^^^^^^
error: using `self` as `Display` in `impl Display` will cause infinite recursion
--> tests/ui/recursive_format_impl.rs:219:9
--> tests/ui/recursive_format_impl.rs:220:9
|
LL | write!(f, "{}", **&&*self)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
error: using `self` as `Display` in `impl Display` will cause infinite recursion
--> tests/ui/recursive_format_impl.rs:236:9
--> tests/ui/recursive_format_impl.rs:237:9
|
LL | write!(f, "{}", &&**&&*self)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -0,0 +1,118 @@
// When testing or blessing this lint, set TESTNAME so only this test runs:
// TESTNAME=useless_borrows_in_formatting cargo uitest
// TESTNAME=useless_borrows_in_formatting cargo uibless
#![warn(clippy::useless_borrows_in_formatting)]
#![allow(unused, clippy::useless_format)]
fn main() {
let s: &str = "hello";
println!("{}", s); //~ useless_borrows_in_formatting
println!("{:?}", s); //~ useless_borrows_in_formatting
println!("{}", s); //~ useless_borrows_in_formatting
let string = String::from("world");
println!("{}", string); //~ useless_borrows_in_formatting
println!("{:?}", string); //~ useless_borrows_in_formatting
println!("{}", string); //~ useless_borrows_in_formatting
println!("{}", &string[..2]); //~ useless_borrows_in_formatting
println!("{:?}", &string[..2]); //~ useless_borrows_in_formatting
// these are ok
println!("{}", &string[..2]);
println!("{:?}", &string[..2]);
let n: i32 = 42;
println!("{}", n); //~ useless_borrows_in_formatting
println!("{:?}", n); //~ useless_borrows_in_formatting
println!("{}", n); //~ useless_borrows_in_formatting
// Reference to slice element
let slice: [i32; 3] = [1, 2, 3];
println!("{}", slice[0]); //~ useless_borrows_in_formatting
println!("{:?}", slice[0]); //~ useless_borrows_in_formatting
println!("{}", slice[0]); //~ useless_borrows_in_formatting
// big array: should not suggest removing & because of the size of the output
println!(
"{:?}",
[
//~^ useless_borrows_in_formatting
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5,
6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1,
2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
]
);
println!("{:?}", [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0]);
//~^ useless_borrows_in_formatting
let a: [i32; 2] = [1, 2];
println!("{:016x?}", [a[0], a[1], a[0], a[1]]); //~ useless_borrows_in_formatting
// &slice[0..1] with {:?}: inner type [i32] is unsized, so we don't suggest removing &
println!("{:?}", &slice[0..1]); // don't change
println!("{:?}", &slice[0..1]); //~ useless_borrows_in_formatting
// Pointer formatting ({:p}): never suggest any changes to it
let x: i32 = 0;
println!("{:p}", &x); // don't change
println!("{:p}", &&x); // should change, but out of scope
struct Wrap(i32);
let w: Wrap = Wrap(42);
println!("{}", w.0); //~ useless_borrows_in_formatting
println!("{:?}", w.0); //~ useless_borrows_in_formatting
println!("{}", w.0); //~ useless_borrows_in_formatting
struct WrapRef<'a>(&'a i32);
let n: i32 = 42;
let w: WrapRef<'_> = WrapRef(&n);
println!("{}", w.0); //~ useless_borrows_in_formatting
println!("{:?}", w.0); //~ useless_borrows_in_formatting
println!("{}", w.0); //~ useless_borrows_in_formatting
let a: &mut String = &mut String::from("foo");
println!("{}", *a); //~ useless_borrows_in_formatting
println!("{:?}", *a); //~ useless_borrows_in_formatting
// Parenthesized expressions: &(expr)
let n: i32 = 42;
println!("{}", (n)); //~ useless_borrows_in_formatting
println!("{:?}", (n + 1)); //~ useless_borrows_in_formatting
println!("{}", (String::from("paren"))); //~ useless_borrows_in_formatting
// Block expressions: &{ expr }
println!("{}", { n }); //~ useless_borrows_in_formatting
println!("{:?}", { n + 1 }); //~ useless_borrows_in_formatting
println!("{}", { String::from("block") }); //~ useless_borrows_in_formatting
let v1 = 42.12345;
let v2 = 20;
let v3 = 10;
println!("{0:1$.2$}", v1, v2, v3);
//~^ useless_borrows_in_formatting
//~| useless_borrows_in_formatting
//~| useless_borrows_in_formatting
println!("{0:1$.2$?}", v1, v2, v3);
//~^ useless_borrows_in_formatting
//~| useless_borrows_in_formatting
//~| useless_borrows_in_formatting
println!("{0:1$.2$}", v1, v2, v3); //~ useless_borrows_in_formatting
println!("{0:1$.2$}", v1, v2, v3); //~ useless_borrows_in_formatting
println!("{0:1$.2$}", v1, v2, v3); //~ useless_borrows_in_formatting
// Macro wrapping println! - should not lint (println! call is inside macro expansion)
macro_rules! my_println {
($($args:tt)*) => {
println!($($args)*);
};
}
my_println!("{}", &n);
// Arguments coming from a macro - should not lint (& comes from expansion)
macro_rules! make_ref {
($e:expr) => {
&$e
};
}
println!("{}", make_ref!(n));
}
+118
View File
@@ -0,0 +1,118 @@
// When testing or blessing this lint, set TESTNAME so only this test runs:
// TESTNAME=useless_borrows_in_formatting cargo uitest
// TESTNAME=useless_borrows_in_formatting cargo uibless
#![warn(clippy::useless_borrows_in_formatting)]
#![allow(unused, clippy::useless_format)]
fn main() {
let s: &str = "hello";
println!("{}", &s); //~ useless_borrows_in_formatting
println!("{:?}", &s); //~ useless_borrows_in_formatting
println!("{}", &&s); //~ useless_borrows_in_formatting
let string = String::from("world");
println!("{}", &string); //~ useless_borrows_in_formatting
println!("{:?}", &string); //~ useless_borrows_in_formatting
println!("{}", &&string); //~ useless_borrows_in_formatting
println!("{}", &&string[..2]); //~ useless_borrows_in_formatting
println!("{:?}", &&string[..2]); //~ useless_borrows_in_formatting
// these are ok
println!("{}", &string[..2]);
println!("{:?}", &string[..2]);
let n: i32 = 42;
println!("{}", &n); //~ useless_borrows_in_formatting
println!("{:?}", &n); //~ useless_borrows_in_formatting
println!("{}", &&n); //~ useless_borrows_in_formatting
// Reference to slice element
let slice: [i32; 3] = [1, 2, 3];
println!("{}", &slice[0]); //~ useless_borrows_in_formatting
println!("{:?}", &slice[0]); //~ useless_borrows_in_formatting
println!("{}", &&slice[0]); //~ useless_borrows_in_formatting
// big array: should not suggest removing & because of the size of the output
println!(
"{:?}",
&[
//~^ useless_borrows_in_formatting
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5,
6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1,
2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
]
);
println!("{:?}", &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0]);
//~^ useless_borrows_in_formatting
let a: [i32; 2] = [1, 2];
println!("{:016x?}", &[a[0], a[1], a[0], a[1]]); //~ useless_borrows_in_formatting
// &slice[0..1] with {:?}: inner type [i32] is unsized, so we don't suggest removing &
println!("{:?}", &slice[0..1]); // don't change
println!("{:?}", &&slice[0..1]); //~ useless_borrows_in_formatting
// Pointer formatting ({:p}): never suggest any changes to it
let x: i32 = 0;
println!("{:p}", &x); // don't change
println!("{:p}", &&x); // should change, but out of scope
struct Wrap(i32);
let w: Wrap = Wrap(42);
println!("{}", &w.0); //~ useless_borrows_in_formatting
println!("{:?}", &w.0); //~ useless_borrows_in_formatting
println!("{}", &&w.0); //~ useless_borrows_in_formatting
struct WrapRef<'a>(&'a i32);
let n: i32 = 42;
let w: WrapRef<'_> = WrapRef(&n);
println!("{}", &w.0); //~ useless_borrows_in_formatting
println!("{:?}", &w.0); //~ useless_borrows_in_formatting
println!("{}", &&w.0); //~ useless_borrows_in_formatting
let a: &mut String = &mut String::from("foo");
println!("{}", &*a); //~ useless_borrows_in_formatting
println!("{:?}", &*a); //~ useless_borrows_in_formatting
// Parenthesized expressions: &(expr)
let n: i32 = 42;
println!("{}", &(n)); //~ useless_borrows_in_formatting
println!("{:?}", &(n + 1)); //~ useless_borrows_in_formatting
println!("{}", &(String::from("paren"))); //~ useless_borrows_in_formatting
// Block expressions: &{ expr }
println!("{}", &{ n }); //~ useless_borrows_in_formatting
println!("{:?}", &{ n + 1 }); //~ useless_borrows_in_formatting
println!("{}", &{ String::from("block") }); //~ useless_borrows_in_formatting
let v1 = 42.12345;
let v2 = 20;
let v3 = 10;
println!("{0:1$.2$}", &v1, &v2, &v3);
//~^ useless_borrows_in_formatting
//~| useless_borrows_in_formatting
//~| useless_borrows_in_formatting
println!("{0:1$.2$?}", &v1, &v2, &v3);
//~^ useless_borrows_in_formatting
//~| useless_borrows_in_formatting
//~| useless_borrows_in_formatting
println!("{0:1$.2$}", &v1, v2, v3); //~ useless_borrows_in_formatting
println!("{0:1$.2$}", v1, &v2, v3); //~ useless_borrows_in_formatting
println!("{0:1$.2$}", v1, v2, &v3); //~ useless_borrows_in_formatting
// Macro wrapping println! - should not lint (println! call is inside macro expansion)
macro_rules! my_println {
($($args:tt)*) => {
println!($($args)*);
};
}
my_println!("{}", &n);
// Arguments coming from a macro - should not lint (& comes from expansion)
macro_rules! make_ref {
($e:expr) => {
&$e
};
}
println!("{}", make_ref!(n));
}
@@ -0,0 +1,266 @@
error: redundant reference in `println!` argument
--> tests/ui/useless_borrows_in_formatting.rs:9:20
|
LL | println!("{}", &s);
| ^^ help: remove the redundant `&`: `s`
|
= note: `-D clippy::useless-borrows-in-formatting` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::useless_borrows_in_formatting)]`
error: redundant reference in `println!` argument
--> tests/ui/useless_borrows_in_formatting.rs:10:22
|
LL | println!("{:?}", &s);
| ^^ help: remove the redundant `&`: `s`
error: redundant reference in `println!` argument
--> tests/ui/useless_borrows_in_formatting.rs:11:20
|
LL | println!("{}", &&s);
| ^^^ help: remove the redundant `&`: `s`
error: redundant reference in `println!` argument
--> tests/ui/useless_borrows_in_formatting.rs:14:20
|
LL | println!("{}", &string);
| ^^^^^^^ help: remove the redundant `&`: `string`
error: redundant reference in `println!` argument
--> tests/ui/useless_borrows_in_formatting.rs:15:22
|
LL | println!("{:?}", &string);
| ^^^^^^^ help: remove the redundant `&`: `string`
error: redundant reference in `println!` argument
--> tests/ui/useless_borrows_in_formatting.rs:16:20
|
LL | println!("{}", &&string);
| ^^^^^^^^ help: remove the redundant `&`: `string`
error: redundant reference in `println!` argument
--> tests/ui/useless_borrows_in_formatting.rs:17:20
|
LL | println!("{}", &&string[..2]);
| ^^^^^^^^^^^^^ help: remove the redundant `&`: `&string[..2]`
error: redundant reference in `println!` argument
--> tests/ui/useless_borrows_in_formatting.rs:18:22
|
LL | println!("{:?}", &&string[..2]);
| ^^^^^^^^^^^^^ help: remove the redundant `&`: `&string[..2]`
error: redundant reference in `println!` argument
--> tests/ui/useless_borrows_in_formatting.rs:24:20
|
LL | println!("{}", &n);
| ^^ help: remove the redundant `&`: `n`
error: redundant reference in `println!` argument
--> tests/ui/useless_borrows_in_formatting.rs:25:22
|
LL | println!("{:?}", &n);
| ^^ help: remove the redundant `&`: `n`
error: redundant reference in `println!` argument
--> tests/ui/useless_borrows_in_formatting.rs:26:20
|
LL | println!("{}", &&n);
| ^^^ help: remove the redundant `&`: `n`
error: redundant reference in `println!` argument
--> tests/ui/useless_borrows_in_formatting.rs:30:20
|
LL | println!("{}", &slice[0]);
| ^^^^^^^^^ help: remove the redundant `&`: `slice[0]`
error: redundant reference in `println!` argument
--> tests/ui/useless_borrows_in_formatting.rs:31:22
|
LL | println!("{:?}", &slice[0]);
| ^^^^^^^^^ help: remove the redundant `&`: `slice[0]`
error: redundant reference in `println!` argument
--> tests/ui/useless_borrows_in_formatting.rs:32:20
|
LL | println!("{}", &&slice[0]);
| ^^^^^^^^^^ help: remove the redundant `&`: `slice[0]`
error: redundant reference in `println!` argument
--> tests/ui/useless_borrows_in_formatting.rs:37:9
|
LL | / &[
LL | |
LL | | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5,
LL | | 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1,
LL | | 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
LL | | ]
| |_________^
|
help: remove the redundant `&`
|
LL ~ [
LL +
LL + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5,
LL + 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1,
LL + 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
LL + ]
|
error: redundant reference in `println!` argument
--> tests/ui/useless_borrows_in_formatting.rs:45:22
|
LL | println!("{:?}", &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the redundant `&`: `[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0]`
error: redundant reference in `println!` argument
--> tests/ui/useless_borrows_in_formatting.rs:49:26
|
LL | println!("{:016x?}", &[a[0], a[1], a[0], a[1]]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the redundant `&`: `[a[0], a[1], a[0], a[1]]`
error: redundant reference in `println!` argument
--> tests/ui/useless_borrows_in_formatting.rs:53:22
|
LL | println!("{:?}", &&slice[0..1]);
| ^^^^^^^^^^^^^ help: remove the redundant `&`: `&slice[0..1]`
error: redundant reference in `println!` argument
--> tests/ui/useless_borrows_in_formatting.rs:62:20
|
LL | println!("{}", &w.0);
| ^^^^ help: remove the redundant `&`: `w.0`
error: redundant reference in `println!` argument
--> tests/ui/useless_borrows_in_formatting.rs:63:22
|
LL | println!("{:?}", &w.0);
| ^^^^ help: remove the redundant `&`: `w.0`
error: redundant reference in `println!` argument
--> tests/ui/useless_borrows_in_formatting.rs:64:20
|
LL | println!("{}", &&w.0);
| ^^^^^ help: remove the redundant `&`: `w.0`
error: redundant reference in `println!` argument
--> tests/ui/useless_borrows_in_formatting.rs:69:20
|
LL | println!("{}", &w.0);
| ^^^^ help: remove the redundant `&`: `w.0`
error: redundant reference in `println!` argument
--> tests/ui/useless_borrows_in_formatting.rs:70:22
|
LL | println!("{:?}", &w.0);
| ^^^^ help: remove the redundant `&`: `w.0`
error: redundant reference in `println!` argument
--> tests/ui/useless_borrows_in_formatting.rs:71:20
|
LL | println!("{}", &&w.0);
| ^^^^^ help: remove the redundant `&`: `w.0`
error: redundant reference in `println!` argument
--> tests/ui/useless_borrows_in_formatting.rs:74:20
|
LL | println!("{}", &*a);
| ^^^ help: remove the redundant `&`: `*a`
error: redundant reference in `println!` argument
--> tests/ui/useless_borrows_in_formatting.rs:75:22
|
LL | println!("{:?}", &*a);
| ^^^ help: remove the redundant `&`: `*a`
error: redundant reference in `println!` argument
--> tests/ui/useless_borrows_in_formatting.rs:79:20
|
LL | println!("{}", &(n));
| ^^^^ help: remove the redundant `&`: `(n)`
error: redundant reference in `println!` argument
--> tests/ui/useless_borrows_in_formatting.rs:80:22
|
LL | println!("{:?}", &(n + 1));
| ^^^^^^^^ help: remove the redundant `&`: `(n + 1)`
error: redundant reference in `println!` argument
--> tests/ui/useless_borrows_in_formatting.rs:81:20
|
LL | println!("{}", &(String::from("paren")));
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the redundant `&`: `(String::from("paren"))`
error: redundant reference in `println!` argument
--> tests/ui/useless_borrows_in_formatting.rs:84:20
|
LL | println!("{}", &{ n });
| ^^^^^^ help: remove the redundant `&`: `{ n }`
error: redundant reference in `println!` argument
--> tests/ui/useless_borrows_in_formatting.rs:85:22
|
LL | println!("{:?}", &{ n + 1 });
| ^^^^^^^^^^ help: remove the redundant `&`: `{ n + 1 }`
error: redundant reference in `println!` argument
--> tests/ui/useless_borrows_in_formatting.rs:86:20
|
LL | println!("{}", &{ String::from("block") });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the redundant `&`: `{ String::from("block") }`
error: redundant reference in `println!` argument
--> tests/ui/useless_borrows_in_formatting.rs:91:27
|
LL | println!("{0:1$.2$}", &v1, &v2, &v3);
| ^^^ help: remove the redundant `&`: `v1`
error: redundant reference in `println!` argument
--> tests/ui/useless_borrows_in_formatting.rs:91:32
|
LL | println!("{0:1$.2$}", &v1, &v2, &v3);
| ^^^ help: remove the redundant `&`: `v2`
error: redundant reference in `println!` argument
--> tests/ui/useless_borrows_in_formatting.rs:91:37
|
LL | println!("{0:1$.2$}", &v1, &v2, &v3);
| ^^^ help: remove the redundant `&`: `v3`
error: redundant reference in `println!` argument
--> tests/ui/useless_borrows_in_formatting.rs:95:28
|
LL | println!("{0:1$.2$?}", &v1, &v2, &v3);
| ^^^ help: remove the redundant `&`: `v1`
error: redundant reference in `println!` argument
--> tests/ui/useless_borrows_in_formatting.rs:95:33
|
LL | println!("{0:1$.2$?}", &v1, &v2, &v3);
| ^^^ help: remove the redundant `&`: `v2`
error: redundant reference in `println!` argument
--> tests/ui/useless_borrows_in_formatting.rs:95:38
|
LL | println!("{0:1$.2$?}", &v1, &v2, &v3);
| ^^^ help: remove the redundant `&`: `v3`
error: redundant reference in `println!` argument
--> tests/ui/useless_borrows_in_formatting.rs:99:27
|
LL | println!("{0:1$.2$}", &v1, v2, v3);
| ^^^ help: remove the redundant `&`: `v1`
error: redundant reference in `println!` argument
--> tests/ui/useless_borrows_in_formatting.rs:100:31
|
LL | println!("{0:1$.2$}", v1, &v2, v3);
| ^^^ help: remove the redundant `&`: `v2`
error: redundant reference in `println!` argument
--> tests/ui/useless_borrows_in_formatting.rs:101:35
|
LL | println!("{0:1$.2$}", v1, v2, &v3);
| ^^^ help: remove the redundant `&`: `v3`
error: aborting due to 41 previous errors