mirror of
https://github.com/rust-lang/rust.git
synced 2026-05-22 10:05:06 +03:00
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:
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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};
|
||||
|
||||
@@ -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};
|
||||
|
||||
@@ -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)`
|
||||
|
||||
@@ -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
|
||||
)]
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user