diff options
Diffstat (limited to 'src/tools/clippy/clippy_lints/src/format.rs')
-rw-r--r-- | src/tools/clippy/clippy_lints/src/format.rs | 91 |
1 files changed, 44 insertions, 47 deletions
diff --git a/src/tools/clippy/clippy_lints/src/format.rs b/src/tools/clippy/clippy_lints/src/format.rs index d0fab6949..d34d6e927 100644 --- a/src/tools/clippy/clippy_lints/src/format.rs +++ b/src/tools/clippy/clippy_lints/src/format.rs @@ -1,14 +1,13 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::macros::{root_macro_call_first_node, FormatArgsExpn}; -use clippy_utils::source::snippet_with_applicability; +use clippy_utils::macros::{find_format_arg_expr, find_format_args, root_macro_call_first_node}; +use clippy_utils::source::{snippet_opt, snippet_with_context}; use clippy_utils::sugg::Sugg; -use if_chain::if_chain; +use rustc_ast::{FormatArgsPiece, FormatOptions, FormatTrait}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::symbol::kw; use rustc_span::{sym, Span}; declare_clippy_lint! { @@ -44,55 +43,53 @@ declare_lint_pass!(UselessFormat => [USELESS_FORMAT]); impl<'tcx> LateLintPass<'tcx> for UselessFormat { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - let (format_args, call_site) = if_chain! { - if let Some(macro_call) = root_macro_call_first_node(cx, expr); - if cx.tcx.is_diagnostic_item(sym::format_macro, macro_call.def_id); - if let Some(format_args) = FormatArgsExpn::find_nested(cx, expr, macro_call.expn); - then { - (format_args, macro_call.span) - } else { - return - } - }; + let Some(macro_call) = root_macro_call_first_node(cx, expr) else { return }; + if !cx.tcx.is_diagnostic_item(sym::format_macro, macro_call.def_id) { + return; + } + + find_format_args(cx, expr, macro_call.expn, |format_args| { + let mut applicability = Applicability::MachineApplicable; + let call_site = macro_call.span; - let mut applicability = Applicability::MachineApplicable; - if format_args.args.is_empty() { - match *format_args.format_string.parts { - [] => span_useless_format_empty(cx, call_site, "String::new()".to_owned(), applicability), - [_] => { + match (format_args.arguments.all_args(), &format_args.template[..]) { + ([], []) => span_useless_format_empty(cx, call_site, "String::new()".to_owned(), applicability), + ([], [_]) => { // Simulate macro expansion, converting {{ and }} to { and }. - let s_expand = format_args.format_string.snippet.replace("{{", "{").replace("}}", "}"); + let Some(snippet) = snippet_opt(cx, format_args.span) else { return }; + let s_expand = snippet.replace("{{", "{").replace("}}", "}"); let sugg = format!("{s_expand}.to_string()"); span_useless_format(cx, call_site, sugg, applicability); }, - [..] => {}, - } - } else if let [arg] = &*format_args.args { - let value = arg.param.value; - if_chain! { - if format_args.format_string.parts == [kw::Empty]; - if arg.format.is_default(); - if match cx.typeck_results().expr_ty(value).peel_refs().kind() { - ty::Adt(adt, _) => Some(adt.did()) == cx.tcx.lang_items().string(), - ty::Str => true, - _ => false, - }; - then { - let is_new_string = match value.kind { - ExprKind::Binary(..) => true, - ExprKind::MethodCall(path, ..) => path.ident.name == sym::to_string, - _ => false, - }; - let sugg = if is_new_string { - snippet_with_applicability(cx, value.span, "..", &mut applicability).into_owned() - } else { - let sugg = Sugg::hir_with_applicability(cx, value, "<arg>", &mut applicability); - format!("{}.to_string()", sugg.maybe_par()) - }; - span_useless_format(cx, call_site, sugg, applicability); - } + ([arg], [piece]) => { + if let Ok(value) = find_format_arg_expr(expr, arg) + && let FormatArgsPiece::Placeholder(placeholder) = piece + && placeholder.format_trait == FormatTrait::Display + && placeholder.format_options == FormatOptions::default() + && match cx.typeck_results().expr_ty(value).peel_refs().kind() { + ty::Adt(adt, _) => Some(adt.did()) == cx.tcx.lang_items().string(), + ty::Str => true, + _ => false, + } + { + let is_new_string = match value.kind { + ExprKind::Binary(..) => true, + ExprKind::MethodCall(path, ..) => path.ident.name == sym::to_string, + _ => false, + }; + let sugg = if is_new_string { + snippet_with_context(cx, value.span, call_site.ctxt(), "..", &mut applicability).0.into_owned() + } else { + let sugg = Sugg::hir_with_context(cx, value, call_site.ctxt(), "<arg>", &mut applicability); + format!("{}.to_string()", sugg.maybe_par()) + }; + span_useless_format(cx, call_site, sugg, applicability); + + } + }, + _ => {}, } - }; + }); } } |