diff --git a/clippy_lints/src/format_args.rs b/clippy_lints/src/format_args.rs index 043112bbc95..70a80d40f46 100644 --- a/clippy_lints/src/format_args.rs +++ b/clippy_lints/src/format_args.rs @@ -7,14 +7,14 @@ use clippy_utils::macros::{ }; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_opt; -use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; +use clippy_utils::ty::{implements_trait, is_type_lang_item}; use if_chain::if_chain; use itertools::Itertools; use rustc_errors::{ Applicability, SuggestionStyle::{CompletelyHidden, ShowCode}, }; -use rustc_hir::{Expr, ExprKind, HirId, QPath}; +use rustc_hir::{Expr, ExprKind, HirId, LangItem, QPath}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::ty::adjustment::{Adjust, Adjustment}; use rustc_middle::ty::Ty; @@ -237,7 +237,7 @@ fn check_unused_format_specifier(cx: &LateContext<'_>, arg: &FormatArg<'_>) { ); } - if is_type_diagnostic_item(cx, param_ty, sym::Arguments) && !arg.format.is_default_for_trait() { + if is_type_lang_item(cx, param_ty, LangItem::FormatArguments) && !arg.format.is_default_for_trait() { span_lint_and_then( cx, UNUSED_FORMAT_SPECS, diff --git a/clippy_utils/src/macros.rs b/clippy_utils/src/macros.rs index 77c5f115542..a8f8da67b51 100644 --- a/clippy_utils/src/macros.rs +++ b/clippy_utils/src/macros.rs @@ -1,6 +1,5 @@ #![allow(clippy::similar_names)] // `expr` and `expn` -use crate::is_path_diagnostic_item; use crate::source::snippet_opt; use crate::visitors::{for_each_expr, Descend}; @@ -8,7 +7,7 @@ use arrayvec::ArrayVec; use itertools::{izip, Either, Itertools}; use rustc_ast::ast::LitKind; use rustc_hir::intravisit::{walk_expr, Visitor}; -use rustc_hir::{self as hir, Expr, ExprField, ExprKind, HirId, Node, QPath}; +use rustc_hir::{self as hir, Expr, ExprField, ExprKind, HirId, LangItem, Node, QPath, TyKind}; use rustc_lexer::unescape::unescape_literal; use rustc_lexer::{tokenize, unescape, LiteralKind, TokenKind}; use rustc_lint::LateContext; @@ -439,8 +438,7 @@ impl<'tcx> FormatArgsValues<'tcx> { // ArgumentV1::from_usize() if let ExprKind::Call(callee, [val]) = expr.kind && let ExprKind::Path(QPath::TypeRelative(ty, _)) = callee.kind - && let hir::TyKind::Path(QPath::Resolved(_, path)) = ty.kind - && path.segments.last().unwrap().ident.name == sym::ArgumentV1 + && let TyKind::Path(QPath::LangItem(LangItem::FormatArgument, _, _)) = ty.kind { let val_idx = if val.span.ctxt() == expr.span.ctxt() && let ExprKind::Field(_, field) = val.kind @@ -486,20 +484,6 @@ struct ParamPosition { impl<'tcx> Visitor<'tcx> for ParamPosition { fn visit_expr_field(&mut self, field: &'tcx ExprField<'tcx>) { - fn parse_count(expr: &Expr<'_>) -> Option { - // ::core::fmt::rt::v1::Count::Param(1usize), - if let ExprKind::Call(ctor, [val]) = expr.kind - && let ExprKind::Path(QPath::Resolved(_, path)) = ctor.kind - && path.segments.last()?.ident.name == sym::Param - && let ExprKind::Lit(lit) = &val.kind - && let LitKind::Int(pos, _) = lit.node - { - Some(pos as usize) - } else { - None - } - } - match field.ident.name { sym::position => { if let ExprKind::Lit(lit) = &field.expr.kind @@ -519,15 +503,41 @@ impl<'tcx> Visitor<'tcx> for ParamPosition { } } +fn parse_count(expr: &Expr<'_>) -> Option { + // <::core::fmt::rt::v1::Count>::Param(1usize), + if let ExprKind::Call(ctor, [val]) = expr.kind + && let ExprKind::Path(QPath::TypeRelative(_, path)) = ctor.kind + && path.ident.name == sym::Param + && let ExprKind::Lit(lit) = &val.kind + && let LitKind::Int(pos, _) = lit.node + { + Some(pos as usize) + } else { + None + } +} + /// Parses the `fmt` arg of `Arguments::new_v1_formatted(pieces, args, fmt, _)` fn parse_rt_fmt<'tcx>(fmt_arg: &'tcx Expr<'tcx>) -> Option + 'tcx> { if let ExprKind::AddrOf(.., array) = fmt_arg.kind && let ExprKind::Array(specs) = array.kind { Some(specs.iter().map(|spec| { - let mut position = ParamPosition::default(); - position.visit_expr(spec); - position + if let ExprKind::Call(f, args) = spec.kind + && let ExprKind::Path(QPath::TypeRelative(ty, f)) = f.kind + && let TyKind::Path(QPath::LangItem(LangItem::FormatPlaceholder, _, _)) = ty.kind + && f.ident.name == sym::new + && let [position, _fill, _align, _flags, precision, width] = args + && let ExprKind::Lit(position) = &position.kind + && let LitKind::Int(position, _) = position.node { + ParamPosition { + value: position as usize, + width: parse_count(width), + precision: parse_count(precision), + } + } else { + ParamPosition::default() + } })) } else { None @@ -890,7 +900,7 @@ impl<'tcx> FormatArgsExpn<'tcx> { // ::core::fmt::Arguments::new_v1_formatted(pieces, args, fmt, _unsafe_arg) if let ExprKind::Call(callee, [pieces, args, rest @ ..]) = expr.kind && let ExprKind::Path(QPath::TypeRelative(ty, seg)) = callee.kind - && is_path_diagnostic_item(cx, ty, sym::Arguments) + && let TyKind::Path(QPath::LangItem(LangItem::FormatArguments, _, _)) = ty.kind && matches!(seg.ident.as_str(), "new_v1" | "new_v1_formatted") { let format_string = FormatString::new(cx, pieces)?; diff --git a/clippy_utils/src/sugg.rs b/clippy_utils/src/sugg.rs index e7879bb196e..2d1044af17e 100644 --- a/clippy_utils/src/sugg.rs +++ b/clippy_utils/src/sugg.rs @@ -219,6 +219,7 @@ impl<'a> Sugg<'a> { | ast::ExprKind::Repeat(..) | ast::ExprKind::Ret(..) | ast::ExprKind::Yeet(..) + | ast::ExprKind::FormatArgs(..) | ast::ExprKind::Struct(..) | ast::ExprKind::Try(..) | ast::ExprKind::TryBlock(..)