mirror of
https://github.com/rust-lang/rust-clippy
synced 2024-11-23 05:03:21 +00:00
Add format_in_format_args
and to_string_in_format_args
lints
Fixes #7667 and #7729
This commit is contained in:
parent
4996e17b14
commit
c9599d79a3
14 changed files with 908 additions and 49 deletions
|
@ -2736,6 +2736,7 @@ Released 2018-09-13
|
|||
[`for_loops_over_fallibles`]: https://rust-lang.github.io/rust-clippy/master/index.html#for_loops_over_fallibles
|
||||
[`forget_copy`]: https://rust-lang.github.io/rust-clippy/master/index.html#forget_copy
|
||||
[`forget_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#forget_ref
|
||||
[`format_in_format_args`]: https://rust-lang.github.io/rust-clippy/master/index.html#format_in_format_args
|
||||
[`from_iter_instead_of_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#from_iter_instead_of_collect
|
||||
[`from_over_into`]: https://rust-lang.github.io/rust-clippy/master/index.html#from_over_into
|
||||
[`from_str_radix_10`]: https://rust-lang.github.io/rust-clippy/master/index.html#from_str_radix_10
|
||||
|
@ -3015,6 +3016,7 @@ Released 2018-09-13
|
|||
[`temporary_assignment`]: https://rust-lang.github.io/rust-clippy/master/index.html#temporary_assignment
|
||||
[`to_digit_is_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_digit_is_some
|
||||
[`to_string_in_display`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_string_in_display
|
||||
[`to_string_in_format_args`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_string_in_format_args
|
||||
[`todo`]: https://rust-lang.github.io/rust-clippy/master/index.html#todo
|
||||
[`too_many_arguments`]: https://rust-lang.github.io/rust-clippy/master/index.html#too_many_arguments
|
||||
[`too_many_lines`]: https://rust-lang.github.io/rust-clippy/master/index.html#too_many_lines
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::higher::FormatExpn;
|
||||
use clippy_utils::last_path_segment;
|
||||
use clippy_utils::source::{snippet_opt, snippet_with_applicability};
|
||||
use clippy_utils::sugg::Sugg;
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{BorrowKind, Expr, ExprKind, QPath};
|
||||
use rustc_hir::{Expr, ExprKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::ty;
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
|
@ -69,8 +68,8 @@ impl<'tcx> LateLintPass<'tcx> for UselessFormat {
|
|||
ty::Str => true,
|
||||
_ => false,
|
||||
};
|
||||
if format_args.args.iter().all(is_display_arg);
|
||||
if format_args.fmt_expr.map_or(true, check_unformatted);
|
||||
if let Some(args) = format_args.args();
|
||||
if args.iter().all(|arg| arg.is_display() && !arg.has_string_formatting());
|
||||
then {
|
||||
let is_new_string = match value.kind {
|
||||
ExprKind::Binary(..) => true,
|
||||
|
@ -106,47 +105,3 @@ fn span_useless_format(cx: &LateContext<'_>, span: Span, mut sugg: String, mut a
|
|||
applicability,
|
||||
);
|
||||
}
|
||||
|
||||
fn is_display_arg(expr: &Expr<'_>) -> bool {
|
||||
if_chain! {
|
||||
if let ExprKind::Call(_, [_, fmt]) = expr.kind;
|
||||
if let ExprKind::Path(QPath::Resolved(_, path)) = fmt.kind;
|
||||
if let [.., t, _] = path.segments;
|
||||
if t.ident.name == sym::Display;
|
||||
then { true } else { false }
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks if the expression matches
|
||||
/// ```rust,ignore
|
||||
/// &[_ {
|
||||
/// format: _ {
|
||||
/// width: _::Implied,
|
||||
/// precision: _::Implied,
|
||||
/// ...
|
||||
/// },
|
||||
/// ...,
|
||||
/// }]
|
||||
/// ```
|
||||
fn check_unformatted(expr: &Expr<'_>) -> bool {
|
||||
if_chain! {
|
||||
if let ExprKind::AddrOf(BorrowKind::Ref, _, expr) = expr.kind;
|
||||
if let ExprKind::Array([expr]) = expr.kind;
|
||||
// struct `core::fmt::rt::v1::Argument`
|
||||
if let ExprKind::Struct(_, fields, _) = expr.kind;
|
||||
if let Some(format_field) = fields.iter().find(|f| f.ident.name == sym::format);
|
||||
// struct `core::fmt::rt::v1::FormatSpec`
|
||||
if let ExprKind::Struct(_, fields, _) = format_field.expr.kind;
|
||||
if let Some(precision_field) = fields.iter().find(|f| f.ident.name == sym::precision);
|
||||
if let ExprKind::Path(ref precision_path) = precision_field.expr.kind;
|
||||
if last_path_segment(precision_path).ident.name == sym::Implied;
|
||||
if let Some(width_field) = fields.iter().find(|f| f.ident.name == sym::width);
|
||||
if let ExprKind::Path(ref width_qpath) = width_field.expr.kind;
|
||||
if last_path_segment(width_qpath).ident.name == sym::Implied;
|
||||
then {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
|
223
clippy_lints/src/format_args.rs
Normal file
223
clippy_lints/src/format_args.rs
Normal file
|
@ -0,0 +1,223 @@
|
|||
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
|
||||
use clippy_utils::higher::{FormatArgsArg, FormatArgsExpn, FormatExpn};
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use clippy_utils::ty::implements_trait;
|
||||
use clippy_utils::{is_diag_trait_item, match_def_path, paths};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Expr, ExprKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::ty::adjustment::{Adjust, Adjustment};
|
||||
use rustc_middle::ty::Ty;
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::{sym, BytePos, ExpnData, ExpnKind, Span, Symbol};
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Detects `format!` within the arguments of another macro that does
|
||||
/// formatting such as `format!` itself, `write!` or `println!`. Suggests
|
||||
/// inlining the `format!` call.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// The recommended code is both shorter and avoids a temporary allocation.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```rust
|
||||
/// # use std::panic::Location;
|
||||
/// println!("error: {}", format!("something failed at {}", Location::caller()));
|
||||
/// ```
|
||||
/// Use instead:
|
||||
/// ```rust
|
||||
/// # use std::panic::Location;
|
||||
/// println!("error: something failed at {}", Location::caller());
|
||||
/// ```
|
||||
pub FORMAT_IN_FORMAT_ARGS,
|
||||
perf,
|
||||
"`format!` used in a macro that does formatting"
|
||||
}
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Checks for [`ToString::to_string`](https://doc.rust-lang.org/std/string/trait.ToString.html#tymethod.to_string)
|
||||
/// applied to a type that implements [`Display`](https://doc.rust-lang.org/std/fmt/trait.Display.html)
|
||||
/// in a macro that does formatting.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// Since the type implements `Display`, the use of `to_string` is
|
||||
/// unnecessary.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```rust
|
||||
/// # use std::panic::Location;
|
||||
/// println!("error: something failed at {}", Location::caller().to_string());
|
||||
/// ```
|
||||
/// Use instead:
|
||||
/// ```rust
|
||||
/// # use std::panic::Location;
|
||||
/// println!("error: something failed at {}", Location::caller());
|
||||
/// ```
|
||||
pub TO_STRING_IN_FORMAT_ARGS,
|
||||
perf,
|
||||
"`to_string` applied to a type that implements `Display` in format args"
|
||||
}
|
||||
|
||||
declare_lint_pass!(FormatArgs => [FORMAT_IN_FORMAT_ARGS, TO_STRING_IN_FORMAT_ARGS]);
|
||||
|
||||
const FORMAT_MACRO_PATHS: &[&[&str]] = &[
|
||||
&paths::FORMAT_ARGS_MACRO,
|
||||
&paths::ASSERT_EQ_MACRO,
|
||||
&paths::ASSERT_MACRO,
|
||||
&paths::ASSERT_NE_MACRO,
|
||||
&paths::EPRINT_MACRO,
|
||||
&paths::EPRINTLN_MACRO,
|
||||
&paths::PRINT_MACRO,
|
||||
&paths::PRINTLN_MACRO,
|
||||
&paths::WRITE_MACRO,
|
||||
&paths::WRITELN_MACRO,
|
||||
];
|
||||
|
||||
const FORMAT_MACRO_DIAG_ITEMS: &[Symbol] = &[sym::format_macro, sym::std_panic_macro];
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for FormatArgs {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
|
||||
if_chain! {
|
||||
if let Some(format_args) = FormatArgsExpn::parse(expr);
|
||||
let expr_expn_data = expr.span.ctxt().outer_expn_data();
|
||||
let outermost_expn_data = outermost_expn_data(expr_expn_data);
|
||||
if let Some(macro_def_id) = outermost_expn_data.macro_def_id;
|
||||
if FORMAT_MACRO_PATHS
|
||||
.iter()
|
||||
.any(|path| match_def_path(cx, macro_def_id, path))
|
||||
|| FORMAT_MACRO_DIAG_ITEMS
|
||||
.iter()
|
||||
.any(|diag_item| cx.tcx.is_diagnostic_item(*diag_item, macro_def_id));
|
||||
if let ExpnKind::Macro(_, name) = outermost_expn_data.kind;
|
||||
if let Some(args) = format_args.args();
|
||||
then {
|
||||
for (i, arg) in args.iter().enumerate() {
|
||||
if !arg.is_display() {
|
||||
continue;
|
||||
}
|
||||
if arg.has_string_formatting() {
|
||||
continue;
|
||||
}
|
||||
if is_aliased(&args, i) {
|
||||
continue;
|
||||
}
|
||||
check_format_in_format_args(cx, outermost_expn_data.call_site, name, arg);
|
||||
check_to_string_in_format_args(cx, name, arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn outermost_expn_data(expn_data: ExpnData) -> ExpnData {
|
||||
if expn_data.call_site.from_expansion() {
|
||||
outermost_expn_data(expn_data.call_site.ctxt().outer_expn_data())
|
||||
} else {
|
||||
expn_data
|
||||
}
|
||||
}
|
||||
|
||||
fn check_format_in_format_args(cx: &LateContext<'_>, call_site: Span, name: Symbol, arg: &FormatArgsArg<'_>) {
|
||||
if_chain! {
|
||||
if FormatExpn::parse(arg.value).is_some();
|
||||
if !arg.value.span.ctxt().outer_expn_data().call_site.from_expansion();
|
||||
then {
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
FORMAT_IN_FORMAT_ARGS,
|
||||
trim_semicolon(cx, call_site),
|
||||
&format!("`format!` in `{}!` args", name),
|
||||
|diag| {
|
||||
diag.help(&format!(
|
||||
"combine the `format!(..)` arguments with the outer `{}!(..)` call",
|
||||
name
|
||||
));
|
||||
diag.help("or consider changing `format!` to `format_args!`");
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_to_string_in_format_args<'tcx>(cx: &LateContext<'tcx>, name: Symbol, arg: &FormatArgsArg<'tcx>) {
|
||||
let value = arg.value;
|
||||
if_chain! {
|
||||
if !value.span.from_expansion();
|
||||
if let ExprKind::MethodCall(_, _, [receiver], _) = value.kind;
|
||||
if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(value.hir_id);
|
||||
if is_diag_trait_item(cx, method_def_id, sym::ToString);
|
||||
let receiver_ty = cx.typeck_results().expr_ty(receiver);
|
||||
if let Some(display_trait_id) = cx.tcx.get_diagnostic_item(sym::Display);
|
||||
if let Some(receiver_snippet) = snippet_opt(cx, receiver.span);
|
||||
then {
|
||||
let (n_needed_derefs, target) = count_needed_derefs(
|
||||
receiver_ty,
|
||||
cx.typeck_results().expr_adjustments(receiver).iter(),
|
||||
);
|
||||
if implements_trait(cx, target, display_trait_id, &[]) {
|
||||
if n_needed_derefs == 0 {
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
TO_STRING_IN_FORMAT_ARGS,
|
||||
value.span.with_lo(receiver.span.hi()),
|
||||
&format!("`to_string` applied to a type that implements `Display` in `{}!` args", name),
|
||||
"remove this",
|
||||
String::new(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
} else {
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
TO_STRING_IN_FORMAT_ARGS,
|
||||
value.span,
|
||||
&format!("`to_string` applied to a type that implements `Display` in `{}!` args", name),
|
||||
"use this",
|
||||
format!("{:*>width$}{}", "", receiver_snippet, width = n_needed_derefs),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Returns true if `args[i]` "refers to" or "is referred to by" another argument.
|
||||
fn is_aliased(args: &[FormatArgsArg<'_>], i: usize) -> bool {
|
||||
let value = args[i].value;
|
||||
args.iter()
|
||||
.enumerate()
|
||||
.any(|(j, arg)| i != j && std::ptr::eq(value, arg.value))
|
||||
}
|
||||
|
||||
fn trim_semicolon(cx: &LateContext<'_>, span: Span) -> Span {
|
||||
snippet_opt(cx, span).map_or(span, |snippet| {
|
||||
let snippet = snippet.trim_end_matches(';');
|
||||
span.with_hi(span.lo() + BytePos(u32::try_from(snippet.len()).unwrap()))
|
||||
})
|
||||
}
|
||||
|
||||
fn count_needed_derefs<'tcx, I>(mut ty: Ty<'tcx>, mut iter: I) -> (usize, Ty<'tcx>)
|
||||
where
|
||||
I: Iterator<Item = &'tcx Adjustment<'tcx>>,
|
||||
{
|
||||
let mut n_total = 0;
|
||||
let mut n_needed = 0;
|
||||
loop {
|
||||
if let Some(Adjustment {
|
||||
kind: Adjust::Deref(overloaded_deref),
|
||||
target,
|
||||
}) = iter.next()
|
||||
{
|
||||
n_total += 1;
|
||||
if overloaded_deref.is_some() {
|
||||
n_needed = n_total;
|
||||
}
|
||||
ty = target;
|
||||
} else {
|
||||
return (n_needed, ty);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -60,6 +60,8 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
|
|||
LintId::of(float_equality_without_abs::FLOAT_EQUALITY_WITHOUT_ABS),
|
||||
LintId::of(float_literal::EXCESSIVE_PRECISION),
|
||||
LintId::of(format::USELESS_FORMAT),
|
||||
LintId::of(format_args::FORMAT_IN_FORMAT_ARGS),
|
||||
LintId::of(format_args::TO_STRING_IN_FORMAT_ARGS),
|
||||
LintId::of(formatting::POSSIBLE_MISSING_COMMA),
|
||||
LintId::of(formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING),
|
||||
LintId::of(formatting::SUSPICIOUS_ELSE_FORMATTING),
|
||||
|
|
|
@ -139,6 +139,8 @@ store.register_lints(&[
|
|||
floating_point_arithmetic::IMPRECISE_FLOPS,
|
||||
floating_point_arithmetic::SUBOPTIMAL_FLOPS,
|
||||
format::USELESS_FORMAT,
|
||||
format_args::FORMAT_IN_FORMAT_ARGS,
|
||||
format_args::TO_STRING_IN_FORMAT_ARGS,
|
||||
formatting::POSSIBLE_MISSING_COMMA,
|
||||
formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING,
|
||||
formatting::SUSPICIOUS_ELSE_FORMATTING,
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
store.register_group(true, "clippy::perf", Some("clippy_perf"), vec![
|
||||
LintId::of(entry::MAP_ENTRY),
|
||||
LintId::of(escape::BOXED_LOCAL),
|
||||
LintId::of(format_args::FORMAT_IN_FORMAT_ARGS),
|
||||
LintId::of(format_args::TO_STRING_IN_FORMAT_ARGS),
|
||||
LintId::of(large_const_arrays::LARGE_CONST_ARRAYS),
|
||||
LintId::of(large_enum_variant::LARGE_ENUM_VARIANT),
|
||||
LintId::of(loops::MANUAL_MEMCPY),
|
||||
|
|
|
@ -218,6 +218,7 @@ mod float_equality_without_abs;
|
|||
mod float_literal;
|
||||
mod floating_point_arithmetic;
|
||||
mod format;
|
||||
mod format_args;
|
||||
mod formatting;
|
||||
mod from_over_into;
|
||||
mod from_str_radix_10;
|
||||
|
@ -775,6 +776,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
store.register_late_pass(move || Box::new(non_send_fields_in_send_ty::NonSendFieldInSendTy::new(enable_raw_pointer_heuristic_for_send)));
|
||||
store.register_late_pass(move || Box::new(undocumented_unsafe_blocks::UndocumentedUnsafeBlocks::default()));
|
||||
store.register_late_pass(|| Box::new(match_str_case_mismatch::MatchStrCaseMismatch));
|
||||
store.register_late_pass(move || Box::new(format_args::FormatArgs));
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
#![deny(clippy::missing_docs_in_private_items)]
|
||||
|
||||
use crate::ty::is_type_diagnostic_item;
|
||||
use crate::{is_expn_of, match_def_path, paths};
|
||||
use crate::{is_expn_of, last_path_segment, match_def_path, paths};
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::ast::{self, LitKind};
|
||||
use rustc_hir as hir;
|
||||
|
@ -572,6 +572,106 @@ impl FormatArgsExpn<'tcx> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a vector of `FormatArgsArg`.
|
||||
pub fn args(&self) -> Option<Vec<FormatArgsArg<'tcx>>> {
|
||||
if let Some(expr) = self.fmt_expr {
|
||||
if_chain! {
|
||||
if let ExprKind::AddrOf(BorrowKind::Ref, _, expr) = expr.kind;
|
||||
if let ExprKind::Array(exprs) = expr.kind;
|
||||
then {
|
||||
exprs.iter().map(|fmt| {
|
||||
if_chain! {
|
||||
// struct `core::fmt::rt::v1::Argument`
|
||||
if let ExprKind::Struct(_, fields, _) = fmt.kind;
|
||||
if let Some(position_field) = fields.iter().find(|f| f.ident.name == sym::position);
|
||||
if let ExprKind::Lit(lit) = &position_field.expr.kind;
|
||||
if let LitKind::Int(position, _) = lit.node;
|
||||
then {
|
||||
let i = usize::try_from(position).unwrap();
|
||||
Some(FormatArgsArg { value: self.value_args[i], arg: &self.args[i], fmt: Some(fmt) })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}).collect()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Some(
|
||||
self.value_args
|
||||
.iter()
|
||||
.zip(self.args.iter())
|
||||
.map(|(value, arg)| FormatArgsArg { value, arg, fmt: None })
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Type representing a `FormatArgsExpn`'s format arguments
|
||||
pub struct FormatArgsArg<'tcx> {
|
||||
/// An element of `value_args` according to `position`
|
||||
pub value: &'tcx Expr<'tcx>,
|
||||
/// An element of `args` according to `position`
|
||||
pub arg: &'tcx Expr<'tcx>,
|
||||
/// An element of `fmt_expn`
|
||||
pub fmt: Option<&'tcx Expr<'tcx>>,
|
||||
}
|
||||
|
||||
impl<'tcx> FormatArgsArg<'tcx> {
|
||||
/// Returns true if any formatting parameters are used that would have an effect on strings,
|
||||
/// like `{:+2}` instead of just `{}`.
|
||||
pub fn has_string_formatting(&self) -> bool {
|
||||
self.fmt.map_or(false, |fmt| {
|
||||
// `!` because these conditions check that `self` is unformatted.
|
||||
!if_chain! {
|
||||
// struct `core::fmt::rt::v1::Argument`
|
||||
if let ExprKind::Struct(_, fields, _) = fmt.kind;
|
||||
if let Some(format_field) = fields.iter().find(|f| f.ident.name == sym::format);
|
||||
// struct `core::fmt::rt::v1::FormatSpec`
|
||||
if let ExprKind::Struct(_, subfields, _) = format_field.expr.kind;
|
||||
let mut precision_found = false;
|
||||
let mut width_found = false;
|
||||
if subfields.iter().all(|field| {
|
||||
match field.ident.name {
|
||||
sym::precision => {
|
||||
precision_found = true;
|
||||
if let ExprKind::Path(ref precision_path) = field.expr.kind {
|
||||
last_path_segment(precision_path).ident.name == sym::Implied
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
sym::width => {
|
||||
width_found = true;
|
||||
if let ExprKind::Path(ref width_qpath) = field.expr.kind {
|
||||
last_path_segment(width_qpath).ident.name == sym::Implied
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
_ => true,
|
||||
}
|
||||
});
|
||||
if precision_found && width_found;
|
||||
then { true } else { false }
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns true if the argument is formatted using `Display::fmt`.
|
||||
pub fn is_display(&self) -> bool {
|
||||
if_chain! {
|
||||
if let ExprKind::Call(_, [_, format_field]) = self.arg.kind;
|
||||
if let ExprKind::Path(QPath::Resolved(_, path)) = format_field.kind;
|
||||
if let [.., t, _] = path.segments;
|
||||
if t.ident.name == sym::Display;
|
||||
then { true } else { false }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks if a `let` statement is from a `for` loop desugaring.
|
||||
|
|
|
@ -17,6 +17,12 @@ pub const APPLICABILITY_VALUES: [[&str; 3]; 4] = [
|
|||
#[cfg(feature = "metadata-collector-lint")]
|
||||
pub const DIAGNOSTIC_BUILDER: [&str; 3] = ["rustc_errors", "diagnostic_builder", "DiagnosticBuilder"];
|
||||
pub const ARC_PTR_EQ: [&str; 4] = ["alloc", "sync", "Arc", "ptr_eq"];
|
||||
#[allow(clippy::invalid_paths)] // `check_path` does not seem to work for macros
|
||||
pub const ASSERT_EQ_MACRO: [&str; 3] = ["core", "macros", "assert_eq"];
|
||||
#[allow(clippy::invalid_paths)] // `check_path` does not seem to work for macros
|
||||
pub const ASSERT_MACRO: [&str; 4] = ["core", "macros", "builtin", "assert"];
|
||||
#[allow(clippy::invalid_paths)] // `check_path` does not seem to work for macros
|
||||
pub const ASSERT_NE_MACRO: [&str; 3] = ["core", "macros", "assert_ne"];
|
||||
pub const ASMUT_TRAIT: [&str; 3] = ["core", "convert", "AsMut"];
|
||||
pub const ASREF_TRAIT: [&str; 3] = ["core", "convert", "AsRef"];
|
||||
pub(super) const BEGIN_PANIC: [&str; 3] = ["std", "panicking", "begin_panic"];
|
||||
|
@ -42,11 +48,17 @@ pub const DROP: [&str; 3] = ["core", "mem", "drop"];
|
|||
pub const DURATION: [&str; 3] = ["core", "time", "Duration"];
|
||||
#[cfg(feature = "internal-lints")]
|
||||
pub const EARLY_CONTEXT: [&str; 2] = ["rustc_lint", "EarlyContext"];
|
||||
#[allow(clippy::invalid_paths)] // `check_path` does not seem to work for macros
|
||||
pub const EPRINT_MACRO: [&str; 3] = ["std", "macros", "eprint"];
|
||||
#[allow(clippy::invalid_paths)] // `check_path` does not seem to work for macros
|
||||
pub const EPRINTLN_MACRO: [&str; 3] = ["std", "macros", "eprintln"];
|
||||
pub const EXIT: [&str; 3] = ["std", "process", "exit"];
|
||||
pub const F32_EPSILON: [&str; 4] = ["core", "f32", "<impl f32>", "EPSILON"];
|
||||
pub const F64_EPSILON: [&str; 4] = ["core", "f64", "<impl f64>", "EPSILON"];
|
||||
pub const FILE: [&str; 3] = ["std", "fs", "File"];
|
||||
pub const FILE_TYPE: [&str; 3] = ["std", "fs", "FileType"];
|
||||
#[allow(clippy::invalid_paths)] // `check_path` does not seem to work for macros
|
||||
pub const FORMAT_ARGS_MACRO: [&str; 4] = ["core", "macros", "builtin", "format_args"];
|
||||
pub const FROM_FROM: [&str; 4] = ["core", "convert", "From", "from"];
|
||||
pub const FROM_ITERATOR: [&str; 5] = ["core", "iter", "traits", "collect", "FromIterator"];
|
||||
pub const FROM_ITERATOR_METHOD: [&str; 6] = ["core", "iter", "traits", "collect", "FromIterator", "from_iter"];
|
||||
|
@ -109,6 +121,10 @@ pub const PERMISSIONS_FROM_MODE: [&str; 6] = ["std", "os", "unix", "fs", "Permis
|
|||
pub const POLL: [&str; 4] = ["core", "task", "poll", "Poll"];
|
||||
pub const POLL_PENDING: [&str; 5] = ["core", "task", "poll", "Poll", "Pending"];
|
||||
pub const POLL_READY: [&str; 5] = ["core", "task", "poll", "Poll", "Ready"];
|
||||
#[allow(clippy::invalid_paths)] // `check_path` does not seem to work for macros
|
||||
pub const PRINT_MACRO: [&str; 3] = ["std", "macros", "print"];
|
||||
#[allow(clippy::invalid_paths)] // `check_path` does not seem to work for macros
|
||||
pub const PRINTLN_MACRO: [&str; 3] = ["std", "macros", "println"];
|
||||
pub const PTR_COPY: [&str; 3] = ["core", "intrinsics", "copy"];
|
||||
pub const PTR_COPY_NONOVERLAPPING: [&str; 3] = ["core", "intrinsics", "copy_nonoverlapping"];
|
||||
pub const PTR_EQ: [&str; 3] = ["core", "ptr", "eq"];
|
||||
|
@ -185,3 +201,7 @@ pub const VEC_NEW: [&str; 4] = ["alloc", "vec", "Vec", "new"];
|
|||
pub const VEC_RESIZE: [&str; 4] = ["alloc", "vec", "Vec", "resize"];
|
||||
pub const WEAK_ARC: [&str; 3] = ["alloc", "sync", "Weak"];
|
||||
pub const WEAK_RC: [&str; 3] = ["alloc", "rc", "Weak"];
|
||||
#[allow(clippy::invalid_paths)] // `check_path` does not seem to work for macros
|
||||
pub const WRITE_MACRO: [&str; 3] = ["core", "macros", "write"];
|
||||
#[allow(clippy::invalid_paths)] // `check_path` does not seem to work for macros
|
||||
pub const WRITELN_MACRO: [&str; 3] = ["core", "macros", "writeln"];
|
||||
|
|
105
tests/ui/format_args.fixed
Normal file
105
tests/ui/format_args.fixed
Normal file
|
@ -0,0 +1,105 @@
|
|||
// run-rustfix
|
||||
|
||||
#![allow(unreachable_code)]
|
||||
#![allow(unused_macros)]
|
||||
#![allow(unused_variables)]
|
||||
#![allow(clippy::assertions_on_constants)]
|
||||
#![allow(clippy::eq_op)]
|
||||
#![warn(clippy::to_string_in_format_args)]
|
||||
|
||||
use std::io::{stdout, Write};
|
||||
use std::ops::Deref;
|
||||
use std::panic::Location;
|
||||
|
||||
struct Somewhere;
|
||||
|
||||
impl ToString for Somewhere {
|
||||
fn to_string(&self) -> String {
|
||||
String::from("somewhere")
|
||||
}
|
||||
}
|
||||
|
||||
struct X(u32);
|
||||
|
||||
impl Deref for X {
|
||||
type Target = u32;
|
||||
|
||||
fn deref(&self) -> &u32 {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
struct Y<'a>(&'a X);
|
||||
|
||||
impl<'a> Deref for Y<'a> {
|
||||
type Target = &'a X;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
struct Z(u32);
|
||||
|
||||
impl Deref for Z {
|
||||
type Target = u32;
|
||||
|
||||
fn deref(&self) -> &u32 {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Z {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "Z")
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! my_macro {
|
||||
() => {
|
||||
// here be dragons, do not enter (or lint)
|
||||
println!("error: something failed at {}", Location::caller().to_string());
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! my_other_macro {
|
||||
() => {
|
||||
Location::caller().to_string()
|
||||
};
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = &X(1);
|
||||
let x_ref = &x;
|
||||
|
||||
let _ = format!("error: something failed at {}", Location::caller());
|
||||
let _ = write!(
|
||||
stdout(),
|
||||
"error: something failed at {}",
|
||||
Location::caller()
|
||||
);
|
||||
let _ = writeln!(
|
||||
stdout(),
|
||||
"error: something failed at {}",
|
||||
Location::caller()
|
||||
);
|
||||
print!("error: something failed at {}", Location::caller());
|
||||
println!("error: something failed at {}", Location::caller());
|
||||
eprint!("error: something failed at {}", Location::caller());
|
||||
eprintln!("error: something failed at {}", Location::caller());
|
||||
let _ = format_args!("error: something failed at {}", Location::caller());
|
||||
assert!(true, "error: something failed at {}", Location::caller());
|
||||
assert_eq!(0, 0, "error: something failed at {}", Location::caller());
|
||||
assert_ne!(0, 0, "error: something failed at {}", Location::caller());
|
||||
panic!("error: something failed at {}", Location::caller());
|
||||
println!("{}", *X(1));
|
||||
println!("{}", ***Y(&X(1)));
|
||||
println!("{}", Z(1));
|
||||
println!("{}", **x);
|
||||
println!("{}", ***x_ref);
|
||||
|
||||
println!("error: something failed at {}", Somewhere.to_string());
|
||||
println!("{} and again {0}", x.to_string());
|
||||
my_macro!();
|
||||
println!("error: something failed at {}", my_other_macro!());
|
||||
}
|
105
tests/ui/format_args.rs
Normal file
105
tests/ui/format_args.rs
Normal file
|
@ -0,0 +1,105 @@
|
|||
// run-rustfix
|
||||
|
||||
#![allow(unreachable_code)]
|
||||
#![allow(unused_macros)]
|
||||
#![allow(unused_variables)]
|
||||
#![allow(clippy::assertions_on_constants)]
|
||||
#![allow(clippy::eq_op)]
|
||||
#![warn(clippy::to_string_in_format_args)]
|
||||
|
||||
use std::io::{stdout, Write};
|
||||
use std::ops::Deref;
|
||||
use std::panic::Location;
|
||||
|
||||
struct Somewhere;
|
||||
|
||||
impl ToString for Somewhere {
|
||||
fn to_string(&self) -> String {
|
||||
String::from("somewhere")
|
||||
}
|
||||
}
|
||||
|
||||
struct X(u32);
|
||||
|
||||
impl Deref for X {
|
||||
type Target = u32;
|
||||
|
||||
fn deref(&self) -> &u32 {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
struct Y<'a>(&'a X);
|
||||
|
||||
impl<'a> Deref for Y<'a> {
|
||||
type Target = &'a X;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
struct Z(u32);
|
||||
|
||||
impl Deref for Z {
|
||||
type Target = u32;
|
||||
|
||||
fn deref(&self) -> &u32 {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Z {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "Z")
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! my_macro {
|
||||
() => {
|
||||
// here be dragons, do not enter (or lint)
|
||||
println!("error: something failed at {}", Location::caller().to_string());
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! my_other_macro {
|
||||
() => {
|
||||
Location::caller().to_string()
|
||||
};
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = &X(1);
|
||||
let x_ref = &x;
|
||||
|
||||
let _ = format!("error: something failed at {}", Location::caller().to_string());
|
||||
let _ = write!(
|
||||
stdout(),
|
||||
"error: something failed at {}",
|
||||
Location::caller().to_string()
|
||||
);
|
||||
let _ = writeln!(
|
||||
stdout(),
|
||||
"error: something failed at {}",
|
||||
Location::caller().to_string()
|
||||
);
|
||||
print!("error: something failed at {}", Location::caller().to_string());
|
||||
println!("error: something failed at {}", Location::caller().to_string());
|
||||
eprint!("error: something failed at {}", Location::caller().to_string());
|
||||
eprintln!("error: something failed at {}", Location::caller().to_string());
|
||||
let _ = format_args!("error: something failed at {}", Location::caller().to_string());
|
||||
assert!(true, "error: something failed at {}", Location::caller().to_string());
|
||||
assert_eq!(0, 0, "error: something failed at {}", Location::caller().to_string());
|
||||
assert_ne!(0, 0, "error: something failed at {}", Location::caller().to_string());
|
||||
panic!("error: something failed at {}", Location::caller().to_string());
|
||||
println!("{}", X(1).to_string());
|
||||
println!("{}", Y(&X(1)).to_string());
|
||||
println!("{}", Z(1).to_string());
|
||||
println!("{}", x.to_string());
|
||||
println!("{}", x_ref.to_string());
|
||||
|
||||
println!("error: something failed at {}", Somewhere.to_string());
|
||||
println!("{} and again {0}", x.to_string());
|
||||
my_macro!();
|
||||
println!("error: something failed at {}", my_other_macro!());
|
||||
}
|
106
tests/ui/format_args.stderr
Normal file
106
tests/ui/format_args.stderr
Normal file
|
@ -0,0 +1,106 @@
|
|||
error: `to_string` applied to a type that implements `Display` in `format!` args
|
||||
--> $DIR/format_args.rs:75:72
|
||||
|
|
||||
LL | let _ = format!("error: something failed at {}", Location::caller().to_string());
|
||||
| ^^^^^^^^^^^^ help: remove this
|
||||
|
|
||||
= note: `-D clippy::to-string-in-format-args` implied by `-D warnings`
|
||||
|
||||
error: `to_string` applied to a type that implements `Display` in `write!` args
|
||||
--> $DIR/format_args.rs:79:27
|
||||
|
|
||||
LL | Location::caller().to_string()
|
||||
| ^^^^^^^^^^^^ help: remove this
|
||||
|
||||
error: `to_string` applied to a type that implements `Display` in `writeln!` args
|
||||
--> $DIR/format_args.rs:84:27
|
||||
|
|
||||
LL | Location::caller().to_string()
|
||||
| ^^^^^^^^^^^^ help: remove this
|
||||
|
||||
error: `to_string` applied to a type that implements `Display` in `print!` args
|
||||
--> $DIR/format_args.rs:86:63
|
||||
|
|
||||
LL | print!("error: something failed at {}", Location::caller().to_string());
|
||||
| ^^^^^^^^^^^^ help: remove this
|
||||
|
||||
error: `to_string` applied to a type that implements `Display` in `println!` args
|
||||
--> $DIR/format_args.rs:87:65
|
||||
|
|
||||
LL | println!("error: something failed at {}", Location::caller().to_string());
|
||||
| ^^^^^^^^^^^^ help: remove this
|
||||
|
||||
error: `to_string` applied to a type that implements `Display` in `eprint!` args
|
||||
--> $DIR/format_args.rs:88:64
|
||||
|
|
||||
LL | eprint!("error: something failed at {}", Location::caller().to_string());
|
||||
| ^^^^^^^^^^^^ help: remove this
|
||||
|
||||
error: `to_string` applied to a type that implements `Display` in `eprintln!` args
|
||||
--> $DIR/format_args.rs:89:66
|
||||
|
|
||||
LL | eprintln!("error: something failed at {}", Location::caller().to_string());
|
||||
| ^^^^^^^^^^^^ help: remove this
|
||||
|
||||
error: `to_string` applied to a type that implements `Display` in `format_args!` args
|
||||
--> $DIR/format_args.rs:90:77
|
||||
|
|
||||
LL | let _ = format_args!("error: something failed at {}", Location::caller().to_string());
|
||||
| ^^^^^^^^^^^^ help: remove this
|
||||
|
||||
error: `to_string` applied to a type that implements `Display` in `assert!` args
|
||||
--> $DIR/format_args.rs:91:70
|
||||
|
|
||||
LL | assert!(true, "error: something failed at {}", Location::caller().to_string());
|
||||
| ^^^^^^^^^^^^ help: remove this
|
||||
|
||||
error: `to_string` applied to a type that implements `Display` in `assert_eq!` args
|
||||
--> $DIR/format_args.rs:92:73
|
||||
|
|
||||
LL | assert_eq!(0, 0, "error: something failed at {}", Location::caller().to_string());
|
||||
| ^^^^^^^^^^^^ help: remove this
|
||||
|
||||
error: `to_string` applied to a type that implements `Display` in `assert_ne!` args
|
||||
--> $DIR/format_args.rs:93:73
|
||||
|
|
||||
LL | assert_ne!(0, 0, "error: something failed at {}", Location::caller().to_string());
|
||||
| ^^^^^^^^^^^^ help: remove this
|
||||
|
||||
error: `to_string` applied to a type that implements `Display` in `panic!` args
|
||||
--> $DIR/format_args.rs:94:63
|
||||
|
|
||||
LL | panic!("error: something failed at {}", Location::caller().to_string());
|
||||
| ^^^^^^^^^^^^ help: remove this
|
||||
|
||||
error: `to_string` applied to a type that implements `Display` in `println!` args
|
||||
--> $DIR/format_args.rs:95:20
|
||||
|
|
||||
LL | println!("{}", X(1).to_string());
|
||||
| ^^^^^^^^^^^^^^^^ help: use this: `*X(1)`
|
||||
|
||||
error: `to_string` applied to a type that implements `Display` in `println!` args
|
||||
--> $DIR/format_args.rs:96:20
|
||||
|
|
||||
LL | println!("{}", Y(&X(1)).to_string());
|
||||
| ^^^^^^^^^^^^^^^^^^^^ help: use this: `***Y(&X(1))`
|
||||
|
||||
error: `to_string` applied to a type that implements `Display` in `println!` args
|
||||
--> $DIR/format_args.rs:97:24
|
||||
|
|
||||
LL | println!("{}", Z(1).to_string());
|
||||
| ^^^^^^^^^^^^ help: remove this
|
||||
|
||||
error: `to_string` applied to a type that implements `Display` in `println!` args
|
||||
--> $DIR/format_args.rs:98:20
|
||||
|
|
||||
LL | println!("{}", x.to_string());
|
||||
| ^^^^^^^^^^^^^ help: use this: `**x`
|
||||
|
||||
error: `to_string` applied to a type that implements `Display` in `println!` args
|
||||
--> $DIR/format_args.rs:99:20
|
||||
|
|
||||
LL | println!("{}", x_ref.to_string());
|
||||
| ^^^^^^^^^^^^^^^^^ help: use this: `***x_ref`
|
||||
|
||||
error: aborting due to 17 previous errors
|
||||
|
60
tests/ui/format_args_unfixable.rs
Normal file
60
tests/ui/format_args_unfixable.rs
Normal file
|
@ -0,0 +1,60 @@
|
|||
#![allow(clippy::assertions_on_constants)]
|
||||
#![allow(clippy::eq_op)]
|
||||
#![warn(clippy::format_in_format_args)]
|
||||
#![warn(clippy::to_string_in_format_args)]
|
||||
|
||||
use std::io::{stdout, Error, ErrorKind, Write};
|
||||
use std::ops::Deref;
|
||||
use std::panic::Location;
|
||||
|
||||
macro_rules! my_macro {
|
||||
() => {
|
||||
// here be dragons, do not enter (or lint)
|
||||
println!("error: {}", format!("something failed at {}", Location::caller()));
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! my_other_macro {
|
||||
() => {
|
||||
format!("something failed at {}", Location::caller())
|
||||
};
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let error = Error::new(ErrorKind::Other, "bad thing");
|
||||
let x = 'x';
|
||||
|
||||
println!("error: {}", format!("something failed at {}", Location::caller()));
|
||||
println!("{}: {}", error, format!("something failed at {}", Location::caller()));
|
||||
println!("{:?}: {}", error, format!("something failed at {}", Location::caller()));
|
||||
println!("{{}}: {}", format!("something failed at {}", Location::caller()));
|
||||
println!(r#"error: "{}""#, format!("something failed at {}", Location::caller()));
|
||||
println!("error: {}", format!(r#"something failed at "{}""#, Location::caller()));
|
||||
println!("error: {}", format!("something failed at {} {0}", Location::caller()));
|
||||
let _ = format!("error: {}", format!("something failed at {}", Location::caller()));
|
||||
let _ = write!(
|
||||
stdout(),
|
||||
"error: {}",
|
||||
format!("something failed at {}", Location::caller())
|
||||
);
|
||||
let _ = writeln!(
|
||||
stdout(),
|
||||
"error: {}",
|
||||
format!("something failed at {}", Location::caller())
|
||||
);
|
||||
print!("error: {}", format!("something failed at {}", Location::caller()));
|
||||
eprint!("error: {}", format!("something failed at {}", Location::caller()));
|
||||
eprintln!("error: {}", format!("something failed at {}", Location::caller()));
|
||||
let _ = format_args!("error: {}", format!("something failed at {}", Location::caller()));
|
||||
assert!(true, "error: {}", format!("something failed at {}", Location::caller()));
|
||||
assert_eq!(0, 0, "error: {}", format!("something failed at {}", Location::caller()));
|
||||
assert_ne!(0, 0, "error: {}", format!("something failed at {}", Location::caller()));
|
||||
panic!("error: {}", format!("something failed at {}", Location::caller()));
|
||||
|
||||
println!("error: {}", format_args!("something failed at {}", Location::caller()));
|
||||
println!("error: {:>70}", format!("something failed at {}", Location::caller()));
|
||||
println!("error: {} {0}", format!("something failed at {}", Location::caller()));
|
||||
println!("{} and again {0}", format!("hi {}", x));
|
||||
my_macro!();
|
||||
println!("error: {}", my_other_macro!());
|
||||
}
|
175
tests/ui/format_args_unfixable.stderr
Normal file
175
tests/ui/format_args_unfixable.stderr
Normal file
|
@ -0,0 +1,175 @@
|
|||
error: `format!` in `println!` args
|
||||
--> $DIR/format_args_unfixable.rs:27:5
|
||||
|
|
||||
LL | println!("error: {}", format!("something failed at {}", Location::caller()));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `-D clippy::format-in-format-args` implied by `-D warnings`
|
||||
= help: combine the `format!(..)` arguments with the outer `println!(..)` call
|
||||
= help: or consider changing `format!` to `format_args!`
|
||||
|
||||
error: `format!` in `println!` args
|
||||
--> $DIR/format_args_unfixable.rs:28:5
|
||||
|
|
||||
LL | println!("{}: {}", error, format!("something failed at {}", Location::caller()));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: combine the `format!(..)` arguments with the outer `println!(..)` call
|
||||
= help: or consider changing `format!` to `format_args!`
|
||||
|
||||
error: `format!` in `println!` args
|
||||
--> $DIR/format_args_unfixable.rs:29:5
|
||||
|
|
||||
LL | println!("{:?}: {}", error, format!("something failed at {}", Location::caller()));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: combine the `format!(..)` arguments with the outer `println!(..)` call
|
||||
= help: or consider changing `format!` to `format_args!`
|
||||
|
||||
error: `format!` in `println!` args
|
||||
--> $DIR/format_args_unfixable.rs:30:5
|
||||
|
|
||||
LL | println!("{{}}: {}", format!("something failed at {}", Location::caller()));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: combine the `format!(..)` arguments with the outer `println!(..)` call
|
||||
= help: or consider changing `format!` to `format_args!`
|
||||
|
||||
error: `format!` in `println!` args
|
||||
--> $DIR/format_args_unfixable.rs:31:5
|
||||
|
|
||||
LL | println!(r#"error: "{}""#, format!("something failed at {}", Location::caller()));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: combine the `format!(..)` arguments with the outer `println!(..)` call
|
||||
= help: or consider changing `format!` to `format_args!`
|
||||
|
||||
error: `format!` in `println!` args
|
||||
--> $DIR/format_args_unfixable.rs:32:5
|
||||
|
|
||||
LL | println!("error: {}", format!(r#"something failed at "{}""#, Location::caller()));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: combine the `format!(..)` arguments with the outer `println!(..)` call
|
||||
= help: or consider changing `format!` to `format_args!`
|
||||
|
||||
error: `format!` in `println!` args
|
||||
--> $DIR/format_args_unfixable.rs:33:5
|
||||
|
|
||||
LL | println!("error: {}", format!("something failed at {} {0}", Location::caller()));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: combine the `format!(..)` arguments with the outer `println!(..)` call
|
||||
= help: or consider changing `format!` to `format_args!`
|
||||
|
||||
error: `format!` in `format!` args
|
||||
--> $DIR/format_args_unfixable.rs:34:13
|
||||
|
|
||||
LL | let _ = format!("error: {}", format!("something failed at {}", Location::caller()));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: combine the `format!(..)` arguments with the outer `format!(..)` call
|
||||
= help: or consider changing `format!` to `format_args!`
|
||||
|
||||
error: `format!` in `write!` args
|
||||
--> $DIR/format_args_unfixable.rs:35:13
|
||||
|
|
||||
LL | let _ = write!(
|
||||
| _____________^
|
||||
LL | | stdout(),
|
||||
LL | | "error: {}",
|
||||
LL | | format!("something failed at {}", Location::caller())
|
||||
LL | | );
|
||||
| |_____^
|
||||
|
|
||||
= help: combine the `format!(..)` arguments with the outer `write!(..)` call
|
||||
= help: or consider changing `format!` to `format_args!`
|
||||
|
||||
error: `format!` in `writeln!` args
|
||||
--> $DIR/format_args_unfixable.rs:40:13
|
||||
|
|
||||
LL | let _ = writeln!(
|
||||
| _____________^
|
||||
LL | | stdout(),
|
||||
LL | | "error: {}",
|
||||
LL | | format!("something failed at {}", Location::caller())
|
||||
LL | | );
|
||||
| |_____^
|
||||
|
|
||||
= help: combine the `format!(..)` arguments with the outer `writeln!(..)` call
|
||||
= help: or consider changing `format!` to `format_args!`
|
||||
|
||||
error: `format!` in `print!` args
|
||||
--> $DIR/format_args_unfixable.rs:45:5
|
||||
|
|
||||
LL | print!("error: {}", format!("something failed at {}", Location::caller()));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: combine the `format!(..)` arguments with the outer `print!(..)` call
|
||||
= help: or consider changing `format!` to `format_args!`
|
||||
|
||||
error: `format!` in `eprint!` args
|
||||
--> $DIR/format_args_unfixable.rs:46:5
|
||||
|
|
||||
LL | eprint!("error: {}", format!("something failed at {}", Location::caller()));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: combine the `format!(..)` arguments with the outer `eprint!(..)` call
|
||||
= help: or consider changing `format!` to `format_args!`
|
||||
|
||||
error: `format!` in `eprintln!` args
|
||||
--> $DIR/format_args_unfixable.rs:47:5
|
||||
|
|
||||
LL | eprintln!("error: {}", format!("something failed at {}", Location::caller()));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: combine the `format!(..)` arguments with the outer `eprintln!(..)` call
|
||||
= help: or consider changing `format!` to `format_args!`
|
||||
|
||||
error: `format!` in `format_args!` args
|
||||
--> $DIR/format_args_unfixable.rs:48:13
|
||||
|
|
||||
LL | let _ = format_args!("error: {}", format!("something failed at {}", Location::caller()));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: combine the `format!(..)` arguments with the outer `format_args!(..)` call
|
||||
= help: or consider changing `format!` to `format_args!`
|
||||
|
||||
error: `format!` in `assert!` args
|
||||
--> $DIR/format_args_unfixable.rs:49:5
|
||||
|
|
||||
LL | assert!(true, "error: {}", format!("something failed at {}", Location::caller()));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: combine the `format!(..)` arguments with the outer `assert!(..)` call
|
||||
= help: or consider changing `format!` to `format_args!`
|
||||
|
||||
error: `format!` in `assert_eq!` args
|
||||
--> $DIR/format_args_unfixable.rs:50:5
|
||||
|
|
||||
LL | assert_eq!(0, 0, "error: {}", format!("something failed at {}", Location::caller()));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: combine the `format!(..)` arguments with the outer `assert_eq!(..)` call
|
||||
= help: or consider changing `format!` to `format_args!`
|
||||
|
||||
error: `format!` in `assert_ne!` args
|
||||
--> $DIR/format_args_unfixable.rs:51:5
|
||||
|
|
||||
LL | assert_ne!(0, 0, "error: {}", format!("something failed at {}", Location::caller()));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: combine the `format!(..)` arguments with the outer `assert_ne!(..)` call
|
||||
= help: or consider changing `format!` to `format_args!`
|
||||
|
||||
error: `format!` in `panic!` args
|
||||
--> $DIR/format_args_unfixable.rs:52:5
|
||||
|
|
||||
LL | panic!("error: {}", format!("something failed at {}", Location::caller()));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: combine the `format!(..)` arguments with the outer `panic!(..)` call
|
||||
= help: or consider changing `format!` to `format_args!`
|
||||
|
||||
error: aborting due to 18 previous errors
|
||||
|
Loading…
Reference in a new issue